dsh-switchman 1.11.5 → 1.11.7

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.md CHANGED
@@ -12,30 +12,27 @@
12
12
 
13
13
  Two pains creep in once you've worked in DSH for a while. First, sessions get heavier the longer they run: history bloats the context into hundreds of thousands of tokens, the model starts forgetting, slowing down, costing more — and a manual /compact loses detail. Second, the main model does everything itself: chasing files, running tests, reconciling data — most of that work belongs on a cheaper model.
14
14
 
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:
15
+ dsh-switchman is a plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Once installed, the main model keeps doing the work itself — just smarter about it: it chooses its battles, handing small chores to cheap lanes and letting intent routing land urgent or hard work on the right model, stepping in personally only where it counts; it sheds bloat and keeps the essence — digested history folds into compact summaries while the watermark meters every spend, keeping context lean; and when the load outgrows one pair of hands, it pulls in standing teammates to divide the work on a shared task board and steps back to dispatch and verify. It's not a new model — it's a dispatch doctrine hooked onto DSH plus a settings page, and it does nine 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"; 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).
17
+ **1. Automatic context trimming: sessions grow longer, costs stay flat.** A manual `/compact` waits on you, loses detail, and punches through the vendor's prompt cache. The trim engine automates all of it: digested stretches of the conversation are folded into compact deterministic summaries at idle boundaries (written by a side model, or folded mechanically without one under emergency pressure), and every outbound request is rebuilt from the fold state from then on — summary blocks stand in for the folded ranges, the live tail kept verbatim. The stored session log is never rewritten, and nothing touches the stream mid-flight. Folds are append-only and the rebuild is deterministic, so the serialized prefix stays byte-identical between folds and vendor caches keep hitting; any internal failure fails open into pass-through — never a malformed request. Three fully automatic tiers (growth gate / pressure / emergency), plus an advisory mode where the model folds on its own — the mechanics live in the "Automatic context trim" section at the bottom.
18
18
 
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).
19
+ **2. 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"; 100k (hard) shrinks the single-read budget and steers toward wrap-up; 200k (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: 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 also carries its own hard cap and exits after writing its HANDOFF summary. The watermark reads the post-trim view — what the model actually sees — so heavily folded sessions are no longer pinned at the high lines. When the automatics don't suit you: `/ctx-pause` stops all actions (measurement keeps running), `/ctx-resume` restores them any time — and they come back on their own after a restart; `/ctx-handover` starts the same handover on demand, no waiting for the ceiling.
20
20
 
21
- **3. Agent Teams mode: from solo to a team.** Off by default — after install it's lightweight subagent dispatch. Two independent toggles on the settings page:
21
+ **3. Intent routing: messages come in, models fall into place.** Pick "Auto (intent routing)" for the session and every user message is first typed by a small classifier model, landing on the best-fitting candidate — each candidate carries a one-line capability note to steer the call. The decision locks for the turn: when confidence is lacking or the cache window is still open, the current model stays (its prompt cache keeps paying off); switching happens only when confidence is high enough or the current model isn't among the candidates. The switch completes silently at the call layer — no "model switched" noise in the session — while a chip above the input box shows the live route and confidence. Decision-style small models and general chat models both work as the classifier; candidates, thresholds, and the cache window are always one settings page away.
22
22
 
23
- - **Agent teams** — once on, the team doctrine is injected (delegate by default + tiered verification + shared task-board discipline) and DSH's Agent Teams is enabled automatically: the main model can pull standing teammates (`spawn_teammate`), put work on a shared task board (`team_task_*`), and message teammates. When to form a team follows clear discipline: parallelizable independent subtasks, bulky self-contained work, high main-context watermark, need for role separation; one-off single-point investigations still go to a subagent. Turn the toggle off and the team clauses vanish without residue, and team tools are never yanked from sessions still running.
24
- - **Subagent model whitelist sync** — DSH keeps an authorization whitelist "allow agents to pick models for subagents": routes chosen in a pool but not authorized get rejected when dispatched by name (marked ⚠ in teams mode). Flip this toggle and the union of all six pools is written into that whitelist wholesale — switchman becomes the single source of truth, no double configuration. The whitelist takes effect as a per-new-session snapshot; the sync only affects sessions started afterwards.
23
+ **4. Agent Teams: from solo to a team.** Off by default — after install it's lightweight subagent dispatch; build a team when you want one. Two independent toggles on the settings page: **Agent teams** injects the team doctrine (delegate by default + tiered verification + shared task-board discipline) and enables DSH's Agent Teams automatically — the main model can pull standing teammates (`spawn_teammate`), put work on the shared task board (`team_task_*`), and message teammates. When to form a team follows clear discipline: parallelizable independent subtasks, bulky self-contained work, a high main-context watermark, a need for role separation; one-off single-point investigations still go to a subagent. Switch it off and the team clauses vanish without residue, and tools are never yanked from sessions still running. **Subagent model whitelist sync** writes the union of all six pools wholesale into DSH's authorization whitelist — switchman becomes the single source of truth, no double configuration (effective as a per-new-session snapshot).
25
24
 
26
- The session header gives at-a-glance feedback: the ⚡ "autonomous team" badge and ◇ with the session's actual model; while an auto-handover runs, a live indicator shows "handover in progress · writing handover doc / compacting context / waking the successor".
25
+ **5. 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).
27
26
 
28
- **4. Language preferences: ask once, remember forever.** One dropdown each for replies, code comments, and documents; scope is global or per-project (`.switchman/lang.json`). Skipping is fine — on first use you're asked once in your DSH interface language, and every session obeys the answer afterwards.
27
+ **6. Language preferences: ask once, remember forever.** One dropdown each for replies, code comments, and documents; scope is global or per-project (`.switchman/lang.json`). Skipping is fine — on first use you're asked once in your DSH interface language, and every session obeys the answer afterwards.
29
28
 
