@tangle-network/agent-runtime 6.0.8 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -0
- package/README.md +23 -12
- package/dist/{activation-Cwy3_Qn_.js → activation-Ce4zUcu8.js} +4 -4
- package/dist/{activation-Cwy3_Qn_.js.map → activation-Ce4zUcu8.js.map} +1 -1
- package/dist/{activation-CWx7I1PU.d.ts → activation-xxvLF1-1.d.ts} +2 -2
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -3
- package/dist/{bundle-Cy5igJdv.js → bundle-CcpL2lfr.js} +2 -2
- package/dist/{bundle-Cy5igJdv.js.map → bundle-CcpL2lfr.js.map} +1 -1
- package/dist/candidate-execution/index.js +4 -4
- package/dist/continuation-CIyKnS1Q.js +451 -0
- package/dist/continuation-CIyKnS1Q.js.map +1 -0
- package/dist/{coordination-manager-D9z7To7p.js → coordination-manager-sa_PkISw.js} +247 -149
- package/dist/coordination-manager-sa_PkISw.js.map +1 -0
- package/dist/{coordination-map-routing-CKRNZSaV.js → coordination-map-routing-XZXTlCmn.js} +2 -4
- package/dist/coordination-map-routing-XZXTlCmn.js.map +1 -0
- package/dist/{delegate-ws-KBA2H.js → delegate-DhTkJIta.js} +3 -3
- package/dist/{delegate-ws-KBA2H.js.map → delegate-DhTkJIta.js.map} +1 -1
- package/dist/durable.d.ts +71 -4
- package/dist/durable.js +162 -13
- package/dist/durable.js.map +1 -1
- package/dist/{errors-AzSuGI23.js → errors-DG8yufqX.js} +8 -1
- package/dist/errors-DG8yufqX.js.map +1 -0
- package/dist/{failure-cause-BzjUUsRz.js → failure-cause-CVB-YE88.js} +17 -16
- package/dist/failure-cause-CVB-YE88.js.map +1 -0
- package/dist/{graph-registry-7X2nrreR.js → graph-registry-czAwYwNj.js} +133 -9
- package/dist/graph-registry-czAwYwNj.js.map +1 -0
- package/dist/{graph-registry-gYbq4L5Z.js → graph-registry-uTIyyy7A.js} +1 -1
- package/dist/graph-tSIT_eWK.js +1793 -0
- package/dist/graph-tSIT_eWK.js.map +1 -0
- package/dist/{improve-BxfqTsZy.js → improve-H08hiIw9.js} +19 -48
- package/dist/improve-H08hiIw9.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +16 -16
- package/dist/intelligence.d.ts +2 -2
- package/dist/intelligence.js +8 -8
- package/dist/intelligence.js.map +1 -1
- package/dist/kernel.d.ts +2 -2
- package/dist/kernel.js +16 -15
- package/dist/{loop-runner-CUMypgRw.d.ts → loop-runner-BGwhcn1p.d.ts} +2 -2
- package/dist/{loop-runner-BmGZ4y1W.js → loop-runner-ChqK8kSz.js} +3 -3
- package/dist/{loop-runner-BmGZ4y1W.js.map → loop-runner-ChqK8kSz.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 +7 -5
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +9 -9
- package/dist/mcp/memory-bin.js +2 -2
- package/dist/{model-policy-JOcg3NRs.js → model-policy-yxOrDTTj.js} +9 -9
- package/dist/model-policy-yxOrDTTj.js.map +1 -0
- package/dist/{prepare-Dtfk_Wi_.js → prepare-BnF8nGIg.js} +4 -4
- package/dist/{prepare-Dtfk_Wi_.js.map → prepare-BnF8nGIg.js.map} +1 -1
- package/dist/{profile-CNSQjOes.js → profile-CD25rTJF.js} +4 -4
- package/dist/{profile-CNSQjOes.js.map → profile-CD25rTJF.js.map} +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.js +2 -2
- package/dist/{provision-supervisor-CeQTPHRr.js → provision-supervisor-Dx4TXTMM.js} +8 -8
- package/dist/{provision-supervisor-CeQTPHRr.js.map → provision-supervisor-Dx4TXTMM.js.map} +1 -1
- package/dist/{run-cancellation-D_4vJ522.js → run-cancellation-DYszFJtQ.js} +4 -4
- package/dist/{run-cancellation-D_4vJ522.js.map → run-cancellation-DYszFJtQ.js.map} +1 -1
- package/dist/{run-state-CTZVngI_.js → run-state-DHBoJjaF.js} +6 -6
- package/dist/{run-state-CTZVngI_.js.map → run-state-DHBoJjaF.js.map} +1 -1
- package/dist/{runtime-COm9uBBx.js → runtime-CaM5Gbbv.js} +76 -987
- package/dist/runtime-CaM5Gbbv.js.map +1 -0
- package/dist/{sandbox-profile-compat-oFGWESLn.js → sandbox-profile-compat-l-SLQnGb.js} +2 -2
- package/dist/{sandbox-profile-compat-oFGWESLn.js.map → sandbox-profile-compat-l-SLQnGb.js.map} +1 -1
- package/dist/{search-executor-DTEIl58w.js → search-executor-B9L8W_1O.js} +17 -46
- package/dist/search-executor-B9L8W_1O.js.map +1 -0
- package/dist/{server-zO9Nz9Nk.js → server-BlDV8sj_.js} +32 -8
- package/dist/{server-zO9Nz9Nk.js.map → server-BlDV8sj_.js.map} +1 -1
- package/dist/{settle-record-U7fkQEZa.js → settle-record-WWQasnDq.js} +12 -4
- package/dist/settle-record-WWQasnDq.js.map +1 -0
- package/dist/{snapshot-Cgj2Wzi6.js → snapshot-BKI_w3JD.js} +19 -5
- package/dist/snapshot-BKI_w3JD.js.map +1 -0
- package/dist/{structural-rollout-BwTwTUXF.js → structural-rollout-C1xxoWcN.js} +39 -57
- package/dist/structural-rollout-C1xxoWcN.js.map +1 -0
- package/dist/{supervise-tmqDU6YT.js → supervise-DWiSgPLB.js} +103 -111
- package/dist/supervise-DWiSgPLB.js.map +1 -0
- package/dist/{supervision-discovery-CGbXayGv.js → supervision-discovery-C9kfBLKy.js} +4 -4
- package/dist/{supervision-discovery-CGbXayGv.js.map → supervision-discovery-C9kfBLKy.js.map} +1 -1
- package/dist/{supervisor-1A27fE6k.js → supervisor-Dpeu7rnZ.js} +209 -999
- package/dist/supervisor-Dpeu7rnZ.js.map +1 -0
- package/dist/{scope-gIYQ5ZiL.js → supervisor-accounting-Bw4MJk-b.js} +755 -458
- package/dist/supervisor-accounting-Bw4MJk-b.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +13 -13
- package/dist/{tool-server-B9q2dtnW.js → tool-server-DYwRbi0I.js} +3 -3
- package/dist/{tool-server-B9q2dtnW.js.map → tool-server-DYwRbi0I.js.map} +1 -1
- package/dist/{top-web-CS4PD4ck.js → top-web-B3HOAtrZ.js} +9 -7
- package/dist/{top-web-CS4PD4ck.js.map → top-web-B3HOAtrZ.js.map} +1 -1
- package/dist/tui/bin.js +6 -6
- package/dist/tui/bin.js.map +1 -1
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +2 -2
- package/dist/{types-w3Oo1uRJ.d.ts → types-C_qbnw9N.d.ts} +1263 -1497
- package/dist/{util-C_cdPNC4.js → util-fcckrkKp.js} +39 -113
- package/dist/util-fcckrkKp.js.map +1 -0
- package/dist/{workspace-streams-B7yNMahl.js → workspace-streams-DA9R3j-p.js} +2 -2
- package/dist/{workspace-streams-B7yNMahl.js.map → workspace-streams-DA9R3j-p.js.map} +1 -1
- package/package.json +1 -1
- package/dist/coordination-manager-D9z7To7p.js.map +0 -1
- package/dist/coordination-map-routing-CKRNZSaV.js.map +0 -1
- package/dist/errors-AzSuGI23.js.map +0 -1
- package/dist/failure-cause-BzjUUsRz.js.map +0 -1
- package/dist/graph-2_nX4ib4.js +0 -579
- package/dist/graph-2_nX4ib4.js.map +0 -1
- package/dist/graph-registry-7X2nrreR.js.map +0 -1
- package/dist/improve-BxfqTsZy.js.map +0 -1
- package/dist/model-policy-JOcg3NRs.js.map +0 -1
- package/dist/runtime-COm9uBBx.js.map +0 -1
- package/dist/scope-gIYQ5ZiL.js.map +0 -1
- package/dist/search-executor-DTEIl58w.js.map +0 -1
- package/dist/settle-record-U7fkQEZa.js.map +0 -1
- package/dist/snapshot-Cgj2Wzi6.js.map +0 -1
- package/dist/structural-rollout-BwTwTUXF.js.map +0 -1
- package/dist/supervise-tmqDU6YT.js.map +0 -1
- package/dist/supervisor-1A27fE6k.js.map +0 -1
- package/dist/util-C_cdPNC4.js.map +0 -1
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { E as writeWorkerCancellation, F as parseWorkerToolTraceArtifact, I as workerTraceAnalysisStore, K as spawnJournalRecordEvents, O as writeWorkerSteerAcknowledgement, Rt as runtimeGraphMetadataKey, S as workerCancelRequestsFile, St as resolveSpawnResourcePaths, T as workerSteerRequestsDir, W as FileSpawnJournal, _ as readWorkerSteerAcknowledgement, d as claimWorkerSteerDelivery, dr as isLiveNodeStatus, fr as isTerminalNodeStatus, g as readWorkerCancellation, h as readWorkerCancelRequests, in as FileResultBlobStore, it as meterRuntimeOwnedAccounting, v as readWorkerSteerRequests } from "./supervisor-accounting-Bw4MJk-b.js";
|
|
2
|
+
import { m as ValidationError } from "./errors-DG8yufqX.js";
|
|
3
|
+
import { M as contentAddress, et as assertValidBudget, o as settlementFailureCause } from "./failure-cause-CVB-YE88.js";
|
|
4
|
+
import { a as errMessage, f as resolveRedactor, t as detachedFrozen } from "./snapshot-BKI_w3JD.js";
|
|
5
|
+
import { Y as INBOX_RECEIPT_KEY, _ as withDriverExecutor, b as createExecutorRegistry, gt as CheckUnavailableError, nt as createPeerMailbox, v as InMemoryResultBlobStore, y as InMemorySpawnJournal } from "./supervisor-Dpeu7rnZ.js";
|
|
6
|
+
import { i as checkVerdictOf, o as failedItems } from "./continuation-CIyKnS1Q.js";
|
|
7
|
+
import { c as writeRunCancellation, i as readRunCancellation, r as readRunCancelRequest, t as applyRunCancellation, v as FileCoordinationLog } from "./run-cancellation-DYszFJtQ.js";
|
|
8
|
+
import { a as admitRuntimeSpawn, i as workerSettlement, n as resolveJsonPointer, o as safeJsonText, r as textBytes, t as createMapRouting } from "./coordination-map-routing-XZXTlCmn.js";
|
|
9
|
+
import { ResourceRequestSchema, agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest } from "@tangle-network/agent-interface";
|
|
8
10
|
import { argHash, errorStreakDetector, observeAll, repeatedActionDetector } from "@tangle-network/agent-eval";
|
|
9
11
|
import { registry } from "zod";
|
|
10
12
|
import { randomUUID } from "node:crypto";
|
|
11
|
-
import {
|
|
13
|
+
import { closeSync, openSync, readSync, statSync } from "node:fs";
|
|
12
14
|
import { join } from "node:path";
|
|
13
15
|
// src/runtime/supervise/run-context.ts
|
|
14
16
|
/**
|
|
@@ -112,6 +114,7 @@ const journalEventKinds = [
|
|
|
112
114
|
"analyst-assignment",
|
|
113
115
|
"acknowledgement",
|
|
114
116
|
"tool-outcome",
|
|
117
|
+
"tool-timing",
|
|
115
118
|
"lead-message",
|
|
116
119
|
"map",
|
|
117
120
|
"route"
|
|
@@ -484,18 +487,62 @@ const BUDGET_FIELD = {
|
|
|
484
487
|
usd: "maxUsd"
|
|
485
488
|
};
|
|
486
489
|
// src/runtime/supervise/driver-control-acknowledgers.ts
|
|
487
|
-
/** The journal file `createFileRunContext` writes inside the run directory. The acknowledger
|
|
488
|
-
* reads it as EVIDENCE for the terminated-descendants set — the nested trees of a cancelled
|
|
489
|
-
* lead journal their terminal records there before the lead settles into this scope. */
|
|
490
490
|
const SPAWN_JOURNAL_FILE = "spawn-journal.jsonl";
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
491
|
+
function appendedLines(tail) {
|
|
492
|
+
let size;
|
|
493
|
+
try {
|
|
494
|
+
size = statSync(tail.file).size;
|
|
495
|
+
} catch {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
if (size < tail.offset) {
|
|
499
|
+
tail.offset = 0;
|
|
500
|
+
tail.partial = "";
|
|
501
|
+
tail.at.clear();
|
|
502
|
+
}
|
|
503
|
+
if (size === tail.offset) return void 0;
|
|
504
|
+
const buf = Buffer.allocUnsafe(size - tail.offset);
|
|
505
|
+
const fd = openSync(tail.file, "r");
|
|
506
|
+
try {
|
|
507
|
+
const got = readSync(fd, buf, 0, buf.length, tail.offset);
|
|
508
|
+
tail.offset += got;
|
|
509
|
+
const text = tail.partial + buf.subarray(0, got).toString("utf8");
|
|
510
|
+
const parts = text.split("\n");
|
|
511
|
+
tail.partial = text.endsWith("\n") ? "" : parts.pop() ?? "";
|
|
512
|
+
if (text.endsWith("\n")) parts.pop();
|
|
513
|
+
return parts;
|
|
514
|
+
} finally {
|
|
515
|
+
closeSync(fd);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
function indexDeaths(tail) {
|
|
519
|
+
const lines = appendedLines(tail);
|
|
520
|
+
if (lines === void 0) return false;
|
|
521
|
+
let grew = false;
|
|
522
|
+
for (const line of lines) {
|
|
523
|
+
const trimmed = line.trim();
|
|
524
|
+
if (!trimmed) continue;
|
|
525
|
+
try {
|
|
526
|
+
for (const event of spawnJournalRecordEvents(JSON.parse(trimmed))) {
|
|
527
|
+
if (event === void 0) continue;
|
|
528
|
+
if (!(event.kind === "settled" && event.status === "down" || event.kind === "cancelled") || typeof event.id !== "string" || typeof event.at !== "string") continue;
|
|
529
|
+
const prev = tail.at.get(event.id);
|
|
530
|
+
if (prev !== void 0 && prev >= event.at) continue;
|
|
531
|
+
tail.at.set(event.id, event.at);
|
|
532
|
+
grew = true;
|
|
533
|
+
}
|
|
534
|
+
} catch {}
|
|
535
|
+
}
|
|
536
|
+
return grew;
|
|
537
|
+
}
|
|
538
|
+
function descendantsSince(tail, nodeId, sinceIso) {
|
|
539
|
+
indexDeaths(tail);
|
|
540
|
+
const prefix = `${nodeId}:`;
|
|
541
|
+
const ids = [...tail.at.keys()].filter((id) => id.startsWith(prefix) && (tail.at.get(id) ?? "") >= sinceIso);
|
|
542
|
+
ids.sort();
|
|
543
|
+
return ids;
|
|
544
|
+
}
|
|
545
|
+
/** Unknown ack lands before delivery. A crash can lose the steer; a restart must not deliver it twice. */
|
|
499
546
|
function createSteerAcknowledger(deps) {
|
|
500
547
|
const iso = () => new Date(deps.now()).toISOString();
|
|
501
548
|
const awaiting = /* @__PURE__ */ new Map();
|
|
@@ -520,9 +567,29 @@ function createSteerAcknowledger(deps) {
|
|
|
520
567
|
worker: request.worker,
|
|
521
568
|
requestedAt: request.at
|
|
522
569
|
});
|
|
570
|
+
let steerStamp = "";
|
|
571
|
+
let steerIdle = false;
|
|
572
|
+
const steerChanged = (phase) => {
|
|
573
|
+
let stamp = "missing";
|
|
574
|
+
try {
|
|
575
|
+
const st = statSync(workerSteerRequestsDir(deps.dir), { bigint: true });
|
|
576
|
+
stamp = `${st.dev}:${st.ino}:${st.mtimeNs}:${st.size}`;
|
|
577
|
+
} catch {
|
|
578
|
+
stamp = "missing";
|
|
579
|
+
}
|
|
580
|
+
const changed = stamp !== steerStamp;
|
|
581
|
+
if (changed && phase !== "boundary") steerStamp = stamp;
|
|
582
|
+
return changed;
|
|
583
|
+
};
|
|
523
584
|
return { async pass(phase) {
|
|
585
|
+
const changed = steerChanged(phase);
|
|
586
|
+
if (phase !== "final" && !changed && steerIdle) return;
|
|
587
|
+
let waiting = false;
|
|
524
588
|
for (const request of readWorkerSteerRequests(deps.dir)) {
|
|
525
|
-
if (phase !== "final" && deps.signal?.aborted)
|
|
589
|
+
if (phase !== "final" && deps.signal?.aborted) {
|
|
590
|
+
steerIdle = false;
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
526
593
|
const rootRequest = request.worker === deps.ownerId && deps.deliverRoot !== void 0;
|
|
527
594
|
if (phase === "boundary" && !rootRequest) continue;
|
|
528
595
|
if (!rootRequest && !isDirectChildNodeId(deps, request.worker)) continue;
|
|
@@ -546,7 +613,10 @@ function createSteerAcknowledger(deps) {
|
|
|
546
613
|
});
|
|
547
614
|
continue;
|
|
548
615
|
}
|
|
549
|
-
if (rootRequest && deps.deliverRootReady !== void 0 && !deps.deliverRootReady())
|
|
616
|
+
if (rootRequest && deps.deliverRootReady !== void 0 && !deps.deliverRootReady()) {
|
|
617
|
+
waiting = true;
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
550
620
|
if (!claimWorkerSteerDelivery(deps.dir, {
|
|
551
621
|
...base(request),
|
|
552
622
|
effect: "unknown",
|
|
@@ -595,17 +665,9 @@ function createSteerAcknowledger(deps) {
|
|
|
595
665
|
});
|
|
596
666
|
}
|
|
597
667
|
}
|
|
668
|
+
if (phase === "turn") steerIdle = !waiting;
|
|
598
669
|
} };
|
|
599
670
|
}
|
|
600
|
-
/**
|
|
601
|
-
* The OPERATOR-facing sentence for a steer outcome, written into the durable acknowledgement file.
|
|
602
|
-
*
|
|
603
|
-
* Deliberately separate from `downMessageRefusalReasons`, which is the MANAGER-facing sentence: one
|
|
604
|
-
* says what happened for someone reading the run afterwards, the other tells a model what to do
|
|
605
|
-
* next, and merging them would make one audience read the other's copy. They must nonetheless cover
|
|
606
|
-
* the SAME outcomes, so `tests/kernel/refusal-reasons.test.ts` holds both maps total over
|
|
607
|
-
* `DownMessageDeliveryOutcome` — a new code cannot land in only one.
|
|
608
|
-
*/
|
|
609
671
|
function steerAcknowledgementDetail(outcome) {
|
|
610
672
|
switch (outcome.outcome) {
|
|
611
673
|
case "delivered": return "the owning manager delivered the steer to the exact live worker";
|
|
@@ -616,42 +678,32 @@ function steerAcknowledgementDetail(outcome) {
|
|
|
616
678
|
case "runtime-error": return "delivery outcome is unknown after a runtime error";
|
|
617
679
|
}
|
|
618
680
|
}
|
|
619
|
-
/**
|
|
620
|
-
* The worker-cancel ACKNOWLEDGER — the runtime-side half of `run-layout`'s `cancelWorker`
|
|
621
|
-
* contract. Router managers check between turns; native managers observe throughout their invocation.
|
|
622
|
-
* Every manager with a `controlDir` mounts one;
|
|
623
|
-
* OWNERSHIP keeps them from colliding: a request naming a node id is owned by the manager whose
|
|
624
|
-
* own id is that node's parent, and a label/profile-name reference is owned by the `'run'`-scoped
|
|
625
|
-
* (root) manager only — so exactly one acknowledger can ever apply one operation.
|
|
626
|
-
*
|
|
627
|
-
* Two-phase, honestly reported: `cancel_requested` is written the moment a live worker's abort is
|
|
628
|
-
* issued (through the per-child abort chain the scope already owns, so siblings are untouched);
|
|
629
|
-
* `cancelled` is written only when that worker's settlement is DELIVERED on the settle path with
|
|
630
|
-
* a terminal `down`, and then the record names every subtree node id proven terminated. A worker
|
|
631
|
-
* that already settled — or that settles `done` despite the abort — records `not_live`; a
|
|
632
|
-
* reference matching nothing this manager owns stays pending (`cancelWorker` reports it
|
|
633
|
-
* `unknown`). No path reports success for a missing worker.
|
|
634
|
-
*
|
|
635
|
-
* Expiry is run end, not a clock: `finish()` (after the final post-drain pass) writes `not_live`
|
|
636
|
-
* for every owned request never applied and `unknown` for an issued abort whose settle the run
|
|
637
|
-
* ended too soon to observe. A pending request can therefore never outlive its run and abort a
|
|
638
|
-
* future spawn that happens to reuse a label.
|
|
639
|
-
*
|
|
640
|
-
* Idempotency is a lookup, in-process and across processes: an operation with a durable
|
|
641
|
-
* acknowledgement is returned as-is and never re-applied.
|
|
642
|
-
*/
|
|
643
681
|
function createCancelAcknowledger(deps) {
|
|
644
682
|
const tracked = /* @__PURE__ */ new Map();
|
|
645
683
|
let runTracked;
|
|
646
684
|
const abortIssuedAt = /* @__PURE__ */ new Map();
|
|
647
685
|
const iso = () => new Date(deps.now()).toISOString();
|
|
686
|
+
const waiting = /* @__PURE__ */ new Map();
|
|
687
|
+
const reconciling = /* @__PURE__ */ new Map();
|
|
688
|
+
const regrowing = /* @__PURE__ */ new Set();
|
|
689
|
+
let inboxBytes;
|
|
690
|
+
const deaths = {
|
|
691
|
+
file: join(deps.dir, SPAWN_JOURNAL_FILE),
|
|
692
|
+
offset: 0,
|
|
693
|
+
partial: "",
|
|
694
|
+
at: /* @__PURE__ */ new Map()
|
|
695
|
+
};
|
|
696
|
+
const watch = (record) => {
|
|
697
|
+
if (record.effect === "cancel_requested") reconciling.set(record.operationId, record);
|
|
698
|
+
else reconciling.delete(record.operationId);
|
|
699
|
+
if (record.effect === "cancelled" && abortIssuedAt.has(record.operationId)) regrowing.add(record.operationId);
|
|
700
|
+
else regrowing.delete(record.operationId);
|
|
701
|
+
};
|
|
648
702
|
const write = (record) => {
|
|
649
703
|
writeWorkerCancellation(deps.dir, record);
|
|
650
704
|
tracked.set(record.operationId, record);
|
|
705
|
+
watch(record);
|
|
651
706
|
};
|
|
652
|
-
/** Whether this acknowledger owns `ref`. A node id deeper in this subtree belongs to the nested
|
|
653
|
-
* manager that parents it; anything that is not a node id under this manager is a
|
|
654
|
-
* label/profile-name reference, owned by the `'run'`-scoped manager alone. */
|
|
655
707
|
const owned = (ref) => {
|
|
656
708
|
if (isDirectChildNodeId(deps, ref)) return true;
|
|
657
709
|
if (deps.controlScope !== "run") return false;
|
|
@@ -694,15 +746,13 @@ function createCancelAcknowledger(deps) {
|
|
|
694
746
|
terminated: []
|
|
695
747
|
});
|
|
696
748
|
};
|
|
697
|
-
/**
|
|
698
|
-
* journal record at/after the abort was issued. Union with what the record already names, so
|
|
699
|
-
* the set only ever grows (a late teardown journal adds; nothing removes). */
|
|
749
|
+
/** Grows only: the worker, the record's ids, and subtree deaths at or after the abort. */
|
|
700
750
|
const provenTerminated = (record, workerId) => {
|
|
701
751
|
const since = abortIssuedAt.get(record.operationId) ?? record.observedAt;
|
|
702
752
|
return [.../* @__PURE__ */ new Set([
|
|
703
753
|
...record.terminated,
|
|
704
754
|
workerId,
|
|
705
|
-
...
|
|
755
|
+
...descendantsSince(deaths, workerId, since)
|
|
706
756
|
])].sort();
|
|
707
757
|
};
|
|
708
758
|
const reconcile = (record) => {
|
|
@@ -728,10 +778,6 @@ function createCancelAcknowledger(deps) {
|
|
|
728
778
|
detail: `worker '${workerId}' settled done despite the abort request; nothing was terminated`
|
|
729
779
|
});
|
|
730
780
|
};
|
|
731
|
-
/** Re-scan a `cancelled` record while the manager still turns: a descendant whose teardown
|
|
732
|
-
* journals after the lead's settle joins the set on a later pass instead of being lost. Only
|
|
733
|
-
* a grown set is re-written; the window needs the in-process abort instant, so a record a
|
|
734
|
-
* PRIOR process closed stays as that process proved it. */
|
|
735
781
|
const regrow = (record) => {
|
|
736
782
|
const workerId = record.workerId;
|
|
737
783
|
if (workerId === void 0 || !abortIssuedAt.has(record.operationId)) return;
|
|
@@ -742,36 +788,49 @@ function createCancelAcknowledger(deps) {
|
|
|
742
788
|
terminated
|
|
743
789
|
});
|
|
744
790
|
};
|
|
745
|
-
/**
|
|
746
|
-
* The RUN-scoped request: seen once, `cancel_requested` written the moment the run's cascading
|
|
747
|
-
* abort is issued through the one controller the run already has. The `supervise()` settle path
|
|
748
|
-
* records what the run then actually did — this manager cannot observe its own tree's terminal
|
|
749
|
-
* state from inside `act`.
|
|
750
|
-
*
|
|
751
|
-
* Applied only at a TURN boundary, never on the final post-drain pass: by then the driver has
|
|
752
|
-
* finished and drained, so a root abort could only void work that is already delivered. A
|
|
753
|
-
* request that arrives that late expires in `finish()` instead — it terminated nothing.
|
|
754
|
-
*/
|
|
755
791
|
const passRun = () => {
|
|
756
792
|
if (deps.controlScope !== "run" || deps.abortRun === void 0) return;
|
|
757
793
|
if (runTracked !== void 0) return;
|
|
758
794
|
runTracked = applyRunCancellation(deps.dir, deps.abortRun, iso);
|
|
759
795
|
};
|
|
760
|
-
const
|
|
761
|
-
|
|
796
|
+
const ingest = () => {
|
|
797
|
+
const file = workerCancelRequestsFile(deps.dir);
|
|
798
|
+
let size;
|
|
799
|
+
try {
|
|
800
|
+
size = statSync(file).size;
|
|
801
|
+
} catch {
|
|
802
|
+
size = null;
|
|
803
|
+
}
|
|
804
|
+
if (size === inboxBytes) return;
|
|
805
|
+
inboxBytes = size;
|
|
762
806
|
for (const request of readWorkerCancelRequests(deps.dir)) {
|
|
763
|
-
if (!owned(request.worker)) continue;
|
|
764
|
-
|
|
765
|
-
if (record === void 0)
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
if (record === void 0) {
|
|
770
|
-
if (phase === "turn") apply(request);
|
|
771
|
-
continue;
|
|
807
|
+
if (!owned(request.worker) || tracked.has(request.operationId) || waiting.has(request.operationId)) continue;
|
|
808
|
+
const record = readWorkerCancellation(deps.dir, request.operationId);
|
|
809
|
+
if (record === void 0) waiting.set(request.operationId, request);
|
|
810
|
+
else {
|
|
811
|
+
tracked.set(record.operationId, record);
|
|
812
|
+
watch(record);
|
|
772
813
|
}
|
|
773
|
-
|
|
774
|
-
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
const pass = (phase) => {
|
|
817
|
+
if (phase === "turn") passRun();
|
|
818
|
+
ingest();
|
|
819
|
+
const pending = [...reconciling.values()];
|
|
820
|
+
if (phase === "turn") for (const request of [...waiting.values()]) {
|
|
821
|
+
waiting.delete(request.operationId);
|
|
822
|
+
apply(request);
|
|
823
|
+
if (!tracked.has(request.operationId)) waiting.set(request.operationId, request);
|
|
824
|
+
}
|
|
825
|
+
const grew = indexDeaths(deaths);
|
|
826
|
+
for (const record of pending) {
|
|
827
|
+
const current = tracked.get(record.operationId);
|
|
828
|
+
if (current?.effect === "cancel_requested") reconcile(current);
|
|
829
|
+
}
|
|
830
|
+
if (!grew) return;
|
|
831
|
+
for (const id of [...regrowing]) {
|
|
832
|
+
const record = tracked.get(id);
|
|
833
|
+
if (record !== void 0) regrow(record);
|
|
775
834
|
}
|
|
776
835
|
};
|
|
777
836
|
return {
|
|
@@ -813,43 +872,6 @@ function createCancelAcknowledger(deps) {
|
|
|
813
872
|
}
|
|
814
873
|
};
|
|
815
874
|
}
|
|
816
|
-
/**
|
|
817
|
-
* Subtree node ids with a terminal `down`/`cancelled` journal record at or after `sinceIso` —
|
|
818
|
-
* the abort-issue instant (the acknowledger's own `observedAt` on the `cancel_requested` record,
|
|
819
|
-
* runtime clock), never the client's `requestedAt` — read from the durable spawn journal beside
|
|
820
|
-
* the run layout. The set is proven at acknowledgement time and is approximate about post-abort
|
|
821
|
-
* causation: a descendant that died of its OWN cause after the abort was issued is
|
|
822
|
-
* indistinguishable from the cascade and may be included; one whose teardown journals late joins
|
|
823
|
-
* on a later acknowledger pass; a teardown journal still absent when the run ends is absent from
|
|
824
|
-
* the set. Ids are hierarchical (`parent:sN`), so `${nodeId}:` prefixes exactly the subtree.
|
|
825
|
-
* Tolerant of a missing or partially-written journal: evidence that cannot be read names fewer
|
|
826
|
-
* nodes, never wrong ones.
|
|
827
|
-
*/
|
|
828
|
-
function terminatedDescendants(dir, nodeId, sinceIso) {
|
|
829
|
-
let raw;
|
|
830
|
-
try {
|
|
831
|
-
raw = readFileSync(join(dir, SPAWN_JOURNAL_FILE), "utf8");
|
|
832
|
-
} catch {
|
|
833
|
-
return [];
|
|
834
|
-
}
|
|
835
|
-
const prefix = `${nodeId}:`;
|
|
836
|
-
const ids = /* @__PURE__ */ new Set();
|
|
837
|
-
for (const line of raw.split("\n")) {
|
|
838
|
-
const trimmed = line.trim();
|
|
839
|
-
if (!trimmed) continue;
|
|
840
|
-
try {
|
|
841
|
-
for (const event of spawnJournalRecordEvents(JSON.parse(trimmed))) {
|
|
842
|
-
if (event === void 0) continue;
|
|
843
|
-
if (!(event.kind === "settled" && event.status === "down" || event.kind === "cancelled")) continue;
|
|
844
|
-
if (typeof event.id !== "string" || !event.id.startsWith(prefix)) continue;
|
|
845
|
-
if (typeof event.at !== "string" || event.at < sinceIso) continue;
|
|
846
|
-
ids.add(event.id);
|
|
847
|
-
}
|
|
848
|
-
} catch {}
|
|
849
|
-
}
|
|
850
|
-
return [...ids].sort();
|
|
851
|
-
}
|
|
852
|
-
/** A direct child has exactly one generated spawn segment below its owner. */
|
|
853
875
|
function isDirectChildNodeId(owner, ref) {
|
|
854
876
|
return ref.startsWith(`${owner.ownerId}:s`) && /^s\d+$/.test(ref.slice(owner.ownerId.length + 1));
|
|
855
877
|
}
|
|
@@ -1866,15 +1888,13 @@ function mountGraphsTools({ opts, tools, admitSpawn }) {
|
|
|
1866
1888
|
error: "invalid-graph",
|
|
1867
1889
|
reason: prepared.reason
|
|
1868
1890
|
};
|
|
1869
|
-
const profile = detachedFrozen(prepared.profile);
|
|
1870
1891
|
return admitSpawn({
|
|
1871
|
-
profile,
|
|
1892
|
+
profile: detachedFrozen(prepared.profile),
|
|
1872
1893
|
args: a,
|
|
1873
1894
|
task: deliverable,
|
|
1874
1895
|
key,
|
|
1875
1896
|
continuity: { continuity: "fresh" },
|
|
1876
1897
|
successorOf: void 0,
|
|
1877
|
-
preflightProfile: () => opts.resolveSpawnProfile ? detachedFrozen(opts.resolveSpawnProfile(profile)) : profile,
|
|
1878
1898
|
resourcesFromPath: [],
|
|
1879
1899
|
defaultLabel: `graph:${prepared.root}`,
|
|
1880
1900
|
accepted: { graph: {
|
|
@@ -2153,6 +2173,10 @@ const projectEvent = (ev) => {
|
|
|
2153
2173
|
type: "tool-outcome",
|
|
2154
2174
|
...ev.outcome
|
|
2155
2175
|
};
|
|
2176
|
+
if (ev.type === "tool-timing") return {
|
|
2177
|
+
type: "tool-timing",
|
|
2178
|
+
...ev.call
|
|
2179
|
+
};
|
|
2156
2180
|
if (ev.type === "lead-message") return {
|
|
2157
2181
|
type: "lead-message",
|
|
2158
2182
|
...ev.message
|
|
@@ -3020,7 +3044,6 @@ async function spawnNode(state, marker, profile, task, key, continuity, traversa
|
|
|
3020
3044
|
key,
|
|
3021
3045
|
continuity,
|
|
3022
3046
|
successorOf: state.settledWorker.get(marker.node),
|
|
3023
|
-
preflightProfile: () => state.opts.resolveSpawnProfile ? detachedFrozen(state.opts.resolveSpawnProfile(profile)) : profile,
|
|
3024
3047
|
resourcesFromPath: [],
|
|
3025
3048
|
defaultLabel: marker.node,
|
|
3026
3049
|
route: Object.freeze({ ...marker })
|
|
@@ -3680,14 +3703,21 @@ function resolveContinuity(state, requested, profileName, key) {
|
|
|
3680
3703
|
* assignment, budget reservation, `Scope.spawn` — is synchronous and commits state.
|
|
3681
3704
|
* Returns the refusal body, or `undefined` when the spawn may proceed.
|
|
3682
3705
|
*/
|
|
3683
|
-
|
|
3706
|
+
/** `spawn_worker`'s optional machine request, as the canonical resource request. */
|
|
3707
|
+
function spawnResources(raw) {
|
|
3708
|
+
if (raw === void 0) return void 0;
|
|
3709
|
+
const parsed = ResourceRequestSchema.omit({ providerOptions: true }).strict().safeParse(raw);
|
|
3710
|
+
if (!parsed.success) throw new ValidationError(`spawn_worker resources: ${parsed.error.message}`);
|
|
3711
|
+
return detachedFrozen(parsed.data);
|
|
3712
|
+
}
|
|
3713
|
+
async function preflightRefusal(state, effective, spawn) {
|
|
3684
3714
|
const { opts } = state;
|
|
3685
3715
|
if (!opts.preflightSpawn) return void 0;
|
|
3686
|
-
const { key } =
|
|
3687
|
-
const refusal = await opts.preflightSpawn(
|
|
3688
|
-
|
|
3716
|
+
const { key, resources, ...rest } = spawn;
|
|
3717
|
+
const refusal = await opts.preflightSpawn(effective, {
|
|
3718
|
+
...rest,
|
|
3689
3719
|
...key !== void 0 ? { key } : {},
|
|
3690
|
-
|
|
3720
|
+
...resources !== void 0 ? { resources } : {}
|
|
3691
3721
|
});
|
|
3692
3722
|
if (!refusal) return void 0;
|
|
3693
3723
|
state.preflightCounts[refusal.cause] += 1;
|
|
@@ -3706,7 +3736,14 @@ async function admitSpawn(state, input) {
|
|
|
3706
3736
|
const a = input.args;
|
|
3707
3737
|
const task = detachedFrozen(input.task);
|
|
3708
3738
|
const label = typeof a.label === "string" ? a.label : input.defaultLabel;
|
|
3709
|
-
const
|
|
3739
|
+
const effective = opts.resolveSpawnProfile ? detachedFrozen(opts.resolveSpawnProfile(profile)) : profile;
|
|
3740
|
+
const resources = spawnResources(a.resources);
|
|
3741
|
+
const refused = await preflightRefusal(state, effective, {
|
|
3742
|
+
label,
|
|
3743
|
+
task,
|
|
3744
|
+
key,
|
|
3745
|
+
resources
|
|
3746
|
+
});
|
|
3710
3747
|
if (refused !== void 0) return refused;
|
|
3711
3748
|
const budget = Object.freeze(a.budget === void 0 ? opts.perWorker : mergeBudget(opts.perWorker, a.budget));
|
|
3712
3749
|
const assignmentId = key !== void 0 ? `key:${key}` : `ordinal:${state.unkeyedAssignment.next++}`;
|
|
@@ -3718,6 +3755,7 @@ async function admitSpawn(state, input) {
|
|
|
3718
3755
|
task,
|
|
3719
3756
|
label,
|
|
3720
3757
|
...key !== void 0 ? { key } : {},
|
|
3758
|
+
...resources !== void 0 ? { resources } : {},
|
|
3721
3759
|
continuity: continuity.continuity,
|
|
3722
3760
|
...continuity.continuity === "resume" ? { resume: continuity.resume } : {},
|
|
3723
3761
|
...successorOf !== void 0 ? { successorOf } : {},
|
|
@@ -3725,7 +3763,7 @@ async function admitSpawn(state, input) {
|
|
|
3725
3763
|
...input.map !== void 0 ? { map: input.map } : {},
|
|
3726
3764
|
...input.route !== void 0 ? { route: input.route } : {}
|
|
3727
3765
|
});
|
|
3728
|
-
const res = opts.scope.spawn(() => opts.makeWorkerAgent(
|
|
3766
|
+
const res = opts.scope.spawn(() => opts.makeWorkerAgent(effective, context), task, {
|
|
3729
3767
|
budget,
|
|
3730
3768
|
label,
|
|
3731
3769
|
assignmentId,
|
|
@@ -4368,7 +4406,7 @@ function spawnWorkerTool(ctx) {
|
|
|
4368
4406
|
const { profileTable } = ctx;
|
|
4369
4407
|
return {
|
|
4370
4408
|
name: "spawn_worker",
|
|
4371
|
-
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 only the channels capped by the pool. workerSlots sets concurrency. A funded worker waits with `status: \"queued\"` when every slot is busy and starts when one frees. A new worker whose budget cannot fit is refused immediately. Wait for settlements or request a smaller allocation before trying again. End your turn to be woken with results. 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 keyed worker that settled with a `budgetStop` keeps its session for a while: spawn the same key with a larger `budget` and a new worker continues that same session where it stopped (`resumed: \"continued\"`, `priorWorkerId`), or cancel_worker the stopped worker to release it. 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."),
|
|
4409
|
+
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 only the channels capped by the pool. workerSlots sets concurrency. A funded worker waits with `status: \"queued\"` when every slot is busy and starts when one frees. A new worker whose budget cannot fit is refused immediately. Wait for settlements or request a smaller allocation before trying again. End your turn to be woken with results. 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 keyed worker that settled with a `budgetStop` keeps its session for a while: spawn the same key with a larger `budget` and a new worker continues that same session where it stopped (`resumed: \"continued\"`, `priorWorkerId`), or cancel_worker the stopped worker to release it. 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. An authored profile must be fully executable before it spawns: `harness`, `model.provider`, a concrete `model.default`, and no legacy `systemPrompt` — one refusal names every field still missing." + (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."),
|
|
4372
4410
|
inputSchema: {
|
|
4373
4411
|
type: "object",
|
|
4374
4412
|
properties: {
|
|
@@ -4389,9 +4427,29 @@ function spawnWorkerTool(ctx) {
|
|
|
4389
4427
|
},
|
|
4390
4428
|
successorOf: {
|
|
4391
4429
|
type: "string",
|
|
4392
|
-
description: "The workerId of a
|
|
4430
|
+
description: "The workerId of a worker you spawned that this new worker revises or replaces — for example one that failed, stalled, or finished with a weak result, restarted with a changed profile or task. The predecessor may still be live; cancel_worker it if the successor supersedes it. The run record names the predecessor on the new worker. Refused for an id you did not spawn (`error: \"successor-unknown\"`). Put what the successor needs from its predecessor in `task`."
|
|
4393
4431
|
},
|
|
4394
|
-
budget: spawnBudgetArg
|
|
4432
|
+
budget: spawnBudgetArg,
|
|
4433
|
+
resources: {
|
|
4434
|
+
type: "object",
|
|
4435
|
+
description: "Optional machine for this worker: `cpu`, `memoryMb`, `diskMb`, `gpu`. Omit for the run's default. Refused, naming the ceiling, above the backend's `maxWorkerResources`.",
|
|
4436
|
+
properties: {
|
|
4437
|
+
cpu: {
|
|
4438
|
+
type: "number",
|
|
4439
|
+
exclusiveMinimum: 0
|
|
4440
|
+
},
|
|
4441
|
+
memoryMb: {
|
|
4442
|
+
type: "number",
|
|
4443
|
+
exclusiveMinimum: 0
|
|
4444
|
+
},
|
|
4445
|
+
diskMb: {
|
|
4446
|
+
type: "number",
|
|
4447
|
+
exclusiveMinimum: 0
|
|
4448
|
+
},
|
|
4449
|
+
gpu: { type: "string" }
|
|
4450
|
+
},
|
|
4451
|
+
additionalProperties: false
|
|
4452
|
+
}
|
|
4395
4453
|
},
|
|
4396
4454
|
required: ["profile", "task"]
|
|
4397
4455
|
},
|
|
@@ -4446,15 +4504,9 @@ function successorRefusal({ opts, spawn, workers }, successorOf) {
|
|
|
4446
4504
|
live: workers.liveWorkerCount(),
|
|
4447
4505
|
freeSlots: workers.freeWorkerSlots()
|
|
4448
4506
|
};
|
|
4449
|
-
if (isLiveNodeStatus(predecessor.status)) return {
|
|
4450
|
-
error: "successor-live",
|
|
4451
|
-
reason: `worker '${successorOf}' has not settled — end your turn until it does, then spawn its successor (steer_agent redirects a live worker instead)`,
|
|
4452
|
-
live: workers.liveWorkerCount(),
|
|
4453
|
-
freeSlots: workers.freeWorkerSlots()
|
|
4454
|
-
};
|
|
4455
4507
|
}
|
|
4456
4508
|
async function spawnWorkerHandler(ctx, raw) {
|
|
4457
|
-
const {
|
|
4509
|
+
const { spawn, workers } = ctx;
|
|
4458
4510
|
const a = obj(raw);
|
|
4459
4511
|
const key = a.key === void 0 ? void 0 : str(a.key, "key");
|
|
4460
4512
|
const resolvedProfile = await resolveSpawnedProfile(ctx, a.profile);
|
|
@@ -4480,7 +4532,6 @@ async function spawnWorkerHandler(ctx, raw) {
|
|
|
4480
4532
|
key,
|
|
4481
4533
|
continuity,
|
|
4482
4534
|
successorOf,
|
|
4483
|
-
preflightProfile: () => opts.resolveSpawnProfile ? detachedFrozen(opts.resolveSpawnProfile(profile)) : profile,
|
|
4484
4535
|
resourcesFromPath: resolved,
|
|
4485
4536
|
defaultLabel: typeof profile.name === "string" && profile.name.length > 0 ? profile.name : "worker"
|
|
4486
4537
|
});
|
|
@@ -4926,7 +4977,54 @@ function assembleTools(parts) {
|
|
|
4926
4977
|
analystRunContext: analysis.analystRunContext,
|
|
4927
4978
|
defineAnalyst: analysis.defineAnalyst
|
|
4928
4979
|
});
|
|
4929
|
-
return tools;
|
|
4980
|
+
return tools.map((tool) => timeCoordinationTool(bus, tool));
|
|
4981
|
+
}
|
|
4982
|
+
/** Record handler duration for every coordination tool call without changing its result. */
|
|
4983
|
+
function timeCoordinationTool(bus, tool) {
|
|
4984
|
+
return {
|
|
4985
|
+
...tool,
|
|
4986
|
+
handler: async (raw) => {
|
|
4987
|
+
const receivedAt = Date.now();
|
|
4988
|
+
try {
|
|
4989
|
+
const value = await tool.handler(raw);
|
|
4990
|
+
await recordToolTiming(bus, tool.name, receivedAt, true, value);
|
|
4991
|
+
return value;
|
|
4992
|
+
} catch (error) {
|
|
4993
|
+
await recordToolTiming(bus, tool.name, receivedAt, false, error);
|
|
4994
|
+
throw error;
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
};
|
|
4998
|
+
}
|
|
4999
|
+
async function recordToolTiming(bus, tool, receivedAt, ok, value) {
|
|
5000
|
+
try {
|
|
5001
|
+
await bus.publish({
|
|
5002
|
+
type: "tool-timing",
|
|
5003
|
+
call: {
|
|
5004
|
+
tool,
|
|
5005
|
+
receivedAt,
|
|
5006
|
+
elapsedMs: Math.max(0, Date.now() - receivedAt),
|
|
5007
|
+
responseBytes: responseUtf8Bytes(ok ? value : errorText(value)),
|
|
5008
|
+
ok
|
|
5009
|
+
}
|
|
5010
|
+
}, { queue: false });
|
|
5011
|
+
} catch (error) {
|
|
5012
|
+
console.error("Runtime could not record coordination tool timing", {
|
|
5013
|
+
tool,
|
|
5014
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5015
|
+
});
|
|
5016
|
+
}
|
|
5017
|
+
}
|
|
5018
|
+
function responseUtf8Bytes(value) {
|
|
5019
|
+
if (typeof value === "string") return Buffer.byteLength(value);
|
|
5020
|
+
try {
|
|
5021
|
+
return Buffer.byteLength(JSON.stringify(value) ?? "null");
|
|
5022
|
+
} catch {
|
|
5023
|
+
return Buffer.byteLength(String(value));
|
|
5024
|
+
}
|
|
5025
|
+
}
|
|
5026
|
+
function errorText(error) {
|
|
5027
|
+
return error instanceof Error ? error.message : String(error);
|
|
4930
5028
|
}
|
|
4931
5029
|
function managerSurface(parts, tools) {
|
|
4932
5030
|
const { opts, bus, state, ledger, questionLedger, spawnAdmission, analysis, settlements, messages, workers, waiting, intake, journal, peerMail, ackEnv, ready } = parts;
|
|
@@ -5135,4 +5233,4 @@ function createResumeReplay({ opts, bus, ledger, analysis, projectSettled }) {
|
|
|
5135
5233
|
}
|
|
5136
5234
|
export { downMessageRefusalReasons as a, createSteerAcknowledger as c, coordinationVerbNames as d, createFileRunContext as f, watchTrace as i, budgetOverspendText as l, withRunContext as m, createCoordinationToolsForManager as n, createEventBus as o, createInMemoryRunContext as p, defaultToolDetectors as r, createCancelAcknowledger as s, createCoordinationTools as t, normalizeAnalyzeOnSettle as u };
|
|
5137
5235
|
|
|
5138
|
-
//# sourceMappingURL=coordination-manager-
|
|
5236
|
+
//# sourceMappingURL=coordination-manager-sa_PkISw.js.map
|