dsh-switchman 1.11.4 → 1.11.5
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 +3 -3
- package/README.es.md +3 -3
- package/README.fr.md +3 -3
- package/README.it.md +3 -3
- package/README.ja.md +3 -3
- package/README.ko.md +3 -3
- package/README.md +6 -6
- package/README.pt.md +3 -3
- package/README.ru.md +3 -3
- package/README.zh-TW.md +3 -3
- package/README.zh.md +3 -3
- package/client.js +113 -52
- package/host/config.js +10 -8
- package/host/context-trim/index.js +6 -9
- package/host/context-trim/summarizer.js +46 -35
- package/host/ptc-guard.js +6 -0
- package/host/routes.js +10 -14
- package/package.json +1 -1
package/README.de.md
CHANGED
|
@@ -33,7 +33,7 @@ Die Session-Kopfzeile zeigt sofort, was los ist: das ⚡-Abzeichen „autonomes
|
|
|
33
33
|
|
|
34
34
|
**7. `/vision`: reine Textmodelle kriegen trotzdem Bilder.** Kann das Hauptmodell keine Bilder lesen, lehnt DSH Bildnachrichten an der Tür ab. Bild einfügen, `/vision was ist an diesem Bild falsch` eintippen — das Bild geht an ein Modell aus dem Vision-Pool, das Urteil kommt in die laufende Session zurück. Über dem Eingabefeld steht vorab „das aktuelle Modell kann keine Bilder lesen“; wird der direkte Bildversand abgelehnt, wird die Nachricht automatisch als `/vision` umgeschrieben und erneut gesendet — kein manueller zweiter Versuch. Ohne konfigurierten Vision-Pool verweigert der Befehl und weist auf die Einstellungen.
|
|
35
35
|
|
|
36
|
-
**8. Intent-Routing: das passende Modell stellt sich von selbst ein.** Auf der Einstellungsseite gibt es eine neue Gruppe „Intent-Routing“: einen Hauptschalter (standardmäßig aus — zum Einschalten sind ein Klassifikator und mindestens ein Kandidat nötig), die Small-Model-Route des Klassifikators (Provider + Modell + optionaler Aufwand — TypeSafe-Jev-artige Entscheidungsmodelle wie allgemeine Chatmodelle funktionieren gleichermaßen, die Ausgabe wird tolerant geparst), eine Dreifachwahl des Klassifikatortyps (auto / decision / chat), eine eigene Kandidatenliste (je Kandidat Provider + Modell + optionaler Aufwand + eine Zeile Fähigkeitsbeschreibung), das Cache-Fenster in Sekunden (Standard 300, abgestimmt auf die Prompt-Caches der Anbieter von rund 5 Minuten), die Umschalt-Vertrauensschwelle (Standard 80), das Klassifikations-Timeout (Standard 60000 ms), die Anzahl der Verlaufsnachrichten (Standard 6) samt Zeichenbudget (Standard 2400) und ein optionales Fallback-Modell. In der Modellauswahl erscheint unter der Gruppe „Auto · Switchman“ der Eintrag „Auto“ (der Client rendert ihn lokalisiert — auf Deutsch „Automatisch (Intent-Routing)“); ist er gewählt, stuft der Klassifikator jede Nutzernachricht ein und der Entscheid gilt für die jeweilige Runde: Bei zu geringem Vertrauen oder noch offenem Cache-Fenster bleibt das aktuelle Modell in Verwendung (sein Cache wird weitergenutzt); gewechselt wird erst, wenn das Vertrauen hoch genug ist oder das aktuelle Modell nicht unter den Kandidaten steht. Der Wechsel geschieht still auf der Aufrufebene — keine „Modell gewechselt“-Nachricht landet in der Session. Über dem Eingabefeld sitzt ein Status-Chip (bei aktivem Routing zeigt er das aktuelle Routing-Modell und das Vertrauen der letzten Entscheidung); Kandidaten und Schwellen stehen jederzeit auf der Einstellungsseite.
|
|
36
|
+
**8. Intent-Routing: das passende Modell stellt sich von selbst ein.** Auf der Einstellungsseite gibt es eine neue Gruppe „Intent-Routing“: einen Hauptschalter (standardmäßig aus — zum Einschalten sind ein Klassifikator und mindestens ein Kandidat nötig), die Small-Model-Route des Klassifikators (Provider + Modell + optionaler Aufwand — TypeSafe-Jev-artige Entscheidungsmodelle wie allgemeine Chatmodelle funktionieren gleichermaßen, die Ausgabe wird tolerant geparst), eine Dreifachwahl des Klassifikatortyps (auto / decision / chat), eine eigene Kandidatenliste (je Kandidat Provider + Modell + optionaler Aufwand + eine Zeile Fähigkeitsbeschreibung), das Cache-Fenster in Sekunden (Standard 300, abgestimmt auf die Prompt-Caches der Anbieter von rund 5 Minuten), die Umschalt-Vertrauensschwelle (Standard 80), das Klassifikations-Timeout (Standard 60000 ms), die Anzahl der Verlaufsnachrichten (Standard 6) samt Zeichenbudget (Standard 2400) und ein optionales Fallback-Modell (mit unabhängigem optionalem Effort-Pin; ohne Pin gilt der Standard des ausgewählten Fallback-Modells, unabhängig vom Klassifikator). In der Modellauswahl erscheint unter der Gruppe „Auto · Switchman“ der Eintrag „Auto“ (der Client rendert ihn lokalisiert — auf Deutsch „Automatisch (Intent-Routing)“); ist er gewählt, stuft der Klassifikator jede Nutzernachricht ein und der Entscheid gilt für die jeweilige Runde: Bei zu geringem Vertrauen oder noch offenem Cache-Fenster bleibt das aktuelle Modell in Verwendung (sein Cache wird weitergenutzt); gewechselt wird erst, wenn das Vertrauen hoch genug ist oder das aktuelle Modell nicht unter den Kandidaten steht. Der Wechsel geschieht still auf der Aufrufebene — keine „Modell gewechselt“-Nachricht landet in der Session. Über dem Eingabefeld sitzt ein Status-Chip (bei aktivem Routing zeigt er das aktuelle Routing-Modell und das Vertrauen der letzten Entscheidung); Kandidaten und Schwellen stehen jederzeit auf der Einstellungsseite.
|
|
37
37
|
|
|
38
38
|
Auch mit nur einem Modell lohnt sich die Installation — Wasserstandskontrolle und gestufte Verifikation hängen nicht von der Modellzahl ab; lange Single-Model-Sessions profitieren genauso.
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ Alle Schlüssel liegen unter Einstellungen → dsh-switchman; Defaults aus `host
|
|
|
129
129
|
| `trimWindowTokens` | `0` | Effektives Fensterlimit für die Stufenberechnung: gerechnet gegen min(Modellfenster, Limit). `0` = folgt `wmForceTokens`. |
|
|
130
130
|
| `trimProtectedTail` | `10` | Die letzten N Nachrichten werden nie gefaltet. |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | Fold-Takt-Obergrenze pro rollierender Stunde für Nebenmodell-Folds (Notfall-Folds ausgenommen). |
|
|
132
|
-
| `trimSideModel` | nicht gesetzt | Route des
|
|
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. |
|
|
132
|
+
| `trimSideModel` | nicht gesetzt | Route des Zusammenfassungs-Nebenmodells. Leer = Provider/Modell der Session folgen, aber den Effort des Aufrufs nicht übernehmen; auch Ladder-Distillationen nutzen diese Route. Der Effort für Zusammenfassungen lässt sich separat festlegen; ohne Pin wird anhand der Modellmetadaten die niedrigste aktivierte Reasoning-Stufe gewählt, bei Modellen mit nur Ein/Aus off. Wird Reasoning nicht unterstützt oder sind keine Metadaten verfügbar, wird kein Effort gesendet und das Modell-/Adapter-Standardverhalten bleibt maßgeblich. |
|
|
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. Das Effort des manuell gewählten Fold-Fallback-Modells ist unabhängig; ohne Pin gilt dieselbe Metadaten-Empfehlung wie beim Zusammenfassungsmodell, ohne Metadaten der Modellstandard. Route mit Spielraum bei Cooldowns, Risikokontrolle und Concurrency wählen. |
|
|
134
134
|
| `trimStateDir` | nicht gesetzt | Überschreibt das Fold-Zustandsverzeichnis. Leer = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
135
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. |
|
|
136
136
|
|
package/README.es.md
CHANGED
|
@@ -33,7 +33,7 @@ La cabecera de la sesión da un feedback visual claro: la insignia ⚡ «equipo
|
|
|
33
33
|
|
|
34
34
|
**7. `/vision`: hasta un modelo de solo texto puede con las imágenes.** Cuando el modelo principal no sabe leer imágenes, DSH rechaza en la puerta de entrada los mensajes con imágenes. Adjunta la imagen y escribe `/vision ¿qué está mal en esta imagen?` — la imagen se entrega a un modelo del pool multimodal para leerla, y la conclusión vuelve a la sesión actual. Sobre el cuadro de entrada aparece por adelantado el aviso «el modelo actual no sabe leer imágenes»; si un envío directo de imagen es rechazado, se reescribe una vez de forma automática a `/vision` y se reenvía, sin rehacer nada a mano; con el pool multimodal sin configurar, el comando se niega y da indicaciones de configuración.
|
|
35
35
|
|
|
36
|
-
**8. Enrutado por intención: el modelo adecuado se elige solo.** La página de ajustes estrena un grupo «Enrutado por intención»: un interruptor maestro (apagado por defecto; para activarlo hacen falta un clasificador y al menos un candidato), la ruta de modelo pequeño del clasificador (provider + model + effort opcional — valen tanto modelos de decisión tipo TypeSafe Jev como modelos de chat genéricos, y la salida se interpreta con tolerancia), un selector de tipo de clasificador a tres bandas (auto / decision / chat), una lista de candidatos independiente (cada candidato: provider + model + effort opcional + una nota de capacidades de una línea), la ventana de caché en segundos (300 por defecto, alineada con las cachés de prompt de los proveedores, unos 5 minutos), el umbral de confianza para el cambio (80 por defecto), el timeout de clasificación (60000 ms por defecto), el número de mensajes del historial (6 por defecto) y el presupuesto de caracteres (2400 por defecto), y un modelo de respaldo opcional. En el selector de modelos aparece una entrada «Auto» dentro del grupo «Auto · Switchman» (el cliente la muestra localizada — «Automático (enrutado por intención)» en español); elegida, cada mensaje del usuario pasa por el clasificador para decidir el mejor candidato y la decisión queda fijada por ese turno: si la confianza no llega o la ventana de caché sigue abierta, se mantiene el modelo actual (reaprovechando su caché); solo se cambia cuando la confianza sobra o el modelo actual no está entre los candidatos. El cambio ocurre en silencio en la capa de llamada — no se inserta ningún mensaje de «modelo cambiado» en la sesión. Sobre el cuadro de entrada hay un chip de estado (con enrutado automático muestra el modelo en ruta y la confianza de la última decisión); los candidatos y los umbrales se consultan siempre en la página de ajustes.
|
|
36
|
+
**8. Enrutado por intención: el modelo adecuado se elige solo.** La página de ajustes estrena un grupo «Enrutado por intención»: un interruptor maestro (apagado por defecto; para activarlo hacen falta un clasificador y al menos un candidato), la ruta de modelo pequeño del clasificador (provider + model + effort opcional — valen tanto modelos de decisión tipo TypeSafe Jev como modelos de chat genéricos, y la salida se interpreta con tolerancia), un selector de tipo de clasificador a tres bandas (auto / decision / chat), una lista de candidatos independiente (cada candidato: provider + model + effort opcional + una nota de capacidades de una línea), la ventana de caché en segundos (300 por defecto, alineada con las cachés de prompt de los proveedores, unos 5 minutos), el umbral de confianza para el cambio (80 por defecto), el timeout de clasificación (60000 ms por defecto), el número de mensajes del historial (6 por defecto) y el presupuesto de caracteres (2400 por defecto), y un modelo de respaldo opcional (con un pin de effort opcional e independiente; si no se fija, se usa el valor predeterminado del modelo de respaldo seleccionado, separado del effort del clasificador). En el selector de modelos aparece una entrada «Auto» dentro del grupo «Auto · Switchman» (el cliente la muestra localizada — «Automático (enrutado por intención)» en español); elegida, cada mensaje del usuario pasa por el clasificador para decidir el mejor candidato y la decisión queda fijada por ese turno: si la confianza no llega o la ventana de caché sigue abierta, se mantiene el modelo actual (reaprovechando su caché); solo se cambia cuando la confianza sobra o el modelo actual no está entre los candidatos. El cambio ocurre en silencio en la capa de llamada — no se inserta ningún mensaje de «modelo cambiado» en la sesión. Sobre el cuadro de entrada hay un chip de estado (con enrutado automático muestra el modelo en ruta y la confianza de la última decisión); los candidatos y los umbrales se consultan siempre en la página de ajustes.
|
|
37
37
|
|
|
38
38
|
¿Solo tienes un modelo? Sigue mereciendo la instalación — el control del nivel de agua y la verificación por niveles no dependen de cuántos modelos tengas, y una sesión larga con un solo modelo se beneficia igual.
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ Todas las claves viven en Ajustes → dsh-switchman; los valores por defecto sal
|
|
|
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
130
|
| `trimProtectedTail` | `10` | Los últimos N mensajes nunca se pliegan. |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | Tope de cadencia de folds por hora móvil para el modelo secundario (los de emergencia quedan exentos). |
|
|
132
|
-
| `trimSideModel` | sin definir | Ruta del modelo secundario que escribe los resúmenes. Vacía = heredar el modelo
|
|
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. |
|
|
132
|
+
| `trimSideModel` | sin definir | Ruta del modelo secundario que escribe los resúmenes. Vacía = seguir el provider/model de la sesión, sin heredar el effort de esa llamada; la destilación ladder también usa esta ruta. El effort del resumen admite un pin manual independiente; si no se fija, los metadatos del modelo recomiendan el nivel de reasoning habilitado más bajo; si el modelo solo tiene interruptor sí/no, se elige off. Si no admite reasoning o faltan metadatos, no se envía effort y se conserva el comportamiento predeterminado del modelo/adaptador. |
|
|
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. El modelo de respaldo de fold elegido manualmente tiene un pin de effort independiente; si no se fija, usa la misma recomendación por metadatos que el modelo de resumen, y si faltan metadatos, el valor predeterminado del modelo. Elige una ruta con margen en cooldowns, control de riesgo y concurrencia. |
|
|
134
134
|
| `trimStateDir` | sin definir | Anula el directorio del estado de folds. Vacía = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
135
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. |
|
|
136
136
|
|
package/README.fr.md
CHANGED
|
@@ -33,7 +33,7 @@ L'en-tête de session donne un retour immédiat : un badge ⚡ « équipe autono
|
|
|
33
33
|
|
|
34
34
|
**7. `/vision` : même un modèle purement textuel peut travailler avec des images.** Quand le modèle principal ne sait pas lire les images, DSH refuse les messages avec image dès l'entrée. Collez l'image, tapez `/vision où est l'erreur sur cette image`, et l'image est confiée à un modèle du pool multimodal pour lecture ; les conclusions reviennent dans la session courante. Un avertissement apparaît tôt au-dessus du champ de saisie — « le modèle courant ne sait pas lire les images » ; si un envoi d'image ordinaire est refusé, le brouillon est réécrit une fois en `/vision` et renvoyé tout seul, sans rien retaper ; sans pool multimodal configuré, la commande refuse et donne les indications de configuration.
|
|
35
35
|
|
|
36
|
-
**8. Routage par intention : le bon modèle se choisit tout seul.** La page de réglages accueille un nouveau groupe « Routage par intention » : un interrupteur général (désactivé par défaut ; l'activer exige un classifieur et au moins un candidat), la route du petit modèle classifieur (provider + model + effort facultatif — les modèles de décision type TypeSafe Jev comme les modèles de conversation génériques conviennent, et la sortie est analysée avec tolérance), un choix du type de classifieur à trois options (auto / decision / chat), une liste de candidats indépendante (chaque candidat : provider + model + effort facultatif + une note de capacité d'une ligne), la fenêtre de cache en secondes (300 par défaut, calée sur les caches de prompt des fournisseurs, environ 5 minutes), le seuil de confiance du basculement (80 par défaut), le timeout de classification (60000 ms par défaut), le nombre de messages d'historique (6 par défaut) et le budget de caractères (2400 par défaut), et un modèle de repli facultatif. Le sélecteur de modèles gagne une entrée « Auto » dans le groupe « Auto · Switchman » (le client la rend localisée — « Automatique (routage par intention) » en français) ; une fois choisie, chaque message utilisateur passe par le classifieur pour désigner le meilleur candidat, et la décision est verrouillée pour ce tour : si la confiance manque ou que la fenêtre de cache est encore ouverte, le modèle courant reste en place (son cache est réutilisé) ; on ne bascule que lorsque la confiance est suffisante ou que le modèle courant ne fait pas partie des candidats. Le basculement se fait en silence à la couche d'appel — aucun message « modèle changé » n'est inséré dans la session. Au-dessus du champ de saisie figure une pastille d'état (en routage automatique, elle montre le modèle routé courant et la confiance de la dernière décision) ; candidats et seuils restent consultables dans la page de réglages.
|
|
36
|
+
**8. Routage par intention : le bon modèle se choisit tout seul.** La page de réglages accueille un nouveau groupe « Routage par intention » : un interrupteur général (désactivé par défaut ; l'activer exige un classifieur et au moins un candidat), la route du petit modèle classifieur (provider + model + effort facultatif — les modèles de décision type TypeSafe Jev comme les modèles de conversation génériques conviennent, et la sortie est analysée avec tolérance), un choix du type de classifieur à trois options (auto / decision / chat), une liste de candidats indépendante (chaque candidat : provider + model + effort facultatif + une note de capacité d'une ligne), la fenêtre de cache en secondes (300 par défaut, calée sur les caches de prompt des fournisseurs, environ 5 minutes), le seuil de confiance du basculement (80 par défaut), le timeout de classification (60000 ms par défaut), le nombre de messages d'historique (6 par défaut) et le budget de caractères (2400 par défaut), et un modèle de repli facultatif (avec un pin d'effort facultatif et indépendant ; sans pin, l'effort par défaut du modèle de repli sélectionné s'applique, indépendamment de celui du classifieur). Le sélecteur de modèles gagne une entrée « Auto » dans le groupe « Auto · Switchman » (le client la rend localisée — « Automatique (routage par intention) » en français) ; une fois choisie, chaque message utilisateur passe par le classifieur pour désigner le meilleur candidat, et la décision est verrouillée pour ce tour : si la confiance manque ou que la fenêtre de cache est encore ouverte, le modèle courant reste en place (son cache est réutilisé) ; on ne bascule que lorsque la confiance est suffisante ou que le modèle courant ne fait pas partie des candidats. Le basculement se fait en silence à la couche d'appel — aucun message « modèle changé » n'est inséré dans la session. Au-dessus du champ de saisie figure une pastille d'état (en routage automatique, elle montre le modèle routé courant et la confiance de la dernière décision) ; candidats et seuils restent consultables dans la page de réglages.
|
|
37
37
|
|
|
38
38
|
Un seul modèle ? Ça vaut quand même l'installation — le contrôle du niveau d'eau et la vérification par paliers se moquent du nombre de modèles, et une longue session mono-modèle en profite tout autant.
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ Toutes les clés vivent dans Réglages → dsh-switchman ; les valeurs par défa
|
|
|
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
130
|
| `trimProtectedTail` | `10` | Les N derniers messages ne sont jamais repliés. |
|
|
131
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
|
-
| `trimSideModel` | non définie | Route du modèle annexe qui écrit les résumés. Vide = hériter du modèle
|
|
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. |
|
|
132
|
+
| `trimSideModel` | non définie | Route du modèle annexe qui écrit les résumés. Vide = suivre le provider/model de la session, sans hériter de l'effort de cet appel ; les distillations ladder utilisent aussi cette route. L'effort du résumé peut être fixé séparément ; sans pin, les métadonnées du modèle déterminent le niveau de reasoning activé le plus bas ; pour un modèle limité à un interrupteur on/off, choisir off. Si le reasoning n'est pas pris en charge ou si les métadonnées sont indisponibles, aucun effort n'est envoyé et le comportement par défaut du modèle/de l'adaptateur s'applique. |
|
|
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. Le modèle de repli du fold choisi manuellement a un pin d'effort indépendant ; sans pin, appliquer la même recommandation par métadonnées que pour le modèle de résumé, et en l'absence de métadonnées, le défaut du modèle. Choisir une route avec de la marge sur cooldowns, contrôle de risque et concurrence. |
|
|
134
134
|
| `trimStateDir` | non défini | Redéfinit le répertoire d'état des folds. Vide = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
135
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. |
|
|
136
136
|
|
package/README.it.md
CHANGED
|
@@ -33,7 +33,7 @@ L'intestazione della sessione dà un riscontro immediato: badge ⚡ «Squadra au
|
|
|
33
33
|
|
|
34
34
|
**7. `/vision`: anche i modelli solo testo trattano le immagini.** Quando il modello principale non sa leggere le immagini, DSH rifiuta al varco i messaggi che le contengono. Alleghi l'immagine e digiti `/vision dov'è l'errore in questa immagine`: l'immagine viene affidata alla lettura di un modello del pool multimodale, e la conclusione torna nella sessione corrente. Sopra la casella di input compare in anticipo l'avviso «il modello corrente non supporta la lettura delle immagini»; se un invio diretto dell'immagine viene rifiutato, il messaggio viene riscritto una volta in `/vision` e reinviato da solo, senza dover rifare tutto a mano; senza pool multimodale configurato, il comando rifiuta e indica come configurarlo.
|
|
35
35
|
|
|
36
|
-
**8. Instradamento per intent: il modello giusto si sceglie da sé.** La pagina delle impostazioni si arricchisce di un gruppo «Instradamento per intent»: un interruttore principale (spento per predefinito; per attivarlo servono un classificatore e almeno un candidato), la route del piccolo modello classificatore (provider + model + effort facoltativo — vanno bene sia i modelli decisionali tipo TypeSafe Jev sia i modelli di chat generici, e l'output viene letto con tolleranza), una scelta a tre vie del tipo di classificatore (auto / decision / chat), una lista di candidati indipendente (per ogni candidato: provider + model + effort facoltativo + una nota di capacità di una riga), la finestra di cache in secondi (300 per predefinito, allineata alle cache di prompt dei provider, circa 5 minuti), la soglia di confidenza per il cambio (80 per predefinito), il timeout di classificazione (60000 ms per predefinito), il numero di messaggi di cronologia (6 per predefinito) e il budget di caratteri (2400 per predefinito), più un modello di fallback facoltativo. Nel selettore dei modelli compare una voce «Auto» nel gruppo «Auto · Switchman» (il client la renderizza localizzata — «Automatico (instradamento per intent)» in italiano); una volta scelta, ogni messaggio dell'utente passa dal classificatore per eleggere il candidato migliore e la decisione resta fissata per quel turno: se la confidenza non basta o la finestra di cache è ancora aperta, resta il modello corrente (riusandone la cache); si cambia solo quando la confidenza è sufficiente o il modello corrente non è tra i candidati. Il cambio avviene in silenzio al livello di chiamata — nessun messaggio «modello cambiato» finisce nella sessione. Sopra la casella di input c'è una chip di stato (con instradamento automatico mostra il modello di instradamento corrente e la confidenza dell'ultima decisione); candidati e soglie si consultano sempre nella pagina delle impostazioni.
|
|
36
|
+
**8. Instradamento per intent: il modello giusto si sceglie da sé.** La pagina delle impostazioni si arricchisce di un gruppo «Instradamento per intent»: un interruttore principale (spento per predefinito; per attivarlo servono un classificatore e almeno un candidato), la route del piccolo modello classificatore (provider + model + effort facoltativo — vanno bene sia i modelli decisionali tipo TypeSafe Jev sia i modelli di chat generici, e l'output viene letto con tolleranza), una scelta a tre vie del tipo di classificatore (auto / decision / chat), una lista di candidati indipendente (per ogni candidato: provider + model + effort facoltativo + una nota di capacità di una riga), la finestra di cache in secondi (300 per predefinito, allineata alle cache di prompt dei provider, circa 5 minuti), la soglia di confidenza per il cambio (80 per predefinito), il timeout di classificazione (60000 ms per predefinito), il numero di messaggi di cronologia (6 per predefinito) e il budget di caratteri (2400 per predefinito), più un modello di fallback facoltativo (con un pin di effort facoltativo e indipendente; se non fissato, si usa l'effort predefinito del modello di fallback selezionato, separato da quello del classificatore). Nel selettore dei modelli compare una voce «Auto» nel gruppo «Auto · Switchman» (il client la renderizza localizzata — «Automatico (instradamento per intent)» in italiano); una volta scelta, ogni messaggio dell'utente passa dal classificatore per eleggere il candidato migliore e la decisione resta fissata per quel turno: se la confidenza non basta o la finestra di cache è ancora aperta, resta il modello corrente (riusandone la cache); si cambia solo quando la confidenza è sufficiente o il modello corrente non è tra i candidati. Il cambio avviene in silenzio al livello di chiamata — nessun messaggio «modello cambiato» finisce nella sessione. Sopra la casella di input c'è una chip di stato (con instradamento automatico mostra il modello di instradamento corrente e la confidenza dell'ultima decisione); candidati e soglie si consultano sempre nella pagina delle impostazioni.
|
|
37
37
|
|
|
38
38
|
Un solo modello? Vale comunque la pena installarlo — il controllo del livello dell'acqua e la verifica a livelli non guardano a quanti modelli hai, e ne giovancono allo stesso modo le sessioni lunghe con un modello unico.
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ Tutte le chiavi stanno in Impostazioni → dsh-switchman; i valori predefiniti v
|
|
|
129
129
|
| `trimWindowTokens` | `0` | Limite di finestra effettivo per il calcolo delle soglie: calcolato su min(finestra del modello, limite). `0` = segue `wmForceTokens`. |
|
|
130
130
|
| `trimProtectedTail` | `10` | Gli ultimi N messaggi non vengono mai ripiegati. |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | Tetto di cadenza dei fold per ora mobile per il modello secondario (quelli di emergenza ne sono esenti). |
|
|
132
|
-
| `trimSideModel` | non impostata | Route del modello secondario che scrive i riassunti. Vuota =
|
|
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. |
|
|
132
|
+
| `trimSideModel` | non impostata | Route del modello secondario che scrive i riassunti. Vuota = seguire il provider/model della sessione, senza ereditare l'effort della chiamata; anche le ladder distillation usano questa route. L'effort del riepilogo si può fissare separatamente; senza pin, i metadati del modello scelgono il livello reasoning abilitato più basso; per i modelli con solo interruttore on/off, scegliere off. Se reasoning non è supportato o i metadati non sono disponibili, non si invia effort e si mantiene il comportamento predefinito del modello/adattatore. |
|
|
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. Il modello di fallback del fold scelto manualmente ha un pin di effort indipendente; senza pin, usa la stessa raccomandazione basata sui metadati del modello di riepilogo e, se mancano metadati, il valore predefinito del modello. Scegli una route con margine su cooldown, risk control e concorrenza. |
|
|
134
134
|
| `trimStateDir` | non impostata | Sostituisce la directory dello stato dei fold. Vuota = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
135
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. |
|
|
136
136
|
|
package/README.ja.md
CHANGED
|
@@ -33,7 +33,7 @@ dsh-switchman は [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-har
|
|
|
33
33
|
|
|
34
34
|
**7. `/vision`:テキスト専用モデルでも画像を扱える。** 主力モデルが画像を読めないとき、DSH は画像付きメッセージを入口で拒否する。画像を貼って `/vision この画像のどこが悪い` と打てば、画像は vision プールのモデルへ渡され、結論は現在のセッションに戻る。入力欄の上には「現在のモデルは画像を読めません」の事前表示が出る。画像を直接送って拒否されたら、自動で `/vision` に書き換えて再送するので手直しは不要。vision プールが未設定ならコマンドは拒否し、設定への案内を出す。
|
|
35
35
|
|
|
36
|
-
**8. 意図ルーティング:最適なモデルを自動で選ぶ。** 設定ページに「意図認識」グループが増える:マスタートグル(既定オフ、有効化には分類器と候補が最低1つ必要)、分類器用の小型モデルルート(provider + model + 任意の effort。TypeSafe Jev 系の決定モデルも汎用対話モデルも使え、出力は寛容にパースされる)、分類器タイプの3択(auto / decision / chat)、独立した候補モデルリスト(各候補に provider + model + 任意の effort + 一行の能力説明)、キャッシュウィンドウ秒数(既定 300、ベンダーの prompt cache 約5分に合わせる)、切替信頼度しきい値(既定 80)、分類タイムアウト(既定 60000ms)、履歴メッセージ件数(既定 6)と文字数予算(既定 2400
|
|
36
|
+
**8. 意図ルーティング:最適なモデルを自動で選ぶ。** 設定ページに「意図認識」グループが増える:マスタートグル(既定オフ、有効化には分類器と候補が最低1つ必要)、分類器用の小型モデルルート(provider + model + 任意の effort。TypeSafe Jev 系の決定モデルも汎用対話モデルも使え、出力は寛容にパースされる)、分類器タイプの3択(auto / decision / chat)、独立した候補モデルリスト(各候補に provider + model + 任意の effort + 一行の能力説明)、キャッシュウィンドウ秒数(既定 300、ベンダーの prompt cache 約5分に合わせる)、切替信頼度しきい値(既定 80)、分類タイムアウト(既定 60000ms)、履歴メッセージ件数(既定 6)と文字数予算(既定 2400)、任意のフォールバックモデル(任意の effort を独立して固定でき、未設定なら選択したフォールバックモデルのデフォルトを使用。分類器の effort とは別)。モデルセレクターの「Auto · Switchman」グループの下に「Auto」エントリが現れる(クライアントは「自動(意図認識)」とローカライズして表示);選んでおくとユーザーメッセージごとに分類器が最適な候補を判定し、判断はそのターンの間固定される:信頼度が足りない、またはまだキャッシュウィンドウ内なら現在のモデルをそのまま使い(キャッシュを再利用)、信頼度が十分高い、または現在のモデルが候補にないときだけ切り替わる。切替は呼び出し層で静かに行われ、「モデルを切り替えました」のメッセージをセッションに差し込まない。入力欄の上には状態 chip(自動ルーティング中は現在のルーティング先モデルと最後の判断の信頼度を表示)。候補としきい値はいつでも設定ページで確認できる。
|
|
37
37
|
|
|
38
38
|
モデルが1つでも入れる価値はある——水位制御と段階的検証はモデルの数と無関係で、単一モデルの長いセッションも同じく恩恵を受ける。
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ bash <インストールディレクトリ>/skills/db-query/scripts/setup.sh
|
|
|
129
129
|
| `trimWindowTokens` | `0` | ティア計算の実効ウィンドウ上限:min(モデルウィンドウ, 上限) で計算。`0` = `wmForceTokens` に追従。 |
|
|
130
130
|
| `trimProtectedTail` | `10` | 最後の N メッセージは決して fold されない。 |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | ローリング1時間あたりのサイドモデル fold ペース上限(緊急段は対象外)。 |
|
|
132
|
-
| `trimSideModel` | 未設定 |
|
|
133
|
-
| `trimFoldFallbackModel` | 未設定 | サマリのサイドモデルが失敗したときに折り畳みが再試行するルート。プレッシャー段でも失敗すると機械折り畳みに縮退。空欄 =
|
|
132
|
+
| `trimSideModel` | 未設定 | サマリ用サイドモデルのルート。空欄 = セッションの provider/model に追従(呼び出しの effort は継承しない);ladder distillation もこのルートを使用。サマリの effort は別途手動固定でき、未設定ならモデルメタデータから有効な reasoning レベルの最小値を選ぶ。オン/オフのみのモデルは off。reasoning 非対応またはメタデータが利用できない場合は effort を送らず、モデル/アダプターのデフォルトに委ねる。 |
|
|
133
|
+
| `trimFoldFallbackModel` | 未設定 | サマリのサイドモデルが失敗したときに折り畳みが再試行するルート。プレッシャー段でも失敗すると機械折り畳みに縮退。空欄 = フォールバックなし。手動選択した fold フォールバックモデルの effort 固定は独立。未設定ならサマリモデルと同じメタデータ基準で推奨し、メタデータがなければそのモデルのデフォルトを使用。クールダウン・リスク制御・同時実行に余裕のあるルートを推奨。 |
|
|
134
134
|
| `trimStateDir` | 未設定 | fold 状態ディレクトリの上書き。空欄 = `<dshHome>/.dsh-switchman/state/trim/`。 |
|
|
135
135
|
| `surfaceFold` | `true` | コミット済みの fold をセッション表面へ出荷します(shadow-price 計量イベント + `surfaceOp` replace イベントのペア)。OFF はスプライスのみの view を維持。 |
|
|
136
136
|
|
package/README.ko.md
CHANGED
|
@@ -33,7 +33,7 @@ dsh-switchman은 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harn
|
|
|
33
33
|
|
|
34
34
|
**7. `/vision`: 텍스트 전용 모델도 이미지를 다룬다.** 주력 모델이 이미지를 못 읽으면 DSH는 이미지 포함 메시지를 입구에서 거절한다. 이미지를 붙이고 `/vision 이 이미지 어디가 잘못됐어`라고 입력하면 이미지는 vision 풀 모델에게 넘어가고 결론이 현재 세션으로 돌아온다. 입력창 위에는 '현재 모델은 이미지를 읽을 수 없음' 안내가 미리 뜬다. 이미지를 직접 보내다 거절되면 자동으로 `/vision`으로 고쳐 다시 보낸다 — 손으로 다시 할 필요 없다. vision 풀이 비어 있으면 명령은 거절하고 설정 안내를 준다.
|
|
35
35
|
|
|
36
|
-
**8. 의도 라우팅: 알맞은 모델을 자동으로 고른다.** 설정 페이지에 '의도 인식' 그룹이 추가된다: 마스터 토글(기본 꺼짐, 켜려면 분류기와 후보 최소 1개 필요), 분류기용 소형 모델 라우트(provider + model + 선택적 effort. TypeSafe Jev 계열 결정 모델도 범용 대화 모델도 지원하며 출력은 관대하게 파싱된다), 분류기 유형 3택(auto / decision / chat), 독립 후보 모델 목록(후보마다 provider + model + 선택적 effort + 한 줄 능력 설명), 캐시 창 초(기본 300, 벤더 prompt cache 약 5분에 맞춤), 전환 신뢰도 임계값(기본 80), 분류 타임아웃(기본 60000ms), 히스토리 메시지 수(기본 6)와 문자 예산(기본 2400), 선택적 폴백
|
|
36
|
+
**8. 의도 라우팅: 알맞은 모델을 자동으로 고른다.** 설정 페이지에 '의도 인식' 그룹이 추가된다: 마스터 토글(기본 꺼짐, 켜려면 분류기와 후보 최소 1개 필요), 분류기용 소형 모델 라우트(provider + model + 선택적 effort. TypeSafe Jev 계열 결정 모델도 범용 대화 모델도 지원하며 출력은 관대하게 파싱된다), 분류기 유형 3택(auto / decision / chat), 독립 후보 모델 목록(후보마다 provider + model + 선택적 effort + 한 줄 능력 설명), 캐시 창 초(기본 300, 벤더 prompt cache 약 5분에 맞춤), 전환 신뢰도 임계값(기본 80), 분류 타임아웃(기본 60000ms), 히스토리 메시지 수(기본 6)와 문자 예산(기본 2400), 선택적 폴백 모델(선택적 effort를 별도로 고정할 수 있으며, 미설정 시 선택한 폴백 모델의 기본 effort를 사용하고 분류기 effort와는 독립적). 모델 선택기의 'Auto · Switchman' 그룹 아래에 'Auto' 항목이 나타난다(클라이언트는 '자동(의도 인식)'으로 현지화해 그린다). 선택해 두면 사용자 메시지마다 분류기가 가장 알맞은 후보를 판정하고 같은 턴 안에서는 결정이 고정된다: 신뢰도가 부족하거나 아직 캐시 창 안이면 현재 모델을 그대로 쓰고(캐시 재사용), 신뢰도가 충분히 높거나 현재 모델이 후보에 없을 때만 전환한다. 전환은 호출 계층에서 조용히 끝나며 세션에 '모델이 전환되었습니다' 메시지를 끼워 넣지 않는다. 입력창 위에는 상태 chip이 뜬다(자동 라우팅 중에는 현재 라우팅 모델과 마지막 판정 신뢰도 표시). 후보와 임계값은 언제든 설정 페이지에서 볼 수 있다.
|
|
37
37
|
|
|
38
38
|
모델이 하나뿐이어도 설치할 가치가 있다 — 수위 제어와 단계별 검증은 모델 수와 무관하고, 단일 모델의 긴 세션도 같은 혜택을 본다.
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ bash <설치-디렉터리>/skills/db-query/scripts/setup.sh
|
|
|
129
129
|
| `trimWindowTokens` | `0` | 티어 계산의 유효 윈도우 상한: min(모델 윈도우, 상한)으로 계산. `0` = `wmForceTokens`를 따름. |
|
|
130
130
|
| `trimProtectedTail` | `10` | 마지막 N개 메시지는 절대 fold되지 않는다. |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | 롤링 1시간당 사이드 모델 fold 케이던스 상한(비상 단계는 제외). |
|
|
132
|
-
| `trimSideModel` | 미설정 |
|
|
133
|
-
| `trimFoldFallbackModel` | 미설정 | 요약
|
|
132
|
+
| `trimSideModel` | 미설정 | 요약 side model 라우트. 비어 있으면 세션 provider/model을 따르며 호출의 effort는 상속하지 않음. ladder distillation도 이 라우트를 사용. 요약 effort는 별도로 수동 고정할 수 있으며, 고정하지 않으면 모델 메타데이터에서 사용 가능한 reasoning 단계 중 가장 낮은 단계를 선택. 켜기/끄기만 지원하는 모델은 off. reasoning 미지원 또는 메타데이터 없음이면 effort를 보내지 않아 모델/어댑터 기본 동작을 따름. |
|
|
133
|
+
| `trimFoldFallbackModel` | 미설정 | 요약 side model 실패 시 폴드가 재시도하는 라우트. 프레셔 단계에서도 실패하면 기계 폴드로 강등. 비어 있으면 폴백 없음. 수동으로 선택한 폴드 폴백 모델의 effort는 독립적으로 고정할 수 있으며, 미설정 시 요약 모델과 동일한 메타데이터 추천을 따르고 메타데이터가 없으면 해당 모델 기본값을 사용. 쿨다운·리스크 컨트롤·동시 실행에 여유가 있는 라우트 권장. |
|
|
134
134
|
| `trimStateDir` | 미설정 | fold 상태 디렉터리 재정의. 비어 있으면 `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
135
135
|
| `surfaceFold` | `true` | 커밋된 fold를 세션 표면으로 발송(shadow-price 계량 이벤트 + `surfaceOp` replace 이벤트 쌍). OFF는 스플라이스 전용 view를 유지. |
|
|
136
136
|
|
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ The session header gives at-a-glance feedback: the ⚡ "autonomous team" badge a
|
|
|
33
33
|
|
|
34
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.
|
|
35
35
|
|
|
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. 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.
|
|
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
37
|
|
|
38
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.
|
|
39
39
|
|
|
@@ -76,7 +76,7 @@ Worth installing even with a single model — watermark control and tiered verif
|
|
|
76
76
|
- **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
77
|
- **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
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).
|
|
79
|
-
- **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. 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.
|
|
79
|
+
- **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
80
|
|
|
81
81
|
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.
|
|
82
82
|
|
|
@@ -100,9 +100,9 @@ Everything below is the full set of defaults after a fresh install (authoritativ
|
|
|
100
100
|
|
|
101
101
|
**Agent Teams**: `teamsMode` = off; `syncWhitelist` = off (the two toggles are independent of each other).
|
|
102
102
|
|
|
103
|
-
**Intent routing** (unavailable by default; needs a classifier + at least one candidate + the master switch on): `intentEnabled` = off (while off, the Auto entry stays hidden and sessions already on Auto fall through the fallback chain); the classifier route is unset; the classifier type is `chat`; the candidate list is empty (the preset categories join routing only once given a model); cache window `300` s / switch confidence threshold `80` / classification timeout `60000` ms; history `6` messages / `2400` characters; `intentContextWindow` = `200000`.
|
|
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`.
|
|
104
104
|
|
|
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 (
|
|
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).
|
|
106
106
|
|
|
107
107
|
**Out-of-the-box notes**: ① intent routing being unavailable out of the box is by design — three steps to switch it on (classifier, candidates, the master switch); ② Auto's effective window is 200000 out of the box — the guardrail guarantees 0.8×window ≥ force (150000), so the core compaction line (160000) always sits after the smooth-handover line (150000); ③ the most tangible out-of-the-box effect is the watermark trio: 80k nudges delegation / 95k tightens reading / 150k backs up and hands over automatically — no configuration needed.
|
|
108
108
|
|
|
@@ -129,8 +129,8 @@ All keys live in Settings → dsh-switchman; defaults from `host/config.js`:
|
|
|
129
129
|
| `trimWindowTokens` | `0` | Effective-window cap for tier math: tiers are computed against min(model window, cap). `0` = follow `wmForceTokens`. |
|
|
130
130
|
| `trimProtectedTail` | `10` | The last N messages are never folded. |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | Side-model fold cadence cap per rolling hour (emergency folds are exempt). |
|
|
132
|
-
| `trimSideModel` | unset | Route for the summary side model. Empty
|
|
133
|
-
| `trimFoldFallbackModel` | unset | Route
|
|
132
|
+
| `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
|
+
| `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. |
|
|
134
134
|
| `trimStateDir` | unset | Fold-state directory override. Empty = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
135
135
|
| `surfaceFold` | `true` | Ship committed folds onto the session surface (shadow-price + `surfaceOp` replace event pair). OFF keeps the splice-only view. |
|
|
136
136
|
|
package/README.pt.md
CHANGED
|
@@ -33,7 +33,7 @@ O cabeçalho da sessão dá um retorno imediato: badge ⚡ “Equipe autônoma
|
|
|
33
33
|
|
|
34
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.
|
|
35
35
|
|
|
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. 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.
|
|
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
37
|
|
|
38
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.
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ Todas as chaves ficam em Configurações → dsh-switchman; os padrões vêm de
|
|
|
129
129
|
| `trimWindowTokens` | `0` | Limite de janela efetivo para o cálculo dos níveis: calculado sobre min(janela do modelo, limite). `0` = segue `wmForceTokens`. |
|
|
130
130
|
| `trimProtectedTail` | `10` | As últimas N mensagens nunca são dobradas. |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | Teto de cadência de folds por hora rolante para o modelo secundário (os de emergência ficam fora). |
|
|
132
|
-
| `trimSideModel` | não definida | Rota do modelo secundário que escreve os resumos. Vazia = herdar o modelo
|
|
133
|
-
| `trimFoldFallbackModel` | não definida | Rota de nova tentativa quando o modelo secundário de resumos falha; um fold de pressão degrada então para mecânico. Vazia = sem fallback. Escolha uma rota com folga em cooldowns, controle de risco e concorrência. |
|
|
132
|
+
| `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
|
+
| `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. |
|
|
134
134
|
| `trimStateDir` | não definido | Sobrepõe o diretório do estado de folds. Vazio = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
135
135
|
| `surfaceFold` | `true` | Envia os folds confirmados para a superfície da sessão (par de eventos: medição shadow-price + replace com `surfaceOp`). OFF mantém a view apenas com splices. |
|
|
136
136
|
|
package/README.ru.md
CHANGED
|
@@ -33,7 +33,7 @@ dsh-switchman — плагин для [DeepSeek Harness](https://github.com/deep
|
|
|
33
33
|
|
|
34
34
|
**7. `/vision`: картинки по зубам даже чисто текстовой модели.** Когда главная модель не читает изображения, DSH прямо на входе отклоняет сообщения с картинками. Прикрепите картинку и введите `/vision что не так на этой картинке` — изображение будет отдано на чтение модели из мультимодального пула, а вывод вернётся в текущую сессию. Над полем ввода заранее подсказывают: «текущая модель не умеет читать изображения»; если прямая отправка картинки отклонена, она один раз автоматически переоформляется в `/vision` и уходит повторно — вручную ничего переписывать не нужно; если мультимодальный пул не настроен, команда откажется и подскажет, что настроить.
|
|
35
35
|
|
|
36
|
-
**8. Маршрутизация по намерению: нужная модель выбирается сама.** На странице настроек появляется раздел «Маршрутизация по намерению»: главный переключатель (по умолчанию выключен; для включения нужны классификатор и хотя бы один кандидат), маршрут маленькой модели-классификатора (provider + model + необязательный effort — подходят и решающие модели типа TypeSafe Jev, и обычные разговорные, вывод парсится нестрого), выбор типа классификатора из трёх (auto / decision / chat), независимый список моделей-кандидатов (для каждого: provider + model + необязательный effort + одна строка описания способностей), окно кэша в секундах (по умолчанию 300, подогнано под промпт-кэши поставщиков ~5 минут), порог уверенности для переключения (по умолчанию 80), тайм-аут классификации (по умолчанию 60000 мс), количество сообщений истории (по умолчанию 6) и символьный бюджет (по умолчанию 2400), а также необязательная запасная
|
|
36
|
+
**8. Маршрутизация по намерению: нужная модель выбирается сама.** На странице настроек появляется раздел «Маршрутизация по намерению»: главный переключатель (по умолчанию выключен; для включения нужны классификатор и хотя бы один кандидат), маршрут маленькой модели-классификатора (provider + model + необязательный effort — подходят и решающие модели типа TypeSafe Jev, и обычные разговорные, вывод парсится нестрого), выбор типа классификатора из трёх (auto / decision / chat), независимый список моделей-кандидатов (для каждого: provider + model + необязательный effort + одна строка описания способностей), окно кэша в секундах (по умолчанию 300, подогнано под промпт-кэши поставщиков ~5 минут), порог уверенности для переключения (по умолчанию 80), тайм-аут классификации (по умолчанию 60000 мс), количество сообщений истории (по умолчанию 6) и символьный бюджет (по умолчанию 2400), а также необязательная запасная модель (с отдельной необязательной фиксацией effort; если он не задан, используется effort по умолчанию выбранной запасной модели, независимо от effort классификатора). В селекторе моделей под группой «Auto · Switchman» появляется вход «Auto» (клиент отрисовывает его локализованно — «Авто (маршрутизация по намерению)» на русском); после выбора классификатор оценивает каждое сообщение пользователя, и решение фиксируется на этот ход: если уверенности не хватает или окно кэша ещё открыто, текущая модель остаётся (её кэш переиспользуется); переключение происходит, только когда уверенность высока или текущей модели нет среди кандидатов. Смена проходит бесшумно на уровне вызова — в сессию не вставляется сообщение «модель переключена». Над полем ввода — чип состояния (при автороутинге он показывает текущую модель маршрута и уверенность последнего решения); кандидаты и пороги всегда можно посмотреть на странице настроек.
|
|
37
37
|
|
|
38
38
|
Всего одна модель? Всё равно стоит поставить — контроль уровня воды и многоуровневая проверка от числа моделей не зависят, и длинная сессия на одной модели выигрывает от них ничуть не меньше.
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ bash <install-dir>/skills/db-query/scripts/setup.sh
|
|
|
129
129
|
| `trimWindowTokens` | `0` | Эффективный лимит окна для расчёта уровней: считается от min(окно модели, лимит). `0` = следует за `wmForceTokens`. |
|
|
130
130
|
| `trimProtectedTail` | `10` | Последние N сообщений никогда не сворачиваются. |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | Потолок частоты fold-ов боковой модели за скользящий час (аварийные не в счёт). |
|
|
132
|
-
| `trimSideModel` | не задан | Маршрут боковой модели, пишущей резюме. Пусто =
|
|
133
|
-
| `trimFoldFallbackModel` | не задан | Маршрут повторной попытки, если боковая модель резюме не сработала; pressure-fold затем деградирует до механического. Пусто = без резерва. Выбирайте маршрут с запасом по кулдаунам, риск-контролю и параллелизму. |
|
|
132
|
+
| `trimSideModel` | не задан | Маршрут боковой модели, пишущей резюме. Пусто = следовать provider/model сессии, не наследуя effort вызова; этот маршрут также используют ladder distillation. Effort резюме можно закрепить отдельно; без фиксации метаданные модели определяют минимальный доступный уровень reasoning, а для моделей только с переключателем вкл./выкл. выбирается off. Если reasoning не поддерживается или метаданные недоступны, effort не отправляется и сохраняется поведение модели/адаптера по умолчанию. |
|
|
133
|
+
| `trimFoldFallbackModel` | не задан | Маршрут повторной попытки, если боковая модель резюме не сработала; pressure-fold затем деградирует до механического. Пусто = без резерва. У вручную выбранной запасной модели fold-а независимый effort; если он не задан, применяется та же рекомендация по метаданным, что для модели резюме, а при отсутствии метаданных — умолчание самой модели. Выбирайте маршрут с запасом по кулдаунам, риск-контролю и параллелизму. |
|
|
134
134
|
| `trimStateDir` | не задан | Переопределяет каталог состояния fold-ов. Пусто = `<dshHome>/.dsh-switchman/state/trim/`. |
|
|
135
135
|
| `surfaceFold` | `true` | Доставляет зафиксированные fold-ы на поверхность сессии (пара событий: учёт shadow-price + replace с `surfaceOp`). OFF оставляет view только со сплайсами. |
|
|
136
136
|
|
package/README.zh-TW.md
CHANGED
|
@@ -33,7 +33,7 @@ dsh-switchman 是一個 [DeepSeek Harness](https://github.com/deepseek-ai/deepse
|
|
|
33
33
|
|
|
34
34
|
**7. `/vision`:純文字模型也能處理圖。** 主力模型讀不了圖時,DSH 會在入口直接拒掉帶圖訊息。貼上圖、輸入 `/vision 這張圖錯在哪`,圖片會被交給多模態池的模型去讀,結論回到目前對話。輸入框上方會提前提示「目前模型不支援讀圖」;直接傳圖被拒時,自動改寫成 `/vision` 重送一次,不用手動重來;多模態池沒設時指令會拒絕並給出設定指引。
|
|
35
35
|
|
|
36
|
-
**8. 意圖識別自動選模型:訊息進來,模型自動落位。** 設定頁新增【意圖識別】分組:主開關(預設關閉,開啟需設定分類器並至少一個候選)、分類器小模型路由(provider + model + 可選 effort,TypeSafe Jev 類決策模型與通用對話模型都支援,輸出寬容解析)、分類器類型三選(auto / decision / chat)、獨立候選模型清單(每個候選 provider + model + 可選 effort + 一句能力描述)、快取視窗秒數(預設 300,對齊廠商 prompt cache 約 5 分鐘)、切換信心閾值(預設 80)、分類逾時(預設 60000ms)、歷史訊息則數(預設 6)與字元預算(預設 2400
|
|
36
|
+
**8. 意圖識別自動選模型:訊息進來,模型自動落位。** 設定頁新增【意圖識別】分組:主開關(預設關閉,開啟需設定分類器並至少一個候選)、分類器小模型路由(provider + model + 可選 effort,TypeSafe Jev 類決策模型與通用對話模型都支援,輸出寬容解析)、分類器類型三選(auto / decision / chat)、獨立候選模型清單(每個候選 provider + model + 可選 effort + 一句能力描述)、快取視窗秒數(預設 300,對齊廠商 prompt cache 約 5 分鐘)、切換信心閾值(預設 80)、分類逾時(預設 60000ms)、歷史訊息則數(預設 6)與字元預算(預設 2400)、可選備援模型(可獨立固定可選 effort;未固定時使用所選備援模型的預設 effort,與分類器 effort 分開)。模型選擇器出現「Auto · Switchman」分組下的「Auto」入口(用戶端渲染為在地化的「自動(意圖識別)」);選中後每條使用者訊息先由分類器判定最合適的候選,同一輪鎖定決策:信心不足或仍在快取視窗內時優先沿用目前模型(快取續用),信心足夠高或目前模型不在候選裡才切換;切換在呼叫層靜默完成,不往對話裡插「模型已切換」。輸入框上方有狀態 chip(自動路由時顯示目前路由模型與上次決策信心),候選與閾值隨時回設定頁查看。
|
|
37
37
|
|
|
38
38
|
只有一個模型也值得裝——水位控制和分級驗證與模型數量無關,單模型長對話同樣受益。
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ bash <安裝目錄>/skills/db-query/scripts/setup.sh
|
|
|
129
129
|
| `trimWindowTokens` | `0` | 視窗上限:壓力與緊急檔按 min(模型視窗, 上限) 計算。`0` = 跟隨 `wmForceTokens`。 |
|
|
130
130
|
| `trimProtectedTail` | `10` | 最後 N 則訊息永不折疊。 |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | 每滾動小時 side model 折疊的節奏上限(緊急級豁免)。 |
|
|
132
|
-
| `trimSideModel` | 未設定 | 寫摘要的 side model 路由。留空 =
|
|
133
|
-
| `trimFoldFallbackModel` | 未設定 | 摘要 side model 失敗時摺疊改用的重試路由;壓力檔仍失敗則退回機械摺疊。留空 =
|
|
132
|
+
| `trimSideModel` | 未設定 | 寫摘要的 side model 路由。留空 = 跟隨對話目前 provider/model,不繼承呼叫的 effort;ladder distillation 也使用此路由。摘要 effort 可獨立手動固定;未固定時依模型 metadata 建議最低啟用的 reasoning 層級,僅有開/關選項時選 off。不支援 reasoning 或 metadata 不可用時不傳 effort,沿用模型/配接器預設行為。 |
|
|
133
|
+
| `trimFoldFallbackModel` | 未設定 | 摘要 side model 失敗時摺疊改用的重試路由;壓力檔仍失敗則退回機械摺疊。留空 = 無備援。手動選擇的折疊備援模型可獨立固定 effort;未設定時依與摘要模型相同的模型 metadata 規則建議,metadata 缺失則使用該模型預設值。盡量選擇冷卻、風控與並行餘量充足的路由。 |
|
|
134
134
|
| `trimStateDir` | 未設定 | 折疊狀態目錄覆蓋。留空 = `<dshHome>/.dsh-switchman/state/trim/`。 |
|
|
135
135
|
| `surfaceFold` | `true` | 把已提交的 fold 送上對話表面(shadow-price 計量事件 + `surfaceOp` replace 事件對)。關閉則維持僅拼接的 view。 |
|
|
136
136
|
|
package/README.zh.md
CHANGED
|
@@ -33,7 +33,7 @@ dsh-switchman 是一个 [DeepSeek Harness](https://github.com/deepseek-ai/deepse
|
|
|
33
33
|
|
|
34
34
|
**7. `/vision`:纯文本模型也能处理图。** 主力模型读不了图时,DSH 会在入口直接拒掉带图消息。贴上图、输入 `/vision 这张图错在哪`,图片会被交给多模态池的模型去读,结论回到当前会话。输入框上方会提前提示「当前模型不支持读图」;直接发图被拒时,自动改写成 `/vision` 重发一次,不用手动重来;多模态池没配时命令会拒绝并给出配置指引。
|
|
35
35
|
|
|
36
|
-
**8. 意图识别自动选模型:消息进来,模型自动落位。** 设置页新增【意图识别】分组:主开关(默认关闭,开启需配置分类器并至少一个候选)、分类器小模型路由(provider + model + 可选 effort,TypeSafe Jev 类决策模型与通用对话模型都支持,输出宽容解析)、分类器类型三选(auto / decision / chat)、独立候选模型列表(每个候选 provider + model + 可选 effort + 一句能力描述)、缓存窗口秒数(默认 300,对齐厂商 prompt cache 约 5 分钟)、切换置信度阈值(默认 80)、分类超时(默认 60000ms)、历史消息条数(默认 6)与字符预算(默认 2400
|
|
36
|
+
**8. 意图识别自动选模型:消息进来,模型自动落位。** 设置页新增【意图识别】分组:主开关(默认关闭,开启需配置分类器并至少一个候选)、分类器小模型路由(provider + model + 可选 effort,TypeSafe Jev 类决策模型与通用对话模型都支持,输出宽容解析)、分类器类型三选(auto / decision / chat)、独立候选模型列表(每个候选 provider + model + 可选 effort + 一句能力描述)、缓存窗口秒数(默认 300,对齐厂商 prompt cache 约 5 分钟)、切换置信度阈值(默认 80)、分类超时(默认 60000ms)、历史消息条数(默认 6)与字符预算(默认 2400)、可选兜底模型(可单独固定可选 effort;未固定时使用所选兜底模型的默认 effort,与分类器 effort 独立)。模型选择器出现「Auto · Switchman」分组下的「Auto」入口(客户端渲染为本地化的「自动(意图识别)」);选中后每条用户消息先由分类器判定最合适的候选,同一轮锁定决策:置信度不足或仍在缓存窗口内时优先沿用当前模型(缓存续用),置信度足够高或当前模型不在候选里才切换;切换在调用层静默完成,不往会话里插「模型已切换」。输入框上方有状态 chip(自动路由时显示当前路由模型与上次决策置信度),候选与阈值随时回设置页查看。
|
|
37
37
|
|
|
38
38
|
只有一个模型也值得装——水位控制和分级验证与模型数量无关,单模型长会话同样受益。
|
|
39
39
|
|
|
@@ -129,8 +129,8 @@ bash <安装目录>/skills/db-query/scripts/setup.sh
|
|
|
129
129
|
| `trimWindowTokens` | `0` | 窗口上限:压力与紧急档按 min(模型窗口, 上限) 计算。`0` = 跟随 `wmForceTokens`。 |
|
|
130
130
|
| `trimProtectedTail` | `10` | 最后 N 条消息永不折叠。 |
|
|
131
131
|
| `trimMaxFoldsPerHour` | `30` | 每滚动小时 side model 折叠的节奏上限(紧急档豁免)。 |
|
|
132
|
-
| `trimSideModel` | 未设置 | 写摘要的 side model 路由。留空 =
|
|
133
|
-
| `trimFoldFallbackModel` | 未设置 | 摘要 side model 失败时折叠改用的重试路由;压力档仍失败则退回机械折叠。留空 =
|
|
132
|
+
| `trimSideModel` | 未设置 | 写摘要的 side model 路由。留空 = 跟随会话当前 provider/model,不继承调用的 effort;ladder distillation 也使用此路由。摘要 effort 可单独手动固定;未固定时按模型元数据推荐最低启用的 reasoning 档,只有开/关选项时选 off。不支持 reasoning 或元数据不可用时不发送 effort,保留模型/适配器默认行为。 |
|
|
133
|
+
| `trimFoldFallbackModel` | 未设置 | 摘要 side model 失败时折叠改用的重试路由;压力档仍失败则退回机械折叠。留空 = 无兜底。手动选择的折叠兜底模型有独立 effort 固定值;未设置时按摘要模型相同的模型元数据规则推荐,元数据缺失则使用该模型默认值。尽量选择冷却、风控与并发余量充足的路由。 |
|
|
134
134
|
| `trimStateDir` | 未设置 | 折叠状态目录覆盖。留空 = `<dshHome>/.dsh-switchman/state/trim/`。 |
|
|
135
135
|
| `surfaceFold` | `true` | 把已提交的 fold 送上会话表面(shadow-price 计量事件 + `surfaceOp` replace 事件对)。关闭则保持仅拼接的 view。 |
|
|
136
136
|
|
package/client.js
CHANGED
|
@@ -373,14 +373,13 @@ window.__ModuleLoader__.load({
|
|
|
373
373
|
const routeKey = (route) => `${route.provider}\0${route.model}`;
|
|
374
374
|
|
|
375
375
|
/** One well-formed {provider, model[, effort]} route, or null. */
|
|
376
|
-
function sanitizeRoute(route) {
|
|
376
|
+
function sanitizeRoute(route, allowEffort = false) {
|
|
377
377
|
if (route === null || typeof route !== 'object') return null;
|
|
378
378
|
if (typeof route.provider !== 'string' || route.provider === '') return null;
|
|
379
379
|
if (typeof route.model !== 'string' || route.model === '') return null;
|
|
380
|
-
//
|
|
381
|
-
// round-trip so a settings save never strips it (intent routes omit it).
|
|
380
|
+
// Preserve effort only for settings routes that expose a dedicated pin.
|
|
382
381
|
const out = { provider: route.provider, model: route.model };
|
|
383
|
-
if (typeof route.effort === 'string' && route.effort !== '') out.effort = route.effort;
|
|
382
|
+
if (allowEffort && typeof route.effort === 'string' && route.effort !== '') out.effort = route.effort;
|
|
384
383
|
return out;
|
|
385
384
|
}
|
|
386
385
|
|
|
@@ -532,10 +531,10 @@ window.__ModuleLoader__.load({
|
|
|
532
531
|
trimLadderEnabled: bool('trimLadderEnabled', true),
|
|
533
532
|
surfaceFold: bool('surfaceFold', true),
|
|
534
533
|
trimSideModel:
|
|
535
|
-
sanitizeRoute(value?.trimSideModel) ??
|
|
534
|
+
sanitizeRoute(value?.trimSideModel, true) ??
|
|
536
535
|
({ provider: '', model: '' }),
|
|
537
536
|
trimFoldFallbackModel:
|
|
538
|
-
|
|
537
|
+
sanitizeRoute(value?.trimFoldFallbackModel, true) ??
|
|
539
538
|
({ provider: '', model: '' }),
|
|
540
539
|
trimStateDir: string('trimStateDir'),
|
|
541
540
|
...Object.fromEntries(
|
|
@@ -565,7 +564,7 @@ window.__ModuleLoader__.load({
|
|
|
565
564
|
INTENT_NUMBER_FIELDS.map((spec) => [spec.field, number(spec)]),
|
|
566
565
|
),
|
|
567
566
|
intentFallbackRoute:
|
|
568
|
-
sanitizeRoute(value?.intentFallbackRoute) ??
|
|
567
|
+
sanitizeRoute(value?.intentFallbackRoute, true) ??
|
|
569
568
|
({ provider: '', model: '' }),
|
|
570
569
|
};
|
|
571
570
|
}
|
|
@@ -619,8 +618,8 @@ window.__ModuleLoader__.load({
|
|
|
619
618
|
trimEnabled: values.trimEnabled,
|
|
620
619
|
trimLadderEnabled: values.trimLadderEnabled,
|
|
621
620
|
surfaceFold: values.surfaceFold,
|
|
622
|
-
trimSideModel: routeKey(values.trimSideModel)
|
|
623
|
-
trimFoldFallbackModel: routeKey(values.trimFoldFallbackModel)
|
|
621
|
+
trimSideModel: `${routeKey(values.trimSideModel)}\0${values.trimSideModel.effort ?? ''}`,
|
|
622
|
+
trimFoldFallbackModel: `${routeKey(values.trimFoldFallbackModel)}\0${values.trimFoldFallbackModel.effort ?? ''}`,
|
|
624
623
|
trimStateDir: values.trimStateDir,
|
|
625
624
|
...Object.fromEntries(
|
|
626
625
|
TRIM_NUMBER_FIELDS.map(({ field }) => [field, values[field]]),
|
|
@@ -645,7 +644,7 @@ window.__ModuleLoader__.load({
|
|
|
645
644
|
...Object.fromEntries(
|
|
646
645
|
INTENT_NUMBER_FIELDS.map(({ field }) => [field, values[field]]),
|
|
647
646
|
),
|
|
648
|
-
intentFallbackRoute: routeKey(values.intentFallbackRoute)
|
|
647
|
+
intentFallbackRoute: `${routeKey(values.intentFallbackRoute)}\0${values.intentFallbackRoute.effort ?? ''}`,
|
|
649
648
|
});
|
|
650
649
|
}
|
|
651
650
|
|
|
@@ -923,11 +922,11 @@ window.__ModuleLoader__.load({
|
|
|
923
922
|
surfaceFoldLabel: '把折叠写入会话表面',
|
|
924
923
|
surfaceFoldHelp: '追加宿主风格的替换事件,让折叠在冻结派发下也能到达线上。建议保持开启。',
|
|
925
924
|
trimSideModelLabel: '摘要模型',
|
|
926
|
-
trimSideModelHelp: '
|
|
925
|
+
trimSideModelHelp: '折叠摘要使用的模型路由;默认「跟随会话模型」。阶梯蒸馏同样使用该路由。未手动指定思考等级时,按模型元数据自动选择最低开启档;只有开/关思考时取关闭。模型不支持思考或元数据不可用时,不发送思考等级并沿用模型默认。',
|
|
927
926
|
trimFollowSession: '跟随会话模型',
|
|
928
|
-
|
|
927
|
+
trimEffortRecommended: '自动(按模型推荐规则)',
|
|
929
928
|
trimFoldFallbackModelLabel: '折叠异常兜底模型',
|
|
930
|
-
trimFoldFallbackModelHelp: '
|
|
929
|
+
trimFoldFallbackModelHelp: '摘要模型调用失败时改用该模型重试;仍失败则压力折叠退回机械折叠。思考等级可单独指定;留空时按该模型的推荐规则自动选择。尽量选择没有冷却、风控或并发限制的模型,避免与主会话共用同一账号。留空 = 无兜底。',
|
|
931
930
|
trimFallbackUnset: '未设置(失败时直接机械折叠)',
|
|
932
931
|
trimStateDirLabel: '账本目录',
|
|
933
932
|
trimStateDirHelp: '留空 = 默认的裁剪状态目录。',
|
|
@@ -1022,7 +1021,7 @@ window.__ModuleLoader__.load({
|
|
|
1022
1021
|
intentHistoryMaxCharsHelp: '对话摘录的总字符上限(200–20000)。',
|
|
1023
1022
|
intentFallbackRouteLabel: '兜底模型',
|
|
1024
1023
|
intentFallbackRouteHelp:
|
|
1025
|
-
'分类失败时依次:上一轮实际路由 → 兜底模型 →
|
|
1024
|
+
'分类失败时依次:上一轮实际路由 → 兜底模型 → 候选第一位;留空用候选第一位。可选固定思考等级;不指定时使用兜底模型默认等级。',
|
|
1026
1025
|
intentRouteUnset: '未设置',
|
|
1027
1026
|
intentEffortFollow: '跟随模型默认',
|
|
1028
1027
|
intentDockAuto: '自动',
|
|
@@ -1194,13 +1193,12 @@ window.__ModuleLoader__.load({
|
|
|
1194
1193
|
surfaceFoldHelp:
|
|
1195
1194
|
'Append host-style replace events so folds reach the wire even on frozen dispatches. Leave on.',
|
|
1196
1195
|
trimSideModelLabel: 'Summarizer model',
|
|
1197
|
-
trimSideModelHelp:
|
|
1198
|
-
'Route for fold summaries; defaults to following the session model. Also used by ladder distillations.',
|
|
1196
|
+
trimSideModelHelp: 'Route for fold summaries; defaults to following the session model. Also used by ladder distillations. Without a pinned effort, choose the lowest enabled level from model metadata; for a thinking on/off-only model, choose off. If reasoning is unsupported or metadata is unavailable, omit the effort and keep the model default.',
|
|
1199
1197
|
trimFollowSession: 'Follow session model',
|
|
1200
|
-
|
|
1198
|
+
trimEffortRecommended: 'Automatic (model recommendation)',
|
|
1201
1199
|
trimFoldFallbackModelLabel: 'Fold fallback model',
|
|
1202
1200
|
trimFoldFallbackModelHelp:
|
|
1203
|
-
'When the summary route fails, the fold retries on this model before degrading a pressure fold to a mechanical one. Prefer a model with headroom on cooldowns, risk control, and concurrency limits — avoid sharing the pinned account with the main session. Empty = no fallback leg.',
|
|
1201
|
+
'When the summary route fails, the fold retries on this model before degrading a pressure fold to a mechanical one. Its effort can be pinned separately; if unset, the model recommendation is used. Prefer a model with headroom on cooldowns, risk control, and concurrency limits — avoid sharing the pinned account with the main session. Empty = no fallback leg.',
|
|
1204
1202
|
trimFallbackUnset: 'Unset (failed folds go straight to mechanical)',
|
|
1205
1203
|
trimStateDirLabel: 'Ledger directory',
|
|
1206
1204
|
trimStateDirHelp: 'Empty = the default per-host trim state directory.',
|
|
@@ -1305,7 +1303,7 @@ window.__ModuleLoader__.load({
|
|
|
1305
1303
|
'Total character cap of the conversation excerpt (200–20000).',
|
|
1306
1304
|
intentFallbackRouteLabel: 'Fallback model',
|
|
1307
1305
|
intentFallbackRouteHelp:
|
|
1308
|
-
'On classification failure: last routed model → fallback → first candidate; empty = first candidate.',
|
|
1306
|
+
'On classification failure: last routed model → fallback → first candidate; empty = first candidate. Optionally pin a thinking effort; when unset, the fallback model default is used.',
|
|
1309
1307
|
intentRouteUnset: 'Not set',
|
|
1310
1308
|
intentEffortFollow: 'model default',
|
|
1311
1309
|
intentDockAuto: 'Auto',
|
|
@@ -1470,11 +1468,11 @@ window.__ModuleLoader__.load({
|
|
|
1470
1468
|
surfaceFoldLabel: '把摺疊寫入會話表面',
|
|
1471
1469
|
surfaceFoldHelp: '追加宿主風格的替換事件,讓摺疊在凍結派發下也能到達線上。建議保持開啟。',
|
|
1472
1470
|
trimSideModelLabel: '摘要模型',
|
|
1473
|
-
trimSideModelHelp: '
|
|
1471
|
+
trimSideModelHelp: '摺疊摘要使用的模型路由;預設「跟隨對話模型」。階梯蒸餾同樣使用該路由。未手動指定思考等級時,依模型中繼資料自動選擇最低啟用等級;模型僅提供思考開/關切換時取關閉。不支援思考或中繼資料不可用時,不傳思考等級並沿用模型預設。',
|
|
1474
1472
|
trimFollowSession: '跟隨對話模型',
|
|
1475
|
-
|
|
1473
|
+
trimEffortRecommended: '自動(依模型推薦規則)',
|
|
1476
1474
|
trimFoldFallbackModelLabel: '摺疊異常備援模型',
|
|
1477
|
-
trimFoldFallbackModelHelp: '
|
|
1475
|
+
trimFoldFallbackModelHelp: '摘要模型呼叫失敗時改用該模型重試;仍失敗則壓力摺疊退回機械摺疊。思考等級可單獨指定;留空時依該模型推薦規則自動選擇。盡量選擇沒有冷卻、風控或並行限制的模型,避免與主對話共用同一帳號。留空 = 無備援。',
|
|
1478
1476
|
trimFallbackUnset: '未設定(失敗時直接機械摺疊)',
|
|
1479
1477
|
trimStateDirLabel: '帳本目錄',
|
|
1480
1478
|
trimStateDirHelp: '留空 = 預設的裁剪狀態目錄。',
|
|
@@ -1566,7 +1564,7 @@ window.__ModuleLoader__.load({
|
|
|
1566
1564
|
intentHistoryMaxCharsHelp: '對話摘錄的總字元上限(200–20000)。',
|
|
1567
1565
|
intentFallbackRouteLabel: '備援模型',
|
|
1568
1566
|
intentFallbackRouteHelp:
|
|
1569
|
-
'分類失敗時依次:上一輪實際路由 → 備援模型 →
|
|
1567
|
+
'分類失敗時依次:上一輪實際路由 → 備援模型 → 候選第一位;留空用候選第一位。可選固定思考等級;未指定時使用備援模型預設等級。',
|
|
1570
1568
|
intentRouteUnset: '未設定',
|
|
1571
1569
|
intentEffortFollow: '跟隨模型預設',
|
|
1572
1570
|
intentDockAuto: '自動',
|
|
@@ -1796,10 +1794,16 @@ window.__ModuleLoader__.load({
|
|
|
1796
1794
|
'会話抜粋の合計文字上限(200–20000)。',
|
|
1797
1795
|
intentFallbackRouteLabel: 'フォールバックモデル',
|
|
1798
1796
|
intentFallbackRouteHelp:
|
|
1799
|
-
'分類失敗時:前回ルート → フォールバック →
|
|
1797
|
+
'分類失敗時:前回ルート → フォールバック → 候補の先頭。空欄は候補の先頭。思考レベルを固定できます。未指定ならモデル既定を使用します。',
|
|
1800
1798
|
intentRouteUnset: '未設定',
|
|
1801
1799
|
intentEffortFollow: 'モデルのデフォルト',
|
|
1802
|
-
|
|
1800
|
+
trimEffortRecommended: '自動(モデル推奨)',
|
|
1801
|
+
trimSideModelLabel: '要約モデル',
|
|
1802
|
+
trimSideModelHelp: '要約に使うモデルルート。既定ではセッションモデルに従いますが、その呼び出しの思考レベルは引き継ぎません。段階的蒸留も同じルートを使います。手動指定がなければ、モデル情報から有効な思考レベルの最低段階を選びます。思考のオン/オフだけのモデルは off を選択します。非対応またはモデル情報がない場合はレベルを送らず、モデルの既定値を使います。',
|
|
1803
|
+
trimFollowSession: 'セッションモデルに従う',
|
|
1804
|
+
trimFoldFallbackModelLabel: '折りたたみ時のフォールバックモデル',
|
|
1805
|
+
trimFoldFallbackModelHelp: '要約モデルの呼び出しに失敗した場合、このモデルで再試行します。これも失敗すると、圧力折りたたみは機械的な折りたたみに切り替わります。思考レベルは個別に指定でき、未指定ならこのモデルの推奨設定を使います。冷却・リスク管理・同時実行の制限に余裕のあるモデルを選び、メインセッションと同じアカウントの共有は避けてください。空欄 = フォールバックなし。',
|
|
1806
|
+
trimFallbackUnset: '未設定(失敗時は機械的な折りたたみに直接移行)',
|
|
1803
1807
|
intentDockAuto: '自動',
|
|
1804
1808
|
intentDockUnrouted: '未ルーティング',
|
|
1805
1809
|
intentDockUsing: '使用中',
|
|
@@ -1939,7 +1943,13 @@ window.__ModuleLoader__.load({
|
|
|
1939
1943
|
'서브에이전트 자체 모델 창에 맞춰 3단계 축소: force = min(정적 기준, 창×비율). soft/hard도 같은 비율로 축소. 완화 없이 강화만.',
|
|
1940
1944
|
wmSubagentFollowForce: 'force 단계 따르기(0)',
|
|
1941
1945
|
wmCommands: '명령: /ctx-pause 수위 개입 일시 중지 · /ctx-resume 재개 · /ctx-handover 지금 핸드오버 문서를 작성하고 압축.',
|
|
1942
|
-
|
|
1946
|
+
trimEffortRecommended: '자동 (모델 권장)',
|
|
1947
|
+
trimSideModelLabel: '요약 모델',
|
|
1948
|
+
trimSideModelHelp: '요약에 사용할 모델 경로입니다. 기본값은 세션 모델을 따르지만 해당 호출의 추론 수준은 상속하지 않습니다. 단계별 증류도 같은 경로를 사용합니다. 수동 지정이 없으면 모델 메타데이터에서 활성화된 가장 낮은 추론 단계를 선택합니다. 추론 켜기/끄기만 지원하는 모델은 off를 선택합니다. 추론을 지원하지 않거나 메타데이터가 없으면 수준을 보내지 않고 모델 기본값을 사용합니다.',
|
|
1949
|
+
trimFollowSession: '세션 모델 따르기',
|
|
1950
|
+
trimFoldFallbackModelLabel: '접기 대체 모델',
|
|
1951
|
+
trimFoldFallbackModelHelp: '요약 모델 호출이 실패하면 이 모델로 재시도합니다. 이것도 실패하면 압력 접기는 기계적 접기로 전환됩니다. 추론 수준은 별도로 지정할 수 있으며, 비워 두면 이 모델의 권장 설정을 사용합니다. 쿨다운, 위험 제어, 동시성 제한에 여유가 있는 모델을 선택하고 주 세션과 같은 계정을 공유하지 않는 편이 좋습니다. 비우면 대체 경로가 없습니다.',
|
|
1952
|
+
trimFallbackUnset: '미설정(실패 시 바로 기계적 접기)',
|
|
1943
1953
|
trimSectionTitle: '컨텍스트 트림',
|
|
1944
1954
|
trimModeLabel: '트림 모드',
|
|
1945
1955
|
trimModeHelp:
|
|
@@ -2028,7 +2038,7 @@ window.__ModuleLoader__.load({
|
|
|
2028
2038
|
'대화 발췌의 총 문자 상한(200–20000).',
|
|
2029
2039
|
intentFallbackRouteLabel: '폴백 모델',
|
|
2030
2040
|
intentFallbackRouteHelp:
|
|
2031
|
-
'분류 실패 시: 이전 라우트 → 폴백 → 첫 후보.
|
|
2041
|
+
'분류 실패 시: 이전 라우트 → 폴백 → 첫 후보. 비어 있으면 첫 후보입니다. 추론 수준을 선택적으로 고정할 수 있으며, 지정하지 않으면 폴백 모델 기본값을 따릅니다.',
|
|
2032
2042
|
intentRouteUnset: '미설정',
|
|
2033
2043
|
intentEffortFollow: '모델 기본값',
|
|
2034
2044
|
intentDockAuto: '자동',
|
|
@@ -2170,7 +2180,13 @@ window.__ModuleLoader__.load({
|
|
|
2170
2180
|
'Skaliert die Stufen auf das eigene Modellfenster des Subagenten: force = min(statische Stufe, Fenster × Quote); soft/hard schrumpfen im selben Faktor. Verengt nur, lockert nie.',
|
|
2171
2181
|
wmSubagentFollowForce: 'Der Force-Stufe folgen (0)',
|
|
2172
2182
|
wmCommands: 'Befehle: /ctx-pause pausiert Wasserstand-Aktionen · /ctx-resume setzt sie fort · /ctx-handover schreibt das Übergabedokument jetzt und komprimiert sofort.',
|
|
2173
|
-
|
|
2183
|
+
trimEffortRecommended: 'Automatisch (Modell-Empfehlung)',
|
|
2184
|
+
trimSideModelLabel: 'Zusammenfassungsmodell',
|
|
2185
|
+
trimSideModelHelp: 'Modellroute für Zusammenfassungen. Standardmäßig folgt sie dem Sitzungsmodell, übernimmt aber nicht dessen Denkstufe. Leiter-Destillationen verwenden dieselbe Route. Ohne manuelle Vorgabe wird anhand der Modellmetadaten die niedrigste aktivierte Denkstufe gewählt; bei Modellen mit reinem Ein/Aus-Schalter wird off gewählt. Bei fehlender Unterstützung oder Metadaten wird keine Denkstufe gesendet und der Modellstandard verwendet.',
|
|
2186
|
+
trimFollowSession: 'Sitzungsmodell folgen',
|
|
2187
|
+
trimFoldFallbackModelLabel: 'Fallback-Modell für Faltungen',
|
|
2188
|
+
trimFoldFallbackModelHelp: 'Wenn der Zusammenfassungsaufruf fehlschlägt, wird mit diesem Modell erneut versucht; schlägt auch das fehl, wird ein Druck-Fold mechanisch ausgeführt. Die Denkstufe kann unabhängig festgelegt werden; ohne Angabe greift die Modellempfehlung. Möglichst ein Modell ohne Cooldown-, Risiko- oder Parallelitätsbeschränkungen wählen und nicht dasselbe Konto wie die Hauptsitzung verwenden. Leer = kein Fallback.',
|
|
2189
|
+
trimFallbackUnset: 'Nicht festgelegt (bei Fehler direkt mechanisch falten)',
|
|
2174
2190
|
trimSectionTitle: 'Kontext-Trim',
|
|
2175
2191
|
trimModeLabel: 'Trim-Modus',
|
|
2176
2192
|
trimModeHelp:
|
|
@@ -2262,7 +2278,7 @@ window.__ModuleLoader__.load({
|
|
|
2262
2278
|
'Gesamtzeichengrenze des Gesprächsauszugs (200–20000).',
|
|
2263
2279
|
intentFallbackRouteLabel: 'Fallback-Modell',
|
|
2264
2280
|
intentFallbackRouteHelp:
|
|
2265
|
-
'Bei Klassifikationsfehler: zuletzt geroutet → Fallback → erster Kandidat; leer = erster Kandidat.',
|
|
2281
|
+
'Bei Klassifikationsfehler: zuletzt geroutet → Fallback → erster Kandidat; leer = erster Kandidat. Der Thinking-Aufwand kann optional festgelegt werden; andernfalls gilt der Modellstandard des Fallbacks.',
|
|
2266
2282
|
intentRouteUnset: 'Nicht festgelegt',
|
|
2267
2283
|
intentEffortFollow: 'Modellstandard',
|
|
2268
2284
|
intentDockAuto: 'Auto',
|
|
@@ -2404,7 +2420,13 @@ window.__ModuleLoader__.load({
|
|
|
2404
2420
|
'Escala los niveles a la ventana del propio modelo del subagente: force = min(nivel estático, ventana × ratio); soft/hard se reducen por el mismo factor. Solo restringe, nunca amplía.',
|
|
2405
2421
|
wmSubagentFollowForce: 'Seguir el nivel forzado (0)',
|
|
2406
2422
|
wmCommands: 'Comandos: /ctx-pause suspende las acciones del nivel · /ctx-resume las reanuda · /ctx-handover escribe el documento y compacta ahora.',
|
|
2407
|
-
|
|
2423
|
+
trimEffortRecommended: 'Automático (recomendación del modelo)',
|
|
2424
|
+
trimSideModelLabel: 'Modelo de resumen',
|
|
2425
|
+
trimSideModelHelp: 'Ruta del modelo para los resúmenes. De forma predeterminada sigue el modelo de la sesión, pero no hereda su nivel de razonamiento. Las destilaciones por niveles usan la misma ruta. Sin una selección manual, los metadatos del modelo determinan el nivel habilitado más bajo; si solo ofrece activar o desactivar el razonamiento, se elige off. Si no admite razonamiento o faltan metadatos, no se envía ningún nivel y se usa el valor predeterminado del modelo.',
|
|
2426
|
+
trimFollowSession: 'Seguir el modelo de la sesión',
|
|
2427
|
+
trimFoldFallbackModelLabel: 'Modelo de respaldo para el plegado',
|
|
2428
|
+
trimFoldFallbackModelHelp: 'Si falla la llamada al modelo de resumen, se reintenta con este modelo; si también falla, el plegado por presión pasa a ser mecánico. El nivel de razonamiento se puede fijar por separado; si se deja vacío, se aplica la recomendación de este modelo. Elige un modelo con margen en límites de enfriamiento, riesgo y concurrencia, y evita compartir cuenta con la sesión principal. Vacío = sin respaldo.',
|
|
2429
|
+
trimFallbackUnset: 'Sin configurar (si falla, pasar directamente al plegado mecánico)',
|
|
2408
2430
|
trimSectionTitle: 'Recorte de contexto',
|
|
2409
2431
|
trimModeLabel: 'Modo de recorte',
|
|
2410
2432
|
trimModeHelp:
|
|
@@ -2497,7 +2519,7 @@ window.__ModuleLoader__.load({
|
|
|
2497
2519
|
'Límite total de caracteres del extracto de conversación (200–20000).',
|
|
2498
2520
|
intentFallbackRouteLabel: 'Modelo de reserva',
|
|
2499
2521
|
intentFallbackRouteHelp:
|
|
2500
|
-
'Si falla la clasificación: último modelo enrutado → reserva → primer candidato; vacío = primer candidato.',
|
|
2522
|
+
'Si falla la clasificación: último modelo enrutado → reserva → primer candidato; vacío = primer candidato. Puedes fijar opcionalmente el nivel de razonamiento; si no, se usa el valor predeterminado del modelo de reserva.',
|
|
2501
2523
|
intentRouteUnset: 'Sin establecer',
|
|
2502
2524
|
intentEffortFollow: 'predeterminado del modelo',
|
|
2503
2525
|
intentDockAuto: 'Auto',
|
|
@@ -2639,7 +2661,13 @@ window.__ModuleLoader__.load({
|
|
|
2639
2661
|
'Ajuste les paliers à la fenêtre propre du modèle du sous-agent : force = min(palier statique, fenêtre × ratio) ; soft/hard réduits du même facteur. Ne fait que resserrer, jamais relâcher.',
|
|
2640
2662
|
wmSubagentFollowForce: 'Suivre le palier force (0)',
|
|
2641
2663
|
wmCommands: 'Commandes : /ctx-pause suspend les actions de niveau d’eau · /ctx-resume les reprend · /ctx-handover écrit le document et compacte maintenant.',
|
|
2642
|
-
|
|
2664
|
+
trimEffortRecommended: 'Automatique (recommandation du modèle)',
|
|
2665
|
+
trimSideModelLabel: 'Modèle de résumé',
|
|
2666
|
+
trimSideModelHelp: 'Route du modèle pour les résumés. Par défaut, elle suit le modèle de la session sans reprendre son niveau de raisonnement. Les distillations en cascade utilisent la même route. Sans choix manuel, les métadonnées sélectionnent le niveau activé le plus faible ; pour un modèle avec seulement un interrupteur de raisonnement, le niveau choisi est off. Si le raisonnement est indisponible ou que les métadonnées manquent, aucun niveau n’est envoyé et le défaut du modèle s’applique.',
|
|
2667
|
+
trimFollowSession: 'Suivre le modèle de la session',
|
|
2668
|
+
trimFoldFallbackModelLabel: 'Modèle de secours pour le pliage',
|
|
2669
|
+
trimFoldFallbackModelHelp: 'Si l’appel au modèle de résumé échoue, une nouvelle tentative utilise ce modèle ; en cas de nouvel échec, un pliage sous pression devient mécanique. Le niveau de raisonnement se règle séparément ; sans choix, la recommandation de ce modèle s’applique. Choisissez un modèle avec de la marge sur le refroidissement, le contrôle des risques et la concurrence, et évitez le même compte que la session principale. Vide = aucun secours.',
|
|
2670
|
+
trimFallbackUnset: 'Non défini (en cas d’échec, passer directement au pliage mécanique)',
|
|
2643
2671
|
trimSectionTitle: 'Rognage du contexte',
|
|
2644
2672
|
trimModeLabel: 'Mode de rognage',
|
|
2645
2673
|
trimModeHelp:
|
|
@@ -2732,7 +2760,7 @@ window.__ModuleLoader__.load({
|
|
|
2732
2760
|
'Plafond total de caractères de l’extrait de conversation (200–20000).',
|
|
2733
2761
|
intentFallbackRouteLabel: 'Modèle de secours',
|
|
2734
2762
|
intentFallbackRouteHelp:
|
|
2735
|
-
'En cas d’échec : dernier modèle routé → secours → premier candidat ; vide = premier candidat.',
|
|
2763
|
+
'En cas d’échec : dernier modèle routé → secours → premier candidat ; vide = premier candidat. Vous pouvez épingler le niveau de raisonnement ; sinon, le niveau par défaut du modèle de secours est utilisé.',
|
|
2736
2764
|
intentRouteUnset: 'Non défini',
|
|
2737
2765
|
intentEffortFollow: 'par défaut du modèle',
|
|
2738
2766
|
intentDockAuto: 'Auto',
|
|
@@ -2874,7 +2902,13 @@ window.__ModuleLoader__.load({
|
|
|
2874
2902
|
'Ridimensiona i livelli alla finestra del modello del subagente: force = min(livello statico, finestra × rapporto); soft/hard si riducono dello stesso fattore. Solo restrizione, mai allentamento.',
|
|
2875
2903
|
wmSubagentFollowForce: 'Segui la soglia force (0)',
|
|
2876
2904
|
wmCommands: 'Comandi: /ctx-pause sospende le azioni da livello dell’acqua · /ctx-resume le riprende · /ctx-handover scrive il documento e compatta subito.',
|
|
2877
|
-
|
|
2905
|
+
trimEffortRecommended: 'Automatico (consigliato dal modello)',
|
|
2906
|
+
trimSideModelLabel: 'Modello di riepilogo',
|
|
2907
|
+
trimSideModelHelp: 'Percorso del modello per i riepiloghi. Per impostazione predefinita segue il modello della sessione, senza ereditarne il livello di ragionamento. Anche le distillazioni a livelli usano lo stesso percorso. Senza una scelta manuale, i metadati determinano il livello attivo più basso; per i modelli con il solo interruttore on/off si usa off. Se il ragionamento non è supportato o mancano i metadati, non viene inviato alcun livello e si usa il valore predefinito del modello.',
|
|
2908
|
+
trimFollowSession: 'Segui il modello della sessione',
|
|
2909
|
+
trimFoldFallbackModelLabel: 'Modello di riserva per la piegatura',
|
|
2910
|
+
trimFoldFallbackModelHelp: 'Se la chiamata al modello di riepilogo fallisce, si riprova con questo modello; se fallisce anche questo, la piegatura sotto pressione diventa meccanica. Il livello di ragionamento si può impostare separatamente; se vuoto, si usa la raccomandazione del modello. Scegli un modello con margine per cooldown, controllo del rischio e concorrenza, evitando di condividere l’account con la sessione principale. Vuoto = nessun fallback.',
|
|
2911
|
+
trimFallbackUnset: 'Non impostato (in caso di errore, passa direttamente alla piegatura meccanica)',
|
|
2878
2912
|
trimSectionTitle: 'Riduzione del contesto',
|
|
2879
2913
|
trimModeLabel: 'Modalità di riduzione',
|
|
2880
2914
|
trimModeHelp:
|
|
@@ -2967,7 +3001,7 @@ window.__ModuleLoader__.load({
|
|
|
2967
3001
|
'Limite totale di caratteri dell’estratto della conversazione (200–20000).',
|
|
2968
3002
|
intentFallbackRouteLabel: 'Modello di riserva',
|
|
2969
3003
|
intentFallbackRouteHelp:
|
|
2970
|
-
'In caso di errore: ultimo modello instradato → riserva → primo candidato; vuoto = primo candidato.',
|
|
3004
|
+
'In caso di errore: ultimo modello instradato → riserva → primo candidato; vuoto = primo candidato. Puoi fissare il livello di ragionamento; se omesso, si usa il valore predefinito del modello di riserva.',
|
|
2971
3005
|
intentRouteUnset: 'Non impostato',
|
|
2972
3006
|
intentEffortFollow: 'predefinito del modello',
|
|
2973
3007
|
intentDockAuto: 'Auto',
|
|
@@ -3109,7 +3143,13 @@ window.__ModuleLoader__.load({
|
|
|
3109
3143
|
'Escala os níveis para a janela do próprio modelo do subagente: force = min(nível estático, janela × razão); soft/hard encolhem pelo mesmo fator. Apenas aperta, nunca afrouxa.',
|
|
3110
3144
|
wmSubagentFollowForce: 'Seguir o limiar force (0)',
|
|
3111
3145
|
wmCommands: 'Comandos: /ctx-pause suspende as ações de nível de água · /ctx-resume as retoma · /ctx-handover escreve o documento e compacta agora.',
|
|
3112
|
-
|
|
3146
|
+
trimEffortRecommended: 'Automático (recomendação do modelo)',
|
|
3147
|
+
trimSideModelLabel: 'Modelo de resumo',
|
|
3148
|
+
trimSideModelHelp: 'Rota do modelo para os resumos. Por padrão, segue o modelo da sessão, mas não herda o nível de raciocínio dessa chamada. As destilações em níveis usam a mesma rota. Sem escolha manual, os metadados selecionam o nível ativo mais baixo; para modelos com apenas a opção de ligar/desligar o raciocínio, usa-se off. Se o raciocínio não for compatível ou faltarem metadados, nenhum nível é enviado e vale o padrão do modelo.',
|
|
3149
|
+
trimFollowSession: 'Seguir o modelo da sessão',
|
|
3150
|
+
trimFoldFallbackModelLabel: 'Modelo de reserva para dobra',
|
|
3151
|
+
trimFoldFallbackModelHelp: 'Se a chamada do modelo de resumo falhar, tenta novamente com este modelo; se também falhar, a dobra por pressão passa a ser mecânica. O nível de raciocínio pode ser definido separadamente; se ficar vazio, usa-se a recomendação deste modelo. Escolha um modelo com margem para cooldown, controle de risco e concorrência, evitando compartilhar a conta com a sessão principal. Vazio = sem fallback.',
|
|
3152
|
+
trimFallbackUnset: 'Não configurado (em caso de falha, usar dobra mecânica diretamente)',
|
|
3113
3153
|
trimSectionTitle: 'Corte de contexto',
|
|
3114
3154
|
trimModeLabel: 'Modo de corte',
|
|
3115
3155
|
trimModeHelp:
|
|
@@ -3202,7 +3242,7 @@ window.__ModuleLoader__.load({
|
|
|
3202
3242
|
'Limite total de caracteres do trecho da conversa (200–20000).',
|
|
3203
3243
|
intentFallbackRouteLabel: 'Modelo de reserva',
|
|
3204
3244
|
intentFallbackRouteHelp:
|
|
3205
|
-
'Se a classificação falhar: último modelo roteado → reserva → primeiro candidato; vazio = primeiro candidato.',
|
|
3245
|
+
'Se a classificação falhar: último modelo roteado → reserva → primeiro candidato; vazio = primeiro candidato. É possível fixar o nível de raciocínio; se não definido, usa-se o padrão do modelo de reserva.',
|
|
3206
3246
|
intentRouteUnset: 'Não definido',
|
|
3207
3247
|
intentEffortFollow: 'padrão do modelo',
|
|
3208
3248
|
intentDockAuto: 'Auto',
|
|
@@ -3344,7 +3384,13 @@ window.__ModuleLoader__.load({
|
|
|
3344
3384
|
'Масштабирует уровни под собственное окно модели субагента: force = min(статический уровень, окно × доля); soft/hard сжимаются на тот же коэффициент. Только ужесточает, не смягчает.',
|
|
3345
3385
|
wmSubagentFollowForce: 'Следовать линии force (0)',
|
|
3346
3386
|
wmCommands: 'Команды: /ctx-pause приостанавливает действия по уровню воды · /ctx-resume возобновляет их · /ctx-handover записывает документ передачи и сжимает прямо сейчас.',
|
|
3347
|
-
|
|
3387
|
+
trimEffortRecommended: 'Авто (рекомендация модели)',
|
|
3388
|
+
trimSideModelLabel: 'Модель сводки',
|
|
3389
|
+
trimSideModelHelp: 'Маршрут модели для сводок. По умолчанию следует модели сессии, но не наследует уровень рассуждения этого вызова. Для ступенчатой дистилляции используется тот же маршрут. Без ручного выбора метаданные задают самый низкий включённый уровень; для модели только с переключателем рассуждений выбирается off. Если рассуждения не поддерживаются или метаданных нет, уровень не передаётся и используется значение модели по умолчанию.',
|
|
3390
|
+
trimFollowSession: 'Следовать модели сессии',
|
|
3391
|
+
trimFoldFallbackModelLabel: 'Резервная модель сворачивания',
|
|
3392
|
+
trimFoldFallbackModelHelp: 'Если вызов модели сводки завершается ошибкой, повтор выполняется на этой модели; при повторном сбое сворачивание под давлением становится механическим. Уровень рассуждения задаётся отдельно; если не указан, действует рекомендация этой модели. Выбирайте модель с запасом по охлаждению, контролю рисков и параллельным запросам и не используйте общий аккаунт с главной сессией. Пусто = без резервного маршрута.',
|
|
3393
|
+
trimFallbackUnset: 'Не задано (при сбое сразу перейти к механическому сворачиванию)',
|
|
3348
3394
|
trimSectionTitle: 'Обрезка контекста',
|
|
3349
3395
|
trimModeLabel: 'Режим обрезки',
|
|
3350
3396
|
trimModeHelp:
|
|
@@ -3436,7 +3482,7 @@ window.__ModuleLoader__.load({
|
|
|
3436
3482
|
'Общий лимит символов выборки диалога (200–20000).',
|
|
3437
3483
|
intentFallbackRouteLabel: 'Резервная модель',
|
|
3438
3484
|
intentFallbackRouteHelp:
|
|
3439
|
-
'При сбое классификации: прошлая модель → резерв → первый кандидат; пусто = первый кандидат.',
|
|
3485
|
+
'При сбое классификации: прошлая модель → резерв → первый кандидат; пусто = первый кандидат. Можно задать уровень reasoning; если он не указан, используется значение резервной модели по умолчанию.',
|
|
3440
3486
|
intentRouteUnset: 'Не задано',
|
|
3441
3487
|
intentEffortFollow: 'по умолчанию модели',
|
|
3442
3488
|
intentDockAuto: 'Авто',
|
|
@@ -5433,10 +5479,12 @@ window.__ModuleLoader__.load({
|
|
|
5433
5479
|
trimSideModel: {
|
|
5434
5480
|
provider: values.trimSideModel.provider,
|
|
5435
5481
|
model: values.trimSideModel.model,
|
|
5482
|
+
...(values.trimSideModel.effort ? { effort: values.trimSideModel.effort } : {}),
|
|
5436
5483
|
},
|
|
5437
5484
|
trimFoldFallbackModel: {
|
|
5438
5485
|
provider: values.trimFoldFallbackModel.provider,
|
|
5439
5486
|
model: values.trimFoldFallbackModel.model,
|
|
5487
|
+
...(values.trimFoldFallbackModel.effort ? { effort: values.trimFoldFallbackModel.effort } : {}),
|
|
5440
5488
|
},
|
|
5441
5489
|
trimStateDir: values.trimStateDir,
|
|
5442
5490
|
...Object.fromEntries(
|
|
@@ -5445,9 +5493,9 @@ window.__ModuleLoader__.load({
|
|
|
5445
5493
|
teamsMode: values.teamsMode,
|
|
5446
5494
|
syncWhitelist: values.syncWhitelist,
|
|
5447
5495
|
// Intent recognition (design: intent-routing.md §2): route
|
|
5448
|
-
// objects materialize {provider, model}
|
|
5449
|
-
//
|
|
5450
|
-
//
|
|
5496
|
+
// Route objects materialize {provider, model[, effort]} as configured;
|
|
5497
|
+
// the classifier route remains effort-free. Candidate effort/note are
|
|
5498
|
+
// always sent (blank string = unset; Host coerces per schema).
|
|
5451
5499
|
intentEnabled: values.intentEnabled,
|
|
5452
5500
|
intentClassifierRoute: {
|
|
5453
5501
|
provider: values.intentClassifierRoute.provider,
|
|
@@ -5472,6 +5520,7 @@ window.__ModuleLoader__.load({
|
|
|
5472
5520
|
intentFallbackRoute: {
|
|
5473
5521
|
provider: values.intentFallbackRoute.provider,
|
|
5474
5522
|
model: values.intentFallbackRoute.model,
|
|
5523
|
+
...(values.intentFallbackRoute.effort ? { effort: values.intentFallbackRoute.effort } : {}),
|
|
5475
5524
|
},
|
|
5476
5525
|
};
|
|
5477
5526
|
if (sameValues(current, desired)) {
|
|
@@ -5875,9 +5924,10 @@ window.__ModuleLoader__.load({
|
|
|
5875
5924
|
(meta) => meta.model === route.model,
|
|
5876
5925
|
);
|
|
5877
5926
|
edit(field, {
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5927
|
+
provider: next,
|
|
5928
|
+
model: kept ? route.model : '',
|
|
5929
|
+
effort: '',
|
|
5930
|
+
});
|
|
5881
5931
|
},
|
|
5882
5932
|
),
|
|
5883
5933
|
'aria-label': `${label} · provider`,
|
|
@@ -5891,7 +5941,7 @@ window.__ModuleLoader__.load({
|
|
|
5891
5941
|
`${intentId}-${field}-model`,
|
|
5892
5942
|
route.model,
|
|
5893
5943
|
(next) => {
|
|
5894
|
-
edit(field, { ...route, model: next });
|
|
5944
|
+
edit(field, { ...route, model: next, effort: '' });
|
|
5895
5945
|
},
|
|
5896
5946
|
),
|
|
5897
5947
|
disabled: !editable || route.provider === '',
|
|
@@ -5899,6 +5949,16 @@ window.__ModuleLoader__.load({
|
|
|
5899
5949
|
},
|
|
5900
5950
|
...intentModelOptions(route.provider, route.model),
|
|
5901
5951
|
),
|
|
5952
|
+
field === 'intentFallbackRoute' && route.provider !== '' && route.model !== ''
|
|
5953
|
+
? intentEffortSelect(
|
|
5954
|
+
`${intentId}-${field}-effort`,
|
|
5955
|
+
route,
|
|
5956
|
+
route.effort ?? '',
|
|
5957
|
+
(next) => edit(field, { ...route, effort: next }),
|
|
5958
|
+
`${label} · effort`,
|
|
5959
|
+
t('intentEffortFollow'),
|
|
5960
|
+
)
|
|
5961
|
+
: null,
|
|
5902
5962
|
);
|
|
5903
5963
|
};
|
|
5904
5964
|
/** Trim route rows reuse the intent route picker machinery — the
|
|
@@ -5950,6 +6010,7 @@ window.__ModuleLoader__.load({
|
|
|
5950
6010
|
...route,
|
|
5951
6011
|
provider: next,
|
|
5952
6012
|
model: kept ? route.model : '',
|
|
6013
|
+
effort: '',
|
|
5953
6014
|
});
|
|
5954
6015
|
},
|
|
5955
6016
|
),
|
|
@@ -5963,10 +6024,10 @@ window.__ModuleLoader__.load({
|
|
|
5963
6024
|
: route.model,
|
|
5964
6025
|
(next) => {
|
|
5965
6026
|
if (followMode && next === TRIM_ROUTE_FOLLOW) {
|
|
5966
|
-
edit(field, { ...route, model: '' });
|
|
6027
|
+
edit(field, { ...route, model: '', effort: '' });
|
|
5967
6028
|
return;
|
|
5968
6029
|
}
|
|
5969
|
-
edit(field, { ...route, model: next });
|
|
6030
|
+
edit(field, { ...route, model: next, effort: '' });
|
|
5970
6031
|
},
|
|
5971
6032
|
),
|
|
5972
6033
|
disabled: !editable || route.provider === '',
|
|
@@ -5976,10 +6037,10 @@ window.__ModuleLoader__.load({
|
|
|
5976
6037
|
? intentEffortSelect(
|
|
5977
6038
|
`${trimId}-${field}-effort`,
|
|
5978
6039
|
route,
|
|
5979
|
-
route.effort,
|
|
6040
|
+
route.effort ?? '',
|
|
5980
6041
|
(next) => edit(field, { ...route, effort: next }),
|
|
5981
6042
|
`${label} · effort`,
|
|
5982
|
-
t('
|
|
6043
|
+
t('trimEffortRecommended'),
|
|
5983
6044
|
)
|
|
5984
6045
|
: null,
|
|
5985
6046
|
);
|
|
@@ -5988,8 +6049,8 @@ window.__ModuleLoader__.load({
|
|
|
5988
6049
|
* wire efforts when the catalog reports them, the EFFORTS
|
|
5989
6050
|
* fallback otherwise; '' = adapter default. A stored value
|
|
5990
6051
|
* missing from the list stays selectable. emptyLabel replaces
|
|
5991
|
-
* the '' option label
|
|
5992
|
-
* the model default
|
|
6052
|
+
* the '' option label. Trim rows use their automatic recommendation;
|
|
6053
|
+
* an empty intent-fallback pin follows the model default. */
|
|
5993
6054
|
const intentEffortSelect = (
|
|
5994
6055
|
id,
|
|
5995
6056
|
route,
|
package/host/config.js
CHANGED
|
@@ -67,10 +67,9 @@ export const IntentCandidateSchema = z.object({
|
|
|
67
67
|
* ModelRouteSchema this accepts the "unset" `{provider:"", model:""}`
|
|
68
68
|
* pair the settings page round-trips — ModelRouteSchema's `.min(1)`
|
|
69
69
|
* would reject that exact declared default on every settings write.
|
|
70
|
-
* Consumers validate non-empty before trusting the route. effort
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* intent-layer routes leave it unset. */
|
|
70
|
+
* Consumers validate non-empty before trusting the route. `effort` is an
|
|
71
|
+
* optional override for summary routes and intent fallback; the classifier
|
|
72
|
+
* route remains effort-free in its route cleaner. */
|
|
74
73
|
const IntentRouteSchema = z.object({
|
|
75
74
|
provider: z.string(),
|
|
76
75
|
model: z.string(),
|
|
@@ -240,8 +239,9 @@ export const Config = z.object({
|
|
|
240
239
|
* the 0.8×-window auto-compaction (see effectiveContextWindow in
|
|
241
240
|
* host/intent.js). */
|
|
242
241
|
intentContextWindow: z.number().min(1024).default(200000).volatile(),
|
|
243
|
-
/** Optional
|
|
244
|
-
*
|
|
242
|
+
/** Optional fallback route after classification fails when no prior route
|
|
243
|
+
* is available; empty = the first candidate. An optional effort pin
|
|
244
|
+
* overrides the fallback model's default. */
|
|
245
245
|
intentFallbackRoute: IntentRouteSchema.default({ provider: "", model: "" }).volatile(),
|
|
246
246
|
|
|
247
247
|
// --- Context trim: fully-automatic conversation compression ------------
|
|
@@ -292,12 +292,14 @@ export const Config = z.object({
|
|
|
292
292
|
* budget and the ladder starved. */
|
|
293
293
|
trimMaxFoldsPerHour: z.number().min(1).max(60).default(30).volatile(),
|
|
294
294
|
/** Route for the side-model summarizer (L3). Empty = inherit the
|
|
295
|
-
* session's current model
|
|
295
|
+
* session's current provider/model; an optional effort pin overrides
|
|
296
|
+
* the model's automatic recommended effort. */
|
|
296
297
|
trimSideModel: IntentRouteSchema.default({ provider: "", model: "" }).volatile(),
|
|
297
298
|
/** Route for the fold-fallback summarizer. When the primary side route
|
|
298
299
|
* (trimSideModel or the inherited session model) fails, raw folds retry
|
|
299
300
|
* on this route before degrading to a mechanical fold; ladder folds
|
|
300
|
-
* retry but never go mechanical.
|
|
301
|
+
* retry but never go mechanical. An optional effort pin overrides the
|
|
302
|
+
* model's automatic recommendation. Pick a route with headroom on cooldown,
|
|
301
303
|
* risk-control, and concurrency limits. Empty = no fallback leg. */
|
|
302
304
|
trimFoldFallbackModel: IntentRouteSchema.default({ provider: "", model: "" }).volatile(),
|
|
303
305
|
/** T1/T2/T3 ladder folding (docs/ladder-fold.md): master switch for the
|
|
@@ -695,10 +695,9 @@ export function applyContextTrim(ctx, config) {
|
|
|
695
695
|
} else if (view.applied > 0) {
|
|
696
696
|
epochResetDoneBySession.delete(sessionId);
|
|
697
697
|
}
|
|
698
|
-
//
|
|
699
|
-
// provider/model
|
|
700
|
-
//
|
|
701
|
-
// verbatim instead of re-deriving (and losing) it.
|
|
698
|
+
// Record the active request's route and resolved effort for diagnostics only.
|
|
699
|
+
// The side summarizer follows provider/model only and resolves effort from its
|
|
700
|
+
// model metadata rather than inheriting this dispatch's effort.
|
|
702
701
|
const model = {
|
|
703
702
|
provider: options.provider ?? null,
|
|
704
703
|
model: options.model ?? null,
|
|
@@ -718,16 +717,14 @@ export function applyContextTrim(ctx, config) {
|
|
|
718
717
|
}
|
|
719
718
|
|
|
720
719
|
/** Resolve the side-model route: explicit trimSideModel route, else the
|
|
721
|
-
* session's own model
|
|
720
|
+
* session's own provider/model. Effort is resolved from that model's
|
|
721
|
+
* supported thinking metadata, not inherited from the active session call. */
|
|
722
722
|
function sideRouteFor(sessionId) {
|
|
723
723
|
const explicit = readRoute(config, "trimSideModel");
|
|
724
724
|
if (explicit !== null) return explicit;
|
|
725
725
|
const model = metrics.of(sessionId)?.lastModel ?? null;
|
|
726
726
|
if (model !== null && typeof model.provider === "string" && model.provider !== "" && typeof model.model === "string" && model.model !== "") {
|
|
727
|
-
|
|
728
|
-
return typeof model.effort === "string" && model.effort !== ""
|
|
729
|
-
? { provider: model.provider, model: model.model, effort: model.effort }
|
|
730
|
-
: { provider: model.provider, model: model.model };
|
|
727
|
+
return { provider: model.provider, model: model.model };
|
|
731
728
|
}
|
|
732
729
|
return null;
|
|
733
730
|
}
|
|
@@ -224,15 +224,25 @@ function describeFailure(chunk) {
|
|
|
224
224
|
return ` (${raw.replace(/\s+/gu, " ").trim().slice(0, 300)})`;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
/**
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
|
|
231
|
-
|
|
227
|
+
/** Choose the lowest enabled tier when several reasoning levels are available.
|
|
228
|
+
* A model with only an on/off switch is pinned to "off"; when reasoning
|
|
229
|
+
* metadata is absent, leave the model's adapter default unchanged. */
|
|
230
|
+
export function recommendedReasoningEffort(modelInfo) {
|
|
231
|
+
const efforts = modelInfo?.reasoning?.efforts;
|
|
232
|
+
if (!Array.isArray(efforts) || efforts.length === 0) return null;
|
|
233
|
+
const ids = efforts.map((entry) => typeof entry === "string" ? entry : entry?.id).filter((id) => typeof id === "string" && id !== "");
|
|
234
|
+
const enabled = ids.filter((id) => id !== "off");
|
|
235
|
+
if (enabled.length > 1) return enabled[0];
|
|
236
|
+
return ids.includes("off") ? "off" : null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** Side-model summary. llm: the dsh llm service; route: {provider, model, effort?}.
|
|
240
|
+
* An empty effort pin is resolved from model reasoning metadata; unavailable
|
|
241
|
+
* metadata leaves the adapter default unchanged. Returns summary text or null. */
|
|
232
242
|
export async function summarizeWithModel(llm, route, materialText, options = {}) {
|
|
233
243
|
const fail = typeof options.onFail === "function" ? options.onFail : null;
|
|
234
|
-
// Effort-retry notice: fires
|
|
235
|
-
//
|
|
244
|
+
// Effort-retry notice: fires before a one-time effort fallback, whether
|
|
245
|
+
// or not that retry lands. Falls back to fail when no notice is supplied.
|
|
236
246
|
const notice = typeof options.onNotice === "function" ? options.onNotice : null;
|
|
237
247
|
if (route === null || route === undefined) { fail?.("no-route"); return null; }
|
|
238
248
|
if (typeof llm?.prepareCall !== "function") { fail?.("no-prepare-call"); return null; }
|
|
@@ -242,39 +252,40 @@ export async function summarizeWithModel(llm, route, materialText, options = {})
|
|
|
242
252
|
const controller = new AbortController();
|
|
243
253
|
const timer = setTimeout(() => controller.abort(new Error("trim summary deadline")), deadlineMs);
|
|
244
254
|
try {
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const
|
|
255
|
+
// Resolve from the selected model itself: an empty pin means the lowest
|
|
256
|
+
// advertised thinking effort, while absent reasoning metadata leaves
|
|
257
|
+
// the adapter default (no thinking) untouched. Explicit effort pins win.
|
|
258
|
+
let modelInfo = null;
|
|
259
|
+
if (typeof llm.resolveModelInfo === "function") {
|
|
260
|
+
try { modelInfo = await llm.resolveModelInfo(route.provider, route.model, controller.signal); }
|
|
261
|
+
catch { /* Metadata is advisory; prepareCall remains authoritative. */ }
|
|
262
|
+
}
|
|
263
|
+
const automaticEffort = recommendedReasoningEffort(modelInfo);
|
|
264
|
+
const hasOffEffort = Array.isArray(modelInfo?.reasoning?.efforts) && modelInfo.reasoning.efforts.some((entry) => (typeof entry === "string" ? entry : entry?.id) === "off");
|
|
265
|
+
const explicitEffort = typeof route.effort === "string" && route.effort !== "";
|
|
266
|
+
const requestedEffort = explicitEffort ? route.effort : automaticEffort;
|
|
267
|
+
const proposalFor = (effort) => ({
|
|
268
|
+
provider: route.provider,
|
|
269
|
+
model: route.model,
|
|
270
|
+
maxTokens,
|
|
271
|
+
...(typeof effort === "string" && effort !== "" ? { reasoningEffort: effort } : {}),
|
|
272
|
+
});
|
|
258
273
|
let call;
|
|
259
274
|
try {
|
|
260
|
-
call = await llm.prepareCall(
|
|
261
|
-
{ provider: route.provider, model: route.model, maxTokens, reasoningEffort: requestedEffort },
|
|
262
|
-
controller.signal,
|
|
263
|
-
(controls) => controls,
|
|
264
|
-
);
|
|
275
|
+
call = await llm.prepareCall(proposalFor(requestedEffort), controller.signal, (controls) => controls);
|
|
265
276
|
} catch (prepareError) {
|
|
266
|
-
// An inherited session effort can exceed what the route's adapter
|
|
267
|
-
// supports: retry once pinned low before giving up (the outer
|
|
268
|
-
// catch then turns the failure into a skipped fold cycle).
|
|
269
277
|
const code = prepareError?.code ?? null;
|
|
270
278
|
const named = typeof prepareError?.message === "string" && prepareError.message.includes("UNSUPPORTED_REASONING_EFFORT");
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
279
|
+
if (code !== "UNSUPPORTED_REASONING_EFFORT" && !named) throw prepareError;
|
|
280
|
+
// Stale metadata or a stale pin should not prevent a summary: retry
|
|
281
|
+
// once at the model's automatic minimum, or without an effort. Never
|
|
282
|
+
// turn an explicitly requested "off" into enabled reasoning.
|
|
283
|
+
const retryEffort = requestedEffort === "off"
|
|
284
|
+
? null
|
|
285
|
+
: (explicitEffort && automaticEffort !== requestedEffort ? automaticEffort : (hasOffEffort ? "off" : null));
|
|
286
|
+
if (retryEffort === requestedEffort) throw prepareError;
|
|
287
|
+
(notice ?? fail)?.(`effort "${requestedEffort ?? "default"}" unsupported, retrying ${retryEffort ?? "without reasoning"}`);
|
|
288
|
+
call = await llm.prepareCall(proposalFor(retryEffort), controller.signal, (controls) => controls);
|
|
278
289
|
}
|
|
279
290
|
let text = "";
|
|
280
291
|
let finishKind = null;
|
package/host/ptc-guard.js
CHANGED
|
@@ -89,6 +89,12 @@ function renderPtcGuard() {
|
|
|
89
89
|
`- Every other tool MUST be invoked as an awaited SDK function inside a ${RUN_CODE_NAME} program: \`await tools.name(args)\` — e.g. \`await tools.skill({ name: "git-commit-message" })\` or \`await tools.spawn_teammate({ ... })\`.`,
|
|
90
90
|
`- A direct call fails with: unknown tool "x": only \`${RUN_CODE_NAME}\` is callable directly — call \`x\` from inside a \`${RUN_CODE_NAME}\` program instead. Never retry the direct form; wrap the call.`,
|
|
91
91
|
`- Wherever this prompt says "call the X tool" (skill catalog, doctrines, per-turn reminders), read it as "call X inside a ${RUN_CODE_NAME} program". Batch independent calls as parallel awaits inside ONE program.`,
|
|
92
|
+
`- \`grep.pattern\` is a regular expression. In a normal JavaScript string inside \`${RUN_CODE_NAME}\`, double backslashes: write \`"\\\\("\` to pass \`\\(\` to grep; \`String.raw\` tagged templates also preserve backslashes. If grep reports \`unclosed group\`, fix the pattern before retrying; never repeat it unchanged.`,
|
|
93
|
+
`- Unless this call must intentionally retain state across calls (e.g. the one-time CUA bridge initialization), MUST wrap the entire ${RUN_CODE_NAME} program body in an async IIFE: \`await (async () => { ... })();\`. Keep all temporary \`const\`/\`let\`/\`class\` declarations inside it; this makes reusing local names such as \`res\` safe even when an earlier call used them. Top-level bindings persist for this Agent: only create them for intentionally shared state, and never redeclare existing top-level \`const\`/\`let\`/\`class\`; reassign an existing top-level \`var\` or choose a fresh unique name. If \`Identifier ... has already been declared\` occurs, rewrite the program in the IIFE rather than merely rerunning it—the SyntaxError happens before the body runs.`,
|
|
94
|
+
`- For intentional top-level bindings, maintain a ledger of declared names at \`globalThis.__dshSwitchmanPtcBindings\` (initialize idempotently with \`globalThis.__dshSwitchmanPtcBindings ??= new Set()\`). Before emitting a program with top-level declarations, check each name against this ledger and the visible prior \`${RUN_CODE_NAME}\` snippets; after a successful declaration, add the name with \`globalThis.__dshSwitchmanPtcBindings.add("name")\`. This ledger is manually maintained, not automatic introspection: if the old history or ledger is incomplete, do not guess—keep the code in an IIFE or choose a fresh name.`,
|
|
95
|
+
`- For routine \`${RUN_CODE_NAME}\` calls — including programs that only call SDK tools such as \`tools.skill(...)\` — pass only \`code\`, \`description\`, and \`timeoutMs\`; omit both \`sandbox_permissions\` and \`justification\`. If a call is rejected for invalid justification, never repeat it unchanged; retry without those fields.`,
|
|
96
|
+
`- If ${RUN_CODE_NAME} returns a parser error such as "Expected ident", treat it as a syntax issue in the submitted code; when present, the appended "File sandbox: ..." reports execution context, not the cause. Correct the code before retrying; never repeat it unchanged.`,
|
|
97
|
+
`- When a ${RUN_CODE_NAME} program embeds long prompt text, do not hand-write it as a double-quoted JavaScript string if it contains quotes (for example, getResource(".") or System.getProperty("user.dir")): build the text as data, escape the inner quotes, or serialize it with JSON.stringify(text); inspect or syntax-check the complete source before retrying.`,
|
|
92
98
|
`- Never set \`sandbox_permissions\` on any call, direct or SDK: it is a privilege-escalation request and fails with "not strictly wider than this call's current ... mode" whenever the session already runs at least that access level — retry without the field.`,
|
|
93
99
|
].join("\n");
|
|
94
100
|
}
|
package/host/routes.js
CHANGED
|
@@ -150,13 +150,12 @@ const INTENT_NUMBER_FIELDS = [
|
|
|
150
150
|
{ field: "intentHistoryMaxChars", min: 200, max: 20000, def: 2400 },
|
|
151
151
|
{ field: "intentContextWindow", min: 1024, max: Number.POSITIVE_INFINITY, def: 200000 },
|
|
152
152
|
];
|
|
153
|
-
/** Intent
|
|
153
|
+
/** Intent classifier routes round-trip the "unset" {provider:"", model:""}
|
|
154
154
|
* pair, so they validate against the loosened cleanIntentRoute (both keys
|
|
155
|
-
* must be strings; either may be empty)
|
|
156
|
-
const INTENT_ROUTE_FIELDS = ["intentClassifierRoute"
|
|
157
|
-
/**
|
|
158
|
-
|
|
159
|
-
const TRIM_ROUTE_FIELDS = ["trimSideModel", "trimFoldFallbackModel"];
|
|
155
|
+
* must be strings; either may be empty). */
|
|
156
|
+
const INTENT_ROUTE_FIELDS = ["intentClassifierRoute"];
|
|
157
|
+
/** Summary routes and the intent fallback route can carry an effort pin. */
|
|
158
|
+
const EFFORT_ROUTE_FIELDS = ["trimSideModel", "trimFoldFallbackModel", "intentFallbackRoute"];
|
|
160
159
|
/** Intent candidate list (route + optional effort/note per entry). */
|
|
161
160
|
const INTENT_CANDIDATE_FIELDS = ["intentCandidates"];
|
|
162
161
|
|
|
@@ -315,11 +314,8 @@ function cleanIntentRoute(entry) {
|
|
|
315
314
|
return provider === null || model === null ? null : { provider, model };
|
|
316
315
|
}
|
|
317
316
|
|
|
318
|
-
/** Coerce one
|
|
319
|
-
|
|
320
|
-
* model, and stripping it here made every settings save silently revert the
|
|
321
|
-
* settings page's effort select to the default. Intent routes omit effort. */
|
|
322
|
-
function cleanTrimRoute(entry) {
|
|
317
|
+
/** Coerce one route that may carry an optional reasoning-effort pin. */
|
|
318
|
+
function cleanEffortRoute(entry) {
|
|
323
319
|
const route = cleanIntentRoute(entry);
|
|
324
320
|
if (route === null) return null;
|
|
325
321
|
const effort = typeof entry.effort === "string" ? entry.effort.trim() : "";
|
|
@@ -370,7 +366,7 @@ export function snapshotOf(config) {
|
|
|
370
366
|
? rawOf(config[field]).map(cleanEffortEntry).filter(Boolean)
|
|
371
367
|
: [];
|
|
372
368
|
for (const field of INTENT_ROUTE_FIELDS) values[field] = cleanIntentRoute(rawOf(config?.[field])) ?? { provider: "", model: "" };
|
|
373
|
-
for (const field of
|
|
369
|
+
for (const field of EFFORT_ROUTE_FIELDS) values[field] = cleanEffortRoute(rawOf(config?.[field])) ?? { provider: "", model: "" };
|
|
374
370
|
for (const field of INTENT_CANDIDATE_FIELDS)
|
|
375
371
|
values[field] = mergeIntentCandidates(rawOf(config?.[field]));
|
|
376
372
|
values.intentClassifierKind = ENUM_FIELDS.intentClassifierKind.includes(rawOf(config?.intentClassifierKind))
|
|
@@ -445,8 +441,8 @@ export function coerceValues(input) {
|
|
|
445
441
|
if (route === null) return null;
|
|
446
442
|
values[field] = route;
|
|
447
443
|
}
|
|
448
|
-
for (const field of
|
|
449
|
-
const route =
|
|
444
|
+
for (const field of EFFORT_ROUTE_FIELDS) {
|
|
445
|
+
const route = cleanEffortRoute(input[field]);
|
|
450
446
|
if (route === null) return null;
|
|
451
447
|
values[field] = route;
|
|
452
448
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-switchman",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.5",
|
|
4
4
|
"description": "Autonomous Agent Teams doctrine for the four shipped DeepSeek Harness presets, plus language preferences, dispatch pools with model ranking, and context watermark control.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|