Derive the context budget from the model, not from VRAM #117
No reviewers
Labels
No labels
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/agent-proxy!117
Loading…
Reference in a new issue
No description provided.
Delete branch "context-budget-per-model"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bug
Fixes #115.
Every
request.prompt_trimmedevent in a seven-day window - all eleven, across every logical model - carried the same triple:48128 = 47 x 1024,47104 = 46 x 1024. That is the shape of a VRAM allocation, not a provider limit. The DeepSeek v4 line advertises a 1M window, so the proxy was enforcing 4.7% of it. Nothing upstream ever objected on length: prompts of 171,203, 119,703, and 83,785 tokens all went out and came back complaining about message structure instead.Root cause
derive_num_ctxappliedmin(context_length, PROXY_NUM_CTX_CEILING) - headroomto every route.num_ctxis an Ollama parameter - the window allocated when a model is loaded into VRAM - and it is exactly right forornith:9bandornith:35bon the tower. A hosted route reports nocontext_length, so it fell through to the ceiling, and every hosted budget became the tower's.Fix
The discriminator was already in the registry: a route with a
directtarget is served out of the tower, and a route without one is served by a hosted provider.derive_context_budget(context_length, local=)returns the budget and which of four bounds produced it:model_window,vram_ceiling,cost_ceiling,unbounded. The bound ridesrequest.prompt_trimmedasbudget_bound_by, so a trim log can no longer present a cost decision as a hardware limit or the reverse.context_windowlets Deploy declare the real window per route.PROXY_CONTEXT_COST_CEILINGis how to ask for a smaller budget than the model allows, named for the reason it exists rather than borrowed from VRAM. It binds every route, hosted or local.num_ctxextension at all. Local routes behind LiteLLM keep both the ceiling and the injection.How to verify
ward exec test- 11 new cases acrosstests/test_models.py,tests/test_route_registry.py,tests/test_analysis.py.test_hosted_route_is_not_bounded_by_the_tower_ceilingpins the exact defect: that route used to resolve to 48128.test_local_route_behind_litellm_keeps_the_tower_ceilingpins thatsirens-echo/defaultis unchanged.Test plan
ward exec format-check,lint,typecheck,pre-commitall cleanRisk
Medium, and worth naming precisely. Hosted prompts are no longer trimmed at all by default, so a genuinely oversized hosted prompt now reaches the provider and gets the provider's own error rather than a silent local trim. That is the intended trade - the previous behaviour destroyed turns to enforce a limit that did not exist - but it does mean hosted spend is bounded only by
max_tokensand the caller until Deploy setscontext_windoworPROXY_CONTEXT_COST_CEILING. Local routes are untouched.Follow-up for Deploy
services/agent-proxy/chart/files/route-registry.jsoncan now declarecontext_windowonsirens-echo/deepseekandevaluation/deepseek-v4-flash. Not required for this to be correct, and the loader accepts a registry with the field absent.Note
Stacked on #116 (issue #113). The two are the same incident from opposite ends: #113 makes trimming correct wherever it runs, this stops it running where nothing asked for it. Review #116 first; this branch contains its commit.