Skip to content

feat(ai): resilient shared OpenRouter client with retry and fallback#99

Merged
pratikbodkhe merged 1 commit into
mainfrom
feat/ai-openrouter-resilience
Jun 6, 2026
Merged

feat(ai): resilient shared OpenRouter client with retry and fallback#99
pratikbodkhe merged 1 commit into
mainfrom
feat/ai-openrouter-resilience

Conversation

@pratikbodkhe

Copy link
Copy Markdown
Contributor

What

PR A of the AI 80:20 program. Extracts a single OpenRouter transport (src/lib/ai/openrouter.ts) and routes all three AI features (enhance-notes, suggestions, ask-series) through it, adding cross-cutting reliability.

Why

The three routes each carried a byte-identical getOpenRouterData with no timeout, no retry, no fallback. A slow or unavailable model surfaced as a hard 502 (the class of bug we just patched). This is the highest-leverage reliability win across every AI feature.

Changes

  • src/lib/ai/openrouter.ts (new): callOpenRouter({ apiKey, system, prompt }) with a 30s timeout (AbortController), one retry, and ordered model fallback; getOpenRouterApiKey(). Returns the model that actually answered.
  • model.ts: getAiModels() returns [AI_MODEL, AI_MODEL_FALLBACK] (fallback defaults to the cheap model). Default stays cheap for testing; self-host already ships claude-sonnet-4-6.
  • Routes: deleted three copies of the fetch boilerplate; each route is now prompt + schema + shared client. Records the answering model in ai_model / response.
  • Tests + CI: new test:ai-client (node:test, 6 cases: success, model fallback, retry, total failure, key precedence, default models). Wired both test:ai-contracts and test:ai-client into ci.yml lint-and-typecheck job. The AI contract verifier was previously orphaned (not in CI); now enforced.
  • Documented AI_MODEL_FALLBACK in .env.example and the self-host env generator.

Verification (local)

  • test:ai-client 6/6, test:ai-contracts, test:query-contracts, test:runtime-config 7/7, test:ci-workflows: pass
  • pnpm build (full typecheck): pass; eslint on changed files: clean

TDD

Client written test-first: failing test (module missing) → minimal implementation → green. Route refactor is behavior-preserving, locked by the contract verifier.

Next in program

PR B carry-over intelligence, PR C transcript paste, then Edge Functions infra PR. STT last.

Extract src/lib/ai/openrouter.ts as the single OpenRouter transport for
enhance-notes, suggestions, and ask-series. Adds timeout, one retry, and a
configurable model fallback (AI_MODEL_FALLBACK) so a slow or unavailable
primary model no longer surfaces as a 502. Routes now record the model that
actually answered and resolve the key via getOpenRouterApiKey.

Wire the AI notes contract verifier and a new OpenRouter client test into
CI; both were previously unenforced.
@pratikbodkhe pratikbodkhe merged commit 6f3d81a into main Jun 6, 2026
18 checks passed
@pratikbodkhe pratikbodkhe deleted the feat/ai-openrouter-resilience branch June 6, 2026 02:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant