@tangle-network/agent-runtime 0.300.0 → 0.306.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/dist/{activation-DqWmWTyB.js → activation-C5wesfzd.js} +3 -3
- package/dist/{activation-DqWmWTyB.js.map → activation-C5wesfzd.js.map} +1 -1
- package/dist/{activation-Bhp8dYV5.d.ts → activation-wZ-8vOjV.d.ts} +88 -13
- package/dist/agent.d.ts +2 -2
- package/dist/agent.js +2 -2
- package/dist/{bundle-C9v5TH_H.js → bundle-C8EO05u3.js} +2 -2
- package/dist/{bundle-C9v5TH_H.js.map → bundle-C8EO05u3.js.map} +1 -1
- package/dist/candidate-execution/index.d.ts +3 -26
- package/dist/candidate-execution/index.js +6 -6
- package/dist/{coordination-driver-DzTvehd6.js → coordination-driver-yj9HPXef.js} +322 -223
- package/dist/coordination-driver-yj9HPXef.js.map +1 -0
- package/dist/{delegate-vJ2g76r6.js → delegate-KtrL9HWq.js} +5 -5
- package/dist/delegate-KtrL9HWq.js.map +1 -0
- package/dist/durable.d.ts +3 -15
- package/dist/durable.js +158 -124
- package/dist/durable.js.map +1 -1
- package/dist/{graph-BDQh3qry.js → graph-DcdyHbgf.js} +5 -6
- package/dist/graph-DcdyHbgf.js.map +1 -0
- package/dist/{improvement-cycle-D6cPLi6k.js → improvement-cycle-DsN-TVXR.js} +1129 -10
- package/dist/improvement-cycle-DsN-TVXR.js.map +1 -0
- package/dist/{index-sC6sl88d.d.ts → index-DflDZq_I.d.ts} +188 -748
- package/dist/index.d.ts +378 -12
- package/dist/index.js +223 -320
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +5 -5
- package/dist/intelligence.js +7 -8
- package/dist/intelligence.js.map +1 -1
- package/dist/kernel.d.ts +4 -4
- package/dist/kernel.js +9 -9
- package/dist/{loop-runner-bin-DZglq4Cf.d.ts → loop-runner-bin-DZfRUVWy.d.ts} +3 -3
- package/dist/{loop-runner-bin-DQIHnCL0.js → loop-runner-bin-rVrSX5l1.js} +3 -3
- package/dist/{loop-runner-bin-DQIHnCL0.js.map → loop-runner-bin-rVrSX5l1.js.map} +1 -1
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +6 -35
- package/dist/mcp/index.js +311 -364
- package/dist/mcp/index.js.map +1 -1
- package/dist/model-policy-DydyWTQg.js.map +1 -1
- package/dist/{openai-tools-DvR82zEo.d.ts → openai-tools-YO30D2s3.d.ts} +2 -2
- package/dist/{prepare-CGVNMb1o.js → prepare--nWcazPr.js} +7 -13
- package/dist/prepare--nWcazPr.js.map +1 -0
- package/dist/{profile-BetOB4_Q.js → profile-h04LDjV6.js} +2 -2
- package/dist/{profile-BetOB4_Q.js.map → profile-h04LDjV6.js.map} +1 -1
- package/dist/profiles.d.ts +2 -94
- package/dist/profiles.js +2 -451
- package/dist/profiles.js.map +1 -1
- package/dist/{protected-model-port-CAa0t1MT.d.ts → protected-model-port-C9QtEf3y.d.ts} +2 -2
- package/dist/{protected-model-port-CuVHkhti.js → protected-model-port-wwalbyXM.js} +4 -4
- package/dist/{protected-model-port-CuVHkhti.js.map → protected-model-port-wwalbyXM.js.map} +1 -1
- package/dist/{provision-supervisor-IXBlLHE0.js → provision-supervisor-WxFEFQeJ.js} +14 -24
- package/dist/provision-supervisor-WxFEFQeJ.js.map +1 -0
- package/dist/{runtime-DpEt5v42.js → runtime-B9eBIyws.js} +86 -496
- package/dist/runtime-B9eBIyws.js.map +1 -0
- package/dist/{search-method-DvU-fc-f.js → search-executor-2tWr38Qw.js} +239 -1132
- package/dist/search-executor-2tWr38Qw.js.map +1 -0
- package/dist/{server-CIE8s4AN.js → server-CpKcrOPj.js} +5 -12
- package/dist/server-CpKcrOPj.js.map +1 -0
- package/dist/{stream-agent-turn-I3bb0eqF.d.ts → stream-agent-turn-B1giFgOg.d.ts} +4 -2
- package/dist/{substrate-UjsxukjZ.d.ts → substrate-L_sC7jCD.d.ts} +2 -2
- package/dist/{supervise-C5mktzrh.js → supervise-DllOHM4M.js} +206 -80
- package/dist/supervise-DllOHM4M.js.map +1 -0
- package/dist/{supervisor-CQSu5XGl.js → supervisor-gCfG6K1-.js} +1130 -1667
- package/dist/supervisor-gCfG6K1-.js.map +1 -0
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +14 -14
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +1 -1
- package/dist/{types-C73caP0U.d.ts → types-DeuEkBhI.d.ts} +167 -261
- package/dist/{workspace-archive-pz8YJ1fr.d.ts → workspace-streams-CpSmt3zx.d.ts} +67 -3
- package/dist/{workspace-streams-D5gHJdTb.js → workspace-streams-ILw0eWZ0.js} +694 -2
- package/dist/workspace-streams-ILw0eWZ0.js.map +1 -0
- package/package.json +8 -8
- package/skills/generate-eval/SKILL.md +1 -1
- package/skills/profile-authoring/SKILL.md +5 -5
- package/skills/supervise/SKILL.md +2 -2
- package/dist/coordination-driver-DzTvehd6.js.map +0 -1
- package/dist/delegate-vJ2g76r6.js.map +0 -1
- package/dist/graph-BDQh3qry.js.map +0 -1
- package/dist/improvement-cycle-D6cPLi6k.js.map +0 -1
- package/dist/prepare-CGVNMb1o.js.map +0 -1
- package/dist/provision-supervisor-IXBlLHE0.js.map +0 -1
- package/dist/runtime-DpEt5v42.js.map +0 -1
- package/dist/search-method-DvU-fc-f.js.map +0 -1
- package/dist/server-CIE8s4AN.js.map +0 -1
- package/dist/supervise-C5mktzrh.js.map +0 -1
- package/dist/supervisor-CQSu5XGl.js.map +0 -1
- package/dist/workspace-streams-D5gHJdTb.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Di as providerAttemptEvidence, Dn as FileSpawnJournal, Dr as resolveRedactor, Dt as createRouterTranscript, En as FileResultBlobStore, Fn as prepareJsonlAppend, Hn as workerTraceAnalysisStore, In as readCommittedJsonLines, Jt as isTerminalNodeStatus, Kn as assertValidBudget, Ln as writeAllBytes, On as InMemoryResultBlobStore, R as meterRuntimeOwnedProviderAttempt, Rt as createInbox, St as createExecutorRegistry, T as failedItems, Ut as createPeerMailbox, Vn as parseWorkerToolTraceArtifact, _ as CheckUnavailableError, br as contentAddress, c as runTree, er as errMessage, et as scopeRetainedOwnerResourceReader, i as bestDelivered, j as withDriverExecutor, kn as InMemorySpawnJournal, o as pickBestDelivered, pn as runBrainLoop, qt as isLiveNodeStatus, s as runFinalizer, st as resolveSpawnResourcePaths, x as checkVerdictOf, zi as detachedFrozen } from "./supervisor-gCfG6K1-.js";
|
|
2
2
|
import { f as RuntimeRunStateError, m as ValidationError } from "./errors-DodWX-cb.js";
|
|
3
|
+
import { V as chargedTokens, Z as promptCacheTokenClasses, at as unmeteredSpend, ft as withBudgetResources, lt as addResourceSpend } from "./workspace-streams-ILw0eWZ0.js";
|
|
3
4
|
import { A as writeWorkerCancellation, M as writeWorkerSteerAcknowledgement, b as workerCancellationsDir, c as readWorkerCancelRequests, d as readWorkerSteerRequests, k as writeRunCancellation, l as readWorkerCancellation, o as readRunCancelRequest, r as claimWorkerSteerDelivery, s as readRunCancellation, u as readWorkerSteerAcknowledgement } from "./run-layout-DSCWdbX2.js";
|
|
4
5
|
import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest } from "@tangle-network/agent-interface";
|
|
5
6
|
import { argHash, errorStreakDetector, observeAll, repeatedActionDetector } from "@tangle-network/agent-eval";
|
|
@@ -7,7 +8,6 @@ import { randomUUID } from "node:crypto";
|
|
|
7
8
|
import { mkdirSync, readFileSync, watch } from "node:fs";
|
|
8
9
|
import { join } from "node:path";
|
|
9
10
|
import { registry } from "zod";
|
|
10
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
11
11
|
//#region src/runtime/supervise/detector-monitor.ts
|
|
12
12
|
/**
|
|
13
13
|
*
|
|
@@ -57,6 +57,7 @@ function createEventBus(now = Date.now) {
|
|
|
57
57
|
const queue = [];
|
|
58
58
|
const log = [];
|
|
59
59
|
const subscribers = [];
|
|
60
|
+
const queuedHandlers = [];
|
|
60
61
|
const byKind = {};
|
|
61
62
|
const staged = /* @__PURE__ */ new WeakMap();
|
|
62
63
|
let seq = 0;
|
|
@@ -97,6 +98,7 @@ function createEventBus(now = Date.now) {
|
|
|
97
98
|
log.push(record);
|
|
98
99
|
published += 1;
|
|
99
100
|
byKind[event.type] = (byKind[event.type] ?? 0) + 1;
|
|
101
|
+
if (opts?.queue !== false) for (const handler of [...queuedHandlers]) handler(record);
|
|
100
102
|
return record;
|
|
101
103
|
},
|
|
102
104
|
pull(kinds) {
|
|
@@ -113,6 +115,13 @@ function createEventBus(now = Date.now) {
|
|
|
113
115
|
if (i >= 0) subscribers.splice(i, 1);
|
|
114
116
|
};
|
|
115
117
|
},
|
|
118
|
+
onQueued(handler) {
|
|
119
|
+
queuedHandlers.push(handler);
|
|
120
|
+
return () => {
|
|
121
|
+
const i = queuedHandlers.indexOf(handler);
|
|
122
|
+
if (i >= 0) queuedHandlers.splice(i, 1);
|
|
123
|
+
};
|
|
124
|
+
},
|
|
116
125
|
pending(kinds) {
|
|
117
126
|
return kinds ? queue.filter((r) => matches(r, kinds)).length : queue.length;
|
|
118
127
|
},
|
|
@@ -129,53 +138,6 @@ function createEventBus(now = Date.now) {
|
|
|
129
138
|
};
|
|
130
139
|
}
|
|
131
140
|
//#endregion
|
|
132
|
-
//#region src/mcp/tools/coordination-request-context.ts
|
|
133
|
-
/**
|
|
134
|
-
* The header a harness sends to a remote MCP server whose tool-call timeout it
|
|
135
|
-
* raised, carrying the applied timeout in milliseconds. The Tangle profile
|
|
136
|
-
* materializer writes it beside `MCP_TOOL_TIMEOUT` (Claude Code) and
|
|
137
|
-
* `tool_timeout_sec` (Codex) when an attachment declares
|
|
138
|
-
* `metadata.toolTimeoutMs`. Without it the server must assume the harness
|
|
139
|
-
* default, 60 s for Claude Code 2.1.287 and Codex (measured 2026-10-03).
|
|
140
|
-
*/
|
|
141
|
-
const MCP_TOOL_TIMEOUT_HEADER = "x-mcp-tool-timeout-ms";
|
|
142
|
-
/** The tool-call timeout Runtime asks harnesses to give its coordination server. */
|
|
143
|
-
const COORDINATION_CLIENT_TOOL_TIMEOUT_MS = 3e5;
|
|
144
|
-
/**
|
|
145
|
-
* The longest `await_event` holds for a caller that declared a raised timeout.
|
|
146
|
-
* A held response through the Sandbox edge was measured to 200 s on 2026-10-03.
|
|
147
|
-
*/
|
|
148
|
-
const MAX_DECLARED_AWAIT_FENCE_MS = 18e4;
|
|
149
|
-
const MIN_DECLARED_TOOL_TIMEOUT_MS = 1e3;
|
|
150
|
-
const MAX_DECLARED_TOOL_TIMEOUT_MS = 36e5;
|
|
151
|
-
const requestContext = new AsyncLocalStorage();
|
|
152
|
-
/**
|
|
153
|
-
* The tool-call timeout a request declared through {@link MCP_TOOL_TIMEOUT_HEADER},
|
|
154
|
-
* or `undefined` when it is absent or malformed. A malformed value is treated as
|
|
155
|
-
* absent: the caller then gets the default fence, which every harness tolerates.
|
|
156
|
-
*/
|
|
157
|
-
function declaredToolTimeoutMs(header) {
|
|
158
|
-
if (typeof header !== "string" || !/^[0-9]{1,8}$/.test(header)) return void 0;
|
|
159
|
-
const value = Number(header);
|
|
160
|
-
return value >= MIN_DECLARED_TOOL_TIMEOUT_MS && value <= MAX_DECLARED_TOOL_TIMEOUT_MS ? value : void 0;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* How long `await_event` may hold for a caller that declared `declaredMs`: 60% of
|
|
164
|
-
* it, so the answer leaves well before the client gives up, and at most
|
|
165
|
-
* {@link MAX_DECLARED_AWAIT_FENCE_MS}.
|
|
166
|
-
*/
|
|
167
|
-
function declaredAwaitFenceMs(declaredMs) {
|
|
168
|
-
return Math.min(MAX_DECLARED_AWAIT_FENCE_MS, Math.floor(declaredMs * .6));
|
|
169
|
-
}
|
|
170
|
-
/** Run one coordination request with the fence its caller declared, if any. */
|
|
171
|
-
function withCoordinationAwaitFence(awaitFenceMs, run) {
|
|
172
|
-
return awaitFenceMs === void 0 ? run() : requestContext.run({ awaitFenceMs }, run);
|
|
173
|
-
}
|
|
174
|
-
/** The fence the current coordination request declared, or `undefined`. */
|
|
175
|
-
function coordinationRequestAwaitFenceMs() {
|
|
176
|
-
return requestContext.getStore()?.awaitFenceMs;
|
|
177
|
-
}
|
|
178
|
-
//#endregion
|
|
179
141
|
//#region src/mcp/tools/worker-output.ts
|
|
180
142
|
const WORKER_OUTPUT_PAGE_CHARS = 16384;
|
|
181
143
|
function workerOutputReadOptions(raw) {
|
|
@@ -532,13 +494,6 @@ function emptyPreflightCounts() {
|
|
|
532
494
|
"unmountable-tool": 0
|
|
533
495
|
};
|
|
534
496
|
}
|
|
535
|
-
/** Default ceiling for a single `await_event` block (ms). Every `pending` return costs the driver an
|
|
536
|
-
* inference turn, so the ceiling is as long as the harness clients allow: Claude Code 2.1.287 and
|
|
537
|
-
* Codex both time out an MCP tool call at 60 s by default (measured 2026-10-03: a 150 s HTTP MCP
|
|
538
|
-
* call failed at about 60 s and passed with `MCP_TOOL_TIMEOUT=300000`), and the Sandbox edge held
|
|
539
|
-
* a 200 s response. 45 s leaves 15 s of that minute for transfer and the driver's own latency. At
|
|
540
|
-
* 15 s a Discovery root director spent 303 of its 401 native tool calls (76%) re-polling. */
|
|
541
|
-
const DEFAULT_AWAIT_EVENT_TIMEOUT_MS = 45e3;
|
|
542
497
|
/** Default and maximum bounds for one {@link CoordinationTools} journal read. The defaults are
|
|
543
498
|
* sized for a driver turn (a page a model can read and still have room to act on); the maxima
|
|
544
499
|
* bound what a single tool result may cost even when the caller asks for everything. */
|
|
@@ -563,7 +518,9 @@ const journalEventKinds = [
|
|
|
563
518
|
"escalation",
|
|
564
519
|
"analyst-defined",
|
|
565
520
|
"analyst-assignment",
|
|
566
|
-
"acknowledgement"
|
|
521
|
+
"acknowledgement",
|
|
522
|
+
"tool-outcome",
|
|
523
|
+
"lead-message"
|
|
567
524
|
];
|
|
568
525
|
/** The reserved coordination verb names — the complete set `createCoordinationTools` can emit
|
|
569
526
|
* (the analyst pair is conditional but still reserved). A driver's extra WORK tools must not
|
|
@@ -582,7 +539,6 @@ const coordinationVerbNames = [
|
|
|
582
539
|
"cancel_worker",
|
|
583
540
|
"observe_agent",
|
|
584
541
|
"steer_agent",
|
|
585
|
-
"await_event",
|
|
586
542
|
"list_questions",
|
|
587
543
|
"answer_question",
|
|
588
544
|
"ask_parent",
|
|
@@ -596,22 +552,18 @@ const coordinationVerbNames = [
|
|
|
596
552
|
"define_analyst"
|
|
597
553
|
];
|
|
598
554
|
/**
|
|
599
|
-
* The `CoordinationEvent` kinds
|
|
600
|
-
*
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
* dispatch. Written twice, the two drift and the schema promises a kind the filter drops — a
|
|
605
|
-
* driver then blocks on a queue that already holds its event.
|
|
555
|
+
* The `CoordinationEvent` kinds that wake a waiting manager. The queue carries the UP-leg only:
|
|
556
|
+
* `steer` / `answer` / `instruction` / `delivery-attempt` are recorded `queue: false` (history and
|
|
557
|
+
* subscribers, never delivered back), and `mail` is delivered to its addressee's inbox. A
|
|
558
|
+
* `question` on this bus is the manager's own `ask_parent`, already escalated: it never wakes the
|
|
559
|
+
* asker, whose answer arrives as a `lead-message`.
|
|
606
560
|
*/
|
|
607
|
-
const
|
|
561
|
+
const wakeEventKinds = [
|
|
608
562
|
"settled",
|
|
609
|
-
"
|
|
610
|
-
"
|
|
563
|
+
"finding",
|
|
564
|
+
"tool-outcome",
|
|
565
|
+
"lead-message"
|
|
611
566
|
];
|
|
612
|
-
function isAwaitableEventKind(value) {
|
|
613
|
-
return awaitableEventKinds.includes(value);
|
|
614
|
-
}
|
|
615
567
|
const idArg = {
|
|
616
568
|
type: "string",
|
|
617
569
|
description: "The workerId returned by spawn_worker."
|
|
@@ -1007,6 +959,10 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
1007
959
|
return readyInFlight;
|
|
1008
960
|
};
|
|
1009
961
|
const deliveries = [];
|
|
962
|
+
const openReceipts = /* @__PURE__ */ new Map();
|
|
963
|
+
let receiptSeq = 0;
|
|
964
|
+
let leadPublishing = 0;
|
|
965
|
+
let deadlineNoticeDelivered = false;
|
|
1010
966
|
let driverAttempt;
|
|
1011
967
|
let journalReadTo = 0;
|
|
1012
968
|
let lastRejection;
|
|
@@ -1338,7 +1294,16 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
1338
1294
|
}, { analyst: route.kind });
|
|
1339
1295
|
} catch {}
|
|
1340
1296
|
};
|
|
1297
|
+
let flushing = 0;
|
|
1341
1298
|
const flushPendingSettlement = async () => {
|
|
1299
|
+
flushing += 1;
|
|
1300
|
+
try {
|
|
1301
|
+
return await flushPendingSettlementOnce();
|
|
1302
|
+
} finally {
|
|
1303
|
+
flushing -= 1;
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
const flushPendingSettlementOnce = async () => {
|
|
1342
1307
|
const pending = pendingSettlement;
|
|
1343
1308
|
if (!pending) return false;
|
|
1344
1309
|
await bus.publish(pending.event);
|
|
@@ -1604,6 +1569,14 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
1604
1569
|
type: "acknowledgement",
|
|
1605
1570
|
...ev.acknowledgement
|
|
1606
1571
|
};
|
|
1572
|
+
if (ev.type === "tool-outcome") return {
|
|
1573
|
+
type: "tool-outcome",
|
|
1574
|
+
...ev.outcome
|
|
1575
|
+
};
|
|
1576
|
+
if (ev.type === "lead-message") return {
|
|
1577
|
+
type: "lead-message",
|
|
1578
|
+
...ev.message
|
|
1579
|
+
};
|
|
1607
1580
|
return {
|
|
1608
1581
|
type: ev.type,
|
|
1609
1582
|
...ev.down
|
|
@@ -1906,21 +1879,26 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
1906
1879
|
const received = new Set(ledger.map((worker) => worker.id));
|
|
1907
1880
|
const nodes = opts.scope.view?.nodes ?? [];
|
|
1908
1881
|
return {
|
|
1909
|
-
running: nodes.filter((node) => isLiveNodeStatus(node.status)
|
|
1882
|
+
running: nodes.filter((node) => isLiveNodeStatus(node.status)),
|
|
1910
1883
|
unqueued: nodes.filter((node) => !isLiveNodeStatus(node.status) && !received.has(node.id) && !flushedAnalystRuns.has(node.id)),
|
|
1911
|
-
queued: bus.queued([
|
|
1884
|
+
queued: bus.queued([
|
|
1885
|
+
"settled",
|
|
1886
|
+
"finding",
|
|
1887
|
+
"lead-message"
|
|
1888
|
+
])
|
|
1912
1889
|
};
|
|
1913
1890
|
};
|
|
1914
1891
|
const openWorkRefusal = (verb) => {
|
|
1892
|
+
if (deadlineNoticeDelivered) return void 0;
|
|
1915
1893
|
const { running, unqueued, queued } = openWork();
|
|
1916
1894
|
if (running.length === 0 && unqueued.length === 0 && queued.length === 0) return void 0;
|
|
1917
1895
|
const parts = [];
|
|
1918
1896
|
if (running.length > 0) parts.push(`${running.length} worker${running.length === 1 ? " is" : "s are"} still running (${running.map((node) => node.id).join(", ")})`);
|
|
1919
1897
|
const waiting = unqueued.length + queued.length;
|
|
1920
|
-
if (waiting > 0) parts.push(`${waiting} event${waiting === 1 ? " is" : "s are"} waiting for you
|
|
1898
|
+
if (waiting > 0) parts.push(`${waiting} event${waiting === 1 ? " is" : "s are"} waiting for you`);
|
|
1921
1899
|
return {
|
|
1922
1900
|
error: "open-work",
|
|
1923
|
-
reason: `${parts.join(" and ")}.
|
|
1901
|
+
reason: `${parts.join(" and ")}. End your turn to wait: you will be woken with each result. Read each settled worker's output, and then call ${verb} again. Nothing was ${verb === "stop" ? "stopped" : "checked"}.`,
|
|
1924
1902
|
running: running.map((node) => ({
|
|
1925
1903
|
id: node.id,
|
|
1926
1904
|
label: node.label,
|
|
@@ -1994,7 +1972,6 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
1994
1972
|
unsub();
|
|
1995
1973
|
} catch {}
|
|
1996
1974
|
};
|
|
1997
|
-
const awaitTimeoutMs = opts.awaitTimeoutMs ?? 45e3;
|
|
1998
1975
|
let inFlightDrain = null;
|
|
1999
1976
|
const ensureDrain = () => {
|
|
2000
1977
|
if (!inFlightDrain) inFlightDrain = drainSettlement().finally(() => {
|
|
@@ -2045,28 +2022,104 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
2045
2022
|
});
|
|
2046
2023
|
return managerAnalysis;
|
|
2047
2024
|
};
|
|
2048
|
-
const
|
|
2049
|
-
|
|
2050
|
-
|
|
2025
|
+
const settledWithoutDrain = async () => {
|
|
2026
|
+
if (inFlightDrain) return;
|
|
2027
|
+
inFlightDrain = (async () => {
|
|
2028
|
+
let drained = false;
|
|
2029
|
+
while (await drainSettlement("nextResolved")) drained = true;
|
|
2030
|
+
return drained;
|
|
2031
|
+
})().finally(() => {
|
|
2032
|
+
inFlightDrain = null;
|
|
2033
|
+
});
|
|
2034
|
+
await inFlightDrain;
|
|
2035
|
+
};
|
|
2036
|
+
const hasOpenWork = () => {
|
|
2037
|
+
const { running, unqueued, queued } = openWork();
|
|
2038
|
+
return running.length > 0 || unqueued.length > 0 || queued.length > 0 || bus.pending(wakeEventKinds) > 0 || openReceipts.size > 0 || leadPublishing > 0 || pendingSettlement !== void 0 || flushing > 0;
|
|
2051
2039
|
};
|
|
2052
|
-
const
|
|
2053
|
-
const
|
|
2054
|
-
|
|
2040
|
+
const awaitWake = async (input) => {
|
|
2041
|
+
const startedAt = Date.now();
|
|
2042
|
+
await ready();
|
|
2043
|
+
await settledWithoutDrain();
|
|
2044
|
+
if (!hasOpenWork() || input.signal.aborted) return void 0;
|
|
2045
|
+
const heartbeatAt = startedAt + Math.max(0, input.heartbeatMs);
|
|
2046
|
+
const deadlineAt = input.deadlineAt ?? Number.POSITIVE_INFINITY;
|
|
2047
|
+
const wakeAt = Math.min(heartbeatAt, deadlineAt);
|
|
2048
|
+
let unsubscribe;
|
|
2055
2049
|
let timer;
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
if (typeof timer?.unref === "function") timer.unref();
|
|
2059
|
-
});
|
|
2050
|
+
let onAbort;
|
|
2051
|
+
let outsideWake = false;
|
|
2060
2052
|
try {
|
|
2061
|
-
|
|
2053
|
+
const queuedEvent = new Promise((resolve) => {
|
|
2054
|
+
unsubscribe = bus.onQueued((record) => {
|
|
2055
|
+
if (wakeEventKinds.includes(record.event.type)) resolve();
|
|
2056
|
+
});
|
|
2057
|
+
});
|
|
2058
|
+
const elapsed = new Promise((resolve) => {
|
|
2059
|
+
timer = setTimeout(resolve, Math.max(0, wakeAt - Date.now()));
|
|
2060
|
+
});
|
|
2061
|
+
const aborted = new Promise((resolve) => {
|
|
2062
|
+
onAbort = () => resolve();
|
|
2063
|
+
input.signal.addEventListener("abort", onAbort, { once: true });
|
|
2064
|
+
});
|
|
2065
|
+
const outside = (input.alsoWakeOn ?? new Promise(() => void 0)).then(() => {
|
|
2066
|
+
outsideWake = true;
|
|
2067
|
+
});
|
|
2068
|
+
let cursorIdle = false;
|
|
2069
|
+
while (bus.pending(wakeEventKinds) === 0 && !outsideWake && !input.signal.aborted && Date.now() < wakeAt) {
|
|
2070
|
+
const drained = !cursorIdle && openWork().running.length > 0 ? ensureDrain() : new Promise(() => void 0);
|
|
2071
|
+
if (await Promise.race([
|
|
2072
|
+
drained.then((value) => value ? "drained" : "idle"),
|
|
2073
|
+
queuedEvent.then(() => "queued"),
|
|
2074
|
+
elapsed.then(() => "elapsed"),
|
|
2075
|
+
aborted.then(() => "aborted"),
|
|
2076
|
+
outside.then(() => "outside")
|
|
2077
|
+
]) === "idle") {
|
|
2078
|
+
cursorIdle = true;
|
|
2079
|
+
if (!hasOpenWork()) break;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
if (input.signal.aborted) return void 0;
|
|
2083
|
+
if (flushing > 0 && inFlightDrain !== null) await inFlightDrain.catch(() => false);
|
|
2084
|
+
if (bus.pending(wakeEventKinds) > 0 && input.debounceMs > 0 && openWork().running.length > 0) {
|
|
2085
|
+
await Promise.race([new Promise((resolve) => {
|
|
2086
|
+
setTimeout(resolve, input.debounceMs);
|
|
2087
|
+
}), aborted]);
|
|
2088
|
+
if (input.signal.aborted) return void 0;
|
|
2089
|
+
await settledWithoutDrain();
|
|
2090
|
+
}
|
|
2062
2091
|
} finally {
|
|
2092
|
+
unsubscribe?.();
|
|
2063
2093
|
if (timer) clearTimeout(timer);
|
|
2094
|
+
if (onAbort) input.signal.removeEventListener("abort", onAbort);
|
|
2064
2095
|
}
|
|
2096
|
+
const events = [];
|
|
2097
|
+
for (let next = bus.pullRecord(wakeEventKinds); next; next = bus.pullRecord(wakeEventKinds)) {
|
|
2098
|
+
deliveries.push({
|
|
2099
|
+
record: next,
|
|
2100
|
+
attempt: input.attempt ?? driverAttempt,
|
|
2101
|
+
acknowledged: false
|
|
2102
|
+
});
|
|
2103
|
+
events.push({
|
|
2104
|
+
...projectEvent(next.event),
|
|
2105
|
+
eventSeq: next.seq
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
if (events.length === 0 && !outsideWake && !hasOpenWork()) return void 0;
|
|
2109
|
+
const reason = events.length > 0 || outsideWake ? "events" : Date.now() >= deadlineAt ? "deadline" : "heartbeat";
|
|
2110
|
+
if (reason === "deadline") deadlineNoticeDelivered = true;
|
|
2111
|
+
return detachedFrozen({
|
|
2112
|
+
reason,
|
|
2113
|
+
events,
|
|
2114
|
+
live: liveSnapshot(),
|
|
2115
|
+
freeSlots: freeWorkerSlots(),
|
|
2116
|
+
idleMs: Date.now() - startedAt
|
|
2117
|
+
});
|
|
2065
2118
|
};
|
|
2066
2119
|
const tools = [
|
|
2067
2120
|
{
|
|
2068
2121
|
name: "spawn_worker",
|
|
2069
|
-
description: "Start a worker the driver will drive. `profile` is the worker or another driver; `task` is what it should do. Reserves budget from the conserved pool and fails closed. Pass an optional `budget` (per-field) to give a sub-task more or less than the default — it merges over the per-worker default; the conserved pool is still the hard fence. Each worker reserves its whole budget when it starts, so the pool divided by the per-worker budget is how many run at once: to run a wide team at once, give each worker less. When every worker slot is busy, or the pool cannot cover the budget until your running workers return what they hold, the worker is admitted with `status: \"queued\"` and starts on its own when a slot and its budget free — it is never refused for concurrency, so spawn all the work you want done
|
|
2122
|
+
description: "Start a worker the driver will drive. `profile` is the worker or another driver; `task` is what it should do. Reserves budget from the conserved pool and fails closed. Pass an optional `budget` (per-field) to give a sub-task more or less than the default — it merges over the per-worker default; the conserved pool is still the hard fence. Each worker reserves its whole budget when it starts, so the pool divided by the per-worker budget is how many run at once: to run a wide team at once, give each worker less. When every worker slot is busy, or the pool cannot cover the budget until your running workers return what they hold, the worker is admitted with `status: \"queued\"` and starts on its own when a slot and its budget free — it is never refused for concurrency, so spawn all the work you want done, then end your turn: you are woken with each result. A queued worker whose budget never frees settles down as budget-exhausted. Pass a `key` naming the assignment to make it run-once ACROSS restarts: a key that already completed returns the finished result (`resumed: \"completed\"` — no work re-runs, nothing is spent), a key whose prior attempt failed (`down`) spawns fresh and says so (`resumed: \"retried\"`), and a key the process died with IN FLIGHT retries under the same key when the executor provably died with the process (an inline worker — the same `resumed: \"retried\"`, naming the interruption). A key with no terminal receipt whose execution may still exist elsewhere (sandbox, CLI bridge, router) is refused (`error: \"in-doubt\"`) until its exact prior execution is recovered. A key still running is refused (`error: \"duplicate-key\"`). Returns `freeSlots`: how many MORE workers start at once (`null` = no slot bound), and `queued`: how many of your workers wait for a slot. Parallel workers finish the run sooner than one at a time." + (profileTable === void 0 ? "" : " This run has a profiles table: pass `profile` as one of the table's names to run that exact profile, or write a new profile under a name the table does not hold."),
|
|
2070
2123
|
inputSchema: {
|
|
2071
2124
|
type: "object",
|
|
2072
2125
|
properties: {
|
|
@@ -2087,7 +2140,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
2087
2140
|
},
|
|
2088
2141
|
successorOf: {
|
|
2089
2142
|
type: "string",
|
|
2090
|
-
description: "The workerId of a SETTLED worker you spawned that this new worker replaces — for example one that failed, stalled, or finished with a weak result, restarted with a changed profile or task. The run record then names the predecessor on the new worker. Refused for an id you did not spawn (`error: \"successor-unknown\"`) and for a worker still live (`error: \"successor-live\"` —
|
|
2143
|
+
description: "The workerId of a SETTLED worker you spawned that this new worker replaces — for example one that failed, stalled, or finished with a weak result, restarted with a changed profile or task. The run record then names the predecessor on the new worker. Refused for an id you did not spawn (`error: \"successor-unknown\"`) and for a worker still live (`error: \"successor-live\"` — end your turn until it settles). Put what the successor needs from its predecessor in `task`."
|
|
2091
2144
|
},
|
|
2092
2145
|
budget: {
|
|
2093
2146
|
type: "object",
|
|
@@ -2187,7 +2240,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
2187
2240
|
};
|
|
2188
2241
|
if (isLiveNodeStatus(predecessor.status)) return {
|
|
2189
2242
|
error: "successor-live",
|
|
2190
|
-
reason: `worker '${successorOf}' has not settled —
|
|
2243
|
+
reason: `worker '${successorOf}' has not settled — end your turn until it does, then spawn its successor (steer_agent redirects a live worker instead)`,
|
|
2191
2244
|
live: liveWorkerCount(),
|
|
2192
2245
|
freeSlots: freeWorkerSlots()
|
|
2193
2246
|
};
|
|
@@ -2293,7 +2346,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
2293
2346
|
},
|
|
2294
2347
|
{
|
|
2295
2348
|
name: "observe_agent",
|
|
2296
|
-
description: "Inspect a worker WHILE IT RUNS, not only after it finishes: status, spend so far, and `progress` — how long since it last did anything (`idleMs`), whether that counts as stalled, how many turns it has taken, the last tools/files it touched (`recentActivity`), what its executor CHANGED about the profile you gave it (`derived` — an MCP config it materialized, an extension it had to add), whether a steer can even reach it (`steerable`), and how many steers it has not yet read (`pendingMessages`). For a worker that leads its own team, `progress.team` counts the agents below it (working, queued, done, down) and its idle clock reads the newest activity anywhere in that team, so a lead whose workers are busy is not stalled. A queued worker waits for a worker slot and is never stalled. A worker whose executor has FINISHED but whose settlement you have not yet drained reports `settlementPending` with its terminal kind; its `status` still reads running until
|
|
2349
|
+
description: "Inspect a worker WHILE IT RUNS, not only after it finishes: status, spend so far, and `progress` — how long since it last did anything (`idleMs`), whether that counts as stalled, how many turns it has taken, the last tools/files it touched (`recentActivity`), what its executor CHANGED about the profile you gave it (`derived` — an MCP config it materialized, an extension it had to add), whether a steer can even reach it (`steerable`), and how many steers it has not yet read (`pendingMessages`). For a worker that leads its own team, `progress.team` counts the agents below it (working, queued, done, down) and its idle clock reads the newest activity anywhere in that team, so a lead whose workers are busy is not stalled. A queued worker waits for a worker slot and is never stalled. A worker whose executor has FINISHED but whose settlement you have not yet drained reports `settlementPending` with its terminal kind; its `status` still reads running until your next wake delivers it, so end your turn rather than observing again. The settled output artifact is returned once drained. Select a field with `outputPath`, for example [\"content\"] to read a provider result without its event history. Omit it to read the complete artifact. Large outputs return a bounded JSON `outputPage`; repeat with `outputOffset: outputPage.nextOffset` until it is null, concatenate page text, then parse the JSON. Offsets and limits count UTF-16 characters. The full artifact stays retained; an outRef is a content address, not a workspace path. Use this BEFORE steer_agent: a steer is only worth sending when the progress says the worker is on the wrong path or has stopped making any.",
|
|
2297
2350
|
inputSchema: {
|
|
2298
2351
|
type: "object",
|
|
2299
2352
|
properties: {
|
|
@@ -2358,7 +2411,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
2358
2411
|
progress: progress ?? null,
|
|
2359
2412
|
...pending ? {
|
|
2360
2413
|
settlementPending: pending,
|
|
2361
|
-
hint: `this worker has finished (${pending.kind}); its settlement is queued —
|
|
2414
|
+
hint: `this worker has finished (${pending.kind}); its settlement is queued for your next wake — end your turn to receive it, observing again will not change this`
|
|
2362
2415
|
} : {}
|
|
2363
2416
|
};
|
|
2364
2417
|
}
|
|
@@ -2400,7 +2453,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
2400
2453
|
},
|
|
2401
2454
|
{
|
|
2402
2455
|
name: "cancel_worker",
|
|
2403
|
-
description: "Cancel one of YOUR live workers — running, or queued for a worker slot — and every worker it leads. Its unspent budget returns to your pool when it settles, so this is how you take back what a stalled or no-longer-needed worker holds (for example when spawn_worker is refused budget-exhausted while workers you no longer need hold the budget). The cancelled worker still settles `down
|
|
2456
|
+
description: "Cancel one of YOUR live workers — running, or queued for a worker slot — and every worker it leads. Its unspent budget returns to your pool when it settles, so this is how you take back what a stalled or no-longer-needed worker holds (for example when spawn_worker is refused budget-exhausted while workers you no longer need hold the budget). The cancelled worker still settles `down`, delivered in your next wake with what it spent. Refused (`error: \"not-live\"`) for a worker that already settled or is not yours.",
|
|
2404
2457
|
inputSchema: {
|
|
2405
2458
|
type: "object",
|
|
2406
2459
|
properties: {
|
|
@@ -2432,117 +2485,6 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
2432
2485
|
};
|
|
2433
2486
|
}
|
|
2434
2487
|
},
|
|
2435
|
-
{
|
|
2436
|
-
name: "await_event",
|
|
2437
|
-
description: "Wait for and pull the next message a worker, sub-driver, or analyst sent up — the unified inbox. Read a settled artifact with the returned `outputRead` call; the receipt carries its reference, not its bytes. An event is one of: a settled worker output ('settled'), a question needing your answer ('question', from ask_parent / the worker's ask-user), or a trace-analyst finding ('finding', from analyze-on-settle). Pass kinds:['settled'] for just the next finished worker; omit `kinds` to also receive questions and findings. Returns { idle: true } when nothing is queued and no workers are live. If a worker is still running when the wait elapses, returns { pending: true, live: [...] } (the workers still in flight) instead of blocking indefinitely — call await_event again to keep waiting; the settlement is not lost. Every reply carries `freeSlots`: how many more workers you can start right now (`null` = uncapped). A settled worker frees its slot, so `freeSlots > 0` means capacity is sitting idle — spawn into it before waiting again. Each event carries `eventSeq`; pass the ones you have processed in `acknowledge` on a later call. An event delivered to a turn that ends in failure is named again when you are re-entered, until it is acknowledged. Pass `max` above 1 to read a whole team at once: the reply is `{ events: [...] }` with the first event it waited for plus every other event already waiting, up to `max`, so a lead of hundreds of workers reads their receipts in a few turns instead of one each.",
|
|
2438
|
-
inputSchema: {
|
|
2439
|
-
type: "object",
|
|
2440
|
-
properties: {
|
|
2441
|
-
kinds: {
|
|
2442
|
-
type: "array",
|
|
2443
|
-
items: {
|
|
2444
|
-
type: "string",
|
|
2445
|
-
enum: [...awaitableEventKinds]
|
|
2446
|
-
},
|
|
2447
|
-
description: "Restrict to these event kinds (any if omitted)."
|
|
2448
|
-
},
|
|
2449
|
-
acknowledge: {
|
|
2450
|
-
type: "array",
|
|
2451
|
-
items: {
|
|
2452
|
-
type: "integer",
|
|
2453
|
-
minimum: 0
|
|
2454
|
-
},
|
|
2455
|
-
description: "The eventSeq of each earlier event you have now processed."
|
|
2456
|
-
},
|
|
2457
|
-
max: {
|
|
2458
|
-
type: "integer",
|
|
2459
|
-
minimum: 1,
|
|
2460
|
-
description: "Most events to return in one reply. Omit or 1 for one event; above 1 returns `{ events }`."
|
|
2461
|
-
}
|
|
2462
|
-
}
|
|
2463
|
-
},
|
|
2464
|
-
handler: async (raw) => {
|
|
2465
|
-
const args = raw === void 0 ? {} : obj(raw);
|
|
2466
|
-
const max = args.max === void 0 ? 1 : args.max;
|
|
2467
|
-
if (typeof max !== "number" || !Number.isSafeInteger(max) || max < 1) throw new Error("coordination tools: \"max\" must be a positive integer");
|
|
2468
|
-
const k = args.kinds;
|
|
2469
|
-
const kinds = Array.isArray(k) ? k.filter(isAwaitableEventKind) : void 0;
|
|
2470
|
-
if (Array.isArray(args.acknowledge)) {
|
|
2471
|
-
const named = new Set(args.acknowledge.filter((value) => typeof value === "number" && Number.isInteger(value)));
|
|
2472
|
-
await acknowledge(deliveries.filter((delivery) => named.has(delivery.record.seq)), "manager");
|
|
2473
|
-
}
|
|
2474
|
-
const deliver = (record) => {
|
|
2475
|
-
deliveries.push({
|
|
2476
|
-
record,
|
|
2477
|
-
attempt: driverAttempt,
|
|
2478
|
-
acknowledged: false
|
|
2479
|
-
});
|
|
2480
|
-
return {
|
|
2481
|
-
...projectEvent(record.event),
|
|
2482
|
-
eventSeq: record.seq
|
|
2483
|
-
};
|
|
2484
|
-
};
|
|
2485
|
-
if (max > 1) {
|
|
2486
|
-
const fenceMs = awaitFenceMs();
|
|
2487
|
-
const fenceAt = fenceMs > 0 ? Date.now() + fenceMs / 2 : Infinity;
|
|
2488
|
-
if (!inFlightDrain) {
|
|
2489
|
-
inFlightDrain = (async () => {
|
|
2490
|
-
let drained = false;
|
|
2491
|
-
while (bus.pending(kinds) < max && Date.now() < fenceAt) {
|
|
2492
|
-
if (!await drainSettlement("nextResolved")) break;
|
|
2493
|
-
drained = true;
|
|
2494
|
-
}
|
|
2495
|
-
return drained;
|
|
2496
|
-
})().finally(() => {
|
|
2497
|
-
inFlightDrain = null;
|
|
2498
|
-
});
|
|
2499
|
-
await inFlightDrain;
|
|
2500
|
-
}
|
|
2501
|
-
const events = [];
|
|
2502
|
-
const takeQueued = () => {
|
|
2503
|
-
for (let next = bus.pullRecord(kinds); next; next = bus.pullRecord(kinds)) {
|
|
2504
|
-
events.push(deliver(next));
|
|
2505
|
-
if (events.length >= max) return;
|
|
2506
|
-
}
|
|
2507
|
-
};
|
|
2508
|
-
takeQueued();
|
|
2509
|
-
if (events.length === 0) {
|
|
2510
|
-
const first = await pullOne();
|
|
2511
|
-
if (!("eventSeq" in first)) return first;
|
|
2512
|
-
const { freeSlots: _slots, ...head } = first;
|
|
2513
|
-
events.push(head);
|
|
2514
|
-
takeQueued();
|
|
2515
|
-
}
|
|
2516
|
-
return {
|
|
2517
|
-
events,
|
|
2518
|
-
freeSlots: freeWorkerSlots()
|
|
2519
|
-
};
|
|
2520
|
-
}
|
|
2521
|
-
return pullOne();
|
|
2522
|
-
async function pullOne() {
|
|
2523
|
-
let ev = bus.pullRecord(kinds);
|
|
2524
|
-
if (ev) return {
|
|
2525
|
-
...deliver(ev),
|
|
2526
|
-
freeSlots: freeWorkerSlots()
|
|
2527
|
-
};
|
|
2528
|
-
const raced = await raceDrainWithTimeout(ensureDrain());
|
|
2529
|
-
if (raced === void 0) return {
|
|
2530
|
-
pending: true,
|
|
2531
|
-
live: liveSnapshot(),
|
|
2532
|
-
freeSlots: freeWorkerSlots()
|
|
2533
|
-
};
|
|
2534
|
-
ev = bus.pullRecord(kinds);
|
|
2535
|
-
if (!ev) return {
|
|
2536
|
-
idle: !raced.drained,
|
|
2537
|
-
freeSlots: freeWorkerSlots()
|
|
2538
|
-
};
|
|
2539
|
-
return {
|
|
2540
|
-
...deliver(ev),
|
|
2541
|
-
freeSlots: freeWorkerSlots()
|
|
2542
|
-
};
|
|
2543
|
-
}
|
|
2544
|
-
}
|
|
2545
|
-
},
|
|
2546
2488
|
{
|
|
2547
2489
|
name: "list_questions",
|
|
2548
2490
|
description: "List questions raised by workers, drivers, or analysts. Blocking stop behavior follows questionPolicy.",
|
|
@@ -3010,7 +2952,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
3010
2952
|
};
|
|
3011
2953
|
if (isLiveNodeStatus(node.status)) return {
|
|
3012
2954
|
error: "worker-not-settled",
|
|
3013
|
-
reason: `worker ${JSON.stringify(id)} has not settled, so it has no trace to analyze yet —
|
|
2955
|
+
reason: `worker ${JSON.stringify(id)} has not settled, so it has no trace to analyze yet — end your turn until it settles, then run the lens`
|
|
3014
2956
|
};
|
|
3015
2957
|
const trace = ledger.find((worker) => worker.id === id)?.trace ?? node.trace ?? {
|
|
3016
2958
|
status: "unavailable",
|
|
@@ -3163,6 +3105,69 @@ function createCoordinationToolsForManager(opts, lifetime) {
|
|
|
3163
3105
|
const attempt = driverAttempt;
|
|
3164
3106
|
if (outcome === "completed") await acknowledge(deliveries.filter((delivery) => delivery.attempt === attempt), "turn-completed");
|
|
3165
3107
|
},
|
|
3108
|
+
hasOpenWork,
|
|
3109
|
+
awaitWake,
|
|
3110
|
+
awaitSettlement: async (workerIds, signal) => {
|
|
3111
|
+
const wanted = new Set(workerIds);
|
|
3112
|
+
const settledIds = () => ledger.filter((worker) => wanted.has(worker.id)).map((w) => w.id);
|
|
3113
|
+
await ready();
|
|
3114
|
+
for (;;) {
|
|
3115
|
+
await settledWithoutDrain();
|
|
3116
|
+
const hit = settledIds();
|
|
3117
|
+
if (hit.length > 0) return hit;
|
|
3118
|
+
signal?.throwIfAborted();
|
|
3119
|
+
if (!(opts.scope.view?.nodes ?? []).some((node) => wanted.has(node.id) && isLiveNodeStatus(node.status))) return [];
|
|
3120
|
+
if (!await (signal === void 0 ? ensureDrain() : Promise.race([ensureDrain(), new Promise((_resolve, reject) => {
|
|
3121
|
+
signal.addEventListener("abort", () => reject(signal.reason), { once: true });
|
|
3122
|
+
})])) && settledIds().length === 0) return [];
|
|
3123
|
+
}
|
|
3124
|
+
},
|
|
3125
|
+
receiveLeadMessage: (message) => {
|
|
3126
|
+
const parsed = leadMessageOf(message);
|
|
3127
|
+
if (parsed === void 0) return false;
|
|
3128
|
+
leadPublishing += 1;
|
|
3129
|
+
bus.publish({
|
|
3130
|
+
type: "lead-message",
|
|
3131
|
+
message: parsed
|
|
3132
|
+
}).catch((error) => {
|
|
3133
|
+
console.error("Runtime could not queue a lead message for its manager", {
|
|
3134
|
+
manager: opts.scope.view.root,
|
|
3135
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3136
|
+
});
|
|
3137
|
+
}).finally(() => {
|
|
3138
|
+
leadPublishing -= 1;
|
|
3139
|
+
});
|
|
3140
|
+
return true;
|
|
3141
|
+
},
|
|
3142
|
+
openToolReceipt: (tool) => {
|
|
3143
|
+
receiptSeq += 1;
|
|
3144
|
+
const receipt = `${tool}#${receiptSeq}`;
|
|
3145
|
+
openReceipts.set(receipt, {
|
|
3146
|
+
tool,
|
|
3147
|
+
startedAt: Date.now()
|
|
3148
|
+
});
|
|
3149
|
+
return receipt;
|
|
3150
|
+
},
|
|
3151
|
+
settleToolReceipt: async (receipt, outcome) => {
|
|
3152
|
+
const open = openReceipts.get(receipt);
|
|
3153
|
+
if (open === void 0) return;
|
|
3154
|
+
openReceipts.delete(receipt);
|
|
3155
|
+
await bus.publish({
|
|
3156
|
+
type: "tool-outcome",
|
|
3157
|
+
outcome: detachedFrozen({
|
|
3158
|
+
receipt,
|
|
3159
|
+
tool: open.tool,
|
|
3160
|
+
...outcome.ok ? {
|
|
3161
|
+
ok: true,
|
|
3162
|
+
value: outcome.value
|
|
3163
|
+
} : {
|
|
3164
|
+
ok: false,
|
|
3165
|
+
error: outcome.error instanceof Error ? outcome.error.message : String(outcome.error)
|
|
3166
|
+
},
|
|
3167
|
+
elapsedMs: Date.now() - open.startedAt
|
|
3168
|
+
})
|
|
3169
|
+
});
|
|
3170
|
+
},
|
|
3166
3171
|
reentryState: () => {
|
|
3167
3172
|
const { unqueued, queued } = openWork();
|
|
3168
3173
|
const deliveredSettled = new Set(deliveries.flatMap((delivery) => delivery.record.event.type === "settled" ? [delivery.record.event.worker.id] : []));
|
|
@@ -3272,6 +3277,22 @@ function safeJsonText(value) {
|
|
|
3272
3277
|
return String(value);
|
|
3273
3278
|
}
|
|
3274
3279
|
}
|
|
3280
|
+
function leadMessageOf(message) {
|
|
3281
|
+
if (message === null || typeof message !== "object") return void 0;
|
|
3282
|
+
const m = message;
|
|
3283
|
+
const interrupt = m.interrupt === true;
|
|
3284
|
+
if (typeof m.steer === "string") return {
|
|
3285
|
+
kind: "steer",
|
|
3286
|
+
text: m.steer,
|
|
3287
|
+
interrupt
|
|
3288
|
+
};
|
|
3289
|
+
if (typeof m.answer === "string") return {
|
|
3290
|
+
kind: "answer",
|
|
3291
|
+
text: m.answer,
|
|
3292
|
+
...typeof m.questionId === "string" ? { questionId: m.questionId } : {},
|
|
3293
|
+
interrupt
|
|
3294
|
+
};
|
|
3295
|
+
}
|
|
3275
3296
|
//#endregion
|
|
3276
3297
|
//#region src/runtime/supervise/run-cancellation.ts
|
|
3277
3298
|
/** Apply a durable request through the run's existing abort controller. */
|
|
@@ -3700,7 +3721,7 @@ function renderAnytimeTable(report) {
|
|
|
3700
3721
|
* A stop rule reads the run's own PROGRESS and decides. Three signals feed it:
|
|
3701
3722
|
* - the objective curve over settled work (best-so-far, from `anytime.ts` — see below),
|
|
3702
3723
|
* - the LIVE worker feed (`WorkerProgress`: `idleMs`, `stalled`, `turns`, `tokens`),
|
|
3703
|
-
* - tree-level shape (how many are in flight,
|
|
3724
|
+
* - tree-level shape (how many are in flight, when the last settle landed).
|
|
3704
3725
|
*
|
|
3705
3726
|
* ── Two boundaries this module holds deliberately ───────────────────────────────────────────────
|
|
3706
3727
|
*
|
|
@@ -3758,7 +3779,6 @@ function createProgressTracker(opts = {}) {
|
|
|
3758
3779
|
const workers = [];
|
|
3759
3780
|
if (scope && treeView) for (const node of treeView.nodes) {
|
|
3760
3781
|
if (isTerminalNodeStatus(node.status)) continue;
|
|
3761
|
-
if (node.status === "waiting") continue;
|
|
3762
3782
|
const p = scope.progress(node.id, viewOpts?.stallAfterMs !== void 0 ? {
|
|
3763
3783
|
now: now(),
|
|
3764
3784
|
stallAfterMs: viewOpts.stallAfterMs
|
|
@@ -3776,8 +3796,7 @@ function createProgressTracker(opts = {}) {
|
|
|
3776
3796
|
lastImprovementAt,
|
|
3777
3797
|
settlesSinceImprovement: lastImprovementIdx < 0 ? recorded.length : recorded.length - 1 - lastImprovementIdx,
|
|
3778
3798
|
workers,
|
|
3779
|
-
inFlight: treeView?.inFlight ?? 0
|
|
3780
|
-
waiting: treeView?.waiting ?? 0
|
|
3799
|
+
inFlight: treeView?.inFlight ?? 0
|
|
3781
3800
|
};
|
|
3782
3801
|
},
|
|
3783
3802
|
evaluate(rule, scope, viewOpts) {
|
|
@@ -3819,7 +3838,7 @@ function noProgressFor(opts) {
|
|
|
3819
3838
|
stop: true,
|
|
3820
3839
|
reason: `no-progress: ${v.settlesSinceImprovement} settles with no improvement (limit ${opts.settles}), best=${v.best}`
|
|
3821
3840
|
};
|
|
3822
|
-
if (opts.ms !== void 0 && v.
|
|
3841
|
+
if (opts.ms !== void 0 && v.lastSettleAt > 0) {
|
|
3823
3842
|
const idle = v.now - v.lastSettleAt;
|
|
3824
3843
|
if (idle >= opts.ms) return {
|
|
3825
3844
|
stop: true,
|
|
@@ -3861,7 +3880,6 @@ function plateau(opts) {
|
|
|
3861
3880
|
function allWorkersStalled(opts = {}) {
|
|
3862
3881
|
const minWorkers = opts.minWorkers ?? 1;
|
|
3863
3882
|
return (v) => {
|
|
3864
|
-
if (v.waiting > 0) return CONTINUE;
|
|
3865
3883
|
if (v.workers.length < minWorkers) return CONTINUE;
|
|
3866
3884
|
if (!v.workers.every((w) => w.stalled)) return CONTINUE;
|
|
3867
3885
|
const worst = Math.max(...v.workers.map((w) => w.idleMs));
|
|
@@ -3919,6 +3937,56 @@ function progressStop(tracker, rule, ledger, scope, now, stallAfterMs) {
|
|
|
3919
3937
|
return tracker.evaluate(rule, scope, stallAfterMs !== void 0 ? { stallAfterMs } : void 0);
|
|
3920
3938
|
}
|
|
3921
3939
|
//#endregion
|
|
3940
|
+
//#region src/runtime/supervise/wake.ts
|
|
3941
|
+
/** How long a waiting manager hears nothing before Runtime wakes it to reconsider: 15 min. */
|
|
3942
|
+
const DEFAULT_WAKE_HEARTBEAT_MS = 15 * 6e4;
|
|
3943
|
+
/** How long a wake waits for more events after its first, while other workers still run: 2 s. */
|
|
3944
|
+
const DEFAULT_WAKE_DEBOUNCE_MS = 2e3;
|
|
3945
|
+
/** How long before its deadline a manager is woken once to submit its best result: 15 min. */
|
|
3946
|
+
const DEFAULT_DEADLINE_WARNING_MS = 15 * 6e4;
|
|
3947
|
+
/** The instruction every manager receives about waiting. */
|
|
3948
|
+
const WAIT_BY_ENDING_TURN = "When you are waiting for workers, end your turn. You will be woken with what happened: a worker settled, a finding, a message or answer from your lead, or the deadline approaching.";
|
|
3949
|
+
function resolveWakePolicy(policy) {
|
|
3950
|
+
const pick = (value, fallback, name) => {
|
|
3951
|
+
const resolved = value ?? fallback;
|
|
3952
|
+
if (!Number.isSafeInteger(resolved) || resolved < 0) throw new TypeError(`wake.${name} must be a nonnegative safe integer of milliseconds`);
|
|
3953
|
+
return resolved;
|
|
3954
|
+
};
|
|
3955
|
+
return {
|
|
3956
|
+
heartbeatMs: pick(policy?.heartbeatMs, DEFAULT_WAKE_HEARTBEAT_MS, "heartbeatMs"),
|
|
3957
|
+
debounceMs: pick(policy?.debounceMs, DEFAULT_WAKE_DEBOUNCE_MS, "debounceMs"),
|
|
3958
|
+
deadlineWarningMs: pick(policy?.deadlineWarningMs, DEFAULT_DEADLINE_WARNING_MS, "deadlineWarningMs")
|
|
3959
|
+
};
|
|
3960
|
+
}
|
|
3961
|
+
/**
|
|
3962
|
+
* The deadline warning, at most once per manager: the epoch ms to wake at, or undefined. The lead
|
|
3963
|
+
* is at most a quarter of the manager's whole time to its deadline, so a short run is not warned
|
|
3964
|
+
* the moment it starts.
|
|
3965
|
+
*/
|
|
3966
|
+
function deadlineWarningAt(deadlineMs, policy, warned, startedAtMs) {
|
|
3967
|
+
if (warned || deadlineMs <= 0 || policy.deadlineWarningMs <= 0) return void 0;
|
|
3968
|
+
return deadlineMs - Math.min(policy.deadlineWarningMs, Math.max(0, deadlineMs - startedAtMs) / 4);
|
|
3969
|
+
}
|
|
3970
|
+
/** The input a woken manager's next turn receives. */
|
|
3971
|
+
function composeWakeInput(wake, context) {
|
|
3972
|
+
const span = (ms) => ms < 12e4 ? `${Math.max(0, Math.round(ms / 1e3))} s` : `${Math.round(ms / 6e4)} min`;
|
|
3973
|
+
const lines = [];
|
|
3974
|
+
const waited = `You waited ${span(wake.idleMs)} without spending a turn.`;
|
|
3975
|
+
if (wake.reason === "deadline") {
|
|
3976
|
+
const left = context.deadlineMs === void 0 ? void 0 : context.deadlineMs - context.now;
|
|
3977
|
+
lines.push(`The run's deadline is ${left === void 0 ? "near" : `in ${span(left)}`}. ${waited}`, context.tools?.includes("submit_result") === true ? "Submit your best result now with submit_result. A run that reaches its deadline without an accepted result delivers nothing." : "Finish now with your best result.");
|
|
3978
|
+
} else if (wake.reason === "heartbeat") lines.push(`Nothing reached your inbox. ${waited} Reconsider whether the running workers still serve the objective.`);
|
|
3979
|
+
else lines.push(`${wake.events.length} event${wake.events.length === 1 ? "" : "s"} arrived. ${waited}`);
|
|
3980
|
+
if (wake.events.length > 0) {
|
|
3981
|
+
lines.push("", "## Events", "");
|
|
3982
|
+
for (const event of wake.events) lines.push(`- ${JSON.stringify(event)}`);
|
|
3983
|
+
}
|
|
3984
|
+
lines.push("", wake.live.length === 0 ? "Workers running: none." : `Workers running: ${wake.live.map((worker) => String(worker.id)).join(", ")}.`);
|
|
3985
|
+
if (wake.freeSlots !== null) lines.push(`Free worker slots: ${wake.freeSlots}.`);
|
|
3986
|
+
lines.push("", WAIT_BY_ENDING_TURN);
|
|
3987
|
+
return lines.join("\n");
|
|
3988
|
+
}
|
|
3989
|
+
//#endregion
|
|
3922
3990
|
//#region src/runtime/supervise/coordination-driver.ts
|
|
3923
3991
|
/**
|
|
3924
3992
|
*
|
|
@@ -3977,7 +4045,7 @@ function formatOverspend(violation) {
|
|
|
3977
4045
|
* overspend usd up to the turn tripwire). */
|
|
3978
4046
|
function poolStarved(scope, perWorker, preserveOwnerTurns = false) {
|
|
3979
4047
|
const b = scope.budget;
|
|
3980
|
-
if (scope.view.inFlight > 0
|
|
4048
|
+
if (scope.view.inFlight > 0) return false;
|
|
3981
4049
|
const tokenStarved = preserveOwnerTurns ? b.tokensLeft <= 0 : b.tokensLeft < perWorker.maxTokens;
|
|
3982
4050
|
const iterationStarved = b.iterationsLeft <= 0;
|
|
3983
4051
|
const usdStarved = b.usdCapped && (b.usdLeft <= 0 || !preserveOwnerTurns && perWorker.maxUsd !== void 0 && b.usdLeft < perWorker.maxUsd);
|
|
@@ -3987,12 +4055,14 @@ function poolStarved(scope, perWorker, preserveOwnerTurns = false) {
|
|
|
3987
4055
|
/** The number of driver turns a manager whose spend Runtime cannot measure may take when no
|
|
3988
4056
|
* deadline or dollar cap bounds it. */
|
|
3989
4057
|
const UNMETERED_DRIVER_TURNS = 16;
|
|
4058
|
+
/** How often a waiting driver applies operator cancels and steers between its turns. */
|
|
4059
|
+
const WAITING_CONTROL_POLL_MS = 5e3;
|
|
3990
4060
|
/**
|
|
3991
4061
|
* Safety guards for a manager's own turns when no deadline bounds them.
|
|
3992
4062
|
*
|
|
3993
4063
|
* `poolStarved` lets a manager keep taking turns while its workers run, because those workers hold
|
|
3994
4064
|
* the pool its turns would otherwise be refused from. With no turn cap and no deadline, a manager
|
|
3995
|
-
* waiting on a worker that never settles would take a metered turn per
|
|
4065
|
+
* waiting on a worker that never settles would take a metered turn per heartbeat wake forever.
|
|
3996
4066
|
* Money bounds that: a manager that has overdrawn its pool by as much again as the whole pool stops.
|
|
3997
4067
|
* A brain that reports no usage cannot be bounded by money, so without a deadline or dollar cap it
|
|
3998
4068
|
* keeps the historical 16-turn bound. A caller's explicit `maxTurns` or a deadline replaces both.
|
|
@@ -4416,7 +4486,6 @@ function driverAgent(opts) {
|
|
|
4416
4486
|
...opts.sourceEvidenceRefs ? { sourceEvidenceRefs: opts.sourceEvidenceRefs } : {},
|
|
4417
4487
|
...opts.watchWorkers ? { watchWorkers: opts.watchWorkers } : {},
|
|
4418
4488
|
...opts.stallAfterMs !== void 0 ? { stallAfterMs: opts.stallAfterMs } : {},
|
|
4419
|
-
...opts.awaitTimeoutMs !== void 0 ? { awaitTimeoutMs: opts.awaitTimeoutMs } : {},
|
|
4420
4489
|
...opts.continuityByProfile ? { continuityByProfile: opts.continuityByProfile } : {},
|
|
4421
4490
|
...opts.preflightSpawn ? { preflightSpawn: opts.preflightSpawn } : {},
|
|
4422
4491
|
...opts.resolveSpawnProfile ? { resolveSpawnProfile: opts.resolveSpawnProfile } : {},
|
|
@@ -4453,7 +4522,7 @@ function driverAgent(opts) {
|
|
|
4453
4522
|
const modelTools = selectedTools.flatMap((selected) => selected.kind === "descriptor" ? [selected.descriptor] : []);
|
|
4454
4523
|
probeableByName = new Map(modelTools.map((tool) => [tool.name, tool]));
|
|
4455
4524
|
const selectedExtraNames = new Set(selectedTools.flatMap((selected) => selected.kind === "extra" ? [selected.extra.name] : []));
|
|
4456
|
-
opts.onCoordinationTools?.(modelTools);
|
|
4525
|
+
opts.onCoordinationTools?.(modelTools, coord);
|
|
4457
4526
|
const acknowledger = opts.controlDir === void 0 ? void 0 : createCancelAcknowledger({
|
|
4458
4527
|
dir: opts.controlDir,
|
|
4459
4528
|
coord,
|
|
@@ -4471,10 +4540,6 @@ function driverAgent(opts) {
|
|
|
4471
4540
|
signal: scope.signal,
|
|
4472
4541
|
...opts.controlScope === "subtree" ? {} : { deliverRoot: inbox.deliver }
|
|
4473
4542
|
});
|
|
4474
|
-
for (const w of scope.resume?.waits ?? []) {
|
|
4475
|
-
const rearmed = scope.wait(w.spec, { label: w.label });
|
|
4476
|
-
if (!rearmed.ok) throw new RuntimeRunStateError(`driverAgent: cannot re-arm resumed wait '${w.label}' (${rearmed.reason})`);
|
|
4477
|
-
}
|
|
4478
4543
|
const byName = new Map(modelTools.map((tool) => [tool.name, tool]));
|
|
4479
4544
|
const toolSpecs = selectedTools.map((selected) => selected.kind === "descriptor" ? {
|
|
4480
4545
|
type: "function",
|
|
@@ -4496,6 +4561,9 @@ function driverAgent(opts) {
|
|
|
4496
4561
|
const poolTokens = scope.budget.tokensLeft + scope.budget.reservedTokens;
|
|
4497
4562
|
let driverTurns = 0;
|
|
4498
4563
|
let progressStopReason;
|
|
4564
|
+
const wakePolicy = resolveWakePolicy(opts.wake);
|
|
4565
|
+
let deadlineWarned = false;
|
|
4566
|
+
const startedAt = now();
|
|
4499
4567
|
let driverTurn = 0;
|
|
4500
4568
|
let driverCall = 0;
|
|
4501
4569
|
const meteredBrain = async (messages, tools, detail, conversationTurn) => {
|
|
@@ -4645,6 +4713,38 @@ function driverAgent(opts) {
|
|
|
4645
4713
|
});
|
|
4646
4714
|
transcript.observe(messages);
|
|
4647
4715
|
},
|
|
4716
|
+
afterFinal: async () => {
|
|
4717
|
+
if (coord.isStopped() || coord.submittedResult() !== void 0 || scope.signal.aborted) return;
|
|
4718
|
+
if (inbox.pending() === 0 && !coord.hasOpenWork()) return void 0;
|
|
4719
|
+
const deadlineMs = scope.budget.deadlineMs;
|
|
4720
|
+
const warnAt = deadlineWarningAt(deadlineMs, wakePolicy, deadlineWarned, startedAt);
|
|
4721
|
+
const controlClock = acknowledger === void 0 && steerAcknowledger === void 0 ? void 0 : setInterval(() => {
|
|
4722
|
+
(async () => {
|
|
4723
|
+
await steerAcknowledger?.pass("turn");
|
|
4724
|
+
acknowledger?.pass("turn");
|
|
4725
|
+
})().catch(() => void 0);
|
|
4726
|
+
}, WAITING_CONTROL_POLL_MS);
|
|
4727
|
+
controlClock?.unref?.();
|
|
4728
|
+
let wake;
|
|
4729
|
+
try {
|
|
4730
|
+
wake = await coord.awaitWake({
|
|
4731
|
+
signal: scope.signal,
|
|
4732
|
+
heartbeatMs: wakePolicy.heartbeatMs,
|
|
4733
|
+
debounceMs: wakePolicy.debounceMs,
|
|
4734
|
+
...warnAt === void 0 ? {} : { deadlineAt: warnAt },
|
|
4735
|
+
alsoWakeOn: inbox.pending() > 0 ? Promise.resolve() : inbox.nextDelivery()
|
|
4736
|
+
});
|
|
4737
|
+
} finally {
|
|
4738
|
+
if (controlClock !== void 0) clearInterval(controlClock);
|
|
4739
|
+
}
|
|
4740
|
+
if (wake === void 0) return void 0;
|
|
4741
|
+
if (wake.reason === "deadline") deadlineWarned = true;
|
|
4742
|
+
return composeWakeInput(wake, {
|
|
4743
|
+
tools: selectedTools.map((selected) => selected.kind === "descriptor" ? selected.descriptor.name : selected.extra.name),
|
|
4744
|
+
deadlineMs,
|
|
4745
|
+
now: now()
|
|
4746
|
+
});
|
|
4747
|
+
},
|
|
4648
4748
|
stopBefore: () => {
|
|
4649
4749
|
if (coord.isStopped() || scope.signal.aborted || poolStarved(scope, opts.perWorker, opts.preserveOwnerTurns) || deadlinePassed(scope, now) || ownTurnsUnbounded(scope, poolTokens, driverTurns, opts.maxTurns)) return true;
|
|
4650
4750
|
if (!opts.stopRule || !tracker) return false;
|
|
@@ -4710,10 +4810,9 @@ function resumeBrief(resume, current, prior) {
|
|
|
4710
4810
|
const inDoubt = byState("in-doubt").filter(([, value]) => !currentIds.has(value.id));
|
|
4711
4811
|
const failed = byState("down");
|
|
4712
4812
|
if (completed.length > 0) lines.push("", "COMPLETED keys — spawn_worker with the same key returns the finished result, spending nothing:", ...completed.map(([k, v]) => `- ${k} → ${v.id} (${v.label})`));
|
|
4713
|
-
if (recovered.length > 0) lines.push("", "Recovered keys are attached to this scope.
|
|
4813
|
+
if (recovered.length > 0) lines.push("", "Recovered keys are attached to this scope. Their results arrive when you are woken; coordinate with their original workers:", ...recovered.map(([key, value]) => `- ${key} → ${value.id} (${value.label})`));
|
|
4714
4814
|
if (inDoubt.length > 0) lines.push("", "Keys IN DOUBT — a prior process recorded them as started but never recorded a terminal receipt. Do NOT spawn a replacement under these keys; inspect or recover each exact prior execution first:", ...inDoubt.map(([k, v]) => `- ${k} (prior attempt ${v.id}, ${v.label})`));
|
|
4715
4815
|
if (failed.length > 0) lines.push("", "Keys whose prior attempt FAILED (settled down) — spawn_worker with the same key retries:", ...failed.map(([k, v]) => `- ${k} (prior attempt ${v.id}, ${v.label})`));
|
|
4716
|
-
if (resume.waits.length > 0) lines.push("", "Pending waits RE-ARMED on their original deadlines (they settle through await_event):", ...resume.waits.map((w) => `- ${w.label} (${w.spec.kind})`));
|
|
4717
4816
|
appendPriorCoordination(lines, prior);
|
|
4718
4817
|
const spent = resume.priorSpend;
|
|
4719
4818
|
lines.push("", "Budget the run ALREADY spent before this process (it counts toward the run total):", `- child work: tokens charged=${chargedTokens(spent.childWork.tokens)} (in=${spent.childWork.tokens.input} out=${spent.childWork.tokens.output}), usd=${spent.childWork.usd}, iterations=${spent.childWork.iterations}`, `- driver inference: tokens charged=${chargedTokens(spent.driverInference.tokens)} (in=${spent.driverInference.tokens.input} out=${spent.driverInference.tokens.output}), usd=${spent.driverInference.usd}`);
|
|
@@ -4784,6 +4883,6 @@ function safeJson(v) {
|
|
|
4784
4883
|
}
|
|
4785
4884
|
}
|
|
4786
4885
|
//#endregion
|
|
4787
|
-
export {
|
|
4886
|
+
export { analystToolGroupNames as A, defaultToolDetectors as B, createInMemoryRunContext as C, applyRunCancellation as D, foldCoordinationRecords as E, downMessageRefusalReasons as F, normalizeAnalyzeOnSettle as I, parseAuthoredAnalystDefinition as L, coordinationVerbNames as M, createCoordinationTools as N, watchRunCancellation as O, createCoordinationToolsForManager as P, questionEscalationTargets as R, createFileRunContext as S, FileCoordinationLog as T, watchTrace as V, anytimeReport as _, DEFAULT_DEADLINE_WARNING_MS as a, plateauLength as b, resolveWakePolicy as c, anyOf as d, createProgressTracker as f, sampleFromSettled as g, progressStop as h, finalizeBestDelivered as i, canonicalFindingEvent as j, ANALYST_DEFINITION_BOUNDS as k, allOf as l, plateau as m, createSteerAcknowledger as n, composeWakeInput as o, noProgressFor as p, driverAgent as r, deadlineWarningAt as s, createCancelAcknowledger as t, allWorkersStalled as u, areaUnderCurve as v, withRunContext as w, renderAnytimeTable as x, bestSoFar as y, createEventBus as z };
|
|
4788
4887
|
|
|
4789
|
-
//# sourceMappingURL=coordination-driver-
|
|
4888
|
+
//# sourceMappingURL=coordination-driver-yj9HPXef.js.map
|