Files
magpie/docs/subsystems
yetone a9cb0ef988 gateway: Claude Sonnet 5.5 is sent thinking between_tools in place of disabled, and Opus 5.5, Fable and Mythos no thinking, so Claude Code's auto mode classifier no longer gets a 400 (#1454)
911Liam's auto mode, on claude-sonnet-5.5 through a relay, got 400 "To
turn thinking off on this model, send "thinking": {"type":
"between_tools"} instead of {"type": "disabled"}". Claude Code turns
thinking off for its classifier and side queries unless it knows the
model refuses that, and a model reached through a gateway can fall
outside what it knows. magpie forwarded the disabled as it came, and
turns thinking off itself too (an effort of none fitted, a budget that
doesn't fit, thinkingOffUnlessAsked for other vendors' models).

thinkingOffAsTaken, in forwardOnce next to adaptiveThinking, so that
relayed requests, count_tokens, magpie's own thinking-off and retries
all go through it, follows Anthropic's rules for each model. It reads
the model's name as the vendor gives it, from the body, or from the path
for Bedrock and Vertex.
- Sonnet 5.5: between_tools with no other field, and xhigh or max asked
  as high (between_tools is a 400 above high).
- Opus 5.5, Fable 5.x and Mythos 5.x refuse disabled at every effort.
  Thinking is left out, effort is low unless one was asked, and
  classifierRoom is added to a reply limit below it, as Claude Code
  itself does for these models.
- Opus 5 and Haiku 5.5: disabled is kept, with xhigh or max asked as
  high.
- between_tools sent to any other Claude goes as disabled, or with no
  thinking where disabled is refused too.
Other vendors' models, Sonnet 5, Opus 4.8 and older, and lines later than
these go byte for byte as they came. A Sonnet 5.5 under a name these
rules can't read is asked again with between_tools, once, on the 400
that asks for it (asksBetweenTools). A refusal of disabled at any effort
(thinkingOffRefused) is asked again with thinking left to the model,
beside alwaysThinks.

TestAdaptiveOnlyModelsNeverGetABudget's "disabled stays" case pinned
disabled for claude-opus-5.5, which the vendor refuses. It now checks an
older Claude keeps disabled and Opus 5.5 is sent none.

Verified:
- Tests:
  - TestThinkingOffAsTheModelTakesIt and
    TestThinkingOffLeavesOtherModelsAlone (deepseek, glm-5.3, kimi,
    Sonnet 5, Opus 5 at high, Haiku 5.5, Opus 4.8 at max, Sonnet 4.6,
    Haiku 4.5, Claude 3.7, dated Sonnet 5 and Sonnet 6 unchanged).
  - TestClaudeFiveFiveThinkingOffOnTheWire: a fake vendor answers with
    the reporter's literal 400, covering the classifier body,
    count_tokens and the retry.
- Without the forwardOnce call, the wire test's Sonnet 5.5, Opus 5.5 and
  count_tokens cases and the Opus 5.5 adaptive case FAIL. Without the
  retry, its unreadable-name case FAILs.
- Live, through this build's `magpie serve` under a sandbox HOME with
  the aihubmix relay key, in the classifier's shape (max_tokens 64,
  temperature 0, stop </block>, thinking disabled):
  - claude-sonnet-5-5 answers 200 at default and xhigh effort (sent
    straight to aihubmix with disabled it gives the reporter's 400);
  - count_tokens 200;
  - claude-opus-5-5 200;
  - claude-haiku-5-5 at max 200;
  - claude-sonnet-5 200.
- gofmt -l, GOOS=linux and GOOS=windows go vet -tags nogui
  ./internal/gateway, and go test -tags nogui ./internal/gateway under a
  temp HOME with pinned caches.
2026-10-10 11:02:38 +08:00
..

Subsystem design references

These pages describe current responsibilities, runtime paths, state, and contracts. Start with the subsystem relevant to your task, then follow its source links to verify the implementation you change.

Subsystem Reference
Built-in subscriptions moving to plugins Provider and plugin ownership
Plugins that run on the gateway's requests and replies Gateway middleware
Claude subscription turns across Claude Code runs Claude subscription bridge
How the gateway picks a provider, key or account, and falls back Gateway routing and fallback
Gateway Session Aggregation Gateway Session Aggregation
Connecting an agent's config to the gateway, drift, disconnect, WSL twins Agent wiring
Providers, keys, subscription accounts, refresh and allowance Providers and accounts
Instructions, MCP servers, skills and RTK written into agents Library
Tray, panel, window, magpie web and the page's JSON API GUI app shell

A subsystem can span several packages or repositories. Its reference describes the behavior those parts provide together; it does not need to list every function.

Maintain a reference

Update the owning reference in the same PR when a change alters a documented responsibility, interface, state transition, runtime path, compatibility rule, or failure behavior. An internal refactor that preserves these contracts does not require a prose change.

Keep each fact in one reference and link to it from agent instructions or other pages. Link to source files and named symbols rather than copying implementation details that change frequently. Explain field meanings and constraints that signatures alone do not express.

For a new reference, include the responsibilities and boundaries, source of truth, main runtime paths, state transitions, important constraints, and existing verification commands. Include failure and compatibility behavior where relevant. Document current behavior separately from proposed changes; the proposal belongs in its issue or PR.

Describe a PR's semantic changes

For each affected subsystem, explain the observable change with its trigger and before/after behavior. Include changes to interfaces, state, compatibility, and failure behavior when relevant. Link the affected reference, implementation, and verification evidence. State when a refactor preserves the documented behavior.

For example, a change to plugin adoption should explain which migration state and account condition trigger it, which implementation handles requests before and after adoption, and which test exercises that transition.

This is an author-provided explanation that a reviewer verifies against the diff and surrounding code. It is not an automatically proven compatibility verdict.

Review a change

  1. Identify the affected subsystem and the actual runtime path, including plugin or built-in ownership.
  2. Compare the claimed before/after behavior with the base and head implementation. Trace relevant callers and state transitions beyond the changed lines.
  3. Check that changed contracts appear in the owning reference and that source links still resolve.
  4. Check that the cited tests or runtime evidence exercise the claimed behavior. Report checks that were not run.

A documentation update alone does not prove the implementation. Existing tests and runtime evidence remain necessary for behavior changes.