@tangle-network/agent-runtime 0.71.1 → 0.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/agent.d.ts +27 -17
- package/dist/agent.js +21 -9
- package/dist/agent.js.map +1 -1
- package/dist/analyst-loop.d.ts +1 -1
- package/dist/analyst-loop.js +3 -2
- package/dist/{chunk-4KGQHS7U.js → chunk-7ODB76J5.js} +2 -18
- package/dist/chunk-7ODB76J5.js.map +1 -0
- package/dist/chunk-HPYWEFVY.js +4039 -0
- package/dist/chunk-HPYWEFVY.js.map +1 -0
- package/dist/{chunk-P5OKDSLB.js → chunk-IODKUOBA.js} +5 -3
- package/dist/{chunk-P5OKDSLB.js.map → chunk-IODKUOBA.js.map} +1 -1
- package/dist/chunk-NBV35BR6.js +68 -0
- package/dist/chunk-NBV35BR6.js.map +1 -0
- package/dist/{chunk-5ISW5JUF.js → chunk-NCH4XUZ7.js} +2004 -6551
- package/dist/chunk-NCH4XUZ7.js.map +1 -0
- package/dist/chunk-PBE35ULD.js +52 -0
- package/dist/chunk-PBE35ULD.js.map +1 -0
- package/dist/{chunk-VLF5RHEQ.js → chunk-T2HVQVB4.js} +1 -66
- package/dist/chunk-T2HVQVB4.js.map +1 -0
- package/dist/{chunk-K3RM4MPM.js → chunk-U56XGKVY.js} +9 -24
- package/dist/chunk-U56XGKVY.js.map +1 -0
- package/dist/chunk-UZ5SODU7.js +29 -0
- package/dist/chunk-UZ5SODU7.js.map +1 -0
- package/dist/{delegates-CsXJPZDH.d.ts → coordination-DU0saWeg.d.ts} +875 -1099
- package/dist/index.d.ts +7 -8
- package/dist/index.js +10 -12
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +1 -1
- package/dist/lifecycle.d.ts +281 -0
- package/dist/lifecycle.js +174 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/{loop-runner-bin-DLM_bVQO.d.ts → loop-runner-bin-eD3m0rHW.d.ts} +10 -27
- package/dist/loop-runner-bin.d.ts +5 -6
- package/dist/loop-runner-bin.js +6 -6
- package/dist/loops.d.ts +47 -10
- package/dist/loops.js +47 -42
- package/dist/mcp/bin.js +17 -329
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +10 -190
- package/dist/mcp/index.js +949 -47
- package/dist/mcp/index.js.map +1 -1
- package/dist/{openai-tools-kdCS-T12.d.ts → openai-tools-CBurv8Cu.d.ts} +11 -13
- package/dist/otel-export-BKmNwiCb.d.ts +180 -0
- package/dist/profiles.d.ts +3 -3
- package/dist/profiles.js +1 -5
- package/dist/profiles.js.map +1 -1
- package/dist/{substrate-BoRXgvka.d.ts → substrate-rNj6TDc3.d.ts} +7 -23
- package/dist/{types-CdnEAE3U.d.ts → types-JufmXF2a.d.ts} +80 -1
- package/dist/worktree-DaxOvw-C.d.ts +702 -0
- package/dist/{worktree-fanout-CK2ypmEm.d.ts → worktree-fanout-DIffZohV.d.ts} +15 -5
- package/package.json +6 -1
- package/dist/chunk-4KGQHS7U.js.map +0 -1
- package/dist/chunk-5ISW5JUF.js.map +0 -1
- package/dist/chunk-74UAWZXE.js +0 -278
- package/dist/chunk-74UAWZXE.js.map +0 -1
- package/dist/chunk-DVQGYDN5.js +0 -59
- package/dist/chunk-DVQGYDN5.js.map +0 -1
- package/dist/chunk-INXDNX2W.js +0 -475
- package/dist/chunk-INXDNX2W.js.map +0 -1
- package/dist/chunk-K3RM4MPM.js.map +0 -1
- package/dist/chunk-VLF5RHEQ.js.map +0 -1
- package/dist/chunk-XRYEZPR6.js +0 -88
- package/dist/chunk-XRYEZPR6.js.map +0 -1
- package/dist/coordination-BPQmuwv8.d.ts +0 -666
- package/dist/delegation-profile-Bvfro2m1.d.ts +0 -99
|
@@ -1,581 +1,234 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DefaultVerdict, AgentEvalError } from '@tangle-network/agent-eval';
|
|
1
|
+
import { L as LocalHarness, p as ExecutorFactory, E as ExecutorRegistry, o as DeliverableSpec, l as Spend, g as Agent, m as Scope, h as ResultBlobStore, B as Budget } from './worktree-DaxOvw-C.js';
|
|
3
2
|
import { AgentProfile } from '@tangle-network/agent-interface';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { U as UiLens, a as UiFinding, C as CoderTask } from './substrate-rNj6TDc3.js';
|
|
4
|
+
import { e as LoopTraceEmitter, c as LoopTraceEvent, S as SandboxClient, A as AgentRunSpec, E as ExecCtx } from './types-JufmXF2a.js';
|
|
5
|
+
import { SandboxEvent, SandboxInstance, BackendType } from '@tangle-network/sandbox';
|
|
6
|
+
import { AgentEvalError } from '@tangle-network/agent-eval';
|
|
7
|
+
import { O as OtelExporter } from './otel-export-BKmNwiCb.js';
|
|
8
|
+
import { T as ToolSpec, R as RouterConfig } from './router-client-C7kp_ECN.js';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* @experimental
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* -
|
|
19
|
-
*
|
|
20
|
-
* the
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
|
|
13
|
+
* The child→parent message bus: the ONE pipe carrying every message a worker, sub-driver, or
|
|
14
|
+
* analyst sends up to the driver — settled outputs, questions, and trace-analyst findings. It
|
|
15
|
+
* unifies channels that were ad-hoc before (the settled-worker cursor, the ask-parent question
|
|
16
|
+
* channel, and analyst results) into a single typed primitive with two lanes:
|
|
17
|
+
*
|
|
18
|
+
* - PASS-THROUGH (`subscribe`): every published event reaches subscribers immediately — the
|
|
19
|
+
* express lane for online steering and live observation (a UI, a hook, the parent's box).
|
|
20
|
+
* - STANDBY (`pull`): events also queue so the driver consumes them on its own cadence. The queue
|
|
21
|
+
* is PRIORITY-ordered: a higher-`priority` event (a blocking question) is bumped ahead of
|
|
22
|
+
* queued settles/findings so the driver sees it first; ties resolve FIFO by publish order.
|
|
23
|
+
*
|
|
24
|
+
* Observability is first-class (A++): every event is stamped with a monotonic `seq` and wall-clock
|
|
25
|
+
* `at`, the full ordered `history()` is retained as an audit/replay trail, and `stats()` exposes
|
|
26
|
+
* published/pulled counts by kind. Subscribers receive the stamped record, not a bare event.
|
|
27
|
+
*
|
|
28
|
+
* The interface is transport-agnostic on purpose. Same box → this in-process queue. Cross box →
|
|
29
|
+
* the SAME publish/pull/subscribe surface backed by a durable mailbox on the parent's box (children
|
|
30
|
+
* POST events with at-least-once retry; payloads are blob refs so the event stays small). Consumers
|
|
31
|
+
* depend only on this interface, so distribution is a transport swap, never an architecture change.
|
|
32
|
+
*/
|
|
33
|
+
/** Every bus event is a discriminated union member keyed by `type`. */
|
|
34
|
+
interface BusEvent {
|
|
35
|
+
readonly type: string;
|
|
36
|
+
}
|
|
37
|
+
/** A published event stamped for ordering and observability. `seq` is the monotonic publish index;
|
|
38
|
+
* `priority` drives pull order (higher = bumped ahead); `at` is the wall-clock publish time (ms). */
|
|
39
|
+
interface BusRecord<E extends BusEvent> {
|
|
40
|
+
readonly seq: number;
|
|
41
|
+
readonly at: number;
|
|
42
|
+
readonly priority: number;
|
|
43
|
+
readonly event: E;
|
|
44
|
+
}
|
|
45
|
+
interface PublishOptions {
|
|
46
|
+
/** Higher = pulled ahead of lower-priority queued events (default 0). A blocking question sets
|
|
47
|
+
* this so it bumps to the front of the driver's inbox. */
|
|
48
|
+
readonly priority?: number;
|
|
49
|
+
/** Whether the event enters the pull queue (default true). Set `false` for record-only events —
|
|
50
|
+
* the parent→child down-leg (steer / answer / resume): they belong in `history()` and reach
|
|
51
|
+
* `subscribe` observers, but the parent must never `pull` its own outbound message back. */
|
|
52
|
+
readonly queue?: boolean;
|
|
53
|
+
}
|
|
54
|
+
interface BusStats {
|
|
55
|
+
readonly published: number;
|
|
56
|
+
readonly pulled: number;
|
|
57
|
+
/** Count published per event `type`. */
|
|
58
|
+
readonly byKind: Readonly<Record<string, number>>;
|
|
59
|
+
}
|
|
60
|
+
interface EventBus<E extends BusEvent> {
|
|
61
|
+
/** Stamp + queue the event, then deliver the stamped record to every subscriber in order.
|
|
62
|
+
* Returns the stamped record. */
|
|
63
|
+
publish(event: E, opts?: PublishOptions): Promise<BusRecord<E>>;
|
|
64
|
+
/** Remove and return the highest-priority QUEUED event whose type is in `kinds` (any if omitted),
|
|
65
|
+
* ties broken FIFO by `seq`; `undefined` when nothing matches. */
|
|
66
|
+
pull(kinds?: ReadonlyArray<E['type']>): E | undefined;
|
|
67
|
+
/** Register a pass-through handler; it receives the stamped record of every event published after
|
|
68
|
+
* registration. Returns an unsubscribe fn. */
|
|
69
|
+
subscribe(handler: (record: BusRecord<E>) => void | Promise<void>): () => void;
|
|
70
|
+
/** Count of queued, not-yet-pulled events (filtered by `kinds` when given). */
|
|
71
|
+
pending(kinds?: ReadonlyArray<E['type']>): number;
|
|
72
|
+
/** The full ordered log of every event ever published (the audit/replay trail). */
|
|
73
|
+
history(): ReadonlyArray<BusRecord<E>>;
|
|
74
|
+
/** Throughput counters for observability dashboards. */
|
|
75
|
+
stats(): BusStats;
|
|
76
|
+
}
|
|
77
|
+
declare function createEventBus<E extends BusEvent>(now?: () => number): EventBus<E>;
|
|
25
78
|
|
|
26
|
-
/** Local coding harness available inside the sandbox. */
|
|
27
|
-
type LocalHarness = 'claude' | 'codex' | 'opencode';
|
|
28
|
-
/** @experimental */
|
|
29
|
-
interface RunLocalHarnessOptions {
|
|
30
|
-
harness: LocalHarness;
|
|
31
|
-
/** Working directory for the subprocess (typically a worktree path). */
|
|
32
|
-
cwd: string;
|
|
33
|
-
/** Prompt forwarded as the harness CLI's task argument. */
|
|
34
|
-
taskPrompt: string;
|
|
35
|
-
/**
|
|
36
|
-
* Pre-built command + args (e.g. from `harnessInvocation` so the full authored
|
|
37
|
-
* `AgentProfile` — systemPrompt + model — reaches the harness). When set it OVERRIDES the
|
|
38
|
-
* default prompt-only `buildArgs(taskPrompt)` path; `command` defaults to the harness's
|
|
39
|
-
* default binary when only `args` is supplied. When absent the legacy prompt-only shape
|
|
40
|
-
* is used unchanged.
|
|
41
|
-
*/
|
|
42
|
-
invocation?: {
|
|
43
|
-
command?: string;
|
|
44
|
-
args: ReadonlyArray<string>;
|
|
45
|
-
};
|
|
46
|
-
/** Wall-clock kill deadline (ms). Default 5 min. Subprocess SIGTERMed on expiry. */
|
|
47
|
-
timeoutMs?: number;
|
|
48
|
-
/** Caller cancellation. SIGTERM is sent on abort. */
|
|
49
|
-
signal?: AbortSignal;
|
|
50
|
-
/** Override env (defaults to inheriting from the parent). */
|
|
51
|
-
env?: NodeJS.ProcessEnv;
|
|
52
|
-
/**
|
|
53
|
-
* Test seam — inject a custom spawner so unit tests can mock the
|
|
54
|
-
* subprocess without touching the OS. Defaults to node's `child_process.spawn`.
|
|
55
|
-
*/
|
|
56
|
-
spawn?: (command: string, args: ReadonlyArray<string>, opts: {
|
|
57
|
-
cwd: string;
|
|
58
|
-
env: NodeJS.ProcessEnv;
|
|
59
|
-
stdio: 'pipe';
|
|
60
|
-
}) => ChildProcess;
|
|
61
|
-
}
|
|
62
|
-
/** @experimental */
|
|
63
|
-
interface LocalHarnessResult {
|
|
64
|
-
/** OS exit code. `null` when killed before exit. */
|
|
65
|
-
exitCode: number | null;
|
|
66
|
-
/** Concatenated stdout. */
|
|
67
|
-
stdout: string;
|
|
68
|
-
/** Concatenated stderr. */
|
|
69
|
-
stderr: string;
|
|
70
|
-
/** Set when the process exited via signal (timeout / abort). */
|
|
71
|
-
killedBySignal: NodeJS.Signals | null;
|
|
72
|
-
/** Wall-clock duration ms (spawn → exit). */
|
|
73
|
-
durationMs: number;
|
|
74
|
-
/** Set when timeoutMs elapsed before exit. */
|
|
75
|
-
timedOut: boolean;
|
|
76
|
-
}
|
|
77
79
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* NOT responsible for parsing the harness's output or extracting a diff —
|
|
81
|
-
* the in-process executor's `streamPrompt` orchestrates `git diff` against
|
|
82
|
-
* the worktree after this resolves. This function is intentionally narrow:
|
|
83
|
-
* spawn, wait, capture, return.
|
|
84
|
-
*
|
|
85
|
-
* Fails loud — throws when:
|
|
86
|
-
* - `cwd` doesn't exist (subprocess emits ENOENT; surfaced as Error)
|
|
87
|
-
* - the harness binary is not on PATH (ENOENT)
|
|
80
|
+
* @experimental
|
|
88
81
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
82
|
+
* Sandbox-session coder decode layer. The sandbox-session delegate (`./delegates`) and the
|
|
83
|
+
* cross-restart resume driver run the in-box harness over a `SandboxClient` and need to
|
|
84
|
+
* (a) build an `AgentRunSpec` from the caller-authored (or minimal model-only default) worker
|
|
85
|
+
* profile, (b) decode the harness event stream into a structured `CoderOutput`, and (c) gate it with
|
|
86
|
+
* the shared mechanical checks. This sandbox-session path is kept separate from the generic recursive
|
|
87
|
+
* path: `worktreeFanout` instead settles the raw `WorktreePatchArtifact` and gates via
|
|
88
|
+
* `patchDelivered`. Prefer `worktreeFanout` / `worktreeLoopRunner` for NEW local-repo coding.
|
|
93
89
|
*
|
|
94
|
-
*
|
|
90
|
+
* The decode tolerates two `result`-event shapes:
|
|
91
|
+
* 1. the in-process executor's raw worktree-harness result (`{ branch, patch, stats, checks }`),
|
|
92
|
+
* projected onto `CoderOutput`; and
|
|
93
|
+
* 2. an LLM-emitted JSON block (`{ branch, patch, testResult, typecheckResult, diffStats }`),
|
|
94
|
+
* lifted onto `data.result` or scanned out of the assistant transcript (any harness shape).
|
|
95
95
|
*/
|
|
96
|
-
|
|
96
|
+
|
|
97
|
+
/** @experimental The structured coder result the sandbox-session path decodes + gates. */
|
|
98
|
+
interface CoderOutput {
|
|
99
|
+
/** Branch the agent wrote the patch on. */
|
|
100
|
+
branch: string;
|
|
101
|
+
/** Unified diff (`git diff <base>..HEAD`). */
|
|
102
|
+
patch: string;
|
|
103
|
+
testResult: {
|
|
104
|
+
passed: boolean;
|
|
105
|
+
output: string;
|
|
106
|
+
};
|
|
107
|
+
typecheckResult: {
|
|
108
|
+
passed: boolean;
|
|
109
|
+
output: string;
|
|
110
|
+
};
|
|
111
|
+
diffStats: {
|
|
112
|
+
filesChanged: number;
|
|
113
|
+
insertions: number;
|
|
114
|
+
deletions: number;
|
|
115
|
+
};
|
|
116
|
+
/** Optional reviewer commentary surfaced by the agent. */
|
|
117
|
+
reviewerNotes?: string;
|
|
118
|
+
}
|
|
97
119
|
|
|
98
120
|
/**
|
|
99
121
|
* @experimental
|
|
100
122
|
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* One self-similar `Agent` atom runs inside a budget-conserving reactive `Scope`,
|
|
104
|
-
* orchestrated by a `Supervisor` over an event-sourced `SpawnJournal`. A leaf is an
|
|
105
|
-
* `Agent` that never calls `scope.spawn`; a driver is an `Agent` that spawns and runs
|
|
106
|
-
* a policy over its children's streaming results.
|
|
107
|
-
*
|
|
108
|
-
* Two invariants the surface exists to make enforceable:
|
|
109
|
-
* - Budget is an atomically-reserved CONSERVED pool, so `Σk(treatment) ≡ Σk(blind)` by
|
|
110
|
-
* construction (reserve-on-spawn, refund-unspent-on-settle, fail-closed admission).
|
|
111
|
-
* - The journal records a content-addressed `outRef` per child result, so replay
|
|
112
|
-
* rehydrates the exact `Settled` the driver branched on (the replay invariant below).
|
|
123
|
+
* Persistence port for the MCP delegation queue.
|
|
113
124
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
125
|
+
* `DelegationTaskQueue` keeps its working set in memory (status/history
|
|
126
|
+
* reads stay synchronous) and journals every record mutation through a
|
|
127
|
+
* `DelegationStore`. `DelegationTaskQueue.restore({ store })` is the load
|
|
128
|
+
* path: it reads the full record set once at construction and rehydrates
|
|
129
|
+
* the queue from it. After that the store only sees writes.
|
|
118
130
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
131
|
+
* Records MUST be JSON-safe — `FileDelegationStore` round-trips them
|
|
132
|
+
* through `JSON.stringify`/`JSON.parse`, so a `Date`, `Map`, or function
|
|
133
|
+
* smuggled into `args`/`result` would corrupt the journal.
|
|
122
134
|
*/
|
|
123
135
|
|
|
124
|
-
/**
|
|
125
|
-
|
|
126
|
-
* is an `Agent` whose `act` spawns children and reacts to them via `scope.next()`. An
|
|
127
|
-
* analyst is an `Agent` whose task is "read these traces → findings" — `where` it runs
|
|
128
|
-
* is its executor, not a separate type.
|
|
129
|
-
*
|
|
130
|
-
* `act` MUST be replay-safe: it may read `verdict`, `spent`, and `out` (rehydrated by
|
|
131
|
-
* `outRef`) off each `Settled`; it MUST NOT read `Date.now`, `Math.random`, or any
|
|
132
|
-
* unordered collection. `scope.next()` delivers strictly in recorded `seq` order.
|
|
133
|
-
*/
|
|
134
|
-
interface Agent<Task, Out> {
|
|
135
|
-
readonly name: string;
|
|
136
|
-
act(task: Task, scope: Scope<Out>): Promise<Out>;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* The leaf runtime — ONE open interface, not a closed union. `execute` returns a
|
|
140
|
-
* `Promise<ExecutorResult>` for one-shot executors OR an `AsyncIterable<UsageEvent>` for
|
|
141
|
-
* streaming ones; a streaming executor reports incremental normalized usage as it runs
|
|
142
|
-
* (the budget pool reconciles against it) and exposes its terminal artifact via
|
|
143
|
-
* `resultArtifact()`. Both shapes normalize usage to `UsageEvent` so the conserved pool
|
|
144
|
-
* meters every runtime identically.
|
|
145
|
-
*
|
|
146
|
-
* Built-in implementations (in `runtime.ts`, NOT variants here): router/inline (a direct
|
|
147
|
-
* Router/HTTP inference call, no box), sandbox (COMPOSES `runLoop` as a leaf, forwarding
|
|
148
|
-
* PR #150's optional `lineage` passthrough — does NOT reinvent checkpoint/fork), cli
|
|
149
|
-
* (Halo/RLM subprocess; `budgetExempt`, excluded from equal-k by construction). A user's
|
|
150
|
-
* own agent (mastra/agno/raw HTTP/anything) is first-class by implementing this interface.
|
|
151
|
-
*/
|
|
152
|
-
interface Executor<Out> {
|
|
153
|
-
/** Stable runtime tag for traces + the equal-k exemption check. */
|
|
154
|
-
readonly runtime: Runtime;
|
|
155
|
-
/**
|
|
156
|
-
* When true, this executor's spend is NOT metered against the conserved pool and its
|
|
157
|
-
* iterations are excluded from the equal-k assertion (a `cli` subprocess without
|
|
158
|
-
* token accounting). Fail-loud everywhere else: a metered executor MUST report usage.
|
|
159
|
-
*/
|
|
160
|
-
readonly budgetExempt?: boolean;
|
|
161
|
-
/**
|
|
162
|
-
* One-shot → resolves a `ExecutorResult`; streaming → yields incremental `UsageEvent`s and
|
|
163
|
-
* the terminal artifact is read from `resultArtifact()` after the stream drains.
|
|
164
|
-
* `signal` is the spawn-scoped abort (chains the acquire lifecycle for sandbox).
|
|
165
|
-
*/
|
|
166
|
-
execute(task: unknown, signal: AbortSignal): Promise<ExecutorResult<Out>> | AsyncIterable<UsageEvent>;
|
|
167
|
-
/**
|
|
168
|
-
* Optional inbox: receive an out-of-band message from the driver mid-run (the `send`/`steer_agent`
|
|
169
|
-
* verb). A streaming executor drains pending messages between turns and folds them into the next
|
|
170
|
-
* step (a steer / interrupt / resume). A one-shot executor that can't be steered mid-flight omits
|
|
171
|
-
* this; `Scope.send` then returns `false` for it. Never throws — a malformed message is the
|
|
172
|
-
* executor's to ignore.
|
|
173
|
-
*/
|
|
174
|
-
deliver?(msg: unknown): void;
|
|
175
|
-
/**
|
|
176
|
-
* Tear the executor's resources down. `grace` mirrors the OTP shutdown spec
|
|
177
|
-
* (`'brutalKill'` = immediate, a number = ms grace, `'infinity'` = await clean exit).
|
|
178
|
-
*/
|
|
179
|
-
teardown(grace: number | 'brutalKill' | 'infinity'): Promise<{
|
|
180
|
-
destroyed: boolean;
|
|
181
|
-
}>;
|
|
136
|
+
/** @experimental */
|
|
137
|
+
interface DelegationStore {
|
|
182
138
|
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
139
|
+
* Read every persisted record. Called once, by
|
|
140
|
+
* `DelegationTaskQueue.restore`, before any write. A missing backing
|
|
141
|
+
* file is an empty store; an unparseable one throws
|
|
142
|
+
* `DelegationStateCorruptError`.
|
|
185
143
|
*/
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
verdict?: DefaultVerdict;
|
|
190
|
-
spent: Spend;
|
|
191
|
-
};
|
|
144
|
+
loadAll(): Promise<DelegationRecord[]>;
|
|
145
|
+
/** Insert or replace the record keyed by `record.taskId`. */
|
|
146
|
+
upsert(record: DelegationRecord): Promise<void>;
|
|
192
147
|
/**
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
* trips the reservation clamp. Read on settle, valid after `execute` resolves OR throws. Leaf
|
|
198
|
-
* executors omit it (returns `undefined`).
|
|
148
|
+
* Resolve an idempotency key to the taskId that claimed it, if any.
|
|
149
|
+
* The queue serves submit-time dedupe from its rehydrated in-memory
|
|
150
|
+
* index; this read exists for consumers that share a store across
|
|
151
|
+
* processes without holding the full record set.
|
|
199
152
|
*/
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
interface ExecutorResult<Out> {
|
|
204
|
-
outRef: string;
|
|
205
|
-
out: Out;
|
|
206
|
-
verdict?: DefaultVerdict;
|
|
207
|
-
spent: Spend;
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Normalized usage event — the single channel every executor reports through, so the
|
|
211
|
-
* conserved pool meters all runtimes identically. `tokens` carries `LoopTokenUsage`'s
|
|
212
|
-
* `{ input, output }`; `usd` is a SEPARATE channel (never folded into tokens).
|
|
213
|
-
*/
|
|
214
|
-
type UsageEvent = {
|
|
215
|
-
kind: 'tokens';
|
|
216
|
-
input: number;
|
|
217
|
-
output: number;
|
|
218
|
-
} | {
|
|
219
|
-
kind: 'cost';
|
|
220
|
-
usd: number;
|
|
221
|
-
} | {
|
|
222
|
-
kind: 'iteration';
|
|
223
|
-
};
|
|
224
|
-
/** The runtime tag of a `Executor` impl. Open by intent — `string` so a BYO executor
|
|
225
|
-
* names its own runtime; the built-ins use these literals. */
|
|
226
|
-
type Runtime = 'router' | 'inline' | 'sandbox' | 'cli' | (string & {});
|
|
227
|
-
/**
|
|
228
|
-
* `AgentProfile` does NOT carry a `harness`/backend field — `harness` lives on the
|
|
229
|
-
* sandbox SDK's `BackendConfig`, not the portable profile. So an agent is mapped to its
|
|
230
|
-
* executor through this MINIMAL wrapper, never by fabricating a field onto `AgentProfile`.
|
|
231
|
-
*
|
|
232
|
-
* Resolution (in `runtime.ts`):
|
|
233
|
-
* - `executor` present → BYO: use it verbatim (a user's own `Executor`).
|
|
234
|
-
* - `harness === null` → router/inline: a direct Router call, no box.
|
|
235
|
-
* - `harness` is a `BackendType` → sandbox: compose `runLoop` against `profile` on that backend.
|
|
236
|
-
* Fail loud on an unresolvable spec (no executor and an unknown harness).
|
|
237
|
-
*/
|
|
238
|
-
interface AgentSpec {
|
|
239
|
-
readonly profile: AgentProfile;
|
|
240
|
-
/** `null` selects router/inline; a `BackendType` selects the sandboxed harness. */
|
|
241
|
-
readonly harness: BackendType | null;
|
|
242
|
-
/** Bring-your-own executor: when set, overrides harness-based resolution entirely. */
|
|
243
|
-
readonly executor?: Executor<unknown>;
|
|
153
|
+
lookupIdempotencyKey(key: string): Promise<string | undefined>;
|
|
154
|
+
/** Delete the named records — the retention-cap eviction path. */
|
|
155
|
+
remove(taskIds: readonly string[]): Promise<void>;
|
|
244
156
|
}
|
|
245
157
|
/**
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
158
|
+
* The persisted delegation state exists but cannot be parsed into
|
|
159
|
+
* records. Fail loud: silently starting empty over a corrupt journal
|
|
160
|
+
* would erase delegation history and re-run idempotent work. Opt into
|
|
161
|
+
* recovery explicitly via `FileDelegationStoreOptions.recoverCorrupt`
|
|
162
|
+
* (the bin maps `AGENT_RUNTIME_DELEGATION_STATE_RECOVER=1` onto it),
|
|
163
|
+
* which archives the corrupt file and starts fresh.
|
|
164
|
+
*
|
|
165
|
+
* @experimental
|
|
249
166
|
*/
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
interface ExecutorContext {
|
|
255
|
-
readonly signal: AbortSignal;
|
|
256
|
-
/** Opaque seams the registry threads through; a built-in narrows what it needs. */
|
|
257
|
-
readonly seams: Readonly<Record<string, unknown>>;
|
|
167
|
+
declare class DelegationStateCorruptError extends AgentEvalError {
|
|
168
|
+
constructor(message: string, options?: {
|
|
169
|
+
cause?: unknown;
|
|
170
|
+
});
|
|
258
171
|
}
|
|
259
172
|
/**
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
173
|
+
* A delegation-store read or write failed (filesystem error, store
|
|
174
|
+
* called before `loadAll`, ...). Once the queue observes one, it stops
|
|
175
|
+
* accepting new submissions — accepting work it cannot journal would
|
|
176
|
+
* silently demote durable mode to in-memory mode.
|
|
177
|
+
*
|
|
178
|
+
* @experimental
|
|
264
179
|
*/
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
* Resolve a spec to a factory. Precedence: a BYO `spec.executor` → a trivial factory
|
|
270
|
-
* returning it; else `harness === null` → the `'router'` factory; else a registered
|
|
271
|
-
* factory for the harness-derived runtime. Returns a typed outcome — the caller
|
|
272
|
-
* inspects `succeeded` before `value` (no silent fallback).
|
|
273
|
-
*/
|
|
274
|
-
resolve<Out>(spec: AgentSpec): {
|
|
275
|
-
succeeded: true;
|
|
276
|
-
value: ExecutorFactory<Out>;
|
|
277
|
-
} | {
|
|
278
|
-
succeeded: false;
|
|
279
|
-
error: string;
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
/** A budget envelope on a spawn or the root. All ceilings; the pool reserves against them. */
|
|
283
|
-
interface Budget {
|
|
284
|
-
readonly maxIterations: number;
|
|
285
|
-
readonly maxTokens: number;
|
|
286
|
-
readonly maxUsd?: number;
|
|
287
|
-
readonly deadlineMs?: number;
|
|
288
|
-
}
|
|
289
|
-
/** Conserved spend, reconciled from the normalized `UsageEvent` stream. Tokens and usd
|
|
290
|
-
* are separate channels (never folded). */
|
|
291
|
-
interface Spend {
|
|
292
|
-
iterations: number;
|
|
293
|
-
tokens: LoopTokenUsage;
|
|
294
|
-
usd: number;
|
|
295
|
-
ms: number;
|
|
296
|
-
}
|
|
297
|
-
/** OTP child-spec restart class. */
|
|
298
|
-
type Restart = 'temporary' | 'transient' | 'permanent';
|
|
299
|
-
/** `'acquiring'` is first-class (M1): a node spends real time + reaps an orphan box
|
|
300
|
-
* during sandbox acquire BEFORE it is `running`, so abort must be defined over it. */
|
|
301
|
-
type NodeStatus = 'pending' | 'acquiring' | 'running' | 'done' | 'failed' | 'cancelled';
|
|
302
|
-
/** Deterministic node id — `${parent}:s${seq}` from the cursor order, never wall-clock. */
|
|
303
|
-
type NodeId = string;
|
|
304
|
-
interface SpawnOpts {
|
|
305
|
-
readonly budget: Budget;
|
|
306
|
-
readonly label: string;
|
|
307
|
-
readonly restart?: Restart;
|
|
308
|
-
/** Teardown grace handed to the executor when this node is reaped. */
|
|
309
|
-
readonly shutdown?: number | 'brutalKill' | 'infinity';
|
|
180
|
+
declare class DelegationPersistenceError extends AgentEvalError {
|
|
181
|
+
constructor(message: string, options?: {
|
|
182
|
+
cause?: unknown;
|
|
183
|
+
});
|
|
310
184
|
}
|
|
311
|
-
/**
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
readonly
|
|
318
|
-
readonly label: string;
|
|
319
|
-
readonly status: NodeStatus;
|
|
320
|
-
abort(reason?: string): void;
|
|
321
|
-
/** Phantom: binds the handle to the child's output type so `spawn<C>` returns a
|
|
322
|
-
* `Handle<C>` distinct from a `Handle<other>`. Type-only — never present at runtime. */
|
|
323
|
-
readonly __out?: Out;
|
|
185
|
+
/** @experimental */
|
|
186
|
+
declare class InMemoryDelegationStore implements DelegationStore {
|
|
187
|
+
private readonly records;
|
|
188
|
+
loadAll(): Promise<DelegationRecord[]>;
|
|
189
|
+
upsert(record: DelegationRecord): Promise<void>;
|
|
190
|
+
lookupIdempotencyKey(key: string): Promise<string | undefined>;
|
|
191
|
+
remove(taskIds: readonly string[]): Promise<void>;
|
|
324
192
|
}
|
|
325
|
-
/**
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
*/
|
|
330
|
-
type Settled<Out> = {
|
|
331
|
-
kind: 'done';
|
|
332
|
-
handle: Handle<Out>;
|
|
333
|
-
out: Out;
|
|
334
|
-
outRef: string;
|
|
335
|
-
verdict?: DefaultVerdict;
|
|
336
|
-
spent: Spend;
|
|
337
|
-
seq: number;
|
|
338
|
-
} | {
|
|
339
|
-
kind: 'down';
|
|
340
|
-
handle: Handle<Out>;
|
|
341
|
-
reason: string;
|
|
342
|
-
/** True = infrastructure failure (excluded from merge `n` / equal-k), not a bad result. */
|
|
343
|
-
infra: boolean;
|
|
344
|
-
restartCount: number;
|
|
345
|
-
seq: number;
|
|
346
|
-
};
|
|
347
|
-
/**
|
|
348
|
-
* The budget-conserving reactive scope an `Agent.act` runs inside. `spawn` reserves
|
|
349
|
-
* budget atomically from the shared pool and fails closed when the pool cannot cover it.
|
|
350
|
-
* `next()` waits for one settlement from this scope's live set; `view` reads live state,
|
|
351
|
-
* not the replay log.
|
|
352
|
-
*/
|
|
353
|
-
interface Scope<Out> {
|
|
354
|
-
/**
|
|
355
|
-
* Spawn a child. Reserves `opts.budget` from the conserved pool atomically; refunds the
|
|
356
|
-
* unspent remainder on settle. Returns a typed outcome — fail-closed on an exhausted
|
|
357
|
-
* pool or an exceeded depth ceiling (the caller inspects `ok` before `handle`).
|
|
358
|
-
*/
|
|
359
|
-
spawn<C extends Out>(agent: Agent<unknown, C>, task: unknown, opts: SpawnOpts): {
|
|
360
|
-
ok: true;
|
|
361
|
-
handle: Handle<C>;
|
|
362
|
-
} | {
|
|
363
|
-
ok: false;
|
|
364
|
-
reason: 'budget-exhausted' | 'depth-exceeded';
|
|
365
|
-
};
|
|
366
|
-
/** ray.wait n=1 over this scope's in-memory live set; resolves as each child settles;
|
|
367
|
-
* `null` when the live set is empty. */
|
|
368
|
-
next(): Promise<Settled<Out> | null>;
|
|
369
|
-
/**
|
|
370
|
-
* Steer a RUNNING child out-of-band — deliver a message to its executor's inbox (the driver's
|
|
371
|
-
* `send` verb: next-instruction, interrupt, or resume). Returns `true` if the message was
|
|
372
|
-
* delivered to a live child whose executor accepts delivery, `false` otherwise (unknown id,
|
|
373
|
-
* already settled, or an executor with no inbox). The executor drains its inbox between turns;
|
|
374
|
-
* a leaf that does not implement `deliver` simply cannot be steered mid-flight. In-process this
|
|
375
|
-
* is a direct call; the sandbox/Agent-Bus transports surface the SAME verb as an MCP tool.
|
|
376
|
-
*/
|
|
377
|
-
send(nodeId: NodeId, msg: unknown): boolean;
|
|
378
|
-
/** This scope's abort signal — aborted when the run is cancelled, a breaker trips, the pool
|
|
379
|
-
* is exhausted, or a parent scope cascades. A long-running driver `act` over this scope reads
|
|
380
|
-
* it to break promptly (the conserved pool + driver-stop are the other bounds). A nested
|
|
381
|
-
* scope carries its own signal, chained off its driver child's abort. */
|
|
382
|
-
readonly signal: AbortSignal;
|
|
193
|
+
/** @experimental */
|
|
194
|
+
interface FileDelegationStoreOptions {
|
|
195
|
+
/** Absolute path of the JSON state file. Parent directories are created on first write. */
|
|
196
|
+
filePath: string;
|
|
383
197
|
/**
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
* halts a driver that thinks the pool dry. `detail` rides an `agent.turn` trace event for live
|
|
388
|
-
* observability (turn index, tool calls, cumulative spend). It also journals a `metered` event —
|
|
389
|
-
* the durable twin of the pool debit (as `settled` is the twin of `reconcile`) — so every
|
|
390
|
-
* journal-based cost reader (`spentFromJournal`, `trajectoryReport`) sums driver inference
|
|
391
|
-
* automatically. A leaf never calls this; a driver meters each chat turn and awaits it (the
|
|
392
|
-
* metered event is cost-critical, so it lands before the join-barrier roll-up).
|
|
198
|
+
* When the state file exists but cannot be parsed, archive it to
|
|
199
|
+
* `<filePath>.corrupt-<timestamp>` and start empty instead of
|
|
200
|
+
* throwing `DelegationStateCorruptError`. Default false.
|
|
393
201
|
*/
|
|
394
|
-
|
|
395
|
-
/** The live tree — reads the in-memory nursery, not the journal. */
|
|
396
|
-
readonly view: TreeView;
|
|
397
|
-
/** Conserved-pool readouts (post-reservation). */
|
|
398
|
-
readonly budget: Readonly<{
|
|
399
|
-
tokensLeft: number;
|
|
400
|
-
usdLeft: number;
|
|
401
|
-
usdCapped: boolean;
|
|
402
|
-
deadlineMs: number;
|
|
403
|
-
reservedTokens: number;
|
|
404
|
-
}>;
|
|
405
|
-
}
|
|
406
|
-
interface NodeSnapshot {
|
|
407
|
-
readonly id: NodeId;
|
|
408
|
-
readonly parent?: NodeId;
|
|
409
|
-
readonly label: string;
|
|
410
|
-
readonly status: NodeStatus;
|
|
411
|
-
readonly runtime: Runtime;
|
|
412
|
-
readonly budget: Budget;
|
|
413
|
-
/** Conserved spend so far for this node. */
|
|
414
|
-
readonly spent: Spend;
|
|
415
|
-
/** `outRef` once the node is `done` (the replay/result pointer). */
|
|
416
|
-
readonly outRef?: string;
|
|
417
|
-
}
|
|
418
|
-
/** The live tree — what `scope.view` / `RootHandle.view()` materialize for a viewer. */
|
|
419
|
-
interface TreeView {
|
|
420
|
-
readonly root: NodeId;
|
|
421
|
-
readonly nodes: ReadonlyArray<NodeSnapshot>;
|
|
422
|
-
/** Count of nodes in `running` or `acquiring` — the "what's in flow?" answer. */
|
|
423
|
-
readonly inFlight: number;
|
|
424
|
-
}
|
|
425
|
-
/** Journaled spawn-tree events (B1/B2). `seq` is the cursor order; `at` is an ISO
|
|
426
|
-
* timestamp for human inspection only (NOT a replay input). */
|
|
427
|
-
type SpawnEvent = {
|
|
428
|
-
kind: 'spawned';
|
|
429
|
-
id: NodeId;
|
|
430
|
-
parent?: NodeId;
|
|
431
|
-
label: string;
|
|
432
|
-
budget: Budget;
|
|
433
|
-
runtime: Runtime;
|
|
434
|
-
seq: number;
|
|
435
|
-
at: string;
|
|
436
|
-
} | {
|
|
437
|
-
kind: 'settled';
|
|
438
|
-
id: NodeId;
|
|
439
|
-
status: 'done' | 'down';
|
|
440
|
-
/** Content-addressed result pointer; rehydrates `out` from `ResultBlobStore`. */
|
|
441
|
-
outRef?: string;
|
|
442
|
-
verdict?: DefaultVerdict;
|
|
443
|
-
spent: Spend;
|
|
444
|
-
infra?: boolean;
|
|
445
|
-
seq: number;
|
|
446
|
-
at: string;
|
|
447
|
-
} | {
|
|
448
|
-
kind: 'cancelled';
|
|
449
|
-
id: NodeId;
|
|
450
|
-
reason: string;
|
|
451
|
-
seq: number;
|
|
452
|
-
at: string;
|
|
453
|
-
} | {
|
|
454
|
-
/** A driver's OWN inference spend, journaled separately from spawned-child work — the journal
|
|
455
|
-
* TWIN of `BudgetPool.observe`, exactly as `settled` is the twin of `reconcile`. So every
|
|
456
|
-
* journal-based cost reader sums it automatically — the journal is the single cost ledger.
|
|
457
|
-
* It carries spend only and is NOT a settlement: replay + `materializeTreeView` skip it for
|
|
458
|
-
* structure, and its `seq` lives outside the cursor-uniqueness namespace. A
|
|
459
|
-
* driver re-homes its nested subtree's metered total up to its parent (like settled spend),
|
|
460
|
-
* so summing any sub-tree root yields that sub-tree's true driver-inference cost. */
|
|
461
|
-
kind: 'metered';
|
|
462
|
-
id: NodeId;
|
|
463
|
-
spend: Spend;
|
|
464
|
-
seq: number;
|
|
465
|
-
at: string;
|
|
466
|
-
};
|
|
467
|
-
/**
|
|
468
|
-
* The spawn-tree event source (mirrors `ConversationJournal`'s begin/append/load shape).
|
|
469
|
-
* `loadTree` replays the full ordered event list for resume/replay; `appendEvent` is
|
|
470
|
-
* called only AFTER the event is observed-committed (never speculative).
|
|
471
|
-
*/
|
|
472
|
-
interface SpawnJournal {
|
|
473
|
-
loadTree(root: NodeId): Promise<SpawnEvent[] | undefined>;
|
|
474
|
-
beginTree(root: NodeId, at: string): Promise<void>;
|
|
475
|
-
appendEvent(root: NodeId, ev: SpawnEvent): Promise<void>;
|
|
476
|
-
}
|
|
477
|
-
/** Content-addressed result blobs (the `outRef` → artifact map) backing the replay
|
|
478
|
-
* invariant. Split from the journal so the journal stays small (decisions) and the
|
|
479
|
-
* payloads (evidence) live where a viewer/replayer rehydrates them. */
|
|
480
|
-
interface ResultBlobStore {
|
|
481
|
-
put(outRef: string, artifact: unknown): Promise<void>;
|
|
482
|
-
get(outRef: string): Promise<unknown | undefined>;
|
|
202
|
+
recoverCorrupt?: boolean;
|
|
483
203
|
}
|
|
484
204
|
/**
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
/** Trace-correlation root + the journal/blob root key. */
|
|
497
|
-
readonly runId: NodeId;
|
|
498
|
-
/** Event source — defaults to the in-memory journal in the impl; pass JSONL/FS for durability. */
|
|
499
|
-
readonly journal: SpawnJournal;
|
|
500
|
-
/** Result payload store backing `outRef` rehydration. */
|
|
501
|
-
readonly blobs: ResultBlobStore;
|
|
502
|
-
/** Executor resolution — the open registry mapping `AgentSpec` → `Executor`. */
|
|
503
|
-
readonly executors: ExecutorRegistry;
|
|
504
|
-
/** Runtime recursion-depth ceiling (paired with the conserved pool per R3). */
|
|
505
|
-
readonly maxDepth?: number;
|
|
506
|
-
/**
|
|
507
|
-
* OTP intensity breaker: more than `maxRestarts` child restarts within `withinMs`
|
|
508
|
-
* trips the supervisor to `no-winner` rather than restarting forever.
|
|
509
|
-
*/
|
|
510
|
-
readonly maxRestarts?: number;
|
|
511
|
-
readonly withinMs?: number;
|
|
512
|
-
readonly now?: () => number;
|
|
513
|
-
readonly signal?: AbortSignal;
|
|
514
|
-
/** Lifecycle stream sink, threaded into the root `Scope` so every `spawn`/settle emits on the
|
|
515
|
-
* same `agent.spawn`/`agent.child` stream `runLoop` feeds — one observable recursive tree. */
|
|
516
|
-
readonly hooks?: RuntimeHooks;
|
|
517
|
-
}
|
|
518
|
-
/** Typed terminal result (M2) — a no-winner is NEVER coerced to a best-effort output. */
|
|
519
|
-
type SupervisedResult<Out> = {
|
|
520
|
-
kind: 'winner';
|
|
521
|
-
out: Out;
|
|
522
|
-
outRef: string;
|
|
523
|
-
verdict?: DefaultVerdict;
|
|
524
|
-
tree: TreeView;
|
|
525
|
-
spentTotal: Spend;
|
|
526
|
-
/** Where `spentTotal` went: `driverInference` = the drivers' own chat turns (metered via
|
|
527
|
-
* `Scope.meter`); `childWork` = every spawned child's reconciled spend (the journal sum).
|
|
528
|
-
* `driverInference + childWork === spentTotal`. Present whenever any driver metered. */
|
|
529
|
-
spentBreakdown?: {
|
|
530
|
-
driverInference: Spend;
|
|
531
|
-
childWork: Spend;
|
|
532
|
-
};
|
|
533
|
-
} | {
|
|
534
|
-
kind: 'no-winner';
|
|
535
|
-
reason: 'all-children-down' | 'budget-exhausted' | 'aborted';
|
|
536
|
-
tree: TreeView;
|
|
537
|
-
downCount: number;
|
|
538
|
-
/** The conserved spend incurred before the run failed — real cost is paid even when no
|
|
539
|
-
* worker delivers, so the caller always learns what the delegation actually spent. Summed
|
|
540
|
-
* off the same journal the `winner` path reads. */
|
|
541
|
-
spentTotal: Spend;
|
|
542
|
-
};
|
|
543
|
-
/** Live root handle — the substrate a chat/pi-viz client attaches to (Q2). `signal`
|
|
544
|
-
* delivers an out-of-band message to the running root; `view()` materializes the tree. */
|
|
545
|
-
interface RootHandle<Out> {
|
|
546
|
-
view(): TreeView;
|
|
547
|
-
signal(msg: RootSignal): void;
|
|
548
|
-
abort(reason?: string): void;
|
|
549
|
-
/** Phantom: binds the handle to the supervised run's output type. Type-only — never
|
|
550
|
-
* present at runtime; lets `attach(h: RootHandle<Out>)` stay output-typed. */
|
|
551
|
-
readonly __out?: Out;
|
|
552
|
-
}
|
|
553
|
-
/** Out-of-band message to a running root. Open by intent — a client extends it. */
|
|
554
|
-
type RootSignal = {
|
|
555
|
-
kind: 'pause';
|
|
556
|
-
} | {
|
|
557
|
-
kind: 'resume';
|
|
558
|
-
} | {
|
|
559
|
-
kind: 'cancel';
|
|
560
|
-
reason?: string;
|
|
561
|
-
} | {
|
|
562
|
-
kind: 'ask';
|
|
563
|
-
question: string;
|
|
564
|
-
};
|
|
565
|
-
/**
|
|
566
|
-
* The progressive-widening gate (MCTS-PW). Decides whether a settled child is
|
|
567
|
-
* `promising` enough to spawn another under the remaining pool. DEFAULTS TO FLAT
|
|
568
|
-
* (`shouldWiden` always false) so a gate run never widens and the selector≠judge
|
|
569
|
-
* firewall conflict (R2) stays dormant. When widening IS enabled, `promising` MUST be
|
|
570
|
-
* derived from TRACE findings (`analyses`), never raw `verdict` — or the gate carries
|
|
571
|
-
* an explicit, argued `judgeExempt: true` (the documented escape hatch, off by default).
|
|
205
|
+
* JSON-file persistence for the delegation queue. Each write serializes
|
|
206
|
+
* the full record set and lands it atomically (write to a sibling tmp
|
|
207
|
+
* file, then `rename`), so readers never observe a torn file — a crash
|
|
208
|
+
* mid-write leaves the previous snapshot intact. Writes are serialized
|
|
209
|
+
* internally; concurrent `upsert`/`remove` calls cannot interleave.
|
|
210
|
+
*
|
|
211
|
+
* Built for the MCP server's scale (one stdio process, hundreds of
|
|
212
|
+
* records): full-snapshot writes keep the format trivially inspectable
|
|
213
|
+
* and corruption-detectable without a database dependency.
|
|
214
|
+
*
|
|
215
|
+
* @experimental
|
|
572
216
|
*/
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
217
|
+
declare class FileDelegationStore implements DelegationStore {
|
|
218
|
+
private readonly filePath;
|
|
219
|
+
private readonly recoverCorrupt;
|
|
220
|
+
private readonly records;
|
|
221
|
+
private loaded;
|
|
222
|
+
private writeTail;
|
|
223
|
+
private tmpSeq;
|
|
224
|
+
constructor(options: FileDelegationStoreOptions);
|
|
225
|
+
loadAll(): Promise<DelegationRecord[]>;
|
|
226
|
+
upsert(record: DelegationRecord): Promise<void>;
|
|
227
|
+
lookupIdempotencyKey(key: string): Promise<string | undefined>;
|
|
228
|
+
remove(taskIds: readonly string[]): Promise<void>;
|
|
229
|
+
private assertLoaded;
|
|
230
|
+
private enqueueWrite;
|
|
231
|
+
private writeSnapshot;
|
|
579
232
|
}
|
|
580
233
|
|
|
581
234
|
/**
|
|
@@ -683,45 +336,50 @@ declare function composeLoopTraceEmitters(...emitters: ReadonlyArray<LoopTraceEm
|
|
|
683
336
|
/**
|
|
684
337
|
* @experimental
|
|
685
338
|
*
|
|
686
|
-
*
|
|
687
|
-
* cross-restart resume driver (`./bin`) run the in-box harness over a `SandboxClient` and need to
|
|
688
|
-
* (a) build an `AgentRunSpec` from the authored coder profile, (b) decode the harness event stream
|
|
689
|
-
* into a structured `CoderOutput`, and (c) gate it with the shared mechanical checks. This is the
|
|
690
|
-
* MCP server's built-in `delegate_code` path — it is the live default delegate, NOT dormant — and is
|
|
691
|
-
* kept separate from the generic recursive path: `worktreeFanout` instead settles the raw
|
|
692
|
-
* `WorktreePatchArtifact` and gates via `patchDelivered`. Only the OPTIONAL cross-restart resume
|
|
693
|
-
* (the `driveTurn` tick) is opt-in (`MCP_ENABLE_DETACHED_RESUME`); the held-stream delegate is
|
|
694
|
-
* always live. Prefer `worktreeFanout` / `worktreeLoopRunner` for NEW local-repo coding.
|
|
339
|
+
* Trace context propagation for MCP subprocess.
|
|
695
340
|
*
|
|
696
|
-
*
|
|
697
|
-
*
|
|
698
|
-
*
|
|
699
|
-
*
|
|
700
|
-
*
|
|
341
|
+
* When the MCP server is launched as a child process by a sandbox harness,
|
|
342
|
+
* the parent passes trace context via environment variables:
|
|
343
|
+
*
|
|
344
|
+
* TRACE_ID=<current-run-trace-id>
|
|
345
|
+
* PARENT_SPAN_ID=<span-that-dispatched-the-delegation>
|
|
346
|
+
*
|
|
347
|
+
* The MCP server reads these at startup and uses them as the root of its
|
|
348
|
+
* internal trace tree. All spans emitted by `runLoop` invocations inside
|
|
349
|
+
* the MCP are children of the parent's delegation span.
|
|
350
|
+
*
|
|
351
|
+
* When these env vars are absent, the MCP generates a fresh trace root —
|
|
352
|
+
* the server operates standalone without trace joining.
|
|
701
353
|
*/
|
|
702
354
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
patch: string;
|
|
709
|
-
testResult: {
|
|
710
|
-
passed: boolean;
|
|
711
|
-
output: string;
|
|
712
|
-
};
|
|
713
|
-
typecheckResult: {
|
|
714
|
-
passed: boolean;
|
|
715
|
-
output: string;
|
|
716
|
-
};
|
|
717
|
-
diffStats: {
|
|
718
|
-
filesChanged: number;
|
|
719
|
-
insertions: number;
|
|
720
|
-
deletions: number;
|
|
721
|
-
};
|
|
722
|
-
/** Optional reviewer commentary surfaced by the agent. */
|
|
723
|
-
reviewerNotes?: string;
|
|
355
|
+
interface TraceContext {
|
|
356
|
+
/** Trace id inherited from the parent process, or a fresh one. */
|
|
357
|
+
traceId: string;
|
|
358
|
+
/** Parent span id from the delegation that launched this MCP server. */
|
|
359
|
+
parentSpanId?: string;
|
|
724
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* Read trace context from the process environment.
|
|
363
|
+
* Returns a context with inherited ids or a freshly generated root.
|
|
364
|
+
*/
|
|
365
|
+
declare function readTraceContextFromEnv(): TraceContext;
|
|
366
|
+
/**
|
|
367
|
+
* Create a LoopTraceEmitter that:
|
|
368
|
+
* 1. Parents all spans under the inherited PARENT_SPAN_ID.
|
|
369
|
+
* 2. Exports spans to OTEL when OTEL_EXPORTER_OTLP_ENDPOINT is set.
|
|
370
|
+
*
|
|
371
|
+
* Returns both the emitter and the optional exporter handle for shutdown.
|
|
372
|
+
*/
|
|
373
|
+
declare function createPropagatingTraceEmitter(ctx: TraceContext): {
|
|
374
|
+
emitter: LoopTraceEmitter;
|
|
375
|
+
exporter: OtelExporter | undefined;
|
|
376
|
+
context: TraceContext;
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* Build env vars to pass to a child MCP subprocess so it inherits the
|
|
380
|
+
* current trace context.
|
|
381
|
+
*/
|
|
382
|
+
declare function traceContextToEnv(ctx: TraceContext): Record<string, string>;
|
|
725
383
|
|
|
726
384
|
/**
|
|
727
385
|
* @experimental
|
|
@@ -980,377 +638,36 @@ interface DelegationHistoryArgs {
|
|
|
980
638
|
/** @experimental */
|
|
981
639
|
interface DelegationFeedbackSnapshot {
|
|
982
640
|
id: string;
|
|
983
|
-
score: number;
|
|
984
|
-
label?: FeedbackRating['label'];
|
|
985
|
-
by: DelegateFeedbackArgs['by'];
|
|
986
|
-
notes: string;
|
|
987
|
-
capturedAt: string;
|
|
988
|
-
}
|
|
989
|
-
/** @experimental */
|
|
990
|
-
interface DelegationHistoryEntry {
|
|
991
|
-
taskId: string;
|
|
992
|
-
profile: DelegationProfile;
|
|
993
|
-
namespace?: string;
|
|
994
|
-
args: DelegateCodeArgs | DelegateResearchArgs | DelegateUiAuditArgs;
|
|
995
|
-
status: DelegationStatus;
|
|
996
|
-
feedback?: DelegationFeedbackSnapshot[];
|
|
997
|
-
costUsd?: number;
|
|
998
|
-
startedAt: string;
|
|
999
|
-
completedAt?: string;
|
|
1000
|
-
/**
|
|
1001
|
-
* True when the record carries a journaled loop trace. History stays
|
|
1002
|
-
* light by design — fetch the spans via
|
|
1003
|
-
* `delegation_status { taskId, includeTrace: true }`.
|
|
1004
|
-
*/
|
|
1005
|
-
hasTrace: boolean;
|
|
1006
|
-
/** Inherited trace identity recorded at submit — join key into the caller's trace. */
|
|
1007
|
-
traceId?: string;
|
|
1008
|
-
}
|
|
1009
|
-
/** @experimental */
|
|
1010
|
-
interface DelegationHistoryResult {
|
|
1011
|
-
delegations: DelegationHistoryEntry[];
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
/**
|
|
1015
|
-
* @experimental
|
|
1016
|
-
*
|
|
1017
|
-
* Persistence port for the MCP delegation queue.
|
|
1018
|
-
*
|
|
1019
|
-
* `DelegationTaskQueue` keeps its working set in memory (status/history
|
|
1020
|
-
* reads stay synchronous) and journals every record mutation through a
|
|
1021
|
-
* `DelegationStore`. `DelegationTaskQueue.restore({ store })` is the load
|
|
1022
|
-
* path: it reads the full record set once at construction and rehydrates
|
|
1023
|
-
* the queue from it. After that the store only sees writes.
|
|
1024
|
-
*
|
|
1025
|
-
* Records MUST be JSON-safe — `FileDelegationStore` round-trips them
|
|
1026
|
-
* through `JSON.stringify`/`JSON.parse`, so a `Date`, `Map`, or function
|
|
1027
|
-
* smuggled into `args`/`result` would corrupt the journal.
|
|
1028
|
-
*/
|
|
1029
|
-
|
|
1030
|
-
/** @experimental */
|
|
1031
|
-
interface DelegationStore {
|
|
1032
|
-
/**
|
|
1033
|
-
* Read every persisted record. Called once, by
|
|
1034
|
-
* `DelegationTaskQueue.restore`, before any write. A missing backing
|
|
1035
|
-
* file is an empty store; an unparseable one throws
|
|
1036
|
-
* `DelegationStateCorruptError`.
|
|
1037
|
-
*/
|
|
1038
|
-
loadAll(): Promise<DelegationRecord[]>;
|
|
1039
|
-
/** Insert or replace the record keyed by `record.taskId`. */
|
|
1040
|
-
upsert(record: DelegationRecord): Promise<void>;
|
|
1041
|
-
/**
|
|
1042
|
-
* Resolve an idempotency key to the taskId that claimed it, if any.
|
|
1043
|
-
* The queue serves submit-time dedupe from its rehydrated in-memory
|
|
1044
|
-
* index; this read exists for consumers that share a store across
|
|
1045
|
-
* processes without holding the full record set.
|
|
1046
|
-
*/
|
|
1047
|
-
lookupIdempotencyKey(key: string): Promise<string | undefined>;
|
|
1048
|
-
/** Delete the named records — the retention-cap eviction path. */
|
|
1049
|
-
remove(taskIds: readonly string[]): Promise<void>;
|
|
1050
|
-
}
|
|
1051
|
-
/**
|
|
1052
|
-
* The persisted delegation state exists but cannot be parsed into
|
|
1053
|
-
* records. Fail loud: silently starting empty over a corrupt journal
|
|
1054
|
-
* would erase delegation history and re-run idempotent work. Opt into
|
|
1055
|
-
* recovery explicitly via `FileDelegationStoreOptions.recoverCorrupt`
|
|
1056
|
-
* (the bin maps `AGENT_RUNTIME_DELEGATION_STATE_RECOVER=1` onto it),
|
|
1057
|
-
* which archives the corrupt file and starts fresh.
|
|
1058
|
-
*
|
|
1059
|
-
* @experimental
|
|
1060
|
-
*/
|
|
1061
|
-
declare class DelegationStateCorruptError extends AgentEvalError {
|
|
1062
|
-
constructor(message: string, options?: {
|
|
1063
|
-
cause?: unknown;
|
|
1064
|
-
});
|
|
1065
|
-
}
|
|
1066
|
-
/**
|
|
1067
|
-
* A delegation-store read or write failed (filesystem error, store
|
|
1068
|
-
* called before `loadAll`, ...). Once the queue observes one, it stops
|
|
1069
|
-
* accepting new submissions — accepting work it cannot journal would
|
|
1070
|
-
* silently demote durable mode to in-memory mode.
|
|
1071
|
-
*
|
|
1072
|
-
* @experimental
|
|
1073
|
-
*/
|
|
1074
|
-
declare class DelegationPersistenceError extends AgentEvalError {
|
|
1075
|
-
constructor(message: string, options?: {
|
|
1076
|
-
cause?: unknown;
|
|
1077
|
-
});
|
|
1078
|
-
}
|
|
1079
|
-
/** @experimental */
|
|
1080
|
-
declare class InMemoryDelegationStore implements DelegationStore {
|
|
1081
|
-
private readonly records;
|
|
1082
|
-
loadAll(): Promise<DelegationRecord[]>;
|
|
1083
|
-
upsert(record: DelegationRecord): Promise<void>;
|
|
1084
|
-
lookupIdempotencyKey(key: string): Promise<string | undefined>;
|
|
1085
|
-
remove(taskIds: readonly string[]): Promise<void>;
|
|
1086
|
-
}
|
|
1087
|
-
/** @experimental */
|
|
1088
|
-
interface FileDelegationStoreOptions {
|
|
1089
|
-
/** Absolute path of the JSON state file. Parent directories are created on first write. */
|
|
1090
|
-
filePath: string;
|
|
1091
|
-
/**
|
|
1092
|
-
* When the state file exists but cannot be parsed, archive it to
|
|
1093
|
-
* `<filePath>.corrupt-<timestamp>` and start empty instead of
|
|
1094
|
-
* throwing `DelegationStateCorruptError`. Default false.
|
|
1095
|
-
*/
|
|
1096
|
-
recoverCorrupt?: boolean;
|
|
1097
|
-
}
|
|
1098
|
-
/**
|
|
1099
|
-
* JSON-file persistence for the delegation queue. Each write serializes
|
|
1100
|
-
* the full record set and lands it atomically (write to a sibling tmp
|
|
1101
|
-
* file, then `rename`), so readers never observe a torn file — a crash
|
|
1102
|
-
* mid-write leaves the previous snapshot intact. Writes are serialized
|
|
1103
|
-
* internally; concurrent `upsert`/`remove` calls cannot interleave.
|
|
1104
|
-
*
|
|
1105
|
-
* Built for the MCP server's scale (one stdio process, hundreds of
|
|
1106
|
-
* records): full-snapshot writes keep the format trivially inspectable
|
|
1107
|
-
* and corruption-detectable without a database dependency.
|
|
1108
|
-
*
|
|
1109
|
-
* @experimental
|
|
1110
|
-
*/
|
|
1111
|
-
declare class FileDelegationStore implements DelegationStore {
|
|
1112
|
-
private readonly filePath;
|
|
1113
|
-
private readonly recoverCorrupt;
|
|
1114
|
-
private readonly records;
|
|
1115
|
-
private loaded;
|
|
1116
|
-
private writeTail;
|
|
1117
|
-
private tmpSeq;
|
|
1118
|
-
constructor(options: FileDelegationStoreOptions);
|
|
1119
|
-
loadAll(): Promise<DelegationRecord[]>;
|
|
1120
|
-
upsert(record: DelegationRecord): Promise<void>;
|
|
1121
|
-
lookupIdempotencyKey(key: string): Promise<string | undefined>;
|
|
1122
|
-
remove(taskIds: readonly string[]): Promise<void>;
|
|
1123
|
-
private assertLoaded;
|
|
1124
|
-
private enqueueWrite;
|
|
1125
|
-
private writeSnapshot;
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
/**
|
|
1129
|
-
* OTEL span exporter — streams LoopTraceEvents to an OTLP/HTTP collector.
|
|
1130
|
-
*
|
|
1131
|
-
* Reads OTEL_EXPORTER_OTLP_ENDPOINT + OTEL_EXPORTER_OTLP_HEADERS from env
|
|
1132
|
-
* when no explicit config is given. Keeps the runtime dep-free from
|
|
1133
|
-
* @opentelemetry/sdk-trace-base — minimal OTLP/JSON serializer.
|
|
1134
|
-
*
|
|
1135
|
-
* The exporter accepts both raw OtelSpan objects and LoopTraceEvents
|
|
1136
|
-
* (which get converted to OTLP spans automatically).
|
|
1137
|
-
*/
|
|
1138
|
-
interface OtelExportConfig {
|
|
1139
|
-
/** OTLP endpoint. Reads OTEL_EXPORTER_OTLP_ENDPOINT env by default. */
|
|
1140
|
-
endpoint?: string;
|
|
1141
|
-
/** OTLP headers. Reads OTEL_EXPORTER_OTLP_HEADERS env by default. */
|
|
1142
|
-
headers?: Record<string, string>;
|
|
1143
|
-
/** Batch size before flush. Default 64. */
|
|
1144
|
-
batchSize?: number;
|
|
1145
|
-
/** Flush interval ms. Default 5000. */
|
|
1146
|
-
flushIntervalMs?: number;
|
|
1147
|
-
/** Resource attributes stamped on every export. */
|
|
1148
|
-
resourceAttributes?: Record<string, string | number | boolean>;
|
|
1149
|
-
/** Service name. Default 'agent-runtime'. */
|
|
1150
|
-
serviceName?: string;
|
|
1151
|
-
}
|
|
1152
|
-
interface OtelExporter {
|
|
1153
|
-
/** Export a span. */
|
|
1154
|
-
exportSpan(span: OtelSpan): void;
|
|
1155
|
-
/** Force flush pending spans. */
|
|
1156
|
-
flush(): Promise<void>;
|
|
1157
|
-
/** Shutdown cleanly. */
|
|
1158
|
-
shutdown(): Promise<void>;
|
|
1159
|
-
}
|
|
1160
|
-
interface OtelSpan {
|
|
1161
|
-
traceId: string;
|
|
1162
|
-
spanId: string;
|
|
1163
|
-
parentSpanId?: string;
|
|
1164
|
-
name: string;
|
|
1165
|
-
kind?: number;
|
|
1166
|
-
startTimeUnixNano: string;
|
|
1167
|
-
endTimeUnixNano: string;
|
|
1168
|
-
attributes?: OtelAttribute[];
|
|
1169
|
-
status?: {
|
|
1170
|
-
code: number;
|
|
1171
|
-
message?: string;
|
|
1172
|
-
};
|
|
1173
|
-
}
|
|
1174
|
-
interface OtelAttribute {
|
|
1175
|
-
key: string;
|
|
1176
|
-
value: {
|
|
1177
|
-
stringValue?: string;
|
|
1178
|
-
intValue?: string;
|
|
1179
|
-
doubleValue?: number;
|
|
1180
|
-
boolValue?: boolean;
|
|
1181
|
-
};
|
|
1182
|
-
}
|
|
1183
|
-
/**
|
|
1184
|
-
* Create an OTEL exporter. Returns undefined when no endpoint is configured.
|
|
1185
|
-
*/
|
|
1186
|
-
declare function createOtelExporter(config?: OtelExportConfig): OtelExporter | undefined;
|
|
1187
|
-
/**
|
|
1188
|
-
* Convert a LoopTraceEvent into an OtelSpan for export.
|
|
1189
|
-
*/
|
|
1190
|
-
declare function loopEventToOtelSpan(event: {
|
|
1191
|
-
kind: string;
|
|
1192
|
-
runId: string;
|
|
1193
|
-
timestamp: number;
|
|
1194
|
-
payload: object;
|
|
1195
|
-
}, traceId: string, parentSpanId?: string): OtelSpan;
|
|
1196
|
-
/**
|
|
1197
|
-
* Sink-neutral node in a reconstructed loop span tree. The root node's
|
|
1198
|
-
* `parentSpanId` is `undefined` — sinks decide how to parent it (the OTEL
|
|
1199
|
-
* mapper attaches the inherited delegation span; the delegation journal
|
|
1200
|
-
* leaves it as the tree root).
|
|
1201
|
-
*/
|
|
1202
|
-
interface LoopSpanNode {
|
|
1203
|
-
spanId: string;
|
|
1204
|
-
parentSpanId?: string;
|
|
1205
|
-
/** `'loop'` | `'loop.round'` | `'loop.iteration'`. */
|
|
1206
|
-
name: string;
|
|
1207
|
-
/** Topology level: loop root, plan round, or iteration branch. */
|
|
1208
|
-
kind: 'loop' | 'round' | 'branch';
|
|
1209
|
-
startMs: number;
|
|
1210
|
-
endMs: number;
|
|
1211
|
-
attrs: Record<string, string | number | boolean>;
|
|
1212
|
-
/** True when the iteration carried an error — maps to OTEL status code 2. */
|
|
1213
|
-
error: boolean;
|
|
1214
|
-
}
|
|
1215
|
-
/**
|
|
1216
|
-
* Build a nested, real-duration OTLP span tree for ONE loop run from its full
|
|
1217
|
-
* ordered `LoopTraceEvent` stream. Unlike `loopEventToOtelSpan` (one flat,
|
|
1218
|
-
* zero-duration span per event), this reconstructs the topology hierarchy a
|
|
1219
|
-
* GenAI trace viewer renders natively:
|
|
1220
|
-
*
|
|
1221
|
-
* loop (invoke_workflow)
|
|
1222
|
-
* └─ loop.round[k] (invoke_workflow) ← tangle.loop.move.{kind,width,rationale}
|
|
1223
|
-
* ├─ loop.iteration[i] (invoke_agent) ← gen_ai.agent.name + usage + verdict + placement
|
|
1224
|
-
* └─ …
|
|
1225
|
-
*
|
|
1226
|
-
* Attributes follow the current GenAI semconv (`gen_ai.*`) where they apply and
|
|
1227
|
-
* a namespaced `tangle.loop.*` / `tangle.cost.usd` extension for topology /
|
|
1228
|
-
* verdict / placement / cost (not yet standardized). Pure: feed it a buffered
|
|
1229
|
-
* per-runId event array (e.g. flushed on `loop.ended`) and export the result.
|
|
1230
|
-
*/
|
|
1231
|
-
declare function buildLoopOtelSpans(events: ReadonlyArray<{
|
|
1232
|
-
kind: string;
|
|
1233
|
-
runId: string;
|
|
1234
|
-
timestamp: number;
|
|
1235
|
-
payload: object;
|
|
1236
|
-
}>, traceId: string, rootParentSpanId?: string): OtelSpan[];
|
|
1237
|
-
/**
|
|
1238
|
-
* Sink-neutral core behind {@link buildLoopOtelSpans}: reconstruct the
|
|
1239
|
-
* loop → round → branch span tree from one run's ordered `LoopTraceEvent`
|
|
1240
|
-
* stream. Consumed by the OTEL mapper above and by the MCP delegation
|
|
1241
|
-
* journal's compact trace tee — one topology reconstruction, two sinks.
|
|
1242
|
-
* Tolerates partial streams (a run that never reached `loop.ended` closes
|
|
1243
|
-
* at the last observed event's timestamp).
|
|
1244
|
-
*/
|
|
1245
|
-
declare function buildLoopSpanNodes(events: ReadonlyArray<{
|
|
1246
|
-
kind: string;
|
|
1247
|
-
runId: string;
|
|
1248
|
-
timestamp: number;
|
|
1249
|
-
payload: object;
|
|
1250
|
-
}>): LoopSpanNode[];
|
|
1251
|
-
/** Wire version the eval-runs ingest enforces (X-Tangle-Wire-Version + body). */
|
|
1252
|
-
declare const INTELLIGENCE_WIRE_VERSION = "2026-05-26.v1";
|
|
1253
|
-
interface EvalRunGeneration {
|
|
1254
|
-
/** 0-based ordinal of this generation within the run (required by ingest). */
|
|
1255
|
-
index: number;
|
|
1256
|
-
/** Identity of the proposed surface change (content-addressed hash). */
|
|
1257
|
-
surfaceHash: string;
|
|
1258
|
-
/** Arbitrary provenance for this generation (rationale, evidence, source). */
|
|
1259
|
-
surface?: unknown;
|
|
1260
|
-
/** Per-scenario results; empty until the generation is measured. */
|
|
1261
|
-
cells?: unknown[];
|
|
1262
|
-
/** Mean composite score (0 when unmeasured — pair with labels.measured). */
|
|
1263
|
-
compositeMean: number;
|
|
1264
|
-
costUsd: number;
|
|
1265
|
-
durationMs: number;
|
|
1266
|
-
}
|
|
1267
|
-
interface EvalRunEvent {
|
|
1268
|
-
runId: string;
|
|
1269
|
-
runDir: string;
|
|
1270
|
-
/** ISO timestamp. */
|
|
1271
|
-
timestamp: string;
|
|
1272
|
-
status: 'started' | 'baseline-complete' | 'generation-complete' | 'gate-decided' | 'finished' | 'errored';
|
|
1273
|
-
labels?: Record<string, string>;
|
|
1274
|
-
baseline?: EvalRunGeneration;
|
|
1275
|
-
generations?: EvalRunGeneration[];
|
|
1276
|
-
gateDecision?: 'ship' | 'hold' | 'need_more_work' | 'model_ceiling' | 'arch_ceiling';
|
|
1277
|
-
holdoutLift?: number;
|
|
1278
|
-
totalCostUsd: number;
|
|
1279
|
-
totalDurationMs: number;
|
|
1280
|
-
errorMessage?: string;
|
|
1281
|
-
}
|
|
1282
|
-
interface EvalRunsExportConfig {
|
|
1283
|
-
/** Bearer key — tenant is resolved server-side from it. Reads TANGLE_API_KEY. */
|
|
1284
|
-
apiKey?: string;
|
|
1285
|
-
/** Intelligence base. Reads INTELLIGENCE_BASE env, else prod. */
|
|
1286
|
-
base?: string;
|
|
1287
|
-
/** Idempotency-Key header (e.g. the runId) — safe retries + upsert. */
|
|
1288
|
-
idempotencyKey?: string;
|
|
641
|
+
score: number;
|
|
642
|
+
label?: FeedbackRating['label'];
|
|
643
|
+
by: DelegateFeedbackArgs['by'];
|
|
644
|
+
notes: string;
|
|
645
|
+
capturedAt: string;
|
|
1289
646
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
647
|
+
/** @experimental */
|
|
648
|
+
interface DelegationHistoryEntry {
|
|
649
|
+
taskId: string;
|
|
650
|
+
profile: DelegationProfile;
|
|
651
|
+
namespace?: string;
|
|
652
|
+
args: DelegateCodeArgs | DelegateResearchArgs | DelegateUiAuditArgs;
|
|
653
|
+
status: DelegationStatus;
|
|
654
|
+
feedback?: DelegationFeedbackSnapshot[];
|
|
655
|
+
costUsd?: number;
|
|
656
|
+
startedAt: string;
|
|
657
|
+
completedAt?: string;
|
|
658
|
+
/**
|
|
659
|
+
* True when the record carries a journaled loop trace. History stays
|
|
660
|
+
* light by design — fetch the spans via
|
|
661
|
+
* `delegation_status { taskId, includeTrace: true }`.
|
|
662
|
+
*/
|
|
663
|
+
hasTrace: boolean;
|
|
664
|
+
/** Inherited trace identity recorded at submit — join key into the caller's trace. */
|
|
665
|
+
traceId?: string;
|
|
1298
666
|
}
|
|
1299
|
-
/**
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
* rejected per event) so a consumer's loop can assert its provenance landed.
|
|
1303
|
-
* Throws only on a missing key or network failure.
|
|
1304
|
-
*/
|
|
1305
|
-
declare function exportEvalRuns(events: EvalRunEvent[], config?: EvalRunsExportConfig): Promise<EvalRunsExportResult>;
|
|
1306
|
-
|
|
1307
|
-
/**
|
|
1308
|
-
* @experimental
|
|
1309
|
-
*
|
|
1310
|
-
* Trace context propagation for MCP subprocess.
|
|
1311
|
-
*
|
|
1312
|
-
* When the MCP server is launched as a child process by a sandbox harness,
|
|
1313
|
-
* the parent passes trace context via environment variables:
|
|
1314
|
-
*
|
|
1315
|
-
* TRACE_ID=<current-run-trace-id>
|
|
1316
|
-
* PARENT_SPAN_ID=<span-that-dispatched-the-delegation>
|
|
1317
|
-
*
|
|
1318
|
-
* The MCP server reads these at startup and uses them as the root of its
|
|
1319
|
-
* internal trace tree. All spans emitted by `runLoop` invocations inside
|
|
1320
|
-
* the MCP are children of the parent's delegation span.
|
|
1321
|
-
*
|
|
1322
|
-
* When these env vars are absent, the MCP generates a fresh trace root —
|
|
1323
|
-
* the server operates standalone without trace joining.
|
|
1324
|
-
*/
|
|
1325
|
-
|
|
1326
|
-
interface TraceContext {
|
|
1327
|
-
/** Trace id inherited from the parent process, or a fresh one. */
|
|
1328
|
-
traceId: string;
|
|
1329
|
-
/** Parent span id from the delegation that launched this MCP server. */
|
|
1330
|
-
parentSpanId?: string;
|
|
667
|
+
/** @experimental */
|
|
668
|
+
interface DelegationHistoryResult {
|
|
669
|
+
delegations: DelegationHistoryEntry[];
|
|
1331
670
|
}
|
|
1332
|
-
/**
|
|
1333
|
-
* Read trace context from the process environment.
|
|
1334
|
-
* Returns a context with inherited ids or a freshly generated root.
|
|
1335
|
-
*/
|
|
1336
|
-
declare function readTraceContextFromEnv(): TraceContext;
|
|
1337
|
-
/**
|
|
1338
|
-
* Create a LoopTraceEmitter that:
|
|
1339
|
-
* 1. Parents all spans under the inherited PARENT_SPAN_ID.
|
|
1340
|
-
* 2. Exports spans to OTEL when OTEL_EXPORTER_OTLP_ENDPOINT is set.
|
|
1341
|
-
*
|
|
1342
|
-
* Returns both the emitter and the optional exporter handle for shutdown.
|
|
1343
|
-
*/
|
|
1344
|
-
declare function createPropagatingTraceEmitter(ctx: TraceContext): {
|
|
1345
|
-
emitter: LoopTraceEmitter;
|
|
1346
|
-
exporter: OtelExporter | undefined;
|
|
1347
|
-
context: TraceContext;
|
|
1348
|
-
};
|
|
1349
|
-
/**
|
|
1350
|
-
* Build env vars to pass to a child MCP subprocess so it inherits the
|
|
1351
|
-
* current trace context.
|
|
1352
|
-
*/
|
|
1353
|
-
declare function traceContextToEnv(ctx: TraceContext): Record<string, string>;
|
|
1354
671
|
|
|
1355
672
|
/**
|
|
1356
673
|
* @experimental
|
|
@@ -1660,128 +977,6 @@ declare class DelegationTaskQueue {
|
|
|
1660
977
|
*/
|
|
1661
978
|
declare function hashIdempotencyInput(value: unknown): string;
|
|
1662
979
|
|
|
1663
|
-
/**
|
|
1664
|
-
* @experimental
|
|
1665
|
-
*
|
|
1666
|
-
* The completion-oracle: **settled ⟺ DELIVERED.**
|
|
1667
|
-
*
|
|
1668
|
-
* Foreman's one hard lesson (0/18 self-improvement deliverables) — "done" must mean a check
|
|
1669
|
-
* PASSED, not the agent's say-so. `gateOnDeliverable` wraps an `Executor` so its settlement
|
|
1670
|
-
* is `valid` ONLY when the deliverable check passes. The child still RUNS and settles (its
|
|
1671
|
-
* spend is conserved into the pool either way), but a child that ran WITHOUT delivering
|
|
1672
|
-
* settles `valid:false` — so a keep-best driver never counts it as done, and a gate never
|
|
1673
|
-
* inflates with self-judged wins.
|
|
1674
|
-
*
|
|
1675
|
-
* Dual-purpose by construction:
|
|
1676
|
-
* - product: the agent fleet only advances on real, checked deliverables.
|
|
1677
|
-
* - proof: the gate's `valid` is the honest settle — equal-k comparisons can't be gamed by an
|
|
1678
|
-
* arm that "ran" without producing the artifact.
|
|
1679
|
-
*
|
|
1680
|
-
* The check is a DEPLOYABLE oracle — a test command, a state verifier, the commit0 judge —
|
|
1681
|
-
* read off the child's output, never the model judging itself. A throwing check is
|
|
1682
|
-
* fail-closed (not delivered), never a crash.
|
|
1683
|
-
*/
|
|
1684
|
-
|
|
1685
|
-
/**
|
|
1686
|
-
* The deployable completion oracle passed to {@link gateOnDeliverable}: a `check` that
|
|
1687
|
-
* decides DELIVERED (settles `valid` ⟺ it resolves true) plus an optional `describe` of
|
|
1688
|
-
* what the spawn was supposed to produce. The check reads the child's output — never the
|
|
1689
|
-
* model judging itself.
|
|
1690
|
-
*/
|
|
1691
|
-
interface DeliverableSpec<Out = unknown> {
|
|
1692
|
-
/** The deployable check that decides DELIVERED. `settled.valid ⟺ this resolves true`. */
|
|
1693
|
-
check: (out: Out) => boolean | Promise<boolean>;
|
|
1694
|
-
/** What the spawn was supposed to produce — surfaced in traces/reports. */
|
|
1695
|
-
describe?: string;
|
|
1696
|
-
}
|
|
1697
|
-
/**
|
|
1698
|
-
* Wrap an `Executor` so its settlement `valid` reflects the deliverable check, not the
|
|
1699
|
-
* inner verdict. Handles both `execute` shapes (one-shot `Promise<ExecutorResult>` and
|
|
1700
|
-
* streaming `AsyncIterable<UsageEvent>` + `resultArtifact()`); the check runs once the inner
|
|
1701
|
-
* executor has produced its output. The inner `score` is preserved; only `valid` is gated.
|
|
1702
|
-
*/
|
|
1703
|
-
declare function gateOnDeliverable<Out>(inner: Executor<Out>, deliverable: DeliverableSpec<Out>): Executor<Out>;
|
|
1704
|
-
|
|
1705
|
-
/**
|
|
1706
|
-
* @experimental
|
|
1707
|
-
*
|
|
1708
|
-
* Git worktree helpers for the in-process delegation executor. Each
|
|
1709
|
-
* delegation runs in its own worktree so multiple parallel harness
|
|
1710
|
-
* subprocesses (claude / codex / opencode in a 3-way fanout) don't clobber
|
|
1711
|
-
* each other's edits on the shared workspace.
|
|
1712
|
-
*
|
|
1713
|
-
* Worktrees live under `<repoRoot>/.agent-worktrees/<runId>/`. After the
|
|
1714
|
-
* harness exits + the diff is captured, the worktree is removed.
|
|
1715
|
-
*
|
|
1716
|
-
* All operations spawn `git` via `child_process.spawn` synchronously
|
|
1717
|
-
* (via a `runGit` helper). Stays narrow on purpose: no commits, no rebases.
|
|
1718
|
-
* Diff capture stages all changes (`git add -A`) into the ephemeral worktree's
|
|
1719
|
-
* index so created (untracked) files appear in the `--cached` diff.
|
|
1720
|
-
*/
|
|
1721
|
-
/** @experimental */
|
|
1722
|
-
interface WorktreeHandle {
|
|
1723
|
-
/** Absolute path to the worktree directory. */
|
|
1724
|
-
path: string;
|
|
1725
|
-
/** SHA the worktree was created at. */
|
|
1726
|
-
baseSha: string;
|
|
1727
|
-
/** Branch name created for this worktree (typically `delegate/<runId>`). */
|
|
1728
|
-
branch: string;
|
|
1729
|
-
}
|
|
1730
|
-
/** @experimental */
|
|
1731
|
-
interface CreateWorktreeOptions {
|
|
1732
|
-
/** Absolute path to the main git checkout. */
|
|
1733
|
-
repoRoot: string;
|
|
1734
|
-
/** Unique id for the worktree path + branch. Use the delegation run id. */
|
|
1735
|
-
runId: string;
|
|
1736
|
-
/** Parent directory the worktree lives under. Defaults to `.agent-worktrees`. */
|
|
1737
|
-
variantsDir?: string;
|
|
1738
|
-
/** Override the base ref (default `HEAD`). */
|
|
1739
|
-
baseRef?: string;
|
|
1740
|
-
/** Test seam — inject a custom git runner. */
|
|
1741
|
-
runGit?: GitRunner;
|
|
1742
|
-
}
|
|
1743
|
-
/** @experimental */
|
|
1744
|
-
interface DiffOptions {
|
|
1745
|
-
/** Worktree to diff. */
|
|
1746
|
-
worktree: WorktreeHandle;
|
|
1747
|
-
/** What to compare against. Default `worktree.baseSha`. */
|
|
1748
|
-
baseRef?: string;
|
|
1749
|
-
/** Test seam. */
|
|
1750
|
-
runGit?: GitRunner;
|
|
1751
|
-
}
|
|
1752
|
-
/** @experimental */
|
|
1753
|
-
interface DiffResult {
|
|
1754
|
-
patch: string;
|
|
1755
|
-
stats: {
|
|
1756
|
-
filesChanged: number;
|
|
1757
|
-
insertions: number;
|
|
1758
|
-
deletions: number;
|
|
1759
|
-
};
|
|
1760
|
-
}
|
|
1761
|
-
/** @experimental */
|
|
1762
|
-
interface RemoveWorktreeOptions {
|
|
1763
|
-
worktree: WorktreeHandle;
|
|
1764
|
-
repoRoot: string;
|
|
1765
|
-
/** Force removal even if dirty (default true; the loser of a fanout has uncommitted changes). */
|
|
1766
|
-
force?: boolean;
|
|
1767
|
-
/** Test seam. */
|
|
1768
|
-
runGit?: GitRunner;
|
|
1769
|
-
}
|
|
1770
|
-
/** Pluggable git runner (sync) — replaceable in tests. */
|
|
1771
|
-
type GitRunner = (args: ReadonlyArray<string>, opts: {
|
|
1772
|
-
cwd: string;
|
|
1773
|
-
}) => {
|
|
1774
|
-
stdout: string;
|
|
1775
|
-
stderr: string;
|
|
1776
|
-
exitCode: number;
|
|
1777
|
-
};
|
|
1778
|
-
/** @experimental */
|
|
1779
|
-
declare function createWorktree(options: CreateWorktreeOptions): Promise<WorktreeHandle>;
|
|
1780
|
-
/** @experimental */
|
|
1781
|
-
declare function captureWorktreeDiff(options: DiffOptions): Promise<DiffResult>;
|
|
1782
|
-
/** @experimental */
|
|
1783
|
-
declare function removeWorktree(options: RemoveWorktreeOptions): Promise<void>;
|
|
1784
|
-
|
|
1785
980
|
/**
|
|
1786
981
|
* @experimental
|
|
1787
982
|
*
|
|
@@ -2083,29 +1278,21 @@ declare function createFleetWorkspaceExecutor(options: FleetWorkspaceExecutorOpt
|
|
|
2083
1278
|
/**
|
|
2084
1279
|
* @experimental
|
|
2085
1280
|
*
|
|
2086
|
-
*
|
|
2087
|
-
*
|
|
2088
|
-
*
|
|
2089
|
-
*
|
|
2090
|
-
*
|
|
2091
|
-
*
|
|
2092
|
-
*
|
|
2093
|
-
*
|
|
2094
|
-
*
|
|
2095
|
-
*
|
|
2096
|
-
*
|
|
2097
|
-
*
|
|
2098
|
-
*
|
|
2099
|
-
*
|
|
2100
|
-
*
|
|
2101
|
-
* `delegate_code` delegate: workers run the in-box harness over a `SandboxClient`. By default it
|
|
2102
|
-
* holds the stream; single-variant turns can OPTIONALLY dispatch DETACHED (`driveTurn` ticks) so a
|
|
2103
|
-
* durable queue resumes them across an MCP restart — that resume tick is the only part gated behind
|
|
2104
|
-
* `MCP_ENABLE_DETACHED_RESUME` (default off) in `bin.ts`, a capability the recursive
|
|
2105
|
-
* `Scope`/worktree-CLI leaf has no durable equivalent for yet. For NEW local-repo coding use
|
|
2106
|
-
* `worktreeFanout` / `worktreeLoopRunner`. The default researcher delegate is **not** wired in this
|
|
2107
|
-
* file — `agent-knowledge` cannot be imported from `agent-runtime` without inducing a cycle.
|
|
2108
|
-
* Consumers pass `researcherDelegate` explicitly.
|
|
1281
|
+
* `detachedSessionDelegate` — the sandbox-session coder delegate: a closure that drives `runLoop`
|
|
1282
|
+
* against a `SandboxClient` + a caller-supplied (or minimal model-only default) worker profile, to a
|
|
1283
|
+
* mechanically-validated `CoderOutput`. The caller invokes the returned delegate directly with its
|
|
1284
|
+
* coder args; when wired into a durable queue it also settles cross-restart-resumed records.
|
|
1285
|
+
*
|
|
1286
|
+
* Delegation vs COORDINATION (`../runtime/supervise/coordination-mcp.ts`): this delegate runs a
|
|
1287
|
+
* coding task INSIDE the agent's OWN sandbox environment — a sibling box on its own `SandboxClient`,
|
|
1288
|
+
* fresh branch on its repo. It is NOT backend-pluggable. To instead SPAWN + live-drive workers in a
|
|
1289
|
+
* CHOSEN backend (sandbox OR cli-bridge, via `createExecutor({ backend })`) with observe/steer/resume
|
|
1290
|
+
* + recursion, use `delegate()` / the coordination MCP.
|
|
1291
|
+
*
|
|
1292
|
+
* The worker profile is a parameter the caller supplies (§1.5: the system authors profiles). When
|
|
1293
|
+
* none is passed, a minimal model-only default profile is materialized in `./detached-coder` — no
|
|
1294
|
+
* hardcoded skills or tools. For NEW local-repo coding use `worktreeFanout` / `worktreeLoopRunner`
|
|
1295
|
+
* (author one `AgentProfile` per harness → `createWorktreeCliExecutor` leaves → `gateOnDeliverable`).
|
|
2109
1296
|
*/
|
|
2110
1297
|
|
|
2111
1298
|
/** @experimental */
|
|
@@ -2129,11 +1316,10 @@ interface DelegateRunCtx {
|
|
|
2129
1316
|
*/
|
|
2130
1317
|
traceEmitter?: LoopTraceEmitter;
|
|
2131
1318
|
}
|
|
2132
|
-
/** @experimental The
|
|
2133
|
-
*
|
|
1319
|
+
/** @experimental The coder delegate closure — given the coder args + run context, drives the
|
|
1320
|
+
* sandbox-session coder path to a validated `CoderOutput`. `detachedSessionDelegate` is the
|
|
1321
|
+
* built-in implementation; the queue invokes one of these per coder delegation. */
|
|
2134
1322
|
type CoderDelegate = (args: DelegateCodeArgs, ctx: DelegateRunCtx) => Promise<CoderOutput>;
|
|
2135
|
-
/** @experimental */
|
|
2136
|
-
type ResearcherDelegate = (args: DelegateResearchArgs, ctx: DelegateRunCtx) => Promise<ResearchOutputShape>;
|
|
2137
1323
|
/**
|
|
2138
1324
|
* UI-auditor delegate — fully consumer-injected. agent-runtime ships no
|
|
2139
1325
|
* default factory because the inputs are workspace path + judge function
|
|
@@ -2188,14 +1374,22 @@ interface DetachedSessionDelegateOptions {
|
|
|
2188
1374
|
* `executor: createSiblingSandboxExecutor({ client: sandboxClient })`.
|
|
2189
1375
|
*/
|
|
2190
1376
|
sandboxClient?: SandboxClient;
|
|
2191
|
-
/**
|
|
1377
|
+
/**
|
|
1378
|
+
* The worker's authored `AgentProfile` (§1.5: the system authors profiles). Spread onto the
|
|
1379
|
+
* sandbox-session run spec → `runLoop` → the executor's `harnessInvocation`, so the harness runs
|
|
1380
|
+
* under the caller's stance. Omit to use a minimal model-only default (no hardcoded skills/tools);
|
|
1381
|
+
* `harness` / `model` / `systemPrompt` below are convenience overrides layered onto whichever
|
|
1382
|
+
* profile is used.
|
|
1383
|
+
*/
|
|
1384
|
+
workerProfile?: AgentProfile;
|
|
1385
|
+
/** Backend harness for the single-coder path (sets `metadata.backendType`). Default `claude-code`. */
|
|
2192
1386
|
harness?: string;
|
|
2193
1387
|
/** Model override for the single-coder path. */
|
|
2194
1388
|
model?: string;
|
|
2195
1389
|
/**
|
|
2196
|
-
* The worker's authored system prompt (§1.5). Flows onto
|
|
1390
|
+
* The worker's authored system prompt (§1.5). Flows onto the run spec's
|
|
2197
1391
|
* `profile.prompt.systemPrompt` → through `runLoop` → the executor's `harnessInvocation`, so the
|
|
2198
|
-
* harness runs under this stance
|
|
1392
|
+
* harness runs under this stance. Omit to keep the profile's own prompt.
|
|
2199
1393
|
*/
|
|
2200
1394
|
systemPrompt?: string;
|
|
2201
1395
|
/** Default `['claude-code', 'codex', 'opencode/zai-coding-plan/glm-5.1']` when variants > 1. */
|
|
@@ -2285,4 +1479,586 @@ interface SettleDetachedCoderTurnOptions {
|
|
|
2285
1479
|
*/
|
|
2286
1480
|
declare function settleDetachedCoderTurn(turn: DetachedTurn, options: SettleDetachedCoderTurnOptions): Promise<CoderOutput>;
|
|
2287
1481
|
|
|
2288
|
-
|
|
1482
|
+
/**
|
|
1483
|
+
* @experimental
|
|
1484
|
+
*
|
|
1485
|
+
* Feedback persistence surface for the MCP layer.
|
|
1486
|
+
*
|
|
1487
|
+
* The substrate cannot import `@tangle-network/agent-knowledge` (it would
|
|
1488
|
+
* induce a dependency cycle), so the store is an abstract interface. The
|
|
1489
|
+
* default implementation is in-memory; consumers wire their own adapter
|
|
1490
|
+
* (a real KbStore-backed sink, an HTTP relay to gtm-agent's knowledge
|
|
1491
|
+
* service, etc.) via `createMcpServer({ feedbackStore })`.
|
|
1492
|
+
*
|
|
1493
|
+
* Feedback events are append-only: every rating is a new event with a
|
|
1494
|
+
* fresh id, even when the same delegation is rated multiple times. The
|
|
1495
|
+
* caller decides how to roll up scores downstream.
|
|
1496
|
+
*/
|
|
1497
|
+
|
|
1498
|
+
/** @experimental */
|
|
1499
|
+
interface FeedbackEvent {
|
|
1500
|
+
id: string;
|
|
1501
|
+
refersTo: DelegateFeedbackArgs['refersTo'];
|
|
1502
|
+
rating: DelegateFeedbackArgs['rating'];
|
|
1503
|
+
by: DelegateFeedbackArgs['by'];
|
|
1504
|
+
capturedAt: string;
|
|
1505
|
+
namespace?: string;
|
|
1506
|
+
}
|
|
1507
|
+
/** @experimental */
|
|
1508
|
+
interface FeedbackStore {
|
|
1509
|
+
/** Append a new event. Never dedupes — every rating is its own event. */
|
|
1510
|
+
put(event: FeedbackEvent): Promise<void>;
|
|
1511
|
+
/**
|
|
1512
|
+
* List events filtered by `namespace`. When `namespace` is omitted, list
|
|
1513
|
+
* across all namespaces. Returns events in insertion order.
|
|
1514
|
+
*/
|
|
1515
|
+
list(filter?: {
|
|
1516
|
+
namespace?: string;
|
|
1517
|
+
refersToRef?: string;
|
|
1518
|
+
}): Promise<FeedbackEvent[]>;
|
|
1519
|
+
}
|
|
1520
|
+
/** @experimental */
|
|
1521
|
+
declare class InMemoryFeedbackStore implements FeedbackStore {
|
|
1522
|
+
private readonly events;
|
|
1523
|
+
put(event: FeedbackEvent): Promise<void>;
|
|
1524
|
+
list(filter?: {
|
|
1525
|
+
namespace?: string;
|
|
1526
|
+
refersToRef?: string;
|
|
1527
|
+
}): Promise<FeedbackEvent[]>;
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Project a `FeedbackEvent` down to the snapshot shape carried on
|
|
1531
|
+
* `delegation_history` entries.
|
|
1532
|
+
*
|
|
1533
|
+
* @experimental
|
|
1534
|
+
*/
|
|
1535
|
+
declare function eventToSnapshot(event: FeedbackEvent): DelegationFeedbackSnapshot;
|
|
1536
|
+
|
|
1537
|
+
/**
|
|
1538
|
+
* @experimental
|
|
1539
|
+
*
|
|
1540
|
+
* The leaf runtime — the built-in `Executor` IMPLEMENTATIONS behind the ONE
|
|
1541
|
+
* open interface frozen in `./types`, plus the open resolver/registry that maps
|
|
1542
|
+
* an `AgentSpec` to one of them OR accepts a bring-your-own executor verbatim.
|
|
1543
|
+
*
|
|
1544
|
+
* The interface is the extension point, not a closed `inline|sandbox|cli` union:
|
|
1545
|
+
* - router/inline : a direct OpenAI-compatible Router call, no box (one-shot).
|
|
1546
|
+
* - sandbox : COMPOSES the existing `runLoop` kernel as a single-task
|
|
1547
|
+
* leaf and surfaces its token/cost usage as `UsageEvent`s;
|
|
1548
|
+
* forwards PR #150's optional `lineage` passthrough WITHOUT
|
|
1549
|
+
* reinventing checkpoint/fork (streaming).
|
|
1550
|
+
* - cli : a Halo/RLM subprocess; `budgetExempt` (no token accounting),
|
|
1551
|
+
* excluded from the equal-k arms by construction (streaming).
|
|
1552
|
+
* Every metered runtime reports through the SAME normalized `UsageEvent` channel
|
|
1553
|
+
* so the conserved budget pool meters them identically. A user's own agent is
|
|
1554
|
+
* first-class the moment it implements `Executor` — register it by name or
|
|
1555
|
+
* pass it as `AgentSpec.executor`.
|
|
1556
|
+
*
|
|
1557
|
+
* Layering: `estimateCost`/`isModelPriced` are substrate primitives from
|
|
1558
|
+
* `@tangle-network/agent-eval`; `runLoop`/`acquireSandbox` are runtime kernels
|
|
1559
|
+
* from this package. No per-vendor adapters live here.
|
|
1560
|
+
*/
|
|
1561
|
+
|
|
1562
|
+
/**
|
|
1563
|
+
* Router/inline connection seam. A direct OpenAI-compatible Router endpoint —
|
|
1564
|
+
* the cheapest leaf, no box, no tools. `model` overrides the profile's model
|
|
1565
|
+
* hint when present; otherwise the profile's `model.default` is required.
|
|
1566
|
+
*/
|
|
1567
|
+
interface RouterSeam {
|
|
1568
|
+
routerBaseUrl: string;
|
|
1569
|
+
routerKey: string;
|
|
1570
|
+
model?: string;
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* Sandbox executor seam. The `sandboxClient` the composed `runLoop` creates
|
|
1574
|
+
* boxes through, plus the optional trace/run/lineage wiring forwarded into the
|
|
1575
|
+
* loop. `lineage` is opaque here (PR #150's `RunLoopOptions.lineage`): forwarded
|
|
1576
|
+
* forward-compatibly, never inspected — this executor does NOT reinvent
|
|
1577
|
+
* checkpoint/fork.
|
|
1578
|
+
*/
|
|
1579
|
+
interface SandboxSeam {
|
|
1580
|
+
sandboxClient: SandboxClient;
|
|
1581
|
+
/** Forwarded into the composed `runLoop`'s `ctx` (trace emitter, run handle, etc.). */
|
|
1582
|
+
loopCtx?: Partial<Omit<ExecCtx, 'sandboxClient' | 'signal'>>;
|
|
1583
|
+
/** PR #150 `RunLoopOptions.lineage` passthrough — opaque; forwarded, not parsed. */
|
|
1584
|
+
lineage?: unknown;
|
|
1585
|
+
/** Hard cap on the composed loop's iterations. The budget pool reserves against
|
|
1586
|
+
* the spawn `Budget.maxIterations`; this is the leaf's own ceiling. Default 1. */
|
|
1587
|
+
maxIterations?: number;
|
|
1588
|
+
}
|
|
1589
|
+
/** CLI subprocess seam. `bin` + `args` describe the Halo/RLM process to spawn. */
|
|
1590
|
+
interface CliSeam {
|
|
1591
|
+
bin: string;
|
|
1592
|
+
args?: string[];
|
|
1593
|
+
/** Extra environment for the subprocess (merged over `process.env`). */
|
|
1594
|
+
env?: Record<string, string>;
|
|
1595
|
+
/** Working directory for the subprocess. */
|
|
1596
|
+
cwd?: string;
|
|
1597
|
+
}
|
|
1598
|
+
/**
|
|
1599
|
+
* cli-worktree seam. A supervisor-authored `AgentProfile` driving a local coding-harness CLI
|
|
1600
|
+
* (claude / codex / opencode) on its own git worktree — the leaf `createWorktreeCliExecutor`
|
|
1601
|
+
* named as data. `harness` + `repoRoot` + `taskPrompt` are required; the authored
|
|
1602
|
+
* `profile.prompt.systemPrompt` + `profile.model.default` reach the harness via the §1.5
|
|
1603
|
+
* `harnessInvocation` mapper. Everything else mirrors `WorktreeCliExecutorOptions`.
|
|
1604
|
+
*/
|
|
1605
|
+
interface CliWorktreeSeam {
|
|
1606
|
+
repoRoot: string;
|
|
1607
|
+
harness: LocalHarness;
|
|
1608
|
+
taskPrompt: string;
|
|
1609
|
+
runId?: string;
|
|
1610
|
+
baseRef?: string;
|
|
1611
|
+
harnessTimeoutMs?: number;
|
|
1612
|
+
}
|
|
1613
|
+
/**
|
|
1614
|
+
* cli-bridge seam. A local OpenAI-compatible bridge that fronts harness CLIs
|
|
1615
|
+
* (claude-code / opencode / kimi / pi) behind one HTTP surface; `model` doubles
|
|
1616
|
+
* as the harness selector (e.g. `claude-code/sonnet`, `opencode/<provider>/<model>`).
|
|
1617
|
+
* `agentProfile` is the bridge-dialect profile (metadata.disallowedTools, mcp)
|
|
1618
|
+
* forwarded verbatim per request — how an arm disables native tools or injects
|
|
1619
|
+
* a provider search MCP.
|
|
1620
|
+
*
|
|
1621
|
+
* The executor opens a RESUMABLE cli-bridge session — structurally identical to the
|
|
1622
|
+
* sandbox executor's persistent box, just local. `sessionId` is the stable
|
|
1623
|
+
* caller-owned id cli-bridge maps to the harness's internal conversation id; a
|
|
1624
|
+
* follow-up steer/resume on the SAME id continues the SAME harness session (opencode
|
|
1625
|
+
* `-s`, claude `--resume`, …). Omit it and the executor mints a stable one per spawn.
|
|
1626
|
+
*/
|
|
1627
|
+
interface BridgeSeam {
|
|
1628
|
+
bridgeUrl: string;
|
|
1629
|
+
bridgeBearer: string;
|
|
1630
|
+
model: string;
|
|
1631
|
+
agentProfile?: Record<string, unknown>;
|
|
1632
|
+
timeoutMs?: number;
|
|
1633
|
+
/** Stable, caller-owned cli-bridge session id for harness-side resume. Defaults
|
|
1634
|
+
* to a freshly minted per-spawn id so each worker is its own resumable session. */
|
|
1635
|
+
sessionId?: string;
|
|
1636
|
+
/** Per-resume-turn inference cap before the worker settles on its last output.
|
|
1637
|
+
* Mirrors `routerToolsInlineExecutor.maxTurns`; default 200 (runaway backstop). */
|
|
1638
|
+
maxTurns?: number;
|
|
1639
|
+
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Router seam WITH tool use — the tool-using router backend. Same direct
|
|
1642
|
+
* OpenAI-compatible endpoint as `RouterSeam`, but each turn passes `tools`; when
|
|
1643
|
+
* the model emits tool_calls they run via `executeToolCall` ON THIS HOST and the
|
|
1644
|
+
* results fold back as `tool` messages, repeating until the model answers without
|
|
1645
|
+
* a tool or `maxTurns` is hit. A real agentic loop, OFF-BOX — no sandbox, so it
|
|
1646
|
+
* is unaffected by a box's egress allowlist. One turn = one completion = the
|
|
1647
|
+
* equal-compute unit. `executeToolCall` receives the task so per-task tool
|
|
1648
|
+
* surfaces (e.g. a gym keyed by task) can dispatch correctly.
|
|
1649
|
+
*/
|
|
1650
|
+
interface RouterToolsSeam {
|
|
1651
|
+
routerBaseUrl: string;
|
|
1652
|
+
routerKey: string;
|
|
1653
|
+
model?: string;
|
|
1654
|
+
tools: ReadonlyArray<ToolSpec>;
|
|
1655
|
+
executeToolCall: (name: string, args: Record<string, unknown>, task: unknown) => Promise<string>;
|
|
1656
|
+
/** Online observer of each tool step — the seam a `DetectorMonitor` taps to watch the live pipe
|
|
1657
|
+
* (raise a `finding` when the worker loops/errors). Called after every tool call resolves, with
|
|
1658
|
+
* real per-call wall-clock (`startedAt`/`endedAt`/`durationMs`) so a push `TraceSource` can carry
|
|
1659
|
+
* non-zero span durations onto the unified timeline. */
|
|
1660
|
+
onToolStep?: (step: {
|
|
1661
|
+
toolName: string;
|
|
1662
|
+
args: Record<string, unknown>;
|
|
1663
|
+
status: 'ok' | 'error';
|
|
1664
|
+
startedAt?: number;
|
|
1665
|
+
endedAt?: number;
|
|
1666
|
+
durationMs?: number;
|
|
1667
|
+
}) => void;
|
|
1668
|
+
/** Max inference turns. Default 200 (runaway backstop — set far above any
|
|
1669
|
+
* legitimate workflow). For tighter per-workflow limits use a cost budget
|
|
1670
|
+
* or wall-clock deadline at the call site. */
|
|
1671
|
+
maxTurns?: number;
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* The leaf `createWorktreeCliExecutor` as a backend-as-data factory: a supervisor-authored
|
|
1675
|
+
* `AgentProfile` driving claude / codex / opencode on its own worktree. `budgetExempt` like
|
|
1676
|
+
* the other CLI leaves; the authored systemPrompt + model reach the harness via §1.5.
|
|
1677
|
+
*/
|
|
1678
|
+
declare const cliWorktreeExecutor: ExecutorFactory<unknown>;
|
|
1679
|
+
/**
|
|
1680
|
+
* Config for {@link createExecutor}: the backend is DATA — the cost dial a profile,
|
|
1681
|
+
* an experiment config, or a replay journal can name — not an import choice. Each
|
|
1682
|
+
* variant carries its backend's seam (router/router-tools/bridge/cli/cli-worktree/sandbox).
|
|
1683
|
+
*/
|
|
1684
|
+
type ExecutorConfig = ({
|
|
1685
|
+
backend: 'router';
|
|
1686
|
+
} & RouterSeam) | ({
|
|
1687
|
+
backend: 'router-tools';
|
|
1688
|
+
} & RouterToolsSeam) | ({
|
|
1689
|
+
backend: 'bridge';
|
|
1690
|
+
} & BridgeSeam) | ({
|
|
1691
|
+
backend: 'cli';
|
|
1692
|
+
} & CliSeam) | ({
|
|
1693
|
+
backend: 'cli-worktree';
|
|
1694
|
+
} & CliWorktreeSeam) | ({
|
|
1695
|
+
backend: 'sandbox';
|
|
1696
|
+
harness?: BackendType;
|
|
1697
|
+
} & SandboxSeam);
|
|
1698
|
+
/**
|
|
1699
|
+
* The single built-in executor factory. Picks a leaf backend by data (`config.backend`),
|
|
1700
|
+
* injects the matching seam, and delegates to that backend's built-in implementation.
|
|
1701
|
+
* The `Executor` port stays OPEN: bring-your-own agents implement `Executor` directly
|
|
1702
|
+
* and never pass through here. Use this (or `createExecutorRegistry`) instead of a
|
|
1703
|
+
* per-vendor adapter or a closed `inline|sandbox|cli` switch — those bypass the
|
|
1704
|
+
* `UsageEvent` reporting channel.
|
|
1705
|
+
*/
|
|
1706
|
+
declare function createExecutor(config: ExecutorConfig): ExecutorFactory<unknown>;
|
|
1707
|
+
/**
|
|
1708
|
+
* The open resolver/registry. Pre-registers the three built-ins under their
|
|
1709
|
+
* runtime tags (`'router'`, `'sandbox'`, `'cli'`) and accepts `register(name,
|
|
1710
|
+
* factory)` for any additional runtime — and a BYO `AgentSpec.executor` resolves
|
|
1711
|
+
* without touching the registry at all. NOT a closed switch; registration + BYO
|
|
1712
|
+
* ARE the extension points.
|
|
1713
|
+
*
|
|
1714
|
+
* `resolve` precedence (frozen in `ExecutorRegistry`): a BYO `spec.executor` →
|
|
1715
|
+
* `harness === null` → the `'router'` factory; else a registered factory for the
|
|
1716
|
+
* harness-derived runtime (`'sandbox'` for any `BackendType`); else fail loud.
|
|
1717
|
+
*/
|
|
1718
|
+
declare function createExecutorRegistry(): ExecutorRegistry;
|
|
1719
|
+
|
|
1720
|
+
/**
|
|
1721
|
+
* @experimental
|
|
1722
|
+
*
|
|
1723
|
+
* `delegate` MCP tool — the ONE generic delegation verb, the agent-facing front door to
|
|
1724
|
+
* `delegate()` / `supervise()`. The agent hands it an INTENT (what it wants done); a default
|
|
1725
|
+
* authoring supervisor decomposes the intent and AUTHORS the worker profile it needs — there is no
|
|
1726
|
+
* hardcoded coder/researcher profile. It is the generic replacement for `delegate_code` /
|
|
1727
|
+
* `delegate_research`.
|
|
1728
|
+
*
|
|
1729
|
+
* Unlike those async, queue-backed tools (kick off → return a taskId → poll `delegation_status`),
|
|
1730
|
+
* `delegate` is SYNCHRONOUS: it awaits the full supervised run and returns the delivered output
|
|
1731
|
+
* TOGETHER WITH `spentTotal` — the conserved cost of the whole delegation (`iterations` / `tokens` /
|
|
1732
|
+
* `usd` / `ms`). Returning the real spend is the whole reason `delegate` beats `delegate_code`,
|
|
1733
|
+
* which has no cost channel.
|
|
1734
|
+
*
|
|
1735
|
+
* The supervisor's substrate (its brain `router`, the worker `backend`, the completion `deliverable`)
|
|
1736
|
+
* is INJECTED at server construction — never an agent-supplied arg — exactly as `delegate_code`
|
|
1737
|
+
* injects its `CoderDelegate`. The agent supplies only the intent (+ an optional per-call `model` /
|
|
1738
|
+
* `runId`).
|
|
1739
|
+
*/
|
|
1740
|
+
|
|
1741
|
+
/** @experimental */
|
|
1742
|
+
declare const DELEGATE_TOOL_NAME = "delegate";
|
|
1743
|
+
/** @experimental */
|
|
1744
|
+
declare const DELEGATE_DESCRIPTION: string;
|
|
1745
|
+
/** @experimental */
|
|
1746
|
+
declare const DELEGATE_INPUT_SCHEMA: {
|
|
1747
|
+
readonly type: "object";
|
|
1748
|
+
readonly properties: {
|
|
1749
|
+
readonly intent: {
|
|
1750
|
+
readonly type: "string";
|
|
1751
|
+
readonly description: "What you want accomplished, as an outcome. The supervisor authors the worker.";
|
|
1752
|
+
};
|
|
1753
|
+
readonly model: {
|
|
1754
|
+
readonly type: "string";
|
|
1755
|
+
readonly description: "Optional per-call override for the supervisor brain model.";
|
|
1756
|
+
};
|
|
1757
|
+
readonly runId: {
|
|
1758
|
+
readonly type: "string";
|
|
1759
|
+
readonly description: "Optional trace-correlation id for this delegation.";
|
|
1760
|
+
};
|
|
1761
|
+
};
|
|
1762
|
+
readonly required: readonly ["intent"];
|
|
1763
|
+
readonly additionalProperties: false;
|
|
1764
|
+
};
|
|
1765
|
+
/** Parsed `delegate` tool arguments. */
|
|
1766
|
+
interface DelegateArgs {
|
|
1767
|
+
intent: string;
|
|
1768
|
+
model?: string;
|
|
1769
|
+
runId?: string;
|
|
1770
|
+
}
|
|
1771
|
+
/** @experimental */
|
|
1772
|
+
declare function validateDelegateArgs(raw: unknown): DelegateArgs;
|
|
1773
|
+
/** The synchronous result the `delegate` tool returns to the calling agent: the delivered output (or
|
|
1774
|
+
* the no-winner reason) PLUS the conserved spend of the whole delegation. */
|
|
1775
|
+
type DelegateResult = {
|
|
1776
|
+
status: 'winner';
|
|
1777
|
+
out: unknown;
|
|
1778
|
+
outRef: string;
|
|
1779
|
+
spentTotal: Spend;
|
|
1780
|
+
} | {
|
|
1781
|
+
status: 'no-winner';
|
|
1782
|
+
reason: string;
|
|
1783
|
+
spentTotal: Spend;
|
|
1784
|
+
};
|
|
1785
|
+
/** @experimental */
|
|
1786
|
+
interface DelegateHandlerOptions {
|
|
1787
|
+
/** The supervisor brain's router substrate (REQUIRED — the default supervisor is router-brained). */
|
|
1788
|
+
router: RouterConfig;
|
|
1789
|
+
/** WHERE the authored workers run. Required for `supervise()` to spawn anything. */
|
|
1790
|
+
backend: ExecutorConfig;
|
|
1791
|
+
/** The completion oracle the authored workers settle against (settled ⟺ delivered). */
|
|
1792
|
+
deliverable?: DeliverableSpec;
|
|
1793
|
+
/** Default supervisor brain model when a call omits `model`. */
|
|
1794
|
+
model?: string;
|
|
1795
|
+
/** Restrict the run to this subset of models. */
|
|
1796
|
+
allowedModels?: readonly string[];
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Build the `delegate` tool handler. Closes over the injected supervisor substrate (`router` /
|
|
1800
|
+
* `backend` / `deliverable`); each call routes the agent's intent to `delegate()` and returns the
|
|
1801
|
+
* delivered output with its conserved cost.
|
|
1802
|
+
*/
|
|
1803
|
+
declare function createDelegateHandler(options: DelegateHandlerOptions): (raw: unknown) => Promise<DelegateResult>;
|
|
1804
|
+
|
|
1805
|
+
/**
|
|
1806
|
+
* @experimental
|
|
1807
|
+
*
|
|
1808
|
+
* Stdio JSON-RPC MCP server exposing the delegation tools to sandbox
|
|
1809
|
+
* coding-harness agents (claude-code, codex, opencode, ...): the generic
|
|
1810
|
+
* `delegate` verb plus the queue-bound `delegate_feedback`,
|
|
1811
|
+
* `delegation_status`, and `delegation_history`. `delegate_ui_audit` is served
|
|
1812
|
+
* when a `uiAuditorDelegate` is wired.
|
|
1813
|
+
*
|
|
1814
|
+
* The server is transport-bound but topology-free: tool execution is
|
|
1815
|
+
* delegated to handler functions composed from a queue, a feedback
|
|
1816
|
+
* store, and the wired run delegates. Consumers wire those at
|
|
1817
|
+
* construction time. The `agent-runtime-mcp` bin serves the generic
|
|
1818
|
+
* `delegate` verb over a real sandbox client when `MCP_ENABLE_DELEGATE=1`.
|
|
1819
|
+
*
|
|
1820
|
+
* Wire protocol: line-delimited JSON-RPC 2.0 over stdio. Each line is
|
|
1821
|
+
* one request; each response is one line. `tools/list` and `tools/call`
|
|
1822
|
+
* mirror the MCP 2024-11-05 spec; we do not pull in
|
|
1823
|
+
* `@modelcontextprotocol/sdk` to keep the dependency footprint zero.
|
|
1824
|
+
*/
|
|
1825
|
+
|
|
1826
|
+
/** @experimental */
|
|
1827
|
+
interface McpServerOptions {
|
|
1828
|
+
/**
|
|
1829
|
+
* Required to enable `delegate` — the ONE generic delegation verb (the replacement for
|
|
1830
|
+
* delegate_code / delegate_research). Inject the supervisor substrate: its brain `router`, the
|
|
1831
|
+
* worker `backend`, and the completion `deliverable`. The supervisor AUTHORS its own worker from
|
|
1832
|
+
* the agent's intent, so there is no worker profile to wire here.
|
|
1833
|
+
*/
|
|
1834
|
+
delegateSupervisor?: DelegateHandlerOptions;
|
|
1835
|
+
/**
|
|
1836
|
+
* Required to enable delegate_ui_audit. Wire one that closes over your
|
|
1837
|
+
* `runLoop` + `uiAuditorProfile` + a `SandboxClient` (the
|
|
1838
|
+
* canonical in-process choice is `createInProcessUiAuditClient` from
|
|
1839
|
+
* `@tangle-network/agent-runtime/profiles`) + your vision judge.
|
|
1840
|
+
*/
|
|
1841
|
+
uiAuditorDelegate?: UiAuditorDelegate;
|
|
1842
|
+
/** Override the default in-memory feedback store. */
|
|
1843
|
+
feedbackStore?: FeedbackStore;
|
|
1844
|
+
/** Override the default in-memory task queue. */
|
|
1845
|
+
queue?: DelegationTaskQueue;
|
|
1846
|
+
/**
|
|
1847
|
+
* Extra tools to serve alongside the delegation tools, for example
|
|
1848
|
+
* `createCoordinationTools(...).tools`. Registered after the built-ins; a
|
|
1849
|
+
* duplicate name throws so delegation tools cannot be shadowed silently.
|
|
1850
|
+
*/
|
|
1851
|
+
extraTools?: McpToolDescriptor[];
|
|
1852
|
+
/**
|
|
1853
|
+
* Inherited trace identity (`readTraceContextFromEnv()`) stamped on every
|
|
1854
|
+
* record the DEFAULT queue creates. Ignored when `queue` is supplied —
|
|
1855
|
+
* pass `traceContext` to that queue's constructor instead.
|
|
1856
|
+
*/
|
|
1857
|
+
traceContext?: TraceContext;
|
|
1858
|
+
/** Server display name surfaced via `initialize`. Default `'agent-runtime-mcp'`. */
|
|
1859
|
+
serverName?: string;
|
|
1860
|
+
/** Server version surfaced via `initialize`. Default = the package version baked at build time. */
|
|
1861
|
+
serverVersion?: string;
|
|
1862
|
+
}
|
|
1863
|
+
/** @experimental */
|
|
1864
|
+
interface McpToolDescriptor {
|
|
1865
|
+
name: string;
|
|
1866
|
+
description: string;
|
|
1867
|
+
inputSchema: Record<string, unknown>;
|
|
1868
|
+
handler: (raw: unknown) => Promise<unknown>;
|
|
1869
|
+
}
|
|
1870
|
+
/** @experimental */
|
|
1871
|
+
interface McpServer {
|
|
1872
|
+
/** Tools currently registered (depend on which delegates were wired). */
|
|
1873
|
+
readonly tools: ReadonlyMap<string, McpToolDescriptor>;
|
|
1874
|
+
/** The underlying queue — exposed so tests can introspect it. */
|
|
1875
|
+
readonly queue: DelegationTaskQueue;
|
|
1876
|
+
/** The feedback store — exposed for the same reason. */
|
|
1877
|
+
readonly feedbackStore: FeedbackStore;
|
|
1878
|
+
/** Handle a single parsed JSON-RPC message. Returns the response object (or `null` for notifications). */
|
|
1879
|
+
handle(message: JsonRpcMessage): Promise<JsonRpcResponse | null>;
|
|
1880
|
+
/** Drive the server on a stdio-shaped transport until `stop()` is called. */
|
|
1881
|
+
serve(transport?: McpTransport): Promise<void>;
|
|
1882
|
+
/** Stop a `serve` call. Subsequent requests are rejected. */
|
|
1883
|
+
stop(): void;
|
|
1884
|
+
}
|
|
1885
|
+
/** @experimental */
|
|
1886
|
+
interface McpTransport {
|
|
1887
|
+
input: NodeJS.ReadableStream;
|
|
1888
|
+
output: NodeJS.WritableStream;
|
|
1889
|
+
}
|
|
1890
|
+
/** @experimental */
|
|
1891
|
+
interface JsonRpcMessage {
|
|
1892
|
+
jsonrpc: '2.0';
|
|
1893
|
+
id?: number | string | null;
|
|
1894
|
+
method: string;
|
|
1895
|
+
params?: unknown;
|
|
1896
|
+
}
|
|
1897
|
+
/** @experimental */
|
|
1898
|
+
interface JsonRpcResponse {
|
|
1899
|
+
jsonrpc: '2.0';
|
|
1900
|
+
id: number | string | null;
|
|
1901
|
+
result?: unknown;
|
|
1902
|
+
error?: {
|
|
1903
|
+
code: number;
|
|
1904
|
+
message: string;
|
|
1905
|
+
data?: unknown;
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
/** @experimental */
|
|
1909
|
+
declare function createMcpServer(options?: McpServerOptions): McpServer;
|
|
1910
|
+
/**
|
|
1911
|
+
* In-process pair of `Readable` + `Writable` streams suitable for driving
|
|
1912
|
+
* `server.serve(...)` from a test. Returns the agent-side stream (the
|
|
1913
|
+
* client writes to it) and the server-side stream (the test reads from it).
|
|
1914
|
+
*
|
|
1915
|
+
* @experimental
|
|
1916
|
+
*/
|
|
1917
|
+
declare function createInProcessTransport(): {
|
|
1918
|
+
transport: McpTransport;
|
|
1919
|
+
clientWrite(line: string): void;
|
|
1920
|
+
clientClose(): void;
|
|
1921
|
+
readServer(): Promise<JsonRpcResponse[]>;
|
|
1922
|
+
};
|
|
1923
|
+
|
|
1924
|
+
/**
|
|
1925
|
+
* @experimental
|
|
1926
|
+
*
|
|
1927
|
+
* MCP binding for a live `Scope`. A sandbox driver gets the same small verbs
|
|
1928
|
+
* the in-process driver has: spawn, observe, await, steer, ask/answer, analyze,
|
|
1929
|
+
* and stop. Settled outputs remain Scope artifacts; product code can project
|
|
1930
|
+
* them into any UI/report envelope it needs.
|
|
1931
|
+
*/
|
|
1932
|
+
|
|
1933
|
+
/** A worker the driver has drained via `await_event`. */
|
|
1934
|
+
interface SettledWorker {
|
|
1935
|
+
readonly id: string;
|
|
1936
|
+
readonly status: 'done' | 'down';
|
|
1937
|
+
readonly score?: number;
|
|
1938
|
+
readonly valid?: boolean;
|
|
1939
|
+
readonly outRef?: string;
|
|
1940
|
+
readonly reason?: string;
|
|
1941
|
+
}
|
|
1942
|
+
type QuestionLevel = 'worker' | 'driver' | 'loop';
|
|
1943
|
+
type QuestionUrgency = 'continue-without' | 'blocks-step' | 'blocks-run';
|
|
1944
|
+
interface QuestionOption {
|
|
1945
|
+
readonly label: string;
|
|
1946
|
+
readonly tradeoff: string;
|
|
1947
|
+
}
|
|
1948
|
+
interface Question {
|
|
1949
|
+
readonly id: string;
|
|
1950
|
+
readonly from: string;
|
|
1951
|
+
readonly level: QuestionLevel;
|
|
1952
|
+
readonly question: string;
|
|
1953
|
+
readonly reason: string;
|
|
1954
|
+
readonly urgency: QuestionUrgency;
|
|
1955
|
+
readonly options?: ReadonlyArray<QuestionOption>;
|
|
1956
|
+
}
|
|
1957
|
+
type QuestionDecision = {
|
|
1958
|
+
readonly kind: 'answer';
|
|
1959
|
+
readonly answer: string;
|
|
1960
|
+
readonly by: string;
|
|
1961
|
+
} | {
|
|
1962
|
+
readonly kind: 'defer';
|
|
1963
|
+
readonly reason: string;
|
|
1964
|
+
} | {
|
|
1965
|
+
readonly kind: 'escalate';
|
|
1966
|
+
readonly to: 'parent' | 'user' | string;
|
|
1967
|
+
readonly reason: string;
|
|
1968
|
+
};
|
|
1969
|
+
interface QuestionRecord extends Question {
|
|
1970
|
+
readonly status: 'open' | 'answered' | 'deferred' | 'escalated';
|
|
1971
|
+
readonly decision?: QuestionDecision;
|
|
1972
|
+
readonly openedAt: number;
|
|
1973
|
+
}
|
|
1974
|
+
type QuestionPolicy = 'auto' | 'mustDecide' | 'bubble' | 'failClosed';
|
|
1975
|
+
interface AnalystRegistry {
|
|
1976
|
+
readonly kinds: ReadonlyArray<{
|
|
1977
|
+
id: string;
|
|
1978
|
+
description: string;
|
|
1979
|
+
area: string;
|
|
1980
|
+
}>;
|
|
1981
|
+
readonly run: (kindId: string, trace: unknown) => Promise<unknown>;
|
|
1982
|
+
}
|
|
1983
|
+
/** A trace-analyst result re-entered as a message on the bus (the `finding` event kind). */
|
|
1984
|
+
interface AnalystFindingEvent {
|
|
1985
|
+
readonly fromWorker: string;
|
|
1986
|
+
readonly analyst: string;
|
|
1987
|
+
readonly findings: unknown;
|
|
1988
|
+
}
|
|
1989
|
+
/** A parent→child message (the down-leg): recorded for observability, delivered via the child inbox,
|
|
1990
|
+
* never pulled back by the parent. `delivered` mirrors whether the live child accepted it. */
|
|
1991
|
+
interface DownMessageEvent {
|
|
1992
|
+
readonly toWorker: string;
|
|
1993
|
+
readonly instruction: string;
|
|
1994
|
+
readonly delivered: boolean;
|
|
1995
|
+
}
|
|
1996
|
+
/** Every message on the one typed pipe. UP (child→parent): question / settled / finding — queued for
|
|
1997
|
+
* the driver to `pull`. DOWN (parent→child): steer / answer — record-only (history + subscribers),
|
|
1998
|
+
* routed to the child inbox. New kinds are additive. */
|
|
1999
|
+
type CoordinationEvent = {
|
|
2000
|
+
readonly type: 'question';
|
|
2001
|
+
readonly question: QuestionRecord;
|
|
2002
|
+
} | {
|
|
2003
|
+
readonly type: 'settled';
|
|
2004
|
+
readonly worker: SettledWorker;
|
|
2005
|
+
} | {
|
|
2006
|
+
readonly type: 'finding';
|
|
2007
|
+
readonly finding: AnalystFindingEvent;
|
|
2008
|
+
} | {
|
|
2009
|
+
readonly type: 'steer';
|
|
2010
|
+
readonly down: DownMessageEvent;
|
|
2011
|
+
} | {
|
|
2012
|
+
readonly type: 'answer';
|
|
2013
|
+
readonly down: DownMessageEvent;
|
|
2014
|
+
readonly questionId: string;
|
|
2015
|
+
};
|
|
2016
|
+
type MakeWorkerAgent = (profile: unknown) => Agent<unknown, unknown>;
|
|
2017
|
+
interface CoordinationToolsOptions {
|
|
2018
|
+
readonly scope: Scope<unknown>;
|
|
2019
|
+
readonly blobs: ResultBlobStore;
|
|
2020
|
+
readonly makeWorkerAgent: MakeWorkerAgent;
|
|
2021
|
+
readonly perWorker: Budget;
|
|
2022
|
+
readonly analysts?: AnalystRegistry;
|
|
2023
|
+
readonly onEvent?: (event: CoordinationEvent) => void | Promise<void>;
|
|
2024
|
+
readonly questionPolicy?: QuestionPolicy;
|
|
2025
|
+
/** Analyst kind ids to run AUTOMATICALLY when a worker settles `done` (the analyst-on-settle
|
|
2026
|
+
* hook). Each result is published as a `finding` event on the bus — pass-through to subscribers
|
|
2027
|
+
* and queued for the driver to pull via `await_event`. Omit/empty = no auto-analysis (default;
|
|
2028
|
+
* the driver can still run lenses on demand via `run_analyst`). Requires `analysts`. */
|
|
2029
|
+
readonly analyzeOnSettle?: ReadonlyArray<string>;
|
|
2030
|
+
/** Hard cap on how many workers may be LIVE (spawned but not yet settled) at once. `spawn_agent`
|
|
2031
|
+
* counts the scope's non-terminal nodes and fails closed (`error: 'max-live-workers'`) BEFORE
|
|
2032
|
+
* reserving from the pool when the cap is already met — a concurrency fence on top of the
|
|
2033
|
+
* conserved-budget fence (the pool bounds total work; this bounds simultaneous work, e.g. live
|
|
2034
|
+
* sandboxes/boxes). Omit or `<= 0` = no cap (the prior behavior; the pool stays the only fence). */
|
|
2035
|
+
readonly maxLiveWorkers?: number;
|
|
2036
|
+
}
|
|
2037
|
+
/**
|
|
2038
|
+
* The supervisor-side toolbox returned by {@link createCoordinationTools}: the MCP tool
|
|
2039
|
+
* descriptors a driver `AgentProfile` calls to spawn, steer, observe, and settle workers
|
|
2040
|
+
* over a live `Scope`, plus the typed accessors (`settled`/`questions`/`history`/`stats`/
|
|
2041
|
+
* `raiseFinding`) for the bidirectional coordination bus. This is the live, backend-of-your-
|
|
2042
|
+
* choice, steerable counterpart to the one-shot own-sandbox delegation MCP.
|
|
2043
|
+
*/
|
|
2044
|
+
interface CoordinationTools {
|
|
2045
|
+
readonly tools: McpToolDescriptor[];
|
|
2046
|
+
isStopped(): boolean;
|
|
2047
|
+
stopReason(): string | undefined;
|
|
2048
|
+
settled(): ReadonlyArray<SettledWorker>;
|
|
2049
|
+
questions(): ReadonlyArray<QuestionRecord>;
|
|
2050
|
+
/** The full ordered log of every bus event — UP (settled / question / finding) and DOWN
|
|
2051
|
+
* (steer / answer) — the observability audit + replay trail. Each record carries seq,
|
|
2052
|
+
* timestamp, and priority. */
|
|
2053
|
+
history(): ReadonlyArray<BusRecord<CoordinationEvent>>;
|
|
2054
|
+
/** Bus throughput counters (published / pulled / by-kind) for live dashboards. */
|
|
2055
|
+
stats(): BusStats;
|
|
2056
|
+
/** Raise a `finding` on the bus from outside the settle hook — the seam an ONLINE detector
|
|
2057
|
+
* (mid-run, on the worker pipe) uses to tell the driver "this worker is looping/erroring" the
|
|
2058
|
+
* moment it happens, instead of only at settle. Queued for `await_event` + pass-through. */
|
|
2059
|
+
raiseFinding(finding: AnalystFindingEvent): Promise<void>;
|
|
2060
|
+
}
|
|
2061
|
+
/** Build the driver's MCP tools over a live scope. */
|
|
2062
|
+
declare function createCoordinationTools(opts: CoordinationToolsOptions): CoordinationTools;
|
|
2063
|
+
|
|
2064
|
+
export { type DelegationTaskQueueOptions as $, type AnalystRegistry as A, type DelegateResearchArgs as B, type CappedDelegationTrace as C, type DelegationExecutor as D, type DelegateResearchConfig as E, type FleetHandle as F, type DelegateResearchResult as G, type DelegateResult as H, type DelegateRunCtx as I, type DelegateUiAuditConfig as J, type DelegateUiAuditRoute as K, type DelegationError as L, type DelegationFeedbackSnapshot as M, type DelegationHistoryEntry as N, DelegationPersistenceError as O, type DelegationProfile as P, type DelegationProgress as Q, type DelegationRecord as R, type DelegationResultPayload as S, type DelegationResumeContext as T, type UiAuditorDelegate as U, type DelegationResumeDriver as V, type DelegationResumeTick as W, type DelegationRunContext as X, DelegationStateCorruptError as Y, type DelegationStatus as Z, type DelegationStore as _, DelegationTaskQueue as a, type ExecutorConfig as a$, type DelegationTraceCaps as a0, type DelegationTraceCollector as a1, type DelegationTraceSpan as a2, type DetachedSessionDelegateOptions as a3, type DetachedSessionRefParts as a4, type DetachedTurn as a5, type DetachedTurnResumeDriverOptions as a6, type DetachedWinnerSelection as a7, type DriveTurnCapableBox as a8, type DriveTurnTick as a9, type SubmitOutput as aA, type TraceContext as aB, type UiAuditorDelegationOutput as aC, buildDelegationTraceSpans as aD, capDelegationTrace as aE, coderTaskFromArgs as aF, composeLoopTraceEmitters as aG, createCoordinationTools as aH, createDelegateHandler as aI, createDelegationTraceCollector as aJ, createDetachedTurnResumeDriver as aK, createFleetWorkspaceExecutor as aL, createInProcessTransport as aM, createMcpServer as aN, createPropagatingTraceEmitter as aO, createSiblingSandboxExecutor as aP, detachedSessionDelegate as aQ, detachedTurnEvents as aR, eventToSnapshot as aS, formatDetachedSessionRef as aT, hashIdempotencyInput as aU, parseDetachedSessionRef as aV, readTraceContextFromEnv as aW, runDetachedTurn as aX, settleDetachedCoderTurn as aY, traceContextToEnv as aZ, validateDelegateArgs as a_, type FeedbackEvent as aa, type FeedbackRating as ab, type FeedbackRefersTo as ac, FileDelegationStore as ad, type FileDelegationStoreOptions as ae, type FleetWorkspaceExecutorOptions as af, InMemoryDelegationStore as ag, InMemoryFeedbackStore as ah, type JsonRpcMessage as ai, type JsonRpcResponse as aj, type MakeWorkerAgent as ak, type McpServer as al, type McpServerOptions as am, type McpToolDescriptor as an, type McpTransport as ao, type Question as ap, type QuestionDecision as aq, type QuestionPolicy as ar, type QuestionRecord as as, type ResearchOutputShape as at, type ResearchSource as au, type RunDetachedTurnOptions as av, type SettleDetachedCoderTurnOptions as aw, type SettledWorker as ax, type SiblingSandboxExecutorOptions as ay, type SubmitInput as az, type FeedbackStore as b, type BusEvent as b0, type BusRecord as b1, type BusStats as b2, type EventBus as b3, type PublishOptions as b4, cliWorktreeExecutor as b5, createEventBus as b6, createExecutor as b7, createExecutorRegistry as b8, type DelegateFeedbackResult as c, type DelegateFeedbackArgs as d, type DelegateUiAuditArgs as e, type DelegateUiAuditResult as f, type DelegationHistoryResult as g, type DelegationHistoryArgs as h, type DelegationStatusResult as i, type DelegationStatusArgs as j, type CoderDelegate as k, type CoderReview as l, type CoderReviewer as m, type CoordinationEvent as n, type CoordinationTools as o, type CoordinationToolsOptions as p, DELEGATE_DESCRIPTION as q, DELEGATE_INPUT_SCHEMA as r, DELEGATE_TOOL_NAME as s, DELEGATION_TRACE_MAX_BYTES as t, DELEGATION_TRACE_MAX_SPANS as u, type DelegateArgs as v, type DelegateCodeArgs as w, type DelegateCodeConfig as x, type DelegateCodeResult as y, type DelegateHandlerOptions as z };
|