ENG-648: Reduce token usage — prompt caching, prompts→skills, cheap router tier#239
Draft
torrmal wants to merge 11 commits into
Draft
ENG-648: Reduce token usage — prompt caching, prompts→skills, cheap router tier#239torrmal wants to merge 11 commits into
torrmal wants to merge 11 commits into
Conversation
This was referenced Jul 8, 2026
…skills, cheap router tier) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every turn used to go straight to the planning model with the full ~11.4K-token system prompt and ~4.2K tokens of tool schemas. With ANTON_ROUTER_ENABLED=true, a cost-effective router model now runs first with a ~400-token prompt and no tool schemas, and either: - answers trivial/from-context turns directly (planning model never invoked), or - delegates via a forced tool call, optionally naming procedural skills that get preloaded into history as a synthetic recall_skill exchange so the planning model doesn't spend a full-context round fetching them. Conservative by construction: image turns, truncated answers, empty responses, and router errors all fall through to the planning model. New LLMClient router role defaults to the coding provider/model, so hosts constructing LLMClient directly need no changes. Off by default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The always-on system prompt carried two full tutorials — backend/ fullstack app generation (~3.8K tokens) and the HTML-dashboard build discipline (~2.7K tokens) — plus a public-data-source catalog (~0.7K), sent on every call of every tool round regardless of the task. They now ship as built-in skills (html-dashboards, backend-apps, public-data-sources) listed as one-line entries in the procedural memory section and loaded on demand: the model calls recall_skill, or the router preloads them at delegation time. Built-ins resolve before the on-disk SkillStore and shadow same-labelled user skills. Measured base system prompt: 45,511 -> 18,847 chars (~11,377 -> ~4,711 tokens, -59%) in dashboards mode. Prompt content itself is unchanged — it just moved; brace escapes collapse at recall exactly as they did at build time. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
anton names its subsystems after brain regions (Cortex, Cerebellum, AnteriorCingulate, hippocampus). The respond-or-delegate front-model is the thalamus: the brain's central relay, which every signal hits first and which gates what reaches the cortex versus what a fast subcortical path handles. That IS respond-vs-delegate. The biology also maps onto behavior we already had, and names it: - default-inhibit (thalamic reticular nucleus 'searchlight') = the conservative 'when in doubt, delegate' bias; - tonic vs burst firing = respond-directly vs alert-the-cortex; - fail-open (a lesioned thalamus must not silently drop signals) = any gating error relays the turn up untouched; - corticothalamic feedback (cortex biases the gate) = documented seam at gate_turn for letting recent outcomes tune future gating (not built). Mechanical rename, no behavior change: router.py -> thalamus.py, route_turn -> gate_turn, RouterDecision -> ThalamicDecision, LLMClient .route -> .gate + thalamus_provider/thalamus_model, ANTON_ROUTER_* -> ANTON_THALAMUS_*. Full suite passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The cheap front-model that gates turns now also owns conversation summarization, so hosts can expose a single 'routing and summarization' model choice distinct from the coding model (scratchpad code gen). New LLMClient.summarize() runs on the thalamus provider/model; _summarize_history calls it instead of code(). thalamus_* still default to the coding role, so this is behavior-preserving unless a distinct routing/summarization model is configured. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keeps one vocabulary end-to-end: the internal mechanism is the thalamus (class, module, gate(), ThalamicDecision), but everything a user or host configures is 'router' — router_enabled / router_max_tokens (CoreSettings), router_provider / router_model (AntonSettings), ANTON_ROUTER_* env. This matches cowork-server's router_provider/router_model settings 1:1 so there's no incongruence across repos. LLMClient's constructor kwargs stay thalamus_provider/thalamus_model (mechanism); from_settings maps the router_* settings onto them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extends #240's AntonSettings validator to cover router_provider. Without it, LLMClient.from_settings validates the router role the same way as planning/coding and a shared minds-cloud config re-crashes with 'Unknown router provider: minds-cloud' — the ENG-655 bug for the routing role. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
torrmal
force-pushed
the
jorge/eng-648-reduce-anton-cowork-server-token-usage-promptskills
branch
from
July 8, 2026 06:34
be306b7 to
7b5b78d
Compare
turn() (unlike turn_stream()) never increments _turn_count, so _inject_recalled_skills emitted the same tool_use id on every call made through the non-streaming turn() API when the thalamus delegated with skill preloads — duplicate ids in history can break provider validation on subsequent turns. Use a dedicated monotonic counter instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ea-rus
approved these changes
Jul 10, 2026
…token-usage-promptskills
…token-usage-promptskills
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linear: ENG-648
Full analysis + plan in
plans/eng-648-token-efficiency.md. Phases 2 and 3 are implemented in this PR; Phase 1 (prompt caching) is pending a design decision with themindshub_inferencegateway.Problem
Every turn — even a trivial "answer from context" one — paid for a ~11.4K-token system prompt, ~4.2K tokens of tool schemas, the full conversation history, and the frontier planning model, multiplied by up to 25 tool rounds per turn, with no prompt caching at all.
What this PR does
Phase 3 — Cheap front-model router (respond-or-delegate) ·
anton/core/llm/router.pyWith
ANTON_ROUTER_ENABLED=true, a cost-effective router model (newrouterrole onLLMClient, defaults to the coding role, i.e. Haiku) runs first on every text turn with a ~420-token prompt and no tool schemas, over a condensed text-only view of history, and either:delegatetool call, optionally naming skills that get preloaded into history as a syntheticrecall_skillexchange — payload-identical to what the planning model would have fetched itself, minus the full-context planning round.Conservative by construction: image turns, truncated router answers, empty responses, unknown skill labels, and router exceptions all fall through to the planning model. Off by default until eval'd.
Phase 2 — Prompt tutorials → built-in skills ·
anton/core/llm/builtin_skills.py~57% of the system prompt was two always-on tutorials + a URL catalog. They now ship as built-in skills —
html-dashboards(~2.7K tok),backend-apps(~3.9K tok),public-data-sources(~0.7K tok) — listed as one-line entries in the procedural-memory section and loaded on demand via the existingrecall_skilltool or the router's preload path. Built-ins resolve before the on-diskSkillStoreand shadow same-labelled user skills. Prompt content is unchanged; it just moved.Measured: base system prompt 45,511 → 18,847 chars (~11,377 → ~4,711 tokens, −59%).
Test coverage
tests/test_router.py(19 tests: condensation, decision parsing, session integration, fail-open) andtests/test_builtin_skills.py(12 tests: registry, prompt slimming with a <25K-char regression guard, recall resolution, router preload). Full suite passes (1 pre-existing unrelated failure intest_chat_scratchpad.py, fails on clean main too).Still to come (this ticket)
cache_controlbreakpoints inAnthropicProvider+ passthrough/usage-surfacing decisions inmindshub_inference(which already has a gateway-sidecache_alignheuristic; client-driven breakpoints need schema + usage plumbing there).mindsdb/cowork-server.🤖 Generated with Claude Code