30
- **5. Interface language: the plugin itself speaks your language.** In the "Interface" section atop the settings page sits the "Interface language" dropdown (setting key `uiLocale`): Auto (default, follows the DeepSeek Harness app language), or any built-in interface language picked by hand — options always appear under the language's own endonym, never translated. It switches only the plugin's own interface (badge, home panel, settings page), never the DSH app language: selecting previews live with no restart, the choice is remembered after save and restored on the next launch, and any failure falls back to the app language; the dictionaries ship inline in the plugin bundle, nothing to download.
29
+ **7. Interface language: the plugin itself speaks your language.** In the "Interface" section atop the settings page sits the "Interface language" dropdown (setting key `uiLocale`): Auto (follows the DeepSeek Harness app language; factory default: Simplified Chinese), or any built-in interface language picked by hand — options always appear under the language's own endonym, never translated. It switches only the plugin's own interface (badge, home panel, settings page), never the DSH app language: selecting previews live with no restart, the choice is remembered after save and restored on the next launch, and any failure falls back to the app language; the dictionaries ship inline in the plugin bundle, nothing to download.
31
30
 
32
- **6. Tiered verification: every change gets checked.** Changes over 20 lines go to a tester; over 300 lines, or touching core / security / data-consistency logic, additionally to an independent reviewer. The review model is picked anchored on the model of "the agent that wrote the diff", avoiding it where possible; when the pool can't, the conclusion declares DOWNGRADED. Say "don't use the team" once and it drops back to solo instantly.
31
+ **8. Tiered verification: every change gets checked.** Changes over 20 lines go to a tester; over 300 lines, or touching core / security / data-consistency logic, additionally to an independent reviewer. The review model is picked anchored on the model of "the agent that wrote the diff", avoiding it where possible; when the pool can't, the conclusion declares DOWNGRADED. Say "don't use the team" once and it drops back to solo instantly.
33
32
 
34
- **7. `/vision`: text-only models can still handle images.** When the main model can't read images, DSH rejects image-bearing messages at the gate. Paste the image, type `/vision what's wrong with this image`, and the image goes to a vision-pool model; the verdict comes back into the current session. A heads-up "current model can't read images" appears above the input box; when a direct image send is rejected, the message is rewritten as `/vision` and resent automatically — no manual redo; with no vision pool configured the command refuses and points to the settings.
33
+ **9. `/vision`: text-only models can still handle images.** When the main model can't read images, DSH rejects image-bearing messages at the gate. Paste the image, type `/vision what's wrong with this image`, and the image goes to a vision-pool model; the verdict comes back into the current session. A heads-up "current model can't read images" appears above the input box; when a direct image send is rejected, the message is rewritten as `/vision` and resent automatically — no manual redo; with no vision pool configured the command refuses and points to the settings.
35
34
 
36
- **8. Intent routing: the right model picks itself.** A new "Intent Routing" group on the settings page: a master switch (off by default — enabling requires a classifier and at least one candidate), the classifier's small-model route (provider + model + optional effort — TypeSafe Jev-style decision models and general chat models both work, with tolerant output parsing), a classifier type three-way choice (auto / decision / chat), an independent candidate list (each candidate: provider + model + optional effort + a one-line capability note), cache window seconds (default 300, aligned to the ~5-minute prompt caches vendors provide), a switch confidence threshold (default 80), a classification timeout (default 60000 ms), history message count (default 6) and character budget (default 2400), plus an optional fallback model route with its own independent reasoning-effort pin; leaving that pin unset uses the selected fallback model's default. The model picker gains an "Auto" entry under the "Auto · Switchman" group (the client renders it localized — "Auto (intent routing)" in English); once selected, every user message is classified to pick the best-fitting candidate and the decision is locked for that turn: when confidence is lacking or the cache window is still open, the current model stays (its cache keeps being reused); switching happens only when confidence is high enough or the current model isn't among the candidates. The switch completes silently at the call layer — no "model switched" message is inserted into the session. A status chip sits above the input box (during auto routing it shows the current routed model and the last decision's confidence); candidates and thresholds can always be checked on the settings page.
37
-
38
- Worth installing even with a single model — watermark control and tiered verification don't care how many models you have, and long single-model sessions benefit just the same.
35
+ Worth installing even with a single model — automatic trimming, watermark control, and tiered verification don't care how many models you have, and long single-model sessions benefit just the same; intent routing only means something with multiple model candidates, so leave it switched off until you scale up the roster.
39
36
 
40
37
  ## Bundled skills
41
38
 
@@ -75,7 +72,7 @@ Worth installing even with a single model — watermark control and tiered verif
75
72
  - **Dispatch pools** — six cards in two rows of three: economy, mechanical, main on top; hard, vision, review below. Tick candidate models grouped by provider; tick "manual order" and a card becomes a numbered priority list reorderable with ⤒ (Move to top), ↑, ↓, ×; every route can pin a thinking effort (default "follow lane"). The summary line at the top updates live — in the shot: "4/6 pools configured · 2 ranked · mode advice".
76
73
  - **Capability ranking + enforcement mode** — the union of selected models across the six pools, ranked by capability, strongest first (the shot anchors glm-5.3 at S and glm-5.3-flash at A), reorderable and removable; enforcement mode advice / force (force = out-of-pool models rejected outright).
77
74
  - **Agent teams** — the two toggles for team mode and whitelist sync, both off by default; in the shot they're on, with a sync status line beneath the toggle.
78
- - **Context watermark** — the three thresholds (80000 / 120000 / 150000 in the shot), the single-read budget (3000), hard-tier behavior (throttle-pass / block), the auto-handover toggle, and subagent independent caps all live here. Bottom command row: `/ctx-pause` pause intervention · `/ctx-resume` resume · `/ctx-handover` write the handover doc and compact now (it steers the session to an idle boundary before compacting — the result can take a few minutes).
75
+ - **Context watermark** — the three thresholds (80000 / 100000 / 200000 in the shot), the single-read budget (3500), hard-tier behavior (throttle-pass / block), the auto-handover toggle, and subagent independent caps all live here. Bottom command row: `/ctx-pause` pause intervention · `/ctx-resume` resume · `/ctx-handover` write the handover doc and compact now (it steers the session to an idle boundary before compacting — the result can take a few minutes).
79
76
  - **Intent Routing** — the master switch, the classifier's small-model route, the classifier type (auto / decision / chat), the independent candidate list (each with a one-line capability note), cache window / confidence threshold / classification timeout / history budget, and an optional fallback model with its own optional effort pin (empty = use that model's default). Once enabled, the model picker gains the localized "Auto (intent routing)" entry, and a status chip above the input box shows the routed model and confidence.
