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.de.md
CHANGED
|
@@ -14,7 +14,7 @@ Wer lange mit DSH arbeitet, ärgert sich über zwei Dinge. Erstens werden Sessio
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman ist ein Plugin für [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Nach der Installation wandelt sich das Hauptmodell vom Selbermacher zum Disponenten: Wasserstand messen, Spur wählen, Aufgaben vergeben, Abnahme prüfen. Es ist kein neues Modell, sondern ein Dispositionsregelwerk an DSH plus eine Einstellungsseite — und es tut acht Dinge:
|
|
16
16
|
|
|
17
|
-
**1. Kontext-Wasserstand: lange Sessions platzen nicht.** Jede Runde zählt die Session-Tokens in Echtzeit; drei Stufen schrauben sich hoch: 80k (soft, einstellbar) mahnt „zeit zu delegieren“;
|
|
17
|
+
**1. Kontext-Wasserstand: lange Sessions platzen nicht.** Jede Runde zählt die Session-Tokens in Echtzeit; drei Stufen schrauben sich hoch: 80k (soft, einstellbar) mahnt „zeit zu delegieren“; 95k (hard) strafft das Einzellese-Budget und lenkt auf den Abschluss; 150k (force) übergibt automatisch — das Übergabedokument wird geschrieben (das append-only Sitzungslog ist dabei die vollständige Sicherung), der Kontext komprimiert, die Session geweckt und läuft weiter, ohne dass die Aufgabe abreißt. Auch Hintergrund-Subagents, die im Moment der Übergabe noch laufen, gehen nicht verloren: id, Aufgabe und Report-Pfad landen im Übergabedokument; die fortgesetzte Session weiß, wo sie Reports abholt, und vergibt nichts doppelt. Jeder Subagent trägt eine eigene harte Obergrenze und verlässt nach seinem HANDOFF-Summary die Bühne. Passt dir die automatische Intervention nicht, übernimm jederzeit von Hand: `/ctx-pause` stoppt alle Wasserstands-Aktionen (die Messung läuft weiter, die Live-Wasserstandszeile am Ende springt auf paused — es wird nur nicht mehr gehandelt), `/ctx-resume` holt alles jederzeit zurück — nach einem DSH-Neustart greift die Intervention auch von selbst wieder, ein temporäres Loslassen, kein Dauer-Aus; `/ctx-handover` wartet nicht, bis der Wasserstand oben ist, und startet dieselbe Übergabe auf Zuruf: Übergabedokument schreiben, Kontext verdichten, Session zum Weiterlaufen wecken (die Session wird erst an eine Leerlauf-Grenze geführt, das Ergebnis kann daher ein paar Minuten dauern).
|
|
18
18
|
|
|
19
19
|
**2. Sechs Dispatch-Pools: das richtige Modell für jede Arbeit.** Economy (Massen-Kleinkram), Mechanical (Schablonen-Umformung), Main (tägliche Codearbeit), Hard (schwere Schlussfolgerungen und große Refactorings), Vision (Bilder), Review (unabhängige Prüfung). Auf der Einstellungsseite kreuzt man Kandidaten an, ordnet Prioritäten, vergibt Noten S/A/B/C und nagelt je Route einen Reasoning-Aufwand fest — das Aufwand-Dropdown führt die Stufen, die das Modell tatsächlich beherrscht, nicht generische drei. Im Prompt jeder Runde steckt eine `[SWITCHMAN:POOLS]`-Empfehlungstabelle; nach der wird vergeben. Drei Enforcement-Modi: aus / Empfehlung / Erzwingen (Erzwingen = Modelle außerhalb der Pools werden glatt abgelehnt).
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ Auch mit nur einem Modell lohnt sich die Installation — Wasserstandskontrolle
|
|
|
86
86
|
bash <Installationsverzeichnis>/skills/db-query/scripts/setup.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
**Empfehlung zur Klassifikator-Wahl:** Wer das Entscheidungsmodell lokal betreiben will, fährt am besten `
|
|
89
|
+
**Empfehlung zur Klassifikator-Wahl:** Wer das Entscheidungsmodell lokal betreiben will, fährt am besten `d3:4b-mxfp8` mit Ollama — als Klassifikatortyp „Entscheidungs-Endpunkt (systemone)“ wählen, als Endpunkt `http://127.0.0.1:11434/v1/systemone` und als Modellnamen `d3:4b-mxfp8` eintragen. Für den Chat-Klassifikator aus dem LLM-Katalog empfiehlt sich ein kleines Cloud-Modell oder ein kleines lokales Modell ohne Thinking- (Reasoning-)Fähigkeit — abgeschaltetes Thinking senkt Latenz und die Timeout-Fehlerrate der Klassifikation zugleich.
|
|
90
90
|
|
|
91
91
|
## Standardkonfiguration
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ Alles Folgende sind die vollständigen Werte direkt nach der Neuinstallation (ma
|
|
|
96
96
|
|
|
97
97
|
**Dispatch-Pools**: alle sechs Spuren (economy/mechanical/main/hard/vision/review) starten ohne Kandidaten (= die Standardmodelle des Systems, keine Einwirkung); manuelle Reihenfolge und gepinnter Aufwand sind aus/leer; `dispatchEnforce` = `advice` (nur Empfehlung, nichts wird erzwungen).
|
|
98
98
|
|
|
99
|
-
**Kontext-Wasserstand**: soft `80000` / hard `
|
|
99
|
+
**Kontext-Wasserstand**: soft `80000` / hard `95000` / force `150000` Token; Einzellese-Budget `3000`; Verhalten bei Budgetüberschreitung `cap` (kürzen mit Warnung); `wmAutoHandover` = an (bei force Übergabedokument schreiben + Komprimierung, automatisch); die harte Obergrenze für Subagents = an (gemeinsame 150k).
|
|
100
100
|
|
|
101
101
|
**Agent Teams**: `teamsMode` = aus; `syncWhitelist` = aus (die beiden Schalter sind unabhängig voneinander).
|
|
102
102
|
|
|
103
103
|
**Intent-Routing** (ab Werk unbrauchbar; nötig sind Klassifikator + mindestens ein Kandidat + der Hauptschalter): `intentEnabled` = aus (ist er aus, bleibt der Auto-Eintrag verborgen, und Sessions, die bereits Auto gewählt hatten, laufen über die Fallback-Kette); Klassifikator-Route nicht gesetzt; Klassifikatortyp `chat`; Kandidatenliste leer (die mitgelieferten Kategorien nehmen erst mit eingetragenem Modell am Routing teil); Cache-Fenster `300` s / Umschalt-Vertrauensschwelle `80` / Klassifikations-Timeout `60000` ms; Verlauf `6` Nachrichten / `2400` Zeichen; `intentContextWindow` = `200000`.
|
|
104
104
|
|
|
105
|
-
**Kontext-Trimming**: `trimEnabled` = an; `trimMode` = `auto` (vollautomatisch); Wachstumsschwelle `22500` + Zuwachs `
|
|
105
|
+
**Kontext-Trimming**: `trimEnabled` = an; `trimMode` = `auto` (vollautomatisch); Wachstumsschwelle `22500` + Zuwachs `25000` Tokens; Druck `65%` / Notfall `95%`; geschütztes Ende `10` Nachrichten; Fold-Takt-Obergrenze `30` pro Stunde; Nebenmodell nicht gesetzt (erbt das Session-Modell) — Details im Abschnitt „Automatisches Kontext-Trimming“ unten.
|
|
106
106
|
|
|
107
|
-
**Out-of-the-Box-Anmerkungen**: ① dass Intent-Routing ab Werk unbrauchbar ist, ist Absicht — drei Schritte zum Einschalten (Klassifikator, Kandidaten, Schalter); ② das wirksame Auto-Fenster steht ab Werk auf 200000 — die Leitplanke garantiert 0.8×Fenster ≥ force (150000), die Kern-Komprimierlinie (160000) liegt also stets hinter der Linie der weichen Übergabe (150000); ③ am spürbarsten ab Werk ist das Wasserstands-Trio: 80k mahnt zur Delegation /
|
|
107
|
+
**Out-of-the-Box-Anmerkungen**: ① dass Intent-Routing ab Werk unbrauchbar ist, ist Absicht — drei Schritte zum Einschalten (Klassifikator, Kandidaten, Schalter); ② das wirksame Auto-Fenster steht ab Werk auf 200000 — die Leitplanke garantiert 0.8×Fenster ≥ force (150000), die Kern-Komprimierlinie (160000) liegt also stets hinter der Linie der weichen Übergabe (150000); ③ am spürbarsten ab Werk ist das Wasserstands-Trio: 80k mahnt zur Delegation / 95k strafft das Lesen / 150k übergibt automatisch (Dokument schreiben + Komprimierung) — ganz ohne Einstellungen.
|
|
108
108
|
|
|
109
109
|
## Automatisches Kontext-Trimming
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ Alle Schlüssel liegen unter Einstellungen → dsh-switchman; Defaults aus `host
|
|
|
123
123
|
| `trimEnabled` | `true` | Hauptschalter. AUS deaktiviert Folds und Metriken komplett (der Listener wird zum reinen Durchreichen). |
|
|
124
124
|
| `trimMode` | `auto` | `off` nur messen / `advisory` modellgetriebene Folds / `auto` systemgetriebene Folds. |
|
|
125
125
|
| `trimGrowthTokens` | `22500` | Wachstumsschwelle: falte, wenn die ausgehende View seit dem letzten Fold so viel gewachsen ist. |
|
|
126
|
-
| `trimIncrementTokens` | `
|
|
127
|
-
| `trimPressurePercent` | `
|
|
126
|
+
| `trimIncrementTokens` | `25000` | Schwellen-Begleiter: der zusammenhängende komprimierbare Zuwachs muss ebenfalls diese Größe erreichen. |
|
|
127
|
+
| `trimPressurePercent` | `65` | Druckstufe: falte, wenn die View-Nutzung diesen Prozentsatz des Kontextfensters erreicht. |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | Notfallstufe: erzwungener mechanischer Fold (kein Nebenmodell-Aufruf) bei diesem Prozentsatz. |
|
|
129
129
|
| `trimWindowTokens` | `0` | Effektives Fensterlimit für die Stufenberechnung: gerechnet gegen min(Modellfenster, Limit). `0` = folgt `wmForceTokens`. |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | Die letzten N Nachrichten werden nie gefaltet. |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | Fold-Takt-Obergrenze pro rollierender Stunde für Nebenmodell-Folds (Notfall-Folds ausgenommen). |
|
|
132
132
|
| `trimSideModel` | nicht gesetzt | Route des zusammenfassenden Nebenmodells. Leer = das aktuelle Session-Modell erben. |
|
|
133
|
+
| `trimFoldFallbackModel` | nicht gesetzt | Route, mit der der Fold den Zusammenfassungs-Versuch wiederholt; scheitert auch sie, degradiert ein Pressure-Fold zu mechanischem Folding. Leer = kein Fallback. Route mit Spielraum bei Cooldowns, Risikokontrolle und Concurrency wählen. |
|
|
133
134
|
| `trimStateDir` | nicht gesetzt | Überschreibt das Fold-Zustandsverzeichnis. Leer = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
134
135
|
| `surfaceFold` | `true` | Liefert committete Folds auf die Session-Oberfläche aus (Shadow-Price-Messereignis + `surfaceOp`-Replace-Ereignispaar). OFF behält die rein gesplicte View. |
|
|
135
136
|
|
|
136
137
|
**Trigger-Pfade.** Stufenprüfungen laufen an der Leerlauf-Grenze und — als Fallback für Hosts, auf denen Leerlauf-Status-Ereignisse nicht erreichbar sind — nach jedem Modell-Stream-Abschluss (auf eine Auswertung pro 60 s und Session gedrosselt). Jede Entscheidung — Folds wie No-ops gleichermaßen — wird als eine zeitgestempelte `key=value`-Zeile an `decisions.log` im Fold-Zustandsverzeichnis (siehe `trimStateDir`) angehängt und gibt Folds so eine Offline-Prüfspur; das Zeilenvokabular (`view-applied`, Fold-Entscheidungs-/Ergebniszeilen, `surface-replace`, `surface-replace skipped reason=…`) ist in [docs/context-trim.md](./docs/context-trim.md) katalogisiert.
|
|
137
138
|
|
|
138
|
-
**Leitungs-Wahrheit und stabiler Zustand.** Entscheidungszeilen tragen `view=<n>` und, sobald eine Antwort eingetroffen ist, `wire=<n>` — den echten Anbieter-Prompt (ungecachter Input + Cache-Read + Cache-Write, entnommen aus dem Usage-Event des Streams). Die View-Schätzung zählt nur das Messages-Array und liest immer um den festen Overhead kleiner als die Leitung (gemessen ≈ 17.3k: System-Prompt + Tool-Schemas + Persona); Druck- und Notfallstufe werten daher auf `max(view, wire)` aus, und nur `wire` ist eine Prompt-Größenmessung. In einem 150k-Fenster läuft der gesunde Sägezahn direkt nach einem Fold auf Leitung ≈ 40k ↔
|
|
139
|
+
**Leitungs-Wahrheit und stabiler Zustand.** Entscheidungszeilen tragen `view=<n>` und, sobald eine Antwort eingetroffen ist, `wire=<n>` — den echten Anbieter-Prompt (ungecachter Input + Cache-Read + Cache-Write, entnommen aus dem Usage-Event des Streams). Die View-Schätzung zählt nur das Messages-Array und liest immer um den festen Overhead kleiner als die Leitung (gemessen ≈ 17.3k: System-Prompt + Tool-Schemas + Persona); Druck- und Notfallstufe werten daher auf `max(view, wire)` aus, und nur `wire` ist eine Prompt-Größenmessung. In einem 150k-Fenster läuft der gesunde Sägezahn direkt nach einem Fold auf Leitung ≈ 40k ↔ 64–97.5k beim nächsten (≈27%–65% des Fensters), ein Fold pro ~25k Rohwachstum, wobei die Obergrenze eher von der Druckstufe als vom Fenster nahe 97.5k festgehalten wird. Steigt `view`, ohne dass je eine `surface-replace`-Zeile erscheint, lies die Skip-Zeilen (`incomplete-seqs`, `no-service`, `compaction-lock`).
|
|
139
140
|
|
|
140
141
|
**Host-Kompaktions-Epochen.** Fold-Verweise sind an Nachrichten-IDs und Inhalts-Hashes verankert; ersetzt der Host selbst den erneut gesendeten Verlauf, veralten sämtliche Blöcke auf einmal: keiner findet mehr seine Position, die View fällt still auf den Rohverlauf zurück (fail-open — das Entscheidungsprotokoll vermerkt `view-applied applied=0`), und das Plugin verankert seine Wachstumsbaseline bei der nächsten Anfrage auf der Sicht nach der Kompaktion. Die Host-Kompaktion ist damit die Backstop-Trimschicht; die Plugin-Folds leisten die feingranulare Arbeit innerhalb einer Host-Epoche. Manche Dispatches übergeben vollständig eingefrorene Anfrage-Arrays oder Optionsobjekte (die aktuelle Agent-Loop friert die zusammengesetzten Anfragen tief ein); für sie meldet `injectView` das Ergebnis im Entscheidungsprotokoll: `nothing-to-apply` (keine lokalisierbaren Fold-Blöcke — der Rohverlauf IST die View), `in-place`/`swapped` (der Fold-View wurde ausgeliefert) oder `none` (ein Fold existierte, aber der eingefrorene Dispatch konnte ihn nicht tragen — auf die Leitung geht der Rohverlauf). **Surface Replace ist der Auslieferungsweg, wann immer er verfügbar ist** (`surfaceFold`, standardmäßig an): an der seriellen `agent/turn-stopping`-Grenze plus einem Idle-Sweep hängt das Plugin das host-typische Shadow-Price-Messereignis und EIN `user/message`-Ersatzereignis an, das `surfaceOp {op:'replace', startSeq, endSeq}` trägt und mit `sourceEventSeqs` jeden überdeckten Oberflächen-Knoten abdeckt — derselbe Mechanismus, den die Host-Kompaktion selbst nutzt —, sodass ein committeter Fold aus der Quellschicht auf die Leitung gelangt, eingefrorene Dispatches eingeschlossen. Solange die letzten Dispatches einer Session `none` vermerken, behandelt das Plugin die View als reines Messobjekt: Der Wasserstand liest stattdessen die vom Anbieter gemeldete Zählung (force-Stufe und Auto-Übergabe arbeiten weiter), Fold-Zyklen pausieren, statt Summarizer-Aufrufe zu verbrennen, und das Trim-Banner markiert die Zeile mit `wire=raw` (folds not shipping; watermark reads the tally); Hosts ohne den Surface-Mechanismus (oder mit ausgeschaltetem Flag) behalten genau dieses alte Verhalten.
|
|
141
142
|
|
package/README.es.md
CHANGED
|
@@ -14,7 +14,7 @@ Trabajando con DSH, tarde o temprano te topas con dos cosas: la sesión pesa cad
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman es un plugin para [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Una vez instalado, el modelo principal deja de «hacerlo todo él solo» y pasa a ser el guardagujas: medir el nivel de agua, elegir el carril, repartir tareas y aceptar el trabajo. No es un modelo nuevo: es un reglamento de despacho enganchado a DSH, más una página de configuración. En concreto hace ocho cosas:
|
|
16
16
|
|
|
17
|
-
**1. Nivel de agua del contexto: la sesión larga no se desborda.** Cada turno contabiliza los tokens de la sesión en vivo, y tres líneas de nivel aprietan por etapas: 80k (soft, ajustable) avisa «toca delegar»;
|
|
17
|
+
**1. Nivel de agua del contexto: la sesión larga no se desborda.** Cada turno contabiliza los tokens de la sesión en vivo, y tres líneas de nivel aprietan por etapas: 80k (soft, ajustable) avisa «toca delegar»; 95k (hard) recorta el presupuesto de lectura por llamada y empuja al cierre; 150k (force) lanza la entrega automática — escribe el documento de entrega (el registro de sesión de solo añadido es la copia completa), compacta el contexto y despierta la sesión para continuar, sin que el trabajo se corte. Los subagentes en segundo plano que sigan corriendo en el momento de la entrega tampoco se pierden: id, descripción de la tarea y ruta del informe quedan escritos en el documento de entrega, y la sesión que continúa sabe dónde recoger los informes en vez de volver a despachar el trabajo. Cada subagente despachado lleva su propio techo duro independiente: al alcanzarlo, termina con un resumen HANDOFF. Si la intervención automática no te encaja, toma el mando manualmente en cualquier momento: `/ctx-pause` detiene todas las acciones del nivel (la medición sigue corriendo, la línea de nivel en vivo del final pasa a paused — solo deja de actuar), `/ctx-resume` lo devuelve en cualquier momento — tras reiniciar DSH la intervención también vuelve sola, lo sueltas por un rato, no lo apagas para siempre; `/ctx-handover` no espera a que el nivel llegue arriba y lanza esa misma entrega a demanda: escribe el documento de entrega, compacta el contexto, despierta la sesión para continuar (la sesión se conduce primero a la frontera de inactividad, así que el resultado puede tardar unos minutos).
|
|
18
18
|
|
|
19
19
|
**2. Seis pools de despacho: a cada trabajo, su modelo.** Pool ligero (economy, tareas pequeñas en lote), mecánico (mechanical, reescrituras con plantilla), principal (main, código del día a día), de alta dificultad (hard, razonamiento difícil y refactorizaciones a gran escala), multimodal (vision, leer imágenes) y de revisión (review, verificación independiente). En la página de ajustes marcas candidatos, ordenas prioridades (con anclaje opcional a las categorías S/A/B/C) y fijas un effort de razonamiento por ruta — el desplegable de categorías sale de los niveles que ese modelo soporta de verdad, no de tres genéricos. Cada turno, el prompt del modelo principal lleva consigo una tabla de recomendaciones `[SWITCHMAN:POOLS]`, y el trabajo se despacha siguiéndola. El modo de ejecución tiene tres estados: off / advice / enforce (enforce = los modelos fuera del pool se rechazan sin más).
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ La cabecera de la sesión da un feedback visual claro: la insignia ⚡ «equipo
|
|
|
86
86
|
bash <install-dir>/skills/db-query/scripts/setup.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
**Recomendaciones para el clasificador:** para desplegar el modelo de decisión en local, lo recomendable es servir `
|
|
89
|
+
**Recomendaciones para el clasificador:** para desplegar el modelo de decisión en local, lo recomendable es servir `d3:4b-mxfp8` con Ollama: elige el tipo de clasificador «endpoint de decisión (systemone)», rellena el endpoint con `http://127.0.0.1:11434/v1/systemone` y pon `d3:4b-mxfp8` como nombre del modelo. Si vas con el clasificador de chat del catálogo LLM, mejor un modelo pequeño en la nube, o un modelo local pequeño sin capacidad de pensamiento (razonamiento): desactivar el pensamiento reduce a la vez la latencia y la tasa de fallos por timeout de clasificación.
|
|
90
90
|
|
|
91
91
|
## Configuración predeterminada
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ Esto es todo el conjunto de valores tras una instalación nueva (fuente autorita
|
|
|
96
96
|
|
|
97
97
|
**Pools de despacho**: los seis carriles (economy/mechanical/main/hard/vision/review) arrancan sin candidatos (= los modelos por defecto del sistema, sin intervenir); el orden manual y el effort fijado, apagados/vacíos; `dispatchEnforce` = `advice` (solo aconseja, no obliga).
|
|
98
98
|
|
|
99
|
-
**Nivel de agua del contexto**: soft `80000` / hard `
|
|
99
|
+
**Nivel de agua del contexto**: soft `80000` / hard `95000` / force `150000` tokens; presupuesto de lectura por llamada `3000`; conducta al pasarse del presupuesto `cap` (recorta y avisa); `wmAutoHandover` = encendido (en force, escritura del documento de entrega + compactación automáticas); el techo duro de subagentes = encendido (150k compartidas).
|
|
100
100
|
|
|
101
101
|
**Agent Teams**: `teamsMode` = apagado; `syncWhitelist` = apagado (los dos interruptores son independientes entre sí).
|
|
102
102
|
|
|
103
103
|
**Enrutado por intención** (no disponible de fábrica; hacen falta clasificador + al menos un candidato + encender el interruptor maestro): `intentEnabled` = apagado (apagado, la entrada Auto queda oculta y las sesiones que ya la tenían elegida caen en la cadena de respaldo); ruta del clasificador sin configurar; tipo de clasificador `chat`; lista de candidatos vacía (las categorías preinstaladas solo entran en el enrutado cuando se les asigna un modelo); ventana de caché `300` s / umbral de confianza para el cambio `80` / timeout de clasificación `60000` ms; historial de `6` mensajes / `2400` caracteres; `intentContextWindow` = `200000`.
|
|
104
104
|
|
|
105
|
-
**Recorte de contexto**: `trimEnabled` = encendido; `trimMode` = `auto` (totalmente automático); compuerta de crecimiento `22500` + incremento `
|
|
105
|
+
**Recorte de contexto**: `trimEnabled` = encendido; `trimMode` = `auto` (totalmente automático); compuerta de crecimiento `22500` + incremento `25000` tokens; presión `65%` / emergencia `95%`; cola protegida `10` mensajes; tope de cadencia de folds `30` por hora; modelo secundario sin definir (hereda el modelo de la sesión) — detalles en la sección «Recorte automático del contexto» más abajo.
|
|
106
106
|
|
|
107
|
-
**Notas de serie**: ① que el enrutado por intención no venga disponible de serie es intencionado: tres pasos para activarlo (clasificador, candidatos, interruptor); ② la ventana efectiva de Auto vale 200000 de serie — la barrera de seguridad garantiza 0.8×ventana ≥ force (150000), así que la línea de compactación del núcleo (160000) queda siempre por detrás de la línea de entrega suave (150000); ③ lo más perceptible de serie es el trío de niveles: 80k avisa de delegar /
|
|
107
|
+
**Notas de serie**: ① que el enrutado por intención no venga disponible de serie es intencionado: tres pasos para activarlo (clasificador, candidatos, interruptor); ② la ventana efectiva de Auto vale 200000 de serie — la barrera de seguridad garantiza 0.8×ventana ≥ force (150000), así que la línea de compactación del núcleo (160000) queda siempre por detrás de la línea de entrega suave (150000); ③ lo más perceptible de serie es el trío de niveles: 80k avisa de delegar / 95k aprieta la lectura / 150k entrega automáticamente (documento + compactación) — sin tocar ningún ajuste.
|
|
108
108
|
|
|
109
109
|
## Recorte automático del contexto
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ Todas las claves viven en Ajustes → dsh-switchman; los valores por defecto sal
|
|
|
123
123
|
| `trimEnabled` | `true` | Interruptor maestro. Apagado desactiva folds y métricas por completo (el listener degenera en puro paso a través). |
|
|
124
124
|
| `trimMode` | `auto` | `off` solo medir / `advisory` folds dictados por el modelo / `auto` folds dictados por el sistema. |
|
|
125
125
|
| `trimGrowthTokens` | `22500` | Compuerta de crecimiento: pliega cuando la view saliente crezca esto desde el último fold. |
|
|
126
|
-
| `trimIncrementTokens` | `
|
|
127
|
-
| `trimPressurePercent` | `
|
|
126
|
+
| `trimIncrementTokens` | `25000` | Compañera de la compuerta: el incremento comprimible contiguo también debe alcanzar este tamaño. |
|
|
127
|
+
| `trimPressurePercent` | `65` | Escalón de presión: pliega cuando el uso de la view alcance este porcentaje de la ventana de contexto. |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | Escalón de emergencia: fold mecánico forzado (sin llamada al modelo secundario) a este porcentaje. |
|
|
129
129
|
| `trimWindowTokens` | `0` | Límite de ventana efectivo para el cálculo de niveles: se calcula sobre min(ventana del modelo, límite). `0` = sigue a `wmForceTokens`. |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | Los últimos N mensajes nunca se pliegan. |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | Tope de cadencia de folds por hora móvil para el modelo secundario (los de emergencia quedan exentos). |
|
|
132
132
|
| `trimSideModel` | sin definir | Ruta del modelo secundario que escribe los resúmenes. Vacía = heredar el modelo actual de la sesión. |
|
|
133
|
+
| `trimFoldFallbackModel` | sin definir | Ruta de reintento cuando falla el modelo secundario de resúmenes; un fold de presión degrada entonces a mecánico. Vacía = sin respaldo. Elige una ruta con margen en cooldowns, control de riesgo y concurrencia. |
|
|
133
134
|
| `trimStateDir` | sin definir | Anula el directorio del estado de folds. Vacía = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
134
135
|
| `surfaceFold` | `true` | Envía los folds confirmados a la superficie de la sesión (par de eventos de medición shadow-price + replace con `surfaceOp`). Apagado conserva la vista de solo empalme. |
|
|
135
136
|
|
|
136
137
|
**Rutas de activación.** Las comprobaciones de escalones se ejecutan en el límite de inactividad y, como respaldo para hosts donde los eventos de estado de inactividad son inalcanzables, tras cada finalización del flujo del modelo (limitadas a una evaluación cada 60 s por sesión). Cada decisión — folds y no-ops por igual — se añade como una línea `key=value` con marca de tiempo a `decisions.log` en el directorio del estado de folds (véase `trimStateDir`), dando a los folds una pista de auditoría fuera de línea; el vocabulario de filas (`view-applied`, filas de decisión/resultado de folds, `surface-replace`, `surface-replace skipped reason=…`) está catalogado en [docs/context-trim.md](./docs/context-trim.md).
|
|
137
138
|
|
|
138
|
-
**Verdad del cable y estado estacionario.** Las filas de decisión llevan `view=<n>` y, una vez que una respuesta ha llegado, `wire=<n>` — el prompt real del proveedor (entrada sin caché + lectura de caché + escritura de caché, muestreado del evento de uso del stream). La estimación de la view cuenta solo el array de mensajes y siempre lee menos que el cable por la sobrecarga fija (medida ≈ 17.3k: system prompt + esquemas de herramientas + persona), así que los escalones de presión y emergencia evalúan sobre `max(view, wire)`, y solo `wire` es una lectura del tamaño del prompt. En una ventana de 150k, el diente de sierra sano marca el cable en ≈ 40k justo después de un fold ↔
|
|
139
|
+
**Verdad del cable y estado estacionario.** Las filas de decisión llevan `view=<n>` y, una vez que una respuesta ha llegado, `wire=<n>` — el prompt real del proveedor (entrada sin caché + lectura de caché + escritura de caché, muestreado del evento de uso del stream). La estimación de la view cuenta solo el array de mensajes y siempre lee menos que el cable por la sobrecarga fija (medida ≈ 17.3k: system prompt + esquemas de herramientas + persona), así que los escalones de presión y emergencia evalúan sobre `max(view, wire)`, y solo `wire` es una lectura del tamaño del prompt. En una ventana de 150k, el diente de sierra sano marca el cable en ≈ 40k justo después de un fold ↔ 64–97.5k en el siguiente (≈27%–65% de la ventana), un fold por cada ~25k de crecimiento bruto, con el techo fijado cerca de 97.5k por el escalón de presión y no por la ventana. Si `view` sube sin que aparezca nunca una fila `surface-replace`, lee las filas de omisión (`incomplete-seqs`, `no-service`, `compaction-lock`).
|
|
139
140
|
|
|
140
141
|
**Épocas de compactación del host.** Las referencias de fold se anclan en ids de mensaje y hashes de contenido, de modo que una compactación del propio host que reemplace el historial reenviado hace envejecer el libro entero de golpe: ningún bloque localiza su posición, la vista retrocede silenciosamente al historial sin plegar (fail-open — el registro de decisiones anota `view-applied applied=0`) y el plugin reancla su línea base de crecimiento en la vista posterior a la compactación en la siguiente petición. La compactación del host es así la capa de recorte de último recurso; los folds del plugin hacen el trabajo fino dentro de una época del host. Algunos despachos entregan matrices de solicitud u objetos de opciones totalmente congelados (el bucle de agente actual congela en profundidad las peticiones ya montadas); para ellos, `injectView` informa del resultado en el registro de decisiones: `nothing-to-apply` (no hay bloques de fold localizados — el historial sin plegar ES la vista), `in-place`/`swapped` (la vista plegada viajó con la petición) o `none` (había un fold, pero el despacho congelado no podía llevarlo — por el cable va el historial sin plegar). **El reemplazo de superficie es la ruta de envío cuando está disponible** (`surfaceFold`, activado por defecto): en el límite serial `agent/turn-stopping` más un barrido de inactividad, el plugin añade el evento de medición shadow-price al estilo del host y UN reemplazo `user/message` que lleva `surfaceOp {op:'replace', startSeq, endSeq}` con `sourceEventSeqs` cubriendo cada nodo de superficie sombreado — el mismo mecanismo que usa la propia compactación del host —, de modo que un fold confirmado llega al cable desde el nivel de origen, despachos congelados incluidos. Mientras los despachos recientes de una sesión registran `none`, el plugin trata la vista como solo-medición: el nivel de agua mide en su lugar la cuenta que reporta el proveedor (el escalón force y la entrega automática siguen funcionando), los ciclos de fold se pausan en vez de quemar llamadas al resumidor, y el banner de recorte marca la línea con `wire=raw` (folds not shipping; watermark reads the tally); los hosts sin el mecanismo de superficie (o con la opción apagada) se quedan exactamente con ese comportamiento antiguo.
|
|
141
142
|
|
package/README.fr.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman est un plugin pour [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Une fois installé, le modèle principal passe de « tout faire lui-même » au rôle de répartiteur : mesurer le niveau d'eau, choisir le couloir, distribuer les tâches, contrôler le résultat. Ce n'est pas un nouveau modèle — c'est une doctrine d'orchestration accrochée à DSH, accompagnée d'une page de réglages. Concrètement, il fait huit choses :
|
|
16
16
|
|
|
17
|
-
**1. Niveau d'eau du contexte : les longues sessions ne débordent jamais.** Chaque tour compte en direct les tokens de la session et les confronte à trois lignes d'eau qui durcissent par paliers : 80k (soft, réglable) rappelle qu'« il est temps de déléguer » ;
|
|
17
|
+
**1. Niveau d'eau du contexte : les longues sessions ne débordent jamais.** Chaque tour compte en direct les tokens de la session et les confronte à trois lignes d'eau qui durcissent par paliers : 80k (soft, réglable) rappelle qu'« il est temps de déléguer » ; 95k (hard) resserre le budget de lecture par appel et pousse à conclure ; 150k (force) déclenche la remise automatique — le document de remise est écrit (le journal de session à ajout seul constitue la sauvegarde complète), le contexte compacté, la session réveillée pour continuer, et la tâche ne s'interrompt jamais. Les subagents d'arrière-plan encore en course à cet instant ne sont pas perdus pour autant : leurs id, descriptions de tâche et chemins de rapport sont consignés dans le document de remise, et la session relancée sait où récupérer les rapports au lieu de redéspatcher en double. Chaque subagent dispatché embarque son propre plafond strict ; une fois atteint, il écrit son résumé HANDOFF et se retire. Quand l'intervention automatique ne vous convient pas, reprenez la main à tout moment : `/ctx-pause` arrête toutes les actions de niveau (la mesure continue, la ligne d'eau en direct de la fin passe en paused — il n'agit plus, c'est tout), `/ctx-resume` rétablit à tout moment — après un redémarrage de DSH, l'intervention revient aussi d'elle-même, un lâcher-prise temporaire, pas une extinction définitive ; `/ctx-handover` n'attend pas que le niveau touche le plafond et déclenche à la demande la même remise : écrire le document de remise, compacter le contexte, réveiller la session pour continuer (la session est d'abord conduite jusqu'à la limite d'inactivité, le résultat peut donc prendre quelques minutes).
|
|
18
18
|
|
|
19
19
|
**2. Six pools de dispatch : le bon modèle pour chaque tâche.** Un pool léger (economy, les petites tâches en série), un pool mécanique (mechanical, les réécritures sur gabarit), un pool principal (main, le code au quotidien), un pool haute difficulté (hard, raisonnement corsé et refontes à grande échelle), un pool multimodal (vision, lire les images) et un pool de relecture (review, vérification indépendante). Dans la page de réglages, vous cochez les candidats, les classez par priorité (avec tiers S/A/B/C en option) et épinglez un effort de raisonnement pour chaque route — le menu déroulant des niveaux reflète ce que ce modèle supporte réellement, pas trois niveaux génériques. Chaque prompt du modèle principal embarque une table de recommandations `[SWITCHMAN:POOLS]`, et le dispatch suit cette table. Le mode d'exécution a trois états : off / advice / enforce (enforce = tout modèle hors pool est refusé sans appel).
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ Un seul modèle ? Ça vaut quand même l'installation — le contrôle du niveau
|
|
|
86
86
|
bash <install-dir>/skills/db-query/scripts/setup.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
**Conseils de choix du classificateur :** pour déployer le modèle de décision en local, le plus simple est de servir `
|
|
89
|
+
**Conseils de choix du classificateur :** pour déployer le modèle de décision en local, le plus simple est de servir `d3:4b-mxfp8` avec Ollama : choisissez le type de classificateur « endpoint de décision (systemone) », renseignez l'endpoint avec `http://127.0.0.1:11434/v1/systemone` et indiquez `d3:4b-mxfp8` comme nom de modèle. Avec le classificateur de chat du catalogue LLM, privilégiez un petit modèle cloud, ou un petit modèle local sans capacité de réflexion (raisonnement) : désactiver la réflexion réduit à la fois la latence et le taux d'échecs par timeout de classification.
|
|
90
90
|
|
|
91
91
|
## Configuration par défaut
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ Voici l'ensemble complet des valeurs juste après une installation neuve (source
|
|
|
96
96
|
|
|
97
97
|
**Pools de dispatch** : les six couloirs (economy/mechanical/main/hard/vision/review) démarrent sans candidats (= les modèles par défaut du système, aucune intervention) ; l'ordre manuel et l'effort épinglé sont désactivés/vides ; `dispatchEnforce` = `advice` (simple recommandation, rien n'est forcé).
|
|
98
98
|
|
|
99
|
-
**Niveau d'eau du contexte** : soft `80000` / hard `
|
|
99
|
+
**Niveau d'eau du contexte** : soft `80000` / hard `95000` / force `150000` tokens ; budget de lecture par appel `3000` ; comportement en cas de dépassement `cap` (tronquer avec avertissement) ; `wmAutoHandover` = activé (à force, écriture du document de remise + compactage automatiques) ; le plafond strict des subagents = activé (150k partagées).
|
|
100
100
|
|
|
101
101
|
**Agent Teams** : `teamsMode` = désactivé ; `syncWhitelist` = désactivé (les deux interrupteurs sont indépendants l'un de l'autre).
|
|
102
102
|
|
|
103
103
|
**Routage par intention** (indisponible par défaut ; il exige un classifieur + au moins un candidat + l'interrupteur général) : `intentEnabled` = désactivé (désactivé, l'entrée Auto reste cachée et les sessions déjà passées en Auto empruntent la chaîne de repli) ; route du classifieur non définie ; type de classifieur `chat` ; liste de candidats vide (les catégories préinstallées ne participent au routage qu'une fois un modèle renseigné) ; fenêtre de cache `300` s / seuil de confiance du basculement `80` / timeout de classification `60000` ms ; historique de `6` messages / `2400` caractères ; `intentContextWindow` = `200000`.
|
|
104
104
|
|
|
105
|
-
**Trim de contexte** : `trimEnabled` = activé ; `trimMode` = `auto` (entièrement automatique) ; porte de croissance `22500` + incrément `
|
|
105
|
+
**Trim de contexte** : `trimEnabled` = activé ; `trimMode` = `auto` (entièrement automatique) ; porte de croissance `22500` + incrément `25000` tokens ; pression `65%` / urgence `95%` ; queue protégée `10` messages ; plafond de cadence des folds `30` par heure ; modèle annexe non défini (hérite du modèle de la session) — détails dans la section « Trim automatique du contexte » ci-dessous.
|
|
106
106
|
|
|
107
|
-
**À savoir dès l'installation** : ① l'indisponibilité du routage par intention en sortie d'usine est un choix délibéré — trois étapes pour l'activer (classifieur, candidats, interrupteur) ; ② la fenêtre effective d'Auto vaut 200000 dès l'usine — le garde-fou garantit 0.8×fenêtre ≥ force (150000), si bien que la ligne de compactage cœur (160000) se situe toujours après la ligne de remise en douceur (150000) ; ③ l'effet le plus tangible dès l'usine est le trio de niveaux : 80k rappelle de déléguer /
|
|
107
|
+
**À savoir dès l'installation** : ① l'indisponibilité du routage par intention en sortie d'usine est un choix délibéré — trois étapes pour l'activer (classifieur, candidats, interrupteur) ; ② la fenêtre effective d'Auto vaut 200000 dès l'usine — le garde-fou garantit 0.8×fenêtre ≥ force (150000), si bien que la ligne de compactage cœur (160000) se situe toujours après la ligne de remise en douceur (150000) ; ③ l'effet le plus tangible dès l'usine est le trio de niveaux : 80k rappelle de déléguer / 95k resserre la lecture / 150k remet automatiquement (document + compactage) — sans aucun réglage.
|
|
108
108
|
|
|
109
109
|
## Trim automatique du contexte
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ Toutes les clés vivent dans Réglages → dsh-switchman ; les valeurs par défa
|
|
|
123
123
|
| `trimEnabled` | `true` | Interrupteur maître. Désactivé, folding et métriques s'arrêtent totalement (le listener se dégrade en simple passage). |
|
|
124
124
|
| `trimMode` | `auto` | `off` mesure seule / `advisory` folds pilotés par le modèle / `auto` folds pilotés par le système. |
|
|
125
125
|
| `trimGrowthTokens` | `22500` | Porte de croissance : on plie quand la view sortante a grandi d'autant depuis le dernier fold. |
|
|
126
|
-
| `trimIncrementTokens` | `
|
|
127
|
-
| `trimPressurePercent` | `
|
|
126
|
+
| `trimIncrementTokens` | `25000` | Compagnon de la porte : l'incrément compressible contigu doit aussi atteindre cette taille. |
|
|
127
|
+
| `trimPressurePercent` | `65` | Palier de pression : on plie quand l'usage de la view atteint ce pourcentage de la fenêtre de contexte. |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | Palier d'urgence : fold mécanique forcé (sans appel de modèle annexe) à ce pourcentage. |
|
|
129
129
|
| `trimWindowTokens` | `0` | Plafond de fenêtre effectif pour le calcul des paliers : calculé sur min(fenêtre du modèle, plafond). `0` = suit `wmForceTokens`. |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | Les N derniers messages ne sont jamais repliés. |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | Plafond de cadence des folds par heure glissante pour le modèle annexe (les folds d'urgence en sont exemptés). |
|
|
132
132
|
| `trimSideModel` | non définie | Route du modèle annexe qui écrit les résumés. Vide = hériter du modèle courant de la session. |
|
|
133
|
+
| `trimFoldFallbackModel` | non définie | Route de relance quand le modèle annexe de résumé échoue ; un fold de pression dégrade alors en mécanique. Vide = pas de repli. Choisir une route avec de la marge sur cooldowns, contrôle de risque et concurrence. |
|
|
133
134
|
| `trimStateDir` | non défini | Redéfinit le répertoire d'état des folds. Vide = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
134
135
|
| `surfaceFold` | `true` | Expédie les folds validés sur la surface de session (paire d'événements : mesure shadow-price + remplacement `surfaceOp`). Désactivé, la vue reste en splice seul. |
|
|
135
136
|
|
|
136
137
|
**Chemins de déclenchement.** Les vérifications de paliers s'exécutent à la frontière d'inactivité et, en repli pour les hôtes où les événements d'état d'inactivité sont inaccessibles, après chaque fin de flux du modèle (limitées à une évaluation par 60 s et par session). Chaque décision — folds comme no-ops — est ajoutée comme une ligne `key=value` horodatée à `decisions.log` dans le répertoire d'état des folds (voir `trimStateDir`), donnant aux folds une piste d'audit hors ligne; le vocabulaire des lignes (`view-applied`, lignes de décision/résultat de fold, `surface-replace`, `surface-replace skipped reason=…`) est catalogué dans [docs/context-trim.md](./docs/context-trim.md).
|
|
137
138
|
|
|
138
|
-
**Vérité du fil et régime stationnaire.** Les lignes de décision portent `view=<n>` et, une fois qu'une réponse est arrivée, `wire=<n>` — le prompt réel du fournisseur (entrée non cachée + lecture de cache + écriture de cache, échantillonné depuis l'événement d'usage du stream). L'estimation de la view ne compte que le tableau de messages et lit toujours moins que le fil, du surcoût fixe (mesuré ≈ 17.3k : system prompt + schémas d'outils + persona), donc les paliers de pression et d'urgence évaluent sur `max(view, wire)`, et seul `wire` est une lecture de la taille du prompt. Sur une fenêtre de 150k, la dent de scie saine fait tourner le fil à ≈ 40k juste après un fold ↔
|
|
139
|
+
**Vérité du fil et régime stationnaire.** Les lignes de décision portent `view=<n>` et, une fois qu'une réponse est arrivée, `wire=<n>` — le prompt réel du fournisseur (entrée non cachée + lecture de cache + écriture de cache, échantillonné depuis l'événement d'usage du stream). L'estimation de la view ne compte que le tableau de messages et lit toujours moins que le fil, du surcoût fixe (mesuré ≈ 17.3k : system prompt + schémas d'outils + persona), donc les paliers de pression et d'urgence évaluent sur `max(view, wire)`, et seul `wire` est une lecture de la taille du prompt. Sur une fenêtre de 150k, la dent de scie saine fait tourner le fil à ≈ 40k juste après un fold ↔ 64–97.5k au suivant (≈27%–65% de la fenêtre), un fold par ~25k de croissance brute, le plafond étant arrimé près de 97.5k par le palier de pression plutôt que par la fenêtre. Si `view` monte sans qu'aucune ligne `surface-replace` n'apparaisse jamais, lisez les lignes d'omission (`incomplete-seqs`, `no-service`, `compaction-lock`).
|
|
139
140
|
|
|
140
141
|
**Époques de compactage de l'hôte.** Les références de fold sont ancrées dans les identifiants de messages et les hachages de contenu ; quand l'hôte compacte lui-même l'historique renvoyé, tout le registre vieillit d'un coup : plus aucun bloc ne se localise, la vue retombe silencieusement sur l'historique brut (fail-open — le journal des décisions note `view-applied applied=0`), et le plugin ré-ancre sa base de croissance sur la vue post-compaction à la requête suivante. La compaction de l'hôte est donc la couche de rognage de dernier recours ; les folds du plugin font le travail fin au sein d'une époque de l'hôte. Certains dispatches remettent des tableaux de requête ou des objets d'options entièrement gelés (la boucle d'agent actuelle gèle en profondeur les requêtes assemblées) ; pour eux, `injectView` rapporte l'issue dans le journal des décisions : `nothing-to-apply` (aucun bloc de fold localisé — l'historique brut EST la vue), `in-place`/`swapped` (la vue pliée est partie avec la requête) ou `none` (un fold existait mais le dispatch gelé ne pouvait pas le transporter — l'historique brut part sur le fil). **Le remplacement de surface est le chemin d'expédition quand il est disponible** (`surfaceFold`, activé par défaut) : à la frontière sérielle `agent/turn-stopping` plus un balayage d'inactivité, le plugin ajoute l'événement de mesure shadow-price à la manière de l'hôte et UN remplacement `user/message` portant `surfaceOp {op:'replace', startSeq, endSeq}` avec des `sourceEventSeqs` couvrant chaque nœud de surface masqué — le même mécanisme que celui de la compaction de l'hôte elle-même —, de sorte qu'un fold validé rejoint le fil depuis le niveau source, dispatches gelés compris. Tant que les dispatches récents d'une session consignent `none`, le plugin traite la vue comme une simple mesure : le niveau d'eau lit à la place le total rapporté par le fournisseur (le palier force et la remise automatique continuent de fonctionner), les cycles de fold se mettent en pause au lieu de brûler des appels au résumeur, et la bannière de rognage marque la ligne avec `wire=raw` (folds not shipping; watermark reads the tally) ; les hôtes sans le mécanisme de surface (ou avec l'option désactivée) gardent exactement cet ancien comportement.
|
|
141
142
|
|
package/README.it.md
CHANGED
|
@@ -14,7 +14,7 @@ Se lavori con DSH, col passare del tempo ti imbatti in due cose: la sessione pes
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman è un plugin per [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Una volta installato, il modello principale smette di «fare tutto da solo» e diventa un dispatcher: misura il livello dell'acqua, sceglie la corsia, assegna i task, verifica il risultato. Non è un nuovo modello: è un regolamento di orchestrazione agganciato a DSH più un'interfaccia di configurazione. In concreto fa otto cose:
|
|
16
16
|
|
|
17
|
-
**1. Livello dell'acqua del contesto: le sessioni lunghe non esplodono.** A ogni turno conta i token della sessione in tempo reale, e tre soglie inaspriscono a gradini: 80k (soft, regolabile) ricorda che «è ora di delegare»;
|
|
17
|
+
**1. Livello dell'acqua del contesto: le sessioni lunghe non esplodono.** A ogni turno conta i token della sessione in tempo reale, e tre soglie inaspriscono a gradini: 80k (soft, regolabile) ricorda che «è ora di delegare»; 95k (hard) stringe il budget di lettura per singola chiamata e spinge verso la chiusura; 150k (force) avvia l'handover automatico — scrittura del documento di handover (il log di sessione append-only è la copia completa), contesto compattato, sessione risvegliata per continuare: il task non si interrompe. Nemmeno i subagent in background ancora in corsa al momento del passaggio si perdono: id, descrizione del task e percorso del report finiscono nel documento di handover, così la sessione ripresa sa dove raccogliere i report invece di ri-assegnare lo stesso lavoro. Ogni subagent inviato porta con sé un tetto massimo indipendente e, raggiunto il limite, esce dopo aver scritto il riepilogo HANDOFF. Se l'intervento automatico non ti torna, prendi tu il comando in qualsiasi momento: `/ctx-pause` ferma tutte le azioni della soglia (la misurazione continua, la riga del livello dell'acqua in tempo reale in coda passa a paused — smette solo di agire), `/ctx-resume` ripristina in qualsiasi momento — dopo un riavvio di DSH l'intervento torna anche da solo, un mollare la presa temporaneo, non uno spegnimento definitivo; `/ctx-handover` non aspetta che la soglia tocchi il limite e avvia su richiesta lo stesso handover: scrittura del documento di handover, compattazione del contesto, risveglio della sessione per continuare (la sessione viene prima guidata fino al confine di inattività, quindi il risultato può richiedere qualche minuto).
|
|
18
18
|
|
|
19
19
|
**2. Sei pool di dispatch: a ogni lavoro il suo modello.** Pool leggero (economy, piccoli lavori in serie), pool meccanico (mechanical, riscritture modellate), pool principale (main, coding di tutti i giorni), pool ad alta difficoltà (hard, ragionamento complesso e refactoring su larga scala), pool multimodale (vision, lettura delle immagini), pool di revisione (review, verifica indipendente). Nella pagina delle impostazioni spunti i candidati, ordini le priorità (con fasce opzionali S/A/B/C) e fichi un reasoning effort per ogni route — il menu a tendina elenca i livelli che quel modello supporta davvero, non tre livelli generici. A ogni turno il prompt del modello principale viaggia con una tabella di raccomandazioni `[SWITCHMAN:POOLS]`: si assegna il lavoro seguendo la tabella. La modalità di esecuzione ha tre stati: off / advice / enforce (enforce = i modelli fuori pool vengono rifiutati sul posto).
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ Un solo modello? Vale comunque la pena installarlo — il controllo del livello
|
|
|
86
86
|
bash <install-dir>/skills/db-query/scripts/setup.sh
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
**Consigli sulla scelta del classificatore:** per far girare il modello di decisione in locale, la scelta consigliata è servire `
|
|
89
|
+
**Consigli sulla scelta del classificatore:** per far girare il modello di decisione in locale, la scelta consigliata è servire `d3:4b-mxfp8` con Ollama: imposta il tipo di classificatore su «endpoint di decisione (systemone)», compila l'endpoint con `http://127.0.0.1:11434/v1/systemone` e indica `d3:4b-mxfp8` come nome del modello. Con il classificatore di chat del catalogo LLM, meglio un piccolo modello cloud, o un piccolo modello locale senza capacità di pensiero (ragionamento): disattivare il pensiero riduce insieme la latenza e il tasso di fallimenti per timeout di classificazione.
|
|
90
90
|
|
|
91
91
|
## Configurazione predefinita
|
|
92
92
|
|
|
@@ -96,15 +96,15 @@ Questi sono tutti i valori così come si presentano dopo una nuova installazione
|
|
|
96
96
|
|
|
97
97
|
**Pool di dispatch**: le sei corsie (economy/mechanical/main/hard/vision/review) partono senza candidati (= i modelli predefiniti del sistema, nessuna interferenza); ordine manuale ed effort fissato spenti/vuoti; `dispatchEnforce` = `advice` (solo consiglio, niente di imposto).
|
|
98
98
|
|
|
99
|
-
**Livello dell'acqua del contesto**: soft `80000` / hard `
|
|
99
|
+
**Livello dell'acqua del contesto**: soft `80000` / hard `95000` / force `150000` token; budget di lettura per singola chiamata `3000`; comportamento oltre budget `cap` (tronca con avviso); `wmAutoHandover` = attivo (a force, scrittura del documento di handover + compattazione automatiche); il tetto massimo dei subagent = attivo (150k condivisi).
|
|
100
100
|
|
|
101
101
|
**Agent Teams**: `teamsMode` = spento; `syncWhitelist` = spento (i due interruttori sono indipendenti tra loro).
|
|
102
102
|
|
|
103
103
|
**Instradamento per intent** (non disponibile per predefinito; servono classificatore + almeno un candidato + l'interruttore principale): `intentEnabled` = spento (spento, la voce Auto resta nascosta e le sessioni che l'avevano già scelta percorrono la catena di fallback); route del classificatore non impostata; tipo di classificatore `chat`; lista dei candidati vuota (le categorie preinstallate entrano nell'instradamento solo con un modello assegnato); finestra di cache `300` s / soglia di confidenza del cambio `80` / timeout di classificazione `60000` ms; cronologia di `6` messaggi / `2400` caratteri; `intentContextWindow` = `200000`.
|
|
104
104
|
|
|
105
|
-
**Trim del contesto**: `trimEnabled` = acceso; `trimMode` = `auto` (del tutto automatico); cancello di crescita `22500` + incremento `
|
|
105
|
+
**Trim del contesto**: `trimEnabled` = acceso; `trimMode` = `auto` (del tutto automatico); cancello di crescita `22500` + incremento `25000` token; pressione `65%` / emergenza `95%`; coda protetta `10` messaggi; tetto di cadenza dei fold `30` all'ora; modello secondario non impostato (eredita il modello della sessione) — dettagli nella sezione «Trim automatico del contesto» più sotto.
|
|
106
106
|
|
|
107
|
-
**Note di serie**: ① l'instradamento per intent non disponibile di serie è una scelta voluta — tre passi per attivarlo (classificatore, candidati, interruttore); ② la finestra effettiva di Auto vale di serie 200000 — la barriera di sicurezza garantisce 0.8×finestra ≥ force (150000), così la linea di compattazione del cuore (160000) resta sempre dopo la linea di consegna morbida (150000); ③ di serie la cosa più percettibile è il terzetto di soglie: 80k ricorda di delegare /
|
|
107
|
+
**Note di serie**: ① l'instradamento per intent non disponibile di serie è una scelta voluta — tre passi per attivarlo (classificatore, candidati, interruttore); ② la finestra effettiva di Auto vale di serie 200000 — la barriera di sicurezza garantisce 0.8×finestra ≥ force (150000), così la linea di compattazione del cuore (160000) resta sempre dopo la linea di consegna morbida (150000); ③ di serie la cosa più percettibile è il terzetto di soglie: 80k ricorda di delegare / 95k stringe la lettura / 150k consegna da sola (documento + compattazione) — senza alcuna impostazione.
|
|
108
108
|
|
|
109
109
|
## Trim automatico del contesto
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ Tutte le chiavi stanno in Impostazioni → dsh-switchman; i valori predefiniti v
|
|
|
123
123
|
| `trimEnabled` | `true` | Interruttore principale. Spento disattiva fold e metriche del tutto (il listener degrada a puro pass-through). |
|
|
124
124
|
| `trimMode` | `auto` | `off` solo misura / `advisory` fold guidati dal modello / `auto` fold guidati dal sistema. |
|
|
125
125
|
| `trimGrowthTokens` | `22500` | Cancello di crescita: ripiega quando la view in uscita è cresciuta di tanto dall'ultimo fold. |
|
|
126
|
-
| `trimIncrementTokens` | `
|
|
127
|
-
| `trimPressurePercent` | `
|
|
126
|
+
| `trimIncrementTokens` | `25000` | Compagno del cancello: anche l'incremento comprimibile contiguo deve raggiungere questa taglia. |
|
|
127
|
+
| `trimPressurePercent` | `65` | Scalino di pressione: ripiega quando l'uso della view raggiunge questa percentuale della finestra di contesto. |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | Scalino di emergenza: fold meccanico forzato (nessuna chiamata al modello secondario) a questa percentuale. |
|
|
129
129
|
| `trimWindowTokens` | `0` | Limite di finestra effettivo per il calcolo delle soglie: calcolato su min(finestra del modello, limite). `0` = segue `wmForceTokens`. |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | Gli ultimi N messaggi non vengono mai ripiegati. |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | Tetto di cadenza dei fold per ora mobile per il modello secondario (quelli di emergenza ne sono esenti). |
|
|
132
132
|
| `trimSideModel` | non impostata | Route del modello secondario che scrive i riassunti. Vuota = eredita il modello attuale della sessione. |
|
|
133
|
+
| `trimFoldFallbackModel` | non impostata | Route di ripiego quando il modello secondario dei riassunti fallisce; un fold di pressione degrada quindi a meccanico. Vuota = nessun fallback. Scegli una route con margine su cooldown, risk control e concorrenza. |
|
|
133
134
|
| `trimStateDir` | non impostata | Sostituisce la directory dello stato dei fold. Vuota = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
134
135
|
| `surfaceFold` | `true` | Spedisce i fold confermati sulla superficie della sessione (coppia di eventi: misurazione shadow-price + replace `surfaceOp`). OFF mantiene la vista a solo splice. |
|
|
135
136
|
|
|
136
137
|
**Percorsi di attivazione.** I controlli degli scalini girano al confine di inattività e, come ripiego per gli host dove gli eventi di stato di inattività non sono raggiungibili, dopo ogni completamento del flusso del modello (limitati a una valutazione ogni 60 s per sessione). Ogni decisione — fold e no-op allo stesso modo — viene aggiunta come una riga `key=value` con timestamp a `decisions.log` nella directory dello stato dei fold (vedi `trimStateDir`), dando ai fold una traccia di audit offline; il vocabolario delle righe (`view-applied`, righe di decisione/esito dei fold, `surface-replace`, `surface-replace skipped reason=…`) è catalogato in [docs/context-trim.md](./docs/context-trim.md).
|
|
137
138
|
|
|
138
|
-
**Verità del filo e stato stazionario.** Le righe di decisione portano `view=<n>` e, una volta arrivata una risposta, `wire=<n>` — il prompt reale del provider (input non in cache + lettura cache + scrittura cache, campionato dall'evento di utilizzo dello stream). La stima della view conta solo l'array di messaggi e legge sempre meno del filo, della misura dell'overhead fisso (misurato ≈ 17.3k: system prompt + schemi degli strumenti + persona), quindi gli scalini di pressione e di emergenza valutano su `max(view, wire)`, e solo `wire` è una lettura della dimensione del prompt. Su una finestra da 150k l'andamento a dente di sega sano porta il filo a ≈ 40k subito dopo un fold ↔
|
|
139
|
+
**Verità del filo e stato stazionario.** Le righe di decisione portano `view=<n>` e, una volta arrivata una risposta, `wire=<n>` — il prompt reale del provider (input non in cache + lettura cache + scrittura cache, campionato dall'evento di utilizzo dello stream). La stima della view conta solo l'array di messaggi e legge sempre meno del filo, della misura dell'overhead fisso (misurato ≈ 17.3k: system prompt + schemi degli strumenti + persona), quindi gli scalini di pressione e di emergenza valutano su `max(view, wire)`, e solo `wire` è una lettura della dimensione del prompt. Su una finestra da 150k l'andamento a dente di sega sano porta il filo a ≈ 40k subito dopo un fold ↔ 64–97.5k al successivo (≈27%–65% della finestra), un fold ogni ~25k di crescita grezza, con il tetto fissato vicino a 97.5k dallo scalino di pressione anziché dalla finestra. Se `view` sale senza che compaia mai una riga `surface-replace`, leggi le righe di salto (`incomplete-seqs`, `no-service`, `compaction-lock`).
|
|
139
140
|
|
|
140
141
|
**Epoche di compattazione dell'host.** I riferimenti dei fold sono ancorati a id dei messaggi e hash dei contenuti; quando l'host compatta esso stesso la cronologia reinviata, l'intero registro invecchia in un colpo: nessun blocco si localizza, la vista retrocede silenziosamente alla cronologia grezza (fail-open — il registro delle decisioni annota `view-applied applied=0`) e il plugin re-ancora la sua baseline di crescita sulla vista post-compattazione alla richiesta successiva. La compattazione dell'host è quindi lo strato di taglio di ultima istanza; i fold del plugin fanno il lavoro fine all'interno di un'epoca dell'host. Alcuni dispatch consegnano array di richiesta o oggetti opzioni completamente congelati (l'attuale loop d'agente congela in profondità le richieste assemblate); per essi `injectView` riporta l'esito nel registro delle decisioni: `nothing-to-apply` (nessun blocco di fold localizzato — la cronologia grezza È la vista), `in-place`/`swapped` (la vista piegata è partita con la richiesta) oppure `none` (esisteva un fold ma il dispatch congelato non poteva portarlo — sul filo va la cronologia grezza). **La sostituzione di superficie è la via di spedizione quando disponibile** (`surfaceFold`, attivo per impostazione predefinita): al confine seriale `agent/turn-stopping` più una spazzata di inattività, il plugin aggiunge l'evento di misurazione shadow-price in stile host e UNA sostituzione `user/message` che porta `surfaceOp {op:'replace', startSeq, endSeq}` con `sourceEventSeqs` che copre ogni nodo di superficie in ombra — lo stesso meccanismo usato dalla compattazione dell'host stessa — cosicché un fold confermato raggiunge il filo dal livello sorgente, dispatch congelati compresi. Finché i dispatch recenti di una sessione registrano `none`, il plugin tratta la vista come sola misurazione: il livello dell'acqua misura invece il conteggio riportato dal provider (lo scalino force e la consegna automatica continuano a funzionare), i cicli di fold si mettono in pausa invece di bruciare chiamate al riassuntore, e il banner di taglio contrassegna la riga con `wire=raw` (folds not shipping; watermark reads the tally); gli host senza il meccanismo di superficie (o con il flag spento) mantengono esattamente quel comportamento legacy.
|
|
141
142
|
|
package/README.ja.md
CHANGED
|
@@ -14,7 +14,7 @@ DSHで長く作業していると、悩みが2つ出てくる。1つはセッシ
|
|
|
14
14
|
|
|
15
15
|
dsh-switchman は [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)のプラグインだ。入れると主モデルは「自分で作業する」役から運転指令へ変わる:水位を測り、レーンを選び、タスクを投げ、受け入れを確認する。新モデルではない。DSHに取り付けるディスパッチ規程と設定ページであり、8つのことを行う。
|
|
16
16
|
|
|
17
|
-
**1. コンテキスト水位:長いセッションを破裂させない。** 毎ターンリアルタイムでセッショントークンを数え、3本の水位線が段階的に締め上げる:80k(soft、調整可)は「そろそろ委譲を」、
|
|
17
|
+
**1. コンテキスト水位:長いセッションを破裂させない。** 毎ターンリアルタイムでセッショントークンを数え、3本の水位線が段階的に締め上げる:80k(soft、調整可)は「そろそろ委譲を」、95k(hard)は1回の読み取り予算を引き締めて収束へ導き、150k(force)で自動引き継ぎ——引き継ぎドキュメントを書き(追加型のセッションログ自体が完全なバックアップ)、コンテキストを圧縮し、セッションを起こして継続する。タスクは切れない。引き継ぎの瞬間に走っているバックグラウンドのサブエージェントも失われない:id・タスク・レポートパスを引き継ぎドキュメントに書き込み、再開したセッションはどこでレポートを受け取るか分かっていて、同じ仕事を二度投げない。各サブエージェントは独立のハード上限を持ち、到達したら HANDOFF サマリを書いて退場する。自動介入が手に合わないときは、いつでも一時的に手動で引き取れる:`/ctx-pause` は水位の動作をすべて止める(計測は走り続け、末尾のリアルタイム水位線は paused に切り替わる、ただ手を出さなくなるだけ)、`/ctx-resume` でいつでも復帰。DSH を再起動しても介入は自動で戻る。一時的に手を離すだけで、恒久的なオフではない。`/ctx-handover` は水位が満ちるのを待たず、同じ引き継ぎを自分から起こす:引き継ぎドキュメントを書き、コンテキストを圧縮し、セッションを起こす(セッションはまずアイドル境界まで導かれるため、結果には数分かかることがある)。
|
|
18
18
|
|
|
19
19
|
**2. 6つのディスパッチプール:仕事に合ったモデルを。** economy(小口の雑務のバッチ)、mechanical(テンプレート化された書き換え)、main(日常のコーディング)、hard(難問推論と大規模リファクタリング)、vision(画像)、review(独立検証)。設定ページで候補にチェックを付け、優先順を決め、S/A/B/C のグレードを付け、さらにルートごとに思考強度をピン留めできる——強度のドロップダウンはそのモデルが実際に対応するレベルから立ち上がり、汎用の3段ではない。主モデルの毎ターンのプロンプトには必ず `[SWITCHMAN:POOLS]` 推薦表が載り、表に従って投げる。実行モードは3態:オフ / アドバイス / 強制(強制=プール外のモデルは即拒否)。
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ dsh-switchman は [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-har
|
|
|
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
|
**ディスパッチプール**:6本のレーン(economy/mechanical/main/hard/vision/review)の候補はすべて空(=システム既定のモデルを使い、介入しない)。手動順と effort のピン留めはすべてオフ/空。`dispatchEnforce` = `advice`(アドバイスのみで強制はしない)。
|
|
98
98
|
|
|
99
|
-
**コンテキスト水位**:soft `80000` / hard `
|
|
99
|
+
**コンテキスト水位**:soft `80000` / hard `95000` / force `150000` トークン。1回の読み取り予算 `3000`。予算超過時の挙動 `cap`(切り詰め+警告)。`wmAutoHandover` = オン(force 段で引き継ぎドキュメント作成+圧縮を自動実行)。サブエージェントのハード上限 = オン(150k を共有)。
|
|
100
100
|
|
|
101
101
|
**Agent Teams**:`teamsMode` = オフ。`syncWhitelist` = オフ(両者は互いに独立)。
|
|
102
102
|
|
|
103
103
|
**意図認識**(既定では利用不可。分類器+候補最低1つ+マスタートグルのオンが必要):`intentEnabled` = オフ(オフの間は Auto エントリが隠れ、Auto を選んでいたセッションはフォールバックチェーンへ流れる)。分類器ルートは未設定。分類器タイプは `chat`。候補リストは空(プリセット分類はモデルを埋めないとルーティングに参加しない)。キャッシュウィンドウ `300` 秒 / 切替信頼度 `80` / 分類タイムアウト `60000` ms。履歴 `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
|
-
**初期状態のポイント**:① 意図認識が既定で使えないのは意図的な設計で、有効化は3ステップ(分類器、候補、トグル)。② Auto の実効ウィンドウは既定で 200000——ガードレールにより 0.8×ウィンドウ ≥ force 段(150000)が保証され、コア圧縮線(160000)は常にスムーズ引き継ぎ線(150000)より後ろにある。③ 既定でいちばん体感できるのは水位の3点セット:80k で委譲を促し、
|
|
107
|
+
**初期状態のポイント**:① 意図認識が既定で使えないのは意図的な設計で、有効化は3ステップ(分類器、候補、トグル)。② Auto の実効ウィンドウは既定で 200000——ガードレールにより 0.8×ウィンドウ ≥ force 段(150000)が保証され、コア圧縮線(160000)は常にスムーズ引き継ぎ線(150000)より後ろにある。③ 既定でいちばん体感できるのは水位の3点セット:80k で委譲を促し、95k で読み取りを収束させ、150k で自動引き継ぎ(文書作成+圧縮)。設定は一切不要。
|
|
108
108
|
|
|
109
109
|
## 自動コンテキストトリム
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ bash <インストールディレクトリ>/skills/db-query/scripts/setup.sh
|
|
|
123
123
|
| `trimEnabled` | `true` | マスタースイッチ。OFF で fold とメトリクスを完全停止(リスナーは純パススルーに退化)。 |
|
|
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` | 圧力段:view 使用量がコンテキストウィンドウのこの割合に達したら fold。 |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | 緊急段:この割合で機械 fold を強制(サイドモデル呼び出しなし)。 |
|
|
129
129
|
| `trimWindowTokens` | `0` | ティア計算の実効ウィンドウ上限:min(モデルウィンドウ, 上限) で計算。`0` = `wmForceTokens` に追従。 |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | 最後の N メッセージは決して fold されない。 |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | ローリング1時間あたりのサイドモデル fold ペース上限(緊急段は対象外)。 |
|
|
132
132
|
| `trimSideModel` | 未設定 | サマリを書くサイドモデルのルート。空欄 = セッションの現在モデルを継承。 |
|
|
133
|
+
| `trimFoldFallbackModel` | 未設定 | サマリのサイドモデルが失敗したときに折り畳みが再試行するルート。プレッシャー段でも失敗すると機械折り畳みに縮退。空欄 = フォールバックなし。クールダウン・リスク制御・同時実行に余裕のあるルートを推奨。 |
|
|
133
134
|
| `trimStateDir` | 未設定 | fold 状態ディレクトリの上書き。空欄 = `<dshHome>/.dsh-switchman/state/trim/`。 |
|
|
134
135
|
| `surfaceFold` | `true` | コミット済みの fold をセッション表面へ出荷します(shadow-price 計量イベント + `surfaceOp` replace イベントのペア)。OFF はスプライスのみの view を維持。 |
|
|
135
136
|
|
|
136
137
|
**トリガーパス。** 段階チェックはアイドル境界で走り、アイドル状態イベントが届かないホストへのフォールバックとして、各モデルストリーム完了後にも走る(セッションごとに 60 秒につき 1 回の評価へスロットル)。すべての決定——fold も no-op も同様に——は、fold 状態ディレクトリ(`trimStateDir` を参照)内の `decisions.log` へ タイムスタンプ付きの 1 行の `key=value` として追記され、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 ウィンドウでは、健全なノコギリ波は fold 直後に回線 ≈ 40k ↔ 次の fold で
|
|
139
|
+
**回線の真実と定常状態。** 決定行は `view=<n>` を持ち、応答が着地した後は `wire=<n>` も持つ——実際のプロバイダプロンプト(非キャッシュ入力 + キャッシュ読み取り + キャッシュ書き込み、ストリームの usage イベントからサンプリング)である。view の推定はメッセージ配列だけを数えるため、固定オーバーヘッド(実測 ≈ 17.3k:システムプロンプト + ツールスキーマ + persona)の分だけ常に回線より小さく読める。したがって圧力段と緊急段は `max(view, wire)` で評価し、プロンプトサイズの計測となるのは `wire` だけである。150k ウィンドウでは、健全なノコギリ波は fold 直後に回線 ≈ 40k ↔ 次の fold で 64–97.5k(ウィンドウの ≈27%–65%)を往復し、生の成長 ~25k ごとに fold 1 回、天井はウィンドウではなく圧力段によって 97.5k 付近に固定される。`surface-replace` 行が一度も現れないのに `view` が上昇する場合は、スキップ行(`incomplete-seqs`, `no-service`, `compaction-lock`)を読む。
|
|
139
140
|
|
|
140
141
|
**ホスト圧縮エポック。** fold の参照はメッセージ id と内容ハッシュにアンカーされるため、ホスト側の圧縮が再送履歴を置き換えると帳簿全体が一度に老化します。すべてのブロックが位置を特定できなくなり、view は元の履歴へ静かにフォールバックし(fail-open —— 決定ログには `view-applied applied=0` が記録されます)、プラグインは次のリクエストで成長ベースラインを圧縮後のビューに再アンカーします。ホスト圧縮は最後のバックストップとなるトリム層であり、プラグインの fold は単一ホストエポック内のきめ細かい作業を担います。 一部のディスパッチは、完全に凍結されたリクエスト配列やオプションオブジェクトを渡されます(現在のエージェントループは組み立て済みリクエストをディープフリーズします)。そのようなディスパッチについて、`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}` を運ぶ 1 件の `user/message` 置換イベントを追記します。`sourceEventSeqs` は影となる表面ノードをすべてカバーします——ホスト自身の圧縮と同じ機構なので、コミット済みの fold はソース層から回線へ届き、凍結ディスパッチも例外ではありません。セッションの最近のディスパッチが `none` を記録している間、プラグインは view を計測専用と扱います:水位は代わりにプロバイダ報告の集計を測り(force 段階と自動引き継ぎは働き続け)、fold サイクルはサマライザ呼び出しを空焼きせず一時停止し、トリムバナーは当該行に `wire=raw`(folds not shipping; watermark reads the tally)の印を付けます。surface 機構を持たないホスト(またはフラグが off の場合)は、まさにこの従来動作を保ちます。
|
|
141
142
|
|
package/README.ko.md
CHANGED
|
@@ -14,7 +14,7 @@ DSH로 오래 일하면 귀찮은 일이 두 가지 생긴다. 첫째, 세션이
|
|
|
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)은 1회 읽기 예산을 조이고 마무리로 유도하며, 150k(force)은 자동 인계다 — 인계 문서를 적고(추가 전용 세션 로그가 그대로 완전한 백업이다), 컨텍스트를 압축하고, 세션을 깨워 이어 달린다. 태스크는 끊기지 않는다. 인계 순간에 돌고 있던 백그라운드 서브에이전트도 잃지 않는다: id, 태스크, 보고서 경로를 인계 문서에 적어 두어 재개된 세션은 어디서 보고를 받을지 알고 중복 발령하지 않는다. 서브에이전트마다 독립 하드 상한이 있어 도달하면 HANDOFF 요약을 쓰고 퇴장한다. 자동 개입이 손에 맞지 않으면 언제든 임시로 직접 맡을 수 있다: `/ctx-pause`는 수위 동작을 전부 멈춘다(측정은 계속 돌고 뒤에 오는 실시간 수위선은 paused로 바뀐다, 그냥 손을 놓을 뿐), `/ctx-resume`으로 언제든 복구한다 — DSH를 재시작해도 개입은 자동으로 돌아온다. 잠시 손을 놓는 것이지 영구 끄기가 아니다. `/ctx-handover`는 수위가 차오르기를 기다리지 않고 같은 인계를 직접 시작한다: 인계 문서를 적고, 컨텍스트를 압축하고, 세션을 깨워 이어 달린다(세션은 먼저 유휴 경계로 유도되므로 결과까지 몇 분 걸릴 수 있다).
|
|
18
18
|
|
|
19
19
|
**2. 6개 디스패치 풀: 일에 맞는 모델.** economy(잔일 배치), mechanical(템플릿 개작), main(일상 코딩), hard(고난도 추론과 대규모 리팩터링), vision(이미지), review(독립 검증). 설정 페이지에서 후보에 체크하고, 우선순위를 정하고, S/A/B/C 등급을 매기고, 루트별로 추론 강도를 고정할 수도 있다 — 강도 드롭다운은 그 모델이 실제 지원하는 수준에서 오고, 범용 3단이 아니다. 주 모델의 매 턴 프롬프트에는 항상 `[SWITCHMAN:POOLS]` 추천표가 실리고, 표대로 발령한다. 실행 모드는 세 가지: 끔 / 조언 / 강제(강제 = 풀 밖 모델은 즉시 거절).
|
|
20
20
|
|
|
@@ -86,7 +86,7 @@ dsh-switchman은 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harn
|
|
|
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` 토큰. 1회 읽기 예산 `3000`. 예산 초과 동작 `cap`(잘라내고 경고). `wmAutoHandover` = 켬(force 단계에서 인계 문서 작성 + 압축 자동 실행). 서브에이전트 하드 상한 = 켬(150k 공유).
|
|
100
100
|
|
|
101
101
|
**Agent Teams**: `teamsMode` = 끔. `syncWhitelist` = 끔(두 토글은 서로 독립적).
|
|
102
102
|
|
|
103
103
|
**의도 인식**(기본은 사용 불가. 분류기 + 후보 최소 1개 + 마스터 토글 켜기가 필요): `intentEnabled` = 끔(꺼져 있으면 Auto 항목은 숨겨지고, Auto를 선택해 둔 세션은 폴백 체인으로 흐른다). 분류기 라우트 미설정. 분류기 유형 `chat`. 후보 목록은 빈 상태(프리셋 분류는 모델을 채워야 라우팅에 참여). 캐시 창 `300`초 / 전환 신뢰도 `80` / 분류 타임아웃 `60000`ms. 히스토리 `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)보다 뒤에 있다. ③ 기본 상태에서 가장 체감되는 건 수위 3종 세트다: 80k에 위임 알림 /
|
|
107
|
+
**기본 상태에서 알아둘 점**: ① 의도 인식이 기본으로 불가능한 것은 의도된 설계고, 세 단계로 켠다(분류기, 후보, 토글). ② Auto의 실효 창은 기본값이 200000이다 — 가드레일이 0.8×창 ≥ force 단계(150000)를 보장하므로, 코어 압축선(160000)은 언제나 부드러운 인계선(150000)보다 뒤에 있다. ③ 기본 상태에서 가장 체감되는 건 수위 3종 세트다: 80k에 위임 알림 / 95k에 읽기 수렴 / 150k에 자동 인계(문서 작성 + 압축) — 설정은 아무것도 필요 없다.
|
|
108
108
|
|
|
109
109
|
## 자동 컨텍스트 트림
|
|
110
110
|
|
|
@@ -123,19 +123,20 @@ bash <설치-디렉터리>/skills/db-query/scripts/setup.sh
|
|
|
123
123
|
| `trimEnabled` | `true` | 마스터 스위치. 끄면 fold와 메트릭이 완전히 정지한다(리스너는 순수 패스스루로 퇴화). |
|
|
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` | 압력 단계: view 사용량이 컨텍스트 창의 이 백분율에 달하면 fold. |
|
|
128
128
|
| `trimEmergencyPercent` | `95` | 비상 단계: 이 백분율에서 기계 fold 강제(사이드 모델 호출 없음). |
|
|
129
129
|
| `trimWindowTokens` | `0` | 티어 계산의 유효 윈도우 상한: min(모델 윈도우, 상한)으로 계산. `0` = `wmForceTokens`를 따름. |
|
|
130
|
-
| `trimProtectedTail` | `
|
|
131
|
-
| `trimMaxFoldsPerHour` | `
|
|
130
|
+
| `trimProtectedTail` | `10` | 마지막 N개 메시지는 절대 fold되지 않는다. |
|
|
131
|
+
| `trimMaxFoldsPerHour` | `30` | 롤링 1시간당 사이드 모델 fold 케이던스 상한(비상 단계는 제외). |
|
|
132
132
|
| `trimSideModel` | 미설정 | 요약을 쓰는 사이드 모델 라우트. 비어 있으면 세션의 현재 모델을 상속. |
|
|
133
|
+
| `trimFoldFallbackModel` | 미설정 | 요약 사이드 모델 실패 시 폴드가 재시도하는 라우트. 프레셔 단계에서도 실패하면 기계 폴드로 강등. 비어 있으면 폴백 없음. 쿨다운·리스크 컨트롤·동시 실행에 여유가 있는 라우트 권장. |
|
|
133
134
|
| `trimStateDir` | 미설정 | fold 상태 디렉터리 재정의. 비어 있으면 `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
134
135
|
| `surfaceFold` | `true` | 커밋된 fold를 세션 표면으로 발송(shadow-price 계량 이벤트 + `surfaceOp` replace 이벤트 쌍). OFF는 스플라이스 전용 view를 유지. |
|
|
135
136
|
|
|
136
137
|
**트리거 경로.** 단계 검사는 유휴 경계에서 돌아가고, 유휴 상태 이벤트가 도달하지 않는 호스트를 위한 폴백으로 각 모델 스트림 완료 후에도 돌아간다(세션당 60초에 한 번 평가로 스로틀링). 모든 결정 — fold든 no-op든 마찬가지 — 는 fold 상태 디렉터리(`trimStateDir` 참조) 안의 `decisions.log`에 한 줄의 `key=value`(타임스탬프 포함)로 추가되어 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: 시스템 프롬프트 + 도구 스키마 + persona)만큼 항상 회선보다 작게 읽힌다. 따라서 압력 단계와 비상 단계는 `max(view, wire)`로 평가하며, 프롬프트 크기 측정은 `wire`뿐이다. 150k 창에서 건강한 톱니파는 fold 직후 회선 ≈ 40k ↔ 다음 fold에서
|
|
139
|
+
**회선의 진실과 정상 상태.** 결정 행은 `view=<n>`를 담고, 응답이 도착한 뒤에는 `wire=<n>`도 담는다 — 실제 프로바이더 프롬프트(비캐시 입력 + 캐시 읽기 + 캐시 쓰기, 스트림의 usage 이벤트에서 샘플링)이다. view 추정은 messages 배열만 세므로 고정 오버헤드(실측 ≈ 17.3k: 시스템 프롬프트 + 도구 스키마 + persona)만큼 항상 회선보다 작게 읽힌다. 따라서 압력 단계와 비상 단계는 `max(view, wire)`로 평가하며, 프롬프트 크기 측정은 `wire`뿐이다. 150k 창에서 건강한 톱니파는 fold 직후 회선 ≈ 40k ↔ 다음 fold에서 64–97.5k(창의 ≈27%–65%)를 오가고, 원시 성장 ~25k마다 fold가 한 번 일어나며, 상한은 창이 아니라 압력 단계에 의해 97.5k 근처로 고정된다. `surface-replace` 행이 한 번도 나타나지 않는데 `view`가 오르면, 스킵 행(`incomplete-seqs`, `no-service`, `compaction-lock`)을 읽어라.
|
|
139
140
|
|
|
140
141
|
**호스트 압축 에포크.** fold 참조는 메시지 id와 내용 해시에 고정되므로, 호스트 자체의 압축이 재전송 기록을 대체하면 장부 전체가 한꺼번에 노후됩니다. 모든 블록이 위치를 찾지 못하고, view는 조용히 원본 기록으로 폴백하며(fail-open — 결정 로그에 `view-applied applied=0`가 기록됨), 플러그인은 다음 요청에서 성장 기준선을 압축 후 뷰에 다시 고정합니다. 호스트 압축이 최후의 트림 계층이고, 플러그인 fold는 하나의 호스트 에포크 안에서 세밀한 작업을 담당합니다. 일부 디스패치는 완전히 동결된 요청 배열이나 옵션 객체를 건네받습니다(현재 에이전트 루프는 조립된 요청을 딥프리즈합니다). 이런 디스패치에 대해 `injectView`는 결과를 결정 로그에 보고합니다: `nothing-to-apply`(위치를 찾은 fold 블록이 없음 — 원본 기록이 곧 view임), `in-place`/`swapped`(fold된 뷰를 실어 보냄), 또는 `none`(fold가 존재했지만 동결된 디스패치는 그것을 실을 수 없음 — 회선에는 원본 기록이 흐름). **Surface replace는 사용 가능할 때의 발송 경로입니다**(`surfaceFold`, 기본값 켬): 직렬 `agent/turn-stopping` 경계에 유휴 스윕을 더한 시점에, 플러그인은 호스트 방식의 shadow-price 계량 이벤트와 `surfaceOp {op:'replace', startSeq, endSeq}`를 실은 단 한 건의 `user/message` 치환 이벤트를 덧붙입니다. `sourceEventSeqs`는 가려진 표면 노드 전부를 커버합니다 — 호스트 자체 압축이 쓰는 바로 그 메커니즘이라, 커밋된 fold는 소스 계층에서 회선까지 도달하며 동결 디스패치도 예외가 아닙니다. 세션의 최근 디스패치가 `none`을 기록하는 동안, 플러그인은 view를 계측 전용으로 취급합니다: 수위는 대신 프로바이더가 보고한 집계를 재고(force 단계와 자동 인계는 계속 동작하며), fold 사이클은 요약기 호출을 태우지 않고 일시 중지하며, 트림 배너는 해당 줄에 `wire=raw`(folds not shipping; watermark reads the tally) 표식을 붙입니다. surface 메커니즘이 없는 호스트(또는 플래그가 꺼진 경우)는 정확히 이 구동 동작을 유지합니다.
|
|
141
142
|
|