@yaag/runtime 0.1.4 → 0.2.1
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.ts +11 -3
- package/src/ask-contract-identity.ts +23 -5
- package/src/ask-exchange-events.ts +14 -1
- package/src/ask-exchange-options.ts +7 -2
- package/src/ask-exchange.ts +198 -26
- package/src/ask-hash.ts +7 -3
- package/src/ask-limit.ts +27 -11
- package/src/ask-output-steering.ts +1 -3
- package/src/ask-output.ts +20 -4
- package/src/ask-turn.ts +11 -0
- package/src/cassette-loader.ts +24 -0
- package/src/cassette-replay.ts +76 -7
- package/src/cassette-schema.ts +17 -2
- package/src/cassette.ts +10 -9
- package/src/checkpoint-flush.ts +101 -0
- package/src/connection.ts +20 -0
- package/src/define-agent.ts +11 -5
- package/src/errors.ts +11 -2
- package/src/events.ts +29 -3
- package/src/fake-transport.ts +55 -0
- package/src/frame-queue.ts +5 -0
- package/src/index.ts +11 -1
- package/src/model-resolution.ts +119 -0
- package/src/model-suffix.ts +24 -0
- package/src/pi-state.ts +63 -8
- package/src/recording-transport.ts +8 -8
- package/src/replay-divergence.ts +1 -0
- package/src/replay-transport.ts +4 -0
- package/src/report-result-extension.ts +128 -0
- package/src/report-result-output.ts +73 -0
- package/src/report-result-steering.ts +83 -0
- package/src/report-result.ts +122 -0
- package/src/resume-transport.ts +26 -8
- package/src/run-checkpoint.ts +93 -41
- package/src/run.ts +86 -32
- package/src/spawn.ts +29 -4
- package/src/stall-watchdog.ts +193 -0
- package/src/summary-agent.ts +11 -2
- package/src/summary.ts +23 -2
- package/src/thinking-level.ts +32 -0
- package/src/transport.ts +43 -8
- package/src/types.ts +50 -14
- package/src/validation-errors.ts +10 -4
package/src/transport.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CanonicalJsonObject } from "./ask-contract-identity.ts";
|
|
2
2
|
import type { AskLimitOutcome, AskStalledOutcome } from "./errors.ts";
|
|
3
|
-
import type {
|
|
3
|
+
import type { ReportedResult } from "./report-result.ts";
|
|
4
|
+
import type { AskOptions, ResolvedSpawnOptions, ThinkingLevel } from "./types.ts";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* The one seam of the runtime (ticket 04). An AgentTransport represents a whole
|
|
@@ -34,7 +35,7 @@ export interface AgentStats {
|
|
|
34
35
|
export interface AskMarkerContext {
|
|
35
36
|
readonly prompt: string;
|
|
36
37
|
readonly spawn: Pick<
|
|
37
|
-
|
|
38
|
+
ResolvedSpawnOptions,
|
|
38
39
|
| "cwd"
|
|
39
40
|
| "model"
|
|
40
41
|
| "systemPrompt"
|
|
@@ -48,7 +49,7 @@ export interface AskMarkerContext {
|
|
|
48
49
|
>;
|
|
49
50
|
readonly ask: Pick<
|
|
50
51
|
AskOptions,
|
|
51
|
-
"maxTurns" | "maxToolCalls" | "maxDurationMs" | "idleMs" | "wrapUpPrompt"
|
|
52
|
+
"maxTurns" | "maxToolCalls" | "maxDurationMs" | "idleMs" | "stallMs" | "wrapUpPrompt"
|
|
52
53
|
> & {
|
|
53
54
|
readonly outputSchema?: CanonicalJsonObject;
|
|
54
55
|
readonly maxSteers?: number;
|
|
@@ -80,6 +81,18 @@ export interface AskInvalidOutputPlayback {
|
|
|
80
81
|
readonly steeringEfforts: number;
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
/** What one live Ask produced, reported to its transport when the Ask finishes. */
|
|
85
|
+
export interface AskCompletion {
|
|
86
|
+
/** Limit outcome, present only when the Ask rejected with ASK_LIMIT. */
|
|
87
|
+
readonly limit?: AskLimitOutcome;
|
|
88
|
+
/** Stalled outcome, present only when the Ask rejected with ASK_STALLED. */
|
|
89
|
+
readonly stalled?: AskStalledOutcome;
|
|
90
|
+
/** Invalid structured-output result, present only when it surfaced. */
|
|
91
|
+
readonly invalidOutput?: AskInvalidOutputPlayback;
|
|
92
|
+
/** The Stall Watchdog settled this Ask from observed state (ADR-0029). */
|
|
93
|
+
readonly recovered?: true;
|
|
94
|
+
}
|
|
95
|
+
|
|
83
96
|
/** Presence identifies Cassette playback, including recorded successful Asks. */
|
|
84
97
|
export interface AskPlayback {
|
|
85
98
|
/** Limit outcome recorded for this Ask, if it rejected with ASK_LIMIT. */
|
|
@@ -88,8 +101,26 @@ export interface AskPlayback {
|
|
|
88
101
|
readonly stalled?: AskStalledOutcome;
|
|
89
102
|
/** Invalid structured-output result recorded for this Ask, if it surfaced. */
|
|
90
103
|
readonly outcome?: AskInvalidOutputPlayback;
|
|
104
|
+
/**
|
|
105
|
+
* The result the recorded Ask reported through `report_result`, read from its
|
|
106
|
+
* frames when the Cassette holds one. Reading it here keeps playback a pure
|
|
107
|
+
* function of the Cassette instead of a race with the replayed frame stream.
|
|
108
|
+
*/
|
|
109
|
+
readonly reported?: ReportedResult;
|
|
91
110
|
/** Whether recorded correction history has an abort settlement after final text. */
|
|
92
111
|
readonly awaitsAbortSettlement?: true;
|
|
112
|
+
/**
|
|
113
|
+
* The recorded Ask settled through Stall Watchdog recovery, so no
|
|
114
|
+
* `agent_settled` frame exists: playback settles on the terminal assistant
|
|
115
|
+
* `message_end` instead.
|
|
116
|
+
*/
|
|
117
|
+
readonly recovered?: true;
|
|
118
|
+
/**
|
|
119
|
+
* False when the recorded Ask holds no `agent_settled` frame. Playback then
|
|
120
|
+
* surfaces the recorded outcome instead of waiting for a settlement that the
|
|
121
|
+
* Cassette does not contain.
|
|
122
|
+
*/
|
|
123
|
+
readonly settles?: false;
|
|
93
124
|
}
|
|
94
125
|
|
|
95
126
|
/** One Agent, as the layer above sees it. */
|
|
@@ -110,11 +141,15 @@ export interface AgentTransport {
|
|
|
110
141
|
beginAsk(marker: AskMarker): AskPlayback | undefined;
|
|
111
142
|
|
|
112
143
|
/** Reports surfaced live outcomes; replay ignores completion. */
|
|
113
|
-
finishAsk(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
144
|
+
finishAsk(completion: AskCompletion): void;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The extraction policy recorded for the Ask at `index`, when a Cassette
|
|
148
|
+
* backs it. An Ask recorded under an older policy keeps that policy, so its
|
|
149
|
+
* identity and its settlement behavior stay the ones it was recorded with
|
|
150
|
+
* (ADR-0032). Live transports have nothing recorded and omit this method.
|
|
151
|
+
*/
|
|
152
|
+
recordedExtractionPolicy?(index: number): string | undefined;
|
|
118
153
|
|
|
119
154
|
/**
|
|
120
155
|
* Shut the Agent down and report its cost. Idempotent.
|
package/src/types.ts
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
import type { Static, TSchema } from "typebox";
|
|
2
|
+
import type { ModelSpec, ThinkingSpec } from "./model-resolution.ts";
|
|
3
|
+
import type { ThinkingLevel } from "./thinking-level.ts";
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
5
|
+
export type { ThinkingLevel } from "./thinking-level.ts";
|
|
5
6
|
|
|
6
7
|
/** Options for spawning one Agent (ADR-0001, ADR-0009, ADR-0026). */
|
|
7
8
|
export interface SpawnOptions {
|
|
8
9
|
/** Working directory. Defaults to the Orchestrator's cwd. */
|
|
9
10
|
readonly cwd?: string;
|
|
10
|
-
/**
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Model pattern, e.g. "anthropic/claude-haiku-4". Unset inherits the user's default.
|
|
13
|
+
*
|
|
14
|
+
* An array is an ordered fallback list and a function picks the next candidate
|
|
15
|
+
* from the failures so far. Any resolved pattern may carry an inline thinking
|
|
16
|
+
* suffix (`"opus-5:medium"`), which wins over `thinking`.
|
|
17
|
+
*/
|
|
18
|
+
readonly model?: ModelSpec;
|
|
12
19
|
/** Replaces the default system prompt (`pi --system-prompt`). */
|
|
13
20
|
readonly systemPrompt?: string;
|
|
14
|
-
/**
|
|
15
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Sets pi's thinking level; omission preserves pi's default. A function picks
|
|
23
|
+
* the level from the settled model, and is not consulted for a model pattern
|
|
24
|
+
* that carries an inline thinking suffix.
|
|
25
|
+
*/
|
|
26
|
+
readonly thinking?: ThinkingSpec;
|
|
16
27
|
/** Appends text to pi's system prompt (`pi --append-system-prompt`). */
|
|
17
28
|
readonly appendSystemPrompt?: string;
|
|
18
29
|
/**
|
|
@@ -49,6 +60,12 @@ export interface SpawnOptions {
|
|
|
49
60
|
readonly worktree?: boolean;
|
|
50
61
|
}
|
|
51
62
|
|
|
63
|
+
/** Spawn options after Model Resolution has settled one model and thinking level. */
|
|
64
|
+
export interface ResolvedSpawnOptions extends Omit<SpawnOptions, "model" | "thinking"> {
|
|
65
|
+
readonly model?: string;
|
|
66
|
+
readonly thinking?: ThinkingLevel;
|
|
67
|
+
}
|
|
68
|
+
|
|
52
69
|
/** Topology-only fields that may change when spawning an Agent Definition. */
|
|
53
70
|
export interface SpawnOverrides {
|
|
54
71
|
/** Log and event label. Defaults to the definition's name; duplicates are suffixed. */
|
|
@@ -85,15 +102,32 @@ export interface AskOptions {
|
|
|
85
102
|
* idle detection (ADR-0020).
|
|
86
103
|
*/
|
|
87
104
|
readonly idleMs?: number;
|
|
105
|
+
/**
|
|
106
|
+
* Silence budget in milliseconds for the Stall Watchdog, which guards every
|
|
107
|
+
* live Ask by default (ADR-0029). On expiry yaag probes the Agent and either
|
|
108
|
+
* recovers a missed settlement or rejects with `ASK_STALLED`. Omission uses
|
|
109
|
+
* the 10-minute default. `false`, and any value that is not above zero,
|
|
110
|
+
* disable the watchdog for this Ask.
|
|
111
|
+
*/
|
|
112
|
+
readonly stallMs?: number | false;
|
|
88
113
|
/** Per-Ask replacement for the runtime's wrap-up steering message. */
|
|
89
114
|
readonly wrapUpPrompt?: string;
|
|
90
115
|
}
|
|
91
116
|
|
|
92
117
|
/** Ask options that require a schema and preserve its inferred successful result. */
|
|
93
118
|
export interface StructuredAskOptions<Schema extends TSchema> extends AskOptions {
|
|
94
|
-
/**
|
|
119
|
+
/**
|
|
120
|
+
* TypeBox object schema the Agent reports its result against, instead of text.
|
|
121
|
+
*
|
|
122
|
+
* It becomes the input schema of one internal tool, so it must describe an
|
|
123
|
+
* object (ADR-0032).
|
|
124
|
+
*/
|
|
95
125
|
readonly outputSchema: Schema;
|
|
96
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* Maximum settlements without a reported result that this Ask corrects;
|
|
128
|
+
* defaults to 3 when omitted. Argument repair inside a turn is the Agent's
|
|
129
|
+
* own loop and costs nothing here.
|
|
130
|
+
*/
|
|
97
131
|
readonly maxSteers?: number;
|
|
98
132
|
}
|
|
99
133
|
|
|
@@ -115,12 +149,14 @@ export interface Handle {
|
|
|
115
149
|
* Sends a prompt and resolves after the Agent's turn settles.
|
|
116
150
|
*
|
|
117
151
|
* Schema-free calls resolve with the exact final assistant text. Calls with
|
|
118
|
-
* `outputSchema` resolve with the
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
152
|
+
* `outputSchema` resolve with the TypeBox-validated value the Agent reports
|
|
153
|
+
* through one internal tool call (ADR-0032). Rejects with a YaagError for a
|
|
154
|
+
* failed or empty turn, timeout, `ASK_LIMIT`, or dead Agent. An Ask that
|
|
155
|
+
* settles without a reported result is corrected at most `maxSteers` times
|
|
156
|
+
* (default 3) and then rejects recoverably with `ASK_INVALID_OUTPUT` after an
|
|
157
|
+
* abort settlement; a reported value the schema rejects fails the same way
|
|
158
|
+
* without a correction. These recoverable outcomes leave the Handle reusable.
|
|
159
|
+
* A concurrent call rejects with `AGENT_BUSY`.
|
|
124
160
|
*/
|
|
125
161
|
ask<Schema extends TSchema>(
|
|
126
162
|
prompt: string,
|
package/src/validation-errors.ts
CHANGED
|
@@ -8,18 +8,23 @@ export function formatValidationErrors(
|
|
|
8
8
|
return Array.from(errors).flatMap((error) => formatError(value, error));
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* A missing property is reported at the object that lacks it, never at the path
|
|
13
|
+
* the property would occupy: the absent path cannot be pointed at, and a pointer
|
|
14
|
+
* that contradicts its own message steers a model into the wrong shape (ADR-0032).
|
|
15
|
+
*/
|
|
11
16
|
function formatError(value: unknown, error: TLocalizedValidationError): readonly string[] {
|
|
17
|
+
const path = toJsonPath(value, error.instancePath);
|
|
12
18
|
if (error.keyword === "required") {
|
|
13
19
|
return error.params.requiredProperties.map(
|
|
14
|
-
(property) => `${
|
|
20
|
+
(property) => `${path}: must have required property ${JSON.stringify(property)}`,
|
|
15
21
|
);
|
|
16
22
|
}
|
|
17
|
-
return [`${
|
|
23
|
+
return [`${path}: ${error.message}`];
|
|
18
24
|
}
|
|
19
25
|
|
|
20
|
-
function toJsonPath(value: unknown, instancePath: string
|
|
26
|
+
function toJsonPath(value: unknown, instancePath: string): string {
|
|
21
27
|
const segments = reconstructSegments(value, instancePath);
|
|
22
|
-
if (property !== undefined) segments.push(property);
|
|
23
28
|
return segments.reduce((path, segment) => `${path}${formatSegment(segment)}`, "$");
|
|
24
29
|
}
|
|
25
30
|
|
|
@@ -66,5 +71,6 @@ function isArrayIndex(value: string): boolean {
|
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
function formatSegment(segment: string): string {
|
|
74
|
+
if (isArrayIndex(segment)) return `[${segment}]`;
|
|
69
75
|
return /^[A-Za-z_$][\w$]*$/.test(segment) ? `.${segment}` : `[${JSON.stringify(segment)}]`;
|
|
70
76
|
}
|