Skip to main content

Configuration

Configuration comes from three places, and each has one job.

PlaceHoldsRead by
api/wrangler.jsonc → varsNon-secret settings, pinned per environment: models, voice, DATABASE_PROVIDER, AI Gateway ids, ALLOWED_ORIGINSwrangler dev and wrangler deploy
api/.dev.vars (gitignored)Local secrets and local overrides: GEMINI_API_KEY, DATABASE_URL, CF_AIG_TOKENwrangler dev, and the CLI scripts through loadDevVars
wrangler secret putDeployed secrets, per environmentThe deployed Worker

Non-secret settings are pinned in wrangler.jsonc rather than set in the dashboard because a wrangler deploy sets only what is in that file. A value set by hand in the dashboard is lost on the next deploy.

Restart after changes

wrangler dev reads .dev.vars and vars only at start-up. Restart it after changing either.

Variables​

The full typed list is Env in api/src/env.ts. The environment reference has the same table with defaults per environment.

VariableRequiredDefaultPurpose
GEMINI_API_KEYfor chat, voice, generationnoneGoogle AI Studio key. Without it /api/health reports configured: false and chat returns an error event.
DATABASE_PROVIDERnod1d1, neon or none: which claims and feedback store the Worker uses. none runs with no store, for a deployment that only serves embedded hosts.
DATABASE_URLwhen neonnoneNeon connection string (project EAIW, database claimpilotchat).
AI_PROVIDERnogeminiscripted swaps Gemini for the offline test adapter. Tests only. Never on a deployment.
GEMINI_MODELnogemini-3.1-flash-liteText chat model.
GEMINI_LIVE_MODELnogemini-3.1-flash-live-previewVoice model (Live API).
GENERATOR_MODELnoGEMINI_MODELModel used by the claim generator.
GEMINI_THINKING_LEVELnomodel defaultlow, medium or high. Capabilities may set their own. Any other value is ignored.
GEMINI_VOICEnoCharonPrebuilt Live voice name.
AI_GATEWAY_ACCOUNT_IDnopinnedCloudflare account id. With AI_GATEWAY_ID, routes model traffic through AI Gateway.
AI_GATEWAY_IDnoclaimpilot-chatAI Gateway name. Either id missing means straight to Google.
CF_AIG_TOKENwhen the gateway is authenticatednonecf-aig-authorization bearer token.
ALLOWED_ORIGINSfor cross-origin embeddingunsetComma-separated origins allowed to embed the assistant. An entry ending :* matches any port on that host.
EMBED_KEYnounset (open)Shared key on /api/chat, /api/voice and /api/feedback. A budget guard, not access control.

The defaults in the table are the code's fallbacks. wrangler.jsonc pins some of them to other values (for example a newer model); /api/health always reports what is actually in use.

Cloudflare AI Gateway​

Both gateway ids are pinned in wrangler.jsonc, so the gateway is on for deployments. Every model call (chat, generation and voice) is proxied through AI Gateway, which gives us request logs, cost per call, retries and rate limiting. Clear both ids and the same code calls Google directly.

How it is wired:

  • api/src/ai/gateway.ts is the only place gateway URLs are built. Blank values count as unset.
  • Google sits behind two provider paths, and they are not interchangeable. google-ai-studio is the REST provider, handed to @google/genai as its baseUrl for chat and generation. google is the realtime provider, used as the voice relay's upstream.
  • We keep sending our own key (x-goog-api-key) rather than storing it in the gateway. Gateway-side key injection is where the Gemini 3.x preview models have been unreliable.
  • The integration is URL-based rather than the env.AI binding, because the generator CLI runs in plain Node, where Worker bindings do not exist.

The ids decide the route; the token does not. The gateway is authenticated, so CF_AIG_TOKEN must be set wherever the ids are. A missing token does not fall back to Google: the gateway rejects every call with AiGatewayError 2009 Unauthorized.

Locally the gateway behaves exactly as in production. It is a public endpoint and wrangler dev makes real outbound calls, so local traffic is logged too. To go straight to Google locally, blank both ids in api/.dev.vars:

api/.dev.vars
GEMINI_API_KEY=…
AI_GATEWAY_ACCOUNT_ID=
AI_GATEWAY_ID=

/api/health, the Claims Data page and /status all show which route is live.

Local Neon instead of local D1​

To point local development at the shared Neon database, set both of these in api/.dev.vars and restart:

api/.dev.vars
DATABASE_PROVIDER=neon
DATABASE_URL=postgres://…

Neon is shared. Prefer local D1 for anything destructive.