@yaag/runtime 0.6.2 → 0.7.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/package.json +1 -1
- package/src/agent/agent.ts +38 -2
- package/src/agent/define-agent.ts +13 -3
- package/src/agent/spawn-request.ts +64 -0
- package/src/agent/spawn.ts +84 -63
- package/src/ask/ask-exchange-events.ts +10 -1
- package/src/ask/ask-exchange-options.ts +13 -0
- package/src/ask/ask-exchange.ts +77 -9
- package/src/ask/index.ts +1 -0
- package/src/cassette/cassette-replay.ts +23 -4
- package/src/cassette/recording-transport.ts +7 -0
- package/src/cassette/replay-divergence.ts +75 -19
- package/src/cassette/replay-transport.ts +8 -1
- package/src/cassette/resume-transport.ts +14 -1
- package/src/errors.ts +55 -2
- package/src/events.ts +19 -0
- package/src/index.ts +2 -0
- package/src/model/index.ts +18 -0
- package/src/model/model-error-history.ts +36 -0
- package/src/model/model-failure.ts +78 -0
- package/src/model/model-fallback.ts +15 -0
- package/src/model/model-match.ts +99 -0
- package/src/model/model-resolution.ts +44 -6
- package/src/model/model-swap.ts +81 -0
- package/src/model/recorded-resolution.ts +61 -0
- package/src/model/resolution-loop.ts +115 -0
- package/src/summary/index.ts +1 -0
- package/src/summary/summary-agent.ts +9 -1
- package/src/summary/summary-fallbacks.ts +50 -0
- package/src/summary/summary.ts +12 -0
- package/src/transport/fake-transport.ts +57 -1
- package/src/transport/index.ts +4 -0
- package/src/transport/live-transport.ts +37 -4
- package/src/transport/stderr-tail.ts +32 -0
- package/src/transport/transport.ts +11 -0
- package/src/types.ts +28 -5
- package/src/wire-constants.ts +3 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Bound on the kept stderr tail, so a chatty Agent cannot grow the buffer. */
|
|
2
|
+
export const STDERR_TAIL_BYTES = 4_096;
|
|
3
|
+
/** Bound on the diagnostic folded into a failure message, so it stays readable. */
|
|
4
|
+
export const STDERR_MESSAGE_CHARS = 300;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lines pi prints that are warnings, not the reason a process died.
|
|
8
|
+
* `No models match pattern "<p>"` is the dangerous one: it classifies as
|
|
9
|
+
* `not_found` (ADR-0037), so an unfiltered tail would turn an unrelated startup
|
|
10
|
+
* failure of the same Agent into a Model Resolution trigger.
|
|
11
|
+
*/
|
|
12
|
+
const WARNINGS: readonly RegExp[] = [/no models match pattern/i, /^\s*warn(ing)?\b/i];
|
|
13
|
+
|
|
14
|
+
/** Appends one chunk to a stderr tail, keeping only the last bounded window. */
|
|
15
|
+
export function appendStderrTail(tail: string, chunk: string): string {
|
|
16
|
+
return (tail + chunk).slice(-STDERR_TAIL_BYTES);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The exit diagnostic of a stderr tail as a message suffix, or "" when pi
|
|
21
|
+
* printed nothing fatal. Warning lines are dropped, the rest is collapsed to one
|
|
22
|
+
* line and capped, so a failure message stays readable.
|
|
23
|
+
*/
|
|
24
|
+
export function stderrDiagnostic(tail: string): string {
|
|
25
|
+
const lines = tail
|
|
26
|
+
.split("\n")
|
|
27
|
+
.map((line) => line.trim())
|
|
28
|
+
.filter((line) => line !== "" && !WARNINGS.some((pattern) => pattern.test(line)));
|
|
29
|
+
const text = lines.join(" ").replace(/\s+/g, " ").trim();
|
|
30
|
+
if (text === "") return "";
|
|
31
|
+
return `: ${text.length > STDERR_MESSAGE_CHARS ? text.slice(-STDERR_MESSAGE_CHARS) : text}`;
|
|
32
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CanonicalJsonObject, ReportedResult } from "../ask-contract/index.ts";
|
|
2
2
|
import type { AskLimitOutcome, AskStalledOutcome } from "../errors.ts";
|
|
3
|
+
import type { RecordedSpawnSelection } from "../model/index.ts";
|
|
3
4
|
import type { AskOptions, ResolvedSpawnOptions, ThinkingLevel } from "../types.ts";
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -209,4 +210,14 @@ export type TransportStartupObserver = (startup: TransportStartup) => void;
|
|
|
209
210
|
/** How the layer above obtains transports. Swapped wholesale for replay. */
|
|
210
211
|
export interface TransportFactory {
|
|
211
212
|
open(options: OpenOptions, observeStartup?: TransportStartupObserver): Promise<AgentTransport>;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* The resolved selection this factory recorded for the Agent it would open
|
|
216
|
+
* next, so a Cassette-backed spawn adopts the recorded outcome instead of
|
|
217
|
+
* re-running Model Resolution (ADR-0037, ADR-0038, ADR-0039).
|
|
218
|
+
*
|
|
219
|
+
* A pure peek: it must not advance the factory's spawn cursor. Live factories
|
|
220
|
+
* record nothing and omit it.
|
|
221
|
+
*/
|
|
222
|
+
recordedSpawn?(options: OpenOptions): RecordedSpawnSelection | undefined;
|
|
212
223
|
}
|
package/src/types.ts
CHANGED
|
@@ -12,7 +12,10 @@ export interface SpawnOptions {
|
|
|
12
12
|
*
|
|
13
13
|
* An array is an ordered fallback list and a function picks the next candidate
|
|
14
14
|
* from the failures so far. Any resolved pattern may carry an inline thinking
|
|
15
|
-
* suffix (`"opus-5:medium"`), which wins over `thinking`.
|
|
15
|
+
* suffix (`"opus-5:medium"`), which wins over `thinking`. Each attempt settles
|
|
16
|
+
* the model first, then the thinking level for that model. yaag starts a new
|
|
17
|
+
* attempt only when pi reports `not_found`, `auth`, or `rate_limited`. See
|
|
18
|
+
* `ModelSpec` and `ModelResolver` for the termination rules (ADR-0037).
|
|
16
19
|
*/
|
|
17
20
|
readonly model?: ModelSpec;
|
|
18
21
|
/** Replaces the default system prompt (`pi --system-prompt`). */
|
|
@@ -20,7 +23,8 @@ export interface SpawnOptions {
|
|
|
20
23
|
/**
|
|
21
24
|
* Sets pi's thinking level; omission preserves pi's default. A function picks
|
|
22
25
|
* the level from the settled model, and is not consulted for a model pattern
|
|
23
|
-
* that carries an inline thinking suffix.
|
|
26
|
+
* that carries an inline thinking suffix. The resolver runs again for each
|
|
27
|
+
* attempt, with the model that settled for that attempt (ADR-0037).
|
|
24
28
|
*/
|
|
25
29
|
readonly thinking?: ThinkingSpec;
|
|
26
30
|
/** Appends text to pi's system prompt (`pi --append-system-prompt`). */
|
|
@@ -59,7 +63,12 @@ export interface SpawnOptions {
|
|
|
59
63
|
readonly worktree?: boolean;
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Spawn options after Model Resolution has settled one model and thinking level.
|
|
68
|
+
*
|
|
69
|
+
* This is the settled shape, and it is what the Cassette identity hashes
|
|
70
|
+
* (ADR-0039).
|
|
71
|
+
*/
|
|
63
72
|
export interface ResolvedSpawnOptions extends Omit<SpawnOptions, "model" | "thinking"> {
|
|
64
73
|
readonly model?: string;
|
|
65
74
|
readonly thinking?: ThinkingLevel;
|
|
@@ -84,6 +93,11 @@ export interface SpawnOverrides {
|
|
|
84
93
|
* Agent, permits one further turn (or a fixed duration grace), then aborts and
|
|
85
94
|
* rejects with `ASK_LIMIT` if it has not settled. This leaves the Handle alive.
|
|
86
95
|
* `timeoutMs` is independent: it kills the Agent and rejects with `ASK_TIMEOUT`.
|
|
96
|
+
*
|
|
97
|
+
* A model failure inside an Ask starts Model Fallback and retries the Ask
|
|
98
|
+
* (ADR-0038). Each attempt gets fresh soft limits, a fresh Stall Watchdog and a
|
|
99
|
+
* fresh output collector. `timeoutMs` is the exception: it is the hard ceiling
|
|
100
|
+
* of the whole Ask, and every attempt shares one deadline.
|
|
87
101
|
*/
|
|
88
102
|
export interface AskOptions {
|
|
89
103
|
/** Reject and kill the Agent if it has not settled in time. Unset = no bound. */
|
|
@@ -106,7 +120,10 @@ export interface AskOptions {
|
|
|
106
120
|
* live Ask by default (ADR-0029). On expiry yaag probes the Agent and either
|
|
107
121
|
* recovers a missed settlement or rejects with `ASK_STALLED`. Omission uses
|
|
108
122
|
* the 10-minute default. `false`, and any value that is not above zero,
|
|
109
|
-
* disable the watchdog for this Ask.
|
|
123
|
+
* disable the watchdog for this Ask. `ASK_STALLED` is a generic failure: it
|
|
124
|
+
* never starts Model Fallback. If the silence budget ends the Ask before pi
|
|
125
|
+
* reports a model failure, the Ask fails `ASK_STALLED` and no swap happens
|
|
126
|
+
* (ADR-0029).
|
|
110
127
|
*/
|
|
111
128
|
readonly stallMs?: number | false;
|
|
112
129
|
/** Per-Ask replacement for the runtime's wrap-up steering message. */
|
|
@@ -141,7 +158,10 @@ export interface Handle {
|
|
|
141
158
|
readonly cwd: string;
|
|
142
159
|
/** Fresh branch for a worktree Agent; undefined for ordinary Agents. */
|
|
143
160
|
readonly branch: string | undefined;
|
|
144
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* Model id as reported by the Agent's own `get_state` — not the requested
|
|
163
|
+
* pattern. A mid-Ask model swap updates it (ADR-0038).
|
|
164
|
+
*/
|
|
145
165
|
readonly model: string;
|
|
146
166
|
|
|
147
167
|
/**
|
|
@@ -155,6 +175,9 @@ export interface Handle {
|
|
|
155
175
|
* (default 3) and then rejects recoverably with `ASK_INVALID_OUTPUT` after an
|
|
156
176
|
* abort settlement; a reported value the schema rejects fails the same way
|
|
157
177
|
* without a correction. These recoverable outcomes leave the Handle reusable.
|
|
178
|
+
* A retry after a Model Fallback discards the result the failed attempt
|
|
179
|
+
* reported, and arms the collector again, so a stale result cannot settle the
|
|
180
|
+
* retried Ask (ADR-0032, ADR-0038).
|
|
158
181
|
* A concurrent call rejects with `AGENT_BUSY`.
|
|
159
182
|
*/
|
|
160
183
|
ask<Schema extends TSchema>(
|
package/src/wire-constants.ts
CHANGED
|
@@ -20,5 +20,8 @@ export const NODE_GIST_MAX_CHARS = 120;
|
|
|
20
20
|
/** Maximum Nested Nodes the Summary keeps per Agent; past it, exited nodes prune oldest-first. */
|
|
21
21
|
export const AGENT_NODE_TABLE_MAX = 64;
|
|
22
22
|
|
|
23
|
+
/** Maximum Model Resolution fallbacks the Summary keeps per Agent; past it, the oldest prune. */
|
|
24
|
+
export const AGENT_MODEL_FALLBACK_MAX = 16;
|
|
25
|
+
|
|
23
26
|
/** Prefix marking that the oldest pending Ask output was dropped to fit the wire cap. */
|
|
24
27
|
export const ASK_OUTPUT_TRUNCATION_MARKER = "[…output truncated…]";
|