@tangle-network/agent-runtime 0.105.0 → 0.106.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/activation-CRjVfOiy.js +203 -0
- package/dist/activation-CRjVfOiy.js.map +1 -0
- package/dist/activation-DyWB0K6E.d.ts +98 -0
- package/dist/agent.d.ts +216 -234
- package/dist/agent.js +615 -547
- package/dist/agent.js.map +1 -1
- package/dist/analyst-loop-DGdtVENg.js +517 -0
- package/dist/analyst-loop-DGdtVENg.js.map +1 -0
- package/dist/analyst-loop.d.ts +10 -43
- package/dist/analyst-loop.js +2 -11
- package/dist/backends-CiOCyRHb.js +743 -0
- package/dist/backends-CiOCyRHb.js.map +1 -0
- package/dist/candidate-execution/index.d.ts +4 -192
- package/dist/candidate-execution/index.js +5 -66
- package/dist/candidate-execution-DqMbv1rU.js +488 -0
- package/dist/candidate-execution-DqMbv1rU.js.map +1 -0
- package/dist/coder-yhVWbdWc.js +40 -0
- package/dist/coder-yhVWbdWc.js.map +1 -0
- package/dist/conversation-BpLQZGPH.js +1265 -0
- package/dist/conversation-BpLQZGPH.js.map +1 -0
- package/dist/conversation.d.ts +2 -804
- package/dist/conversation.js +2 -55
- package/dist/environment-provider-CfLUmKmf.js +1168 -0
- package/dist/environment-provider-CfLUmKmf.js.map +1 -0
- package/dist/environment-provider-IUGU3epE.d.ts +964 -0
- package/dist/environment-provider.d.ts +2 -78
- package/dist/environment-provider.js +2 -18
- package/dist/errors-DEAvWQPy.js +111 -0
- package/dist/errors-DEAvWQPy.js.map +1 -0
- package/dist/improvement-adapter-Cr5TBSji.d.ts +166 -0
- package/dist/improvement-cycle-C095kS_g.js +2624 -0
- package/dist/improvement-cycle-C095kS_g.js.map +1 -0
- package/dist/index-BGdxAwfO.d.ts +838 -0
- package/dist/index-C-FYUuFG.d.ts +193 -0
- package/dist/index-CbNM40xG.d.ts +140 -0
- package/dist/index-DruSKs3Z.d.ts +7224 -0
- package/dist/index-Efjb3nrQ.d.ts +671 -0
- package/dist/index.d.ts +14 -1058
- package/dist/index.js +2106 -2082
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +768 -889
- package/dist/intelligence.js +1466 -1367
- package/dist/intelligence.js.map +1 -1
- package/dist/{kb-gate-CwHO0vz6.d.ts → kb-gate-C8z2juK8.d.ts} +33 -31
- package/dist/kb-gate-DpaSwXVx.js +80 -0
- package/dist/kb-gate-DpaSwXVx.js.map +1 -0
- package/dist/knowledge-Ku-mPP4f.js +433 -0
- package/dist/knowledge-Ku-mPP4f.js.map +1 -0
- package/dist/knowledge.d.ts +2 -150
- package/dist/knowledge.js +2 -40
- package/dist/local-harness-Dh8PJ0ot.d.ts +455 -0
- package/dist/loop-runner-bin-BXsFEUcf.d.ts +162 -0
- package/dist/loop-runner-bin-CRagyuNb.js +268 -0
- package/dist/loop-runner-bin-CRagyuNb.js.map +1 -0
- package/dist/loop-runner-bin.d.ts +2 -15
- package/dist/loop-runner-bin.js +2 -24
- package/dist/loops.d.ts +5 -4164
- package/dist/loops.js +8 -419
- package/dist/mcp/bin.d.ts +1 -1
- package/dist/mcp/bin.js +116 -146
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +295 -436
- package/dist/mcp/index.js +1242 -1177
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/memory-bin.d.ts +1 -1
- package/dist/mcp/memory-bin.js +37 -16
- package/dist/mcp/memory-bin.js.map +1 -1
- package/dist/memory-server-DL6cE2Ag.js +234 -0
- package/dist/memory-server-DL6cE2Ag.js.map +1 -0
- package/dist/model-resolution-Btd9iIKV.js +98 -0
- package/dist/model-resolution-Btd9iIKV.js.map +1 -0
- package/dist/openai-tools-B68JaOCx.d.ts +24 -0
- package/dist/openai-tools-CKLy1C7M.js +44 -0
- package/dist/openai-tools-CKLy1C7M.js.map +1 -0
- package/dist/otel-export-D34IQW1C.js +843 -0
- package/dist/otel-export-D34IQW1C.js.map +1 -0
- package/dist/platform.d.ts +188 -185
- package/dist/platform.js +185 -218
- package/dist/platform.js.map +1 -1
- package/dist/prepare-B53sPV7M.js +4292 -0
- package/dist/prepare-B53sPV7M.js.map +1 -0
- package/dist/primeintellect/index.d.ts +149 -145
- package/dist/primeintellect/index.js +626 -1003
- package/dist/primeintellect/index.js.map +1 -1
- package/dist/profiles.d.ts +296 -490
- package/dist/profiles.js +722 -749
- package/dist/profiles.js.map +1 -1
- package/dist/protected-model-port-BLPH5VVv.js +722 -0
- package/dist/protected-model-port-BLPH5VVv.js.map +1 -0
- package/dist/protected-model-port-BP6Z4eau.d.ts +283 -0
- package/dist/protected-redaction--F3v1oo8.js +200 -0
- package/dist/protected-redaction--F3v1oo8.js.map +1 -0
- package/dist/redact-D-u-rrcn.js +82 -0
- package/dist/redact-D-u-rrcn.js.map +1 -0
- package/dist/redact-kbIOjfjM.d.ts +452 -0
- package/dist/researcher-CoVqNhfI.js +433 -0
- package/dist/researcher-CoVqNhfI.js.map +1 -0
- package/dist/runtime-5zM5XxLr.js +5408 -0
- package/dist/runtime-5zM5XxLr.js.map +1 -0
- package/dist/sandbox-events-DeI5xX8P.js +316 -0
- package/dist/sandbox-events-DeI5xX8P.js.map +1 -0
- package/dist/spawn-journal-CwPvKUTa.js +456 -0
- package/dist/spawn-journal-CwPvKUTa.js.map +1 -0
- package/dist/structural-rollout-IXUEplky.js +1445 -0
- package/dist/structural-rollout-IXUEplky.js.map +1 -0
- package/dist/substrate-B0TYNrXn.js +27 -0
- package/dist/substrate-B0TYNrXn.js.map +1 -0
- package/dist/{substrate-Dyiqmd3o.d.ts → substrate-BcnuSHXm.d.ts} +57 -54
- package/dist/supervise-BiRutHS9.js +7321 -0
- package/dist/supervise-BiRutHS9.js.map +1 -0
- package/dist/supervisor-DTKhF-RV.js +3826 -0
- package/dist/supervisor-DTKhF-RV.js.map +1 -0
- package/dist/testing.d.ts +4 -3
- package/dist/testing.js +2478 -2637
- package/dist/testing.js.map +1 -1
- package/dist/tool-server-RcWgLIsL.js +141 -0
- package/dist/tool-server-RcWgLIsL.js.map +1 -0
- package/dist/trace-propagation-CJJC7SVB.js +57 -0
- package/dist/trace-propagation-CJJC7SVB.js.map +1 -0
- package/dist/types-BaIpb0XT.d.ts +492 -0
- package/dist/types-BevOjfTY.d.ts +765 -0
- package/dist/types-C9j4qg6l.d.ts +500 -0
- package/dist/types-Cja5OTGh.d.ts +190 -0
- package/dist/util-MVgdwuIS.js +145 -0
- package/dist/util-MVgdwuIS.js.map +1 -0
- package/dist/workspace-archive-BosQiotA.js +575 -0
- package/dist/workspace-archive-BosQiotA.js.map +1 -0
- package/package.json +44 -56
- package/skills/build-with-agent-runtime/SKILL.md +1 -0
- package/dist/activation-Cm-9MMX1.d.ts +0 -69
- package/dist/analyst-loop.js.map +0 -1
- package/dist/backends-BO4Jqoe2.d.ts +0 -134
- package/dist/candidate-execution/index.js.map +0 -1
- package/dist/chunk-2KGAN2HM.js +0 -1256
- package/dist/chunk-2KGAN2HM.js.map +0 -1
- package/dist/chunk-2VZYRB55.js +0 -834
- package/dist/chunk-2VZYRB55.js.map +0 -1
- package/dist/chunk-3MDZX7YU.js +0 -125
- package/dist/chunk-3MDZX7YU.js.map +0 -1
- package/dist/chunk-5IBQAPVB.js +0 -29
- package/dist/chunk-5IBQAPVB.js.map +0 -1
- package/dist/chunk-5QOB7H74.js +0 -387
- package/dist/chunk-5QOB7H74.js.map +0 -1
- package/dist/chunk-C5RTIBNZ.js +0 -48
- package/dist/chunk-C5RTIBNZ.js.map +0 -1
- package/dist/chunk-CTRA64LY.js +0 -680
- package/dist/chunk-CTRA64LY.js.map +0 -1
- package/dist/chunk-DPEUKJRO.js +0 -27
- package/dist/chunk-DPEUKJRO.js.map +0 -1
- package/dist/chunk-FD2MBMOH.js +0 -494
- package/dist/chunk-FD2MBMOH.js.map +0 -1
- package/dist/chunk-H5QPIZNX.js +0 -907
- package/dist/chunk-H5QPIZNX.js.map +0 -1
- package/dist/chunk-HLKC4UYB.js +0 -3514
- package/dist/chunk-HLKC4UYB.js.map +0 -1
- package/dist/chunk-HNP72PNU.js +0 -192
- package/dist/chunk-HNP72PNU.js.map +0 -1
- package/dist/chunk-ISPWRSEC.js +0 -408
- package/dist/chunk-ISPWRSEC.js.map +0 -1
- package/dist/chunk-KRBFHMV6.js +0 -1228
- package/dist/chunk-KRBFHMV6.js.map +0 -1
- package/dist/chunk-M22PL4GH.js +0 -171
- package/dist/chunk-M22PL4GH.js.map +0 -1
- package/dist/chunk-NURIQBJQ.js +0 -72
- package/dist/chunk-NURIQBJQ.js.map +0 -1
- package/dist/chunk-OPVWXJ2H.js +0 -75
- package/dist/chunk-OPVWXJ2H.js.map +0 -1
- package/dist/chunk-PZZKQVQV.js +0 -52
- package/dist/chunk-PZZKQVQV.js.map +0 -1
- package/dist/chunk-Q2JSAVQ3.js +0 -671
- package/dist/chunk-Q2JSAVQ3.js.map +0 -1
- package/dist/chunk-RDOAVVHY.js +0 -699
- package/dist/chunk-RDOAVVHY.js.map +0 -1
- package/dist/chunk-SGKPNBXE.js +0 -60
- package/dist/chunk-SGKPNBXE.js.map +0 -1
- package/dist/chunk-SMQXZGLZ.js +0 -351
- package/dist/chunk-SMQXZGLZ.js.map +0 -1
- package/dist/chunk-UHEZW5BU.js +0 -2918
- package/dist/chunk-UHEZW5BU.js.map +0 -1
- package/dist/chunk-UPWGXKXB.js +0 -254
- package/dist/chunk-UPWGXKXB.js.map +0 -1
- package/dist/chunk-VISA6CI3.js +0 -200
- package/dist/chunk-VISA6CI3.js.map +0 -1
- package/dist/chunk-WMTCUOQL.js +0 -474
- package/dist/chunk-WMTCUOQL.js.map +0 -1
- package/dist/chunk-WRTOVNN4.js +0 -4728
- package/dist/chunk-WRTOVNN4.js.map +0 -1
- package/dist/chunk-WSTRQZYQ.js +0 -5576
- package/dist/chunk-WSTRQZYQ.js.map +0 -1
- package/dist/chunk-XBG2W2VW.js +0 -6434
- package/dist/chunk-XBG2W2VW.js.map +0 -1
- package/dist/chunk-YEJR7IXO.js +0 -68
- package/dist/chunk-YEJR7IXO.js.map +0 -1
- package/dist/chunk-YJZA2BIK.js +0 -1338
- package/dist/chunk-YJZA2BIK.js.map +0 -1
- package/dist/completion-gate-BMy5LGoP.d.ts +0 -256
- package/dist/conversation.js.map +0 -1
- package/dist/coordination-BZZSVYpZ.d.ts +0 -2570
- package/dist/environment-provider.js.map +0 -1
- package/dist/improvement-adapter-HAZz-7vK.d.ts +0 -203
- package/dist/knowledge.js.map +0 -1
- package/dist/local-harness-BDNcl6jI.d.ts +0 -175
- package/dist/loop-runner-bin-68aoM9-7.d.ts +0 -199
- package/dist/loop-runner-bin.js.map +0 -1
- package/dist/loops.js.map +0 -1
- package/dist/openai-tools-fnj6SRVg.d.ts +0 -46
- package/dist/protected-model-port-B4t-OQjL.d.ts +0 -271
- package/dist/redact-BuFjxBUJ.d.ts +0 -481
- package/dist/sanitize-DEbPNtyI.d.ts +0 -328
- package/dist/structural-rollout-DEh6CEsa.d.ts +0 -446
- package/dist/supervise-4_48wwvy.d.ts +0 -379
- package/dist/types-BCoemcXU.d.ts +0 -802
- package/dist/types-BwoZWq-i.d.ts +0 -510
- package/dist/types-Cbp72qyu.d.ts +0 -491
- package/dist/types-CmYCMbFT.d.ts +0 -203
- package/dist/types-CvNwMzQt.d.ts +0 -957
- package/dist/worktree-fanout-DxhAWr5Z.d.ts +0 -999
package/dist/types-CvNwMzQt.d.ts
DELETED
|
@@ -1,957 +0,0 @@
|
|
|
1
|
-
import { ToolSpan, DefaultVerdict } from '@tangle-network/agent-eval';
|
|
2
|
-
import { AgentProfile } from '@tangle-network/agent-interface';
|
|
3
|
-
import { BackendType } from '@tangle-network/sandbox';
|
|
4
|
-
import { L as LoopTokenUsage, R as RuntimeHooks } from './types-BCoemcXU.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
* The LIVE read-model of a still-RUNNING worker — what a driver can see BEFORE the worker settles.
|
|
9
|
-
*
|
|
10
|
-
* Until this existed, `observe_agent` on a running worker returned `{status:'running', spent:{0,0},
|
|
11
|
-
* outRef:null, output:null}`: nothing a brain could act on, so a brain that wanted to steer had no
|
|
12
|
-
* evidence to steer FROM. This is the other half of the steering wire (the first half is
|
|
13
|
-
* `Executor.deliver`): a supervisor cannot correct a worker it cannot watch.
|
|
14
|
-
*
|
|
15
|
-
* Two layers, both pull-based — no timer, no background task, so it is safe to leave on:
|
|
16
|
-
*
|
|
17
|
-
* - The SCOPE layer, available for EVERY executor with no executor cooperation at all: usage
|
|
18
|
-
* events are timestamped as they arrive, so `lastActivityAt` / `idleMs` / `stalled` /
|
|
19
|
-
* `tokens` / `turns` are derived from the stream the conserved pool already meters.
|
|
20
|
-
* - The EXECUTOR layer, optional enrichment via `Executor.progress()`: the tool/file activity
|
|
21
|
-
* the harness exposes, its own turn count, and how many steers are queued but unread.
|
|
22
|
-
*
|
|
23
|
-
* `stalled` is a DERIVED read, computed at observation time against `stallAfterMs` — never a
|
|
24
|
-
* background watchdog. A worker that has produced no metered activity for longer than the
|
|
25
|
-
* threshold reads `stalled: true`; nothing is killed, nothing is retried. The driver decides.
|
|
26
|
-
*
|
|
27
|
-
* @experimental
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/** How long a worker may produce no metered activity before a `progress()` read calls it stalled.
|
|
31
|
-
* Deliberately generous: a coding harness routinely spends minutes inside one tool call, and a
|
|
32
|
-
* false stall that provokes a steer is worse than a late one. */
|
|
33
|
-
declare const DEFAULT_STALL_AFTER_MS = 180000;
|
|
34
|
-
/** The most recent activity the executor can name — one tool call, one turn, or a free-form note.
|
|
35
|
-
* `label` is the tool/file/turn name; `detail` is a short, already-truncated descriptor (a path,
|
|
36
|
-
* a command head) that a driver can read without pulling the whole transcript. */
|
|
37
|
-
interface ActivityNote {
|
|
38
|
-
readonly at: number;
|
|
39
|
-
readonly kind: 'turn' | 'tool' | 'note';
|
|
40
|
-
readonly label: string;
|
|
41
|
-
readonly status?: 'ok' | 'error';
|
|
42
|
-
readonly detail?: string;
|
|
43
|
-
}
|
|
44
|
-
/** What an executor OPTIONALLY adds to the scope-derived progress (`Executor.progress()`). Every
|
|
45
|
-
* field is optional: an executor that knows only its own turn count reports only that. */
|
|
46
|
-
interface ExecutorProgress {
|
|
47
|
-
/** The executor's own turn/step count when it is more meaningful than metered iterations. */
|
|
48
|
-
readonly turns?: number;
|
|
49
|
-
/** Steers/answers delivered but not yet folded into the worker's conversation. */
|
|
50
|
-
readonly pendingMessages?: number;
|
|
51
|
-
/** Newest-last window of what the worker has been doing. */
|
|
52
|
-
readonly recentActivity?: ReadonlyArray<ActivityNote>;
|
|
53
|
-
/** A one-line human-readable state ("turn 3, running tests"). */
|
|
54
|
-
readonly note?: string;
|
|
55
|
-
}
|
|
56
|
-
/** The full live view of one worker, as `observe_agent` returns it mid-flight. */
|
|
57
|
-
interface WorkerProgress {
|
|
58
|
-
readonly id: string;
|
|
59
|
-
readonly status: NodeStatus;
|
|
60
|
-
/** True while the node is neither done, failed, nor cancelled — i.e. a steer could still land. */
|
|
61
|
-
readonly live: boolean;
|
|
62
|
-
/** True when this worker's executor exposes an inbox (`Executor.deliver`) — i.e. `steer_agent`
|
|
63
|
-
* can actually reach it. False means a steer would be recorded and dropped. */
|
|
64
|
-
readonly steerable: boolean;
|
|
65
|
-
readonly startedAt: number;
|
|
66
|
-
/** Epoch ms of the last metered usage event or executor-reported activity. */
|
|
67
|
-
readonly lastActivityAt: number;
|
|
68
|
-
readonly idleMs: number;
|
|
69
|
-
readonly stalled: boolean;
|
|
70
|
-
readonly stallAfterMs: number;
|
|
71
|
-
/** Metered iterations so far (the executor's own count when it reports one). */
|
|
72
|
-
readonly turns: number;
|
|
73
|
-
readonly tokens: {
|
|
74
|
-
readonly input: number;
|
|
75
|
-
readonly output: number;
|
|
76
|
-
};
|
|
77
|
-
readonly usd: number;
|
|
78
|
-
/** Steers delivered but not yet read by the worker. */
|
|
79
|
-
readonly pendingMessages: number;
|
|
80
|
-
/** Newest-last window of tool/turn activity; empty when the executor exposes none. */
|
|
81
|
-
readonly recentActivity: ReadonlyArray<ActivityNote>;
|
|
82
|
-
readonly note?: string;
|
|
83
|
-
}
|
|
84
|
-
/** A bounded newest-last ring of `ActivityNote`s an executor keeps to answer `progress()`. */
|
|
85
|
-
interface ActivityLog {
|
|
86
|
-
push(note: ActivityNote): void;
|
|
87
|
-
/** Newest-last, at most `limit` entries. */
|
|
88
|
-
read(): ReadonlyArray<ActivityNote>;
|
|
89
|
-
last(): ActivityNote | undefined;
|
|
90
|
-
size(): number;
|
|
91
|
-
}
|
|
92
|
-
/** Create a bounded activity ring. `limit` caps memory for a worker that runs thousands of tools. */
|
|
93
|
-
declare function createActivityLog(limit?: number): ActivityLog;
|
|
94
|
-
/** The scope-side facts about a child, independent of whether its executor cooperates. */
|
|
95
|
-
interface ScopeProgressInput {
|
|
96
|
-
readonly id: string;
|
|
97
|
-
readonly status: NodeStatus;
|
|
98
|
-
readonly steerable: boolean;
|
|
99
|
-
readonly startedAt: number;
|
|
100
|
-
readonly lastActivityAt: number;
|
|
101
|
-
readonly turns: number;
|
|
102
|
-
readonly tokens: {
|
|
103
|
-
readonly input: number;
|
|
104
|
-
readonly output: number;
|
|
105
|
-
};
|
|
106
|
-
readonly usd: number;
|
|
107
|
-
}
|
|
108
|
-
/** Fold the scope-derived facts and the executor's optional enrichment into one read. Pure: the
|
|
109
|
-
* caller supplies `now`, so a test can observe a stall without waiting for one. */
|
|
110
|
-
declare function readWorkerProgress(scope: ScopeProgressInput, executor: ExecutorProgress | undefined, now: number, stallAfterMs?: number): WorkerProgress;
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
*
|
|
114
|
-
* `TraceSource` — the ONE substrate-agnostic source of a worker's tool-call trace. The online
|
|
115
|
-
* detectors and the settle-time analyzers consume agent-eval `ToolSpan`s from here, regardless of
|
|
116
|
-
* whether the worker is:
|
|
117
|
-
* - an OWNED tool loop (router-tools, cli-bridge tool dispatch) → push spans as we dispatch them;
|
|
118
|
-
* - a SANDBOX / fleet box → read the harness's tool calls off the session (`streamPrompt` parts
|
|
119
|
-
* live, `session.messages()` / `findCompletedTurn` at settle).
|
|
120
|
-
*
|
|
121
|
-
* The common currency is agent-eval's `ToolSpan` (so the same detectors + `buildTrajectory`/
|
|
122
|
-
* `stuckLoopView`/`toolWasteView` run over any source). A source exposes two lanes:
|
|
123
|
-
* - `onSpan` — live spans for ONLINE detection (best-effort; a black-box box may only collect).
|
|
124
|
-
* - `collect` — the full span set at settle for the BATCH analyzers (always available).
|
|
125
|
-
*
|
|
126
|
-
* This module imports NO substrate SDK — it decodes generic message parts / OpenAI tool-call shapes.
|
|
127
|
-
* The sandbox wiring (`sandboxSessionTraceSource`) is the thin adapter that feeds box session parts in.
|
|
128
|
-
*
|
|
129
|
-
* @experimental
|
|
130
|
-
*/
|
|
131
|
-
|
|
132
|
-
interface ToolStepInput {
|
|
133
|
-
readonly toolName: string;
|
|
134
|
-
readonly args: unknown;
|
|
135
|
-
readonly status?: 'ok' | 'error';
|
|
136
|
-
readonly result?: unknown;
|
|
137
|
-
/** Stable id of the tool call — used to de-duplicate the repeated state transitions a harness
|
|
138
|
-
* streams for one call (opencode emits pending→running→completed, plus a `raw`-wrapped copy). */
|
|
139
|
-
readonly callId?: string;
|
|
140
|
-
/** Real per-call wall-clock when the source has it (owned tool-loop; opencode parts with `time`).
|
|
141
|
-
* When omitted the span collapses to a single instant (`at`) — order + counts only, no duration. */
|
|
142
|
-
readonly startedAt?: number;
|
|
143
|
-
readonly endedAt?: number;
|
|
144
|
-
}
|
|
145
|
-
interface TraceSource {
|
|
146
|
-
/** Subscribe to tool spans as they are produced (ONLINE). Returns an unsubscribe. A source that
|
|
147
|
-
* only exposes its trace at the end registers nothing and returns a no-op. */
|
|
148
|
-
onSpan(handler: (span: ToolSpan) => void): () => void;
|
|
149
|
-
/** The full set of tool spans for the run (SETTLE / batch). Always available. */
|
|
150
|
-
collect(): Promise<ToolSpan[]>;
|
|
151
|
-
}
|
|
152
|
-
/** Decode a part with a specific harness's adapter when known, else try every registered adapter
|
|
153
|
-
* (the composite — robust to mixed/unknown streams). Never throws. */
|
|
154
|
-
declare function decodeToolPart(part: unknown, harness?: string): ToolStepInput | undefined;
|
|
155
|
-
/** A push source for OWNED tool loops (router-tools / cli-bridge tool dispatch): the loop calls
|
|
156
|
-
* `record(step)` for each tool call; it becomes a span, fan-out to live subscribers + buffered for
|
|
157
|
-
* `collect`. */
|
|
158
|
-
declare function createPushTraceSource(opts?: {
|
|
159
|
-
runId?: string;
|
|
160
|
-
now?: () => number;
|
|
161
|
-
}): {
|
|
162
|
-
source: TraceSource;
|
|
163
|
-
record: (input: ToolStepInput) => ToolSpan;
|
|
164
|
-
};
|
|
165
|
-
/** A harness session message carrying parts (the shape `box.messages()` returns). Structurally typed
|
|
166
|
-
* so this works with the real `@tangle-network/sandbox` box AND a test double, no SDK import. */
|
|
167
|
-
interface SessionMessageLike {
|
|
168
|
-
readonly parts?: ReadonlyArray<unknown>;
|
|
169
|
-
}
|
|
170
|
-
/** The minimal box surface this needs: list a session's messages (incl. mid-turn partials). */
|
|
171
|
-
interface SessionTraceBox {
|
|
172
|
-
messages(opts: {
|
|
173
|
-
sessionId: string;
|
|
174
|
-
}): Promise<ReadonlyArray<SessionMessageLike>>;
|
|
175
|
-
}
|
|
176
|
-
/** The SANDBOX / fleet trace source: read a box session's message parts and decode the harness's tool
|
|
177
|
-
* calls into spans. `collect` (settle) is the solid path — `box.messages({sessionId})` → parts → spans;
|
|
178
|
-
* black-box harnesses aren't mid-step interruptible, so online steering is the owned-loop's job and a
|
|
179
|
-
* live `subscribe` is opt-in (pass `subscribeParts` from `streamPrompt` when the harness streams parts). */
|
|
180
|
-
declare function sandboxSessionTraceSource(box: SessionTraceBox, sessionId: string, opts?: {
|
|
181
|
-
/** The box's harness (e.g. 'opencode', 'claude-code') → selects its decoder adapter. */
|
|
182
|
-
harness?: string;
|
|
183
|
-
subscribeParts?: (onPart: (part: unknown) => void) => () => void;
|
|
184
|
-
runId?: string;
|
|
185
|
-
now?: () => number;
|
|
186
|
-
}): TraceSource;
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
*
|
|
190
|
-
* WAIT-STATES — a supervision-tree node that waits on wall-clock time or an external condition
|
|
191
|
-
* without holding a worker, an executor, a sandbox, or a single LLM turn.
|
|
192
|
-
*
|
|
193
|
-
* A long-horizon run spends most of its wall-clock NOT computing: waiting for CI to finish,
|
|
194
|
-
* for a nightly job to land, for a human to reply, for a rate-limit window to reopen. Before
|
|
195
|
-
* this, the only way to express that was to keep something alive and re-ask — which spends
|
|
196
|
-
* driver tokens per re-ask and pins a process to the wait.
|
|
197
|
-
*
|
|
198
|
-
* Two node kinds, both first-class:
|
|
199
|
-
* - `timer` — wake at an ABSOLUTE wall-clock instant (`untilMs`).
|
|
200
|
-
* - `poll` — re-run a named predicate every `intervalMs` until it returns true, or until an
|
|
201
|
-
* absolute `timeoutAtMs` passes (CI status, file existence, an HTTP probe, an
|
|
202
|
-
* inbox message).
|
|
203
|
-
*
|
|
204
|
-
* ── How this differs from `await_event`'s 15s poll fence (`DEFAULT_AWAIT_EVENT_TIMEOUT_MS`) ──
|
|
205
|
-
*
|
|
206
|
-
* They look similar and are not the same mechanism. `await_event` is an IN-RUN RENDEZVOUS: the
|
|
207
|
-
* driver blocks on the coordination bus for the next event from a live worker, and the 15s fence
|
|
208
|
-
* exists only so a remote MCP request does not exceed the client's timeout — the caller re-polls.
|
|
209
|
-
* Every re-poll is another driver inference turn (real tokens) against a process that must stay
|
|
210
|
-
* up, and nothing about that wait is recorded: kill the process and the wait is simply gone.
|
|
211
|
-
*
|
|
212
|
-
* A wait-state is a NODE, not a call. It has a node id in the tree, a journal record carrying its
|
|
213
|
-
* ABSOLUTE deadline, and it settles through the same `Scope.next()` cursor as any worker. Nobody
|
|
214
|
-
* is blocked on it — the driver can stop reasoning entirely, and the process can die. Cost while
|
|
215
|
-
* waiting: zero LLM calls, zero executor, zero sandbox, zero conserved budget (a wait reserves
|
|
216
|
-
* nothing from the pool). The only in-process residue is one timer entry.
|
|
217
|
-
*
|
|
218
|
-
* ── Why probes are NAMED, not passed as closures ────────────────────────────────────────────
|
|
219
|
-
*
|
|
220
|
-
* A wait must survive a process restart with its original deadline intact, and a closure cannot
|
|
221
|
-
* be journaled. So a `poll` names its predicate (`probe: 'ci-green'`) and the run resolves it
|
|
222
|
-
* through a `WaitProbeRegistry`. A brand-new process re-resolves the SAME name against its own
|
|
223
|
-
* registry and re-arms the wait — which is what makes "kill the box, the wait keeps waiting"
|
|
224
|
-
* true rather than aspirational.
|
|
225
|
-
*
|
|
226
|
-
* Absolute instants for the same reason: `untilMs` / `timeoutAtMs` are epoch ms, not durations,
|
|
227
|
-
* so a resumed wait counts down from the original arm, not from the restart. `timerAt`/`pollFor`
|
|
228
|
-
* build them from a duration when that is what the caller has.
|
|
229
|
-
*
|
|
230
|
-
* @experimental
|
|
231
|
-
*/
|
|
232
|
-
/** What a wait node is waiting for. Both variants carry ABSOLUTE epoch-ms instants so a wait
|
|
233
|
-
* re-armed by a later process keeps the deadline the first process set. */
|
|
234
|
-
type WaitSpec = {
|
|
235
|
-
readonly kind: 'timer';
|
|
236
|
-
/** Absolute epoch ms to wake at. A past instant fires immediately. */
|
|
237
|
-
readonly untilMs: number;
|
|
238
|
-
} | {
|
|
239
|
-
readonly kind: 'poll';
|
|
240
|
-
/** Name of the predicate in the run's `WaitProbeRegistry`. Named (not a closure) so a
|
|
241
|
-
* resumed process can re-resolve it — see the module header. */
|
|
242
|
-
readonly probe: string;
|
|
243
|
-
/** How often to re-run the predicate, in ms. Must be > 0. */
|
|
244
|
-
readonly intervalMs: number;
|
|
245
|
-
/** Absolute epoch ms after which an unfired poll settles `timeout`. Omit = no timeout
|
|
246
|
-
* (then the run's own deadline is the only bound, and a run WITH a deadline refuses an
|
|
247
|
-
* unbounded poll — see `assertWaitWithinDeadline`). */
|
|
248
|
-
readonly timeoutAtMs?: number;
|
|
249
|
-
/** Opaque JSON handed to the probe on every check. Journaled with the spec, so a resumed
|
|
250
|
-
* probe gets the same arguments. */
|
|
251
|
-
readonly args?: Record<string, unknown>;
|
|
252
|
-
};
|
|
253
|
-
/** Build a `timer` spec from a DURATION. The instant is resolved once, at arm time — a resumed
|
|
254
|
-
* wait re-uses the journaled instant, never a fresh `now + ms`. */
|
|
255
|
-
declare function timerAt(ms: number, now: number): WaitSpec;
|
|
256
|
-
/** Build a bounded `poll` spec from a duration. */
|
|
257
|
-
declare function pollFor(probe: string, opts: {
|
|
258
|
-
readonly intervalMs: number;
|
|
259
|
-
readonly timeoutMs?: number;
|
|
260
|
-
readonly args?: Record<string, unknown>;
|
|
261
|
-
}, now: number): WaitSpec;
|
|
262
|
-
/**
|
|
263
|
-
* A named predicate a `poll` node re-checks. Returns true when the condition it watches has
|
|
264
|
-
* flipped. A throw is treated as "not yet" (an unreachable CI endpoint is not a settled answer),
|
|
265
|
-
* and is counted in the outcome's `probeErrors` so a probe that never works is visible rather
|
|
266
|
-
* than silently polling forever.
|
|
267
|
-
*/
|
|
268
|
-
type WaitProbe = (args: Record<string, unknown> | undefined, signal: AbortSignal) => boolean | Promise<boolean>;
|
|
269
|
-
/** Resolves a `poll` spec's `probe` name to its predicate. Threaded through `SupervisorOpts` so
|
|
270
|
-
* the SAME registry a fresh run used is what a resumed run re-resolves against. */
|
|
271
|
-
interface WaitProbeRegistry {
|
|
272
|
-
resolve(name: string): WaitProbe | undefined;
|
|
273
|
-
}
|
|
274
|
-
/** Registry over a plain name→predicate record. */
|
|
275
|
-
declare function createWaitProbes(entries: Record<string, WaitProbe>): WaitProbeRegistry;
|
|
276
|
-
/** The `out` a settled wait node delivers through `Scope.next()`. `settled` is the outcome the
|
|
277
|
-
* caller branches on: `'fired'` = the timer reached its instant or the predicate flipped;
|
|
278
|
-
* `'timeout'` = a bounded poll gave up. A timeout is a first-class ANSWER, not a failure — a
|
|
279
|
-
* wait only settles `down` when it is cancelled or aborted. */
|
|
280
|
-
interface WaitOutcome {
|
|
281
|
-
/** Tag for `isWaitOutcome` — a wait outcome arrives on the same cursor as worker outputs. */
|
|
282
|
-
readonly waitOutcome: true;
|
|
283
|
-
readonly kind: WaitSpec['kind'];
|
|
284
|
-
readonly settled: 'fired' | 'timeout';
|
|
285
|
-
readonly label: string;
|
|
286
|
-
/** The absolute instant this wait was armed for (timer `untilMs` / poll `timeoutAtMs`); absent
|
|
287
|
-
* for an unbounded poll. */
|
|
288
|
-
readonly untilMs?: number;
|
|
289
|
-
/** Epoch ms the wait was FIRST armed — preserved across a resume, so `wokenAt - armedAt` is
|
|
290
|
-
* the true end-to-end wait even when it spanned several processes. */
|
|
291
|
-
readonly armedAt: number;
|
|
292
|
-
readonly wokenAt: number;
|
|
293
|
-
/** Predicate checks performed in the process that settled it (a resume restarts this count). */
|
|
294
|
-
readonly polls: number;
|
|
295
|
-
/** Probe checks that threw (counted, not fatal). */
|
|
296
|
-
readonly probeErrors: number;
|
|
297
|
-
/** True when a later process re-armed this wait from the journal instead of creating it. */
|
|
298
|
-
readonly resumed: boolean;
|
|
299
|
-
}
|
|
300
|
-
/** Narrow a settlement's `out` to a wait outcome — a wait settles on the SAME cursor as workers,
|
|
301
|
-
* so a driver that mixes them tags them apart with this. */
|
|
302
|
-
declare function isWaitOutcome(value: unknown): value is WaitOutcome;
|
|
303
|
-
/** A wait recorded in the journal that never woke — what a resumed run re-arms. */
|
|
304
|
-
interface PendingWait {
|
|
305
|
-
readonly id: string;
|
|
306
|
-
readonly label: string;
|
|
307
|
-
readonly spec: WaitSpec;
|
|
308
|
-
/** The ORIGINAL arm instant. A re-armed wait keeps it, so its deadline never slides. */
|
|
309
|
-
readonly armedAt: number;
|
|
310
|
-
/** The wait ordinal in its parent scope, so a resumed scope continues past it. */
|
|
311
|
-
readonly ordinal: number;
|
|
312
|
-
}
|
|
313
|
-
/** Reject reasons for `Scope.wait`, mirroring `Scope.spawn`'s fail-closed admission shape. */
|
|
314
|
-
type WaitRejection = 'invalid-spec' | 'unknown-probe' | 'deadline-exceeded';
|
|
315
|
-
/** The absolute instant a spec is bounded by, or `undefined` for an unbounded poll. */
|
|
316
|
-
declare function waitUntil(spec: WaitSpec): number | undefined;
|
|
317
|
-
/** Structural validation, independent of the run. Returns null when the spec is usable. */
|
|
318
|
-
declare function validateWaitSpec(spec: WaitSpec): string | null;
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
*
|
|
322
|
-
* Recursive execution atom — the FROZEN type surface (the keystone contract).
|
|
323
|
-
*
|
|
324
|
-
* One self-similar `Agent` atom runs inside a budget-conserving reactive `Scope`,
|
|
325
|
-
* orchestrated by a `Supervisor` over an event-sourced `SpawnJournal`. A leaf is an
|
|
326
|
-
* `Agent` that never calls `scope.spawn`; a driver is an `Agent` that spawns and runs
|
|
327
|
-
* a policy over its children's streaming results.
|
|
328
|
-
*
|
|
329
|
-
* Two invariants the surface exists to make enforceable:
|
|
330
|
-
* - Budget is an atomically-reserved CONSERVED pool, so `Σk(treatment) ≡ Σk(blind)` by
|
|
331
|
-
* construction (reserve-on-spawn, refund-unspent-on-settle, fail-closed admission).
|
|
332
|
-
* - The journal records a content-addressed `outRef` per child result, so replay
|
|
333
|
-
* rehydrates the exact `Settled` the driver branched on (the replay invariant below).
|
|
334
|
-
*
|
|
335
|
-
* The leaf RUNTIME is one OPEN `Executor` interface, not a closed `inline|sandbox|cli`
|
|
336
|
-
* union the call site switches on. The built-ins (router/inline, sandbox, cli) are the
|
|
337
|
-
* initial IMPLEMENTATIONS; any user agent is first-class the moment it implements the
|
|
338
|
-
* interface. The interface IS the extension point — no per-vendor adapters live here.
|
|
339
|
-
*
|
|
340
|
-
* Layering: substrate types (`DefaultVerdict`) come from `@tangle-network/agent-eval`;
|
|
341
|
-
* runtime-shaped types (everything else) live here. Pure types/interfaces only — this
|
|
342
|
-
* module typechecks standalone and is imported by every keystone impl.
|
|
343
|
-
*
|
|
344
|
-
* @experimental
|
|
345
|
-
*/
|
|
346
|
-
|
|
347
|
-
/** Options for `Scope.wait`. `label` is the wait's identity within its parent scope — it is what
|
|
348
|
-
* a resumed run matches to re-adopt a journaled, still-unfired wait, so it must be stable across
|
|
349
|
-
* processes (a label derived from wall-clock would resume as a NEW wait). */
|
|
350
|
-
interface WaitOpts {
|
|
351
|
-
readonly label: string;
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* One self-similar atom. A leaf is an `Agent` that never calls `scope.spawn`; a driver
|
|
355
|
-
* is an `Agent` whose `act` spawns children and reacts to them via `scope.next()`. An
|
|
356
|
-
* analyst is an `Agent` whose task is "read these traces → findings" — `where` it runs
|
|
357
|
-
* is its executor, not a separate type.
|
|
358
|
-
*
|
|
359
|
-
* `act` MUST be replay-safe: it may read `verdict`, `spent`, and `out` (rehydrated by
|
|
360
|
-
* `outRef`) off each `Settled`; it MUST NOT read `Date.now`, `Math.random`, or any
|
|
361
|
-
* unordered collection. `scope.next()` delivers strictly in recorded `seq` order.
|
|
362
|
-
*/
|
|
363
|
-
interface Agent<Task, Out> {
|
|
364
|
-
readonly name: string;
|
|
365
|
-
act(task: Task, scope: Scope<Out>): Promise<Out>;
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* The leaf runtime — ONE open interface, not a closed union. `execute` returns a
|
|
369
|
-
* `Promise<ExecutorResult>` for one-shot executors OR an `AsyncIterable<UsageEvent>` for
|
|
370
|
-
* streaming ones; a streaming executor reports incremental normalized usage as it runs
|
|
371
|
-
* (the budget pool reconciles against it) and exposes its terminal artifact via
|
|
372
|
-
* `resultArtifact()`. Both shapes normalize usage to `UsageEvent` so the conserved pool
|
|
373
|
-
* meters every runtime identically.
|
|
374
|
-
*
|
|
375
|
-
* Built-in implementations (in `runtime.ts`, NOT variants here): router/inline (a direct
|
|
376
|
-
* Router/HTTP inference call, no box), sandbox (COMPOSES `runAgentRounds` as a leaf, forwarding
|
|
377
|
-
* PR #150's optional `lineage` passthrough — does NOT reinvent checkpoint/fork), cli
|
|
378
|
-
* (Halo/RLM subprocess; `budgetExempt`, excluded from equal-k by construction). A user's
|
|
379
|
-
* own agent (mastra/agno/raw HTTP/anything) is first-class by implementing this interface.
|
|
380
|
-
*/
|
|
381
|
-
interface Executor<Out> {
|
|
382
|
-
/** Stable runtime tag for traces + the equal-k exemption check. */
|
|
383
|
-
readonly runtime: Runtime;
|
|
384
|
-
/**
|
|
385
|
-
* When true, this executor's spend is NOT metered against the conserved pool and its
|
|
386
|
-
* iterations are excluded from the equal-k assertion (a `cli` subprocess without
|
|
387
|
-
* token accounting). Fail-loud everywhere else: a metered executor MUST report usage.
|
|
388
|
-
*/
|
|
389
|
-
readonly budgetExempt?: boolean;
|
|
390
|
-
/**
|
|
391
|
-
* One-shot → resolves a `ExecutorResult`; streaming → yields incremental `UsageEvent`s and
|
|
392
|
-
* the terminal artifact is read from `resultArtifact()` after the stream drains.
|
|
393
|
-
* `signal` is the spawn-scoped abort (chains the acquire lifecycle for sandbox).
|
|
394
|
-
*/
|
|
395
|
-
execute(task: unknown, signal: AbortSignal): Promise<ExecutorResult<Out>> | AsyncIterable<UsageEvent>;
|
|
396
|
-
/**
|
|
397
|
-
* Optional inbox: receive an out-of-band message from the driver mid-run (the `send`/`steer_agent`
|
|
398
|
-
* verb). A streaming executor drains pending messages between turns and folds them into the next
|
|
399
|
-
* step (a steer / interrupt / resume). A one-shot executor that can't be steered mid-flight omits
|
|
400
|
-
* this; `Scope.send` then returns `false` for it. Never throws — a malformed message is the
|
|
401
|
-
* executor's to ignore.
|
|
402
|
-
*/
|
|
403
|
-
deliver?(msg: unknown): void;
|
|
404
|
-
/**
|
|
405
|
-
* Optional LIVE progress: what this worker is doing RIGHT NOW, read synchronously and
|
|
406
|
-
* cheaply while `execute` is still streaming. The scope already derives activity timing,
|
|
407
|
-
* turns, and spend from the metered usage stream for EVERY executor; this adds only what
|
|
408
|
-
* the executor alone knows — the harness's tool/file activity, its own turn count, and how
|
|
409
|
-
* many delivered steers it has not yet folded in. Never throws; a read that cannot be
|
|
410
|
-
* answered returns `undefined`.
|
|
411
|
-
*
|
|
412
|
-
* This is the observe half of steering: `deliver` lets a driver correct a worker, and this
|
|
413
|
-
* is the evidence it corrects FROM. An executor that implements neither cannot be supervised
|
|
414
|
-
* mid-flight — it can only be waited on.
|
|
415
|
-
*/
|
|
416
|
-
progress?(): ExecutorProgress | undefined;
|
|
417
|
-
/**
|
|
418
|
-
* Optional live tool-call trace for the ONLINE detectors (`watchTrace`). An executor that
|
|
419
|
-
* can see its worker's tool calls exposes them here, so a supervisor can run the streaming
|
|
420
|
-
* repeated-action / error-streak panel over a RUNNING worker and raise a `finding` the
|
|
421
|
-
* moment it loops, instead of discovering it at settle. Omitted = no online detection for
|
|
422
|
-
* this runtime (the settle-time analyzers still work).
|
|
423
|
-
*/
|
|
424
|
-
traceSource?(): TraceSource | undefined;
|
|
425
|
-
/**
|
|
426
|
-
* Tear the executor's resources down. `grace` mirrors the OTP shutdown spec
|
|
427
|
-
* (`'brutalKill'` = immediate, a number = ms grace, `'infinity'` = await clean exit).
|
|
428
|
-
*/
|
|
429
|
-
teardown(grace: number | 'brutalKill' | 'infinity'): Promise<{
|
|
430
|
-
destroyed: boolean;
|
|
431
|
-
}>;
|
|
432
|
-
/**
|
|
433
|
-
* The replay source (B1): the content-addressed `outRef` + the materialized output the
|
|
434
|
-
* driver branched on, its verdict, and the conserved spend. Read once, after settle.
|
|
435
|
-
*/
|
|
436
|
-
resultArtifact(): {
|
|
437
|
-
outRef: string;
|
|
438
|
-
out: Out;
|
|
439
|
-
verdict?: DefaultVerdict;
|
|
440
|
-
spent: Spend;
|
|
441
|
-
};
|
|
442
|
-
/**
|
|
443
|
-
* A driver-executor's OWN-inference subtree total (rolled up from its nested tree's `metered`
|
|
444
|
-
* events) — the parent scope journals it as a `metered` event for this node on settle, on BOTH
|
|
445
|
-
* the done AND the down/crash paths, so a crashed sub-driver's partial inference still re-homes
|
|
446
|
-
* (the pool already debited it via `observe`; the journal must match). NOT reconciled, so it never
|
|
447
|
-
* trips the reservation clamp. Read on settle, valid after `execute` resolves OR throws. Leaf
|
|
448
|
-
* executors omit it (returns `undefined`).
|
|
449
|
-
*/
|
|
450
|
-
metered?(): Spend | undefined;
|
|
451
|
-
}
|
|
452
|
-
/** Terminal artifact of a one-shot `Executor.execute`. */
|
|
453
|
-
interface ExecutorResult<Out> {
|
|
454
|
-
outRef: string;
|
|
455
|
-
out: Out;
|
|
456
|
-
verdict?: DefaultVerdict;
|
|
457
|
-
spent: Spend;
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* Normalized usage event — the single channel every executor reports through, so the
|
|
461
|
-
* conserved pool meters all runtimes identically. `tokens` carries `LoopTokenUsage`'s
|
|
462
|
-
* `{ input, output }`; `usd` is a SEPARATE channel (never folded into tokens).
|
|
463
|
-
*/
|
|
464
|
-
type UsageEvent = {
|
|
465
|
-
kind: 'tokens';
|
|
466
|
-
input: number;
|
|
467
|
-
output: number;
|
|
468
|
-
} | {
|
|
469
|
-
kind: 'cost';
|
|
470
|
-
usd: number;
|
|
471
|
-
} | {
|
|
472
|
-
kind: 'iteration';
|
|
473
|
-
};
|
|
474
|
-
/** The runtime tag of a `Executor` impl. Open by intent: custom runtimes use their own string name.
|
|
475
|
-
* External executors can register additional runtime strings without widening this type. */
|
|
476
|
-
type Runtime = 'router' | 'inline' | 'sandbox' | 'cli' | (string & {});
|
|
477
|
-
/**
|
|
478
|
-
* `AgentProfile` does NOT carry a `harness`/backend field — `harness` lives on the
|
|
479
|
-
* sandbox SDK's `BackendConfig`, not the portable profile. So an agent is mapped to its
|
|
480
|
-
* executor through this MINIMAL wrapper, never by fabricating a field onto `AgentProfile`.
|
|
481
|
-
*
|
|
482
|
-
* Resolution (in `runtime.ts`):
|
|
483
|
-
* - `executor` present → BYO: use it verbatim (a user's own `Executor`).
|
|
484
|
-
* - `harness === null` → router/inline: a direct Router call, no box.
|
|
485
|
-
* - `harness` is a `BackendType` → sandbox: compose `runAgentRounds` against `profile` on that backend.
|
|
486
|
-
* Fail loud on an unresolvable spec (no executor and an unknown harness).
|
|
487
|
-
*/
|
|
488
|
-
interface AgentSpec {
|
|
489
|
-
readonly profile: AgentProfile;
|
|
490
|
-
/** `null` selects router/inline; a `BackendType` selects the sandboxed harness. */
|
|
491
|
-
readonly harness: BackendType | null;
|
|
492
|
-
/** Bring-your-own executor: when set, overrides harness-based resolution entirely. */
|
|
493
|
-
readonly executor?: Executor<unknown>;
|
|
494
|
-
}
|
|
495
|
-
/**
|
|
496
|
-
* Builds a fresh `Executor` for one spawn from the resolved spec. Per-spawn (not
|
|
497
|
-
* shared) so each child owns its own box/abort/teardown lifecycle. A BYO factory lets a
|
|
498
|
-
* user supply construction args without pre-instantiating.
|
|
499
|
-
*/
|
|
500
|
-
type ExecutorFactory<Out> = (spec: AgentSpec, ctx: ExecutorContext) => Executor<Out>;
|
|
501
|
-
/** Construction context handed to a `ExecutorFactory` — the seams a built-in needs
|
|
502
|
-
* (sandbox client for the sandbox executor, router config for router/inline) without
|
|
503
|
-
* the factory reaching into module globals. */
|
|
504
|
-
interface ExecutorContext {
|
|
505
|
-
readonly signal: AbortSignal;
|
|
506
|
-
/** Opaque seams the registry threads through; a built-in narrows what it needs. */
|
|
507
|
-
readonly seams: Readonly<Record<string, unknown>>;
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* The OPEN resolver: maps an `AgentSpec` to a `ExecutorFactory`. The default
|
|
511
|
-
* registry resolves the three built-ins AND accepts a BYO `executor`/factory; callers
|
|
512
|
-
* register more runtimes by name. NOT a closed switch — registration is the extension
|
|
513
|
-
* point, mirroring the open `Executor` interface.
|
|
514
|
-
*/
|
|
515
|
-
interface ExecutorRegistry {
|
|
516
|
-
/** Register a factory for a named runtime. Throws on a duplicate name (fail loud). */
|
|
517
|
-
register<Out>(runtime: Runtime, factory: ExecutorFactory<Out>): void;
|
|
518
|
-
/**
|
|
519
|
-
* Resolve a spec to a factory. Precedence: a BYO `spec.executor` → a trivial factory
|
|
520
|
-
* returning it; else `harness === null` → the `'router'` factory; else a registered
|
|
521
|
-
* factory for the harness-derived runtime. Returns a typed outcome — the caller
|
|
522
|
-
* inspects `succeeded` before `value` (no silent fallback).
|
|
523
|
-
*/
|
|
524
|
-
resolve<Out>(spec: AgentSpec): {
|
|
525
|
-
succeeded: true;
|
|
526
|
-
value: ExecutorFactory<Out>;
|
|
527
|
-
} | {
|
|
528
|
-
succeeded: false;
|
|
529
|
-
error: string;
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
/** A budget envelope on a spawn or the root. All ceilings; the pool reserves against them. */
|
|
533
|
-
interface Budget {
|
|
534
|
-
readonly maxIterations: number;
|
|
535
|
-
readonly maxTokens: number;
|
|
536
|
-
readonly maxUsd?: number;
|
|
537
|
-
readonly deadlineMs?: number;
|
|
538
|
-
}
|
|
539
|
-
/** Conserved spend, reconciled from the normalized `UsageEvent` stream. Tokens and usd
|
|
540
|
-
* are separate channels (never folded). */
|
|
541
|
-
interface Spend {
|
|
542
|
-
iterations: number;
|
|
543
|
-
tokens: LoopTokenUsage;
|
|
544
|
-
/** Dollar accounting is known unless explicitly false. A false value must not be treated as $0
|
|
545
|
-
* when enforcing a dollar-denominated comparison or limit. */
|
|
546
|
-
usdKnown?: boolean;
|
|
547
|
-
usd: number;
|
|
548
|
-
ms: number;
|
|
549
|
-
}
|
|
550
|
-
/** OTP child-spec restart class. */
|
|
551
|
-
type Restart = 'temporary' | 'transient' | 'permanent';
|
|
552
|
-
/** `'acquiring'` is first-class (M1): a node spends real time + reaps an orphan box
|
|
553
|
-
* during sandbox acquire BEFORE it is `running`, so abort must be defined over it.
|
|
554
|
-
* `'waiting'` is first-class for the opposite reason: a wait-state node holds NO executor, NO
|
|
555
|
-
* box, and no conserved budget — it is neither in flight nor settled, so neither `inFlight` nor
|
|
556
|
-
* a terminal status describes it (see `Scope.wait`). */
|
|
557
|
-
type NodeStatus = 'pending' | 'acquiring' | 'running' | 'waiting' | 'done' | 'failed' | 'cancelled';
|
|
558
|
-
/** Deterministic node id — `${parent}:s${seq}` from the cursor order, never wall-clock. */
|
|
559
|
-
type NodeId = string;
|
|
560
|
-
interface SpawnOpts {
|
|
561
|
-
readonly budget: Budget;
|
|
562
|
-
readonly label: string;
|
|
563
|
-
readonly restart?: Restart;
|
|
564
|
-
/** Teardown grace handed to the executor when this node is reaped. */
|
|
565
|
-
readonly shutdown?: number | 'brutalKill' | 'infinity';
|
|
566
|
-
}
|
|
567
|
-
/**
|
|
568
|
-
* A live child handle. `abort()` is defined over the ACQUIRE lifecycle: it chains into
|
|
569
|
-
* the `acquireSandbox` signal and reaps a find-by-name orphan box, so a node aborted
|
|
570
|
-
* mid-acquire never leaks (M1).
|
|
571
|
-
*/
|
|
572
|
-
interface Handle<Out> {
|
|
573
|
-
readonly id: NodeId;
|
|
574
|
-
readonly label: string;
|
|
575
|
-
readonly status: NodeStatus;
|
|
576
|
-
abort(reason?: string): void;
|
|
577
|
-
/** Phantom: binds the handle to the child's output type so `spawn<C>` returns a
|
|
578
|
-
* `Handle<C>` distinct from a `Handle<other>`. Type-only — never present at runtime. */
|
|
579
|
-
readonly __out?: Out;
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* A settled child, delivered by `scope.next()`. `seq` is the monotonic cursor order
|
|
583
|
-
* `next()` yielded this settlement (B2) — NOT wall-clock — and replay delivers strictly
|
|
584
|
-
* in `seq` order. `outRef` rehydrates `out` from the `ResultBlobStore` on replay.
|
|
585
|
-
*/
|
|
586
|
-
type Settled<Out> = {
|
|
587
|
-
kind: 'done';
|
|
588
|
-
handle: Handle<Out>;
|
|
589
|
-
out: Out;
|
|
590
|
-
outRef: string;
|
|
591
|
-
verdict?: DefaultVerdict;
|
|
592
|
-
spent: Spend;
|
|
593
|
-
seq: number;
|
|
594
|
-
} | {
|
|
595
|
-
kind: 'down';
|
|
596
|
-
handle: Handle<Out>;
|
|
597
|
-
reason: string;
|
|
598
|
-
/** True = infrastructure failure (excluded from merge `n` / equal-k), not a bad result. */
|
|
599
|
-
infra: boolean;
|
|
600
|
-
restartCount: number;
|
|
601
|
-
seq: number;
|
|
602
|
-
};
|
|
603
|
-
/**
|
|
604
|
-
* The budget-conserving reactive scope an `Agent.act` runs inside. `spawn` reserves
|
|
605
|
-
* budget atomically from the shared pool and fails closed when the pool cannot cover it.
|
|
606
|
-
* `next()` waits for one settlement from this scope's live set; `view` reads live state,
|
|
607
|
-
* not the replay log.
|
|
608
|
-
*/
|
|
609
|
-
interface Scope<Out> {
|
|
610
|
-
/**
|
|
611
|
-
* Spawn a child. Reserves `opts.budget` from the conserved pool atomically; refunds the
|
|
612
|
-
* unspent remainder on settle. Returns a typed outcome — fail-closed on an exhausted
|
|
613
|
-
* pool or an exceeded depth ceiling (the caller inspects `ok` before `handle`).
|
|
614
|
-
*/
|
|
615
|
-
spawn<C extends Out>(agent: Agent<unknown, C>, task: unknown, opts: SpawnOpts): {
|
|
616
|
-
ok: true;
|
|
617
|
-
handle: Handle<C>;
|
|
618
|
-
} | {
|
|
619
|
-
ok: false;
|
|
620
|
-
reason: 'budget-exhausted' | 'depth-exceeded';
|
|
621
|
-
};
|
|
622
|
-
/** ray.wait n=1 over this scope's in-memory live set; resolves as each child settles;
|
|
623
|
-
* `null` when the live set is empty. */
|
|
624
|
-
next(): Promise<Settled<Out> | null>;
|
|
625
|
-
/**
|
|
626
|
-
* Non-blocking twin of `next()`: deliver an ALREADY-settled, undelivered child, or `null`
|
|
627
|
-
* when none is ready — never awaits a live child. The driver's post-loop drain reads this so
|
|
628
|
-
* a child that settled while the driver was busy (or after it stopped pulling) still reaches
|
|
629
|
-
* the finalize ledger instead of being silently lost.
|
|
630
|
-
*/
|
|
631
|
-
nextResolved(): Promise<Settled<Out> | null>;
|
|
632
|
-
/**
|
|
633
|
-
* Steer a RUNNING child out-of-band — deliver a message to its executor's inbox (the driver's
|
|
634
|
-
* `send` verb: next-instruction, interrupt, or resume). Returns `true` if the message was
|
|
635
|
-
* delivered to a live child whose executor accepts delivery, `false` otherwise (unknown id,
|
|
636
|
-
* already settled, or an executor with no inbox). The executor drains its inbox between turns;
|
|
637
|
-
* a leaf that does not implement `deliver` simply cannot be steered mid-flight. In-process this
|
|
638
|
-
* is a direct call; the sandbox/Agent-Bus transports surface the SAME verb as an MCP tool.
|
|
639
|
-
*/
|
|
640
|
-
send(nodeId: NodeId, msg: unknown): boolean;
|
|
641
|
-
/**
|
|
642
|
-
* Arm a WAIT-STATE node: a first-class tree node that waits on wall-clock time (`timer`) or on
|
|
643
|
-
* a named external predicate (`poll`) and settles through THIS scope's `next()` cursor like any
|
|
644
|
-
* other child — but holds no executor, no sandbox, and no conserved budget. Waiting costs zero
|
|
645
|
-
* tokens and zero dollars by construction.
|
|
646
|
-
*
|
|
647
|
-
* It is journaled (`waiting` → `woken`) with its ABSOLUTE deadline, so a run that dies mid-wait
|
|
648
|
-
* resumes still waiting: the supervisor surfaces the un-woken waits on `Scope.resume.waits`, and
|
|
649
|
-
* re-arming the same `label` adopts the recorded node id and original instant instead of
|
|
650
|
-
* restarting the countdown.
|
|
651
|
-
*
|
|
652
|
-
* Fail-closed admission, mirroring `spawn`: `invalid-spec`, `unknown-probe` (a `poll` naming a
|
|
653
|
-
* predicate this run's registry cannot resolve), or `deadline-exceeded` (the wait would outlive
|
|
654
|
-
* the pool's hard wall-clock ceiling — a wait never extends a budget guard).
|
|
655
|
-
*
|
|
656
|
-
* NOT `await_event`: that is an in-run rendezvous on the coordination bus whose 15s fence makes
|
|
657
|
-
* the caller re-poll — each re-poll a driver inference turn against a process that must stay up,
|
|
658
|
-
* and nothing about it survives a restart. See `supervise/wait.ts`.
|
|
659
|
-
*/
|
|
660
|
-
wait(spec: WaitSpec, opts: WaitOpts): {
|
|
661
|
-
ok: true;
|
|
662
|
-
handle: Handle<WaitOutcome>;
|
|
663
|
-
} | {
|
|
664
|
-
ok: false;
|
|
665
|
-
reason: WaitRejection;
|
|
666
|
-
};
|
|
667
|
-
/**
|
|
668
|
-
* The LIVE read-model of one child, valid WHILE it runs: last-activity timestamp, idle time,
|
|
669
|
-
* a derived `stalled` flag, tokens/turns spent so far, whether a steer can even reach it
|
|
670
|
-
* (`steerable`), and whatever tool activity its executor exposes. `undefined` for an unknown
|
|
671
|
-
* id. This is the counterpart to `send`: a driver that can steer but cannot observe has
|
|
672
|
-
* nothing to steer on, which is precisely why steering went unused.
|
|
673
|
-
*
|
|
674
|
-
* Pull-based and side-effect free — reading it starts no timer and spends nothing. `now` and
|
|
675
|
-
* `stallAfterMs` are injectable so a caller (and a test) controls what counts as stalled.
|
|
676
|
-
*/
|
|
677
|
-
progress(nodeId: NodeId, opts?: {
|
|
678
|
-
now?: number;
|
|
679
|
-
stallAfterMs?: number;
|
|
680
|
-
}): WorkerProgress | undefined;
|
|
681
|
-
/** The live tool-call trace of one child when its executor exposes one (`Executor.traceSource`),
|
|
682
|
-
* for running the online detector panel over a RUNNING worker. `undefined` otherwise. */
|
|
683
|
-
traceSource(nodeId: NodeId): TraceSource | undefined;
|
|
684
|
-
/** This scope's abort signal — aborted when the run is cancelled, a breaker trips, the pool
|
|
685
|
-
* is exhausted, or a parent scope cascades. A long-running driver `act` over this scope reads
|
|
686
|
-
* it to break promptly (the conserved pool + driver-stop are the other bounds). A nested
|
|
687
|
-
* scope carries its own signal, chained off its driver child's abort. */
|
|
688
|
-
readonly signal: AbortSignal;
|
|
689
|
-
/**
|
|
690
|
-
* Meter the driver's OWN compute against the conserved pool — its inference turns, which are
|
|
691
|
-
* real tokens/usd but not a spawned child (no reserve/reconcile). A direct `free → committed`
|
|
692
|
-
* debit, so equal-k counts the driver's tokens AND the in-loop budget guard (`budget.tokensLeft`)
|
|
693
|
-
* halts a driver that thinks the pool dry. `detail` rides an `agent.turn` trace event for live
|
|
694
|
-
* observability (turn index, tool calls, cumulative spend). It also journals a `metered` event —
|
|
695
|
-
* the durable twin of the pool debit (as `settled` is the twin of `reconcile`) — so every
|
|
696
|
-
* journal-based cost reader (`spentFromJournal`, `trajectoryReport`) sums driver inference
|
|
697
|
-
* automatically. A leaf never calls this; a driver meters each chat turn and awaits it (the
|
|
698
|
-
* metered event is cost-critical, so it lands before the join-barrier roll-up).
|
|
699
|
-
*/
|
|
700
|
-
meter(spend: Spend, detail?: Record<string, unknown>): Promise<void>;
|
|
701
|
-
/**
|
|
702
|
-
* Prior committed work, present ONLY on a resumed run (`undefined` on a fresh run, which is
|
|
703
|
-
* every run that did not pass `SupervisorOpts.resume`). The supervisor `loadTree`s the journal
|
|
704
|
-
* first; when a non-empty tree exists it rehydrates the already-settled children (via
|
|
705
|
-
* `replaySpawnTree`) and hands them here so a resume-aware `act` re-uses them instead of
|
|
706
|
-
* re-spawning committed work. A resume-blind driver simply ignores it and re-spawns — correct
|
|
707
|
-
* but redundant. The scope's spawn ordinal + cursor seq are already advanced past the recorded
|
|
708
|
-
* maxima, so any NEW spawn appends without colliding with a journaled event.
|
|
709
|
-
*/
|
|
710
|
-
readonly resume?: ResumedWork<Out>;
|
|
711
|
-
/** The live tree — reads the in-memory nursery, not the journal. */
|
|
712
|
-
readonly view: TreeView;
|
|
713
|
-
/** Conserved-pool readouts (post-reservation). */
|
|
714
|
-
readonly budget: Readonly<{
|
|
715
|
-
tokensLeft: number;
|
|
716
|
-
usdLeft: number;
|
|
717
|
-
usdCapped: boolean;
|
|
718
|
-
deadlineMs: number;
|
|
719
|
-
reservedTokens: number;
|
|
720
|
-
}>;
|
|
721
|
-
}
|
|
722
|
-
/**
|
|
723
|
-
* The committed work a resumed run inherits from its journal. `settled` is the replayed
|
|
724
|
-
* `Settled[]` (cursor-ordered, rehydrated from the blob store by `replaySpawnTree`); `view`
|
|
725
|
-
* is the tree as `materializeTreeView` folded it at the recorded cursor position. A
|
|
726
|
-
* resume-aware `act` reads `scope.resume?.settled` to pick up where the crashed run left off.
|
|
727
|
-
*/
|
|
728
|
-
interface ResumedWork<Out> {
|
|
729
|
-
readonly settled: ReadonlyArray<Settled<Out>>;
|
|
730
|
-
readonly view: TreeView;
|
|
731
|
-
/**
|
|
732
|
-
* Wait-state nodes the journal shows as ARMED but never woken — the run died mid-wait. Each
|
|
733
|
-
* carries the ORIGINAL arm instant and absolute deadline, so re-arming the same `label` through
|
|
734
|
-
* `Scope.wait` resumes the countdown instead of restarting it. Empty on a fresh run and on a
|
|
735
|
-
* resumed run that was not waiting.
|
|
736
|
-
*/
|
|
737
|
-
readonly waits: ReadonlyArray<PendingWait>;
|
|
738
|
-
}
|
|
739
|
-
interface NodeSnapshot {
|
|
740
|
-
readonly id: NodeId;
|
|
741
|
-
readonly parent?: NodeId;
|
|
742
|
-
readonly label: string;
|
|
743
|
-
readonly status: NodeStatus;
|
|
744
|
-
readonly runtime: Runtime;
|
|
745
|
-
readonly budget: Budget;
|
|
746
|
-
/** Conserved spend so far for this node. */
|
|
747
|
-
readonly spent: Spend;
|
|
748
|
-
/** `outRef` once the node is `done` (the replay/result pointer). */
|
|
749
|
-
readonly outRef?: string;
|
|
750
|
-
}
|
|
751
|
-
/** The live tree — what `scope.view` / `RootHandle.view()` materialize for a viewer. */
|
|
752
|
-
interface TreeView {
|
|
753
|
-
readonly root: NodeId;
|
|
754
|
-
readonly nodes: ReadonlyArray<NodeSnapshot>;
|
|
755
|
-
/** Count of nodes in `running` or `acquiring` — the "what's in flow?" answer. */
|
|
756
|
-
readonly inFlight: number;
|
|
757
|
-
/** Count of nodes in `waiting` — armed wait-states. Deliberately NOT folded into `inFlight`:
|
|
758
|
-
* a wait burns no executor and no budget, so counting it as flow would misreport both idle
|
|
759
|
-
* capacity and how much work is actually running. */
|
|
760
|
-
readonly waiting: number;
|
|
761
|
-
}
|
|
762
|
-
/** Journaled spawn-tree events (B1/B2). `seq` is the cursor order; `at` is an ISO
|
|
763
|
-
* timestamp for human inspection only (NOT a replay input). */
|
|
764
|
-
type SpawnEvent = {
|
|
765
|
-
kind: 'spawned';
|
|
766
|
-
id: NodeId;
|
|
767
|
-
parent?: NodeId;
|
|
768
|
-
label: string;
|
|
769
|
-
budget: Budget;
|
|
770
|
-
runtime: Runtime;
|
|
771
|
-
seq: number;
|
|
772
|
-
at: string;
|
|
773
|
-
} | {
|
|
774
|
-
kind: 'settled';
|
|
775
|
-
id: NodeId;
|
|
776
|
-
status: 'done' | 'down';
|
|
777
|
-
/** Content-addressed result pointer; rehydrates `out` from `ResultBlobStore`. */
|
|
778
|
-
outRef?: string;
|
|
779
|
-
verdict?: DefaultVerdict;
|
|
780
|
-
spent: Spend;
|
|
781
|
-
infra?: boolean;
|
|
782
|
-
seq: number;
|
|
783
|
-
at: string;
|
|
784
|
-
} | {
|
|
785
|
-
kind: 'cancelled';
|
|
786
|
-
id: NodeId;
|
|
787
|
-
reason: string;
|
|
788
|
-
seq: number;
|
|
789
|
-
at: string;
|
|
790
|
-
} | {
|
|
791
|
-
/** A wait-state node was ARMED. Lives in the SPAWN-ORDINAL namespace (`seq` is the wait
|
|
792
|
-
* ordinal within its parent scope), exactly like `spawned` — it creates a node, it does not
|
|
793
|
-
* settle one. It carries the whole `spec` and the original `armedAt` so a brand-new process
|
|
794
|
-
* re-arms the identical wait with the identical ABSOLUTE deadline. */
|
|
795
|
-
kind: 'waiting';
|
|
796
|
-
id: NodeId;
|
|
797
|
-
parent?: NodeId;
|
|
798
|
-
label: string;
|
|
799
|
-
spec: WaitSpec;
|
|
800
|
-
armedAt: number;
|
|
801
|
-
seq: number;
|
|
802
|
-
at: string;
|
|
803
|
-
} | {
|
|
804
|
-
/** A wait-state node SETTLED — the cursor-namespace twin of `settled`, kept distinct so a
|
|
805
|
-
* reader can tell zero-cost waiting apart from paid work without inspecting payloads. A
|
|
806
|
-
* wait carries no `spent` (it is free by construction, not by measurement); `outRef`
|
|
807
|
-
* rehydrates its `WaitOutcome`, absent when the wait was cancelled. */
|
|
808
|
-
kind: 'woken';
|
|
809
|
-
id: NodeId;
|
|
810
|
-
by: 'fired' | 'timeout' | 'cancelled';
|
|
811
|
-
outRef?: string;
|
|
812
|
-
seq: number;
|
|
813
|
-
at: string;
|
|
814
|
-
} | {
|
|
815
|
-
/** A driver's OWN inference spend, journaled separately from spawned-child work — the journal
|
|
816
|
-
* TWIN of `BudgetPool.observe`, exactly as `settled` is the twin of `reconcile`. So every
|
|
817
|
-
* journal-based cost reader sums it automatically — the journal is the single cost ledger.
|
|
818
|
-
* It carries spend only and is NOT a settlement: replay + `materializeTreeView` skip it for
|
|
819
|
-
* structure, and its `seq` lives outside the cursor-uniqueness namespace. A
|
|
820
|
-
* driver re-homes its nested subtree's metered total up to its parent (like settled spend),
|
|
821
|
-
* so summing any sub-tree root yields that sub-tree's true driver-inference cost. */
|
|
822
|
-
kind: 'metered';
|
|
823
|
-
id: NodeId;
|
|
824
|
-
spend: Spend;
|
|
825
|
-
seq: number;
|
|
826
|
-
at: string;
|
|
827
|
-
};
|
|
828
|
-
/**
|
|
829
|
-
* The spawn-tree event source (mirrors `ConversationJournal`'s begin/append/load shape).
|
|
830
|
-
* `loadTree` returns events for inspection and completed-settlement replay, not live process
|
|
831
|
-
* recovery; `appendEvent` runs only AFTER the event is observed-committed (never speculative).
|
|
832
|
-
*/
|
|
833
|
-
interface SpawnJournal {
|
|
834
|
-
loadTree(root: NodeId): Promise<SpawnEvent[] | undefined>;
|
|
835
|
-
beginTree(root: NodeId, at: string): Promise<void>;
|
|
836
|
-
appendEvent(root: NodeId, ev: SpawnEvent): Promise<void>;
|
|
837
|
-
}
|
|
838
|
-
/** Content-addressed result blobs (the `outRef` → artifact map) backing the replay
|
|
839
|
-
* invariant. Split from the journal so the journal stays small (decisions) and the
|
|
840
|
-
* payloads (evidence) live where a viewer/replayer rehydrates them. */
|
|
841
|
-
interface ResultBlobStore {
|
|
842
|
-
put(outRef: string, artifact: unknown): Promise<void>;
|
|
843
|
-
get(outRef: string): Promise<unknown | undefined>;
|
|
844
|
-
}
|
|
845
|
-
/**
|
|
846
|
-
* Owns the conserved pool, the spawn log, the abort cascade, the OTP intensity breaker,
|
|
847
|
-
* and the root handle. `run` executes the root `Agent` to completion; `attach` wires a
|
|
848
|
-
* live `RootHandle` (the Q2 substrate the chat/pi-viz client later consumes).
|
|
849
|
-
*/
|
|
850
|
-
interface Supervisor<Task, Out> {
|
|
851
|
-
run(root: Agent<Task, Out>, task: Task, opts: SupervisorOpts): Promise<SupervisedResult<Out>>;
|
|
852
|
-
attach(h: RootHandle<Out>): void;
|
|
853
|
-
}
|
|
854
|
-
interface SupervisorOpts {
|
|
855
|
-
/** The root conserved-pool ceiling (tokens + usd + iterations + deadline). */
|
|
856
|
-
readonly budget: Budget;
|
|
857
|
-
/** Trace-correlation root + the journal/blob root key. */
|
|
858
|
-
readonly runId: NodeId;
|
|
859
|
-
/** Event source — defaults to the in-memory journal in the impl; pass JSONL/FS for durability. */
|
|
860
|
-
readonly journal: SpawnJournal;
|
|
861
|
-
/** Result payload store backing `outRef` rehydration. */
|
|
862
|
-
readonly blobs: ResultBlobStore;
|
|
863
|
-
/** Executor resolution — the open registry mapping `AgentSpec` → `Executor`. */
|
|
864
|
-
readonly executors: ExecutorRegistry;
|
|
865
|
-
/** Predicate resolution for `poll` wait-states (`Scope.wait`). A `poll` names its predicate so
|
|
866
|
-
* the wait can be journaled and re-armed by a later process; this is what the name resolves
|
|
867
|
-
* against. Unset ⇒ `poll` waits are refused (`unknown-probe`); `timer` waits are unaffected. */
|
|
868
|
-
readonly probes?: WaitProbeRegistry;
|
|
869
|
-
/** Runtime recursion-depth ceiling (paired with the conserved pool per R3). */
|
|
870
|
-
readonly maxDepth?: number;
|
|
871
|
-
/**
|
|
872
|
-
* OTP intensity breaker: more than `maxRestarts` child restarts within `withinMs`
|
|
873
|
-
* trips the supervisor to `no-winner` rather than restarting forever.
|
|
874
|
-
*/
|
|
875
|
-
readonly maxRestarts?: number;
|
|
876
|
-
readonly withinMs?: number;
|
|
877
|
-
/**
|
|
878
|
-
* Opt into RESUME-FIRST: read any prior journal tree for this `runId` BEFORE beginning a fresh
|
|
879
|
-
* one, and when a non-empty tree exists rehydrate its committed work onto `Scope.resume`
|
|
880
|
-
* (`replaySpawnTree` + `materializeTreeView`) instead of starting over. Requires a journal +
|
|
881
|
-
* blob store that OUTLIVE the process (`createFileRunContext(dir)`); against the in-memory
|
|
882
|
-
* stores there is never a prior tree, so it is a no-op.
|
|
883
|
-
*
|
|
884
|
-
* Default `false` — a run always begins a fresh tree, which is the behavior every existing
|
|
885
|
-
* consumer has. Resume is a durability contract the caller opts into, never a silent default.
|
|
886
|
-
*/
|
|
887
|
-
readonly resume?: boolean;
|
|
888
|
-
readonly now?: () => number;
|
|
889
|
-
readonly signal?: AbortSignal;
|
|
890
|
-
/** Lifecycle stream sink, threaded into the root `Scope` so every `spawn`/settle emits on the
|
|
891
|
-
* same `agent.spawn`/`agent.child` stream `runAgentRounds` feeds — one observable recursive tree. */
|
|
892
|
-
readonly hooks?: RuntimeHooks;
|
|
893
|
-
}
|
|
894
|
-
/** Typed terminal result (M2) — a no-winner is NEVER coerced to a best-effort output. */
|
|
895
|
-
type SupervisedResult<Out> = {
|
|
896
|
-
kind: 'winner';
|
|
897
|
-
out: Out;
|
|
898
|
-
outRef: string;
|
|
899
|
-
verdict?: DefaultVerdict;
|
|
900
|
-
tree: TreeView;
|
|
901
|
-
spentTotal: Spend;
|
|
902
|
-
/** Where `spentTotal` went: `driverInference` = the drivers' own chat turns (metered via
|
|
903
|
-
* `Scope.meter`); `childWork` = every spawned child's reconciled spend (the journal sum).
|
|
904
|
-
* `driverInference + childWork === spentTotal`. Present whenever any driver metered. */
|
|
905
|
-
spentBreakdown?: {
|
|
906
|
-
driverInference: Spend;
|
|
907
|
-
childWork: Spend;
|
|
908
|
-
};
|
|
909
|
-
} | {
|
|
910
|
-
kind: 'no-winner';
|
|
911
|
-
reason: 'all-children-down' | 'budget-exhausted' | 'aborted';
|
|
912
|
-
tree: TreeView;
|
|
913
|
-
downCount: number;
|
|
914
|
-
/** The conserved spend incurred before the run failed — real cost is paid even when no
|
|
915
|
-
* worker delivers, so the caller always learns what the delegation actually spent. Summed
|
|
916
|
-
* off the same journal the `winner` path reads. */
|
|
917
|
-
spentTotal: Spend;
|
|
918
|
-
};
|
|
919
|
-
/** Live root handle — the substrate a chat/pi-viz client attaches to (Q2). `signal`
|
|
920
|
-
* delivers an out-of-band message to the running root; `view()` materializes the tree. */
|
|
921
|
-
interface RootHandle<Out> {
|
|
922
|
-
view(): TreeView;
|
|
923
|
-
signal(msg: RootSignal): void;
|
|
924
|
-
abort(reason?: string): void;
|
|
925
|
-
/** Phantom: binds the handle to the supervised run's output type. Type-only — never
|
|
926
|
-
* present at runtime; lets `attach(h: RootHandle<Out>)` stay output-typed. */
|
|
927
|
-
readonly __out?: Out;
|
|
928
|
-
}
|
|
929
|
-
/** Out-of-band message to a running root. Open by intent — a client extends it. */
|
|
930
|
-
type RootSignal = {
|
|
931
|
-
kind: 'pause';
|
|
932
|
-
} | {
|
|
933
|
-
kind: 'resume';
|
|
934
|
-
} | {
|
|
935
|
-
kind: 'cancel';
|
|
936
|
-
reason?: string;
|
|
937
|
-
} | {
|
|
938
|
-
kind: 'ask';
|
|
939
|
-
question: string;
|
|
940
|
-
};
|
|
941
|
-
/**
|
|
942
|
-
* The progressive-widening gate (MCTS-PW). Decides whether a settled child is
|
|
943
|
-
* `promising` enough to spawn another under the remaining pool. DEFAULTS TO FLAT
|
|
944
|
-
* (`shouldWiden` always false) so a gate run never widens and the selector≠judge
|
|
945
|
-
* firewall conflict (R2) stays dormant. When widening IS enabled, `promising` MUST be
|
|
946
|
-
* derived from TRACE findings (`analyses`), never raw `verdict` — or the gate carries
|
|
947
|
-
* an explicit, argued `judgeExempt: true` (the documented escape hatch, off by default).
|
|
948
|
-
*/
|
|
949
|
-
interface WidenGate<Out> {
|
|
950
|
-
/** Default impl returns false for every settlement (flat — never widens). */
|
|
951
|
-
shouldWiden(settled: Settled<Out>, budget: Scope<Out>['budget']): boolean;
|
|
952
|
-
/** When true, widening may read `verdict` directly (collides with the steer firewall —
|
|
953
|
-
* must be explicitly argued per cell, never defaulted on). */
|
|
954
|
-
readonly judgeExempt?: boolean;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
export { type Agent as A, type Budget as B, type WaitSpec as C, DEFAULT_STALL_AFTER_MS as D, type ExecutorFactory as E, type WidenGate as F, createActivityLog as G, createPushTraceSource as H, createWaitProbes as I, decodeToolPart as J, isWaitOutcome as K, pollFor as L, readWorkerProgress as M, type NodeId as N, sandboxSessionTraceSource as O, type PendingWait as P, timerAt as Q, type Runtime as R, type Scope as S, type TraceSource as T, type UsageEvent as U, validateWaitSpec as V, type WorkerProgress as W, waitUntil as X, type Settled as a, type ResultBlobStore as b, type SpawnJournal as c, type WaitProbeRegistry as d, type SupervisedResult as e, type Executor as f, type Spend as g, type AgentSpec as h, type ExecutorRegistry as i, type RootHandle as j, type ExecutorProgress as k, type SpawnEvent as l, type TreeView as m, type SpawnOpts as n, type Supervisor as o, type ActivityLog as p, type ActivityNote as q, type ExecutorContext as r, type ExecutorResult as s, type ResumedWork as t, type ScopeProgressInput as u, type SessionTraceBox as v, type SupervisorOpts as w, type WaitOutcome as x, type WaitProbe as y, type WaitRejection as z };
|