dsh-autotier 0.1.0 → 0.2.0
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/AGENTS.md +26 -3
- package/CHANGELOG.md +59 -0
- package/README.es.md +6 -2
- package/README.hi.md +7 -2
- package/README.md +7 -2
- package/README.pt.md +6 -2
- package/README.zh.md +6 -2
- package/THIRD_PARTY_NOTICES.md +31 -0
- package/docs/roadmap-v0.2.md +114 -0
- package/lib/client.js +5956 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +274 -58
- package/lib/typert.host.js +26 -0
- package/lib/types/client/TierPill.d.ts +24 -0
- package/lib/types/client/TierPill.d.ts.map +1 -0
- package/lib/types/client/TierSettingsCard.d.ts +31 -0
- package/lib/types/client/TierSettingsCard.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +30 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/locales.d.ts +60 -0
- package/lib/types/client/locales.d.ts.map +1 -0
- package/lib/types/client/present.d.ts +61 -0
- package/lib/types/client/present.d.ts.map +1 -0
- package/lib/types/client/remote.d.ts +313 -0
- package/lib/types/client/remote.d.ts.map +1 -0
- package/lib/types/client/styles.d.ts +12 -0
- package/lib/types/client/styles.d.ts.map +1 -0
- package/lib/types/command.d.ts.map +1 -1
- package/lib/types/index.d.ts +4 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/policy.d.ts +4 -0
- package/lib/types/policy.d.ts.map +1 -1
- package/lib/types/preflight.d.ts +48 -0
- package/lib/types/preflight.d.ts.map +1 -0
- package/lib/types/routing.d.ts +2 -0
- package/lib/types/routing.d.ts.map +1 -1
- package/lib/types/selection.d.ts +50 -0
- package/lib/types/selection.d.ts.map +1 -0
- package/lib/types/tier-remote.d.ts +79 -0
- package/lib/types/tier-remote.d.ts.map +1 -0
- package/lib/types/typert.host.d.ts +300 -0
- package/lib/types/typert.host.d.ts.map +1 -0
- package/lib/types/wire.d.ts +804 -0
- package/lib/types/wire.d.ts.map +1 -0
- package/lib/wire-BpKSOHgo.js +5193 -0
- package/package.json +63 -11
- package/src/client/TierPill.tsx +83 -0
- package/src/client/TierSettingsCard.tsx +175 -0
- package/src/client/index.ts +146 -0
- package/src/client/locales.ts +107 -0
- package/src/client/present.ts +124 -0
- package/src/client/remote.ts +39 -0
- package/src/client/styles.ts +174 -0
- package/src/command.ts +1 -0
- package/src/index.ts +43 -0
- package/src/policy.ts +6 -0
- package/src/preflight.ts +105 -0
- package/src/routing.ts +28 -1
- package/src/selection.ts +124 -0
- package/src/tier-remote.ts +139 -0
- package/src/typert.host.ts +25 -0
- package/src/wire.ts +248 -0
package/AGENTS.md
CHANGED
|
@@ -21,9 +21,28 @@ records repo-local decisions.
|
|
|
21
21
|
- `src/service.ts` — `ctx.autotier` (`status()` and the live settings scope).
|
|
22
22
|
- `src/types.ts` — shared vocabulary (tier ids, effort ids, routing modes,
|
|
23
23
|
scenarios, route/status shapes).
|
|
24
|
+
- `src/wire.ts` — the `tier` Remote wire vocabulary: `TierStatus` (the public
|
|
25
|
+
`AutotierStatus` plus an additive `session` view), `TierCatalog`, their zod v4
|
|
26
|
+
codecs, and the three invocation descriptors shared verbatim by the host
|
|
27
|
+
manifest and the client contribution.
|
|
28
|
+
- `src/typert.host.ts` — the hand-written host Typert manifest exported as
|
|
29
|
+
`./typert`; the harness's typert-loader registers the `tier` invocations from
|
|
30
|
+
it when the plugin mounts.
|
|
31
|
+
- `src/tier-remote.ts` — `TierRemoteService` (`TypertRemoteService`, namespace
|
|
32
|
+
`tier`): `status(agentId?)` / `catalog()` / `setMode(mode, agentId?)`. The
|
|
33
|
+
override it writes is the same per-agent `RouteState.override` the router and
|
|
34
|
+
`/tier` read; `agents` is read optionally through the injected resolver.
|
|
35
|
+
- `src/client/` — browser half: `$mount`s the Remote contribution, registers the
|
|
36
|
+
composer pill into `conversation.input.left` (id `tier-pill`) and the Settings
|
|
37
|
+
card into `settings.plugins.tab` (id `autotier`), with a pure presenter
|
|
38
|
+
(`present.ts`), inline scoped stylesheet (`styles.ts`), and en/zh dictionaries
|
|
39
|
+
(`locales.ts`). The slot registry is read through a local structural
|
|
40
|
+
`SlotsFace` (its owning package differs across host lines).
|
|
24
41
|
- `tests/` — vitest over the REAL published `0.1.2-rc.1` host packages
|
|
25
42
|
(`Context`, `SessionStore`, `SystemPrompt`, `ToolRuntime`, `CommandRuntime`,
|
|
26
|
-
in-memory `SettingsProvider`) plus one real Loader composition.
|
|
43
|
+
in-memory `SettingsProvider`) plus one real Loader composition. The browser
|
|
44
|
+
half is covered through its pure units (wire codecs, presenter, dictionaries)
|
|
45
|
+
and the `tier` service through a real mount with a scripted `agents` face.
|
|
27
46
|
|
|
28
47
|
## Hard rules applied here
|
|
29
48
|
|
|
@@ -63,8 +82,12 @@ table.
|
|
|
63
82
|
`typescript` + `tsdown` are regular `dependencies` (the git channel's `prepare`
|
|
64
83
|
builds with production dependencies alone). `scripts/prepare.mjs` wipes `lib/`,
|
|
65
84
|
emits tsc declarations into `lib/types`, then runs tsdown (tsdown `clean` stays
|
|
66
|
-
OFF so the declarations survive).
|
|
67
|
-
`
|
|
85
|
+
OFF so the declarations survive). Two build faces: the node half
|
|
86
|
+
(`lib/index.js` + `lib/typert.host.js`) and the browser half (`lib/client.js`),
|
|
87
|
+
whose CJS factory is wrapped in `window.__ModuleLoader__.load({ id, factory })`
|
|
88
|
+
with the shell's platform modules (`react`, `react/jsx-runtime`, the
|
|
89
|
+
`@deepseek-ai/dsh-client-*` singletons) left external and zod inlined.
|
|
90
|
+
`pnpm-workspace.yaml` declares `allowBuilds: { esbuild: true }`.
|
|
68
91
|
|
|
69
92
|
## Checks
|
|
70
93
|
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,65 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.0] - 2026-09-09
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Browser half: a Settings card and a composer tier pill.** The plugin now
|
|
13
|
+
ships a `tier` Typert Remote service (`tier/status`, `tier/catalog`,
|
|
14
|
+
`tier/setMode`) behind a hand-written `./typert` host manifest, and a client
|
|
15
|
+
bundle that registers the composer pill into `conversation.input.left`
|
|
16
|
+
(id `tier-pill`) and the autotier card into the Plugins settings section
|
|
17
|
+
(`settings.plugins.tab`, id `autotier`). The pill shows the session's effective
|
|
18
|
+
mode (`AUTO` / `STRONG` / `CHEAP` / `OFF`) with an escalation badge and cycles
|
|
19
|
+
the session override on click; the card offers the full
|
|
20
|
+
`auto | strong | cheap | delegated | off` selector, the read-only tier
|
|
21
|
+
landings, the live session state, and a model-catalog dropdown fed by the live
|
|
22
|
+
`ctx.llm` registry. Copy ships in English and Simplified Chinese.
|
|
23
|
+
- `TierStatus` extends the public `AutotierStatus` additively with a `session`
|
|
24
|
+
view (override, effective mode, applied tier and source, escalation, plan
|
|
25
|
+
mode, guard denials); the host still serves `ctx.autotier.status()` unchanged.
|
|
26
|
+
- `zod` is now a runtime dependency (the strict wire codecs on both faces) and
|
|
27
|
+
the client peers (`dsh-api-remotes`, `dsh-client-connection`,
|
|
28
|
+
`dsh-client-locale`, `dsh-client-ui-conversation`, `dsh-client-ui-settings`,
|
|
29
|
+
`dsh-client-ui-slots`, `dsh-typert-protocol`) are declared as optional peers.
|
|
30
|
+
|
|
31
|
+
### Notes
|
|
32
|
+
|
|
33
|
+
- The session override stays runtime-only: `auto` clears it, and a plugin reload
|
|
34
|
+
restores the `cordis.yml` routing mode. Nothing is persisted.
|
|
35
|
+
- `pnpm run verify:artifacts` now asserts the two new shipped faces
|
|
36
|
+
(`lib/typert.host.js` with its manifest shape, `lib/client.js` with its
|
|
37
|
+
ModuleLoader handshake and external platform modules).
|
|
38
|
+
- The five-language READMEs are not updated in this change; the client copy is
|
|
39
|
+
English + Simplified Chinese only.
|
|
40
|
+
|
|
41
|
+
## [0.1.1] - 2026-09-09
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- **Route pre-flight against the live registry.** Before a tier landing is
|
|
46
|
+
written into the request configuration, the plugin now checks the two facts
|
|
47
|
+
that would fail the request outright: the provider route must be registered,
|
|
48
|
+
and the target model must declare the configured reasoning effort. An
|
|
49
|
+
unregistered provider redirects to a registered fallback chain entry; an
|
|
50
|
+
unsupported effort is dropped so the adapter default applies; an adapter that
|
|
51
|
+
cannot answer is treated leniently. Both answers are cached per
|
|
52
|
+
`provider/model`, and each degradation is logged once.
|
|
53
|
+
- Compat workflow now runs its profile job over a matrix of both published
|
|
54
|
+
harness lines (`0.1.2-rc.1` and `0.1.5-alpha.1`), so drift in either is caught
|
|
55
|
+
automatically.
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- Peer ranges name both published lines explicitly
|
|
60
|
+
(`>=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0`): a semver range whose only
|
|
61
|
+
prerelease comparator sits on an earlier version tuple does not admit a later
|
|
62
|
+
alpha, so the previous range left `0.1.5-alpha.1` unsatisfied.
|
|
63
|
+
- `dsh.compatibility.dshReleases` and the five READMEs now declare
|
|
64
|
+
`0.1.5-alpha.1` compatible after an end-to-end verification (real profile
|
|
65
|
+
install, `--dump-config` row, keyless headless smoke).
|
|
66
|
+
|
|
8
67
|
## [0.1.0] - 2026-09-09
|
|
9
68
|
|
|
10
69
|
### Added
|
package/README.es.md
CHANGED
|
@@ -19,10 +19,14 @@ strong con un TTL de retorno.
|
|
|
19
19
|
|
|
20
20
|
| Harness | Estado |
|
|
21
21
|
|---|---|
|
|
22
|
-
| `@deepseek-ai/dsh` `0.1.2-rc.1` | compatible
|
|
23
|
-
| `0.1.5-alpha.1`
|
|
22
|
+
| `@deepseek-ai/dsh` `0.1.2-rc.1` | compatible; el flujo compat instala esta línea de extremo a extremo |
|
|
23
|
+
| `@deepseek-ai/dsh` `0.1.5-alpha.1` | compatible; verificada de extremo a extremo (perfil real, fila en `--dump-config`, smoke keyless) y en la matriz compat |
|
|
24
24
|
| `@deepseek-ai/cordis` `^4.0.2`, `@deepseek-ai/schemastery` `^3.18.2` | base de peers |
|
|
25
25
|
|
|
26
|
+
Los rangos de peers nombran ambas líneas publicadas (`>=0.1.2-rc.1 <0.2.0 ||
|
|
27
|
+
>=0.1.5-alpha.1 <0.2.0`), porque un rango cuyo único comparador de prerelease
|
|
28
|
+
está en una tupla anterior no admite un alpha posterior. Se refrescan por ola.
|
|
29
|
+
|
|
26
30
|
El plugin vive solo en el plano host y no necesita un preset propio: la fila host
|
|
27
31
|
se aplica a todas las sesiones. Una sección de prompt en *tu* preset es opcional
|
|
28
32
|
y solo hace visibles las decisiones al modelo (véase [Instalación y desinstalación](#instalación-y-desinstalación)).
|
package/README.hi.md
CHANGED
|
@@ -17,10 +17,15 @@ DeepSeek Harness के लिए स्वचालित मॉडल-स्
|
|
|
17
17
|
|
|
18
18
|
| Harness | स्थिति |
|
|
19
19
|
|---|---|
|
|
20
|
-
| `@deepseek-ai/dsh` `0.1.2-rc.1` |
|
|
21
|
-
| `0.1.5-alpha.1`
|
|
20
|
+
| `@deepseek-ai/dsh` `0.1.2-rc.1` | संगत; compat वर्कफ़्लो इस लाइन को end-to-end इंस्टॉल करता है |
|
|
21
|
+
| `@deepseek-ai/dsh` `0.1.5-alpha.1` | संगत; end-to-end सत्यापित (वास्तविक profile, `--dump-config` पंक्ति, keyless smoke) और compat मैट्रिक्स में |
|
|
22
22
|
| `@deepseek-ai/cordis` `^4.0.2`, `@deepseek-ai/schemastery` `^3.18.2` | peer आधार |
|
|
23
23
|
|
|
24
|
+
peer ranges दोनों प्रकाशित लाइनें स्पष्ट रूप से लिखती हैं (`>=0.1.2-rc.1 <0.2.0
|
|
25
|
+
|| >=0.1.5-alpha.1 <0.2.0`), क्योंकि जिस range का एकमात्र prerelease comparator
|
|
26
|
+
पुराने tuple पर हो वह बाद के alpha को स्वीकार नहीं करता। हर प्रकाशन-लहर पर
|
|
27
|
+
रिफ़्रेश होता है।
|
|
28
|
+
|
|
24
29
|
यह प्लगइन केवल host plane पर रहता है और अपना preset नहीं माँगता: host पंक्ति
|
|
25
30
|
हर सत्र पर लागू होती है। *आपके* preset में एक प्रॉम्प्ट खंड वैकल्पिक है और
|
|
26
31
|
केवल मॉडल को निर्णय दिखाता है ([इंस्टॉल और अनइंस्टॉल](#इंस्टॉल-और-अनइंस्टॉल) देखें)।
|
package/README.md
CHANGED
|
@@ -17,10 +17,15 @@ escalate to the strong tier with a TTL fallback.
|
|
|
17
17
|
|
|
18
18
|
| Harness | Status |
|
|
19
19
|
|---|---|
|
|
20
|
-
| `@deepseek-ai/dsh` `0.1.2-rc.1` | compatible
|
|
21
|
-
| `0.1.5-alpha.1`
|
|
20
|
+
| `@deepseek-ai/dsh` `0.1.2-rc.1` | compatible; the compat workflow installs this line end-to-end |
|
|
21
|
+
| `@deepseek-ai/dsh` `0.1.5-alpha.1` | compatible; verified end-to-end (real profile install, `--dump-config` row, keyless headless smoke) and in the compat matrix |
|
|
22
22
|
| `@deepseek-ai/cordis` `^4.0.2`, `@deepseek-ai/schemastery` `^3.18.2` | peer baseline |
|
|
23
23
|
|
|
24
|
+
Peer ranges name both published lines explicitly (`>=0.1.2-rc.1 <0.2.0 ||
|
|
25
|
+
>=0.1.5-alpha.1 <0.2.0`), because a semver range whose only prerelease
|
|
26
|
+
comparator sits on an earlier version tuple does not admit a later alpha.
|
|
27
|
+
They are refreshed per published wave.
|
|
28
|
+
|
|
24
29
|
The plugin is host-plane only. It needs no agent preset of its own: the host
|
|
25
30
|
row applies to every session. A one-line prompt section in *your* preset is
|
|
26
31
|
optional and only makes the router's decisions visible to the model (see
|
package/README.pt.md
CHANGED
|
@@ -18,10 +18,14 @@ retorno.
|
|
|
18
18
|
|
|
19
19
|
| Harness | Estado |
|
|
20
20
|
|---|---|
|
|
21
|
-
| `@deepseek-ai/dsh` `0.1.2-rc.1` | compatível
|
|
22
|
-
| `0.1.5-alpha.1`
|
|
21
|
+
| `@deepseek-ai/dsh` `0.1.2-rc.1` | compatível; o fluxo compat instala esta linha ponta a ponta |
|
|
22
|
+
| `@deepseek-ai/dsh` `0.1.5-alpha.1` | compatível; verificada ponta a ponta (perfil real, linha no `--dump-config`, smoke keyless) e na matriz compat |
|
|
23
23
|
| `@deepseek-ai/cordis` `^4.0.2`, `@deepseek-ai/schemastery` `^3.18.2` | base de peers |
|
|
24
24
|
|
|
25
|
+
Os ranges de peers nomeiam as duas linhas publicadas (`>=0.1.2-rc.1 <0.2.0 ||
|
|
26
|
+
>=0.1.5-alpha.1 <0.2.0`), porque um range cujo único comparador de prerelease
|
|
27
|
+
está numa tupla anterior não admite um alpha posterior. São atualizados por onda.
|
|
28
|
+
|
|
25
29
|
O plugin vive apenas no plano host e não precisa de preset próprio: a linha host
|
|
26
30
|
vale para todas as sessões. Uma seção de prompt no *seu* preset é opcional e
|
|
27
31
|
apenas torna as decisões visíveis ao modelo (veja [Instalação e desinstalação](#instalação-e-desinstalação)).
|
package/README.zh.md
CHANGED
|
@@ -14,10 +14,14 @@ DeepSeek Harness 的自动模型分档路由:一条用户指令进来,一个
|
|
|
14
14
|
|
|
15
15
|
| Harness | 状态 |
|
|
16
16
|
|---|---|
|
|
17
|
-
| `@deepseek-ai/dsh` `0.1.2-rc.1` |
|
|
18
|
-
| `0.1.5-alpha.1
|
|
17
|
+
| `@deepseek-ai/dsh` `0.1.2-rc.1` | 兼容;compat 工作流对该线做端到端安装验证 |
|
|
18
|
+
| `@deepseek-ai/dsh` `0.1.5-alpha.1` | 兼容;已端到端实测(真实 profile 安装、`--dump-config` 行、keyless headless 冒烟)并纳入 compat 矩阵 |
|
|
19
19
|
| `@deepseek-ai/cordis` `^4.0.2`、`@deepseek-ai/schemastery` `^3.18.2` | peer 基线 |
|
|
20
20
|
|
|
21
|
+
peer 范围显式列出两条已发布线(`>=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1
|
|
22
|
+
<0.2.0`)——因为仅含较早版本元组预发布比较符的 semver 范围无法接纳更晚的 alpha;
|
|
23
|
+
每次发布波同步刷新。
|
|
24
|
+
|
|
21
25
|
本插件只驻留 host 平面,不需要自带 agent preset:host 行对所有会话生效。
|
|
22
26
|
在你的 preset 中加一段提示是可选项,仅用于让模型看见路由决策
|
|
23
27
|
(见[安装与卸载](#安装与卸载))。
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# Third-party notices
|
|
2
2
|
|
|
3
|
+
## zod (https://github.com/colinhacks/zod)
|
|
4
|
+
|
|
5
|
+
The `tier` Remote wire codecs (`src/wire.ts`) are zod v4 schemas. `zod` is a
|
|
6
|
+
declared runtime dependency (MIT) and its library code is inlined into the built
|
|
7
|
+
`lib/index.js`, `lib/typert.host.js` and `lib/client.js` bundles; no zod source
|
|
8
|
+
is modified.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
MIT License
|
|
12
|
+
|
|
13
|
+
Copyright (c) 2020 Colin McDonnell
|
|
14
|
+
|
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
17
|
+
in the Software without restriction, including without limitation the rights
|
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
20
|
+
furnished to do so, subject to the following conditions:
|
|
21
|
+
|
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
|
23
|
+
copies or substantial portions of the Software.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
|
32
|
+
```
|
|
33
|
+
|
|
3
34
|
## dsh-tier-router (`lib/pure.js`)
|
|
4
35
|
|
|
5
36
|
The high-risk command guard in `src/guard-rules.ts` is a port of the rule table
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# v0.2 roadmap: concrete designs for the deferred items
|
|
2
|
+
|
|
3
|
+
This file records the researched, decision-ready design for every capability
|
|
4
|
+
that is deliberately **not** in 0.1.x. Each entry states the goal, the exact
|
|
5
|
+
mechanism, the acceptance criteria, and why it is not enabled yet. Nothing here
|
|
6
|
+
is speculation: the seams named below were read in the harness checkout
|
|
7
|
+
(`dsh-v0.1.5-alpha.1-13`).
|
|
8
|
+
|
|
9
|
+
## 1. Browser half (Settings card + composer pill)
|
|
10
|
+
|
|
11
|
+
**Status:** implemented on the `v0.2.0` line (client bundle + Typert Remote
|
|
12
|
+
`tier/status|setMode|catalog`); see `src/client/`, `src/wire.ts`,
|
|
13
|
+
`src/typert.host.ts`.
|
|
14
|
+
|
|
15
|
+
**Why it was deferred:** the host surface was complete first (`ctx.autotier`),
|
|
16
|
+
and the client half needs the browser bundle pipeline (tsdown CJS face wrapped
|
|
17
|
+
in `window.__ModuleLoader__.load`), which is a packaging change rather than a
|
|
18
|
+
routing change.
|
|
19
|
+
|
|
20
|
+
## 2. Fingerprint posterior persistence
|
|
21
|
+
|
|
22
|
+
**Goal:** a restarted harness keeps the per-shape cheap/strong win rates instead
|
|
23
|
+
of re-learning from the judge's cold start.
|
|
24
|
+
|
|
25
|
+
**Mechanism (chosen):** a dedicated settings namespace, not the user-facing
|
|
26
|
+
`autotier` one:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
ctx.settings.register('autotier-fingerprints', FingerprintSchema, { applies: 'live' })
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- `FingerprintSchema` = `{ version: 1, entries: [{ key, cheapOK, cheapN, strongOK, strongN, observations, lastSeen }] }`, capped at the same LRU 2000.
|
|
33
|
+
- Writes are **debounced** (≥30 s between flushes and one final flush on
|
|
34
|
+
`ctx.effect` disposal) and use `replace()` on the whole section, so a user
|
|
35
|
+
editing the document cannot produce a partial merge.
|
|
36
|
+
- On mount, `PosteriorTable.hydrate(section)` validates and loads; a
|
|
37
|
+
`stateVersion`/`version` mismatch discards the section (the same rule the
|
|
38
|
+
session-projection cache uses).
|
|
39
|
+
- A namespace that is absent (a deployment without settings) degrades to the
|
|
40
|
+
current in-memory behaviour — the plugin never depends on persistence.
|
|
41
|
+
|
|
42
|
+
**Why not the `autotier` namespace:** it is user-facing; writing a large learned
|
|
43
|
+
table into it would surface in the Settings card and collide with the user's
|
|
44
|
+
revision on every flush. A separate namespace keeps the two concerns apart.
|
|
45
|
+
|
|
46
|
+
**Acceptance:** a unit test proving hydrate → record → flush → hydrate is
|
|
47
|
+
idempotent; an integration test proving a refused settings write leaves the
|
|
48
|
+
in-memory table intact.
|
|
49
|
+
|
|
50
|
+
**Why not enabled yet:** it adds a write path to a plugin whose current promise
|
|
51
|
+
is "writes only the `autotier` namespace", and the benefit only appears after a
|
|
52
|
+
long enough session history that the cold-start fallback has already paid for
|
|
53
|
+
itself. Ship it behind `persistence.fingerprints: false` default.
|
|
54
|
+
|
|
55
|
+
## 3. Attempt-first middle band (default on)
|
|
56
|
+
|
|
57
|
+
**Goal:** start ambiguous turns on the cheap tier and escalate on a signal,
|
|
58
|
+
which the cascade literature shows is cheaper *and* faster than deciding up
|
|
59
|
+
front.
|
|
60
|
+
|
|
61
|
+
**What is missing is calibration, not code:** the band, its `tauLow`, the
|
|
62
|
+
verify-once review, and the effort-first ladder are implemented and tested; the
|
|
63
|
+
shipped default is `intent.attemptBand.enabled: false` because the thresholds
|
|
64
|
+
have never been measured on real traffic.
|
|
65
|
+
|
|
66
|
+
**Mechanism:** `scripts/calibrate.mjs` + a 90-case labelled corpus:
|
|
67
|
+
|
|
68
|
+
- Corpus: `fixtures/intent-corpus.jsonl`, one `{ text, expectedTier, hard }` per
|
|
69
|
+
line, balanced across the eight scenarios (11–12 each) plus 10 adversarial
|
|
70
|
+
"looks simple, is complex" cases.
|
|
71
|
+
- The script replays the corpus through the *shipped* classifier (no LLM), then
|
|
72
|
+
sweeps `ruleThreshold`/`tauLow` and prints a table of PGR, APGR, CPT(50 %),
|
|
73
|
+
CPT(80 %), strong-call % and rule-layer hit rate — the same metrics RouteLLM's
|
|
74
|
+
`calibrate_threshold` reports.
|
|
75
|
+
- CI gate (a vitest suite over the same corpus): **CPT(80 %) ≤ 40 %**,
|
|
76
|
+
**APGR ≥ 0.7**, routing quality ≥ 95 % of an always-strong oracle, rule-layer
|
|
77
|
+
zero-token hit ≥ 60 %.
|
|
78
|
+
- Only when the gate is green does the shipped default flip to
|
|
79
|
+
`attemptBand.enabled: true`.
|
|
80
|
+
|
|
81
|
+
**Why not enabled yet:** enabling an uncalibrated band would spend strong calls
|
|
82
|
+
on turns the rules already classify correctly, which is exactly the cost the
|
|
83
|
+
plugin exists to avoid.
|
|
84
|
+
|
|
85
|
+
## 4. Long-context lane
|
|
86
|
+
|
|
87
|
+
**Goal:** route very long sessions (est. tokens ≥ 30 k) to a model whose context
|
|
88
|
+
window actually fits, instead of failing or compacting mid-turn.
|
|
89
|
+
|
|
90
|
+
**Mechanism:** the same pre-flight module already answers "does this route
|
|
91
|
+
exist"; extend it with `ctx.llm.resolveModelInfo(...).context?.contextWindow`:
|
|
92
|
+
|
|
93
|
+
- When the assembled request's estimated tokens exceed the target route's
|
|
94
|
+
`contextWindow`, pick the first fallback entry (or the other tier) whose
|
|
95
|
+
window fits, and log the substitution once.
|
|
96
|
+
- If nothing fits, leave the route alone — compaction owns that case, and a
|
|
97
|
+
router must not silently drop the user's context.
|
|
98
|
+
|
|
99
|
+
**Why not yet:** `LlmCallConfig` carries no message payload at the request
|
|
100
|
+
waterfall, so the estimate must come from the session's derived history; the
|
|
101
|
+
read is cheap but it is a new dependency on `session.deriveMessages()`, and the
|
|
102
|
+
harness's own compaction is the primary owner of this problem.
|
|
103
|
+
|
|
104
|
+
## 5. Multi-router coexistence
|
|
105
|
+
|
|
106
|
+
**Status:** implemented in 0.1.2 — a foreign `provider/model` at the request
|
|
107
|
+
waterfall is detected, logged once per session, and surfaced by `/tier status`
|
|
108
|
+
and `tier_status`.
|
|
109
|
+
|
|
110
|
+
## 6. Explicit user selection
|
|
111
|
+
|
|
112
|
+
**Status:** implemented in 0.1.2 — the applied tier is mirrored into the
|
|
113
|
+
`agent-default-model` document, and an external change to that document moves
|
|
114
|
+
every live session to `delegated` until `/tier auto`.
|