@yaag/cli 0.1.2 → 0.2.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/assets/types/runtime/agent.d.ts +4 -2
- package/assets/types/runtime/ask-contract-identity.d.ts +11 -2
- package/assets/types/runtime/ask-exchange-events.d.ts +11 -1
- package/assets/types/runtime/ask-exchange-options.d.ts +7 -2
- package/assets/types/runtime/ask-hash.d.ts +4 -3
- package/assets/types/runtime/ask-limit.d.ts +2 -0
- package/assets/types/runtime/ask-output-steering.d.ts +0 -2
- package/assets/types/runtime/ask-output.d.ts +16 -4
- package/assets/types/runtime/ask-turn.d.ts +5 -0
- package/assets/types/runtime/cassette-loader.d.ts +10 -0
- package/assets/types/runtime/cassette-schema.d.ts +9 -1
- package/assets/types/runtime/cassette.d.ts +4 -2
- package/assets/types/runtime/checkpoint-flush.d.ts +31 -0
- package/assets/types/runtime/connection.d.ts +12 -0
- package/assets/types/runtime/define-agent.d.ts +10 -5
- package/assets/types/runtime/errors.d.ts +7 -1
- package/assets/types/runtime/events.d.ts +24 -2
- package/assets/types/runtime/fake-transport.d.ts +10 -0
- package/assets/types/runtime/frame-queue.d.ts +2 -0
- package/assets/types/runtime/index.d.ts +3 -2
- package/assets/types/runtime/model-resolution.d.ts +45 -0
- package/assets/types/runtime/model-suffix.d.ts +16 -0
- package/assets/types/runtime/pi-state.d.ts +16 -0
- package/assets/types/runtime/report-result-extension.d.ts +44 -0
- package/assets/types/runtime/report-result-output.d.ts +37 -0
- package/assets/types/runtime/report-result-steering.d.ts +35 -0
- package/assets/types/runtime/report-result.d.ts +66 -0
- package/assets/types/runtime/run-checkpoint.d.ts +35 -13
- package/assets/types/runtime/run.d.ts +3 -2
- package/assets/types/runtime/stall-watchdog.d.ts +70 -0
- package/assets/types/runtime/summary-agent.d.ts +7 -1
- package/assets/types/runtime/summary.d.ts +10 -0
- package/assets/types/runtime/thinking-level.d.ts +11 -0
- package/assets/types/runtime/transport.d.ts +41 -4
- package/assets/types/runtime/types.d.ts +49 -14
- package/package.json +5 -5
- package/src/cli.ts +19 -10
- package/src/interactive-run.ts +3 -2
- package/src/output-channel.ts +35 -0
- package/src/presenter.ts +2 -1
- package/src/runtime-alias.ts +6 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Static, TSchema } from "typebox";
|
|
2
2
|
import type { EventSink } from "./events.ts";
|
|
3
3
|
import type { AgentStats, AgentTransport } from "./transport.ts";
|
|
4
|
-
import type { AskOptions, Handle,
|
|
4
|
+
import type { AskOptions, Handle, ResolvedSpawnOptions, StructuredAskOptions } from "./types.ts";
|
|
5
5
|
export interface AgentOptions {
|
|
6
6
|
readonly name: string;
|
|
7
7
|
readonly cwd: string;
|
|
@@ -9,7 +9,7 @@ export interface AgentOptions {
|
|
|
9
9
|
readonly transport: AgentTransport;
|
|
10
10
|
readonly emit: EventSink;
|
|
11
11
|
/** The options this Agent was spawned with, for the ADR-0014 Ask hash. */
|
|
12
|
-
readonly spawnOptions:
|
|
12
|
+
readonly spawnOptions: ResolvedSpawnOptions;
|
|
13
13
|
/** Definition-owned defaults merged below explicit per-Ask options. */
|
|
14
14
|
readonly askDefaults?: AskOptions;
|
|
15
15
|
/** Definition identity recorded on its Asks, outside replay identity. */
|
|
@@ -18,6 +18,8 @@ export interface AgentOptions {
|
|
|
18
18
|
readonly askLimitGraceMs?: number;
|
|
19
19
|
/** Test-only override for the bounded wait for `agent_settled` after an idle abort. */
|
|
20
20
|
readonly idleAbortSettleMs?: number;
|
|
21
|
+
/** Test-only override for the bounded wait for the Stall Watchdog probe. */
|
|
22
|
+
readonly stallProbeSettleMs?: number;
|
|
21
23
|
}
|
|
22
24
|
/** One Agent as an Orchestration Program sees it. Lives above the transport seam. */
|
|
23
25
|
export declare class Agent implements Handle {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TSchema } from "typebox";
|
|
2
|
+
import { type AskOutputExtractionPolicy } from "./ask-output.ts";
|
|
2
3
|
/** A JSON value suitable for deterministic Cassette identity. */
|
|
3
4
|
export type CanonicalJson = null | boolean | number | string | CanonicalJson[] | CanonicalJsonObject;
|
|
4
5
|
/** A JSON object with recursively sorted keys. */
|
|
@@ -17,8 +18,16 @@ export interface AskOutputContract {
|
|
|
17
18
|
* Throws when the value cannot be represented in a Cassette JSON artifact.
|
|
18
19
|
*/
|
|
19
20
|
export declare function canonicalizeSchema(value: unknown): CanonicalJsonObject;
|
|
20
|
-
/**
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Builds the recorded and hashed behavioral contract for one structured Ask.
|
|
23
|
+
*
|
|
24
|
+
* `policy` is the live policy unless a Cassette recorded this Ask under an
|
|
25
|
+
* older one, in which case that Ask keeps its recorded identity and behavior.
|
|
26
|
+
* Throws a TypeError when a live Ask declares a schema that is not an object
|
|
27
|
+
* schema: the Agent reports the result as one tool call's arguments (ADR-0032),
|
|
28
|
+
* and an Ask recorded before that decision keeps whatever schema it recorded.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createAskOutputContract(schema: TSchema, maxSteers?: number, policy?: AskOutputExtractionPolicy): AskOutputContract;
|
|
22
31
|
/** Validates an externally supplied canonical schema representation. */
|
|
23
32
|
export declare function validateCanonicalOutputSchema(value: unknown): CanonicalJsonObject;
|
|
24
33
|
/** Validates a policy identifier while allowing future versions to load and diverge at replay. */
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import type { AgentActivity, AskOutputChannel, EventSink } from "./events.ts";
|
|
2
2
|
import type { NodeSnapshot } from "./node-tracker.ts";
|
|
3
|
+
import type { SettlementCause } from "./stall-watchdog.ts";
|
|
4
|
+
/** What one finished Ask reports in its `ask_end` Lifecycle Event. */
|
|
5
|
+
export interface AskEndOutcome {
|
|
6
|
+
readonly durationMs: number;
|
|
7
|
+
readonly ok: boolean;
|
|
8
|
+
/** Largest inter-frame silence; absent during Cassette playback. */
|
|
9
|
+
readonly maxFrameGapMs: number | undefined;
|
|
10
|
+
readonly cause?: SettlementCause;
|
|
11
|
+
}
|
|
3
12
|
/** Emits the four Ask-scoped Lifecycle Events for one exchange. */
|
|
4
13
|
export declare class AskEvents {
|
|
5
14
|
#private;
|
|
@@ -9,5 +18,6 @@ export declare class AskEvents {
|
|
|
9
18
|
output: (channel: AskOutputChannel, text: string) => void;
|
|
10
19
|
/** Composes the Nested Node path from this Ask's identity, then reports it. */
|
|
11
20
|
node: (snapshot: NodeSnapshot) => void;
|
|
12
|
-
|
|
21
|
+
/** A `normal` cause is the absent default, so ordinary settlements stay lean. */
|
|
22
|
+
end(outcome: AskEndOutcome): void;
|
|
13
23
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { EffectiveAskOptions } from "./ask-hash.ts";
|
|
2
2
|
import type { Connection } from "./connection.ts";
|
|
3
3
|
import type { EventSink } from "./events.ts";
|
|
4
|
+
import type { ReportResultTool } from "./report-result.ts";
|
|
4
5
|
import type { AgentTransport, Frame } from "./transport.ts";
|
|
5
|
-
import type {
|
|
6
|
+
import type { ResolvedSpawnOptions } from "./types.ts";
|
|
6
7
|
/** A frame consumer whose lifetime exceeds one Ask; the Agent's AgentUsage satisfies it. */
|
|
7
8
|
export interface FrameObserver {
|
|
8
9
|
observe(frame: Frame): void;
|
|
@@ -15,8 +16,10 @@ export interface AskExchangeOptions {
|
|
|
15
16
|
readonly prompt: string;
|
|
16
17
|
readonly index: number;
|
|
17
18
|
readonly ask: EffectiveAskOptions;
|
|
18
|
-
readonly spawnOptions:
|
|
19
|
+
readonly spawnOptions: ResolvedSpawnOptions;
|
|
19
20
|
readonly definitionName: string | undefined;
|
|
21
|
+
/** The Agent's report_result activation state, which spans its Asks (ADR-0032). */
|
|
22
|
+
readonly reportResultTool: ReportResultTool;
|
|
20
23
|
/** Lifecycle Event sink; the exchange emits every Ask-scoped event itself. */
|
|
21
24
|
readonly emit: EventSink;
|
|
22
25
|
/** The Agent's persistent usage accumulator; fed frames only during live Asks. */
|
|
@@ -27,4 +30,6 @@ export interface AskExchangeOptions {
|
|
|
27
30
|
readonly askLimitGraceMs: number | undefined;
|
|
28
31
|
/** Test-only override for the bounded settle wait after an idle abort. */
|
|
29
32
|
readonly idleAbortSettleMs: number | undefined;
|
|
33
|
+
/** Test-only override for the bounded wait for the Stall Watchdog probe. */
|
|
34
|
+
readonly stallProbeSettleMs: number | undefined;
|
|
30
35
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { TSchema } from "typebox";
|
|
2
2
|
import { type AskOutputContract } from "./ask-contract-identity.ts";
|
|
3
|
+
import type { AskOutputExtractionPolicy } from "./ask-output.ts";
|
|
3
4
|
import type { AskMarkerContext } from "./transport.ts";
|
|
4
|
-
import type { AskOptions,
|
|
5
|
+
import type { AskOptions, ResolvedSpawnOptions, StructuredAskOptions } from "./types.ts";
|
|
5
6
|
/** The combined option shape used internally after Definition defaults merge. */
|
|
6
7
|
export type EffectiveAskOptions = AskOptions | StructuredAskOptions<TSchema>;
|
|
7
8
|
/** Inputs that identify an Ask in a Cassette. */
|
|
8
9
|
export interface AskHashOptions {
|
|
9
|
-
readonly spawnOptions:
|
|
10
|
+
readonly spawnOptions: ResolvedSpawnOptions;
|
|
10
11
|
readonly index: number;
|
|
11
12
|
readonly prompt: string;
|
|
12
13
|
/** Soft-limit behavior and structured output contract, unlike timeoutMs, identify replay. */
|
|
@@ -29,4 +30,4 @@ export declare function askHash(options: AskHashOptions): string;
|
|
|
29
30
|
*/
|
|
30
31
|
export declare function askMarkerContext({ spawnOptions, prompt, ask, outputContract, }: AskHashOptions): AskMarkerContext;
|
|
31
32
|
/** Creates structured identity only when the Ask explicitly carries a schema. */
|
|
32
|
-
export declare function structuredOutputContract(ask: EffectiveAskOptions | undefined): AskOutputContract | undefined;
|
|
33
|
+
export declare function structuredOutputContract(ask: EffectiveAskOptions | undefined, policy?: AskOutputExtractionPolicy): AskOutputContract | undefined;
|
|
@@ -10,6 +10,8 @@ export interface AskLimitOptions {
|
|
|
10
10
|
readonly command: (frame: Frame) => Promise<boolean>;
|
|
11
11
|
readonly durationGraceMs?: number;
|
|
12
12
|
readonly now?: () => number;
|
|
13
|
+
/** One sentence appended to the wrap-up, so a structured Ask still reports its result. */
|
|
14
|
+
readonly wrapUpSuffix?: string;
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* Per-Ask soft-limit controller.
|
|
@@ -2,10 +2,19 @@ import type { TSchema } from "typebox";
|
|
|
2
2
|
import type { AskInvalidOutputOutcome } from "./errors.ts";
|
|
3
3
|
import { YaagError } from "./errors.ts";
|
|
4
4
|
import type { AskInvalidOutputPlayback } from "./transport.ts";
|
|
5
|
-
/** Versioned extraction behavior
|
|
6
|
-
export declare const ASK_OUTPUT_EXTRACTION_POLICY = "
|
|
7
|
-
/**
|
|
8
|
-
|
|
5
|
+
/** Versioned extraction behavior, and part of Ask identity in a Cassette. */
|
|
6
|
+
export declare const ASK_OUTPUT_EXTRACTION_POLICY = "report-result-tool/v1";
|
|
7
|
+
/**
|
|
8
|
+
* The pre-ADR-0032 policy: the first JSON block of the final assistant text.
|
|
9
|
+
*
|
|
10
|
+
* No live Ask selects it. It stays reachable so a Cassette recorded under it
|
|
11
|
+
* replays through the same ADR-0027 code path it was recorded from.
|
|
12
|
+
*/
|
|
13
|
+
export declare const LEGACY_ASK_OUTPUT_EXTRACTION_POLICY = "json-first-block/v1";
|
|
14
|
+
/** The extraction policy identifiers this runtime can execute. */
|
|
15
|
+
export type AskOutputExtractionPolicy = typeof ASK_OUTPUT_EXTRACTION_POLICY | typeof LEGACY_ASK_OUTPUT_EXTRACTION_POLICY;
|
|
16
|
+
/** The per-Ask bound when a structured Ask omits `maxSteers`. */
|
|
17
|
+
export declare const DEFAULT_MAX_STEERS = 3;
|
|
9
18
|
export type AskOutputResult = {
|
|
10
19
|
readonly ok: true;
|
|
11
20
|
readonly value: unknown;
|
|
@@ -23,6 +32,9 @@ export declare function formatAskOutputCorrection(errors: readonly string[]): st
|
|
|
23
32
|
* A recorded invalid-output outcome rethrows deterministically (ADR-0027); otherwise
|
|
24
33
|
* the text is re-validated so playback and live settlement agree. Throws the same
|
|
25
34
|
* recoverable ASK_INVALID_OUTPUT error as a live Ask on validation failure.
|
|
35
|
+
*
|
|
36
|
+
* Its signature is frozen with the policy it serves: this path exists only for
|
|
37
|
+
* Cassettes recorded under `json-first-block/v1` (ADR-0032).
|
|
26
38
|
*/
|
|
27
39
|
export declare function resolvePlaybackAskOutput(agent: string, schema: TSchema, text: string, recordedOutcome: AskInvalidOutputPlayback | undefined): unknown;
|
|
28
40
|
/** Creates the recoverable error for final structured-output validation failure. */
|
|
@@ -14,6 +14,11 @@ export declare class AskTurn {
|
|
|
14
14
|
observe(frame: Frame): void;
|
|
15
15
|
/** True once `agent_settled` has been seen — settled says nothing about success. */
|
|
16
16
|
get settled(): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* True once an assistant `message_end` was seen — the Agent produced a final
|
|
19
|
+
* message even if `agent_settled` never arrived. The Stall Watchdog reads it.
|
|
20
|
+
*/
|
|
21
|
+
get terminal(): boolean;
|
|
17
22
|
/** Starts a new correction effort without retaining the preceding terminal state. */
|
|
18
23
|
rearm(): void;
|
|
19
24
|
/**
|
|
@@ -9,3 +9,13 @@ import { type Cassette } from "./cassette.ts";
|
|
|
9
9
|
* Unknown fields are retained, never dropped (forward tolerance).
|
|
10
10
|
*/
|
|
11
11
|
export declare function loadCassette(path: string): Promise<Cassette>;
|
|
12
|
+
/**
|
|
13
|
+
* Strict replay demands a settled Run. An `interrupted` artifact stops at the
|
|
14
|
+
* last Ask boundary, so its final Ask has no recorded settlement (ADR-0031).
|
|
15
|
+
*/
|
|
16
|
+
export declare function assertReplayable(cassette: Cassette, path: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Warns once when a resume source came from a hard death. The Run continues:
|
|
19
|
+
* resume already handles an incomplete last Ask.
|
|
20
|
+
*/
|
|
21
|
+
export declare function interruptedResumeWarning(cassette: Cassette, path: string): string | null;
|
|
@@ -11,7 +11,7 @@ import type { Frame } from "./transport.ts";
|
|
|
11
11
|
export declare const CassetteSchema: Type.TObject<{
|
|
12
12
|
v: Type.TUnion<[Type.TLiteral<1>, Type.TLiteral<2>]>;
|
|
13
13
|
run: Type.TOptional<Type.TObject<{
|
|
14
|
-
outcome: Type.TUnion<Type.TLiteral<"completed" | "failed" | "paused" | "stopped">[]>;
|
|
14
|
+
outcome: Type.TUnion<Type.TLiteral<"completed" | "failed" | "interrupted" | "paused" | "stopped">[]>;
|
|
15
15
|
programFile: Type.TOptional<Type.TString>;
|
|
16
16
|
args: Type.TOptional<Type.TUnknown>;
|
|
17
17
|
programHash: Type.TOptional<Type.TString>;
|
|
@@ -71,6 +71,7 @@ export declare const CassetteSchema: Type.TObject<{
|
|
|
71
71
|
maxToolCalls: Type.TOptional<Type.TNumber>;
|
|
72
72
|
maxDurationMs: Type.TOptional<Type.TNumber>;
|
|
73
73
|
idleMs: Type.TOptional<Type.TNumber>;
|
|
74
|
+
stallMs: Type.TOptional<Type.TUnion<[Type.TNumber, Type.TLiteral<false>]>>;
|
|
74
75
|
wrapUpPrompt: Type.TOptional<Type.TString>;
|
|
75
76
|
}>;
|
|
76
77
|
}>>;
|
|
@@ -83,11 +84,18 @@ export declare const CassetteSchema: Type.TObject<{
|
|
|
83
84
|
stalled: Type.TOptional<Type.TObject<{
|
|
84
85
|
idleMs: Type.TNumber;
|
|
85
86
|
destructive: Type.TBoolean;
|
|
87
|
+
state: Type.TOptional<Type.TObject<{
|
|
88
|
+
working: Type.TBoolean;
|
|
89
|
+
streaming: Type.TBoolean;
|
|
90
|
+
compacting: Type.TBoolean;
|
|
91
|
+
pendingMessages: Type.TNumber;
|
|
92
|
+
}>>;
|
|
86
93
|
}>>;
|
|
87
94
|
outcome: Type.TOptional<Type.TObject<{
|
|
88
95
|
kind: Type.TLiteral<"invalid_output">;
|
|
89
96
|
steeringEfforts: Type.TInteger;
|
|
90
97
|
}>>;
|
|
98
|
+
recovered: Type.TOptional<Type.TLiteral<true>>;
|
|
91
99
|
}>>;
|
|
92
100
|
stats: Type.TObject<{
|
|
93
101
|
tokens: Type.TUnion<[Type.TNull, Type.TObject<{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CanonicalJsonObject } from "./ask-contract-identity.ts";
|
|
2
2
|
import type { AskLimitOutcome, AskStalledOutcome } from "./errors.ts";
|
|
3
3
|
import type { RunOutcome } from "./events.ts";
|
|
4
|
-
import type { AgentStats, AskInvalidOutputPlayback, AskMarker, AskMarkerContext, Frame, OpenOptions, WorktreeResolution } from "./transport.ts";
|
|
4
|
+
import type { AgentStats, AskCompletion, AskInvalidOutputPlayback, AskMarker, AskMarkerContext, Frame, OpenOptions, WorktreeResolution } from "./transport.ts";
|
|
5
5
|
import type { ThinkingLevel } from "./types.ts";
|
|
6
6
|
/** The Cassette format this runtime writes; the loader also reads version 1. */
|
|
7
7
|
export declare const CASSETTE_VERSION: 2;
|
|
@@ -88,6 +88,8 @@ export interface CassetteAsk {
|
|
|
88
88
|
readonly stalled?: AskStalledOutcome;
|
|
89
89
|
/** Present only when the Ask surfaced ASK_INVALID_OUTPUT. */
|
|
90
90
|
readonly outcome?: AskInvalidOutputPlayback;
|
|
91
|
+
/** Present only when the Stall Watchdog recovered the settlement (ADR-0029). */
|
|
92
|
+
readonly recovered?: true;
|
|
91
93
|
}
|
|
92
94
|
/** Sink consumed by recordingTransport without exposing its mutable state. */
|
|
93
95
|
export interface CassetteSink {
|
|
@@ -107,7 +109,7 @@ export interface CassetteRecorder {
|
|
|
107
109
|
sent(frame: Frame): void;
|
|
108
110
|
received(frame: Frame): void;
|
|
109
111
|
beginAsk(marker: AskMarker): void;
|
|
110
|
-
finishAsk(
|
|
112
|
+
finishAsk(completion: AskCompletion): void;
|
|
111
113
|
closed(stats: AgentStats): void;
|
|
112
114
|
}
|
|
113
115
|
/** Collects a Cassette in memory; `executeRun` serializes it at Run settlement. */
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CassetteSink } from "./cassette.ts";
|
|
2
|
+
import { type RunIdentity } from "./run-checkpoint.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Publishes the Run's in-progress Checkpoint (ADR-0031).
|
|
5
|
+
*
|
|
6
|
+
* Each flush rewrites the full collected Cassette to the Run's destination with
|
|
7
|
+
* the same atomic write a settled Checkpoint uses, and states the outcome
|
|
8
|
+
* `interrupted`. Flushes never reject: a failed one writes a diagnostic, and the
|
|
9
|
+
* next Ask boundary tries again.
|
|
10
|
+
*/
|
|
11
|
+
export interface CheckpointFlusher {
|
|
12
|
+
/** Requests a publication; returns at once. Concurrent requests coalesce. */
|
|
13
|
+
flush(): void;
|
|
14
|
+
/** Resolves when no publication is in flight, and stops accepting new ones. */
|
|
15
|
+
quiesce(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export interface CheckpointFlushOptions {
|
|
18
|
+
/** Read at each flush; its current content becomes the artifact. */
|
|
19
|
+
readonly collector: CassetteSink;
|
|
20
|
+
/** Explicit `--record` destination, or undefined when the Run only checkpoints. */
|
|
21
|
+
readonly record: string | undefined;
|
|
22
|
+
/** Where the in-progress artifact lives; fixed at Run start. */
|
|
23
|
+
readonly destination: string;
|
|
24
|
+
readonly identity: RunIdentity;
|
|
25
|
+
}
|
|
26
|
+
export declare function createCheckpointFlusher(options: CheckpointFlushOptions): CheckpointFlusher;
|
|
27
|
+
/**
|
|
28
|
+
* Wraps a sink so every Ask boundary publishes the Checkpoint: an Agent opened,
|
|
29
|
+
* an Ask begun, an Ask finished, an Agent closed (ADR-0031).
|
|
30
|
+
*/
|
|
31
|
+
export declare function flushingSink(sink: CassetteSink, flusher: CheckpointFlusher): CassetteSink;
|
|
@@ -21,6 +21,18 @@ export declare class Connection {
|
|
|
21
21
|
get closed(): Promise<void>;
|
|
22
22
|
/** Routes non-response frames to a listener, replacing any previous one. */
|
|
23
23
|
observe(listener: ((frame: Frame) => void) | null): void;
|
|
24
|
+
/**
|
|
25
|
+
* Drops every frame up to and including the abandoned turn's `agent_settled`.
|
|
26
|
+
*
|
|
27
|
+
* A stall leaves the Agent still working on the turn yaag gave up on. pi
|
|
28
|
+
* queues the next prompt behind that turn, so its late frames — above all
|
|
29
|
+
* its `agent_settled` — arrive after the next Ask started, and would settle
|
|
30
|
+
* that Ask with the abandoned turn's text. Draining to the settlement frame
|
|
31
|
+
* is the only boundary pi gives. A turn that never settles keeps the drain
|
|
32
|
+
* open, and the next Ask's own Stall Watchdog ends that wait with
|
|
33
|
+
* `ASK_STALLED` instead of a wrong answer.
|
|
34
|
+
*/
|
|
35
|
+
drainStaleTurn(): void;
|
|
24
36
|
/**
|
|
25
37
|
* Sends one command and resolves with its id-correlated response.
|
|
26
38
|
* Rejects with AGENT_DIED if the Agent dies first.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ModelSpec, ThinkingSpec } from "./model-resolution.ts";
|
|
2
|
+
import type { AskOptions } from "./types.ts";
|
|
2
3
|
export type { ThinkingLevel } from "./types.ts";
|
|
3
4
|
/** What `defineAgent` is given: the policy of one Agent, never its topology. */
|
|
4
5
|
export interface AgentConfig {
|
|
@@ -8,10 +9,14 @@ export interface AgentConfig {
|
|
|
8
9
|
readonly prompt?: string;
|
|
9
10
|
/** Replace pi's system prompt with `prompt` instead of appending to it. */
|
|
10
11
|
readonly overrideSystemPrompt?: boolean;
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Model id handed to `pi --model`. Unset = pi's default. An array is an ordered
|
|
14
|
+
* fallback list, a function picks the next candidate from the failures so far,
|
|
15
|
+
* and any pattern may carry an inline thinking suffix (`"opus-5:medium"`).
|
|
16
|
+
*/
|
|
17
|
+
readonly model?: ModelSpec;
|
|
18
|
+
/** Thinking budget for the Agent's turns, as a level or a resolver. */
|
|
19
|
+
readonly thinking?: ThinkingSpec;
|
|
15
20
|
/** Allow-list of tool names. Unset = pi's default tool set. */
|
|
16
21
|
readonly tools?: readonly string[];
|
|
17
22
|
/** Deny-list of tool names, applied after `tools`. */
|
|
@@ -5,12 +5,16 @@ export interface AskLimitOutcome {
|
|
|
5
5
|
readonly kind: AskLimitKind;
|
|
6
6
|
readonly count: number;
|
|
7
7
|
}
|
|
8
|
+
import type { AgentProgress } from "./pi-state.ts";
|
|
9
|
+
export type { AgentProgress } from "./pi-state.ts";
|
|
8
10
|
/** The recorded result when yaag rejects an Ask because no frame arrived within `idleMs`. */
|
|
9
11
|
export interface AskStalledOutcome {
|
|
10
12
|
/** The configured silence threshold that tripped. */
|
|
11
13
|
readonly idleMs: number;
|
|
12
|
-
/** True when
|
|
14
|
+
/** True when escalation failed to settle the Agent and yaag killed the process. */
|
|
13
15
|
readonly destructive: boolean;
|
|
16
|
+
/** State the Stall Watchdog probe observed; absent when the probe stayed silent. */
|
|
17
|
+
readonly state?: AgentProgress;
|
|
14
18
|
}
|
|
15
19
|
/** Recoverable result when all structured-output correction efforts are exhausted. */
|
|
16
20
|
export interface AskInvalidOutputOutcome {
|
|
@@ -34,6 +38,8 @@ export declare class YaagError extends Error {
|
|
|
34
38
|
readonly idleMs?: number;
|
|
35
39
|
/** True when an `ASK_STALLED` escalation had to kill the Agent. */
|
|
36
40
|
readonly destructive?: boolean;
|
|
41
|
+
/** State observed by the Stall Watchdog probe, present only for `ASK_STALLED`. */
|
|
42
|
+
readonly state?: AgentProgress;
|
|
37
43
|
/** Number of corrective output steers sent, present only for `ASK_INVALID_OUTPUT`. */
|
|
38
44
|
readonly steeringEfforts?: number;
|
|
39
45
|
/** Localized extraction or schema errors, present only for `ASK_INVALID_OUTPUT`. */
|
|
@@ -6,9 +6,15 @@
|
|
|
6
6
|
* activity, output, and usage observations. v0 renders them as stderr lines; the
|
|
7
7
|
* dedicated fd arrives with the extension.
|
|
8
8
|
*/
|
|
9
|
+
import type { SettlementCause } from "./stall-watchdog.ts";
|
|
9
10
|
import type { TokenBreakdown, WorktreeResolution } from "./transport.ts";
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
export type { SettlementCause } from "./stall-watchdog.ts";
|
|
12
|
+
/**
|
|
13
|
+
* A Run's outcome (ADR-0022). `paused` arrives with the pause slice.
|
|
14
|
+
* `interrupted` is not terminal: only an in-flight Checkpoint carries it, and a
|
|
15
|
+
* settled Run never writes it (ADR-0031).
|
|
16
|
+
*/
|
|
17
|
+
export type RunOutcome = "completed" | "failed" | "stopped" | "paused" | "interrupted";
|
|
12
18
|
/** The current, Ask-scoped observer projection derived from Agent frames. */
|
|
13
19
|
export type AgentActivity = {
|
|
14
20
|
readonly type: "thinking";
|
|
@@ -37,6 +43,12 @@ export interface NodeUsage {
|
|
|
37
43
|
export type LifecycleEventBody = {
|
|
38
44
|
readonly type: "run_start";
|
|
39
45
|
readonly program: string;
|
|
46
|
+
/**
|
|
47
|
+
* Path of the in-progress Checkpoint this Run publishes at each Ask
|
|
48
|
+
* boundary (ADR-0031). A hard death leaves this file loadable with the
|
|
49
|
+
* outcome `interrupted`, so an observer can name the resume source.
|
|
50
|
+
*/
|
|
51
|
+
readonly artifact?: string;
|
|
40
52
|
} | {
|
|
41
53
|
readonly type: "agent_spawn";
|
|
42
54
|
readonly agent: string;
|
|
@@ -95,6 +107,11 @@ export type LifecycleEventBody = {
|
|
|
95
107
|
readonly ok: boolean;
|
|
96
108
|
/** Largest inter-frame silence during this Ask; absent during Cassette playback. */
|
|
97
109
|
readonly maxFrameGapMs?: number;
|
|
110
|
+
/**
|
|
111
|
+
* How the Ask settled. Absent means `normal`. `recovered` means the Stall
|
|
112
|
+
* Watchdog settled it from observed state, so its usage is an undercount.
|
|
113
|
+
*/
|
|
114
|
+
readonly cause?: SettlementCause;
|
|
98
115
|
} | {
|
|
99
116
|
readonly type: "agent_usage";
|
|
100
117
|
readonly agent: string;
|
|
@@ -124,6 +141,11 @@ export type LifecycleEventBody = {
|
|
|
124
141
|
readonly incomplete: boolean;
|
|
125
142
|
/** Largest inter-frame silence across every Ask; 0 when nothing was measured. */
|
|
126
143
|
readonly worstFrameGapMs: number;
|
|
144
|
+
/**
|
|
145
|
+
* The Run failed, `--record` asked for a Checkpoint, and publication also
|
|
146
|
+
* failed. Carries the publication error text. Absent on every other path.
|
|
147
|
+
*/
|
|
148
|
+
readonly checkpointLost?: string;
|
|
127
149
|
};
|
|
128
150
|
/**
|
|
129
151
|
* A Lifecycle Event as observers see it: the body plus `at` — epoch-ms wall
|
|
@@ -32,10 +32,16 @@ export interface FakePromptScript {
|
|
|
32
32
|
export interface FakeTransportOptions extends FakePromptScript {
|
|
33
33
|
/** One script per Ask's initial prompt, used in order; preserves the single-script shorthand above. */
|
|
34
34
|
readonly scripts?: readonly FakePromptScript[];
|
|
35
|
+
/** Payload of a `get_state` probe; omission answers with an idle, non-streaming Agent. */
|
|
36
|
+
readonly state?: Record<string, unknown>;
|
|
37
|
+
/** Makes the fake ignore every `get_state` probe, as a wedged Agent does. */
|
|
38
|
+
readonly stateSilent?: boolean;
|
|
35
39
|
/** Makes a steer RPC response fail without embedding a limit decision in playback. */
|
|
36
40
|
readonly steerError?: string;
|
|
37
41
|
/** Makes an abort RPC response fail without embedding a limit decision in playback. */
|
|
38
42
|
readonly abortError?: string;
|
|
43
|
+
/** Makes the private report_result schema command fail. */
|
|
44
|
+
readonly schemaCommandError?: string;
|
|
39
45
|
readonly stats?: AgentStats;
|
|
40
46
|
/** pi can answer a command after `agent_settled` — it is last among events only. */
|
|
41
47
|
readonly promptResponse?: "immediate" | "after-settle";
|
|
@@ -67,9 +73,13 @@ export declare class FakeTransport implements AgentTransport {
|
|
|
67
73
|
/** Number of times this fake actually began close work. */
|
|
68
74
|
get closeCalls(): number;
|
|
69
75
|
close(): Promise<AgentStats>;
|
|
76
|
+
/** Pushes one unsolicited frame, as a late or abandoned turn would emit. */
|
|
77
|
+
emit(frame: Frame): void;
|
|
70
78
|
/** Simulates the process dying: the frame stream just ends. */
|
|
71
79
|
die(): void;
|
|
72
80
|
}
|
|
81
|
+
/** The frames one accepted `report_result` call produces, for scripted Asks. */
|
|
82
|
+
export declare function reportResultFrames(value: unknown, toolCallId?: string): readonly Frame[];
|
|
73
83
|
/**
|
|
74
84
|
* Loads and parses a named JSONL frame fixture from the runtime fixtures directory.
|
|
75
85
|
*
|
|
@@ -9,6 +9,8 @@ import type { Frame } from "./transport.ts";
|
|
|
9
9
|
export declare class FrameQueue {
|
|
10
10
|
#private;
|
|
11
11
|
push(frame: Frame): void;
|
|
12
|
+
/** Drops every buffered frame the consumer has not taken yet. */
|
|
13
|
+
discardPending(): void;
|
|
12
14
|
/** Ends the stream; the consumer's iteration finishes once drained. */
|
|
13
15
|
end(): void;
|
|
14
16
|
frames(): AsyncGenerator<Frame>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type { Cassette, CassetteAgent, CassetteArtifact, CassetteAsk, CassetteGit, CassetteRun, CassetteSink, CassetteSpawn, } from "./cassette.ts";
|
|
2
2
|
export { CASSETTE_VERSION } from "./cassette.ts";
|
|
3
|
-
export { loadCassette } from "./cassette-loader.ts";
|
|
3
|
+
export { assertReplayable, loadCassette } from "./cassette-loader.ts";
|
|
4
4
|
export type { AgentConfig, AgentDefinition } from "./define-agent.ts";
|
|
5
5
|
export { agentDefinitionConfig, defineAgent, isAgentDefinition } from "./define-agent.ts";
|
|
6
6
|
export type { OrchestrationProgram, ProgramDefinition } from "./define-run.ts";
|
|
@@ -8,6 +8,7 @@ export { defineRun, isOrchestrationProgram, programDefinition } from "./define-r
|
|
|
8
8
|
export type { AskInvalidOutputOutcome, AskLimitKind, AskLimitOutcome, AskStalledOutcome, YaagErrorCode, } from "./errors.ts";
|
|
9
9
|
export { isYaagError, YaagError } from "./errors.ts";
|
|
10
10
|
export type { AgentActivity, AskOutputChannel, EventSink, LifecycleEvent, LifecycleEventBody, NodeState, NodeUsage, StampedEventSink, } from "./events.ts";
|
|
11
|
+
export type { ModelError, ModelErrorReason, ModelResolver, ModelSelection, ModelSpec, ThinkingResolver, ThinkingSpec, } from "./model-resolution.ts";
|
|
11
12
|
export type { DecodedNode, NodeDecoder } from "./node-decoder.ts";
|
|
12
13
|
export { DEFAULT_NODE_DECODERS } from "./node-decoders.ts";
|
|
13
14
|
export type { NodePath } from "./node-path.ts";
|
|
@@ -28,6 +29,6 @@ export type { DiscoveredSkill, SkillProbeFactory } from "./skill-probe.ts";
|
|
|
28
29
|
export type { AgentInfo, AgentState, AskingAgentInfo, EndedRunSummary, ExitedAgentInfo, IdleAgentInfo, NodeInfo, RunningRunSummary, RunOutcome, RunState, RunSummary, } from "./summary.ts";
|
|
29
30
|
export { applyEvent, initialSummary } from "./summary.ts";
|
|
30
31
|
export type { AgentStats, AgentTransport, AskMarker, AskMarkerContext, AskPlayback, Frame, TokenBreakdown, TransportFactory, TransportStartup, TransportStartupObserver, WorktreeResolution, } from "./transport.ts";
|
|
31
|
-
export type { AskOptions, Handle, SpawnOptions, SpawnOverrides, StructuredAskOptions, ThinkingLevel, } from "./types.ts";
|
|
32
|
+
export type { AskOptions, Handle, ResolvedSpawnOptions, SpawnOptions, SpawnOverrides, StructuredAskOptions, ThinkingLevel, } from "./types.ts";
|
|
32
33
|
export { AGENT_NODE_TABLE_MAX, ASK_OUTPUT_FLUSH_INTERVAL_MS, ASK_OUTPUT_MAX_BYTES, ASK_OUTPUT_TRUNCATION_MARKER, NODE_GIST_MAX_CHARS, PROMPT_GIST_MAX_CHARS, TOOL_ARGS_GIST_MAX_CHARS, } from "./wire-constants.ts";
|
|
33
34
|
export { worktreeTransport } from "./worktree-transport.ts";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type ThinkingLevel } from "./thinking-level.ts";
|
|
2
|
+
/** Why one model candidate was rejected by pi. */
|
|
3
|
+
export type ModelErrorReason = "not_found" | "auth" | "rate_limited";
|
|
4
|
+
/** One failed Model Resolution attempt, handed back to the caller's resolver. */
|
|
5
|
+
export interface ModelError {
|
|
6
|
+
readonly reason: ModelErrorReason;
|
|
7
|
+
/** The model pattern that failed, after inline-suffix stripping. */
|
|
8
|
+
readonly failedModel: string;
|
|
9
|
+
/** 0-based index of the attempt that produced this error. */
|
|
10
|
+
readonly attempt: number;
|
|
11
|
+
}
|
|
12
|
+
/** Picks the next model candidate, or `undefined` to give up. */
|
|
13
|
+
export type ModelResolver = (errors: readonly ModelError[]) => string | undefined;
|
|
14
|
+
/** Every accepted `model` form: one pattern, an ordered list, or a resolver. */
|
|
15
|
+
export type ModelSpec = string | readonly string[] | ModelResolver;
|
|
16
|
+
/** Picks the thinking level for a settled model, or `undefined` for pi's default. */
|
|
17
|
+
export type ThinkingResolver = (selectedModel: string, errors: readonly ModelError[]) => ThinkingLevel | undefined;
|
|
18
|
+
/** Every accepted `thinking` form: one level or a resolver. */
|
|
19
|
+
export type ThinkingSpec = ThinkingLevel | ThinkingResolver;
|
|
20
|
+
/** One attempt's settled selection; `model: undefined` inherits pi's default model. */
|
|
21
|
+
export interface ModelSelection {
|
|
22
|
+
readonly model: string | undefined;
|
|
23
|
+
readonly thinking: ThinkingLevel | undefined;
|
|
24
|
+
}
|
|
25
|
+
/** The canonical shape the spawn loop consumes, whatever form the caller wrote. */
|
|
26
|
+
export interface ModelResolution {
|
|
27
|
+
/** The next selection given the errors so far, or `undefined` when candidates run out. */
|
|
28
|
+
resolve(errors: readonly ModelError[]): ModelSelection | undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Turns any accepted `model`/`thinking` form into one canonical resolver pair.
|
|
32
|
+
*
|
|
33
|
+
* Within one attempt the order is: model resolver → inline-suffix parse →
|
|
34
|
+
* thinking resolver, and an inline suffix wins over the `thinking` spec, which
|
|
35
|
+
* is then not consulted at all. An absent `model` inherits pi's default for
|
|
36
|
+
* attempt 0 only; a thinking *resolver* is then not called, because no model has
|
|
37
|
+
* settled, while a thinking level still applies.
|
|
38
|
+
* Array specs are copied, so later caller mutation cannot change resolution.
|
|
39
|
+
* Throws a `TypeError` when a caller resolver returns something other than a
|
|
40
|
+
* non-empty model string or a valid thinking level.
|
|
41
|
+
*/
|
|
42
|
+
export declare function normalizeModelResolution(spec: {
|
|
43
|
+
readonly model?: ModelSpec;
|
|
44
|
+
readonly thinking?: ThinkingSpec;
|
|
45
|
+
}): ModelResolution;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ThinkingLevel } from "./thinking-level.ts";
|
|
2
|
+
/** A model pattern split into its model part and its optional inline thinking suffix. */
|
|
3
|
+
export interface ModelPattern {
|
|
4
|
+
readonly model: string;
|
|
5
|
+
readonly thinking: ThinkingLevel | undefined;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Splits a resolved model pattern on its inline thinking suffix.
|
|
9
|
+
*
|
|
10
|
+
* The split happens on the *last* `:` only when the tail is exactly one of pi's
|
|
11
|
+
* thinking levels and the head is non-empty, so colon-bearing model ids such as
|
|
12
|
+
* `llama3:8b` and suffix-only strings such as `:medium` survive untouched. The
|
|
13
|
+
* parser is total: it never throws, and an unusable pattern simply fails later
|
|
14
|
+
* as an ordinary model lookup failure.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseModelSuffix(pattern: string): ModelPattern;
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { AgentStats, Frame, OpenOptions } from "./transport.ts";
|
|
2
|
+
/** What the Agent reported about its own work, read from a `get_state` probe. */
|
|
3
|
+
export interface AgentProgress {
|
|
4
|
+
/** True while pi streams a completion, compacts its context, or holds a queued prompt. */
|
|
5
|
+
readonly working: boolean;
|
|
6
|
+
readonly streaming: boolean;
|
|
7
|
+
readonly compacting: boolean;
|
|
8
|
+
/** Prompts pi has queued but not started. */
|
|
9
|
+
readonly pendingMessages: number;
|
|
10
|
+
}
|
|
2
11
|
/** The command line for one Agent. */
|
|
3
12
|
export declare function piCommand(options: OpenOptions, toolProbeExtensionPath?: string): string[];
|
|
4
13
|
/**
|
|
@@ -6,6 +15,13 @@ export declare function piCommand(options: OpenOptions, toolProbeExtensionPath?:
|
|
|
6
15
|
* to, not the pattern that was requested. Null when the payload has no model.
|
|
7
16
|
*/
|
|
8
17
|
export declare function readModel(response: Frame): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Reads what a `get_state` payload says about the Agent's own work.
|
|
20
|
+
*
|
|
21
|
+
* Null when the payload does not carry pi's streaming flags, which the Stall
|
|
22
|
+
* Watchdog treats as work in progress rather than as a settlement.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readAgentProgress(data: unknown): AgentProgress | null;
|
|
9
25
|
/** Returns pi's persisted session path from a startup `get_state` response, when valid. */
|
|
10
26
|
export declare function readSessionFile(response: Frame): string | null;
|
|
11
27
|
/**
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yaag's private structured-result tool, loaded into every Agent at spawn.
|
|
3
|
+
*
|
|
4
|
+
* The tool stays inactive until a schema-bearing Ask delivers its output schema
|
|
5
|
+
* through the `yaag-report-result` command; the schema becomes the tool's input
|
|
6
|
+
* schema, so pi validates the arguments and the Orchestrator settles the Ask
|
|
7
|
+
* from the call instead of scraping final text (ADR-0032).
|
|
8
|
+
*
|
|
9
|
+
* Types are declared locally rather than imported from pi: this file is passed
|
|
10
|
+
* to `pi -e` as a path and must load without yaag's dependency graph.
|
|
11
|
+
*/
|
|
12
|
+
/** One tool result, in the shape pi's tool layer returns to the model. */
|
|
13
|
+
export interface ReportResultToolResult {
|
|
14
|
+
readonly content: readonly {
|
|
15
|
+
readonly type: "text";
|
|
16
|
+
readonly text: string;
|
|
17
|
+
}[];
|
|
18
|
+
readonly details?: {
|
|
19
|
+
readonly reportedResult: unknown;
|
|
20
|
+
};
|
|
21
|
+
readonly isError?: boolean;
|
|
22
|
+
readonly terminate?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** One tool definition, in the shape `pi.registerTool` accepts. */
|
|
25
|
+
export interface ReportResultToolDefinition {
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly label: string;
|
|
28
|
+
readonly description: string;
|
|
29
|
+
readonly promptSnippet: string;
|
|
30
|
+
readonly promptGuidelines: readonly string[];
|
|
31
|
+
readonly parameters: object;
|
|
32
|
+
execute(toolCallId: string, params: unknown): Promise<ReportResultToolResult>;
|
|
33
|
+
}
|
|
34
|
+
/** The part of pi's extension API this extension uses (pi docs/extensions.md). */
|
|
35
|
+
export interface ReportResultAPI {
|
|
36
|
+
registerTool(definition: ReportResultToolDefinition): void;
|
|
37
|
+
registerCommand(name: string, command: {
|
|
38
|
+
readonly description: string;
|
|
39
|
+
handler(args: string): void;
|
|
40
|
+
}): void;
|
|
41
|
+
getActiveTools(): string[];
|
|
42
|
+
setActiveTools(names: readonly string[]): void;
|
|
43
|
+
}
|
|
44
|
+
export default function (pi: ReportResultAPI): void;
|