dsh-context-budget
在 DSH 模型设置页为每个 pi-ai 路由配置上下文窗口、压缩阈值与保留预算,并在输入框右下角按厂商提供思考强度选择器。 · Per-route context window, compaction threshold, and vendor-aware thinking-effort controls for DSH models.
- Stars
- 0
- Language
- JavaScript
- Created
- Sep 9, 2026
- Updated
- Sep 9, 2026
Introduction
dsh-context-budget
English | 中文
Adds a "context window / compaction threshold / retain budget" group to every pi-ai provider card on DSH Web's Settings → Models page. Type the numbers once; the window and the compaction trigger take effect without a restart.
What it fixes
Third-party gateways are usually declared by hand (api + baseURL + models). Their model ids rarely match the built-in pi-ai catalog — grok-4.6 on a my-gateway route is not the catalog's x-ai/grok-4.6, because they belong to different routes — so capacity resolution falls through to the last level, defaultContextWindow, which is 262144. Meanwhile the compaction backend only accepts a ratio, so "compact at 600k" has no direct spelling.
This plugin turns both into two fields:
| Field | Written to | Effect |
|---|---|---|
| Context window | llm-pi-ai settings, providers.<route>.defaultContextWindow | Models on that route that neither their own entry nor the installed catalog sizes get your value immediately |
| Compaction threshold | the profile's cordis.patch.yml, compaction-basic modelPolicies[].thresholdRatio | The backend computes floor(contextWindow × ratio) — your absolute threshold |
| Retain budget (optional) | same row, modelPolicies[].retainTokens | Recent context kept verbatim; blank keeps the backend's 16% default |
| Thinking effort | llm-pi-ai settings, providers.<route>.models[].reasoningEfforts | The picker at the composer's bottom-right resolves levels by vendor and the selected one is sent to the model |
The threshold is stored as threshold / window, so changing the window later needs one more Apply to re-derive the ratio.
Thinking effort (bottom-right of the composer)
A hand-declared route has no catalog entry, so the adapter treats its models as non-reasoning — the model selector only ever says "this model provides no reasoning effort levels". This plugin puts the control at the bottom-right of the composer, right next to the model selector, and keeps it out of the settings card:
- it reads the session's current model and uses the levels the catalog already advertises for it, when there are any;
- otherwise it identifies the vendor from the model id and takes that vendor's level profile;
- when you pick a level and the model has never declared one, the plugin writes the profile into
models[i].reasoningEffortsfirst, then switches the session effort — without that declaration the adapter rejects the selection as unsupported.
Built-in vendor profiles, matched against the model id, first match wins:
| Vendor | Match | Levels |
|---|---|---|
| xAI | grok | off low high max |
| OpenAI | gpt / chatgpt / o1…o9 | minimal low medium high |
| Anthropic | claude | low medium high |
| DeepSeek | deepseek | off high |
gemini / gemma | minimal low medium high | |
| Qwen | qwen | off low medium high |
| Z.ai | glm / z-ai | off high |
| Moonshot | kimi / moonshot | off high |
| MiniMax | minimax | off low medium high |
The wire value is the level name itself (reasoning_effort for openai-completions, reasoning.effort for openai-responses). If your gateway spells one differently, edit the value side of that model's reasoningEfforts in settings.yaml — the name shown in the picker is unaffected.
A selected level is persisted in the session log's request/header and sent with the request.
Why the compaction engine is not replaced
compaction-basic computes thresholdTokens = floor(contextWindow × thresholdRatio), and contextWindow is re-resolved through llm.resolveModelInfo() on every agent/pre-step. Writing the ratio is therefore enough: the official durable transaction, replay reuse, and overflow recovery all stay in place, and this plugin only supplies two numbers the engine already accepts.
Install
dsh plugin --profile web add dsh-context-budget
Restart dsh web once, then open Settings → Models and expand any pi-ai provider card — the "Context budget" group sits inside it.
After a successful write, the profile's patch watcher (patchReload: live) recomposes in about a second. No second restart.
Validation
Rejected host-side with a reason before anything is written:
- window and threshold must be positive integers;
- the threshold must be smaller than the window;
- the derived ratio must land in
(0, 1)and stay abovecompaction-basic's default retain ratio0.16, which the backend would otherwise refuse to load; - a supplied retain budget must be smaller than the threshold;
- the route must enumerate at least one model id, because
modelPoliciesrows are exactprovider/modelpairs.
Safe writes
cordis.patch.yml is your own layer, and the plugin touches only the block it owns:
- one marked managed block; every other line — comments and foreign patch rows — is preserved;
- the previous file is copied to
cordis.patch.yml.contextbudget.bakfirst; - the result is re-parsed and every
provider/modelrow is verified on disk, with an immediate rollback on failure; - if a hand-written
- id: compaction-basicrow already exists, the plugin refuses and names the line instead of overwriting your configuration.
Known limits
- pi-ai routes only.
llm-deepseekalready exposescontextWindowin the official editor. defaultContextWindowis a fallback: it does not override acontextWindowalready written on a model entry, nor a model the installed catalog describes. For a pure catalog route, set capacities per model instead.- The window must match the gateway's real capability. Too large and requests fail with
CONTEXT_WINDOW_EXCEEDED, then burn an extra summarization request on overflow recovery. maxTokensis not one of the fields; it stays at 32768, so a 1M window leaves roughly 968k of usable input.- Compaction costs one extra summarization request, so a lower threshold means more of them.
Uninstall and rollback
dsh plugin --profile web remove dsh-context-budget
Removing the plugin does not undo its two durable effects; that choice is yours:
defaultContextWindowunderllm-pi-aisettings — delete the field to fall back to 262144;- the
# dsh-context-budget managed blocksection incordis.patch.yml— delete that block; everything around it is untouched.
Every write leaves cordis.patch.yml.contextbudget.bak behind for comparison or restore.
Development
node --check lib/index.js
node --check client.js
node test/pure.test.mjs # validation rules + managed-block write/rollback
node test/integration.test.mjs # apply() registration and patch-path resolution
node test/apply.test.mjs # full write flow against a mocked context
node test/client.test.mjs # client seat registration and card rendering
Neither suite needs a running Harness.
License
MIT