ytdb-slate 0.8.0 → 0.10.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 +27 -11
- package/docs/context-budget.md +102 -52
- package/docs/design-principles.md +7 -7
- package/docs/model-routing.md +65 -31
- package/docs/pr-publishing.md +39 -13
- package/docs/review-rules.md +84 -14
- package/docs/thread-cache-cost.md +227 -0
- package/docs/track-workflow.md +248 -161
- package/docs/writing-guidance.md +8 -3
- package/extension/episodes.ts +69 -24
- package/extension/index.ts +39 -22
- package/extension/mode.ts +27 -12
- package/extension/model-profiles.ts +168 -13
- package/extension/model-router.ts +128 -21
- package/extension/paths.ts +1 -0
- package/extension/render.ts +14 -6
- package/extension/route.ts +109 -1
- package/extension/state.ts +341 -9
- package/extension/thread-choice.ts +1207 -0
- package/extension/threads.ts +522 -32
- package/extension/tools.ts +107 -6
- package/extension/worker.ts +54 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
Slate is a thread-weaving orchestration extension for the [pi coding agent](https://pi.dev).
|
|
6
6
|
|
|
7
|
-
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.
|
|
7
|
+
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. Slate also injects a mandatory workflow doctrine. Its design and review gates scale with the confirmed change class. Optional umbrella **draft-PR publishing** covers tracks.
|
|
8
|
+
|
|
9
|
+
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.
|
|
8
10
|
|
|
9
11
|
## Why Slate?
|
|
10
12
|
|
|
@@ -36,16 +38,29 @@ Full rationale: [`docs/design-principles.md`](docs/design-principles.md), shippe
|
|
|
36
38
|
|
|
37
39
|
## Feature development workflow
|
|
38
40
|
|
|
39
|
-
In orchestrator mode, Slate injects a track-based development workflow
|
|
41
|
+
In orchestrator mode, Slate injects a mandatory track-based development workflow. Project configuration can extend it through `doctrineExtraPath`. Configuration cannot replace it.
|
|
42
|
+
|
|
43
|
+
Slate uses four change classes. Evaluate these tests in order. The first match
|
|
44
|
+
sets the class:
|
|
45
|
+
|
|
46
|
+
1. **Risky:** The change touches concurrency, durability, recovery,
|
|
47
|
+
transactional semantics, security, or user data. This class also covers a
|
|
48
|
+
public API or behavioral change, or a silent failure mode.
|
|
49
|
+
2. **Complex:** The shape is unclear, several parts interact, or a live design
|
|
50
|
+
alternative exists.
|
|
51
|
+
3. **Trivial:** The change is an obvious fix with no behavioral change, and one
|
|
52
|
+
reviewer pass covers it.
|
|
53
|
+
4. **Medium:** Otherwise.
|
|
54
|
+
|
|
55
|
+
After classification, follow these workflow steps:
|
|
40
56
|
|
|
41
|
-
1. **
|
|
42
|
-
2. **
|
|
43
|
-
3. **
|
|
44
|
-
4. **
|
|
45
|
-
5. **
|
|
46
|
-
6. **Delivery** — with draft-PR publishing enabled, the squash-merge is performed by the user; the agent never merges. With it disabled (the default), the change lands as a squashed commit that carries the workflow log's key content in its message.
|
|
57
|
+
1. **Classification and research** — the orchestrator proposes the change class, and the user confirms it. A research log is required for medium changes and above.
|
|
58
|
+
2. **Design gates** — medium changes need high-level design approval before implementation. Complex and risky changes add an adversarial review between two user approvals.
|
|
59
|
+
3. **Track split** — the orchestrator owns the split. Size determines tracks and marker commits, not workflow gates.
|
|
60
|
+
4. **Per-track loop** — each track gets implementation, fixes, and mandatory user review. Agent code review is skipped only when the whole change is trivial.
|
|
61
|
+
5. **Delivery** — the user performs the squash merge when draft publishing is enabled. Otherwise, the squashed commit carries the workflow log's key content.
|
|
47
62
|
|
|
48
|
-
|
|
63
|
+
Trivial changes have no high-level design gate. Every change keeps mandatory user review of its track diff. Umbrella draft-PR publishing activates only when `workflow.draftPRs` is `true`.
|
|
49
64
|
|
|
50
65
|
This summary is orientation only; the shipped docs listed below are normative.
|
|
51
66
|
|
|
@@ -104,6 +119,7 @@ Optional config file: `slate.json` in the project's pi config dir (`.pi/slate.js
|
|
|
104
119
|
| `orchestratorPromptDocs` | string[] | `[]` | Project markdown files (paths relative to the project root) whose **contents** are appended to the orchestrator system prompt. |
|
|
105
120
|
| `workerPromptDocs` | string[] | `[]` | Project markdown files whose **contents** are appended to every worker-thread system prompt. |
|
|
106
121
|
| `workflow.draftPRs` | boolean | `false` | Enable umbrella draft-PR publishing for tracks. |
|
|
122
|
+
| `workflow.followUpIssues` | boolean | `false` | When true, the orchestrator asks which suggestions become follow-up issues in the project tracker. Suggestions are always reported whatever the value. |
|
|
107
123
|
| `writing.check` | boolean | `false` | Add the writing doctrine rule, per-turn status, and worker guidance. An absent option is silently off. A malformed `writing` value, or a non-boolean `check` value, warns and defaults to off. Unknown `writing` keys warn and are ignored. See [`docs/writing-guidance.md`](docs/writing-guidance.md). |
|
|
108
124
|
| `writing.remind` | boolean | `false` | Send a hidden reminder after an eligible tool result. All gates must pass: orchestrator mode, project trust, `writing.check`, this option, no pause, cadence or handoff force, and one-per-round control. See [`docs/writing-guidance.md`](docs/writing-guidance.md). |
|
|
109
125
|
| `writing.remindPercent` | number | `10` | Set cadence as a percentage of Slate's current effective context budget. The value must be finite and in `(0, 100]`. The interval has an 8,192-token floor and no cap. A handoff force bypasses this threshold. See [`docs/writing-guidance.md`](docs/writing-guidance.md). |
|
|
@@ -124,7 +140,7 @@ Example `.pi/slate.json` (the `docs/agents/...` paths are placeholders — point
|
|
|
124
140
|
"maxConcurrent": 4,
|
|
125
141
|
"orchestratorPromptDocs": ["docs/agents/orchestrator-guidelines.md"],
|
|
126
142
|
"workerPromptDocs": ["docs/agents/thread-guidelines.md"],
|
|
127
|
-
"workflow": { "draftPRs": true },
|
|
143
|
+
"workflow": { "draftPRs": true, "followUpIssues": false },
|
|
128
144
|
"writing": {
|
|
129
145
|
"check": true,
|
|
130
146
|
"remind": false,
|
|
@@ -170,7 +186,7 @@ Slate reads project configuration (`.pi/slate.json`) and injects project files (
|
|
|
170
186
|
|
|
171
187
|
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:
|
|
172
188
|
|
|
173
|
-
- `docs/track-workflow.md` — the
|
|
189
|
+
- `docs/track-workflow.md` — the class-scaled workflow for research, high-level design, adversarial review, and track review
|
|
174
190
|
- `docs/pr-publishing.md` — umbrella draft-PR publishing (cited only when `workflow.draftPRs` is `true`)
|
|
175
191
|
- `docs/review-rules.md` — review discipline and finding rules
|
|
176
192
|
- `docs/design-principles.md` — Slate's own design rationale
|
package/docs/context-budget.md
CHANGED
|
@@ -142,13 +142,16 @@ schema. A tool description and a parameter description are therefore both
|
|
|
142
142
|
always loaded.
|
|
143
143
|
|
|
144
144
|
The current `thread` tool description is 1,386 UTF-8 bytes. Its serialized
|
|
145
|
-
parameter schema is
|
|
146
|
-
includes the 289-byte `type` parameter description
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
145
|
+
parameter schema is 2,005 bytes, measured as `JSON.stringify(parameters)`.
|
|
146
|
+
The schema includes the 289-byte `type` parameter description and the
|
|
147
|
+
`freshContext` argument.
|
|
148
|
+
|
|
149
|
+
The description and schema total 3,391 bytes before provider framing. The
|
|
150
|
+
`freshContext` schema entry adds 214 bytes to the previous combined figure.
|
|
151
|
+
The increase is roughly 54 tokens at four characters per token.
|
|
152
|
+
|
|
153
|
+
The figure excludes the prompt snippet, prompt guidelines, tool name,
|
|
154
|
+
provider framing, and serialization outside the parameter schema.
|
|
152
155
|
|
|
153
156
|
The always-loaded doctrine has a separate measurement after the compaction
|
|
154
157
|
policy.
|
|
@@ -174,14 +177,14 @@ you pay its input tokens every turn.
|
|
|
174
177
|
|
|
175
178
|
**Its size depends on where the package is installed.** That is not
|
|
176
179
|
obvious, and it catches anyone who measures: the doctrine cites the
|
|
177
|
-
shipped docs by ABSOLUTE path, so
|
|
178
|
-
are embedded in the block —
|
|
179
|
-
(`
|
|
180
|
-
plus `pr-publishing.md` when
|
|
181
|
-
`model-routing.md` when the routing
|
|
182
|
-
`writing-guidance.md` when `writing.check` is on.
|
|
183
|
-
character in the installed `docs/` directory therefore
|
|
184
|
-
characters of doctrine.
|
|
180
|
+
shipped docs by ABSOLUTE path, so four to seven full filesystem paths
|
|
181
|
+
are embedded in the block — four at minimum
|
|
182
|
+
(`thread-cache-cost.md`, `track-workflow.md`, `review-rules.md`,
|
|
183
|
+
`design-principles.md`), plus `pr-publishing.md` when
|
|
184
|
+
`workflow.draftPRs` is on, plus `model-routing.md` when the routing
|
|
185
|
+
rule renders, plus `writing-guidance.md` when `writing.check` is on.
|
|
186
|
+
Every additional character in the installed `docs/` directory therefore
|
|
187
|
+
costs 4–7 characters of doctrine.
|
|
185
188
|
|
|
186
189
|
The figures below are **portable characters**, defined exactly as
|
|
187
190
|
Slate's own automated `doctrine-budget` check defines them: the
|
|
@@ -204,18 +207,18 @@ must be named instead of presented as the same measurement:
|
|
|
204
207
|
|
|
205
208
|
| router | models | `draftPRs` | `writing.check` | paths | portable | lines |
|
|
206
209
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
207
|
-
| off | — | off | off |
|
|
208
|
-
| off | — | off | on |
|
|
209
|
-
| off | — | on | off |
|
|
210
|
-
| off | — | on | on |
|
|
211
|
-
| on | `.pi/slate.json` six | off | off |
|
|
212
|
-
| on | `.pi/slate.json` six | off | on |
|
|
213
|
-
| on | `.pi/slate.json` six | on | off |
|
|
214
|
-
| on | `.pi/slate.json` six | on | on |
|
|
215
|
-
| on | all 9 shipped | off | off |
|
|
216
|
-
| on | all 9 shipped | off | on |
|
|
217
|
-
| on | all 9 shipped | on | off |
|
|
218
|
-
| on | all 9 shipped | on | on |
|
|
210
|
+
| off | — | off | off | 4 | 2,701 | 46 |
|
|
211
|
+
| off | — | off | on | 5 | 3,771 | 68 |
|
|
212
|
+
| off | — | on | off | 5 | 2,720 | 46 |
|
|
213
|
+
| off | — | on | on | 6 | 3,790 | 68 |
|
|
214
|
+
| on | `.pi/slate.json` six | off | off | 5 | 4,731 | 67 |
|
|
215
|
+
| on | `.pi/slate.json` six | off | on | 6 | 5,801 | 89 |
|
|
216
|
+
| on | `.pi/slate.json` six | on | off | 6 | 4,750 | 67 |
|
|
217
|
+
| on | `.pi/slate.json` six | on | on | 7 | 5,820 | 89 |
|
|
218
|
+
| on | all 9 shipped | off | off | 5 | 5,286 | 70 |
|
|
219
|
+
| on | all 9 shipped | off | on | 6 | 6,356 | 92 |
|
|
220
|
+
| on | all 9 shipped | on | off | 6 | 5,305 | 70 |
|
|
221
|
+
| on | all 9 shipped | on | on | 7 | 6,375 | 92 |
|
|
219
222
|
|
|
220
223
|
An untrusted project reads the first row whatever its `slate.json`
|
|
221
224
|
says: no project config is loaded, so no optional rule renders. Line
|
|
@@ -231,9 +234,9 @@ path:
|
|
|
231
234
|
|
|
232
235
|
- The routing rule is a live table with ONE ROW PER ROUTABLE MODEL,
|
|
233
236
|
so what renders is the models you CONFIGURE — not the nine Slate
|
|
234
|
-
ships profiles for. In this snapshot it is
|
|
235
|
-
characters and adds
|
|
236
|
-
for all nine it is 2,
|
|
237
|
+
ships profiles for. In this snapshot it is 2,030 portable
|
|
238
|
+
characters and adds 21 doctrine lines for six configured models;
|
|
239
|
+
for all nine it is 2,585 characters and adds 24 lines. The six
|
|
237
240
|
model rows are 146–181 characters; all nine are 146–183. The
|
|
238
241
|
legend adds a one-off clause per marker it has to explain, so
|
|
239
242
|
growth is not only the sum of new rows.
|
|
@@ -247,17 +250,19 @@ worker extensions and support verification decisions:
|
|
|
247
250
|
|
|
248
251
|
| basis | models | worker extensions | paths | portable | lines | rough tokens |
|
|
249
252
|
| --- | ---: | --- | ---: | ---: | ---: | ---: |
|
|
250
|
-
| current `.pi/slate.json` dogfood config | 6 |
|
|
251
|
-
| stable maximal fixture | 9 | synthetic 2 units / 4 tools, every rendered field at its cap |
|
|
253
|
+
| current `.pi/slate.json` dogfood config | 6 | pinned-package 2 units / 4 tools | 7 | 6,736 | 99 | ≈1,684 |
|
|
254
|
+
| stable maximal fixture | 9 | synthetic 2 units / 4 tools, every rendered field at its cap | 7 | 7,722 | 102 | ≈1,931 |
|
|
255
|
+
| follow-up-issues maximal fixture | 9 | synthetic 2 units / 4 tools, every rendered field at its cap | 7 | 7,800 | 103 | ≈1,950 |
|
|
252
256
|
|
|
253
257
|
The dogfood row uses `workflow.draftPRs: true`, `writing.check: true`, and the
|
|
254
258
|
six models in `.pi/slate.json`. Its extension basis is
|
|
255
259
|
`pi-smart-fetch@0.3.12` plus `pi-web-search@1.3.1`. Those packages resolve to two
|
|
256
260
|
units and four tools. Their worker-extension rule is 916 portable characters /
|
|
257
|
-
11 lines. Raw size remains symbolic: `portable +
|
|
261
|
+
11 lines. Raw size remains symbolic: `portable + 7 × length(installed docs
|
|
258
262
|
directory)`. No maintainer checkout path belongs in this shipped document.
|
|
259
263
|
|
|
260
264
|
The stable maximal row uses all nine shipped profiles, draft PRs, and writing.
|
|
265
|
+
The follow-up-issues row uses the same basis with `workflow.followUpIssues: true`.
|
|
261
266
|
Its direct post-resolution worker fixture has two units and four tools. Unit
|
|
262
267
|
labels are 128 characters. Tool names are 64 characters. Descriptions are 140
|
|
263
268
|
characters.
|
|
@@ -267,24 +272,67 @@ independent of installed extension labels, descriptions, versions and other
|
|
|
267
272
|
prose. The worker rule measures 1,347 characters against its 1,600-character
|
|
268
273
|
verification budget.
|
|
269
274
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
fixture
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
275
|
+
The reserve policy is: every doctrine upper bound must exceed its current
|
|
276
|
+
measurement by at least five percent, with a required character-bound raise
|
|
277
|
+
rounded up to the next hundred characters. Existing bounds stay in place when
|
|
278
|
+
they already satisfy the policy. Line bounds use the same five-percent rule and
|
|
279
|
+
the next whole line.
|
|
280
|
+
|
|
281
|
+
Two guards have different jobs. An exact pinned literal is the sensitive guard.
|
|
282
|
+
It fails for every size change in its rendered fixture, including one character.
|
|
283
|
+
The maximal fixtures cover draft pull requests enabled, draft pull requests
|
|
284
|
+
disabled, and follow-up issues enabled. Each budget term also has one enforced
|
|
285
|
+
bound. The bound is a coarse ceiling that stops unbounded growth over time. A
|
|
286
|
+
bound close to a fixture adds friction but no detection, because its exact
|
|
287
|
+
literal already detects the change. Real reserve therefore weakens nothing.
|
|
288
|
+
|
|
289
|
+
A doctrine change updates the exact literal and every published measurement. A
|
|
290
|
+
maintainer revisits a bound only when the reserve policy requires it. The check
|
|
291
|
+
applies the five-percent rule to every upper bound, so this decision is auditable.
|
|
292
|
+
|
|
293
|
+
| budget term | current | enforced bound | current reserve |
|
|
294
|
+
| --- | ---: | ---: | ---: |
|
|
295
|
+
| routing rule characters | 2,585 | 4,000 | 1,415 |
|
|
296
|
+
| routing rule lines | 25 | 34 | 9 |
|
|
297
|
+
| routing fixed prose | 1,110 | 1,500 | 390 |
|
|
298
|
+
| largest model row | 183 | 300 | 117 |
|
|
299
|
+
| router-on doctrine | 5,286 | 6,500 | 1,214 |
|
|
300
|
+
| writing-only doctrine | 3,771 | 5,600 | 1,829 |
|
|
301
|
+
| writing plus router | 6,356 | 6,700 | 344 |
|
|
302
|
+
| writing plus extensions | 4,026 | 6,000 | 1,974 |
|
|
303
|
+
| writing plus router and extensions | 6,611 | 7,000 | 389 |
|
|
304
|
+
| maximal doctrine, draft PRs enabled | 7,722 | 8,200 | 478 |
|
|
305
|
+
| maximal doctrine, draft PRs disabled | 7,703 | 8,200 | 497 |
|
|
306
|
+
| maximal doctrine, follow-up issues enabled | 7,800 | 8,200 | 400 |
|
|
307
|
+
| capped worker rule | 1,347 | 1,600 | 253 |
|
|
308
|
+
| writing rule characters | 1,070 | 1,150 | 80 |
|
|
309
|
+
| writing rule lines | 23 | 25 | 2 |
|
|
310
|
+
|
|
311
|
+
The four changed bound decisions record the user's choices. The fuller
|
|
312
|
+
Option 3 text puts the enforcement trigger, class confirmation, presentation
|
|
313
|
+
order, and two previously unstated gates in the injected prompt. Writing plus
|
|
314
|
+
router moved from 6,500 to 6,700. Writing plus router and extensions moved from
|
|
315
|
+
6,800 to 6,900. The maximal family moved from 7,900 to 8,200. Writing plus router
|
|
316
|
+
and extensions then moved from 6,900 to 7,000 with user approval so rule 8 could
|
|
317
|
+
keep the skip-the-read clause that rules 9 and 10 also carry. A redundant read of
|
|
318
|
+
the track workflow document costs far more than the clause.
|
|
319
|
+
|
|
320
|
+
The positive control adds one capped tool and four copies of the largest
|
|
321
|
+
measured model row. It measures 8,670 portable characters and exceeds the
|
|
322
|
+
8,200-character maximal bound by 470. That margin remains larger than the
|
|
323
|
+
184-character maximum model-row growth and the 212-character capped tool growth.
|
|
324
|
+
The raised bound does not blunt the positive control.
|
|
325
|
+
|
|
326
|
+
These figures are verification budgets, never runtime limits. Arbitrary user
|
|
327
|
+
extension rosters can exceed them. Keep the positive-control steps unchanged
|
|
328
|
+
unless the fixture design itself changes.
|
|
329
|
+
|
|
330
|
+
Against a 256,000-token context budget, these blocks remain small. The rough
|
|
331
|
+
estimate divides each measured portable-character render by four and rounds to
|
|
332
|
+
the nearest whole token. The shipped-rule table ranges from about 675 tokens to
|
|
333
|
+
about 1,594 tokens. The current dogfood basis is about 1,684 tokens. The stable
|
|
334
|
+
representative maximum is about 1,931 tokens. The follow-up-issues maximum is
|
|
335
|
+
about 1,950 tokens, or 0.76 percent of the default budget.
|
|
288
336
|
|
|
289
337
|
No tokenizer was run, and tables are denser than prose. The block is re-sent on every request rather than paid once. These figures show how
|
|
290
338
|
much headroom Slate consumes before conversation content.
|
|
@@ -381,7 +429,9 @@ long-context rates listed above.
|
|
|
381
429
|
|
|
382
430
|
With action-level routing on, this override also settles a warning
|
|
383
431
|
you will otherwise see once per session for each configured
|
|
384
|
-
`gpt-5.6-*` model
|
|
432
|
+
`gpt-5.6-*` model during resolution. Dispatch-time price divergence warnings
|
|
433
|
+
are conditional and can repeat on later dispatches. Slate's own profile for those
|
|
434
|
+
models records a
|
|
385
435
|
1,050,000-token window, pi's stock registry reports 272,000, and the
|
|
386
436
|
router reports that divergence without adjudicating it (routing uses
|
|
387
437
|
the registry figure). Raising the registry window removes the
|
|
@@ -312,19 +312,19 @@ the load-on-demand discipline the extension itself prescribes:
|
|
|
312
312
|
|
|
313
313
|
- **Tier 1 — always loaded.** The doctrine in `mode.ts` is the operational
|
|
314
314
|
distillation of P1–P10, the review discipline defined in
|
|
315
|
-
`review-rules.md`, and a pointer to the
|
|
316
|
-
that ships with this package (`track-workflow.md` in this directory),
|
|
315
|
+
`review-rules.md`, and a pointer to the class-scaled track workflow
|
|
316
|
+
protocol that ships with this package (`track-workflow.md` in this directory),
|
|
317
317
|
appended to the system prompt every turn while orchestrator mode is
|
|
318
318
|
on. Sizing it matters to the tiering argument, so it is measured
|
|
319
|
-
rather than asserted: with
|
|
320
|
-
`workflow.draftPRs` off, the block is **
|
|
321
|
-
|
|
322
|
-
|
|
319
|
+
rather than asserted: with every conditional tail rule off and
|
|
320
|
+
`workflow.draftPRs` off, the block is **2,701 portable characters /
|
|
321
|
+
46 lines**, and configuring the router for six models nearly
|
|
322
|
+
doubles it, to **4,731** on that same basis — the routing rule
|
|
323
323
|
renders one table row per routable model. (Portable characters, and
|
|
324
324
|
the rest of the configurations, are defined and tabulated in
|
|
325
325
|
`context-budget.md`; the raw count also depends on where the package
|
|
326
326
|
is installed, because the doctrine embeds absolute doc paths.) At a
|
|
327
|
-
rough 4 characters per token that is order-
|
|
327
|
+
rough 4 characters per token that is order-700 tokens, order-1,200
|
|
328
328
|
with the router on — so the original "a few hundred tokens" holds
|
|
329
329
|
only for the fixed rules, and a configured router buys its table with
|
|
330
330
|
a real slice of every request. It still covers everything routine
|
package/docs/model-routing.md
CHANGED
|
@@ -279,6 +279,7 @@ warning, but removal is not the ADD remedy in condition 2. Condition
|
|
|
279
279
|
| pi has no usable credentials configured for it | dropped | "has no usable credentials configured in pi. Slate drops it from routing." | configuration fault |
|
|
280
280
|
| every entry is dropped | router turns OFF | "survived validation. The warnings above name each dropped entry" | configuration fault |
|
|
281
281
|
| no usable input price exists for today's date | kept, ordered last | "Slate cannot compare its cost with the other models." | model data note |
|
|
282
|
+
| a profile price is negative or non-finite | kept, ordered last or unavailable | "has invalid input price data" or "has invalid output price data" | model data note |
|
|
282
283
|
| no usable effort ladder exists in the profile | kept | "Such a level passes through to pi, which clamps it" | model data note |
|
|
283
284
|
| profile context window differs from the registry window | kept, registry value used | "differs between two sources" | model data note |
|
|
284
285
|
| the first profile names unknown routing-critical fields | kept | "picks models from a research table shipped inside slate" | model data note |
|
|
@@ -288,20 +289,30 @@ warning, but removal is not the ADD remedy in condition 2. Condition
|
|
|
288
289
|
| every configured candidate is marked non-preferred | cheapest candidate becomes the base | "profiles mark every configured model as one it must never pick by itself" | configuration fault |
|
|
289
290
|
| resolution throws | router turns OFF | "routing is disabled. The router could not resolve its model list" | configuration fault |
|
|
290
291
|
|
|
291
|
-
|
|
292
|
-
resolution
|
|
293
|
-
|
|
294
|
-
channel
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
292
|
+
Each resolution warning is deduplicated by a condition key and retained in the
|
|
293
|
+
frozen resolution regardless of display filtering. With `router.showWarnings:
|
|
294
|
+
true`, every resolution warning reaches the normal UI notification or console
|
|
295
|
+
channel. With the default `false`, every configuration fault remains visible
|
|
296
|
+
and model data notes are hidden.
|
|
297
|
+
|
|
298
|
+
When resolution hides at least one note, Slate emits one discoverability line.
|
|
299
|
+
It gives the hidden warning count, names `router.showWarnings`, and says that a
|
|
300
|
+
hidden warning can affect model selection. The count is warnings, not physical
|
|
301
|
+
display lines. The line appears at most once per session.
|
|
302
|
+
|
|
303
|
+
Dispatch-time warnings are separate. Context substitution, effort evidence
|
|
304
|
+
gaps, long-context billing, failover window notices, and the model-visible
|
|
305
|
+
registry-price divergence warning are evaluated for each planned action. They
|
|
306
|
+
can repeat on later dispatches. The divergence warning is hardened and capped
|
|
307
|
+
through the router sanitizer. It omits exact rates and is not deduplicated.
|
|
308
|
+
|
|
309
|
+
The exact-rate companion uses the class-aware router sink as a model data note.
|
|
310
|
+
It is hidden by default and shown when `router.showWarnings` is true. Its
|
|
311
|
+
condition key includes the model, date, and differing rates, so identical live
|
|
312
|
+
evidence reports once while changed evidence reports again. It passes through
|
|
313
|
+
the same control stripping, citation cleanup, field caps, and whole-message cap
|
|
314
|
+
as resolution warnings. A hidden dispatch-time note can trigger the one-time
|
|
315
|
+
discoverability line only when resolution did not already trigger it.
|
|
305
316
|
|
|
306
317
|
Half a list is still a routing policy, so partial drops leave the
|
|
307
318
|
router ON. Nothing surviving is not a policy: the router turns OFF
|
|
@@ -485,17 +496,18 @@ model's ladder is unreadable.
|
|
|
485
496
|
`(unmeasured)` where that applies. `live=<model> (failover)` means
|
|
486
497
|
a held fallback currently overrides the nominal base for the live
|
|
487
498
|
session.
|
|
488
|
-
- **At the session level:**
|
|
489
|
-
|
|
499
|
+
- **At the session level:** configuration faults and model data notes enabled by
|
|
500
|
+
`router.showWarnings`, as UI notifications or console output. The default
|
|
501
|
+
instead shows one discoverability line when it hides notes.
|
|
490
502
|
- **In the orchestrator's own system prompt, every turn:** the
|
|
491
503
|
doctrine gains a routing rule — a table with one row per routable
|
|
492
504
|
model, plus the rules for reading it. This is the surface you do
|
|
493
|
-
not see, and it is the router's standing cost:
|
|
494
|
-
|
|
505
|
+
not see, and it is the router's standing cost: 2,030 characters /
|
|
506
|
+
21 added doctrine lines for six configured models, 2,585 / 24 for
|
|
495
507
|
all nine. In the current snapshot a model row costs 146–183
|
|
496
508
|
characters, plus a one-off legend clause for each marker it
|
|
497
509
|
introduces. Configuring the router roughly doubles Slate's
|
|
498
|
-
always-loaded block (
|
|
510
|
+
always-loaded block (2,701 characters with routing and writing
|
|
499
511
|
off). Those are PORTABLE characters — the
|
|
500
512
|
doctrine with each occurrence of the installed `docs/` directory
|
|
501
513
|
removed, filenames kept — because the doctrine embeds absolute doc
|
|
@@ -506,10 +518,12 @@ model's ladder is unreadable.
|
|
|
506
518
|
|
|
507
519
|
## Expected first-session warnings
|
|
508
520
|
|
|
509
|
-
The stock count below
|
|
510
|
-
`.pi/slate.json`, the shipped profile table, and
|
|
511
|
-
|
|
512
|
-
|
|
521
|
+
The stock count below comes from executing `resolveModelRouter` with this
|
|
522
|
+
repository's sanitized `.pi/slate.json`, the shipped profile table, and a real
|
|
523
|
+
`ModelRuntime` from the pinned pi 0.83.0 package. The runtime used
|
|
524
|
+
`modelsPath: null` and `allowModelNetwork: false`, so no local registry override
|
|
525
|
+
or network refresh could affect it. Dummy OpenAI and Anthropic credentials made
|
|
526
|
+
the configured-auth premise explicit. The packaged OpenAI data at
|
|
513
527
|
`@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json`
|
|
514
528
|
reports a **272,000-token** context window for
|
|
515
529
|
`openai/gpt-5.6-luna`, `openai/gpt-5.6-terra` and
|
|
@@ -528,8 +542,8 @@ data notes**. The default `router.showWarnings: false` therefore
|
|
|
528
542
|
shows **0 of those warnings** and one discoverability line. That line
|
|
529
543
|
begins `slate: there are 11 hidden warnings in the model router.`
|
|
530
544
|
Enabling the option shows all 11 warnings and no discoverability
|
|
531
|
-
line. Each warning fires at most once per session, and the
|
|
532
|
-
is frozen after the first consultation.
|
|
545
|
+
line. Each resolution warning fires at most once per session, and the
|
|
546
|
+
resolution is frozen after the first consultation.
|
|
533
547
|
|
|
534
548
|
| warnings | class | condition keys | why | shown by default |
|
|
535
549
|
| --- | --- | --- | --- | --- |
|
|
@@ -576,9 +590,31 @@ A hidden warning can still alter which model runs an action. Context-
|
|
|
576
590
|
window divergence is the concrete case, and the stock registry emits
|
|
577
591
|
three such hidden notes for this list. Routing uses the registry
|
|
578
592
|
window, and that value drives the context-window substitution guard.
|
|
579
|
-
`router.showWarnings` changes display only
|
|
593
|
+
`router.showWarnings` changes display only. It does not change the
|
|
580
594
|
resolution or the guard input.
|
|
581
595
|
|
|
596
|
+
## Thread choice after routing
|
|
597
|
+
|
|
598
|
+
Routing resolves the model and effort for one action. Thread choice then uses that applied pair when it evaluates a continuation.
|
|
599
|
+
|
|
600
|
+
A model or effort change makes the existing prefix cold. Current cache-write prices are 12.5 times the matching cache-read prices.
|
|
601
|
+
|
|
602
|
+
The `thread` tool owns the economic comparison. The orchestrator still decides whether named episodes can replace the live transcript.
|
|
603
|
+
|
|
604
|
+
On a continuation with `threadChoice.act: true`, `freshContext` is required. With acting off, it is optional. Every supplied valid value reaches the planner on either continuation path. An empty array refuses a restart. A non-empty list of existing episode ids permits one and seeds the new thread.
|
|
605
|
+
|
|
606
|
+
Whenever `freshContext` is supplied, malformed input or an unknown episode is a tool error before creation or mutation. A valid value on a creation call is accepted and unused because creation has no planner.
|
|
607
|
+
|
|
608
|
+
The planner can return `continue`, `fresh`, `abstain`, or `refused`. Only `fresh` can trigger a restart when `threadChoice.act` is enabled.
|
|
609
|
+
|
|
610
|
+
Acting defaults off. The default `threadChoice.report` setting returns the verdict without moving the action.
|
|
611
|
+
|
|
612
|
+
The planner uses current price rows, recorded prefix size, episode size, and dated retention evidence. It abstains when required price or size evidence is missing.
|
|
613
|
+
|
|
614
|
+
A stale retention row grants no retention window. Missing retention or elapsed time does not prove expiry, so an unchanged route remains warm.
|
|
615
|
+
|
|
616
|
+
The complete mechanism and evidence limits are in [Thread cache cost](thread-cache-cost.md).
|
|
617
|
+
|
|
582
618
|
## What the router does NOT enforce
|
|
583
619
|
|
|
584
620
|
Two obligations carried by the shipped profile data and stated in
|
|
@@ -724,11 +760,9 @@ concern; a green suite says nothing about it.
|
|
|
724
760
|
the shipped profile for the plan target when pi's registry can serve
|
|
725
761
|
that model. The `model` argument itself is passed through
|
|
726
762
|
byte-for-byte, so a malformed spec still produces pi's own error.
|
|
727
|
-
- **A mid-thread
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
the warm one. The router compares base rates, not the cache state
|
|
731
|
-
of your thread.
|
|
763
|
+
- **A mid-thread route can cost the prompt cache.** A model or effort
|
|
764
|
+
change makes the prefix cold. The thread-choice planner prices that
|
|
765
|
+
cache state after routing. See [Thread choice after routing](#thread-choice-after-routing).
|
|
732
766
|
- **The window guard can move an action to a model you did not
|
|
733
767
|
choose** (it warns, and names what it replaced), and it never
|
|
734
768
|
blocks: if nothing listed is wider, the action runs and pi
|
package/docs/pr-publishing.md
CHANGED
|
@@ -9,21 +9,36 @@ workflow-log lifecycle in that mode is owned by track-workflow.md
|
|
|
9
9
|
|
|
10
10
|
## Creation
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
For every change with a high-level design, draft the PR description
|
|
13
|
+
before the pre-implementation presentation. Present the draft alongside
|
|
14
|
+
the high-level design, so one approval covers both. The description has
|
|
15
|
+
no separate approval gate.
|
|
16
|
+
|
|
17
|
+
The umbrella draft PR is created after the gate required by the
|
|
18
|
+
confirmed change class passes and BEFORE implementation. For a complex
|
|
19
|
+
or risky change, that gate is the final high-level design approval after
|
|
20
|
+
the adversarial review. For a medium change, it is the high-level design
|
|
21
|
+
approval. A trivial change has no high-level design gate, so the PR is
|
|
22
|
+
created after the user confirms the class and before implementation:
|
|
14
23
|
|
|
15
24
|
- Created as a DRAFT, based on the repository's default development
|
|
16
25
|
branch.
|
|
17
26
|
- If the working branch has no diff against the base yet, land a
|
|
18
27
|
bootstrap empty commit so the PR can be created.
|
|
19
|
-
- At creation
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
- At creation for a medium, complex, or risky change, the research
|
|
29
|
+
log's Planned changes content folds into the PR description. Key
|
|
30
|
+
decisions, Risks, and Open questions feed the corresponding
|
|
31
|
+
Planned-changes subsections. The applicable design review verdict
|
|
32
|
+
lines land in Risks & accepted trade-offs. The adversarial review
|
|
33
|
+
verdict line lands there only when that review ran; a medium change
|
|
34
|
+
carries the design verdict lines alone.
|
|
35
|
+
- For a trivial change, the initial request supplies Motivation. The
|
|
36
|
+
confirmed class proposal and intended fix supply Planned changes. If
|
|
37
|
+
a log exists, its relevant decisions and Open Questions also fold
|
|
38
|
+
into the description.
|
|
39
|
+
- The research log is retained until delivery, and its Decision Log
|
|
40
|
+
keeps appending during implementation. track-workflow.md § Research
|
|
41
|
+
log owns the full lifecycle.
|
|
27
42
|
|
|
28
43
|
## Description rules
|
|
29
44
|
|
|
@@ -46,8 +61,13 @@ Subsections activate when their content exists:
|
|
|
46
61
|
- **Key decisions** — chosen vs rejected; preempts "why not X?" review
|
|
47
62
|
comments.
|
|
48
63
|
- **Out of scope** — explicit non-goals.
|
|
49
|
-
- **Risks & accepted trade-offs** — including the design
|
|
50
|
-
adversarial review verdict
|
|
64
|
+
- **Risks & accepted trade-offs** — including the applicable design
|
|
65
|
+
review verdict lines, and the adversarial review verdict line only
|
|
66
|
+
when that review ran.
|
|
67
|
+
- **Suggestions** — a one-line index per suggestion: identifier,
|
|
68
|
+
location, and one-line summary. The standalone text lives in the
|
|
69
|
+
final report to the user or in a tracker issue when
|
|
70
|
+
`workflow.followUpIssues` enables that prompt.
|
|
51
71
|
- **Verification approach** — 1–2 lines.
|
|
52
72
|
|
|
53
73
|
"Deep enough" test: a reviewer who knows the codebase but not this
|
|
@@ -113,7 +133,10 @@ executed in order:
|
|
|
113
133
|
review) is completed or explicitly user-waived — flipping never
|
|
114
134
|
discards a pending review.
|
|
115
135
|
- All commits landed since the last user-approved gate are presented
|
|
116
|
-
to the user.
|
|
136
|
+
to the user. For a trivial change, present the description here
|
|
137
|
+
because no design gate presented it before implementation.
|
|
138
|
+
- Every remaining suggestion is reported to the user, and the
|
|
139
|
+
Suggestions index is present in the description.
|
|
117
140
|
- Strip the whole Tracks section from the description, whatever its
|
|
118
141
|
form — the table for multi-track changes or the "N/A (single-track)"
|
|
119
142
|
placeholder — plus any notes under it. Track numbers are ephemeral
|
|
@@ -153,6 +176,9 @@ of any recorded size exception.
|
|
|
153
176
|
|
|
154
177
|
## After the merge
|
|
155
178
|
|
|
179
|
+
Complete the research-log delivery cleanup defined by
|
|
180
|
+
track-workflow.md § Research log.
|
|
181
|
+
|
|
156
182
|
Any cleanup a layered peer-review process requires (closing its review
|
|
157
183
|
PRs, deleting its pinned branches) is an agent duty, executed when the
|
|
158
184
|
user reports the merge or a later session detects it, per that
|