ytdb-slate 0.4.0 → 0.5.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/README.md +14 -4
- package/docs/context-budget.md +125 -0
- package/docs/design-principles.md +59 -4
- package/docs/model-routing.md +553 -0
- package/extension/base-model.ts +545 -0
- package/extension/episodes.ts +387 -31
- package/extension/failover.ts +26 -16
- package/extension/handoff.ts +43 -3
- package/extension/index.ts +113 -11
- package/extension/mode.ts +277 -5
- package/extension/model-profiles.ts +812 -0
- package/extension/model-router.ts +858 -0
- package/extension/paths.ts +1 -0
- package/extension/render.ts +20 -1
- package/extension/route.ts +1185 -0
- package/extension/state.ts +450 -5
- package/extension/threads.ts +808 -50
- package/extension/tools.ts +80 -16
- package/extension/worker.ts +10 -4
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Slate is a thread-weaving orchestration extension for the [pi coding agent](https://pi.dev).
|
|
4
4
|
|
|
5
|
-
The orchestrator (your main pi session) dispatches **bounded actions** to persistent **worker threads**. Each completed action is compressed by an LLM into an **episode** — a durable, structured record (intent, actions, findings, artifacts, open issues, handoff notes) that the orchestrator composes into further dispatches instead of re-reading raw transcripts. On top of that, Slate injects a mandatory workflow doctrine: research before design, design review, adversarial review, and track review — with optional umbrella **draft-PR publishing** for tracks. An opt-in **model-failover** map adds high availability: when a model API fails, the orchestrator, worker threads, and episode compression each retry once on a configured equal-quality alternative.
|
|
5
|
+
The orchestrator (your main pi session) dispatches **bounded actions** to persistent **worker threads**. Each completed action is compressed by an LLM into an **episode** — a durable, structured record (intent, actions, findings, artifacts, open issues, handoff notes) that the orchestrator composes into further dispatches instead of re-reading raw transcripts. On top of that, Slate injects a mandatory workflow doctrine: research before design, design review, adversarial review, and track review — with optional umbrella **draft-PR publishing** for tracks. An opt-in **model-failover** map adds high availability: when a model API fails, the orchestrator, worker threads, and episode compression each retry once on a configured equal-quality alternative. A second opt-in, **action-level model routing**, gives each dispatched action a model and an effort level chosen to be up to the task and no more, so cost is bounded per action instead of per session.
|
|
6
6
|
|
|
7
7
|
## Why Slate?
|
|
8
8
|
|
|
@@ -51,6 +51,12 @@ This summary is orientation only; the shipped docs listed below are normative.
|
|
|
51
51
|
|
|
52
52
|
Slate can ride through model API outages. The opt-in `modelFailover` map in `.pi/slate.json` (trusted projects only) maps a model (`provider/id`) to an equal-quality alternative; on an eligible model API failure — not an abort or a context overflow, and for the orchestrator and worker sites only after pi's own retries are exhausted — the affected site (orchestrator, worker thread, or episode compression) retries once on the mapped model (single hop, never chained). An orchestrator failover — like the handoff adoption that re-applies a parent session's model — would otherwise leave pi's global model defaults changed, so Slate restores them on a best-effort basis unless `preserveGlobalModelDefault` is `false`. The map is empty by default (feature off) and read once at session start. Full semantics: the `modelFailover` row in [Configuration](#configuration) and the shipped [`docs/model-failover.md`](docs/model-failover.md) — if they disagree, that document wins.
|
|
53
53
|
|
|
54
|
+
## Action-level model routing
|
|
55
|
+
|
|
56
|
+
Slate can pick the model and the effort level per dispatched action rather than running every action on whatever model the orchestrator happens to be on. `router.models` in `.pi/slate.json` (trusted projects only) is a closed list of `provider/id` specs; a dispatch then runs on the `model` and `effort` arguments of that action, else on the thread's own base model and a level DERIVED for the model that actually runs — the lowest level that model has a capability measurement at, never a fixed default. The list is empty by default, and empty means off: no list is enforced, nothing is seeded, and model selection is exactly what it was before the router existed. Only models Slate ships a benchmark profile for can be routed to; entries pi cannot serve, or has no profile for, are dropped with a warning naming them.
|
|
57
|
+
|
|
58
|
+
What the code enforces is deliberately narrower than what the routing data advises. The dispatch guards refuse an unlisted model, a level off the target model's ladder and a level the provider rejects outright; they warn about — and mark — an unmeasured level, refusing it only when `router.allowUnmeasuredEffort` is `false`; and the context-window guard substitutes a wider listed model instead of ever blocking an action. The obligations that come from the profile data itself — keeping review and gate actions on measured levels, and honoring a REFUSE such as `anthropic/claude-fable-5`'s for zero-data-retention work — are stated in the doctrine for the orchestrator to honor; they are **not** code-enforced guards. Full semantics: the `router.*` rows in [Configuration](#configuration) and the shipped [`docs/model-routing.md`](docs/model-routing.md) — if they disagree, that document wins.
|
|
59
|
+
|
|
54
60
|
## Install
|
|
55
61
|
|
|
56
62
|
Install into a project (pinned, project-scoped — recorded in `.pi/settings.json`):
|
|
@@ -68,7 +74,7 @@ Optional config file: `slate.json` in the project's pi config dir (`.pi/slate.js
|
|
|
68
74
|
| Key | Type | Default | Semantics |
|
|
69
75
|
| --- | --- | --- | --- |
|
|
70
76
|
| `orchestratorModeDefault` | boolean | `false` | Start fresh interactive sessions with orchestrator mode ON. |
|
|
71
|
-
| `episodeModel` | string | newest available Anthropic Sonnet, else the
|
|
77
|
+
| `episodeModel` | string | newest available Anthropic Sonnet, else the orchestrator's own base model | Model (`provider/id`) used to compress a finished action into an episode. Never the model an action was routed to: an episode is read by every later consumer of the thread, so one cheap route must not degrade the record. An unusable value is reported and the default is used. |
|
|
72
78
|
| `workerTools` | string[] | `["read", "bash", "edit", "write", "grep", "find", "ls"]` | Tools available to worker threads (an empty list also falls back to the default). |
|
|
73
79
|
| `workerExtensions` | string[] | `[]` | Regex patterns (matched **unanchored**) selecting which of the host session's already-loaded extensions also load into every worker thread; each matched extension's tools are added **on top of** `workerTools`. Empty (default) means workers load no extensions. The orchestrator keeps its restricted tool set but its doctrine is told what was whitelisted. Invalid patterns are dropped with a warning at session start. |
|
|
74
80
|
| `maxConcurrent` | number | `4` | Maximum number of worker actions running concurrently (must be ≥ 1 — unenforced: a value of 0 or less silently hangs all dispatches). Excess dispatches wait in a queue; actions on the same thread always run in dispatch order. Default rationale: shipped `docs/design-principles.md` §5 (repo-local note). |
|
|
@@ -80,6 +86,8 @@ Optional config file: `slate.json` in the project's pi config dir (`.pi/slate.js
|
|
|
80
86
|
| `reviewPerspectivesPath` | string | — | Project review charters, each declaring its own finding-ID prefix. The doctrine references this **path**; the orchestrator reads the file alongside the shipped review rules. |
|
|
81
87
|
| `modelFailover` | object (string → string) | — (empty, failover off) | Map of `provider/id` → equal-quality alternative model; on a model API failure the affected site retries once on the mapped model (worker/orchestrator sites only after pi's own retries are exhausted; episode compression has no pi retry loop). Read once at session start — see [`docs/model-failover.md`](docs/model-failover.md). |
|
|
82
88
|
| `preserveGlobalModelDefault` | boolean | `true` | Put pi's global model defaults (`defaultProvider`, `defaultModel`, `defaultThinkingLevel`) back after a Slate-initiated model switch — orchestrator failover and handoff adoption — so the switch stays session-scoped. `false` turns that restore off at both sites (the switches themselves are unaffected), leaving each one persisted in pi's global settings. Best-effort: Slate reverts only a value its own switch produced, and can stand down or give up — limits in [`docs/model-failover.md`](docs/model-failover.md). |
|
|
89
|
+
| `router.models` | string[] | `[]` (empty — routing off) | Closed list of models (`provider/id`) an action may be routed to. **Empty or absent means the router is OFF and dispatch behaves exactly as it did before the router existed** — no model list is enforced and no thread gets a seeded base model. A listed model becomes routable only where four things intersect: your list, a benchmark profile Slate ships for that model, pi's model registry, and credentials pi actually has configured; anything that fails one of those is dropped with a warning naming it (if every entry drops, routing turns off with one summary warning). Read once at session start and resolved once per session — see [`docs/model-routing.md`](docs/model-routing.md). |
|
|
90
|
+
| `router.allowUnmeasuredEffort` | boolean | `true` | What happens when an explicitly requested effort level is on the target model's ladder but has no capability measurement in Slate's profiles: `true` dispatches it with a ⚠ notice and marks the episode `(unmeasured level)`; `false` refuses the dispatch. Either way a level that is off the model's ladder, or one the provider rejects outright, is refused, and a level Slate DERIVES for an action is always a measured one. |
|
|
83
91
|
|
|
84
92
|
Example `.pi/slate.json` (the `docs/agents/...` paths are placeholders — point them at markdown files that actually exist in **your** project):
|
|
85
93
|
|
|
@@ -93,7 +101,8 @@ Example `.pi/slate.json` (the `docs/agents/...` paths are placeholders — point
|
|
|
93
101
|
"workflow": { "draftPRs": true },
|
|
94
102
|
"doctrineExtraPath": "docs/agents/workflow-additions.md",
|
|
95
103
|
"reviewPerspectivesPath": "docs/agents/review-perspectives.md",
|
|
96
|
-
"modelFailover": { "anthropic/claude-sonnet-5": "openai/gpt-5.2" }
|
|
104
|
+
"modelFailover": { "anthropic/claude-sonnet-5": "openai/gpt-5.2" },
|
|
105
|
+
"router": { "models": ["openai/gpt-5.6-luna", "anthropic/claude-opus-5"] }
|
|
97
106
|
}
|
|
98
107
|
```
|
|
99
108
|
|
|
@@ -126,7 +135,7 @@ Slate reads project configuration (`.pi/slate.json`) and injects project files (
|
|
|
126
135
|
|
|
127
136
|
## Shipped docs
|
|
128
137
|
|
|
129
|
-
In orchestrator mode, Slate appends a short **doctrine** (a block of numbered rules) to the orchestrator's system prompt each turn. The doctrine does not embed the workflow docs — it cites them by **absolute path**, resolved inside the installed package (not your project), and the orchestrator reads them on demand:
|
|
138
|
+
In orchestrator mode, Slate appends a short **doctrine** (a block of numbered rules) to the orchestrator's system prompt each turn. The doctrine does not embed the workflow docs — it cites them by **absolute path**, resolved inside the installed package (not your project), and the orchestrator reads them on demand. Those embedded paths are also why the block's character count depends on your install location; [`docs/context-budget.md`](docs/context-budget.md) has the measured sizes, with and without the optional rules, and the arithmetic for your own install:
|
|
130
139
|
|
|
131
140
|
- `docs/track-workflow.md` — the track-based workflow (research → design review → adversarial review → track review)
|
|
132
141
|
- `docs/pr-publishing.md` — umbrella draft-PR publishing (cited only when `workflow.draftPRs` is `true`)
|
|
@@ -134,6 +143,7 @@ In orchestrator mode, Slate appends a short **doctrine** (a block of numbered ru
|
|
|
134
143
|
- `docs/design-principles.md` — Slate's own design rationale
|
|
135
144
|
- `docs/model-failover.md` — the opt-in `modelFailover` map (**reference documentation** — unlike the entries above it is not workflow doctrine and is not cited by the doctrine)
|
|
136
145
|
- `docs/context-budget.md` — the orchestrator `contextBudget`: defaults, per-model overrides, the window clamp, and the pricing rationale (also **reference documentation**, not cited by the doctrine)
|
|
146
|
+
- `docs/model-routing.md` — action-level model routing: the two `router` keys, how a model becomes routable, how an omitted effort level resolves, the dispatch guards, and the warnings a first routed session emits. Unlike the two entries above it **is** cited by the doctrine, by absolute path, but only while the routing rule renders — it is the extra embedded path that appears with the rule, the fourth normally and the fifth when `workflow.draftPRs` is also on, which the size arithmetic in `docs/context-budget.md` accounts for. The routable model list itself is never read from this file: the rule renders it live from the session's own resolution, because that set depends on your registry and credentials.
|
|
137
147
|
|
|
138
148
|
Project-specific additions layer on top — they extend, not replace, the shipped doctrine — via two distinct mechanisms:
|
|
139
149
|
|
package/docs/context-budget.md
CHANGED
|
@@ -118,6 +118,114 @@ paused, threshold compactions pass through as an escape valve.
|
|
|
118
118
|
Overflow-recovery compaction and manual `/compact` are never
|
|
119
119
|
touched.
|
|
120
120
|
|
|
121
|
+
## What the always-loaded doctrine costs the budget
|
|
122
|
+
|
|
123
|
+
The budget's denominator includes Slate's own always-loaded block.
|
|
124
|
+
While orchestrator mode is on, the doctrine sits in the
|
|
125
|
+
orchestrator's system prompt for the whole session — and, like the
|
|
126
|
+
rest of the conversation (see the pricing cliff above), it is sent
|
|
127
|
+
again with every request. It occupies its space in the window once;
|
|
128
|
+
you pay its input tokens every turn.
|
|
129
|
+
|
|
130
|
+
**Its size depends on where the package is installed.** That is not
|
|
131
|
+
obvious, and it catches anyone who measures: the doctrine cites the
|
|
132
|
+
shipped docs by ABSOLUTE path, so three to five full filesystem
|
|
133
|
+
paths are embedded in the block — three at minimum
|
|
134
|
+
(`track-workflow.md`, `review-rules.md`, `design-principles.md`),
|
|
135
|
+
plus `pr-publishing.md` when `workflow.draftPRs` is on, plus
|
|
136
|
+
`model-routing.md` when the routing rule renders. Every additional
|
|
137
|
+
character in the installed `docs/` directory therefore costs 3–5
|
|
138
|
+
characters of doctrine.
|
|
139
|
+
|
|
140
|
+
So the figures below are **portable characters**, defined exactly as
|
|
141
|
+
Slate's own automated size check defines them: the block with each
|
|
142
|
+
occurrence of the installed `docs/` DIRECTORY removed, keeping the
|
|
143
|
+
filename. That makes them install-invariant by construction —
|
|
144
|
+
verified by measuring at a 12-character docs path and at this repo's
|
|
145
|
+
58-character one, which give identical portable counts — and it
|
|
146
|
+
makes the arithmetic one multiplication:
|
|
147
|
+
|
|
148
|
+
> rendered characters = portable + (embedded paths × length of your
|
|
149
|
+
> installed `docs/` directory)
|
|
150
|
+
|
|
151
|
+
Every row below states its full basis, because router state, model
|
|
152
|
+
count and `draftPRs` each move the number:
|
|
153
|
+
|
|
154
|
+
| router | models | `draftPRs` | paths | portable | lines | rendered at a 58-char docs dir |
|
|
155
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
156
|
+
| off | — | off | 3 | 1,929 | 38 | 2,103 |
|
|
157
|
+
| off | — | on | 4 | 1,948 | 38 | 2,180 |
|
|
158
|
+
| on | 6 configured | off | 4 | 3,870 | 58 | 4,102 |
|
|
159
|
+
| on | 6 configured | on | 5 | 3,889 | 58 | 4,179 |
|
|
160
|
+
| on | all 9 shipped | off | 4 | 4,448 | 61 | 4,680 |
|
|
161
|
+
| on | all 9 shipped | on | 5 | 4,467 | 61 | 4,757 |
|
|
162
|
+
|
|
163
|
+
An untrusted project reads the first row whatever its `slate.json`
|
|
164
|
+
says: no project config is loaded, so neither optional rule renders.
|
|
165
|
+
Line counts do not vary with the install path. Enabling `draftPRs`
|
|
166
|
+
costs 19 portable characters plus one more embedded path.
|
|
167
|
+
|
|
168
|
+
Two parts of the block grow with configuration rather than with the
|
|
169
|
+
path:
|
|
170
|
+
|
|
171
|
+
- The routing rule is a live table with ONE ROW PER ROUTABLE MODEL,
|
|
172
|
+
so what renders is the models you CONFIGURE — not the nine Slate
|
|
173
|
+
ships profiles for. It is 1,941 portable characters / 20 lines for
|
|
174
|
+
six configured models and 2,519 / 23 for all nine. A model ROW
|
|
175
|
+
costs 154–186 characters; the legend adds a one-off clause per
|
|
176
|
+
marker it has to explain, so listing the first cheap-tier model
|
|
177
|
+
costs ~50 characters more than its row (two new clauses). That is
|
|
178
|
+
why stepping from six to nine averages 193 per model where the
|
|
179
|
+
first six average 171.
|
|
180
|
+
- The worker-extension rule grows per whitelisted extension and per
|
|
181
|
+
tool that extension contributes, so it has no fixed size; one
|
|
182
|
+
extension contributing two tools measured 373 portable characters
|
|
183
|
+
/ 7 lines.
|
|
184
|
+
|
|
185
|
+
Against a 256,000-token budget none of this is material — as a rough
|
|
186
|
+
estimate, at 4 characters per token (no tokenizer was run, and the
|
|
187
|
+
table is denser than prose, so treat it as a floor) the whole block
|
|
188
|
+
is ≈480–525 tokens with both optional rules off and ≈970–1,025 with
|
|
189
|
+
six models routed, each range spanning portable to as-rendered-here.
|
|
190
|
+
That is under half a percent of the default budget, though it is
|
|
191
|
+
re-sent on every request rather than paid once. It is listed here
|
|
192
|
+
because it is context Slate itself puts in front of the model on
|
|
193
|
+
every turn, and because it is the number to check before assuming
|
|
194
|
+
the budget's headroom is all conversation.
|
|
195
|
+
|
|
196
|
+
## Worker threads: the routing window guard
|
|
197
|
+
|
|
198
|
+
The budget above is the ORCHESTRATOR's. Worker threads have no
|
|
199
|
+
budget and never pause; with action-level routing on, they get a
|
|
200
|
+
weaker but automatic counterpart. Before each dispatch — whenever
|
|
201
|
+
the thread's context size is knowable, so not for a thread whose
|
|
202
|
+
worker session has not been opened yet — the routed model's
|
|
203
|
+
REGISTRY context window is checked against that size using pi's OWN
|
|
204
|
+
compaction settings, the same settings whose `reserveTokens` clamps
|
|
205
|
+
the budget above. (The check runs even if you disabled
|
|
206
|
+
auto-compaction: turning compaction off does not make an
|
|
207
|
+
over-window dispatch safe, it only turns the compaction into an
|
|
208
|
+
overflow error.) If the thread no longer fits, the action is moved
|
|
209
|
+
to the widest listed model when that one is strictly wider, with a
|
|
210
|
+
warning; if nothing listed is wider it runs anyway and pi compacts.
|
|
211
|
+
The guard never blocks a dispatch and never pauses a thread.
|
|
212
|
+
|
|
213
|
+
Two consequences for this document's subject:
|
|
214
|
+
|
|
215
|
+
- The registry window is what decides the substitution, so the
|
|
216
|
+
overrides in the next section change worker routing too: raising
|
|
217
|
+
`gpt-5.6-*` to 1,050,000 makes those models genuinely wide
|
|
218
|
+
candidates rather than 272K ones.
|
|
219
|
+
- A narrow model in `router.models` is not a hazard the way it would
|
|
220
|
+
be for the orchestrator — it is a model long threads get routed
|
|
221
|
+
AWAY from, paying the wider model's rate instead. That is not
|
|
222
|
+
silent: the substituted action carries a ⚠ notice naming both
|
|
223
|
+
models.
|
|
224
|
+
|
|
225
|
+
Routing itself — the two `router` keys, what makes a model routable,
|
|
226
|
+
how effort levels resolve and the full guard list — is documented in
|
|
227
|
+
`model-routing.md` in this directory.
|
|
228
|
+
|
|
121
229
|
## Using GPT-5.6's full 1.05M window
|
|
122
230
|
|
|
123
231
|
Two deliberate steps. First, raise the registry window in
|
|
@@ -155,6 +263,17 @@ dropped:
|
|
|
155
263
|
WARNING: beyond 272K total input every request bills at the
|
|
156
264
|
long-context rates listed above.
|
|
157
265
|
|
|
266
|
+
With action-level routing on, this override also settles a warning
|
|
267
|
+
you will otherwise see once per session for each configured
|
|
268
|
+
`gpt-5.6-*` model: Slate's own profile for those models records a
|
|
269
|
+
1,050,000-token window, pi's stock registry reports 272,000, and the
|
|
270
|
+
router reports that divergence without adjudicating it (routing uses
|
|
271
|
+
the registry figure). Raising the registry window removes the
|
|
272
|
+
disagreement at its source. Leaving it alone is equally valid — the
|
|
273
|
+
registry figure is the conservative one — and `model-routing.md`
|
|
274
|
+
explains why Slate does not silence the warning by editing its own
|
|
275
|
+
number.
|
|
276
|
+
|
|
158
277
|
## Accepted limitations
|
|
159
278
|
|
|
160
279
|
- On models with a 272K pricing tier and a larger registry window
|
|
@@ -174,3 +293,9 @@ long-context rates listed above.
|
|
|
174
293
|
compaction can land in the same cycle and the handoff brief is
|
|
175
294
|
written from compacted context — episodes and thread state survive
|
|
176
295
|
on disk, so handoff still functions.
|
|
296
|
+
- The doctrine sizes above cover the shipped rules only. A project
|
|
297
|
+
that also injects `doctrineExtraPath` or `orchestratorPromptDocs`,
|
|
298
|
+
or whitelists worker extensions, pays for those on top in the same
|
|
299
|
+
always-loaded position, and Slate measures none of it against the
|
|
300
|
+
budget separately — it simply arrives as context the budget then
|
|
301
|
+
has less room for.
|
|
@@ -8,9 +8,22 @@ for its content. This document records the reasoning behind the
|
|
|
8
8
|
extension's design so maintainers — and the orchestrator itself, on
|
|
9
9
|
demand — can check changes and behavior against the original intent.
|
|
10
10
|
|
|
11
|
-
Note: module headers cite
|
|
12
|
-
original implementation plan
|
|
13
|
-
|
|
11
|
+
Note: module headers cite ids from design records that are not part of this
|
|
12
|
+
repository — the original implementation plan (ExecPlan: D3–D9, M1–M3), later
|
|
13
|
+
design rounds (higher-numbered D ids, and W ids for named warnings), and
|
|
14
|
+
per-round review findings, whose prefix says which review raised them:
|
|
15
|
+
AD (adversarial), AF (agent-failure), BG (blocker/bug), CN (concurrency),
|
|
16
|
+
CQ (code quality), DF (data fidelity), N (numeric), RG (regression),
|
|
17
|
+
RI (research integrity), SE (security), WB (worker boundary) and WS (worker
|
|
18
|
+
safety). `extension/model-profiles.ts` additionally cites research TRACE keys
|
|
19
|
+
(`G1a`, `GM3`, `O4.2`, `A4b`, …). Those name rows in the research corpus that
|
|
20
|
+
produced the profile table; the corpus lives in the project repository and is
|
|
21
|
+
NOT part of the published package, so in an installed copy the keys are
|
|
22
|
+
provenance marks to quote when reporting a data problem, not links to follow.
|
|
23
|
+
What a consumer can act on without the corpus is in `model-routing.md`
|
|
24
|
+
(§ where the numbers come from): the table's provenance rules, its `asOf`
|
|
25
|
+
date, and which fields are marked untraced. This document is the in-repo
|
|
26
|
+
source for the architecture rationale.
|
|
14
27
|
|
|
15
28
|
## 1. The problems Slate is built to solve
|
|
16
29
|
|
|
@@ -167,6 +180,36 @@ while staying safe on common consumer API tiers; wider fan-outs only
|
|
|
167
180
|
pay tail latency, and projects with higher-tier keys raise the cap in
|
|
168
181
|
`slate.json`.
|
|
169
182
|
|
|
183
|
+
Repo-local note (not from the report): **action-level model routing**
|
|
184
|
+
applies P10's discipline to a second scarce resource. P10 treats
|
|
185
|
+
CONTEXT as RAM; the optional `router.models` list treats SPEND the same
|
|
186
|
+
way — each dispatched action gets a model and an effort level chosen to
|
|
187
|
+
be up to the task and no more, instead of every action inheriting
|
|
188
|
+
whatever model the orchestrator happens to be running. It is also a P1
|
|
189
|
+
corollary: an action is only a bounded unit if what it may cost is
|
|
190
|
+
bounded too, and the closed model list plus a derived (never inflated)
|
|
191
|
+
effort level is what bounds it. The two disciplines even share
|
|
192
|
+
machinery — pi's compaction settings, which clamp the orchestrator's
|
|
193
|
+
context budget, also decide per dispatch whether a worker thread still
|
|
194
|
+
fits the model it is routed to, in which case the action moves to the
|
|
195
|
+
widest listed model rather than being blocked.
|
|
196
|
+
|
|
197
|
+
The feature is OFF until `router.models` lists something, and it is
|
|
198
|
+
built on a deliberate split that is worth holding onto when reasoning
|
|
199
|
+
about the architecture: the code ENFORCES less than the routing data
|
|
200
|
+
ADVISES. Dispatch guards refuse what is mechanically wrong — a model
|
|
201
|
+
outside the configured list, a level a model does not offer — because
|
|
202
|
+
those are decidable from the data. The obligations that require
|
|
203
|
+
JUDGMENT about the work, such as which actions count as review or gate
|
|
204
|
+
actions and what a compliance constraint demands of a given task, are
|
|
205
|
+
stated in the doctrine for the orchestrator to honor and are not
|
|
206
|
+
guards. That is the same reasoning as P6: the harness makes the right
|
|
207
|
+
thing natural and blocks what it can decide, rather than pretending to
|
|
208
|
+
adjudicate what it cannot see. Which obligations fall on which side of
|
|
209
|
+
that line changes as the feature grows, so this document deliberately
|
|
210
|
+
does not restate the list — `model-routing.md` in this directory owns
|
|
211
|
+
it, along with the mechanics and the provenance of the routing data.
|
|
212
|
+
|
|
170
213
|
Repo-local note (not from the report): the P7 guard was originally
|
|
171
214
|
absolute — workers loaded no extensions, so Slate's `thread` tool simply
|
|
172
215
|
never existed for them. The optional `workerExtensions` key (`slate.json`,
|
|
@@ -268,7 +311,19 @@ the load-on-demand discipline the extension itself prescribes:
|
|
|
268
311
|
`review-rules.md`, and a pointer to the track-based workflow protocol
|
|
269
312
|
that ships with this package (`track-workflow.md` in this directory),
|
|
270
313
|
appended to the system prompt every turn while orchestrator mode is
|
|
271
|
-
on.
|
|
314
|
+
on. Sizing it matters to the tiering argument, so it is measured
|
|
315
|
+
rather than asserted: with both conditional tail rules and
|
|
316
|
+
`workflow.draftPRs` off, the block is **1,929 portable characters /
|
|
317
|
+
38 lines**, and configuring the router for six models roughly
|
|
318
|
+
DOUBLES it, to **3,870** on that same basis — the routing rule
|
|
319
|
+
renders one table row per routable model. (Portable characters, and
|
|
320
|
+
the rest of the configurations, are defined and tabulated in
|
|
321
|
+
`context-budget.md`; the raw count also depends on where the package
|
|
322
|
+
is installed, because the doctrine embeds absolute doc paths.) At a
|
|
323
|
+
rough 4 characters per token that is order-500 tokens, order-1,000
|
|
324
|
+
with the router on — so the original "a few hundred tokens" holds
|
|
325
|
+
only for the fixed rules, and a configured router buys its table with
|
|
326
|
+
a real slice of every request. It still covers everything routine
|
|
272
327
|
dispatching needs.
|
|
273
328
|
- **Tier 2 — on demand.** This document. The doctrine carries a short
|
|
274
329
|
pointer to it (doctrine rule 10); the orchestrator reads it only when
|