Route sandbox inference through the gateway behind a deployment flag#449
Conversation
When R_INFERENCE_GATEWAY is enabled (control-plane env or persisted deployment env var), task sandboxes no longer receive raw provider API keys for gateway-covered providers (OpenRouter, Anthropic, OpenAI, Google Gemini). Instead: - The dequeue/resume env resolver emits R_INFERENCE_GATEWAY_URL and withholds covered keys from the sandbox env (control-plane inference keeps direct keys since it holds no run token). - The worker daemon launch env skips covered operator keys. - The worker's OpenCode config rebases covered providers onto the gateway with the run token as the API key, preserving OpenRouter attribution headers and leaving ChatGPT-subscription OAuth and Bedrock/Vertex untouched. - The API token middleware accepts the run token from x-api-key / x-goog-api-key on the inference gateway surface only, since the Anthropic and Gemini SDKs send their key through those headers. Provider definitions are shared between the gateway and the worker via @roomote/types so path suffixes and env keys cannot drift.
|
2 issues outstanding. See task
Reviewed 9c489b0 |
|
Verified end-to-end locally (Modal sandbox, OpenRouter, worker built from this branch): with the flag enabled the sandbox's opencode config rebases openrouter onto the gateway (baseURL + run-token apiKey), |
Replaces the R_INFERENCE_GATEWAY env var with an InferenceGateway feature flag stored in deployment metadata (metadata key inference_gateway), so the gateway can be toggled from the admin controls like other deployment-level features. - resolveEffectiveModelRuntimeEnv takes an explicit inferenceGateway option instead of sniffing env vars; the dequeue path evaluates the flag through the shared evaluator and fails closed (direct keys) if flag evaluation is unavailable. - Worker daemon env builders take inferenceGatewayEnabled via BuildWorkerEnvOptions; each controller spawn path evaluates the flag before building the env. - Control-plane inference is unaffected: callers that do not pass the option keep direct provider keys.
|
Follow-up commit replaces the |
Folds the exact-match path allowlists, Gemini key alias, and array-based provider key resolution into the shared @roomote/types registry so the gateway and worker keep a single source of truth.
Summary
Stacked on #447. When the
InferenceGatewayfeature flag is enabled, task sandboxes stop receiving raw provider API keys for gateway-covered providers (OpenRouter, Anthropic, OpenAI, Google Gemini) and route inference through the gateway with their run-scoped token instead. Off by default; nothing changes for deployments that don't enable it.How it works
Flag:
InferenceGatewayfeature flag (deployment metadata keyinference_gateway), togglable from the admin metadata controls like other deployment-level features. Evaluation fails closed to direct provider keys if flag evaluation is unavailable, so a Redis outage cannot break task inference.Control plane (
resolveEffectiveModelRuntimeEnvgains aninferenceGatewayoption):R_INFERENCE_GATEWAY_URL(derived from the sandbox-reachable platform API URL). Raw deployment env vars carrying those key names are also stripped from the merged sandbox env.Worker launch env:
BuildWorkerEnvOptionsgainsinferenceGatewayEnabled; each controller spawn path evaluates the flag before building the worker daemon env, so the daemon's process env no longer carries covered keys when enabled.OpenCode config: for each selected model whose provider is gateway-covered, the worker rebases the provider onto the gateway (
baseURL= gateway URL + provider + SDK base-path suffix,apiKey={env:ROOMOTE_CLOUD_TOKEN}), following the existing Bedrock Mantle pattern. OpenRouter attribution headers are preserved, and theopenaiprovider is left untouched when a ChatGPT subscription record is present (its OAuth flows through opencode's Codex plugin).Token transport: the Anthropic and Gemini SDKs send their "API key" through
x-api-key/x-goog-api-keyrather thanAuthorization, so the API token middleware now accepts the run token from those headers on the/api/inferencesurface only. Everywhere else, Authorization remains the single token transport.Provider definitions (ids, env keys, upstream URLs, path allowlists, SDK base-path suffixes) live in
@roomote/typesso the gateway and the worker share one source of truth.Testing
types,feature-flags,db,sdk,compute-providers,controller,api, andworkersuites pass; typecheck, lint, knip clean/api/inference/openrouter/v1and completed normallyRollout notes