80
77
 
81
78
  4. **Verify** — the ⚡ "autonomous team" badge appears in the session header (with ◇ beside it showing the session's current model); or simply ask the model "what's the heading of the last section of your system prompt" — the answer should mention the dsh-switchman doctrine.
@@ -92,19 +89,19 @@ bash <install-dir>/skills/db-query/scripts/setup.sh
92
89
 
93
90
  Everything below is the full set of defaults after a fresh install (authoritative source: the zod schema in `host/config.js`).
94
91
 
95
- **Interface and languages**: `uiLocale` = `auto` (follows the DSH app language); `langScope` = `global`; `langConversation/Comments/Docs` = empty (asked once in the first session and then remembered; the comment and document languages follow the conversation language).
92
+ **Interface and languages**: `uiLocale` = `zh` (Simplified Chinese; `auto` follows the DSH app language); `langScope` = `project`; `langConversation` = `zh-CN`; `langComments/Docs` = empty (factory default; if cleared, asked once in the first session and then remembered; the comment and document languages follow the conversation language).
96
93
 
97
94
  **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
95
 
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).
96
+ **Context watermark**: soft `80000` / hard `100000` / force `200000` tokens; single-read budget `3500`; over-budget behavior `cap` (truncate with a warning); `wmAutoHandover` = on (at force, automatic handover: write doc + compact); the subagent hard cap = on (sharing 200k).
100
97
 
