Gateway
gateway/src/index.ts
Cloudflare Worker that brokers Venice API access. Holds one Venice master key and sub-keys are never issued — all inference goes through the gateway as a proxy, and capacity limits are enforced per request.
Authentication
POST /auth
Signs in with SIWE (Sign-In With Ethereum).
Request body
{
"message": "EIP-4361 message string",
"signature": "0x...",
"agentToken": "0x..." // optional — agent owner access
}Flow
1. Verify SIWE signature → extract address
2. If agentToken provided:
call agentToken.owner() on-chain
if owner != address → reject (403)
3. Generate session token
4. Store in KV: session → { address, agentToken | null }Response
{ "token": "<session-token>" }Pass the token in subsequent requests as Authorization: Bearer <token>.
Two separate identities
A user can authenticate in two modes:
| Mode | Condition | Venice key used |
|---|---|---|
| Personal | No agentToken in POST /auth | vkey:{address} |
| Agent | agentToken provided, owner() verified | vkey:agent:{agentToken} |
The two keys are completely independent. Capacity is never summed. An agent can accumulate capacity under its token contract address (via staking) without affecting the owner's personal capacity, and vice versa.
Capacity
How capacity is determined
Personal: pool.capacityToday(userAddress)
Agent: pool.capacityToday(agentToken)AgentToken's capacity grows as DIEM is staked under address(agentToken) — from buy-side LP fees routed by AgentHook and from rebalance dead DIEM, both via pool.enterFor(agentToken, amount).
The agent owner sets an inference reservation with agentToken.setReserve(X), which calls pool.reserve(X) — this caps how much of the staked capacity appears as daily inference quota.
Staleness and refresh
Venice capacity data is cached in KV. On each proxied request:
1. Look up cached Venice key for the identity
2. If key is stale or missing:
re-read pool.capacityToday(identity)
sync Venice key limits
store updated key in KV
3. Forward request to Venice with the keyProxy
All authenticated inference requests are forwarded to Venice:
POST /v1/* → Venice API (with key injected)
GET /v1/* → Venice API (with key injected)The gateway injects the Venice API key into the Authorization header — the client never sees the Venice key directly.
KV schema
| Key | Value |
|---|---|
session:{token} | { address, agentToken | null } |
vkey:{address} | Venice key record for personal use |
vkey:agent:{agentToken} | Venice key record for agent use |