dsh-switchman 1.10.3 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.de.md +11 -10
- package/README.es.md +11 -10
- package/README.fr.md +11 -10
- package/README.it.md +11 -10
- package/README.ja.md +11 -10
- package/README.ko.md +11 -10
- package/README.md +19 -10
- package/README.pt.md +11 -10
- package/README.ru.md +11 -10
- package/README.zh-TW.md +11 -10
- package/README.zh.md +11 -10
- package/client.js +326 -43
- package/cordis.patch.yml +24 -21
- package/host/config.js +57 -10
- package/host/context-trim/fork.js +5 -1
- package/host/context-trim/index.js +340 -183
- package/host/context-trim/metrics.js +22 -14
- package/host/context-trim/state.js +351 -50
- package/host/context-trim/summarizer.js +147 -33
- package/host/context-trim/surface.js +222 -2
- package/host/context-trim/trigger.js +170 -51
- package/host/context-trim/view.js +132 -16
- package/host/context-watch.js +81 -73
- package/host/dispatch.js +30 -5
- package/host/routes.js +64 -4
- package/host/teams.js +2 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Two pains creep in once you've worked in DSH for a while. First, sessions get he
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman is a plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Once installed, the main model stops doing and starts dispatching: measure the watermark, pick a lane, hand out tasks, check acceptance. It's not a new model — it's a dispatch doctrine hooked onto DSH plus a settings page, and it does eight things:
|
|
16
16
|
|
|
17
|
-
**1. Context watermark: long sessions don't blow up.** Every turn counts session tokens in real time, and three escalating lines tighten the screws: 80k (soft, adjustable) nudges "time to delegate";
|
|
17
|
+
**1. Context watermark: long sessions don't blow up.** Every turn counts session tokens in real time, and three escalating lines tighten the screws: 80k (soft, adjustable) nudges "time to delegate"; 95k (hard) shrinks the single-read budget and steers toward wrap-up; 150k (force) hands over automatically — writes the handover document (the append-only session log is the full-fidelity backup), compacts the context, wakes the session to continue, task unbroken. Background subagents still running at handover aren't lost either: their ids, tasks, and report paths go into the handover document, so the resumed session knows where to collect reports and never dispatches twice. Every subagent carries its own hard cap and exits after writing its HANDOFF summary. When the automatic intervention doesn't suit you, take over manually: `/ctx-pause` stops all watermark actions (measurement keeps running, the live watermark line switches to paused — it just stops acting), `/ctx-resume` restores them at any time — after a DSH restart the enforcement also comes back on its own, a temporary let-go, not a permanent off; `/ctx-handover` doesn't wait for the watermark to hit the ceiling and starts the same handover on demand: write the handover document, compact the context, wake the continuation (the session is first steered to an idle boundary, so the result can take a few minutes).
|
|
18
18
|
|
|
19
19
|
**2. Six dispatch pools: the right model for every job.** Economy (batch small chores), mechanical (template rewrites), main (day-to-day coding), hard (hard reasoning and large refactors), vision (images), review (independent verification). On the settings page you tick candidates, order priorities, grade S/A/B/C, and pin a per-route thinking effort — the effort dropdown lists the levels that model actually supports, not a generic three. Every turn's prompt carries a `[SWITCHMAN:POOLS]` recommendation table, and the main model dispatches by it. Three enforcement modes: off / advice / force (force = out-of-pool models get rejected outright).
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ Worth installing even with a single model — watermark control and tiered verif
|
|
|
86
86
|
bash <install-dir>/skills/db-query/scripts/setup.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
**Classifier model tips:** to run the decision model locally, serve `
|
|
89
|
+
**Classifier model tips:** to run the decision model locally, serve `d3:4b-mxfp8` with Ollama — set the classifier kind to the decision endpoint (systemone), fill the endpoint with `http://127.0.0.1:11434/v1/systemone`, and set the model name to `d3:4b-mxfp8`. For the chat classifier from the LLM catalog, prefer a small cloud model, or a small local model without thinking (reasoning) — turning thinking off lowers both latency and the classification-timeout failure rate.
|
|
90
90
|
|
|
91
91
|
## Default configuration
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ Everything below is the full set of defaults after a fresh install (authoritativ
|
|
|
96
96
|
|
|
97
97
|
**Dispatch pools**: all six lanes (economy/mechanical/main/hard/vision/review) start with empty candidates (= the system default models, no intervention); manual ordering and pinned effort are off/empty; `dispatchEnforce` = `advice` (advisory only, nothing enforced).
|
|
98
98
|
|
|
99
|
-
**Context watermark**: soft `80000` / hard `
|
|
99
|
+
**Context watermark**: soft `80000` / hard `95000` / force `150000` tokens; single-read budget `3000`; over-budget behavior `cap` (truncate with a warning); `wmAutoHandover` = on (at force, automatic handover: write doc + compact); the subagent hard cap = on (sharing 150k).
|
|
100
100
|
|
|
101
101
|
**Agent Teams**: `teamsMode` = off; `syncWhitelist` = off (the two toggles are independent of each other).
|
|
102
102
|
|
|
103
103
|
**Intent routing** (unavailable by default; needs a classifier + at least one candidate + the master switch on): `intentEnabled` = off (while off, the Auto entry stays hidden and sessions already on Auto fall through the fallback chain); the classifier route is unset; the classifier type is `chat`; the candidate list is empty (the preset categories join routing only once given a model); cache window `300` s / switch confidence threshold `80` / classification timeout `60000` ms; history `6` messages / `2400` characters; `intentContextWindow` = `200000`.
|
|
104
104
|
|
|
105
|
-
**Context trim**: `trimEnabled` = on; `trimMode` = `auto` (fully automatic); growth gate `22500` tokens + increment `
|
|
105
|
+
**Context trim**: `trimEnabled` = on; `trimMode` = `auto` (fully automatic); growth gate `22500` tokens + increment `25000` tokens; pressure `65%` / emergency `95%`; protected tail `10` messages; fold cadence cap `30` per hour; side model unset (inherits the session model); **ladder folding on** — T2 distills accumulated T1 summaries (8000-token mass, ≥3 blocks), T3 distills T2 (6000-token mass, ≥2 blocks); the engine never shows the model a water level, percentage, or progress number — details in the "Automatic context trim" section below and [docs/ladder-fold.md](./docs/ladder-fold.md).
|
|
106
106
|
|
|
107
|
-
**Out-of-the-box notes**: ① intent routing being unavailable out of the box is by design — three steps to switch it on (classifier, candidates, the master switch); ② Auto's effective window is 200000 out of the box — the guardrail guarantees 0.8×window ≥ force (150000), so the core compaction line (160000) always sits after the smooth-handover line (150000); ③ the most tangible out-of-the-box effect is the watermark trio: 80k nudges delegation /
|
|
107
|
+
**Out-of-the-box notes**: ① intent routing being unavailable out of the box is by design — three steps to switch it on (classifier, candidates, the master switch); ② Auto's effective window is 200000 out of the box — the guardrail guarantees 0.8×window ≥ force (150000), so the core compaction line (160000) always sits after the smooth-handover line (150000); ③ the most tangible out-of-the-box effect is the watermark trio: 80k nudges delegation / 95k tightens reading / 150k backs up and hands over automatically — no configuration needed.
|
|
108
108
|
|
|
109
109
|
## Automatic context trim
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
|
|
|
123
123
|
| `trimEnabled` | `true` | Master switch. OFF disables folding and metrics entirely (the listener degrades to a pure pass-through). |
|
|
124
124
|
| `trimMode` | `auto` | `off` measure only / `advisory` model-driven folds / `auto` system-driven folds. |
|
|
125
125
|
| `trimGrowthTokens` | `22500` | Growth gate: fold when the outbound view grew this much since the last fold. |
|
|
126
|
-
| `trimIncrementTokens` | `
|
|
127
|
-
| `trimPressurePercent` | `
|
|
126
|
+
| `trimIncrementTokens` | `25000` | Gate companion: the contiguous compressible increment must also reach this size. |
|
|
127
|
+
| `trimPressurePercent` | `65` | Pressure tier: fold when view usage reaches this percent of the context window. |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | Emergency tier: forced mechanical fold (no side-model call) at this percent. |
|
|
129
129
|
| `trimWindowTokens` | `0` | Effective-window cap for tier math: tiers are computed against min(model window, cap). `0` = follow `wmForceTokens`. |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | The last N messages are never folded. |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | Side-model fold cadence cap per rolling hour (emergency folds are exempt). |
|
|
132
132
|
| `trimSideModel` | unset | Route for the summary side model. Empty = inherit the session's current model. |
|
|
133
|
+
| `trimFoldFallbackModel` | unset | Route the fold retries on when the summary side model fails; a pressure fold then degrades to a mechanical one. Empty = no fallback leg. Pick a route with headroom on cooldowns, risk control, and concurrency limits. |
|
|
133
134
|
| `trimStateDir` | unset | Fold-state directory override. Empty = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
134
135
|
| `surfaceFold` | `true` | Ship committed folds onto the session surface (shadow-price + `surfaceOp` replace event pair). OFF keeps the splice-only view. |
|
|
135
136
|
|
|
136
137
|
**Trigger paths.** Tier checks run at the idle boundary and, as a fallback for hosts where idle status events are unreachable, after each model-stream completion (throttled to one evaluation per 60 s per session). Every decision — folds and no-ops alike — is appended as one timestamped `key=value` line to `decisions.log` in the trim state directory (see `trimStateDir`), giving folds an offline audit trail; the row vocabulary (`view-applied`, fold decision/outcome rows, `surface-replace`, `surface-replace skipped reason=…`) is catalogued in [docs/context-trim.md](./docs/context-trim.md).
|
|
137
138
|
|
|
138
|
-
**Wire truth and steady state.** Decision rows carry `view=<n>` and, once a response has landed, `wire=<n>` — the real provider prompt (uncached input + cache read + cache write, sampled from the stream's usage event). The view estimate counts the messages array only and always reads smaller than the wire by the fixed overhead (measured ≈ 17.3k: system prompt + tool schemas + persona), so pressure and emergency tiers evaluate on `max(view, wire)`, and only `wire` is a prompt-size reading. On a 150k window the healthy sawtooth runs wire ≈ 40k just after a fold ↔
|
|
139
|
+
**Wire truth and steady state.** Decision rows carry `view=<n>` and, once a response has landed, `wire=<n>` — the real provider prompt (uncached input + cache read + cache write, sampled from the stream's usage event). The view estimate counts the messages array only and always reads smaller than the wire by the fixed overhead (measured ≈ 17.3k: system prompt + tool schemas + persona), so pressure and emergency tiers evaluate on `max(view, wire)`, and only `wire` is a prompt-size reading. On a 150k window the healthy sawtooth runs wire ≈ 40k just after a fold ↔ 64–97.5k at the next one (≈27%–65% of the window), one fold per ~25k of raw growth, with the ceiling pinned near 97.5k by the pressure tier rather than by the window. If `view` climbs while no `surface-replace` row ever appears, read the skip rows (`incomplete-seqs`, `no-service`, `compaction-lock`).
|
|
139
140
|
|
|
140
141
|
**Host-compaction epochs.** Fold refs are anchored in message ids and content hashes, so a host-side compaction that replaces the re-send history ages the whole ledger out at once: no block locates, the view silently falls back to raw history (fail-open — the decision log records `view-applied applied=0`), and the plugin re-anchors its growth baseline at the post-compaction view on the next request. The host compaction is thus the backstop trim layer, and plugin folds do the fine-grained work within one host epoch. Some dispatches hand out fully frozen request arrays or option objects (the current agent loop deep-freezes assembled requests); for those `injectView` reports the outcome in the decision log: `nothing-to-apply` (no located fold blocks — raw history IS the view), `in-place`/`swapped` (the fold view shipped), or `none` (a fold existed but the frozen dispatch could not carry it — the wire ships raw history). **Surface replace is the shipping path when available** (`surfaceFold`, default on): at the serial `agent/turn-stopping` boundary plus an idle sweep, the plugin appends the host-style shadow-price metering event and ONE `user/message` replacement carrying `surfaceOp {op:'replace', startSeq, endSeq}` with `sourceEventSeqs` covering every shadowed surface node — the same mechanism the host's own compaction uses — so a committed fold reaches the wire from the source level, frozen dispatches included. While a session's recent dispatches log `none`, the view is meter-only: the watermark measures the provider-reported tally instead (so the force tier and the auto-handover keep working). Folding pauses only when the surface channel is unusable as well — a durable capability probe (live session exposing `append`/`surface.nodes`, no open compaction lock), never a recency window, so a restart no longer freezes the engine. The banner marks the line with `wire=raw` only when no fold block has ever shipped a surface replacement, so a session with a shipped block stays quiet across restarts; hosts without the surface mechanism (or with the flag off) keep exactly the legacy behavior.
|
|
141
142
|
|
|
@@ -143,6 +144,10 @@ All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
|
|
|
143
144
|
|
|
144
145
|
**Compaction arbitration.** Two automatic trimmers over one history would double-summarize and destroy each other's frontier, so `cordis.patch.yml` sets `auto: false` on the host's `dsh-compaction-basic` rows: context-trim becomes the single semantic trimmer. Manual `/compact` keeps working, and the force-tier handover (which borrows that same manual path) is untouched. Overflow recovery moves to trim: an over-window attempt fails once, then the emergency tier folds the view so the next attempt fits.
|
|
145
146
|
|
|
147
|
+
**The ladder (v1.11): T1/T2/T3 tiered folding.** Every raw-range fold produces a T1 block. As T1 summaries themselves accumulate (≥8000 tokens of summary mass across ≥3 blocks), the engine distills them into ONE T2 block; T2s condense into a T3 the same way — month-long sessions stop drifting upward, because the folded floor no longer grows with every fold. Consumed blocks deactivate (never deleted), so coverage stays expressible and the ledger stays inspectable. Distillation runs through the same side model, on its own 120 s cadence, mass-gated so it stays rare (each distill rewrites the wire from its anchor onward — the mass gates keep that cost rare on purpose).
|
|
148
|
+
|
|
149
|
+
**Nothing leaks to the model.** The engine never tells the session model a water level, a fill percentage, a window size, or a growth number — judgment stays rooted in the task (a model told "you're at 20%" anchors on "looks healthy" and refuses to fold). What the model MAY see, on demand, is `ctx_trim_status`: concrete compressible ranges with their true sizes. All metering lives in `decisions.log` and the settings-page badge — human channels.
|
|
150
|
+
|
|
146
151
|
**Fork inheritance.** A forked session (a subagent fork) inherits the parent's fold state copy-on-fork — but only when the parent state exists and the child's history actually resolves the parent's frontier; otherwise the child starts clean. One inheritance per child, idempotent across restarts.
|
|
147
152
|
|
|
148
153
|
**The watermark reads the view.** The watermark banner reports the outbound view's token count (what the model actually sees after folding) instead of the stored tally, so a heavily folded session no longer pins the watermark at the hard tier.
|
|
@@ -161,6 +166,10 @@ All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
|
|
|
161
166
|
- `npm pack --dry-run` should keep the audited 60-file / ~380 kB tarball shape (~1.26 MB unpacked). `docs/` stays out of the package (it is not in `package.json files`), while the 11 `README.*` translations are always shipped by npm.
|
|
162
167
|
- **Zero runtime dependencies — a hard invariant.** Host-plane packages (`@deepseek-ai/schemastery`, cordis, …) are declared as `peerDependencies` only, and the running DSH satisfies them from its own copy. An ordinary `dependencies` entry is physically installed into the profile workspace (`<profile>/node_modules/…`), where it shadows the host's copy for every other profile-resident plugin — this is exactly what crashed the dshmarket plugin market while 1.7.0 carried schemastery as a dependency (two schemastery instances in one process; the market's schemas no longer matched the host's). `scripts/validate.mjs` fails if a `dependencies` entry ever reappears, so installing, updating, or removing dsh-switchman can never touch what dshmarket or any other community bundle resolves at runtime.
|
|
163
168
|
|
|
169
|
+
## Acknowledgments
|
|
170
|
+
|
|
171
|
+
The tiered folding design (T1/T2/T3) was inspired by [billion-context](https://github.com/ranxianglei/billion-context) — thank you for open-sourcing the idea.
|
|
172
|
+
|
|
164
173
|
## License
|
|
165
174
|
|
|
166
175
|
MIT
|
package/README.pt.md
CHANGED
|
@@ -14,7 +14,7 @@ Se você trabalha com o DSH, com o tempo esbarra em duas coisas: a sessão fica
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman é um plugin para o [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Depois de instalado, o modelo principal deixa de “fazer tudo sozinho” e vira um dispatcher: mede o nível de água, escolhe a faixa, entrega as tarefas, confere o resultado. Não é um modelo novo: é um regulamento de despacho plugado ao DSH mais uma interface de configuração. Em concreto, ele faz oito coisas:
|
|
16
16
|
|
|
17
|
-
**1. Nível de água do contexto: sessões longas não estouram.** A cada turno ele conta os tokens da sessão em tempo real, e três limiares apertam em degraus: 80k (soft, ajustável) lembra que “é hora de delegar”;
|
|
17
|
+
**1. Nível de água do contexto: sessões longas não estouram.** A cada turno ele conta os tokens da sessão em tempo real, e três limiares apertam em degraus: 80k (soft, ajustável) lembra que “é hora de delegar”; 95k (hard) aperta o orçamento de leitura por chamada e empurra para encerrar; 150k (force) dispara o handover automático — escrita do documento de handover (o log de sessão append-only é a cópia completa), contexto compactado, sessão despertada para continuar: a tarefa não cai no meio. Nem os subagents em segundo plano que ainda estiverem rodando no momento da entrega se perdem: id, descrição da tarefa e caminho do relatório vão para o documento de handover, e a sessão retomada sabe onde coletar os relatórios em vez de despachar o mesmo trabalho de novo. Cada subagent enviado carrega um teto próprio e independente e, ao atingi-lo, sai depois de escrever o resumo HANDOFF. Se a intervenção automática não estiver do seu jeito, assuma o comando manualmente a qualquer momento: `/ctx-pause` interrompe todas as ações do nível (a medição continua rodando, a linha de nível de água ao vivo do final muda para paused — só deixa de agir), `/ctx-resume` retoma a qualquer momento — depois de reiniciar o DSH a intervenção também volta sozinha, você tira o pé por um tempo, não desliga de vez; `/ctx-handover` não espera o nível encher e dispara sob demanda o mesmo handover: escrita do documento de handover, compactação do contexto, despertar da sessão para continuar (a sessão é conduzida primeiro até o limite de inatividade, então o resultado pode demorar alguns minutos).
|
|
18
18
|
|
|
19
19
|
**2. Seis pools de despacho: a cada trabalho, o seu modelo.** Pool leve (economy, trabalho pequeno em lote), pool mecânico (mechanical, reescritas de molde), pool principal (main, codificação do dia a dia), pool difícil (hard, raciocínio pesado e refatoração em grande escala), pool multimodal (vision, leitura de imagens), pool de revisão (review, verificação independente). Na página de configurações você marca os candidatos, ordena as prioridades (com níveis opcionais S/A/B/C) e fixa um reasoning effort por rota — o dropdown lista os níveis que aquele modelo realmente suporta, não três níveis genéricos. A cada turno, o prompt do modelo principal carrega uma tabela de recomendações `[SWITCHMAN:POOLS]`: o trabalho é despachado seguindo a tabela. O modo de execução tem três estados: off / advice / enforce (enforce = modelos fora do pool são recusados na hora).
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ Só um modelo? Ainda vale a pena instalar — o controle do nível de água e a
|
|
|
86
86
|
bash <install-dir>/skills/db-query/scripts/setup.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
**Dicas de escolha do classificador:** para rodar o modelo de decisão localmente, o recomendado é servir `
|
|
89
|
+
**Dicas de escolha do classificador:** para rodar o modelo de decisão localmente, o recomendado é servir `d3:4b-mxfp8` com Ollama: escolha o tipo de classificador “endpoint de decisão (systemone)”, preencha o endpoint com `http://127.0.0.1:11434/v1/systemone` e coloque `d3:4b-mxfp8` como nome do modelo. Se preferir o classificador de chat do catálogo LLM, aposte em um modelo pequeno na nuvem, ou em um modelo local pequeno sem capacidade de pensamento (raciocínio): desligar o pensamento reduz ao mesmo tempo a latência e a taxa de falhas por timeout de classificação.
|
|
90
90
|
|
|
91
91
|
## Configuração padrão
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ Estes são todos os valores logo depois de uma instalação nova (fonte autorita
|
|
|
96
96
|
|
|
97
97
|
**Pools de despacho**: as seis faixas (economy/mechanical/main/hard/vision/review) começam sem candidatos (= os modelos padrão do sistema, sem intervenção); ordem manual e effort fixado desligados/vazios; `dispatchEnforce` = `advice` (só aconselha, não obriga).
|
|
98
98
|
|
|
99
|
-
**Nível de água do contexto**: soft `80000` / hard `
|
|
99
|
+
**Nível de água do contexto**: soft `80000` / hard `95000` / force `150000` tokens; orçamento de leitura por chamada `3000`; comportamento ao estourar o orçamento `cap` (corta e avisa); `wmAutoHandover` = ligado (no force, escrita do documento de handover + compactação automáticas); o teto dos subagents = ligado (150k compartilhadas).
|
|
100
100
|
|
|
101
101
|
**Agent Teams**: `teamsMode` = desligado; `syncWhitelist` = desligado (as duas chaves são independentes entre si).
|
|
102
102
|
|
|
103
103
|
**Roteamento por intenção** (indisponível por padrão; são precisos classificador + pelo menos um candidato + ligar a chave mestra): `intentEnabled` = desligado (desligado, a entrada Auto fica oculta e as sessões que já a tinham escolhido caem na cadeia de fallback); rota do classificador sem definir; tipo de classificador `chat`; lista de candidatos vazia (as categorias pré-instaladas só entram no roteamento com um modelo preenchido); janela de cache `300` s / limiar de confiança da troca `80` / timeout de classificação `60000` ms; histórico de `6` mensagens / `2400` caracteres; `intentContextWindow` = `200000`.
|
|
104
104
|
|
|
105
|
-
**Trim de contexto**: `trimEnabled` = ligado; `trimMode` = `auto` (totalmente automático); portão de crescimento `22500` + incremento `
|
|
105
|
+
**Trim de contexto**: `trimEnabled` = ligado; `trimMode` = `auto` (totalmente automático); portão de crescimento `22500` + incremento `25000` tokens; pressão `65%` / emergência `95%`; cauda protegida `10` mensagens; teto de cadência de folds `30` por hora; modelo secundário não definido (herda o modelo da sessão) — detalhes na seção «Trim automático do contexto» abaixo.
|
|
106
106
|
|
|
107
|
-
**Observações de fábrica**: ① o roteamento por intenção vir indisponível de fábrica é proposital — três passos para ligar (classificador, candidatos, chave); ② a janela efetiva do Auto já nasce em 200000 — o guard-rail garante 0.8×janela ≥ force (150000), então a linha de compactação do núcleo (160000) fica sempre depois da linha de entrega suave (150000); ③ o que mais se sente de fábrica é o trio de níveis: 80k lembra de delegar /
|
|
107
|
+
**Observações de fábrica**: ① o roteamento por intenção vir indisponível de fábrica é proposital — três passos para ligar (classificador, candidatos, chave); ② a janela efetiva do Auto já nasce em 200000 — o guard-rail garante 0.8×janela ≥ force (150000), então a linha de compactação do núcleo (160000) fica sempre depois da linha de entrega suave (150000); ③ o que mais se sente de fábrica é o trio de níveis: 80k lembra de delegar / 95k aperta a leitura / 150k entrega sozinho (documento + compactação) — sem nenhuma configuração.
|
|
108
108
|
|
|
109
109
|
## Trim automático do contexto
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ Todas as chaves ficam em Configurações → dsh-switchman; os padrões vêm de
|
|
|
123
123
|
| `trimEnabled` | `true` | Chave mestra. Desligado desativa folds e métricas por completo (o listener degrada a puro pass-through). |
|
|
124
124
|
| `trimMode` | `auto` | `off` só medição / `advisory` folds conduzidos pelo modelo / `auto` folds conduzidos pelo sistema. |
|
|
125
125
|
| `trimGrowthTokens` | `22500` | Portão de crescimento: dobra quando a view de saída crescer isso desde o último fold. |
|
|
126
|
-
| `trimIncrementTokens` | `
|
|
127
|
-
| `trimPressurePercent` | `
|
|
126
|
+
| `trimIncrementTokens` | `25000` | Companheiro do portão: o incremento comprimível contíguo também precisa alcançar esse tamanho. |
|
|
127
|
+
| `trimPressurePercent` | `65` | Degrau de pressão: dobra quando o uso da view alcança essa porcentagem da janela de contexto. |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | Degrau de emergência: fold mecânico forçado (sem chamada ao modelo secundário) nessa porcentagem. |
|
|
129
129
|
| `trimWindowTokens` | `0` | Limite de janela efetivo para o cálculo dos níveis: calculado sobre min(janela do modelo, limite). `0` = segue `wmForceTokens`. |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | As últimas N mensagens nunca são dobradas. |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | Teto de cadência de folds por hora rolante para o modelo secundário (os de emergência ficam fora). |
|
|
132
132
|
| `trimSideModel` | não definida | Rota do modelo secundário que escreve os resumos. Vazia = herdar o modelo atual da sessão. |
|
|
133
|
+
| `trimFoldFallbackModel` | não definida | Rota de nova tentativa quando o modelo secundário de resumos falha; um fold de pressão degrada então para mecânico. Vazia = sem fallback. Escolha uma rota com folga em cooldowns, controle de risco e concorrência. |
|
|
133
134
|
| `trimStateDir` | não definido | Sobrepõe o diretório do estado de folds. Vazio = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
134
135
|
| `surfaceFold` | `true` | Envia os folds confirmados para a superfície da sessão (par de eventos: medição shadow-price + replace com `surfaceOp`). OFF mantém a view apenas com splices. |
|
|
135
136
|
|
|
136
137
|
**Caminhos do gatilho.** As verificações de degraus rodam na fronteira de ociosidade e, como fallback para hosts onde os eventos de estado de ociosidade são inalcançáveis, após cada conclusão do fluxo do modelo (limitadas a uma avaliação a cada 60 s por sessão). Cada decisão — folds e no-ops igualmente — é anexada como uma linha `key=value` com timestamp a `decisions.log` no diretório do estado de folds (veja `trimStateDir`), dando aos folds uma trilha de auditoria offline; o vocabulário de linhas (`view-applied`, linhas de decisão/resultado de folds, `surface-replace`, `surface-replace skipped reason=…`) está catalogado em [docs/context-trim.md](./docs/context-trim.md).
|
|
137
138
|
|
|
138
|
-
**Verdade do fio e estado estacionário.** As linhas de decisão carregam `view=<n>` e, depois que uma resposta chega, `wire=<n>` — o prompt real do provedor (entrada sem cache + leitura de cache + escrita de cache, amostrado do evento de uso do stream). A estimativa da view conta apenas o array de mensagens e sempre lê menos que o fio, pelo overhead fixo (medido ≈ 17.3k: system prompt + esquemas de ferramentas + persona), então os degraus de pressão e de emergência avaliam sobre `max(view, wire)`, e só `wire` é uma leitura do tamanho do prompt. Numa janela de 150k o dente-de-serra saudável deixa o fio em ≈ 40k logo após um fold ↔
|
|
139
|
+
**Verdade do fio e estado estacionário.** As linhas de decisão carregam `view=<n>` e, depois que uma resposta chega, `wire=<n>` — o prompt real do provedor (entrada sem cache + leitura de cache + escrita de cache, amostrado do evento de uso do stream). A estimativa da view conta apenas o array de mensagens e sempre lê menos que o fio, pelo overhead fixo (medido ≈ 17.3k: system prompt + esquemas de ferramentas + persona), então os degraus de pressão e de emergência avaliam sobre `max(view, wire)`, e só `wire` é uma leitura do tamanho do prompt. Numa janela de 150k o dente-de-serra saudável deixa o fio em ≈ 40k logo após um fold ↔ 64–97.5k no seguinte (≈27%–65% da janela), um fold a cada ~25k de crescimento bruto, com o teto fixado perto de 97.5k pelo degrau de pressão em vez da janela. Se `view` sobe sem que nenhuma linha `surface-replace` apareça, leia as linhas de salto (`incomplete-seqs`, `no-service`, `compaction-lock`).
|
|
139
140
|
|
|
140
141
|
**Épocas de compactação do host.** As referências de fold são ancoradas em ids de mensagens e hashes de conteúdo; quando o próprio host compacta o histórico reenviado, o livro inteiro envelhece de uma vez: nenhum bloco se localiza, a view retrocede silenciosamente ao histórico bruto (fail-open — o registro de decisões anota `view-applied applied=0`) e o plugin reancora sua linha de base de crescimento na view pós-compactação na requisição seguinte. A compactação do host é, assim, a camada de aparo de último recurso; os folds do plugin fazem o trabalho fino dentro de uma época do host. Alguns despachos entregam arrays de solicitação ou objetos de opções totalmente congelados (o laço de agente atual congela em profundidade as requisições montadas); para eles, o `injectView` informa o resultado no registro de decisões: `nothing-to-apply` (nenhum bloco de fold localizado — o histórico bruto É a view), `in-place`/`swapped` (a view dobrada seguiu com a requisição) ou `none` (havia um fold, mas o despacho congelado não podia carregá-lo — o histórico bruto segue pelo fio). **A substituição de superfície é o caminho de envio quando disponível** (`surfaceFold`, ativado por padrão): na fronteira serial `agent/turn-stopping` mais uma varredura de ociosidade, o plugin anexa o evento de medição shadow-price no estilo do host e UM replacement `user/message` carregando `surfaceOp {op:'replace', startSeq, endSeq}` com `sourceEventSeqs` cobrindo cada nó de superfície sombreado — o mesmo mecanismo que a própria compactação do host usa —, de modo que um fold confirmado chega ao fio a partir do nível de origem, despachos congelados incluídos. Enquanto os despachos recentes de uma sessão registram `none`, o plugin trata a view como somente medição: o nível de água mede em vez disso a contagem relatada pelo provedor (o degrau force e a entrega automática continuam funcionando), os ciclos de fold pausam em vez de queimar chamadas ao resumidor, e o banner de aparo marca a linha com `wire=raw` (folds not shipping; watermark reads the tally); hosts sem o mecanismo de superfície (ou com a flag desligada) mantêm exatamente esse comportamento antigo.
|
|
141
142
|
|
package/README.ru.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman — плагин для [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). После установки главная модель перестаёт «делать всё сама» и становится диспетчером: замеряет уровень воды, выбирает полосу, раздаёт задачи, принимает работу. Это не новая модель, а свод правил диспетчеризации, пристёгнутый к DSH, плюс страница настроек. Конкретно он делает восемь вещей:
|
|
16
16
|
|
|
17
|
-
**1. Уровень воды в контексте: длинная сессия не переполняется.** Каждый ход подсчитывает токены сессии в реальном времени, и три линии уровня ужесточаются по нарастающей: 80k (soft, настраивается) подсказывает «пора делегировать»;
|
|
17
|
+
**1. Уровень воды в контексте: длинная сессия не переполняется.** Каждый ход подсчитывает токены сессии в реальном времени, и три линии уровня ужесточаются по нарастающей: 80k (soft, настраивается) подсказывает «пора делегировать»; 95k (hard) урезает бюджет разового чтения и подталкивает к завершению; 150k (force) запускает автоматическую передачу — записывает документ передачи (append-only лог сессии — сам по себе полная резервная копия), сжимает контекст и будит сессию, работа не обрывается. Фоновые субагенты, которые ещё бегут в момент передачи, тоже не теряются: id, описания задач и пути к отчётам записываются в документ передачи, и продолжившаяся сессия знает, куда идти за отчётами, а не раздаёт работу заново. У каждого отправленного субагента свой жёсткий потолок: доработав до него, он завершается резюме HANDOFF. Если автоматическое вмешательство работает не так, как вам нужно, возьмите управление в свои руки в любой момент: `/ctx-pause` останавливает все действия по уровню (замер продолжает работать, хвостовая строка уровня в реальном времени переключается на paused — вмешательство просто перестаёт действовать), `/ctx-resume` всё возвращает в любой момент — после перезапуска DSH вмешательство тоже вернётся само, вы временно отпускаете, а не выключаете навсегда; `/ctx-handover` не ждёт, пока уровень дойдёт до верха, и запускает ту же передачу по требованию — записать документ передачи, сжать контекст, разбудить сессию (сессию сначала подводят к границе простоя, поэтому результат может занять несколько минут).
|
|
18
18
|
|
|
19
19
|
**2. Шесть пулов диспетчеризации: под каждую работу — своя модель.** Лёгкий пул (economy — мелкие массовые задачи), механический (mechanical — шаблонные переработки), основной (main — повседневный кодинг), пул высокой сложности (hard — тяжёлые рассуждения и крупные рефакторинги), мультимодальный (vision — чтение картинок), пул ревью (review — независимая проверка). На странице настроек отмечаете кандидатов, расставляете приоритеты (можно с привязкой к ступеням S/A/B/C) и для каждого маршрута отдельно фиксируете reasoning effort — выпадающий список ступеней берётся из уровней, которые модель реально поддерживает, а не из трёх универсальных. Каждый ход промпт главной модели несёт с собой таблицу рекомендаций `[SWITCHMAN:POOLS]`, и работа раздаётся по ней. У режима исполнения три состояния: off / advice / enforce (enforce = модель вне пула просто отклоняется).
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ dsh-switchman — плагин для [DeepSeek Harness](https://github.com/deep
|
|
|
86
86
|
bash <install-dir>/skills/db-query/scripts/setup.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
**Рекомендации по выбору классификатора:** чтобы развернуть модель принятия решений локально, проще всего запустить `
|
|
89
|
+
**Рекомендации по выбору классификатора:** чтобы развернуть модель принятия решений локально, проще всего запустить `d3:4b-mxfp8` через Ollama: выберите тип классификатора «endpoint решений (systemone)», укажите в поле endpoint `http://127.0.0.1:11434/v1/systemone`, а в поле имени модели — `d3:4b-mxfp8`. Если использовать chat-классификатор из каталога LLM, берите небольшую облачную модель или небольшую локальную модель без режима размышления (reasoning) — отключение размышления снижает одновременно и задержку, и долю сбоев по таймауту классификации.
|
|
90
90
|
|
|
91
91
|
## Конфигурация по умолчанию
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ bash <install-dir>/skills/db-query/scripts/setup.sh
|
|
|
96
96
|
|
|
97
97
|
**Пулы диспетчеризации**: у всех шести полос (economy/mechanical/main/hard/vision/review) кандидаты пусты (= системные модели по умолчанию, без вмешательства); ручной порядок и закреплённый effort выключены/пусты; `dispatchEnforce` = `advice` (только совет, без принуждения).
|
|
98
98
|
|
|
99
|
-
**Уровень воды в контексте**: soft `80000` / hard `
|
|
99
|
+
**Уровень воды в контексте**: soft `80000` / hard `95000` / force `150000` токенов; бюджет разового чтения `3000`; поведение при превышении бюджета `cap` (обрезать с предупреждением); `wmAutoHandover` = включён (на force — запись документа передачи + сжатие автоматически); жёсткий потолок субагентов = включён (общие 150k).
|
|
100
100
|
|
|
101
101
|
**Agent Teams**: `teamsMode` = выключен; `syncWhitelist` = выключен (два переключателя независимы друг от друга).
|
|
102
102
|
|
|
103
103
|
**Маршрутизация по намерению** (по умолчанию недоступна; нужны классификатор + хотя бы один кандидат + включённый главный переключатель): `intentEnabled` = выключен (пока выключен, вход Auto скрыт, а сессии, где Auto уже выбран, идут по цепочке запасных моделей); маршрут классификатора не задан; тип классификатора `chat`; список кандидатов пуст (предустановленные категории участвуют в маршрутизации, только если у них указана модель); окно кэша `300` с / порог уверенности для переключения `80` / тайм-аут классификации `60000` мс; история `6` сообщений / `2400` символов; `intentContextWindow` = `200000`.
|
|
104
104
|
|
|
105
|
-
**Обрезка контекста**: `trimEnabled` = включено; `trimMode` = `auto` (полностью автоматически); ворота роста `22500` + прирост `
|
|
105
|
+
**Обрезка контекста**: `trimEnabled` = включено; `trimMode` = `auto` (полностью автоматически); ворота роста `22500` + прирост `25000` токенов; давление `65%` / авария `95%`; защищённый хвост `10` сообщений; потолок частоты fold-ов `30` в час; боковая модель не задана (наследует модель сессии) — подробности в разделе «Автоматическая обрезка контекста» ниже.
|
|
106
106
|
|
|
107
|
-
**Что важно знать из коробки**: ① то, что маршрутизация по намерению недоступна из коробки, — намеренное решение; включается в три шага (классификатор, кандидаты, переключатель); ② эффективное окно Auto из коробки равно 200000 — защитная планка гарантирует 0.8×окна ≥ force (150000), поэтому линия сжатия ядра (160000) всегда стоит после линии плавной передачи (150000); ③ заметнее всего из коробки троица уровней: 80k напоминает делегировать /
|
|
107
|
+
**Что важно знать из коробки**: ① то, что маршрутизация по намерению недоступна из коробки, — намеренное решение; включается в три шага (классификатор, кандидаты, переключатель); ② эффективное окно Auto из коробки равно 200000 — защитная планка гарантирует 0.8×окна ≥ force (150000), поэтому линия сжатия ядра (160000) всегда стоит после линии плавной передачи (150000); ③ заметнее всего из коробки троица уровней: 80k напоминает делегировать / 95k ужимает чтение / 150k сам передаёт управление (документ + сжатие) — без каких-либо настроек.
|
|
108
108
|
|
|
109
109
|
## Автоматическая обрезка контекста
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ bash <install-dir>/skills/db-query/scripts/setup.sh
|
|
|
123
123
|
| `trimEnabled` | `true` | Главный выключатель. ВЫКЛ полностью отключает fold-ы и метрики (слушатель вырождается в чистый pass-through). |
|
|
124
124
|
| `trimMode` | `auto` | `off` только измерения / `advisory` fold-ы по решению модели / `auto` fold-ы по решению системы. |
|
|
125
125
|
| `trimGrowthTokens` | `22500` | Ворота роста: fold, когда исходящая view выросла на столько с прошлого fold-а. |
|
|
126
|
-
| `trimIncrementTokens` | `
|
|
127
|
-
| `trimPressurePercent` | `
|
|
126
|
+
| `trimIncrementTokens` | `25000` | Спутник ворот: непрерывный сжимаемый прирост тоже должен достичь этого размера. |
|
|
127
|
+
| `trimPressurePercent` | `65` | Ступень давления: fold, когда использование view достигает этого процента окна контекста. |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | Аварийная ступень: принудительный механический fold (без вызова боковой модели) на этом проценте. |
|
|
129
129
|
| `trimWindowTokens` | `0` | Эффективный лимит окна для расчёта уровней: считается от min(окно модели, лимит). `0` = следует за `wmForceTokens`. |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | Последние N сообщений никогда не сворачиваются. |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | Потолок частоты fold-ов боковой модели за скользящий час (аварийные не в счёт). |
|
|
132
132
|
| `trimSideModel` | не задан | Маршрут боковой модели, пишущей резюме. Пусто = унаследовать текущую модель сессии. |
|
|
133
|
+
| `trimFoldFallbackModel` | не задан | Маршрут повторной попытки, если боковая модель резюме не сработала; pressure-fold затем деградирует до механического. Пусто = без резерва. Выбирайте маршрут с запасом по кулдаунам, риск-контролю и параллелизму. |
|
|
133
134
|
| `trimStateDir` | не задан | Переопределяет каталог состояния fold-ов. Пусто = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
134
135
|
| `surfaceFold` | `true` | Доставляет зафиксированные fold-ы на поверхность сессии (пара событий: учёт shadow-price + replace с `surfaceOp`). OFF оставляет view только со сплайсами. |
|
|
135
136
|
|
|
136
137
|
**Пути срабатывания.** Проверки ступеней выполняются на границе простоя и — как запасной путь для хостов, где события статуса простоя недостижимы — после завершения каждого потока модели (не чаще одной оценки в 60 с на сессию). Каждое решение — и fold-ы, и no-op-ы — дописывается одной строкой `key=value` (с отметкой времени) в `decisions.log` внутри каталога состояния fold-ов (см. `trimStateDir`), что даёт fold-ам офлайн-журнал аудита; словарь строк (`view-applied`, строки решений/исходов fold-ов, `surface-replace`, `surface-replace skipped reason=…`) перечислен в [docs/context-trim.md](./docs/context-trim.md).
|
|
137
138
|
|
|
138
|
-
**Правда провода и установившийся режим.** Строки решений несут `view=<n>` и, после того как ответ пришёл, `wire=<n>` — реальный промпт провайдера (некэшированный вход + чтение кэша + запись кэша, сэмплированные из usage-события потока). Оценка view считает только массив сообщений и всегда читается меньше провода на фиксированный оверхед (измерено ≈ 17.3k: системный промпт + схемы инструментов + persona), поэтому ступени давления и аварии оценивают по `max(view, wire)`, и только `wire` — это измерение размера промпта. На окне 150k здоровая пилообразная кривая ведёт провод от ≈ 40k сразу после fold ↔
|
|
139
|
+
**Правда провода и установившийся режим.** Строки решений несут `view=<n>` и, после того как ответ пришёл, `wire=<n>` — реальный промпт провайдера (некэшированный вход + чтение кэша + запись кэша, сэмплированные из usage-события потока). Оценка view считает только массив сообщений и всегда читается меньше провода на фиксированный оверхед (измерено ≈ 17.3k: системный промпт + схемы инструментов + persona), поэтому ступени давления и аварии оценивают по `max(view, wire)`, и только `wire` — это измерение размера промпта. На окне 150k здоровая пилообразная кривая ведёт провод от ≈ 40k сразу после fold ↔ 64–97.5k на следующем (≈27%–65% окна), один fold на ~25k сырого прироста, причём потолок удерживается около 97.5k ступенью давления, а не окном. Если `view` растёт, а строка `surface-replace` так и не появляется, читайте строки пропуска (`incomplete-seqs`, `no-service`, `compaction-lock`).
|
|
139
140
|
|
|
140
141
|
**Эпохи сжатия на стороне хоста.** Ссылки fold привязаны к идентификаторам сообщений и хешам содержимого, поэтому сжатие, выполненное самим хостом и заменяющее повторно отправляемую историю, старит весь журнал разом: ни один блок не находит своей позиции, view молча откатывается к исходной истории (fail-open — в журнал решений записывается `view-applied applied=0`), а плагин при следующем запросе перепривязывает базовую линию роста к виду после сжатия. Таким образом, сжатие хоста — запасной слой обрезки последней инстанции, а fold плагина выполняет тонкую работу внутри одной эпохи хоста. Некоторые диспетчеры передают полностью замороженные массивы запросов или объекты опций (текущий агентный луп глубоко замораживает собранные запросы); для них `injectView` фиксирует исход в журнале решений: `nothing-to-apply` (ни одного найденного fold-блока — сырая история и ЕСТЬ view), `in-place`/`swapped` (свёрнутое представление ушло с запросом) или `none` (fold существовал, но замороженный диспетчер не смог его нести — по проводу идёт сырая история). **Surface replace — путь доставки, когда он доступен** (`surfaceFold`, по умолчанию включён): на серийной границе `agent/turn-stopping` плюс холостая проходка плагин дописывает хост-стильное событие учёта shadow-price и ОДНО замещающее событие `user/message` с `surfaceOp {op:'replace', startSeq, endSeq}`, где `sourceEventSeqs` покрывает каждый затенённый узел поверхности, — тот же механизм, которым пользуется сжатие самого хоста, — так что зафиксированный fold доходит до провода с уровня источника, замороженные диспетчеры включительно. Пока недавние диспетчеры сессии пишут `none`, плагин считает view чисто измерительным: уровень воды вместо этого меряет присланную провайдером сумму (ступень force и автоматическая передача продолжают работать), циклы fold-ов приостанавливаются, не сжигая вызовы суммаризатора, а баннер обрезки помечает строку `wire=raw` (folds not shipping; watermark reads the tally); хосты без surface-механизма (или с выключенным флагом) сохраняют ровно это прежнее поведение.
|
|
141
142
|
|
package/README.zh-TW.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman 是一個 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)外掛。裝上之後,主模型從「親自幹活」變成調度員:量水位、選車道、派任務、盯驗收。它不是新模型,是一套掛在 DSH 上的調度規程加一個設定頁,一共做八件事:
|
|
16
16
|
|
|
17
|
-
**1. 上下文水位:長對話不撐爆。** 每輪即時統計對話 token,三條水位線逐級加碼:80k(soft,可調)提醒「該委派了」;
|
|
17
|
+
**1. 上下文水位:長對話不撐爆。** 每輪即時統計對話 token,三條水位線逐級加碼:80k(soft,可調)提醒「該委派了」;95k(hard)收緊單次讀取預算、引導收尾;150k(force)自動交接——寫交接文件(附加式對話日誌本身就是完整備份)、壓縮上下文、喚醒續跑,任務不斷線。交接那一刻還在跑的背景子代理也不會丟:id、任務、報告路徑都寫進交接文件,續跑的對話知道去哪收報告,不會重複派工。每個子代理自帶獨立硬上限,到頂寫完 HANDOFF 摘要退場。自動干預不合手時可臨時接管:`/ctx-pause` 停掉全部水位動作(量測照跑、尾部水位線轉成 paused,只是不動手),`/ctx-resume` 隨時恢復——重新啟動 DSH 後干預也會自動回來,是臨時放手,不是永久關閉;`/ctx-handover` 不等水位到頂,主動發起同一次交接:寫交接文件、壓縮上下文、喚醒續跑(對話先被引導到閒置邊界,結果可能要等幾分鐘)。
|
|
18
18
|
|
|
19
19
|
**2. 六個派發池:什麼活配什麼模型。** 輕量池(批次小活)、機械池(模板化改寫)、主力池(日常編碼)、高難池(高難推理與大規模重構)、多模態池(看圖)、複審池(獨立驗證)。設定頁裡勾候選、排優先順序、標 S/A/B/C 級,還能給每條路線單獨釘選思考強度——強度下拉來自該模型真實支援的級別,不是通用三級。主模型每輪提示詞裡都帶著一張 `[SWITCHMAN:POOLS]` 推薦表,照表派工。執行模式三態:關閉 / 建議 / 強制(強制 = 池外模型直接拒絕)。
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ dsh-switchman 是一個 [DeepSeek Harness](https://github.com/deepseek-ai/deepse
|
|
|
86
86
|
bash <安裝目錄>/skills/db-query/scripts/setup.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
**分類器選型建議**:若要在本機部署決策模型,建議用 Ollama 執行 `
|
|
89
|
+
**分類器選型建議**:若要在本機部署決策模型,建議用 Ollama 執行 `d3:4b-mxfp8`:分類器類型選「決策端點(systemone)」,端點填 `http://127.0.0.1:11434/v1/systemone`,模型名稱填 `d3:4b-mxfp8`。若走 LLM 目錄的 chat 分類器,建議選雲端小模型,或不帶思考(推理)能力的本機小模型——關閉思考可同時壓低延遲與分類逾時失敗率。
|
|
90
90
|
|
|
91
91
|
## 預設配置
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ bash <安裝目錄>/skills/db-query/scripts/setup.sh
|
|
|
96
96
|
|
|
97
97
|
**派發池**:六條泳道(economy/mechanical/main/hard/vision/review)候選均為空(= 用系統預設模型,不干預);手動排序與 effort 釘選均為關/空;`dispatchEnforce` = `advice`(建議不強制)。
|
|
98
98
|
|
|
99
|
-
**上下文水位**:soft `80000` / hard `
|
|
99
|
+
**上下文水位**:soft `80000` / hard `95000` / force `150000` tokens;單次讀取預算 `3000`;超預算行為 `cap`(截斷加警告);`wmAutoHandover` = 開(force 級自動寫交接文件+壓縮);子代理硬上限 = 開(共享 150k)。
|
|
100
100
|
|
|
101
101
|
**Agent Teams**:`teamsMode` = 關;`syncWhitelist` = 關(兩者相互獨立)。
|
|
102
102
|
|
|
103
103
|
**意圖識別**(預設不可用,需設定分類器 + 至少一個候選 + 打開主開關):`intentEnabled` = 關(關閉時 Auto 入口隱藏,已選 Auto 的對話走備援鏈);分類器路由未設定;分類器類型 `chat`;候選清單空(預置分類需填模型才參與路由);快取視窗 `300` 秒 / 切換信心閾值 `80` / 分類逾時 `60000` ms;歷史 `6` 則 / `2400` 字元;`intentContextWindow` = `200000`。
|
|
104
104
|
|
|
105
|
-
**上下文裁剪**:`trimEnabled` = 開;`trimMode` = `auto`(全自動);增長閘門 `22500` token + 增量 `
|
|
105
|
+
**上下文裁剪**:`trimEnabled` = 開;`trimMode` = `auto`(全自動);增長閘門 `22500` token + 增量 `25000` token;壓力 `65%` / 緊急 `95%`;保護尾部 `10` 則;折疊節奏上限每小時 `30` 次;side model 未設定(繼承對話模型)——詳見下文「自動上下文裁剪」一節。
|
|
106
106
|
|
|
107
|
-
**開箱要點**:① 意圖識別開箱不可用是有意設計,三步開啟(分類器、候選、開關);② Auto 有效視窗開箱即為 200000——護欄保證 0.8×視窗 ≥ force 級(150000),核心壓縮線(160000)永遠在平滑交接線(150000)之後;③ 開箱最有感的是水位三件套:80k 提醒委派 /
|
|
107
|
+
**開箱要點**:① 意圖識別開箱不可用是有意設計,三步開啟(分類器、候選、開關);② Auto 有效視窗開箱即為 200000——護欄保證 0.8×視窗 ≥ force 級(150000),核心壓縮線(160000)永遠在平滑交接線(150000)之後;③ 開箱最有感的是水位三件套:80k 提醒委派 / 95k 收斂讀取 / 150k 自動交接(寫文件+壓縮),無須任何設定。
|
|
108
108
|
|
|
109
109
|
## 自動上下文裁剪
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ bash <安裝目錄>/skills/db-query/scripts/setup.sh
|
|
|
123
123
|
| `trimEnabled` | `true` | 總開關。關閉後折疊與度量全部停用(監聽器退化為純透傳)。 |
|
|
124
124
|
| `trimMode` | `auto` | `off` 只測量 / `advisory` 模型自折 / `auto` 系統自動折。 |
|
|
125
125
|
| `trimGrowthTokens` | `22500` | 增長閘門:出站 view 自上次 fold 以來增長到該值即觸發折疊。 |
|
|
126
|
-
| `trimIncrementTokens` | `
|
|
127
|
-
| `trimPressurePercent` | `
|
|
126
|
+
| `trimIncrementTokens` | `25000` | 閘門搭檔:連續可壓縮增量也須達到該規模。 |
|
|
127
|
+
| `trimPressurePercent` | `65` | 壓力級:view 用量達到上下文視窗該百分比即折疊。 |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | 緊急級:到該百分比強制機械折疊(無 side model 呼叫)。 |
|
|
129
129
|
| `trimWindowTokens` | `0` | 視窗上限:壓力與緊急檔按 min(模型視窗, 上限) 計算。`0` = 跟隨 `wmForceTokens`。 |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | 最後 N 則訊息永不折疊。 |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | 每滾動小時 side model 折疊的節奏上限(緊急級豁免)。 |
|
|
132
132
|
| `trimSideModel` | 未設定 | 寫摘要的 side model 路由。留空 = 繼承對話目前模型。 |
|
|
133
|
+
| `trimFoldFallbackModel` | 未設定 | 摘要 side model 失敗時摺疊改用的重試路由;壓力檔仍失敗則退回機械摺疊。留空 = 無備援。盡量選擇冷卻、風控與並行餘量充足的路由。 |
|
|
133
134
|
| `trimStateDir` | 未設定 | 折疊狀態目錄覆蓋。留空 = `<dshHome>/.dsh-switchman/state/trim/`。 |
|
|
134
135
|
| `surfaceFold` | `true` | 把已提交的 fold 送上對話表面(shadow-price 計量事件 + `surfaceOp` replace 事件對)。關閉則維持僅拼接的 view。 |
|
|
135
136
|
|
|
136
137
|
**觸發路徑。** 級別檢查在閒置邊界上執行;在閒置狀態事件不可達的宿主上,兜底改為在每次模型串流完成後也檢查一次(每個對話節流為每 60 秒至多評估一次)。每個決策——fold 與 no-op 皆然——都會作為一行帶時間戳的 `key=value` 附加進裁剪狀態目錄(見 `trimStateDir`)下的 `decisions.log`,為 fold 留下離線稽核軌跡;列詞彙(`view-applied`、fold 決策/結果列、`surface-replace`、`surface-replace skipped reason=…`)收錄於 [docs/context-trim.md](./docs/context-trim.md)。
|
|
137
138
|
|
|
138
|
-
**線上真值與穩態。** 決策列攜帶 `view=<n>`,回應落地後還會帶上 `wire=<n>`——真實的廠商提示詞(未快取輸入 + 快取讀取 + 快取寫入,從串流的 usage 事件取樣得到)。view 估算只統計 messages 陣列,而且總是比線上讀數小一個固定額外開銷(實測 ≈ 17.3k:系統提示詞 + 工具 schema + persona),所以壓力級與緊急級按 `max(view, wire)` 評估,只有 `wire` 才是提示詞大小的讀數。150k 視窗下,健康的鋸齒波在每次 fold 剛結束時線上 ≈ 40k ↔ 下次 fold 時
|
|
139
|
+
**線上真值與穩態。** 決策列攜帶 `view=<n>`,回應落地後還會帶上 `wire=<n>`——真實的廠商提示詞(未快取輸入 + 快取讀取 + 快取寫入,從串流的 usage 事件取樣得到)。view 估算只統計 messages 陣列,而且總是比線上讀數小一個固定額外開銷(實測 ≈ 17.3k:系統提示詞 + 工具 schema + persona),所以壓力級與緊急級按 `max(view, wire)` 評估,只有 `wire` 才是提示詞大小的讀數。150k 視窗下,健康的鋸齒波在每次 fold 剛結束時線上 ≈ 40k ↔ 下次 fold 時 64–97.5k(佔視窗的 ≈27%–65%),每 ~25k 原始增長折疊一次,上限由壓力級而非視窗釘在 97.5k 附近。若 `view` 持續攀升卻從不出現 `surface-replace` 列,就去讀跳過列(`incomplete-seqs`、`no-service`、`compaction-lock`)。
|
|
139
140
|
|
|
140
141
|
**宿主壓縮紀元。** fold 引用錨定在訊息 id 與內容雜湊上,因此宿主自身的壓縮一旦替換了重發歷史,整本帳就會同時老化:所有塊都無法定位,view 靜默回退為原始歷史(fail-open——決策日誌會記錄 `view-applied applied=0`),外掛在下一次請求時把增長基線重錨到壓縮後的視圖。宿主壓縮因此是兜底的裁剪層,外掛 fold 負責單一宿主紀元內的細粒度工作。 部分派發改用完全凍結的請求陣列或選項物件(目前的 agent loop 會深凍結裝配好的請求);對這類派發,`injectView` 會在決策日誌裡報告結果:`nothing-to-apply`(沒有定位到 fold 塊——原始歷史本身就是 view)、`in-place`/`swapped`(fold view 已隨請求送出)或 `none`(fold 存在但凍結的派發帶不動它——線上送出原始歷史)。**Surface replace 是可用時的發送路徑**(`surfaceFold`,預設開啟):在序列的 `agent/turn-stopping` 邊界外加一次閒置清掃,外掛追加宿主風格的 shadow-price 計量事件與一條攜帶 `surfaceOp {op:'replace', startSeq, endSeq}` 的 `user/message` 替換事件,`sourceEventSeqs` 覆蓋被遮蔽的每個表面節點——與宿主自身壓縮用的是同一機制——已提交的 fold 由此從源頭直達線上,凍結派發也不例外。當某對話近期派發都記錄 `none` 時,外掛把 view 當作僅供計量:水位改用服務商上報的計數(force 檔與自動交接照常運作),fold 循環暫停、不再空燒 summarizer 呼叫,裁剪橫幅以 `wire=raw`(folds not shipping; watermark reads the tally)標記該行;沒有 surface 機制的宿主(或開關關閉時)保持的正是這套舊行為。
|
|
141
142
|
|
package/README.zh.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman 是一个 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)插件。装上之后,主模型从「亲自干活」变成调度员:量水位、选车道、派任务、盯验收。它不是新模型,是一套挂在 DSH 上的调度规程加一个配置界面,一共做八件事:
|
|
16
16
|
|
|
17
|
-
**1. 上下文水位:长会话不撑爆。** 每轮实时统计会话 token,三条水位线逐级加码:80k(soft,可调)提醒「该委派了」;
|
|
17
|
+
**1. 上下文水位:长会话不撑爆。** 每轮实时统计会话 token,三条水位线逐级加码:80k(soft,可调)提醒「该委派了」;95k(hard)收紧单次读取预算、引导收尾;150k(force)自动交接——写交接文档(追加式会话日志本身就是完整备份)、压缩上下文、唤醒续跑,任务不断线。交接那一刻还在跑的后台子智能体也不会丢:id、任务、报告路径都写进交接文档,续跑的会话知道去哪收报告,不会重复派活。每个子智能体自带独立硬顶,到顶写完 HANDOFF 摘要退场。自动干预不合手时可临时接管:`/ctx-pause` 停掉全部水位动作(测量照跑、尾部水位行转成 paused,只是不动手),`/ctx-resume` 随时恢复——重启 DSH 后干预也会自动回来,是临时放手,不是永久关闭;`/ctx-handover` 不等水位到顶,主动发起同一次交接:写交接文档、压缩上下文、唤醒续跑(会话先被引导到空闲边界,结果可能要等几分钟)。
|
|
18
18
|
|
|
19
19
|
**2. 六个派发池:什么活配什么模型。** 轻量池(批量小活)、机械池(模板化改写)、主力池(日常编码)、高难池(高难推理与大规模重构)、多模态池(看图)、复审池(独立验证)。设置页里勾候选、排优先级、标 S/A/B/C 档,还能给每条路线单独钉思考强度——档位下拉来自该模型真实支持的级别,不是通用三档。主模型每轮提示词里都带着一张 `[SWITCHMAN:POOLS]` 推荐表,照表派活。执行模式三态:关闭 / 建议 / 强制(强制 = 池外模型直接拒绝)。
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ dsh-switchman 是一个 [DeepSeek Harness](https://github.com/deepseek-ai/deepse
|
|
|
86
86
|
bash <安装目录>/skills/db-query/scripts/setup.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
**分类器选型建议**:若要本地部署决策模型,推荐用 Ollama 运行 `
|
|
89
|
+
**分类器选型建议**:若要本地部署决策模型,推荐用 Ollama 运行 `d3:4b-mxfp8`:分类器类型选「决策端点(systemone)」,端点填 `http://127.0.0.1:11434/v1/systemone`,模型名填 `d3:4b-mxfp8`。若走 LLM 目录的 chat 分类器,推荐云端小模型,或不带思考(推理)能力的本地小模型——关闭思考可同时压低延迟与分类超时失败率。
|
|
90
90
|
|
|
91
91
|
## 默认配置
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ bash <安装目录>/skills/db-query/scripts/setup.sh
|
|
|
96
96
|
|
|
97
97
|
**派发池**:六条泳道(economy/mechanical/main/hard/vision/review)候选均为空(= 用系统默认模型,不干预);手动排序与 effort 钉选均为关/空;`dispatchEnforce` = `advice`(建议不强制)。
|
|
98
98
|
|
|
99
|
-
**上下文水位**:soft `80000` / hard `
|
|
99
|
+
**上下文水位**:soft `80000` / hard `95000` / force `150000` tokens;单次读取预算 `3000`;超预算行为 `cap`(截断加警告);`wmAutoHandover` = 开(force 档自动写交接文档+压缩);子会话硬顶 = 开(共享 150k)。
|
|
100
100
|
|
|
101
101
|
**Agent Teams**:`teamsMode` = 关;`syncWhitelist` = 关(两者相互独立)。
|
|
102
102
|
|
|
103
103
|
**意图识别**(默认不可用,需配置分类器 + 至少一个候选 + 打开主开关):`intentEnabled` = 关(关闭时 Auto 入口隐藏,已选 Auto 的会话走兜底链);分类器路由未设置;分类器类型 `chat`;候选列表空(预置分类需填模型才参与路由);缓存窗口 `300` 秒 / 切换置信度 `80` / 分类超时 `60000` ms;历史 `6` 条 / `2400` 字符;`intentContextWindow` = `200000`。
|
|
104
104
|
|
|
105
|
-
**上下文裁剪**:`trimEnabled` = 开;`trimMode` = `auto`(全自动);增长闸门 `22500` token + 增量 `
|
|
105
|
+
**上下文裁剪**:`trimEnabled` = 开;`trimMode` = `auto`(全自动);增长闸门 `22500` token + 增量 `25000` token;压力 `65%` / 紧急 `95%`;保护尾部 `10` 条;折叠节奏上限每小时 `30` 次;side model 未设置(继承会话模型)——详见下文「自动上下文裁剪」一节。
|
|
106
106
|
|
|
107
|
-
**开箱要点**:① 意图识别开箱不可用是有意设计,三步开启(分类器、候选、开关);② Auto 有效窗口开箱即为 200000——护栏保证 0.8×窗口 ≥ force 档(150000),核心压缩线(160000)永远在平滑交接线(150000)之后;③ 开箱最有感的是水位三件套:80k 提醒委派 /
|
|
107
|
+
**开箱要点**:① 意图识别开箱不可用是有意设计,三步开启(分类器、候选、开关);② Auto 有效窗口开箱即为 200000——护栏保证 0.8×窗口 ≥ force 档(150000),核心压缩线(160000)永远在平滑交接线(150000)之后;③ 开箱最有感的是水位三件套:80k 提醒委派 / 95k 收敛读取 / 150k 自动交接(写文档+压缩),无需任何设置。
|
|
108
108
|
|
|
109
109
|
## 自动上下文裁剪
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ bash <安装目录>/skills/db-query/scripts/setup.sh
|
|
|
123
123
|
| `trimEnabled` | `true` | 总开关。关闭后折叠与度量全部停用(监听器退化为纯透传)。 |
|
|
124
124
|
| `trimMode` | `auto` | `off` 只测量 / `advisory` 模型自折 / `auto` 系统自动折。 |
|
|
125
125
|
| `trimGrowthTokens` | `22500` | 增长闸门:出站 view 自上次 fold 以来增长到该值即触发折叠。 |
|
|
126
|
-
| `trimIncrementTokens` | `
|
|
127
|
-
| `trimPressurePercent` | `
|
|
126
|
+
| `trimIncrementTokens` | `25000` | 闸门搭档:连续可压缩增量也须达到该规模。 |
|
|
127
|
+
| `trimPressurePercent` | `65` | 压力档:view 用量达到上下文窗口该百分比即折叠。 |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | 紧急档:到该百分比强制机械折叠(无 side model 调用)。 |
|
|
129
129
|
| `trimWindowTokens` | `0` | 窗口上限:压力与紧急档按 min(模型窗口, 上限) 计算。`0` = 跟随 `wmForceTokens`。 |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | 最后 N 条消息永不折叠。 |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | 每滚动小时 side model 折叠的节奏上限(紧急档豁免)。 |
|
|
132
132
|
| `trimSideModel` | 未设置 | 写摘要的 side model 路由。留空 = 继承会话当前模型。 |
|
|
133
|
+
| `trimFoldFallbackModel` | 未设置 | 摘要 side model 失败时折叠改用的重试路由;压力档仍失败则退回机械折叠。留空 = 无兜底。尽量选择冷却、风控与并发余量充足的路由。 |
|
|
133
134
|
| `trimStateDir` | 未设置 | 折叠状态目录覆盖。留空 = `<dshHome>/.dsh-switchman/state/trim/`。 |
|
|
134
135
|
| `surfaceFold` | `true` | 把已提交的 fold 送上会话表面(shadow-price 计量事件 + `surfaceOp` replace 事件对)。关闭则保持仅拼接的 view。 |
|
|
135
136
|
|
|
136
137
|
**触发路径。** 档位检查在空闲边界上运行;在空闲状态事件不可达的宿主上,兜底改为在每次模型流式完成后也检查一次(每个会话节流为每 60 秒至多评估一次)。每个决策——fold 与 no-op 皆然——都以「ISO 时间戳 + `key=value` 字段」的形式追加一行到裁剪状态目录(见 `trimStateDir`)下的 `decisions.log`,为 fold 留下离线审计轨迹;行词汇(`view-applied`、fold 决策/结果行、`surface-replace`、`surface-replace skipped reason=…`)收录于 [docs/context-trim.md](./docs/context-trim.md)。
|
|
137
138
|
|
|
138
|
-
**线上真值与稳态。** 决策行携带 `view=<n>`,响应落地后还会带上 `wire=<n>`——真实的供应商提示词(未缓存输入 + 缓存读取 + 缓存写入,从流的 usage 事件采样得到)。view 估算只统计 messages 数组,并且总是比线上读数小一个固定开销(实测 ≈ 17.3k:系统提示词 + 工具 schema + persona),所以压力档与紧急档按 `max(view, wire)` 评估,只有 `wire` 才是提示词大小的读数。150k 窗口下,健康的锯齿波在每次 fold 刚结束时线上 ≈ 40k ↔ 下次 fold 时
|
|
139
|
+
**线上真值与稳态。** 决策行携带 `view=<n>`,响应落地后还会带上 `wire=<n>`——真实的供应商提示词(未缓存输入 + 缓存读取 + 缓存写入,从流的 usage 事件采样得到)。view 估算只统计 messages 数组,并且总是比线上读数小一个固定开销(实测 ≈ 17.3k:系统提示词 + 工具 schema + persona),所以压力档与紧急档按 `max(view, wire)` 评估,只有 `wire` 才是提示词大小的读数。150k 窗口下,健康的锯齿波在每次 fold 刚结束时线上 ≈ 40k ↔ 下次 fold 时 64–97.5k(占窗口的 ≈27%–65%),每 ~25k 原始增长折叠一次,上限由压力档而非窗口钉在 97.5k 附近。若 `view` 持续攀升却从不出现 `surface-replace` 行,就去读跳过行(`incomplete-seqs`、`no-service`、`compaction-lock`)。
|
|
139
140
|
|
|
140
141
|
**宿主压缩纪元。** fold 引用锚定在消息 id 与内容哈希上,因此宿主自身的压缩一旦替换了重发历史,整本账就会同时老化:所有块都无法定位,view 静默回退为原始历史(fail-open——决策日志会记录 `view-applied applied=0`),插件在下一次请求时把增长基线重锚到压缩后的视图。宿主压缩因此是兜底的裁剪层,插件 fold 负责单个宿主纪元内的细粒度工作。 部分派发改用完全冻结的请求数组或选项对象(当前的 agent loop 会深冻结装配好的请求);对这类派发,`injectView` 会在决策日志里报告结果:`nothing-to-apply`(没有定位到 fold 块——原始历史本身就是 view)、`in-place`/`swapped`(fold view 已随请求发出)或 `none`(fold 存在但冻结的派发带不动它——线上发送原始历史)。**Surface replace 是可用时的发送路径**(`surfaceFold`,默认开启):在串行的 `agent/turn-stopping` 边界外加一次空闲清扫,插件追加宿主风格的 shadow-price 计量事件和一条携带 `surfaceOp {op:'replace', startSeq, endSeq}` 的 `user/message` 替换事件,`sourceEventSeqs` 覆盖被遮蔽的每个表面节点——与宿主自身压缩用的是同一机制——已提交的 fold 由此从源头直达线上,冻结派发也不例外。当某会话近期派发都记录 `none` 时,view 仅用于计量:水位改用服务商上报的计数(force 档与自动交接照常工作)。折叠只在 surface 通道同样不可用时才暂停——由持久的可用性探测判定(会话在线且暴露 `append`/`surface.nodes`、没有打开的 compaction 锁),与「最近是否发过货」无关,因此重启不再把引擎冻住。只有当该会话从未成功发出过任何 surface 替换时,裁剪横幅才以 `wire=raw`(folds not shipping; watermark reads the tally)标记该行;没有 surface 机制的宿主(或开关关闭时)保持的正是这套旧行为。
|
|
141
142
|
|