101
- **Agent Teams**: `teamsMode` = off; `syncWhitelist` = off (the two toggles are independent of each other).
98
+ **Agent Teams**: `teamsMode` = on; `syncWhitelist` = on (the two toggles are independent of each other).
102
99
 
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; optional `intentFallbackRoute` is unset, and its own effort is model-default when later configured; `intentContextWindow` = `200000`.
100
+ **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; optional `intentFallbackRoute` is unset, and its own effort is model-default when later configured; `intentContextWindow` = `250000`.
104
101
 
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 (follows the session provider/model, not the session call's effort); without an explicit effort pin, use the lowest enabled reasoning level from model metadata, choose `off` for toggle-only models, and omit effort when reasoning is unsupported or metadata is unavailable (model default). Ladder distillation shares that route and policy; a configured fold-fallback route has an independent effort pin with the same model-aware default. **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).
102
+ **Context trim**: `trimEnabled` = on; `trimMode` = `advisory` (nudges + fold tools; the session model folds itself — switch to `auto` for fully automatic idle-boundary folds); growth gate `22500` tokens + increment `45000` tokens; pressure `45%` / emergency `90%`; advisory nudge `50%` / `80%`; protected tail `6` messages; fold cadence cap `30` per hour; side model unset (follows the session provider/model, not the session call's effort); without an explicit effort pin, use the lowest enabled reasoning level from model metadata, choose `off` for toggle-only models, and omit effort when reasoning is unsupported or metadata is unavailable (model default). Ladder distillation shares that route and policy; a configured fold-fallback route has an independent effort pin with the same model-aware default. **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
103
 
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.
104
+ **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 250000 out of the box — the guardrail guarantees 0.8×window ≥ force (200000), and the core compaction line (200000) lands exactly on the smooth-handover line (200000); ③ the most tangible out-of-the-box effect is the watermark trio: 80k nudges delegation / 100k tightens reading / 200k backs up and hands over automatically — no configuration needed.
108
105
 
109
106
  ## Automatic context trim
110
107
 
@@ -113,21 +110,25 @@ Long sessions stay cheap: consumed conversation ranges are folded into compact d
113
110
  Automation levels (`trimMode`):
114
111
 
115
112
  - **`off`** — measure only: usage and cache-hit sampling still runs; no banner, no folds.
116
- - **`advisory`** — the session model folds itself: the `ctx_trim_fold` and `ctx_trim_status` tools plus the protocol head are exposed for it.
117
- - **`auto`** (default) — everything above plus automatic folds at the idle boundary, in three tiers: a growth gate (growth > `trimGrowthTokens` measured from the last fold's post-fold low — the anchor that keeps the gate armed after folds committing at high view points — AND a contiguous compressible increment ≥ `trimIncrementTokens`; the increment floor is what actually binds), a pressure tier (`trimPressurePercent` of the context window), and an emergency tier (`trimEmergencyPercent` — a mechanical fold with its own cooldown). Pressure and emergency usage is measured on `max(view, wire)`, i.e. on the real provider prompt when it is known.
113
+ - **`advisory`** (default) — the session model folds itself: the `ctx_trim_fold` and `ctx_trim_status` tools plus the protocol head are exposed for it. When session pressure reaches `trimAdvisoryPercent` of the effective window the engine appends a one-off pinned fold nudge as a `user/message` suffix to the live session surface tail (not the dispatch system head) — it is re-spoken immediately on escalation to critical and pruned once pressure falls back below the line. At the critical line the engine itself performs one mechanical relief fold (90 s cooldown, `trimCriticalRelief` = on).
114
+ - **`auto`** — everything above plus automatic folds at the idle boundary, in three tiers: a growth gate (growth > `trimGrowthTokens` measured from the last fold's post-fold low — the anchor that keeps the gate armed after folds committing at high view points — AND a contiguous compressible increment ≥ `trimIncrementTokens`; the increment floor is what actually binds), a pressure tier (`trimPressurePercent` of the context window), and an emergency tier (`trimEmergencyPercent` — a mechanical fold with its own cooldown). Pressure and emergency usage is measured on `max(view, wire)`, i.e. on the real provider prompt when it is known.
118
115
 
119
116
  All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
120
117
 
121
118
  | Key | Default | Meaning |
122
119
  | --- | --- | --- |
123
120
  | `trimEnabled` | `true` | Master switch. OFF disables folding and metrics entirely (the listener degrades to a pure pass-through). |
124
- | `trimMode` | `auto` | `off` measure only / `advisory` model-driven folds / `auto` system-driven folds. |
121
+ | `trimMode` | `advisory` | `off` measure only / `advisory` model-driven folds / `auto` system-driven folds. |
125
122
  | `trimGrowthTokens` | `22500` | Growth gate: fold when the outbound view grew this much since the last fold. |
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
- | `trimEmergencyPercent` | `95` | Emergency tier: forced mechanical fold (no side-model call) at this percent. |
123
+ | `trimIncrementTokens` | `45000` | Gate companion: the contiguous compressible increment must also reach this size. |
124
+ | `trimPressurePercent` | `45` | Pressure tier: fold when view usage reaches this percent of the context window. |
125
+ | `trimEmergencyPercent` | `90` | Emergency tier: forced mechanical fold (no side-model call) at this percent. |
126
+ | `trimAdvisoryPercent` | `50` | Advisory nudge line: when pressure reaches this percent of the effective window, the engine nudges the model to fold now with `ctx_trim_fold` (advisory mode only). |
127
+ | `trimAdvisoryCriticalPercent` | `80` | Critical nudge line: reaching it re-speaks the nudge immediately, bypassing the 10-minute same-band throttle. |
129
128
  | `trimWindowTokens` | `0` | Effective-window cap for tier math: tiers are computed against min(model window, cap). `0` = follow `wmForceTokens`. |
130
- | `trimProtectedTail` | `10` | The last N messages are never folded. |
129
+ | `trimCriticalRelief` | `true` | Advisory critical relief: at the critical line the engine itself performs one mechanical (emergency-style) fold, on a 90 s cooldown. |
130
+ | — | — | Trim percentages are not comparable with the composer's context meter: trim divides the last paid prompt (max of view/wire) by the effective window (cap included), while the meter shows the meter's projected next prompt over the model's full window. |
131
+ | `trimProtectedTail` | `6` | The last N messages are never folded. |
131
132
  | `trimMaxFoldsPerHour` | `30` | Side-model fold cadence cap per rolling hour (emergency folds are exempt). |
132
133
  | `trimSideModel` | unset | Route for the summary side model. Empty follows the session provider/model only, not its effort. The independent effort pin defaults to the lowest enabled reasoning level from model metadata; toggle-only models use `off`, while unsupported reasoning or missing metadata omits the effort and leaves the model default. Ladder distillations share the route and policy. |
133
134
  | `trimFoldFallbackModel` | unset | Route used when a summary call fails; a pressure fold then degrades to mechanical if the retry also fails. Its effort pin is independent; when unset, use the same model-aware recommendation as the summary route. Empty = no fallback leg. |
@@ -136,7 +137,7 @@ All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
136
137
 
137
138
  **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).
138
139
 
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`).
140
+ **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 200k window the healthy sawtooth runs wire ≈ 40k just after a fold ↔ 64–90k at the next one (≈20%–45% of the window), one fold per ~45k of raw growth, with the ceiling pinned near 90k 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`).
140
141
 
141
142
  **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.
142
143
 
@@ -146,7 +147,7 @@ All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
146
147
 
147
148
  **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
 
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
+ **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. The advisory-mode pressure nudge is the deliberate exception: in `advisory` mode the model drives the fold, so the engine does tell it the pressure and the fold line, on the explicit instruction channel.
150
151
 
151
152
  **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.
152
153
 
@@ -170,6 +171,12 @@ All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
170
171
 
171
172
  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
173
 
174
+ ## Downloads
175
+
176
+ All-time npm downloads since the first release, cumulative — drawn from the official [npm downloads API](https://api.npmjs.org/) and refreshed daily by GitHub Actions ([chart script](scripts/downloads-chart.mjs)):
177
+
178
+ ![All-time cumulative npm downloads for dsh-switchman](docs/assets/downloads.svg)
179
+
173
180
  ## License
174
181
 
175
- MIT
182
+ MIT
package/README.pt.md CHANGED
@@ -12,30 +12,27 @@
12
12
 
13
13
  Se você trabalha com o DSH, com o tempo esbarra em duas coisas: a sessão fica cada vez mais pesada — o histórico empurra o contexto para centenas de milhares de tokens, o modelo começa a esquecer, fica lento e caro, e o /compact manual compacta perdendo detalhes no processo; e o modelo principal faz tudo sozinho — consultar um arquivo, rodar um teste, conferir dados: é sempre ele que mastiga tudo, lento e caro, sendo que a maior parte desse trabalho caberia a um modelo barato.
14
14
 
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:
15
+ dsh-switchman é um plugin para o [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Depois de instalado, o modelo principal continua trabalhando por conta própria — só que com mais critério: escolhe as brigas dele, manda os serviços pequenos para faixas baratas e deixa o roteamento por intenção aterrissar o urgente ou o difícil no modelo certo, reservando para si só o que realmente merece um toque pessoal; descarta o inchado e destila o essencial — as partes já digeridas da conversa se dobram em resumos compactos enquanto o nível de água mede cada gasto, e o contexto viaja sempre leve; e quando a carga ultrapassa um único par de mãos, recruta companheiros permanentes que dividem o trabalho num quadro de tarefas compartilhado, enquanto ele fica com o despacho e a conferência. Não é um modelo novo: é um regulamento de despacho plugado ao DSH mais uma interface de configuração. Em concreto, ele faz nove 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”; 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).
17
+ **1. Trim automático do contexto: a sessão fica mais longa, o custo fica plano.** Um `/compact` manual faz você esperar, perde detalhes e atravessa a cache de prompt do fornecedor. O motor de trim automatiza tudo isso: as partes já digeridas da conversa são dobradas em resumos deterministas e compactos nas fronteiras de inatividade (quem escreve é um side model; sob pressão de emergência a dobra é mecânica, sem chamada de modelo), e a partir daí cada requisição de saída é reconstruída a partir do estado das dobras — blocos de resumo substituem as partes dobradas, a cauda viva fica palavra por palavra. O log de sessão salvo nunca é reescrito, e nada toca o stream em pleno curso. As dobras são só append e a reconstrução é determinística: o prefixo serializado fica idêntico byte a byte entre dobras e a cache do fornecedor continua acertando; qualquer falha interna cai em fail-open para o repasse transparente — nunca uma requisição quebrada. Três níveis totalmente automáticos (crescimento / pressão / emergência), mais um modo advisory em que o próprio modelo dobra — a mecânica está no fim, na seção “Trim automático do contexto”.
18
18
 
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).
19
+ **2. 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”; 100k (hard) aperta o orçamento de leitura por chamada e empurra para encerrar; 200k (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 ainda um teto próprio e independente e, ao atingi-lo, sai depois de escrever o resumo HANDOFF. O nível lê a visão depois do trim — o que o modelo realmente vê —, então uma sessão muito dobrada não fica mais presa nos limiares altos. Se o automático não estiver do seu jeito: `/ctx-pause` interrompe todas as ações (a medição continua), `/ctx-resume` retoma a qualquer momento — e depois de reiniciar volta sozinho; `/ctx-handover` dispara sob demanda o mesmo handover, sem esperar o teto.
20
20
 
21
- **3. Modo Agent Teams: do trabalho solo para comandar uma equipe.** Desligado por padrão: recém-instalado, o trabalho corre no despacho leve via subagent. Na página de configurações, duas chaves independentes:
21
+ **3. Roteamento por intenção: chega a mensagem, o modelo toma seu posto.** Ao escolher “Auto (roteamento por intenção)” para a sessão, cada mensagem do usuário passa primeiro por um pequeno modelo classificador, que a faz aterrissar no candidato mais adequado — cada candidato traz uma nota de capacidades de uma linha para orientar a escolha. A decisão vale para o turno: se a confiança não chega ou a janela de cache ainda está aberta, o modelo atual permanece (a cache de prompt dele segue rendendo); só se troca quando a confiança sobra ou o modelo atual não está entre os candidatos. A troca acontece em silêncio na camada de chamada — nenhum barulho de “modelo trocado” na sessão — enquanto um chip acima da caixa de entrada mostra rota e confiança em tempo real. Como classificador servem tanto pequenos modelos de decisão quanto modelos de chat genéricos; candidatos, limiares e janela de cache ficam sempre a uma página de configurações de distância.
22
22
 
23
- - **Modo Agent Teams** — ao ligar, injeta a doutrina de equipe (delegar por padrão + verificação em níveis + disciplina do quadro de tarefas compartilhado) e habilita automaticamente os Agent Teams do DSH: o modelo principal pode recrutar colegas permanentes (`spawn_teammate`), despachar trabalho para o quadro compartilhado (`team_task_*`) e trocar mensagens com eles. Há uma disciplina clara sobre quando formar a equipe: subtarefas independentes paralelizáveis, trabalho volumoso e autossuficiente, nível de água do contexto principal já alto, necessidade de separar papéis; investigações pontuais de uma vez só continuam pelo subagent. Desligando a chave de novo, as cláusulas de equipe somem sem resíduo, e as ferramentas de equipe nas sessões em andamento não são recolhidas.
24
- - **Sincronização da whitelist de modelos de subagent** — o DSH tem uma whitelist de autorização “Permitir que os agents escolham modelos para os subagents”: rotas escolhidas nos pools mas não autorizadas são recusadas quando o modelo principal as nomeia explicitamente (no modo equipe, são marcadas com ⚠). Com esta chave ligada, a união dos seis pools é gravada de uma vez nessa whitelist — sem configurar dos dois lados: o switchman é a única fonte da verdade. A whitelist vale como snapshot por “nova sessão”: a sincronização só alcança as sessões abertas depois.
23
+ **4. Modo Agent Teams: do trabalho solo para comandar uma equipe.** Desligado por padrão: recém-instalado, o trabalho corre no despacho leve via subagent. Na página de configurações, duas chaves independentes: **Modo Agent Teams** — ao ligar, injeta a doutrina de equipe (delegar por padrão + verificação em níveis + disciplina do quadro de tarefas compartilhado) e habilita automaticamente os Agent Teams do DSH: o modelo principal pode recrutar colegas permanentes (`spawn_teammate`), despachar trabalho para o quadro compartilhado (`team_task_*`) e trocar mensagens com eles. Há uma disciplina clara sobre quando formar a equipe: subtarefas independentes paralelizáveis, trabalho volumoso e autossuficiente, nível de água do contexto principal já alto, necessidade de separar papéis; investigações pontuais de uma vez só continuam pelo subagent. Desligando a chave de novo, as cláusulas de equipe somem sem resíduo, e as ferramentas de equipe nas sessões em andamento não são recolhidas. **Sincronização da whitelist de modelos de subagent** — o DSH tem uma whitelist de autorização “Permitir que os agents escolham modelos para os subagents”: rotas escolhidas nos pools mas não autorizadas são recusadas quando o modelo principal as nomeia explicitamente (no modo equipe, são marcadas com ⚠). Com esta chave ligada, a união dos seis pools é gravada de uma vez nessa whitelist — sem configurar dos dois lados: o switchman é a única fonte da verdade. A whitelist vale como snapshot por “nova sessão”: a sincronização só alcança as sessões abertas depois.
25
24
 
26
- O cabeçalho da sessão dá um retorno imediato: badge ⚡ “Equipe autônoma”, ◇ modelo em uso na sessão atual; durante um handover automático aparece um aviso em tempo real do tipo “Handover em andamento · escrevendo documento de handover / compactação do contexto / despertar da continuação”.
25
+ **5. 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).
27
26
 
28
- **4. Preferências de idioma: pergunta uma vez, lembra para sempre.** Um dropdown para cada um dos três idiomas — respostas, comentários de código, documentos — com escopo à escolha: global ou por projeto (`.switchman/lang.json`). Pode deixar em branco: no primeiro uso perguntam uma vez, no idioma da interface do DSH, e daí em diante toda sessão segue sozinha.
27
+ **6. Preferências de idioma: pergunta uma vez, lembra para sempre.** Um dropdown para cada um dos três idiomas — respostas, comentários de código, documentos — com escopo à escolha: global ou por projeto (`.switchman/lang.json`). Pode deixar em branco: no primeiro uso perguntam uma vez, no idioma da interface do DSH, e daí em diante toda sessão segue sozinha.
29
28
 
30
- **5. Idioma da interface: o plugin também fala o seu idioma.** No topo da página de configurações entra uma nova seção “Interface” com um dropdown “Idioma da interface” (chave de configuração `uiLocale`): Automático (padrão — segue o idioma do app DeepSeek Harness) ou qualquer um dos idiomas da interface do plugin, sempre pelo endônimo, nunca traduzido. Ele troca só a interface do próprio plugin — o badge do cabeçalho, o painel da página inicial e a página de configurações —, não o idioma do app DSH: a prévia é imediata, sem reinício; ao salvar, a escolha fica guardada; o próximo início a restaura; qualquer falha volta ao idioma do app; e todos os dicionários vêm dentro do bundle, sem download.
29
+ **7. Idioma da interface: o plugin também fala o seu idioma.** No topo da página de configurações entra uma nova seção “Interface” com um dropdown “Idioma da interface” (chave de configuração `uiLocale`): Automático (segue o idioma do app DeepSeek Harness; chinês simplificado por padrão) ou qualquer um dos idiomas da interface do plugin, sempre pelo endônimo, nunca traduzido. Ele troca só a interface do próprio plugin — o badge do cabeçalho, o painel da página inicial e a página de configurações —, não o idioma do app DSH: a prévia é imediata, sem reinício; ao salvar, a escolha fica guardada; o próximo início a restaura; qualquer falha volta ao idioma do app; e todos os dicionários vêm dentro do bundle, sem download.
31
30
 
32
- **6. Verificação em níveis: mudou, testa.** Alterações acima de 20 linhas vão para um tester validar; acima de 300 linhas, ou quando tocam lógica central / segurança / consistência de dados, entra também um reviewer com revisão independente. O modelo do reviewer é escolhido ancorando no modelo do “agent que escreveu o diff”, evitando-o sempre que possível; se no pool não dá para evitá-lo, a conclusão declara DOWNGRADED. Basta dizer “não use equipes” e ele volta na hora a trabalhar sozinho.
31
+ **8. Verificação em níveis: mudou, testa.** Alterações acima de 20 linhas vão para um tester validar; acima de 300 linhas, ou quando tocam lógica central / segurança / consistência de dados, entra também um reviewer com revisão independente. O modelo do reviewer é escolhido ancorando no modelo do “agent que escreveu o diff”, evitando-o sempre que possível; se no pool não dá para evitá-lo, a conclusão declara DOWNGRADED. Basta dizer “não use equipes” e ele volta na hora a trabalhar sozinho.
33
32
 
34
- **7. `/vision`: até modelo somente texto lida com imagens.** Quando o modelo principal não sabe ler imagens, o DSH recusa na entrada as mensagens que as trazem. Você anexa a imagem e digita `/vision onde está o erro nesta imagem`: a imagem é entregue à leitura de um modelo do pool multimodal, e a conclusão volta para a sessão atual. Acima da caixa de entrada aparece antes o aviso “o modelo atual não suporta leitura de imagens”; se um envio direto da imagem for recusado, a mensagem é reescrita uma vez para `/vision` e reenviada sozinha, sem precisar refazer à mão; sem pool multimodal configurado, o comando recusa e indica como configurar.
33
+ **9. `/vision`: até modelo somente texto lida com imagens.** Quando o modelo principal não sabe ler imagens, o DSH recusa na entrada as mensagens que as trazem. Você anexa a imagem e digita `/vision onde está o erro nesta imagem`: a imagem é entregue à leitura de um modelo do pool multimodal, e a conclusão volta para a sessão atual. Acima da caixa de entrada aparece antes o aviso “o modelo atual não suporta leitura de imagens”; se um envio direto da imagem for recusado, a mensagem é reescrita uma vez para `/vision` e reenviada sozinha, sem precisar refazer à mão; sem pool multimodal configurado, o comando recusa e indica como configurar.
35
34
 
36
- **8. Roteamento por intenção: o modelo certo se escolhe sozinho.** A página de configurações ganha um grupo “Roteamento por intenção”: uma chave mestra (desligada por padrão; para ligar são precisos um classificador e pelo menos um candidato), a rota do modelo pequeno do classificador (provider + model + effort opcional — servem tanto modelos de decisão tipo TypeSafe Jev quanto modelos de conversa genéricos, e a saída é interpretada com tolerância), uma escolha do tipo de classificador em três opções (auto / decision / chat), uma lista de candidatos independente (cada candidato: provider + model + effort opcional + uma nota de capacidade de uma linha), a janela de cache em segundos (300 por padrão, alinhada com os caches de prompt dos provedores, cerca de 5 minutos), o limiar de confiança para a troca (80 por padrão), o timeout de classificação (60000 ms por padrão), a contagem de mensagens do histórico (6 por padrão) e o orçamento de caracteres (2400 por padrão), além de um modelo de fallback opcional (com um pin de effort opcional e independente; se não for fixado, usa-se o effort padrão do modelo de fallback selecionado, separado do effort do classificador). No seletor de modelos aparece uma entrada “Auto” no grupo “Auto · Switchman” (o cliente a renderiza localizada — “Automático (roteamento por intenção)” em português); escolhida, cada mensagem do usuário passa pelo classificador para eleger o melhor candidato, e a decisão fica travada por aquele turno: se a confiança não alcança ou a janela de cache ainda está aberta, o modelo atual permanece (reaproveitando o cache); só troca quando a confiança é suficiente ou o modelo atual não está entre os candidatos. A troca acontece em silêncio na camada de chamada — nenhuma mensagem de “modelo trocado” entra na sessão. Acima da caixa de entrada há um chip de status (no roteamento automático, ele mostra o modelo roteado atual e a confiança da última decisão); candidatos e limiares ficam sempre visíveis na página de configurações.
37
-
38
- Só um modelo? Ainda vale a pena instalar — o controle do nível de água e a verificação em níveis não ligam para quantos modelos você tem, e sessões longas de modelo único se beneficiam do mesmo jeito.
35
+ Só um modelo? Ainda vale a pena instalar — trim automático, controle do nível de água e verificação em níveis não ligam para quantos modelos você tem, e sessões longas de modelo único se beneficiam do mesmo jeito. O roteamento por intenção só faz sentido com vários candidatos de modelo: deixe desligado até ampliar o elenco.
39
36
 
40
37
  ## Skills embutidas
41
38
 
@@ -75,7 +72,7 @@ Só um modelo? Ainda vale a pena instalar — o controle do nível de água e a
75
72
  - **Pools de despacho** — seis cards em duas fileiras de três: em cima leve / mecânico / principal; embaixo difícil / multimodal / revisão. Em cada card você marca os candidatos agrupados por provider; marque “ordem manual” e ele vira uma lista de prioridade numerada, reordenável com ↑ ↓ ×; ao lado de cada rota dá para fixar o reasoning effort (padrão “seguir a faixa”). A linha de resumo no topo se atualiza em tempo real; na captura: “4/6 pools configurados · 2 no ranking · modo advice”.
76
73
  - **Ranking de capacidade + modo de execução** — a união dos modelos escolhidos nos seis pools, ordenada por capacidade com os mais fortes na frente (na captura glm-5.3 ancorado em S e glm-5.3-flash ancorado em A); dá para reordenar e cortar; o modo de execução vai de advice / enforce (enforce = modelos fora do pool são recusados na hora).
77
74
  - **Equipe de agentes** — as duas chaves, modo equipe e sincronização da whitelist, começam desligadas; na captura estão ligadas, e abaixo de cada uma há uma linha de status de sincronização.
78
- - **Nível de água do contexto** — os três limiares (na captura 80000 / 120000 / 150000), o orçamento de leitura por chamada (3000), o comportamento do limiar hard (deixa passar com limitação / bloqueia), a chave do handover automático e o teto independente dos subagents ficam todos nesta área. Uma linha de comandos embaixo: `/ctx-pause` pausa as intervenções · `/ctx-resume` retoma · `/ctx-handover` escreve o documento e entrega na hora (ele conduz a sessão até o limite de inatividade antes de compactar: o resultado pode levar alguns minutos).
75
+ - **Nível de água do contexto** — os três limiares (na captura 80000 / 100000 / 200000), o orçamento de leitura por chamada (3500), o comportamento do limiar hard (deixa passar com limitação / bloqueia), a chave do handover automático e o teto independente dos subagents ficam todos nesta área. Uma linha de comandos embaixo: `/ctx-pause` pausa as intervenções · `/ctx-resume` retoma · `/ctx-handover` escreve o documento e entrega na hora (ele conduz a sessão até o limite de inatividade antes de compactar: o resultado pode levar alguns minutos).
79
76
  - **Roteamento por intenção** — a chave mestra, a rota do modelo pequeno do classificador, o tipo de classificador (auto / decision / chat), a lista de candidatos independente (cada um com sua nota de capacidade), janela de cache / limiar de confiança / timeout / orçamento de histórico e um modelo de fallback opcional. Ligado, o seletor de modelos ganha a entrada localizada “Automático (roteamento por intenção)” e acima da caixa de entrada aparece o chip com o modelo roteado e a confiança.
80
77
 
81
78
  4. **Verifique** — no cabeçalho da sessão aparece o badge ⚡ “Equipe autônoma” (ao lado, o ◇ mostra o modelo da sessão atual); ou pergunte direto ao modelo “qual é o título da última seção do seu system prompt?” — a resposta deve mencionar a doutrina dsh-switchman.
@@ -92,19 +89,19 @@ bash <install-dir>/skills/db-query/scripts/setup.sh
92
89
 
93
90
  Estes são todos os valores logo depois de uma instalação nova (fonte autoritativa: o esquema zod em `host/config.js`).
94
91
 
95
- **Interface e idiomas**: `uiLocale` = `auto` (segue o idioma do app DSH); `langScope` = `global`; `langConversation/Comments/Docs` = vazios (pergunta uma vez na primeira sessão e fica guardado; o idioma de comentários e documentos segue o da conversa).
92
+ **Interface e idiomas**: `uiLocale` = `zh` (chinês simplificado; `auto` segue o idioma do app DSH); `langScope` = `project`; `langConversation` = `zh-CN`; `langComments/Docs` = vazios (valor de fábrica; se vazio, pergunta uma vez na primeira sessão e fica guardado; o idioma de comentários e documentos segue o da conversa).
96
93
 
97
94
  **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
95
 
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).
96
+ **Nível de água do contexto**: soft `80000` / hard `100000` / force `200000` tokens; orçamento de leitura por chamada `3500`; 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 (200k compartilhadas).
100
97
 
101
- **Agent Teams**: `teamsMode` = desligado; `syncWhitelist` = desligado (as duas chaves são independentes entre si).
98
+ **Agent Teams**: `teamsMode` = ligado; `syncWhitelist` = ligado (as duas chaves são independentes entre si).
102
99
 
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`.
100
+ **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` = `250000`.
104
101
 
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.
102
+ **Trim de contexto**: `trimEnabled` = ligado; `trimMode` = `advisory` (avisos + ferramentas de dobra; o modelo da sessão dobra-se sozinho — para o modo totalmente automático, `auto`); portão de crescimento `22500` + incremento `45000` tokens; pressão `45%` / emergência `90%`; avisos advisory `50%` / `80%`; cauda protegida `6` 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
103
 
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.
104
+ **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 250000 — o guard-rail garante 0.8×janela ≥ force (200000), então a linha de compactação do núcleo (200000) cai exatamente sobre a linha de entrega suave (200000); ③ o que mais se sente de fábrica é o trio de níveis: 80k lembra de delegar / 100k aperta a leitura / 200k entrega sozinho (documento + compactação) — sem nenhuma configuração.
108
105
 
109
106
  ## Trim automático do contexto
110
107
 
@@ -113,21 +110,25 @@ Sessões longas ficam baratas: os trechos já consumidos da conversa viram resum
113
110
  Níveis de automação (`trimMode`):
114
111
 
115
112
  - **`off`** — só medição: a amostragem de uso e de acertos de cache continua rodando; sem banner, sem folds.
116
- - **`advisory`** — o modelo da sessão dobra sozinho: as ferramentas `ctx_trim_fold` e `ctx_trim_status` mais o cabeçalho de protocolo ficam expostas.
117
- - **`auto`** (padrão) — tudo isso mais folds automáticos na fronteira de ociosidade, em três degraus: um portão de crescimento (crescimento > `trimGrowthTokens` medido a partir da mínima pós-dobra do último fold — a âncora que mantém o portão armado após dobras confirmadas em pontos altos da view — E um incremento comprimível contíguo ≥ `trimIncrementTokens`), um degrau de pressão (`trimPressurePercent` da janela de contexto) e um degrau de emergência (`trimEmergencyPercent` — um fold mecânico com cooldown próprio).
113
+ - **`advisory`** (padrão) — o modelo da sessão dobra sozinho: as ferramentas `ctx_trim_fold` e `ctx_trim_status` mais o cabeçalho de protocolo ficam expostas. Quando a pressão da sessão atinge `trimAdvisoryPercent` da janela efetiva, o motor acrescenta um lembrete de dobra fixado como sufixo `user/message` ao final da surface ativa da sessão (não ao cabeçalho system do despacho) — repetido imediatamente ao escalar para crítico e removido quando a pressão volta abaixo da linha. Na linha crítica o próprio motor executa uma dobra mecânica de alívio (arrefecimento de 90 s, `trimCriticalRelief` = ligado).
114
+ - **`auto`** — tudo isso mais folds automáticos na fronteira de ociosidade, em três degraus: um portão de crescimento (crescimento > `trimGrowthTokens` medido a partir da mínima pós-dobra do último fold — a âncora que mantém o portão armado após dobras confirmadas em pontos altos da view — E um incremento comprimível contíguo ≥ `trimIncrementTokens`), um degrau de pressão (`trimPressurePercent` da janela de contexto) e um degrau de emergência (`trimEmergencyPercent` — um fold mecânico com cooldown próprio).
118
115
 
119
116
  Todas as chaves ficam em Configurações → dsh-switchman; os padrões vêm de `host/config.js`:
120
117
 
121
118
  | Chave | Padrão | Significado |
122
119
  | --- | --- | --- |
123
120
  | `trimEnabled` | `true` | Chave mestra. Desligado desativa folds e métricas por completo (o listener degrada a puro pass-through). |
124
- | `trimMode` | `auto` | `off` só medição / `advisory` folds conduzidos pelo modelo / `auto` folds conduzidos pelo sistema. |
121
+ | `trimMode` | `advisory` | `off` só medição / `advisory` folds conduzidos pelo modelo / `auto` folds conduzidos pelo sistema. |
125
122
  | `trimGrowthTokens` | `22500` | Portão de crescimento: dobra quando a view de saída crescer isso desde o último fold. |
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
- | `trimEmergencyPercent` | `95` | Degrau de emergência: fold mecânico forçado (sem chamada ao modelo secundário) nessa porcentagem. |
123
+ | `trimIncrementTokens` | `45000` | Companheiro do portão: o incremento comprimível contíguo também precisa alcançar esse tamanho. |
124
+ | `trimPressurePercent` | `45` | Degrau de pressão: dobra quando o uso da view alcança essa porcentagem da janela de contexto. |
125
+ | `trimEmergencyPercent` | `90` | Degrau de emergência: fold mecânico forçado (sem chamada ao modelo secundário) nessa porcentagem. |
126
+ | `trimAdvisoryPercent` | `50` | Linha de lembrete advisory: ao atingir essa porcentagem da janela efetiva, o motor insta o modelo a dobrar já com `ctx_trim_fold` (somente modo advisory). |
127
+ | `trimAdvisoryCriticalPercent` | `80` | Linha crítica: ao atingi-la, repete o lembrete de imediato, contornando o limite de 10 minutos na mesma faixa. |
129
128
  | `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` | `10` | As últimas N mensagens nunca são dobradas. |
129
+ | `trimCriticalRelief` | `true` | Alívio crítico advisory: ao atingir a linha crítica, o próprio motor executa uma dobra mecânica (estilo emergência), com cooldown de 90 s. |
130
+ | — | — | As porcentagens do trim não são comparáveis ao medidor de contexto do compositor: o trim divide o último prompt pago (máximo de view/wire) pela janela efetiva (limite incluído); o medidor mostra a projeção do próximo prompt sobre a janela completa do modelo. |
131
+ | `trimProtectedTail` | `6` | As últimas N mensagens nunca são dobradas. |
131
132
  | `trimMaxFoldsPerHour` | `30` | Teto de cadência de folds por hora rolante para o modelo secundário (os de emergência ficam fora). |
132
133
  | `trimSideModel` | não definida | Rota do modelo secundário que escreve os resumos. Vazia = seguir o provider/model da sessão, sem herdar o effort da chamada; a ladder distillation também usa esta rota. O effort do resumo aceita um pin manual independente; se não fixado, os metadados do modelo recomendam o nível de reasoning habilitado mais baixo; se o modelo só tiver interruptor sim/não, escolhe-se off. Se não houver suporte a reasoning ou os metadados não estiverem disponíveis, nenhum effort é enviado e prevalece o comportamento padrão do modelo/adaptador. |
133
134
  | `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. O modelo de fallback do fold escolhido manualmente tem um pin de effort independente; sem pin, usa a mesma recomendação por metadados do modelo de resumo e, sem metadados, o padrão do modelo. Escolha uma rota com folga em cooldowns, controle de risco e concorrência. |
@@ -136,7 +137,7 @@ Todas as chaves ficam em Configurações → dsh-switchman; os padrões vêm de
136
137
 
137
138
  **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).
138
139
 
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`).
140
+ **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 200k o dente-de-serra saudável deixa o fio em ≈ 40k logo após um fold ↔ 64–90k no seguinte (≈20%–45% da janela), um fold a cada ~45k de crescimento bruto, com o teto fixado perto de 90k 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`).
140
141
 
141
142
  **É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.
142
143
 
@@ -161,6 +162,12 @@ Todas as chaves ficam em Configurações → dsh-switchman; os padrões vêm de
161
162
  - As linhas de protocolo (`[SWITCHMAN:LANG|POOLS|WATERMARK|TEAMS]`) ficam deliberadamente em inglês e estáveis a byte — não as localize.
162
163
  - `npm pack --dry-run` deve continuar na forma auditada de 60 arquivos / ~380 kB (~1,26 MB descompactado; `docs/` fica de fora).
163
164
 
165
+ ## Downloads
166
+
167
+ Todos os downloads do npm desde a primeira publicação, acumulados — desenhados a partir da [API oficial de downloads do npm](https://api.npmjs.org/) e atualizados diariamente pelo GitHub Actions ([script do gráfico](scripts/downloads-chart.mjs)):
168
+
169
+ ![Downloads acumulados do npm para dsh-switchman](docs/assets/downloads.svg)
170
+
164
171
  ## License
165
172
 
166
173
  MIT