Skip to content

feat(eu): route AI through OpenRouter's EU endpoint and turn chat back on - #1052

Merged
Makisuo merged 1 commit into
mainfrom
feat/eu-openrouter-in-region
Sep 24, 2026
Merged

Makisuo merged 1 commit into
mainfrom
feat/eu-openrouter-in-region

feat(eu): route AI through OpenRouter's EU endpoint and turn chat bac…

76d64e9
Select commit
Loading
Failed to load commit list.
Maple Review Bot / Maple / review completed Sep 24, 2026 in 2m 48s

Confidence 3/5 · Quality 100/100 · No issues found

Confidence Quality Open findings Commit
3/5 · needs attention 100/100 · excellent none 76d64e9

Why 3/5: I verified the EU endpoint/model plumbing in apps/ai/src/platform/Llm.ts and its env wiring, but the truncated web hunks (dashboard-layout.tsx, chat.tsx, region.ts) and the EU behaviour of the non-chat consumers of DecisionModel were not fully read.

Warning

This review ended early; what follows is what it established.

The EU instance now routes every OpenRouter call to https://eu.openrouter.ai/api/v1 when MAPLE_REGION=eu and switches its chat, triage and review defaults to openai/gpt-6-luna, which has an EU provider; Jev's decision model has none, so resolveDecisionModel returns undefined there and the triage route fails closed. The web change undoes #997's instance guard, re-enabling the global chat sheet, the ⌘K action, widget "fix with AI" and the header button everywhere. As written it looks safe: the region flag is derived into the AI worker's env, the model ids and limits are registered, and the new EU path is covered by tests.

  • layerLlm now builds its OpenRouterClient against openRouterApiUrl(env), picking the EU in-region endpoint from MAPLE_REGION (Llm.ts:505, 72-75)
  • resolveTriageModel and resolveReviewModel fall back to EU_DEFAULT_OPENROUTER_MODEL / EU_DEFAULT_REVIEW_MODEL in the EU, and MODEL_LIMITS gains openai/gpt-6-luna (Llm.ts:208-210, 408-409)
  • resolveDecisionModel returns undefined in the EU unless MAPLE_DECISION_MODEL is set, so triage.http.ts answers IncidentTriageModelError instead of calling a model with no EU provider
  • Web chat is re-enabled on all instances: aiChatEnabled is deleted from lib/region.ts and its guards are removed from the chat sheet, command palette, widget actions and dashboard layout

What was checked

  • MAPLE_REGION actually reaches the AI worker's LlmEnv: it is derived in selfObservabilityEnv (packages/infra/src/env.ts:222) and that env is merged into the worker's bindings (apps/ai/src/worker.ts:104)
  • The EU branch of resolveTriageModel is the only caller of the new default and keeps MAPLE_TRIAGE_MODEL_OPENROUTER as the override (apps/ai/src/platform/Llm.ts:408)
  • Removing aiChatEnabled from lib/region.ts leaves no dangling references — a repo-wide grep for the symbol returns nothing at the head SHA
  • The EU routing and model-id assertions are exercised by the new tests (https://eu.openrouter.ai/api/v1/chat/completions, openai/gpt-6-luna)
Observability coverage: 1 of 1 changes observable
Change Kind Observable Evidence
OpenRouter chat/completions call routed by region outbound HTTP call yes Existing client instrumentation: instrumentedModel wraps every model layer with LanguageModel spans and provider attribution (apps/ai/src/platform/Llm.ts:343-352), so the EU URL swap is visible on the same spans as before

Updated on every push. Resolve a thread or reply "won't fix" to dismiss a finding, or mention @maple to ask about one. Confidence is the reviewer's judgement of merge risk, capped at 2 by a critical finding and 3 by a warning. Quality: 100, minus 25 per critical finding, 10 per warning and 2 per note still open.