Back to home@zpis666

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
GitHub repo

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:

FieldWritten toEffect
Context windowllm-pi-ai settings, providers.<route>.defaultContextWindowModels on that route that neither their own entry nor the installed catalog sizes get your value immediately
Compaction thresholdthe profile's cordis.patch.yml, compaction-basic modelPolicies[].thresholdRatioThe backend computes floor(contextWindow × ratio) — your absolute threshold
Retain budget (optional)same row, modelPolicies[].retainTokensRecent context kept verbatim; blank keeps the backend's 16% default
Thinking effortllm-pi-ai settings, providers.<route>.models[].reasoningEffortsThe 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].reasoningEfforts first, 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:

VendorMatchLevels
xAIgrokoff low high max
OpenAIgpt / chatgpt / o1o9minimal low medium high
Anthropicclaudelow medium high
DeepSeekdeepseekoff high
Googlegemini / gemmaminimal low medium high
Qwenqwenoff low medium high
Z.aiglm / z-aioff high
Moonshotkimi / moonshotoff high
MiniMaxminimaxoff 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 above compaction-basic's default retain ratio 0.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 modelPolicies rows are exact provider/model pairs.

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.bak first;
  • the result is re-parsed and every provider/model row is verified on disk, with an immediate rollback on failure;
  • if a hand-written - id: compaction-basic row already exists, the plugin refuses and names the line instead of overwriting your configuration.

Known limits

  • pi-ai routes only. llm-deepseek already exposes contextWindow in the official editor.
  • defaultContextWindow is a fallback: it does not override a contextWindow already 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.
  • maxTokens is 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:

  • defaultContextWindow under llm-pi-ai settings — delete the field to fall back to 262144;
  • the # dsh-context-budget managed block section in cordis.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