@tangle-network/agent-runtime 7.0.0 → 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 +68 -0
- package/README.md +0 -3
- package/dist/{activation-Ba9IAgQ3.js → activation-Ce4zUcu8.js} +4 -4
- package/dist/{activation-Ba9IAgQ3.js.map → activation-Ce4zUcu8.js.map} +1 -1
- package/dist/{activation-DIkTEBWF.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-DQZ2u6L-.js → coordination-manager-sa_PkISw.js} +194 -148
- 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-DFLSVjFG.js → delegate-DhTkJIta.js} +3 -3
- package/dist/{delegate-DFLSVjFG.js.map → delegate-DhTkJIta.js.map} +1 -1
- package/dist/durable.d.ts +1 -1
- package/dist/durable.js +13 -12
- 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-rJTm_Tx8.js → failure-cause-CVB-YE88.js} +12 -8
- package/dist/{failure-cause-rJTm_Tx8.js.map → failure-cause-CVB-YE88.js.map} +1 -1
- 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-BolbYegO.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-Cs9IJ6Nk.d.ts → loop-runner-BGwhcn1p.d.ts} +2 -2
- package/dist/{loop-runner-C9W3T_3T.js → loop-runner-ChqK8kSz.js} +3 -3
- package/dist/{loop-runner-C9W3T_3T.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-BQFHjCtN.js → provision-supervisor-Dx4TXTMM.js} +8 -8
- package/dist/{provision-supervisor-BQFHjCtN.js.map → provision-supervisor-Dx4TXTMM.js.map} +1 -1
- package/dist/{run-cancellation-B84X8ZAP.js → run-cancellation-DYszFJtQ.js} +4 -4
- package/dist/{run-cancellation-B84X8ZAP.js.map → run-cancellation-DYszFJtQ.js.map} +1 -1
- package/dist/{run-state-Dh1bGERI.js → run-state-DHBoJjaF.js} +5 -5
- package/dist/{run-state-Dh1bGERI.js.map → run-state-DHBoJjaF.js.map} +1 -1
- package/dist/{runtime-C9F1PG2A.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-CKR9_6NR.js → search-executor-B9L8W_1O.js} +17 -46
- package/dist/search-executor-B9L8W_1O.js.map +1 -0
- package/dist/{server-Dh3SQGQT.js → server-BlDV8sj_.js} +32 -8
- package/dist/{server-Dh3SQGQT.js.map → server-BlDV8sj_.js.map} +1 -1
- package/dist/{settle-record-C6LdVvok.js → settle-record-WWQasnDq.js} +2 -2
- package/dist/{settle-record-C6LdVvok.js.map → settle-record-WWQasnDq.js.map} +1 -1
- package/dist/{snapshot-Cgj2Wzi6.js → snapshot-BKI_w3JD.js} +19 -5
- package/dist/snapshot-BKI_w3JD.js.map +1 -0
- package/dist/{structural-rollout-Dapf2aZY.js → structural-rollout-C1xxoWcN.js} +18 -54
- package/dist/structural-rollout-C1xxoWcN.js.map +1 -0
- package/dist/{supervise-xwl2D6q3.js → supervise-DWiSgPLB.js} +101 -111
- package/dist/supervise-DWiSgPLB.js.map +1 -0
- package/dist/{supervision-discovery-B47U8TH5.js → supervision-discovery-C9kfBLKy.js} +4 -4
- package/dist/{supervision-discovery-B47U8TH5.js.map → supervision-discovery-C9kfBLKy.js.map} +1 -1
- package/dist/{supervisor-gC-u_PRk.js → supervisor-Dpeu7rnZ.js} +206 -693
- package/dist/supervisor-Dpeu7rnZ.js.map +1 -0
- package/dist/{supervisor-accounting-DxLQ_TQe.js → supervisor-accounting-Bw4MJk-b.js} +434 -423
- 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-Dg350Bgz.js → tool-server-DYwRbi0I.js} +3 -3
- package/dist/{tool-server-Dg350Bgz.js.map → tool-server-DYwRbi0I.js.map} +1 -1
- package/dist/{top-web-BJLnFQdr.js → top-web-B3HOAtrZ.js} +9 -7
- package/dist/{top-web-BJLnFQdr.js.map → top-web-B3HOAtrZ.js.map} +1 -1
- package/dist/tui/bin.js +3 -3
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +2 -2
- package/dist/{types-Jg274chm.d.ts → types-C_qbnw9N.d.ts} +1335 -1413
- 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-DQZ2u6L-.js.map +0 -1
- package/dist/coordination-map-routing-CKRNZSaV.js.map +0 -1
- package/dist/errors-AzSuGI23.js.map +0 -1
- package/dist/graph-BjQF2syl.js +0 -579
- package/dist/graph-BjQF2syl.js.map +0 -1
- package/dist/graph-registry-7X2nrreR.js.map +0 -1
- package/dist/improve-BolbYegO.js.map +0 -1
- package/dist/model-policy-JOcg3NRs.js.map +0 -1
- package/dist/runtime-C9F1PG2A.js.map +0 -1
- package/dist/search-executor-CKR9_6NR.js.map +0 -1
- package/dist/snapshot-Cgj2Wzi6.js.map +0 -1
- package/dist/structural-rollout-Dapf2aZY.js.map +0 -1
- package/dist/supervise-xwl2D6q3.js.map +0 -1
- package/dist/supervisor-accounting-DxLQ_TQe.js.map +0 -1
- package/dist/supervisor-gC-u_PRk.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
|
/**
|
|
@@ -485,18 +487,62 @@ const BUDGET_FIELD = {
|
|
|
485
487
|
usd: "maxUsd"
|
|
486
488
|
};
|
|
487
489
|
// src/runtime/supervise/driver-control-acknowledgers.ts
|
|
488
|
-
/** The journal file `createFileRunContext` writes inside the run directory. The acknowledger
|
|
489
|
-
* reads it as EVIDENCE for the terminated-descendants set — the nested trees of a cancelled
|
|
490
|
-
* lead journal their terminal records there before the lead settles into this scope. */
|
|
491
490
|
const SPAWN_JOURNAL_FILE = "spawn-journal.jsonl";
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
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. */
|
|
500
546
|
function createSteerAcknowledger(deps) {
|
|
501
547
|
const iso = () => new Date(deps.now()).toISOString();
|
|
502
548
|
const awaiting = /* @__PURE__ */ new Map();
|
|
@@ -521,9 +567,29 @@ function createSteerAcknowledger(deps) {
|
|
|
521
567
|
worker: request.worker,
|
|
522
568
|
requestedAt: request.at
|
|
523
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
|
+
};
|
|
524
584
|
return { async pass(phase) {
|
|
585
|
+
const changed = steerChanged(phase);
|
|
586
|
+
if (phase !== "final" && !changed && steerIdle) return;
|
|
587
|
+
let waiting = false;
|
|
525
588
|
for (const request of readWorkerSteerRequests(deps.dir)) {
|
|
526
|
-
if (phase !== "final" && deps.signal?.aborted)
|
|
589
|
+
if (phase !== "final" && deps.signal?.aborted) {
|
|
590
|
+
steerIdle = false;
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
527
593
|
const rootRequest = request.worker === deps.ownerId && deps.deliverRoot !== void 0;
|
|
528
594
|
if (phase === "boundary" && !rootRequest) continue;
|
|
529
595
|
if (!rootRequest && !isDirectChildNodeId(deps, request.worker)) continue;
|
|
@@ -547,7 +613,10 @@ function createSteerAcknowledger(deps) {
|
|
|
547
613
|
});
|
|
548
614
|
continue;
|
|
549
615
|
}
|
|
550
|
-
if (rootRequest && deps.deliverRootReady !== void 0 && !deps.deliverRootReady())
|
|
616
|
+
if (rootRequest && deps.deliverRootReady !== void 0 && !deps.deliverRootReady()) {
|
|
617
|
+
waiting = true;
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
551
620
|
if (!claimWorkerSteerDelivery(deps.dir, {
|
|
552
621
|
...base(request),
|
|
553
622
|
effect: "unknown",
|
|
@@ -596,17 +665,9 @@ function createSteerAcknowledger(deps) {
|
|
|
596
665
|
});
|
|
597
666
|
}
|
|
598
667
|
}
|
|
668
|
+
if (phase === "turn") steerIdle = !waiting;
|
|
599
669
|
} };
|
|
600
670
|
}
|
|
601
|
-
/**
|
|
602
|
-
* The OPERATOR-facing sentence for a steer outcome, written into the durable acknowledgement file.
|
|
603
|
-
*
|
|
604
|
-
* Deliberately separate from `downMessageRefusalReasons`, which is the MANAGER-facing sentence: one
|
|
605
|
-
* says what happened for someone reading the run afterwards, the other tells a model what to do
|
|
606
|
-
* next, and merging them would make one audience read the other's copy. They must nonetheless cover
|
|
607
|
-
* the SAME outcomes, so `tests/kernel/refusal-reasons.test.ts` holds both maps total over
|
|
608
|
-
* `DownMessageDeliveryOutcome` — a new code cannot land in only one.
|
|
609
|
-
*/
|
|
610
671
|
function steerAcknowledgementDetail(outcome) {
|
|
611
672
|
switch (outcome.outcome) {
|
|
612
673
|
case "delivered": return "the owning manager delivered the steer to the exact live worker";
|
|
@@ -617,42 +678,32 @@ function steerAcknowledgementDetail(outcome) {
|
|
|
617
678
|
case "runtime-error": return "delivery outcome is unknown after a runtime error";
|
|
618
679
|
}
|
|
619
680
|
}
|
|
620
|
-
/**
|
|
621
|
-
* The worker-cancel ACKNOWLEDGER — the runtime-side half of `run-layout`'s `cancelWorker`
|
|
622
|
-
* contract. Router managers check between turns; native managers observe throughout their invocation.
|
|
623
|
-
* Every manager with a `controlDir` mounts one;
|
|
624
|
-
* OWNERSHIP keeps them from colliding: a request naming a node id is owned by the manager whose
|
|
625
|
-
* own id is that node's parent, and a label/profile-name reference is owned by the `'run'`-scoped
|
|
626
|
-
* (root) manager only — so exactly one acknowledger can ever apply one operation.
|
|
627
|
-
*
|
|
628
|
-
* Two-phase, honestly reported: `cancel_requested` is written the moment a live worker's abort is
|
|
629
|
-
* issued (through the per-child abort chain the scope already owns, so siblings are untouched);
|
|
630
|
-
* `cancelled` is written only when that worker's settlement is DELIVERED on the settle path with
|
|
631
|
-
* a terminal `down`, and then the record names every subtree node id proven terminated. A worker
|
|
632
|
-
* that already settled — or that settles `done` despite the abort — records `not_live`; a
|
|
633
|
-
* reference matching nothing this manager owns stays pending (`cancelWorker` reports it
|
|
634
|
-
* `unknown`). No path reports success for a missing worker.
|
|
635
|
-
*
|
|
636
|
-
* Expiry is run end, not a clock: `finish()` (after the final post-drain pass) writes `not_live`
|
|
637
|
-
* for every owned request never applied and `unknown` for an issued abort whose settle the run
|
|
638
|
-
* ended too soon to observe. A pending request can therefore never outlive its run and abort a
|
|
639
|
-
* future spawn that happens to reuse a label.
|
|
640
|
-
*
|
|
641
|
-
* Idempotency is a lookup, in-process and across processes: an operation with a durable
|
|
642
|
-
* acknowledgement is returned as-is and never re-applied.
|
|
643
|
-
*/
|
|
644
681
|
function createCancelAcknowledger(deps) {
|
|
645
682
|
const tracked = /* @__PURE__ */ new Map();
|
|
646
683
|
let runTracked;
|
|
647
684
|
const abortIssuedAt = /* @__PURE__ */ new Map();
|
|
648
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
|
+
};
|
|
649
702
|
const write = (record) => {
|
|
650
703
|
writeWorkerCancellation(deps.dir, record);
|
|
651
704
|
tracked.set(record.operationId, record);
|
|
705
|
+
watch(record);
|
|
652
706
|
};
|
|
653
|
-
/** Whether this acknowledger owns `ref`. A node id deeper in this subtree belongs to the nested
|
|
654
|
-
* manager that parents it; anything that is not a node id under this manager is a
|
|
655
|
-
* label/profile-name reference, owned by the `'run'`-scoped manager alone. */
|
|
656
707
|
const owned = (ref) => {
|
|
657
708
|
if (isDirectChildNodeId(deps, ref)) return true;
|
|
658
709
|
if (deps.controlScope !== "run") return false;
|
|
@@ -695,15 +746,13 @@ function createCancelAcknowledger(deps) {
|
|
|
695
746
|
terminated: []
|
|
696
747
|
});
|
|
697
748
|
};
|
|
698
|
-
/**
|
|
699
|
-
* journal record at/after the abort was issued. Union with what the record already names, so
|
|
700
|
-
* 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. */
|
|
701
750
|
const provenTerminated = (record, workerId) => {
|
|
702
751
|
const since = abortIssuedAt.get(record.operationId) ?? record.observedAt;
|
|
703
752
|
return [.../* @__PURE__ */ new Set([
|
|
704
753
|
...record.terminated,
|
|
705
754
|
workerId,
|
|
706
|
-
...
|
|
755
|
+
...descendantsSince(deaths, workerId, since)
|
|
707
756
|
])].sort();
|
|
708
757
|
};
|
|
709
758
|
const reconcile = (record) => {
|
|
@@ -729,10 +778,6 @@ function createCancelAcknowledger(deps) {
|
|
|
729
778
|
detail: `worker '${workerId}' settled done despite the abort request; nothing was terminated`
|
|
730
779
|
});
|
|
731
780
|
};
|
|
732
|
-
/** Re-scan a `cancelled` record while the manager still turns: a descendant whose teardown
|
|
733
|
-
* journals after the lead's settle joins the set on a later pass instead of being lost. Only
|
|
734
|
-
* a grown set is re-written; the window needs the in-process abort instant, so a record a
|
|
735
|
-
* PRIOR process closed stays as that process proved it. */
|
|
736
781
|
const regrow = (record) => {
|
|
737
782
|
const workerId = record.workerId;
|
|
738
783
|
if (workerId === void 0 || !abortIssuedAt.has(record.operationId)) return;
|
|
@@ -743,36 +788,49 @@ function createCancelAcknowledger(deps) {
|
|
|
743
788
|
terminated
|
|
744
789
|
});
|
|
745
790
|
};
|
|
746
|
-
/**
|
|
747
|
-
* The RUN-scoped request: seen once, `cancel_requested` written the moment the run's cascading
|
|
748
|
-
* abort is issued through the one controller the run already has. The `supervise()` settle path
|
|
749
|
-
* records what the run then actually did — this manager cannot observe its own tree's terminal
|
|
750
|
-
* state from inside `act`.
|
|
751
|
-
*
|
|
752
|
-
* Applied only at a TURN boundary, never on the final post-drain pass: by then the driver has
|
|
753
|
-
* finished and drained, so a root abort could only void work that is already delivered. A
|
|
754
|
-
* request that arrives that late expires in `finish()` instead — it terminated nothing.
|
|
755
|
-
*/
|
|
756
791
|
const passRun = () => {
|
|
757
792
|
if (deps.controlScope !== "run" || deps.abortRun === void 0) return;
|
|
758
793
|
if (runTracked !== void 0) return;
|
|
759
794
|
runTracked = applyRunCancellation(deps.dir, deps.abortRun, iso);
|
|
760
795
|
};
|
|
761
|
-
const
|
|
762
|
-
|
|
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;
|
|
763
806
|
for (const request of readWorkerCancelRequests(deps.dir)) {
|
|
764
|
-
if (!owned(request.worker)) continue;
|
|
765
|
-
|
|
766
|
-
if (record === void 0)
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
if (record === void 0) {
|
|
771
|
-
if (phase === "turn") apply(request);
|
|
772
|
-
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);
|
|
773
813
|
}
|
|
774
|
-
|
|
775
|
-
|
|
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);
|
|
776
834
|
}
|
|
777
835
|
};
|
|
778
836
|
return {
|
|
@@ -814,43 +872,6 @@ function createCancelAcknowledger(deps) {
|
|
|
814
872
|
}
|
|
815
873
|
};
|
|
816
874
|
}
|
|
817
|
-
/**
|
|
818
|
-
* Subtree node ids with a terminal `down`/`cancelled` journal record at or after `sinceIso` —
|
|
819
|
-
* the abort-issue instant (the acknowledger's own `observedAt` on the `cancel_requested` record,
|
|
820
|
-
* runtime clock), never the client's `requestedAt` — read from the durable spawn journal beside
|
|
821
|
-
* the run layout. The set is proven at acknowledgement time and is approximate about post-abort
|
|
822
|
-
* causation: a descendant that died of its OWN cause after the abort was issued is
|
|
823
|
-
* indistinguishable from the cascade and may be included; one whose teardown journals late joins
|
|
824
|
-
* on a later acknowledger pass; a teardown journal still absent when the run ends is absent from
|
|
825
|
-
* the set. Ids are hierarchical (`parent:sN`), so `${nodeId}:` prefixes exactly the subtree.
|
|
826
|
-
* Tolerant of a missing or partially-written journal: evidence that cannot be read names fewer
|
|
827
|
-
* nodes, never wrong ones.
|
|
828
|
-
*/
|
|
829
|
-
function terminatedDescendants(dir, nodeId, sinceIso) {
|
|
830
|
-
let raw;
|
|
831
|
-
try {
|
|
832
|
-
raw = readFileSync(join(dir, SPAWN_JOURNAL_FILE), "utf8");
|
|
833
|
-
} catch {
|
|
834
|
-
return [];
|
|
835
|
-
}
|
|
836
|
-
const prefix = `${nodeId}:`;
|
|
837
|
-
const ids = /* @__PURE__ */ new Set();
|
|
838
|
-
for (const line of raw.split("\n")) {
|
|
839
|
-
const trimmed = line.trim();
|
|
840
|
-
if (!trimmed) continue;
|
|
841
|
-
try {
|
|
842
|
-
for (const event of spawnJournalRecordEvents(JSON.parse(trimmed))) {
|
|
843
|
-
if (event === void 0) continue;
|
|
844
|
-
if (!(event.kind === "settled" && event.status === "down" || event.kind === "cancelled")) continue;
|
|
845
|
-
if (typeof event.id !== "string" || !event.id.startsWith(prefix)) continue;
|
|
846
|
-
if (typeof event.at !== "string" || event.at < sinceIso) continue;
|
|
847
|
-
ids.add(event.id);
|
|
848
|
-
}
|
|
849
|
-
} catch {}
|
|
850
|
-
}
|
|
851
|
-
return [...ids].sort();
|
|
852
|
-
}
|
|
853
|
-
/** A direct child has exactly one generated spawn segment below its owner. */
|
|
854
875
|
function isDirectChildNodeId(owner, ref) {
|
|
855
876
|
return ref.startsWith(`${owner.ownerId}:s`) && /^s\d+$/.test(ref.slice(owner.ownerId.length + 1));
|
|
856
877
|
}
|
|
@@ -1867,15 +1888,13 @@ function mountGraphsTools({ opts, tools, admitSpawn }) {
|
|
|
1867
1888
|
error: "invalid-graph",
|
|
1868
1889
|
reason: prepared.reason
|
|
1869
1890
|
};
|
|
1870
|
-
const profile = detachedFrozen(prepared.profile);
|
|
1871
1891
|
return admitSpawn({
|
|
1872
|
-
profile,
|
|
1892
|
+
profile: detachedFrozen(prepared.profile),
|
|
1873
1893
|
args: a,
|
|
1874
1894
|
task: deliverable,
|
|
1875
1895
|
key,
|
|
1876
1896
|
continuity: { continuity: "fresh" },
|
|
1877
1897
|
successorOf: void 0,
|
|
1878
|
-
preflightProfile: () => opts.resolveSpawnProfile ? detachedFrozen(opts.resolveSpawnProfile(profile)) : profile,
|
|
1879
1898
|
resourcesFromPath: [],
|
|
1880
1899
|
defaultLabel: `graph:${prepared.root}`,
|
|
1881
1900
|
accepted: { graph: {
|
|
@@ -3025,7 +3044,6 @@ async function spawnNode(state, marker, profile, task, key, continuity, traversa
|
|
|
3025
3044
|
key,
|
|
3026
3045
|
continuity,
|
|
3027
3046
|
successorOf: state.settledWorker.get(marker.node),
|
|
3028
|
-
preflightProfile: () => state.opts.resolveSpawnProfile ? detachedFrozen(state.opts.resolveSpawnProfile(profile)) : profile,
|
|
3029
3047
|
resourcesFromPath: [],
|
|
3030
3048
|
defaultLabel: marker.node,
|
|
3031
3049
|
route: Object.freeze({ ...marker })
|
|
@@ -3685,14 +3703,21 @@ function resolveContinuity(state, requested, profileName, key) {
|
|
|
3685
3703
|
* assignment, budget reservation, `Scope.spawn` — is synchronous and commits state.
|
|
3686
3704
|
* Returns the refusal body, or `undefined` when the spawn may proceed.
|
|
3687
3705
|
*/
|
|
3688
|
-
|
|
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) {
|
|
3689
3714
|
const { opts } = state;
|
|
3690
3715
|
if (!opts.preflightSpawn) return void 0;
|
|
3691
|
-
const { key } =
|
|
3692
|
-
const refusal = await opts.preflightSpawn(
|
|
3693
|
-
|
|
3716
|
+
const { key, resources, ...rest } = spawn;
|
|
3717
|
+
const refusal = await opts.preflightSpawn(effective, {
|
|
3718
|
+
...rest,
|
|
3694
3719
|
...key !== void 0 ? { key } : {},
|
|
3695
|
-
|
|
3720
|
+
...resources !== void 0 ? { resources } : {}
|
|
3696
3721
|
});
|
|
3697
3722
|
if (!refusal) return void 0;
|
|
3698
3723
|
state.preflightCounts[refusal.cause] += 1;
|
|
@@ -3711,7 +3736,14 @@ async function admitSpawn(state, input) {
|
|
|
3711
3736
|
const a = input.args;
|
|
3712
3737
|
const task = detachedFrozen(input.task);
|
|
3713
3738
|
const label = typeof a.label === "string" ? a.label : input.defaultLabel;
|
|
3714
|
-
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
|
+
});
|
|
3715
3747
|
if (refused !== void 0) return refused;
|
|
3716
3748
|
const budget = Object.freeze(a.budget === void 0 ? opts.perWorker : mergeBudget(opts.perWorker, a.budget));
|
|
3717
3749
|
const assignmentId = key !== void 0 ? `key:${key}` : `ordinal:${state.unkeyedAssignment.next++}`;
|
|
@@ -3723,6 +3755,7 @@ async function admitSpawn(state, input) {
|
|
|
3723
3755
|
task,
|
|
3724
3756
|
label,
|
|
3725
3757
|
...key !== void 0 ? { key } : {},
|
|
3758
|
+
...resources !== void 0 ? { resources } : {},
|
|
3726
3759
|
continuity: continuity.continuity,
|
|
3727
3760
|
...continuity.continuity === "resume" ? { resume: continuity.resume } : {},
|
|
3728
3761
|
...successorOf !== void 0 ? { successorOf } : {},
|
|
@@ -3730,7 +3763,7 @@ async function admitSpawn(state, input) {
|
|
|
3730
3763
|
...input.map !== void 0 ? { map: input.map } : {},
|
|
3731
3764
|
...input.route !== void 0 ? { route: input.route } : {}
|
|
3732
3765
|
});
|
|
3733
|
-
const res = opts.scope.spawn(() => opts.makeWorkerAgent(
|
|
3766
|
+
const res = opts.scope.spawn(() => opts.makeWorkerAgent(effective, context), task, {
|
|
3734
3767
|
budget,
|
|
3735
3768
|
label,
|
|
3736
3769
|
assignmentId,
|
|
@@ -4373,7 +4406,7 @@ function spawnWorkerTool(ctx) {
|
|
|
4373
4406
|
const { profileTable } = ctx;
|
|
4374
4407
|
return {
|
|
4375
4408
|
name: "spawn_worker",
|
|
4376
|
-
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."),
|
|
4377
4410
|
inputSchema: {
|
|
4378
4411
|
type: "object",
|
|
4379
4412
|
properties: {
|
|
@@ -4394,9 +4427,29 @@ function spawnWorkerTool(ctx) {
|
|
|
4394
4427
|
},
|
|
4395
4428
|
successorOf: {
|
|
4396
4429
|
type: "string",
|
|
4397
|
-
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`."
|
|
4398
4431
|
},
|
|
4399
|
-
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
|
+
}
|
|
4400
4453
|
},
|
|
4401
4454
|
required: ["profile", "task"]
|
|
4402
4455
|
},
|
|
@@ -4451,15 +4504,9 @@ function successorRefusal({ opts, spawn, workers }, successorOf) {
|
|
|
4451
4504
|
live: workers.liveWorkerCount(),
|
|
4452
4505
|
freeSlots: workers.freeWorkerSlots()
|
|
4453
4506
|
};
|
|
4454
|
-
if (isLiveNodeStatus(predecessor.status)) return {
|
|
4455
|
-
error: "successor-live",
|
|
4456
|
-
reason: `worker '${successorOf}' has not settled — end your turn until it does, then spawn its successor (steer_agent redirects a live worker instead)`,
|
|
4457
|
-
live: workers.liveWorkerCount(),
|
|
4458
|
-
freeSlots: workers.freeWorkerSlots()
|
|
4459
|
-
};
|
|
4460
4507
|
}
|
|
4461
4508
|
async function spawnWorkerHandler(ctx, raw) {
|
|
4462
|
-
const {
|
|
4509
|
+
const { spawn, workers } = ctx;
|
|
4463
4510
|
const a = obj(raw);
|
|
4464
4511
|
const key = a.key === void 0 ? void 0 : str(a.key, "key");
|
|
4465
4512
|
const resolvedProfile = await resolveSpawnedProfile(ctx, a.profile);
|
|
@@ -4485,7 +4532,6 @@ async function spawnWorkerHandler(ctx, raw) {
|
|
|
4485
4532
|
key,
|
|
4486
4533
|
continuity,
|
|
4487
4534
|
successorOf,
|
|
4488
|
-
preflightProfile: () => opts.resolveSpawnProfile ? detachedFrozen(opts.resolveSpawnProfile(profile)) : profile,
|
|
4489
4535
|
resourcesFromPath: resolved,
|
|
4490
4536
|
defaultLabel: typeof profile.name === "string" && profile.name.length > 0 ? profile.name : "worker"
|
|
4491
4537
|
});
|
|
@@ -5187,4 +5233,4 @@ function createResumeReplay({ opts, bus, ledger, analysis, projectSettled }) {
|
|
|
5187
5233
|
}
|
|
5188
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 };
|
|
5189
5235
|
|
|
5190
|
-
//# sourceMappingURL=coordination-manager-
|
|
5236
|
+
//# sourceMappingURL=coordination-manager-sa_PkISw.js.map
|