pi-goal-list-loop-audit 0.34.139 → 0.35.4
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 +105 -93
- package/docs/DESIGN.md +55 -4
- package/docs/RELEASING.md +7 -4
- package/extensions/drafter-model.ts +97 -0
- package/extensions/goal-commands.ts +31 -20
- package/extensions/goal-continuation.ts +61 -11
- package/extensions/goal-heartbeat.ts +40 -8
- package/extensions/goal-loop-auditor-process.ts +5 -6
- package/extensions/goal-loop-auditor.ts +1 -1
- package/extensions/goal-loop-backoff.ts +9 -69
- package/extensions/goal-loop-core.ts +142 -98
- package/extensions/goal-loop-display.ts +76 -78
- package/extensions/goal-loop-forever.ts +23 -4
- package/extensions/goal-loop-subagents.ts +37 -17
- package/extensions/goal-loop.ts +77 -13
- package/extensions/goal-recovery.ts +41 -105
- package/extensions/goal-settings.ts +73 -49
- package/extensions/goal-state.ts +1 -1
- package/extensions/loops/goal-activation.ts +57 -75
- package/extensions/loops/goal-auditor-hooks.ts +159 -112
- package/extensions/loops/goal-list-queue.ts +206 -11
- package/extensions/loops/goal-orchestrator.ts +15 -27
- package/extensions/loops/goal-runtime-globals.ts +5 -4
- package/extensions/loops/goal-session.ts +10 -27
- package/extensions/loops/goal-settings-ui.ts +166 -57
- package/extensions/loops/goal-tools.ts +50 -41
- package/extensions/loops/goal-ui.ts +9 -17
- package/extensions/loops/goal.ts +2 -5
- package/extensions/main-model-recovery.ts +27 -94
- package/extensions/model-selector.ts +2 -1
- package/extensions/quota-retry.ts +99 -81
- package/extensions/reviewer.ts +0 -5
- package/extensions/settings-menu.ts +195 -144
- package/package.json +8 -7
- package/prompts/goal-loop-continuation.md +15 -9
- package/prompts/goal-loop-draft.md +10 -0
- package/prompts/goal-loop-forever-draft.md +8 -0
- package/schemas/goal.schema.json +51 -8
- package/scripts/smoke.sh +20 -7
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ This is a detached process, not a nested session in the main pi process. `comple
|
|
|
10
10
|
|
|
11
11
|
On Windows, npm installs the `pi.cmd` shim rather than a directly executable `pi` binary. The auditor launches it through an explicitly quoted `cmd.exe` boundary; POSIX keeps direct shell-less execution. Protocol snapshots also tolerate transient Windows file-locks without deleting the last valid snapshot first.
|
|
12
12
|
|
|
13
|
-
**Current package version:** `v0.
|
|
13
|
+
**Current package version:** `v0.35.3` — use `/glla version` to see the installed version and the command for comparing it with the registry latest. This checkout may contain unreleased changes; the npm registry is authoritative for published versions.
|
|
14
14
|
|
|
15
15
|
## Why this exists
|
|
16
16
|
|
|
@@ -122,6 +122,26 @@ ONE confirmed batch, not 50 dialogs.
|
|
|
122
122
|
Note: every list item is audited individually, so at hundreds of items the
|
|
123
123
|
audit cost per item is the thing to think about.
|
|
124
124
|
|
|
125
|
+
Long-running judgment is explicit: the drafter preserves the objective and
|
|
126
|
+
verification contract, prefers a durable root-cause fix, allows a safe,
|
|
127
|
+
reversible workaround when it is genuinely useful, and asks only at an actual
|
|
128
|
+
scope/permission/irreversible-action decision boundary. If you want a design
|
|
129
|
+
checkpoint before implementation, mark a goal, list item, or task-plan entry
|
|
130
|
+
with `Agent: Designer` (also accepted: `Role: designer` or `Designer: yes`).
|
|
131
|
+
The managed Designer is read-only; if it is unavailable, the main agent keeps
|
|
132
|
+
the same checkpoint inline.
|
|
133
|
+
|
|
134
|
+
Drafting can use a separate temporary agent configured in `/glla` under the
|
|
135
|
+
**Drafter** tab (`Drafter agent`, `Drafter thinking`, and `Drafter fallback
|
|
136
|
+
agents`).
|
|
137
|
+
The thinking choice is derived from the selected model, applies only while the
|
|
138
|
+
drafting agent is active, and restores the original session thinking level
|
|
139
|
+
after confirmation or interruption. A drafting failure retries the existing
|
|
140
|
+
interview through that agent's fallback chain. Main-agent and auditor-agent
|
|
141
|
+
recovery chains remain separate. Provider recovery is intentionally blind:
|
|
142
|
+
there is no live quota checking or reset inference; the generic retry envelope
|
|
143
|
+
and the optional hourly `:00:30` probe remain the policy.
|
|
144
|
+
|
|
125
145
|
**Drafting is the default for long-running things.** `/goal` and
|
|
126
146
|
`/loop` with no arguments — and any vague `/list` dump — all start a
|
|
127
147
|
grilling turn that ends in a Confirm dialog. For `/loop` specifically, the orchestrator **test-runs the proposed
|
|
@@ -231,13 +251,17 @@ A persistent `glla:` status segment + an above-editor widget show the current
|
|
|
231
251
|
goal/list item/loop at all times: objective, durable state, elapsed time,
|
|
232
252
|
tokens, next task or loop metric, pause reason, and live auditor progress
|
|
233
253
|
during audits. If something is running, you can see it — no command needed.
|
|
254
|
+
Goal cards label their total wall-clock age explicitly; it includes time parked
|
|
255
|
+
for recovery or waiting on a verdict, so it should not be read as active model
|
|
256
|
+
compute. Recovery cards call the timestamp `last host activity` for the same
|
|
257
|
+
reason: a retry/error event is liveness evidence, not proof of useful work.
|
|
234
258
|
|
|
235
259
|
The status bar is the single activity HUD. It uses compact state capsules plus
|
|
236
260
|
an animated pulse waveform so live work is obvious at a glance without turning
|
|
237
261
|
the line into a progress meter. Fresh stream age is the proof of live work:
|
|
238
262
|
|
|
239
263
|
```text
|
|
240
|
-
glla: [▁▂▄▆█▆ LIVE · WORKING] 1m 09s · last stream 11s ago · 3 queued
|
|
264
|
+
glla: [▁▂▄▆█▆ LIVE · WORKING] total 1m 09s · last stream 11s ago · 3 queued
|
|
241
265
|
glla: [QUEUED] 44s · 18 queued
|
|
242
266
|
```
|
|
243
267
|
|
|
@@ -252,81 +276,62 @@ Activity is otherwise intentionally honest:
|
|
|
252
276
|
| `QUEUED` | A continuation is waiting to start; no work is fabricated. |
|
|
253
277
|
| `IDLE` | The durable item remains active, but no recent work is observed. |
|
|
254
278
|
| `auditor …` | A detached, extension-less verifier is queued, running, quiet, or waiting for its verdict. |
|
|
255
|
-
| `
|
|
256
|
-
|
|
257
|
-
## Provider failures: one retry envelope, bounded (v0.34.51)
|
|
279
|
+
| `RECOVERING` | A bounded automatic retry is pending; the status does not guess why the provider failed. |
|
|
258
280
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
`base → 2×base → 4×base → 8×base → 16×base → 5h`, where `base` is the
|
|
264
|
-
`mainModelRetryMinutes` setting (15 minutes by default). A factual provider
|
|
265
|
-
`Retry-After` hint wins when it fits the five-hour probe budget; an over-budget
|
|
266
|
-
hint falls back to the configured ladder. `hourlyQuotaProbe=on` adds a separate
|
|
267
|
-
`:00:30` probe while recovery is parked. The automatic window is 24h, then an
|
|
268
|
-
explicit `/goal resume`/`/list resume`/`/loop resume` starts a fresh window.
|
|
269
|
-
The only failures that do not auto-retry are the ones identified by *positive
|
|
270
|
-
evidence* as futile: context/output-token limits and user aborts
|
|
271
|
-
(`non-recoverable`), plus auditor watchdog timeouts (a hanging verification
|
|
272
|
-
command will hang again — the stored claim waits for an explicit resume).
|
|
273
|
-
With global `autoResume=on`, pending probes survive a session reload.
|
|
274
|
-
|
|
275
|
-
For continuous work, configure up to **10 ordered Main model backups** in
|
|
276
|
-
`/glla` using models from different providers or billing/quota pools when
|
|
277
|
-
possible — another model on the same exhausted plan is not a real fallback.
|
|
278
|
-
The editor is the top row of the **Backups** settings tab (one place for
|
|
279
|
-
main-session backup policy). It shows the actual try order as
|
|
280
|
-
`current → backup 1 → backup 2 …`, shows each configured backup's rank, lets
|
|
281
|
-
**Space** add/remove a backup, and **Tab** enters order mode where **↑/↓**
|
|
282
|
-
moves the highlighted backup (brackets `[` `]` also reorder without leaving
|
|
283
|
-
the list). On an account/plan/billing/auth provider failure, glla calls `setModel` for the
|
|
284
|
-
first eligible backup only; the next supervised turn tests it. If that
|
|
285
|
-
candidate fails, the next backup is tried in order. With the global
|
|
286
|
-
`mainModelFallbackOnRateLimit=on` default, an explicit HTTP 429/request-rate
|
|
287
|
-
failure also walks the ordered chain; set it off to keep 429s on the current
|
|
288
|
-
model with the bounded cadence plus extra post-hour probe. A 429 remains a
|
|
289
|
-
request-rate classification, not a token-limit failure. Forbidden,
|
|
290
|
-
unavailable, and unauthenticated refs are skipped; a successful supervised
|
|
291
|
-
turn clears the episode. The chain
|
|
292
|
-
is global, durable, and its attempted cursor survives reload; after the chain
|
|
293
|
-
is exhausted, bounded recovery probes continue rather than silently abandoning
|
|
294
|
-
work. The Backups tab shows the `N/10` count and the numbered chain.
|
|
295
|
-
|
|
296
|
-
**Quota walls engage fast** (v0.34.57): a surfaced long-lived failure
|
|
297
|
-
(quota / billing / auth) records a 30-minute knowledge window; a send-rearm
|
|
298
|
-
storm inside that window escalates into the recovery envelope after **3
|
|
299
|
-
minutes** of failed sends instead of the generic 15 — a wedge right after a
|
|
300
|
-
quota wall is almost always the same wall. Transient (5xx/stream/network)
|
|
301
|
-
failures never record the signal and keep the fast error ladder. The
|
|
302
|
-
envelope is armed by configuration: an empty `mainModelFallbacks` list means
|
|
303
|
-
"park and probe the same model" rather than switching pools. The
|
|
304
|
-
`mainModelFallbackOnRateLimit=off` setting is the explicit never-switch
|
|
305
|
-
posture for non-empty chains.
|
|
306
|
-
|
|
307
|
-
Classification still exists, but it only *labels*: the card and badge show
|
|
308
|
-
what the provider said (quota wall, billing, rate limit) so the reason is
|
|
309
|
-
diagnosable, and `QUOTA WALL` is only shown when the provider's own words say
|
|
310
|
-
quota — ambiguous prose is never relabeled. The raw provider message stays in
|
|
311
|
-
the ledger/durable state; the card shows the classified reason and recovery
|
|
312
|
-
action. Detached-auditor failures get the same treatment: any infrastructure
|
|
313
|
-
error on a stored completion claim pauses the goal with a durable bounded
|
|
314
|
-
one-shot retry (`auditor retry: …`), and only the plan's 24h horizon stops
|
|
315
|
-
automatic probes.
|
|
316
|
-
|
|
317
|
-
The quota-specific card hides raw provider JSON while preserving it in durable
|
|
318
|
-
state and the ledger:
|
|
281
|
+
Detached-auditor elapsed time keeps advancing between worker events. A long
|
|
282
|
+
tool call or hidden reasoning interval therefore remains visibly timed; after
|
|
283
|
+
three minutes without worker activity the UI changes to `auditor quiet` and
|
|
284
|
+
names the cancellation/recovery path instead of presenting a frozen live card.
|
|
319
285
|
|
|
320
|
-
|
|
321
|
-
glla: ⟦⏳ QUOTA WALL · next probe in 10m 48s⟧ · 1 queued
|
|
322
|
-
├─ QUOTA WALL · Token Plan usage limit · 1 waiting in list
|
|
323
|
-
├─ waiting — nothing for you to do · next probe in 10m 48s
|
|
324
|
-
```
|
|
286
|
+
## Provider failures: aggressive retry envelope, bounded (v0.35.0)
|
|
325
287
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
288
|
+
Error text is **not trusted** to pick a retry policy. The runtime does not
|
|
289
|
+
query or infer provider quota state, and it does not use status codes, billing
|
|
290
|
+
words, rate-limit words, or `Retry-After` hints to choose a branch. Those
|
|
291
|
+
values are retained only as bounded diagnostics. Every recoverable main-model
|
|
292
|
+
failure uses the same durable envelope: an eager 5-second retry, then
|
|
293
|
+
`base → 2×base → 4×base → 8×base → 16×base → 5h`, where `base` is the
|
|
294
|
+
`mainModelRetryMinutes` setting (15 minutes by default). `hourlyRetryProbe=on`
|
|
295
|
+
adds a blind `:00:30` retry after each hour starts, so work can be picked up
|
|
296
|
+
quickly after a possible provider-side change. The automatic window is 24h;
|
|
297
|
+
explicit `/goal resume`, `/list resume`, or `/loop resume` starts a fresh
|
|
298
|
+
window. With global `autoResume=on`, pending retries survive a session reload.
|
|
299
|
+
|
|
300
|
+
Only failures identified by positive evidence as futile avoid automatic retry:
|
|
301
|
+
context/output-token limits and user aborts (`non-recoverable`). Auditor
|
|
302
|
+
watchdog timeouts are also kept separate because rerunning a hanging local
|
|
303
|
+
verification command immediately would repeat the same local failure; the
|
|
304
|
+
stored claim remains available for explicit resume.
|
|
305
|
+
|
|
306
|
+
For continuous work, configure up to **10 ordered Main-agent fallback models**
|
|
307
|
+
in `/glla` using independent model references when possible. The editor is in
|
|
308
|
+
the **Main agent** settings tab (one role per tab, with the current agent,
|
|
309
|
+
thinking level, and fallback chain together). It shows the actual try order as
|
|
310
|
+
`current → fallback 1 → fallback 2 …`, shows each configured fallback's rank,
|
|
311
|
+
lets **Space** add/remove a fallback, and **Tab** enters order mode where
|
|
312
|
+
**↑/↓** moves the highlighted fallback (brackets `[` `]` also reorder without
|
|
313
|
+
leaving the list). Every recoverable provider failure uses the same ordered
|
|
314
|
+
chain: glla calls `setModel` for the first eligible fallback, the next
|
|
315
|
+
supervised turn tests it, and later failures advance left-to-right. Forbidden,
|
|
316
|
+
unavailable, and unauthenticated references are skipped; a successful
|
|
317
|
+
supervised turn clears the episode. The chain is global, durable, and its
|
|
318
|
+
attempted cursor survives reload. After the chain is exhausted, bounded
|
|
319
|
+
retries continue on the active model rather than silently abandoning work.
|
|
320
|
+
The Main agent tab shows the `N/10` count and numbered chain. The Drafter and
|
|
321
|
+
Auditor tabs likewise show each selected model together with its requested
|
|
322
|
+
thinking level; fallback rows show the effective/requested thinking level when
|
|
323
|
+
the model registry exposes the capability map. Press `d` in the settings table
|
|
324
|
+
to toggle the long descriptions and give the model/value column the available
|
|
325
|
+
width.
|
|
326
|
+
|
|
327
|
+
Provider payloads are never copied into chat cards or notifications. A bounded
|
|
328
|
+
diagnostic may remain in the ledger and durable state for forensics, while
|
|
329
|
+
user-facing surfaces use the same generic provider-error label for every
|
|
330
|
+
failure family. The detached auditor follows the same rule: every retriable
|
|
331
|
+
infrastructure failure gets one eager 5-second retry, then stored-claim
|
|
332
|
+
retries at `:00:30` after each hour starts. Its existing 5-attempt/24-hour
|
|
333
|
+
safety envelope prevents an unbounded worker storm; explicit resume starts a
|
|
334
|
+
fresh window.
|
|
330
335
|
|
|
331
336
|
For long-running `/list` work, the card adds a compact queue trail with the
|
|
332
337
|
immediate next item and its truthful wait age while `/list` remains the
|
|
@@ -428,44 +433,48 @@ confirmation is intentionally not bypassed.
|
|
|
428
433
|
Open `/glla` to edit these settings in the table (the rows show effective values and provenance):
|
|
429
434
|
|
|
430
435
|
- Auditor model and thinking level
|
|
431
|
-
- Auditor fallback
|
|
436
|
+
- Auditor fallback agent
|
|
432
437
|
- Notify command, token limit, and wedge-alert minutes
|
|
433
438
|
- Auto-resume, auto-accept drafts, decision popup, and carryover policy
|
|
434
|
-
-
|
|
439
|
+
- Main-agent current model/thinking, fallback models, and recovery cadence in the Main agent tab
|
|
440
|
+
- Drafter agent/thinking/fallback agents in the Drafter tab
|
|
441
|
+
- Auditor agent/thinking/fallback agent in the Auditor tab
|
|
435
442
|
- Forbidden model patterns and switch policy
|
|
436
|
-
- Audit cap/report size, aggressive mode,
|
|
443
|
+
- Audit cap/report size, aggressive mode (ON by default), retry cadence, and
|
|
444
|
+
stall brakes
|
|
437
445
|
|
|
438
446
|
The argument namespace is reserved for actions such as `/glla status`, `/glla
|
|
439
447
|
resume`, `/glla cancel`, `/glla stats`, `/glla audits`, `/glla tooloverride`,
|
|
440
448
|
`/glla fallbacks clear`, and `/glla wipe`. `fallbacks clear` atomically removes
|
|
441
|
-
the global
|
|
449
|
+
the global main-agent fallback chain and cancels any pending fallback switch. Cancel stops the
|
|
442
450
|
active objective; wipe clears all live state while preserving history.
|
|
443
451
|
There is no top-level `/glla key=value` setting syntax.
|
|
444
452
|
|
|
445
453
|
Resolution per key: **project > global > defaults** — EXCEPT `autoResume` and
|
|
446
|
-
|
|
447
|
-
`
|
|
454
|
+
agent recovery settings (`mainModelFallbacks`, `mainModelRetryMinutes`,
|
|
455
|
+
`drafterModel`, `drafterThinkingLevel`, `drafterModelFallbacks`,
|
|
456
|
+
`hourlyRetryProbe`),
|
|
448
457
|
which are **global-only**: per-project opt-ins from old versions
|
|
449
458
|
silently overrode the global hold at launch (the junk-runner incident), so
|
|
450
459
|
the launch-restore gate and the reviewer-enqueue gate read only the global
|
|
451
460
|
file now. Main-session recovery policy is likewise one global chain/cadence
|
|
452
|
-
for the active session. Main-
|
|
453
|
-
failure selects
|
|
454
|
-
time. The
|
|
461
|
+
for the active session. Main-agent fallback models are global and ordered (up to 10): a provider
|
|
462
|
+
failure selects fallback 1, then fallback 2, and so on, one supervised turn at a
|
|
463
|
+
time. The Main agent tab leads with the ordered-chain editor — a multi-select
|
|
455
464
|
picker where Space toggles membership, Tab enters order mode (↑/↓ moves a
|
|
456
465
|
chain row), and clearing the selection removes the global key. Forbidden,
|
|
457
466
|
unavailable, and unauthenticated refs are skipped. When every candidate is
|
|
458
|
-
down, glla
|
|
467
|
+
down, glla stops the current send attempt and uses the configured
|
|
459
468
|
`base → 2×base → 4×base → 8×base → 16×base → 5h` ladder (`base` defaults to
|
|
460
|
-
15m). `
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
the
|
|
465
|
-
work, and requires an explicit
|
|
469
|
+
15m). `hourlyRetryProbe=on` adds a blind :00:30 retry after each hour starts.
|
|
470
|
+
No provider availability or quota check is made before any retry; all
|
|
471
|
+
recoverable failures walk the ordered fallbacks and then continue on the active
|
|
472
|
+
model through the bounded retry policy. Automatic recovery stops at 24h,
|
|
473
|
+
preserves the saved work, and requires an explicit
|
|
466
474
|
`/goal resume`, `/list resume`, or `/loop resume` to start a fresh window. A
|
|
467
|
-
|
|
468
|
-
manual intervention; no blind 50ms resend loop is introduced. The
|
|
475
|
+
provider becoming available within that horizon therefore resumes saved work
|
|
476
|
+
without manual intervention; no blind 50ms resend loop is introduced. The
|
|
477
|
+
detached auditor uses an explicit cascade: primary
|
|
469
478
|
`auditorModel` → optional fallback pin → the pi session model. If a selected
|
|
470
479
|
model fails after launch, the worker retries it once and then advances through
|
|
471
480
|
that same cascade; every candidate is still audited in a detached,
|
|
@@ -532,7 +541,10 @@ in-session warning + your configured notify push, once per interval while
|
|
|
532
541
|
it persists. Tune Wedge alert minutes in the `/glla` settings table (0 = off).
|
|
533
542
|
|
|
534
543
|
Every other wait is bounded too: continuation retries are milliseconds,
|
|
535
|
-
|
|
544
|
+
nudge accounting counts consecutive unproductive turns (substantive text
|
|
545
|
+
or tool calls reset the counter) and pauses the goal / stops the loop after
|
|
546
|
+
3 — provider-error and user-abort turns are exempt (v0.27.3+). Measure
|
|
547
|
+
commands get a 10m
|
|
536
548
|
hard timeout, and the detached auditor aborts after 10m with no activity while no
|
|
537
549
|
an auditor tool is running. A long-running verification tool is allowed to
|
|
538
550
|
finish, but each tool has an independent five-minute ceiling and the worker
|
package/docs/DESIGN.md
CHANGED
|
@@ -189,11 +189,15 @@ architectural decisions that changed the SHAPE of the system:
|
|
|
189
189
|
|
|
190
190
|
## Addendum v0.34.31 (main-session model recovery)
|
|
191
191
|
|
|
192
|
+
> Historical rollout note: this section records the older reason-aware
|
|
193
|
+
> recovery implementation. The active policy is the v0.34.142 addendum below;
|
|
194
|
+
> quota/rate-limit wording no longer selects fallback or retry timing.
|
|
195
|
+
|
|
192
196
|
- **Global recovery policy**: `mainModelFallbacks`,
|
|
193
197
|
`mainModelFallbackOnRateLimit`, `mainModelRetryMinutes`, and
|
|
194
198
|
`hourlyQuotaProbe` are global-only, so the runtime and settings provenance
|
|
195
199
|
cannot disagree about which recovery policy is active.
|
|
196
|
-
- **Ordered global
|
|
200
|
+
- **Ordered global fallback agents**: `mainModelFallbacks` is an explicit ordered list
|
|
197
201
|
of up to 10 `provider/model` references. A provider/quota error selects the
|
|
198
202
|
first eligible authenticated candidate for account/plan/billing/auth failures,
|
|
199
203
|
calls `setModel`, and lets the next supervised turn test it; later failures
|
|
@@ -201,7 +205,7 @@ architectural decisions that changed the SHAPE of the system:
|
|
|
201
205
|
walk the list when global `mainModelFallbackOnRateLimit` is on (default); off
|
|
202
206
|
keeps them on the current model with bounded retry + hourly probe cadence.
|
|
203
207
|
The detached auditor's model cascade remains a separate subsystem. The
|
|
204
|
-
ordered-chain editor
|
|
208
|
+
ordered-chain editor lives in the **Main agent** settings tab: Space toggles
|
|
205
209
|
membership, Tab enters an explicit order mode where ↑/↓ moves a chain row,
|
|
206
210
|
and clearing the list removes the global key. The attempted cursor is durable, so a reload cannot
|
|
207
211
|
restart at an already-failed rung.
|
|
@@ -256,7 +260,7 @@ replacement without delivering a successor `session_start`:
|
|
|
256
260
|
the report surface stays truthful (the AuditProgress/AuditorProgress dual-interface
|
|
257
261
|
rule: display evidence-gates on `unmatchedStarts + unmatchedEnds > 0`).
|
|
258
262
|
- **Uniform retry envelope, no text-trust** (v0.34.51 historical baseline): error
|
|
259
|
-
text was not trusted to pick a retry policy. The current ordered-
|
|
263
|
+
text was not trusted to pick a retry policy. The current ordered-fallback policy
|
|
260
264
|
supersedes that baseline: account/plan/billing/auth failures may walk the configured
|
|
261
265
|
chain, while explicit HTTP 429/request-rate failures walk it when
|
|
262
266
|
`mainModelFallbackOnRateLimit` is on (default), or remain on the current model
|
|
@@ -268,6 +272,10 @@ replacement without delivering a successor `session_start`:
|
|
|
268
272
|
|
|
269
273
|
## Addendum v0.34.57 (quota walls engage recovery fast)
|
|
270
274
|
|
|
275
|
+
> Historical rollout note: the knowledge-window and quota-specific branches
|
|
276
|
+
> described here are retained for design history only and are not active in
|
|
277
|
+
> v0.34.142.
|
|
278
|
+
|
|
271
279
|
- **Knowledge-window escalation**: a surfaced long-lived failure (quota /
|
|
272
280
|
billing / auth) records a 30-minute knowledge window. A send-rearm storm
|
|
273
281
|
inside that window escalates into the recovery envelope after 3 minutes of
|
|
@@ -280,7 +288,7 @@ replacement without delivering a successor `session_start`:
|
|
|
280
288
|
- **Armed by configuration**: the envelope is inert without
|
|
281
289
|
`mainModelFallbacks` (rotation) — an empty list means "park and probe the
|
|
282
290
|
same model" instead of switching pools. When the list is non-empty, the
|
|
283
|
-
runtime tries one eligible
|
|
291
|
+
runtime tries one eligible fallback at a time in persisted order, skips
|
|
284
292
|
forbidden/unavailable refs, and parks only after the ordered chain is
|
|
285
293
|
exhausted. Explicit HTTP 429/rate-limit errors remain request-rate signals,
|
|
286
294
|
not token-limit labels; the global `mainModelFallbackOnRateLimit` switch
|
|
@@ -317,6 +325,49 @@ replacement without delivering a successor `session_start`:
|
|
|
317
325
|
remains held unless the existing Auto-resume policy or a validated lifecycle
|
|
318
326
|
handoff supplies consent. `/goal resume` still starts a direct fresh audit.
|
|
319
327
|
|
|
328
|
+
## Addendum v0.34.142 (generic provider recovery)
|
|
329
|
+
|
|
330
|
+
- **No quota availability check exists in the live policy**: provider text,
|
|
331
|
+
status codes, billing/rate-limit words, and upstream retry hints do not
|
|
332
|
+
select a recovery branch, fallback gate, or delay. They may remain as
|
|
333
|
+
bounded diagnostics for forensics and redaction only.
|
|
334
|
+
- **One retry envelope covers every recoverable provider failure**: the first
|
|
335
|
+
retry is eager at 5 seconds, later retries use the configured bounded
|
|
336
|
+
ladder, and the optional `hourlyRetryProbe` adds a blind `:00:30` retry
|
|
337
|
+
after every hour starts. Main-model recovery and detached-auditor recovery
|
|
338
|
+
use this same reason-agnostic rule, with existing context/user-abort and
|
|
339
|
+
safety-horizon exceptions.
|
|
340
|
+
- **Legacy state is inert**: old `quota-waiting` phases, quota-named retry
|
|
341
|
+
counters, and provider-hint fields are accepted only long enough to load
|
|
342
|
+
and normalize old files. Canonical persisted state uses `retry-waiting`,
|
|
343
|
+
`retryAttempts`, `retryFirstAt`, and `retryUntil`.
|
|
344
|
+
|
|
345
|
+
## Addendum v0.35.0 (long-running judgment, Designer, and drafting chain)
|
|
346
|
+
|
|
347
|
+
- **Judgment is a prompt-level contract**: drafting and continuation preserve
|
|
348
|
+
the objective and verification contract, prefer durable root-cause fixes,
|
|
349
|
+
allow only safe/reversible/testable in-scope workarounds, and ask one focused
|
|
350
|
+
question only at a genuine scope, priority, permission, or irreversible-action
|
|
351
|
+
boundary. The unattended fallback is explicit and never infers provider or
|
|
352
|
+
quota state.
|
|
353
|
+
- **Designer routing is explicit, persisted, and read-only**: `Agent: Designer`,
|
|
354
|
+
`Role: designer`, and `Designer: yes` are declarations rather than natural
|
|
355
|
+
language classification. The role is carried by goals, queue items, and task
|
|
356
|
+
plans; continuation injects the hand-off; a managed `Designer.md` uses only
|
|
357
|
+
read/search tools; unavailable role/provider falls back to an inline design
|
|
358
|
+
checkpoint.
|
|
359
|
+
- **Drafting owns a temporary agent lease**: the `/goal`, `/list`, and `/loop`
|
|
360
|
+
interviews resolve a separate primary/fallback chain, select a model-specific
|
|
361
|
+
thinking level, retry the existing interview after generic provider errors,
|
|
362
|
+
and restore the original model and thinking level after confirmation or
|
|
363
|
+
interruption. A current-session last resort is bounded and does not enter
|
|
364
|
+
main-goal recovery. A generation fence and serialized restore prevent
|
|
365
|
+
stale-session or overlapping-draft agent changes.
|
|
366
|
+
- **Host replacement remains host-owned**: Pi event contexts do not expose the
|
|
367
|
+
command-only `newSession`/`fork`/`switchSession` operations. glla therefore
|
|
368
|
+
persists the work and truthfully asks for `/new` when no replacement boundary
|
|
369
|
+
arrives; the proposed event-safe host API is recorded in the audit docs.
|
|
370
|
+
|
|
320
371
|
## Addendum v0.4.0 (completion)
|
|
321
372
|
|
|
322
373
|
- **Auditor compaction enabled** (flaw #3 — the last open one). Safety:
|
package/docs/RELEASING.md
CHANGED
|
@@ -18,10 +18,13 @@ the repository.
|
|
|
18
18
|
## Release checklist
|
|
19
19
|
|
|
20
20
|
Accumulated changes since the last release live under an `## Unreleased`
|
|
21
|
-
section at the top of `CHANGELOG.md
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
section at the top of `CHANGELOG.md`; each milestone gets its own
|
|
22
|
+
`## <version> — <one-line title> (<date>)` header plus `###` topic
|
|
23
|
+
subsections (e.g. `## 0.35.3 — live auditor clock and clearer recovery
|
|
24
|
+
timing (2026-08-15)`). The release commit renames the `Unreleased` section
|
|
25
|
+
to the released version. Do not invent version headers for work that was
|
|
26
|
+
never tagged — untagged work stays under `Unreleased` until the release
|
|
27
|
+
commit.
|
|
25
28
|
|
|
26
29
|
```bash
|
|
27
30
|
npm version <major.minor.patch> --no-git-tag-version
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Drafting-only model resolution and fallback selection.
|
|
2
|
+
//
|
|
3
|
+
// Drafting runs in the main pi session, so the selected model is a temporary
|
|
4
|
+
// lease: the caller must restore the original session model when drafting
|
|
5
|
+
// ends. This module only resolves an ordered candidate list; lifecycle and
|
|
6
|
+
// retries remain in goal-list-queue.ts.
|
|
7
|
+
|
|
8
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
|
|
10
|
+
import { isForbiddenModel } from "./goal-loop-core.js";
|
|
11
|
+
import { MAX_MAIN_MODEL_FALLBACKS, modelRef, normalizeMainModelFallbackRefs } from "./main-model-recovery.js";
|
|
12
|
+
import { ModelSelector } from "./model-selector.js";
|
|
13
|
+
import type { Settings } from "./goal-settings.js";
|
|
14
|
+
|
|
15
|
+
export const MAX_DRAFTER_FALLBACKS = MAX_MAIN_MODEL_FALLBACKS;
|
|
16
|
+
|
|
17
|
+
export interface DrafterModelCandidate {
|
|
18
|
+
ref: string;
|
|
19
|
+
model: any;
|
|
20
|
+
via: "configured" | "session-last-resort";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DrafterModelResolution {
|
|
24
|
+
configuredRefs: string[];
|
|
25
|
+
candidates: DrafterModelCandidate[];
|
|
26
|
+
selected?: DrafterModelCandidate;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Resolve a provider/model ref without making a provider request. */
|
|
30
|
+
export function resolveDrafterModelRef(ctx: Pick<ExtensionContext, "modelRegistry">, ref: string): any | undefined {
|
|
31
|
+
const trimmed = ref.trim();
|
|
32
|
+
if (!trimmed) return undefined;
|
|
33
|
+
const slash = trimmed.indexOf("/");
|
|
34
|
+
try {
|
|
35
|
+
if (slash > 0) {
|
|
36
|
+
const model = ctx.modelRegistry.find(trimmed.slice(0, slash), trimmed.slice(slash + 1));
|
|
37
|
+
if (!model || !ctx.modelRegistry.hasConfiguredAuth(model)) return undefined;
|
|
38
|
+
return model;
|
|
39
|
+
}
|
|
40
|
+
return ctx.modelRegistry
|
|
41
|
+
.getAvailable()
|
|
42
|
+
.filter((candidate: any) => candidate.id === trimmed || candidate.name === trimmed)
|
|
43
|
+
.find((candidate: any) => ctx.modelRegistry.hasConfiguredAuth(candidate));
|
|
44
|
+
} catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the dedicated drafter chain. The current session model is always a
|
|
51
|
+
* final in-process fallback, even when every configured candidate is missing
|
|
52
|
+
* auth or forbidden. No error text, quota state, or retry hint is inspected.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveDrafterModel(ctx: ExtensionContext, settings: Pick<Settings, "drafterModel" | "drafterModelFallbacks" | "forbiddenModels">): DrafterModelResolution {
|
|
55
|
+
const primary = typeof settings.drafterModel === "string" ? settings.drafterModel.trim() : "";
|
|
56
|
+
const configuredRefs = normalizeMainModelFallbackRefs([
|
|
57
|
+
...(primary ? [primary] : []),
|
|
58
|
+
...normalizeMainModelFallbackRefs(settings.drafterModelFallbacks),
|
|
59
|
+
]).slice(0, MAX_DRAFTER_FALLBACKS);
|
|
60
|
+
const currentRef = modelRef(ctx.model);
|
|
61
|
+
const forbidden = (ref: string) => isForbiddenModel(ref, settings.forbiddenModels);
|
|
62
|
+
const selector = new ModelSelector({
|
|
63
|
+
getChain: () => configuredRefs,
|
|
64
|
+
resolve: (ref) => resolveDrafterModelRef(ctx, ref),
|
|
65
|
+
isForbidden: forbidden,
|
|
66
|
+
});
|
|
67
|
+
const attempted: string[] = [];
|
|
68
|
+
const candidates: DrafterModelCandidate[] = [];
|
|
69
|
+
|
|
70
|
+
// ModelSelector deliberately skips the current model so the main recovery
|
|
71
|
+
// walker never selects the model that just failed. Drafting is different:
|
|
72
|
+
// its configured primary may intentionally be the current session model,
|
|
73
|
+
// and that primary still needs a lease so its later fallbacks remain
|
|
74
|
+
// available if the first drafting turn fails.
|
|
75
|
+
const configuredPrimary = configuredRefs[0];
|
|
76
|
+
if (
|
|
77
|
+
configuredPrimary &&
|
|
78
|
+
currentRef &&
|
|
79
|
+
configuredPrimary.toLowerCase() === currentRef.toLowerCase() &&
|
|
80
|
+
!forbidden(configuredPrimary) &&
|
|
81
|
+
ctx.model
|
|
82
|
+
) {
|
|
83
|
+
candidates.push({ ref: configuredPrimary, model: ctx.model, via: "configured" });
|
|
84
|
+
attempted.push(configuredPrimary);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (;;) {
|
|
88
|
+
const selected = selector.selectNextValid({ kind: "drafter" }, currentRef, attempted);
|
|
89
|
+
if (!("model" in selected) || typeof selected.ref !== "string") break;
|
|
90
|
+
attempted.push(selected.ref);
|
|
91
|
+
candidates.push({ ref: selected.ref, model: selected.model, via: "configured" });
|
|
92
|
+
}
|
|
93
|
+
if (ctx.model && currentRef && !candidates.some((candidate) => candidate.ref.toLowerCase() === currentRef.toLowerCase())) {
|
|
94
|
+
candidates.push({ ref: currentRef, model: ctx.model, via: "session-last-resort" });
|
|
95
|
+
}
|
|
96
|
+
return { configuredRefs, candidates, selected: candidates[0] };
|
|
97
|
+
}
|