Skip to content

M4a: forward AI chat to Gecko Suite behind AI_BACKEND - #213

Merged
davior merged 1 commit into
mainfrom
claude/beautiful-wright-og4xur
Nov 4, 2026
Merged

davior merged 1 commit into
mainfrom
claude/beautiful-wright-og4xur

Conversation

@davior

@davior davior commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Summary

Notes' side of M4a (the suite's SN-1 and SN-7). With AI_BACKEND=suite, the six proxy functions in routers/settings.py (blocking and streaming, for Anthropic, OpenAI-compatible and Ollama) forward to the suite's /api/v1/ai/proxy/* (davior/gecko-suite#8). local stays the default and its code path is untouched, so this is reversible with one variable.

  • Everything Notes knows about the suite is app/suite.py. The frontend, the assistant worker and the on_delta watching for long planning calls are unchanged: the routes still answer in the shapes they always did (the same dicts, and delta / final / error frames).
  • The local provider row is still looked up, so ownership (404) and protocol (400) checks behave as before. What goes to the suite is the row's vendor and the model name, not its id or key. The suite finds the person's provider by vendor + model.
  • Calls are made as Notes on the user's behalf (X-Gecko-App: notes, secret, X-On-Behalf-Of), never with the browser's token, because a worker's call outlives its request.
  • Notes records no usage in this mode; the suite does.
  • Suite down: a 503 suite_unavailable (or an error frame when streaming) with a sentence. Nothing else in Notes depends on the suite.
  • Startup: AI_BACKEND=suite without SUITE_APP_SECRET (or an unknown value) refuses to start, rather than failing every chat.

Not in this PR: speech, image generation and web search (SN-2) and the Settings pages (SN-5). They still use Notes' own keys.

Differences someone may notice in suite mode: errors from the vendor arrive as the suite's {code, message} rather than the vendor's raw text; cache reads and writes are priced at their own rates; OpenAI's own models are sent max_completion_tokens; the provider's extra_params come from the suite's copy.

Test plan

  • pytest -q in backend/: 1361 passed, 1 skipped (on Python 3.13 locally; CI uses 3.11). 10 new in tests/test_suite_proxy.py, through the real routes and middleware with a fake suite transport: forwarded request shape and credentials, no usage written, all three protocols, frame-for-frame streaming, refusal before streaming, suite down, ownership/protocol checks, worker on_delta, local mode never calls the suite, startup validation.
  • Not run against the real suite or a vendor.

Deployment

Nothing changes until AI_BACKEND=suite is set, so this can be deployed first.

  • Before enabling suite mode:
    1. davior/gecko-suite#8 is merged and deployed.
    2. The person's providers exist in the suite (the importer brings Notes' across, or they are added there) with a model of the same vendor.
    3. An administrator registers the app notes on the suite's Apps screen and copies the secret, which is shown once.
  • Configuration (.env, defaults shown in .env.example): AI_BACKEND=local (set suite to switch), SUITE_BASE_URL=https://suite.geckopico.com, SUITE_APP_ID=notes, SUITE_APP_SECRET (required with suite; the app refuses to start without it).
  • Services rebuilt: backend only (docker compose up --build -d). No migration, no frontend change, no Caddy change.
  • Verify: curl -f http://localhost:18081/api/health; with suite, send a chat in the app and see it in the suite's Usage view under app notes.
  • Roll back: set AI_BACKEND=local and docker compose up -d; nothing was written locally in suite mode.

Generated by Claude Code

With AI_BACKEND=suite the six proxy functions (blocking and streaming, Anthropic,
OpenAI-compatible, Ollama) still resolve the caller's provider row, then send the
vendor and model to the suite's /ai/proxy/* as Notes on the user's behalf. The suite
holds the key and records usage; Notes records none. local stays the default.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1geD2ELWgL2sDpxYbx3Aw
@davior
davior marked this pull request as ready for review November 4, 2026 06:05
@davior
davior merged commit 631f97c into main Nov 4, 2026
2 checks passed
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.

2 participants