@tangle-network/agent-runtime 0.259.1 → 0.262.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.
Files changed (73) hide show
  1. package/dist/{activation-Btw2npV2.js → activation-C0AoYRgS.js} +3 -3
  2. package/dist/{activation-Btw2npV2.js.map → activation-C0AoYRgS.js.map} +1 -1
  3. package/dist/{activation-Cus2oZaT.d.ts → activation-CozZXBTg.d.ts} +2 -2
  4. package/dist/agent.d.ts +2 -2
  5. package/dist/agent.js +2 -2
  6. package/dist/{bundle-DXrBPEFw.js → bundle-CvLGRVO-.js} +2 -2
  7. package/dist/{bundle-DXrBPEFw.js.map → bundle-CvLGRVO-.js.map} +1 -1
  8. package/dist/candidate-execution/index.js +5 -4
  9. package/dist/candidate-execution/index.js.map +1 -1
  10. package/dist/{coordination-driver-BmtrkNPu.js → coordination-driver-COGC8FK2.js} +377 -32
  11. package/dist/coordination-driver-COGC8FK2.js.map +1 -0
  12. package/dist/{delegate-DJgmZZKH.js → delegate-BC7Au73v.js} +2 -2
  13. package/dist/{delegate-DJgmZZKH.js.map → delegate-BC7Au73v.js.map} +1 -1
  14. package/dist/durable.d.ts +285 -57
  15. package/dist/durable.js +637 -108
  16. package/dist/durable.js.map +1 -1
  17. package/dist/{graph-BKRvWzHx.js → graph-DgODOGWN.js} +4 -3
  18. package/dist/graph-DgODOGWN.js.map +1 -0
  19. package/dist/{improvement-cycle-D0Os0Hg_.js → improvement-cycle-DirqO-fX.js} +8 -7
  20. package/dist/improvement-cycle-DirqO-fX.js.map +1 -0
  21. package/dist/{index-sGOO254Q.d.ts → index-B8tXCisZ.d.ts} +251 -293
  22. package/dist/index.d.ts +6 -6
  23. package/dist/index.js +9 -9
  24. package/dist/intelligence.d.ts +3 -3
  25. package/dist/intelligence.js +7 -6
  26. package/dist/intelligence.js.map +1 -1
  27. package/dist/kernel.d.ts +4 -4
  28. package/dist/kernel.js +9 -9
  29. package/dist/{loop-runner-bin-DAU4rNIL.d.ts → loop-runner-bin-BaZd1XIm.d.ts} +3 -3
  30. package/dist/{loop-runner-bin-pRlDgm1i.js → loop-runner-bin-C9P1ELVv.js} +3 -3
  31. package/dist/{loop-runner-bin-pRlDgm1i.js.map → loop-runner-bin-C9P1ELVv.js.map} +1 -1
  32. package/dist/loop-runner-bin.d.ts +1 -1
  33. package/dist/loop-runner-bin.js +1 -1
  34. package/dist/mcp/bin.js +3 -3
  35. package/dist/mcp/index.d.ts +6 -6
  36. package/dist/mcp/index.js +4 -4
  37. package/dist/{openai-tools-BsqD1_Zr.d.ts → openai-tools-CHwN_S24.d.ts} +2 -2
  38. package/dist/{prepare-RuaAclli.js → prepare-oHUQdC5-.js} +22 -452
  39. package/dist/prepare-oHUQdC5-.js.map +1 -0
  40. package/dist/profile-D3eXNBQV.js +438 -0
  41. package/dist/profile-D3eXNBQV.js.map +1 -0
  42. package/dist/profiles.d.ts +2 -2
  43. package/dist/{protected-model-port-BFhSgMAy.js → protected-model-port-DqF0qDU6.js} +4 -3
  44. package/dist/{protected-model-port-BFhSgMAy.js.map → protected-model-port-DqF0qDU6.js.map} +1 -1
  45. package/dist/{provision-supervisor-B9tf4soF.js → provision-supervisor-9FMwo-Es.js} +3 -3
  46. package/dist/{provision-supervisor-B9tf4soF.js.map → provision-supervisor-9FMwo-Es.js.map} +1 -1
  47. package/dist/{runtime-DKiucqGX.js → runtime-BXWVW51r.js} +218 -20
  48. package/dist/runtime-BXWVW51r.js.map +1 -0
  49. package/dist/{server-DIsiQ6mu.js → server-6g6KFwUC.js} +3 -3
  50. package/dist/{server-DIsiQ6mu.js.map → server-6g6KFwUC.js.map} +1 -1
  51. package/dist/{stream-agent-turn-DRTFLphI.d.ts → stream-agent-turn-u28hoxuR.d.ts} +2 -2
  52. package/dist/{structural-rollout-BIBxgW64.js → structural-rollout-WEfWpjub.js} +2 -2
  53. package/dist/{structural-rollout-BIBxgW64.js.map → structural-rollout-WEfWpjub.js.map} +1 -1
  54. package/dist/{substrate-BToFBpfh.d.ts → substrate-BeQiXkpa.d.ts} +2 -2
  55. package/dist/{supervise-DsQjhLN-.js → supervise-BeAI8-On.js} +295 -51
  56. package/dist/supervise-BeAI8-On.js.map +1 -0
  57. package/dist/{supervisor-CJyzUjc7.js → supervisor-BGGvnXvV.js} +243 -24
  58. package/dist/{supervisor-CJyzUjc7.js.map → supervisor-BGGvnXvV.js.map} +1 -1
  59. package/dist/testing.d.ts +2 -2
  60. package/dist/testing.js +14 -14
  61. package/dist/tui/index.d.ts +1 -1
  62. package/dist/tui/index.js +1 -1
  63. package/dist/{types-ChewVlpE.d.ts → types-CP3iQ8Ji.d.ts} +376 -4
  64. package/dist/{workspace-archive-DQGFwvM6.js → workspace-archive-C9lgf77y.js} +11 -11
  65. package/dist/workspace-archive-C9lgf77y.js.map +1 -0
  66. package/package.json +5 -5
  67. package/dist/coordination-driver-BmtrkNPu.js.map +0 -1
  68. package/dist/graph-BKRvWzHx.js.map +0 -1
  69. package/dist/improvement-cycle-D0Os0Hg_.js.map +0 -1
  70. package/dist/prepare-RuaAclli.js.map +0 -1
  71. package/dist/runtime-DKiucqGX.js.map +0 -1
  72. package/dist/supervise-DsQjhLN-.js.map +0 -1
  73. package/dist/workspace-archive-DQGFwvM6.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { $r as readCommittedJsonLines, Cn as runBrainLoop, Kt as createInbox, Ot as parseWorkerToolTraceArtifact, Qi as addResourceSpend, Qr as prepareJsonlAppend, R as scopeRetainedOwnerResourceReader, Ri as chargedTokens, U as resolveSpawnResourcePaths, Ui as promptCacheTokenClasses, Xn as resolveRedactor, Yi as unmeteredSpend, Zt as createPeerMailbox, _t as FileSpawnJournal, a as pickBestDelivered, ea as withBudgetResources, ei as writeAllBytes, et as errMessage, g as withDriverExecutor, gt as FileResultBlobStore, jt as assertValidBudget, kt as workerTraceAnalysisStore, li as providerAttemptEvidence, nn as isTerminalNodeStatus, nt as freeSlots, o as runFinalizer, r as bestDelivered, s as runTree, tn as isLiveNodeStatus, ut as createExecutorRegistry, vt as InMemoryResultBlobStore, x as meterRuntimeOwnedProviderAttempt, xi as detachedFrozen, yt as InMemorySpawnJournal } from "./supervisor-CJyzUjc7.js";
1
+ import { Ct as InMemorySpawnJournal, Dn as runBrainLoop, Ei as detachedFrozen, Ft as assertValidBudget, H as scopeRetainedOwnerResourceReader, Ji as promptCacheTokenClasses, Mt as parseWorkerToolTraceArtifact, Nt as workerTraceAnalysisStore, St as InMemoryResultBlobStore, Ui as chargedTokens, Xt as createInbox, a as pickBestDelivered, aa as withBudgetResources, ai as writeAllBytes, an as isLiveNodeStatus, bt as FileResultBlobStore, ea as unmeteredSpend, er as resolveRedactor, ii as readCommittedJsonLines, it as errMessage, mi as providerAttemptEvidence, mt as createExecutorRegistry, o as runFinalizer, on as isTerminalNodeStatus, ot as freeSlots, q as resolveSpawnResourcePaths, r as bestDelivered, ra as addResourceSpend, ri as prepareJsonlAppend, s as runTree, tn as createPeerMailbox, v as withDriverExecutor, w as meterRuntimeOwnedProviderAttempt, xt as FileSpawnJournal } from "./supervisor-BGGvnXvV.js";
2
2
  import { f as RuntimeRunStateError, m as ValidationError } from "./errors-DodWX-cb.js";
3
3
  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-vwd4SwX_.js";
4
4
  import { agentProfileSchema, canonicalCandidateDigest } from "@tangle-network/agent-interface";
@@ -74,6 +74,12 @@ function createEventBus(now = Date.now) {
74
74
  }
75
75
  return best;
76
76
  };
77
+ const pullRecord = (kinds) => {
78
+ const i = bestIndex(kinds);
79
+ if (i < 0) return void 0;
80
+ pulled++;
81
+ return queue.splice(i, 1)[0];
82
+ };
77
83
  return {
78
84
  async publish(event, opts) {
79
85
  const record = staged.get(event) ?? {
@@ -92,10 +98,11 @@ function createEventBus(now = Date.now) {
92
98
  return record;
93
99
  },
94
100
  pull(kinds) {
95
- const i = bestIndex(kinds);
96
- if (i < 0) return void 0;
97
- pulled++;
98
- return queue.splice(i, 1)[0]?.event;
101
+ return pullRecord(kinds)?.event;
102
+ },
103
+ pullRecord,
104
+ queued(kinds) {
105
+ return queue.filter((r) => matches(r, kinds));
99
106
  },
100
107
  subscribe(handler) {
101
108
  subscribers.push(handler);
@@ -498,7 +505,8 @@ const journalEventKinds = [
498
505
  "delivery-attempt",
499
506
  "mail",
500
507
  "escalation",
501
- "analyst-defined"
508
+ "analyst-defined",
509
+ "acknowledgement"
502
510
  ];
503
511
  /** The reserved coordination verb names — the complete set `createCoordinationTools` can emit
504
512
  * (the analyst pair is conditional but still reserved). A driver's extra WORK tools must not
@@ -522,6 +530,7 @@ const coordinationVerbNames = [
522
530
  "ask_parent",
523
531
  "submit_result",
524
532
  "stop",
533
+ "report_blocked",
525
534
  "read_journal",
526
535
  "list_analysts",
527
536
  "run_analyst",
@@ -713,6 +722,33 @@ function spawnProfileArg() {
713
722
  }).properties));
714
723
  return spawnProfileArgCache;
715
724
  }
725
+ /** `spawn_worker`'s `profile` argument when the run has a profiles table: one of the table's names,
726
+ * listed with each entry's description and whether a sealed verdict promoted it, or a profile the
727
+ * manager authors. Without a table the argument is the authored shape alone, byte for byte. */
728
+ function spawnProfileArgWithTable(profiles) {
729
+ const menu = [...profiles].map(([name, entry]) => {
730
+ return `- '${name}'${typeof entry.profile.description === "string" && entry.profile.description.length > 0 ? ` — ${entry.profile.description}` : ""} (${entry.promotion ? `promoted by sealed play ${JSON.stringify(entry.promotion.experiment.spec.id)}` : "exploratory"})`;
731
+ });
732
+ return { anyOf: [{
733
+ type: "string",
734
+ enum: [...profiles.keys()],
735
+ description: `The name of a profile in this run's profiles table. The runtime runs that exact profile, so do not retype it; other profile fields cannot be added to a name. Promoted entries beat their control in a sealed comparison; exploratory ones have no verdict yet.\n${menu.join("\n")}`
736
+ }, spawnProfileArg()] };
737
+ }
738
+ /** Why `spawn_worker` cannot use this `profile` argument against the profiles table, or
739
+ * `undefined` when it can. A name must be in the table. An authored profile must not take a table
740
+ * name: continuity and every per-name record key on `profile.name`, so one name must mean one
741
+ * profile. Without a table nothing is refused here, and the canonical schema answers as before. */
742
+ function profileTableRefusal(table, profile) {
743
+ if (table === void 0) return void 0;
744
+ if (typeof profile === "string") {
745
+ if (table.has(profile)) return void 0;
746
+ return `profile ${JSON.stringify(profile)} is not in this run's profiles table, which holds ${[...table.keys()].map((name) => JSON.stringify(name)).join(", ")}`;
747
+ }
748
+ const name = typeof profile === "object" && profile !== null ? profile.name : void 0;
749
+ if (typeof name !== "string" || !table.has(name)) return void 0;
750
+ return `profile.name ${JSON.stringify(name)} is a profiles-table entry: pass profile: ${JSON.stringify(name)} to run that exact profile, or give the profile you wrote another name`;
751
+ }
716
752
  const BUDGET_FIELD = {
717
753
  tokens: "maxTokens",
718
754
  iterations: "maxIterations",
@@ -763,6 +799,7 @@ function createCoordinationTools(opts) {
763
799
  /** Internal manager binding; its lifetime fences delivery without cancelling the worker scope. */
764
800
  function createCoordinationToolsForManager(opts, lifetime) {
765
801
  const deliverable = opts.deliverable;
802
+ const profileTable = opts.profiles !== void 0 && opts.profiles.size > 0 ? opts.profiles : void 0;
766
803
  const readWorkerOutput = createWorkerOutputReader(opts.blobs);
767
804
  const priorSubmission = deliverable === void 0 ? void 0 : opts.priorJournal?.find((record) => record.event.type === "submission");
768
805
  let stopped = priorSubmission !== void 0;
@@ -770,6 +807,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
770
807
  let stopNotified = false;
771
808
  let submitted = priorSubmission === void 0 ? void 0 : detachedFrozen({ result: priorSubmission.event.result });
772
809
  let submissionInFlight;
810
+ let blockedEvidence;
773
811
  let questionSeq = 0;
774
812
  const ledger = [];
775
813
  const questions = [...opts.priorQuestions ?? []];
@@ -856,6 +894,27 @@ function createCoordinationToolsForManager(opts, lifetime) {
856
894
  });
857
895
  return readyInFlight;
858
896
  };
897
+ const deliveries = [];
898
+ let driverAttempt;
899
+ let journalReadTo = 0;
900
+ let lastRejection;
901
+ const flushedAnalystRuns = /* @__PURE__ */ new Set();
902
+ const eventWorker = (event) => event.type === "settled" ? event.worker.id : event.type === "finding" ? event.finding.fromWorker : event.type === "question" ? event.question.from : void 0;
903
+ const acknowledge = async (targets, by) => {
904
+ const fresh = targets.filter((delivery) => !delivery.acknowledged);
905
+ if (fresh.length === 0) return [];
906
+ const seqs = fresh.map((delivery) => delivery.record.seq);
907
+ await bus.publish({
908
+ type: "acknowledgement",
909
+ acknowledgement: detachedFrozen({
910
+ seqs,
911
+ by,
912
+ ...driverAttempt === void 0 ? {} : { attempt: driverAttempt }
913
+ })
914
+ }, { queue: false });
915
+ for (const delivery of fresh) delivery.acknowledged = true;
916
+ return seqs;
917
+ };
859
918
  const urgencyPriority = (u) => u === "blocks-run" ? 20 : u === "blocks-step" ? 10 : 0;
860
919
  const str = (v, field) => {
861
920
  if (typeof v !== "string" || v.length === 0) throw new Error(`coordination tools: "${field}" must be a non-empty string`);
@@ -1118,6 +1177,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
1118
1177
  await bus.publish(pending.event);
1119
1178
  if (pending.analystRun) {
1120
1179
  analystRuns.delete(pending.worker.id);
1180
+ flushedAnalystRuns.add(pending.worker.id);
1121
1181
  unwatchWorker(pending.worker.id);
1122
1182
  pendingSettlement = void 0;
1123
1183
  const { route } = pending.analystRun;
@@ -1369,6 +1429,10 @@ function createCoordinationToolsForManager(opts, lifetime) {
1369
1429
  type: "analyst-defined",
1370
1430
  ...ev.analyst
1371
1431
  };
1432
+ if (ev.type === "acknowledgement") return {
1433
+ type: "acknowledgement",
1434
+ ...ev.acknowledgement
1435
+ };
1372
1436
  return {
1373
1437
  type: ev.type,
1374
1438
  ...ev.down
@@ -1579,9 +1643,11 @@ function createCoordinationToolsForManager(opts, lifetime) {
1579
1643
  usedBytes += bytes;
1580
1644
  }
1581
1645
  const last = entries[entries.length - 1];
1646
+ const nextRow = last === void 0 ? sinceRow : last.row + 1;
1647
+ journalReadTo = Math.max(journalReadTo, nextRow);
1582
1648
  return {
1583
1649
  entries,
1584
- nextRow: last === void 0 ? sinceRow : last.row + 1,
1650
+ nextRow,
1585
1651
  remaining: matching.length - index,
1586
1652
  truncated: bounded,
1587
1653
  bounds: {
@@ -1673,6 +1739,39 @@ function createCoordinationToolsForManager(opts, lifetime) {
1673
1739
  ...resumed ? { resumed: true } : {}
1674
1740
  });
1675
1741
  const liveSnapshot = () => opts.scope.view.nodes.filter((n) => isLiveNodeStatus(n.status)).map((n) => projectNodeEvidence(n));
1742
+ const openWork = () => {
1743
+ const received = new Set(ledger.map((worker) => worker.id));
1744
+ const nodes = opts.scope.view?.nodes ?? [];
1745
+ return {
1746
+ running: nodes.filter((node) => isLiveNodeStatus(node.status) && node.status !== "waiting"),
1747
+ unqueued: nodes.filter((node) => !isLiveNodeStatus(node.status) && !received.has(node.id) && !flushedAnalystRuns.has(node.id)),
1748
+ queued: bus.queued(["settled", "finding"])
1749
+ };
1750
+ };
1751
+ const openWorkRefusal = (verb) => {
1752
+ const { running, unqueued, queued } = openWork();
1753
+ if (running.length === 0 && unqueued.length === 0 && queued.length === 0) return void 0;
1754
+ const parts = [];
1755
+ if (running.length > 0) parts.push(`${running.length} worker${running.length === 1 ? " is" : "s are"} still running (${running.map((node) => node.id).join(", ")})`);
1756
+ const waiting = unqueued.length + queued.length;
1757
+ if (waiting > 0) parts.push(`${waiting} event${waiting === 1 ? " is" : "s are"} waiting for you in await_event`);
1758
+ return {
1759
+ error: "open-work",
1760
+ reason: `${parts.join(" and ")}. Call await_event until it returns idle, read each settled worker's output, and then call ${verb} again. Nothing was ${verb === "stop" ? "stopped" : "checked"}.`,
1761
+ running: running.map((node) => ({
1762
+ id: node.id,
1763
+ label: node.label,
1764
+ status: node.status
1765
+ })),
1766
+ waiting: [...queued.map((record) => ({
1767
+ type: record.event.type,
1768
+ ...eventWorker(record.event) === void 0 ? {} : { worker: eventWorker(record.event) }
1769
+ })), ...unqueued.map((node) => ({
1770
+ type: "settled",
1771
+ worker: node.id
1772
+ }))]
1773
+ };
1774
+ };
1676
1775
  const freeWorkerSlots = () => usesTreeWideLimit() ? sharedWorkerCapacity()?.freeSlots ?? null : freeSlots(localLiveWorkerCount(), maxLiveWorkers);
1677
1776
  const readProgress = (id) => {
1678
1777
  const scope = opts.scope;
@@ -1756,11 +1855,11 @@ function createCoordinationToolsForManager(opts, lifetime) {
1756
1855
  const tools = [
1757
1856
  {
1758
1857
  name: "spawn_worker",
1759
- 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 hard sub-task more than the default — it merges over the per-worker default; the conserved pool is still the hard fence. When a max-live-workers cap is set it also fails closed (`error: \"max-live-workers\"`) while that many workers are still in flight — settle or steer one before spawning another. 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 with no terminal receipt 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 you can start right now (`null` = uncapped). While `freeSlots > 0` there is idle capacity — call this again to fill it rather than waiting; parallel workers finish the run sooner than one at a time.",
1858
+ 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 hard sub-task more than the default — it merges over the per-worker default; the conserved pool is still the hard fence. When a max-live-workers cap is set it also fails closed (`error: \"max-live-workers\"`) while that many workers are still in flight — settle or steer one before spawning another. 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 with no terminal receipt 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 you can start right now (`null` = uncapped). While `freeSlots > 0` there is idle capacity — call this again to fill it rather than waiting; 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."),
1760
1859
  inputSchema: {
1761
1860
  type: "object",
1762
1861
  properties: {
1763
- profile: spawnProfileArg(),
1862
+ profile: profileTable === void 0 ? spawnProfileArg() : spawnProfileArgWithTable(profileTable),
1764
1863
  task: { description: "The task the worker should perform." },
1765
1864
  label: {
1766
1865
  type: "string",
@@ -1775,6 +1874,10 @@ function createCoordinationToolsForManager(opts, lifetime) {
1775
1874
  enum: ["fresh", "resume"],
1776
1875
  description: "How this spawn continues the node's prior work. \"fresh\" (the default) starts a brand-new session. \"resume\" re-attaches to the node's most recent SETTLED worker: a NEW live worker is spawned whose session continues where that worker stopped (the backend receives the prior workerId and the resume sequence). Resume fails closed when the node has no settled prior worker (`error: \"resume-no-prior\"` — spawn it fresh first), while a prior worker of the node is still live (`error: \"resume-while-live\"` — steer_agent is the live-worker channel), and under a `key` (`error: \"resume-with-key\"` — keys are run-once, resume runs again). Omit to use the run's declared default for this profile name."
1777
1876
  },
1877
+ successorOf: {
1878
+ type: "string",
1879
+ 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\"` — await_event until it settles). Put what the successor needs from its predecessor in `task`."
1880
+ },
1778
1881
  budget: {
1779
1882
  type: "object",
1780
1883
  description: "Optional per-spawn budget that merges over the per-worker default (per field). Only set the ceilings this sub-task needs raised; the conserved pool still fences.",
@@ -1827,7 +1930,21 @@ function createCoordinationToolsForManager(opts, lifetime) {
1827
1930
  live,
1828
1931
  freeSlots: freeWorkerSlots()
1829
1932
  }))(liveWorkerCount()));
1830
- const resourcePaths = await resolveSpawnResourcePaths(a.profile, opts.spawnResourceReader ?? opts.spawnResourceRoot);
1933
+ const tableRefusal = profileTableRefusal(profileTable, a.profile);
1934
+ if (tableRefusal !== void 0) return {
1935
+ error: "invalid-profile",
1936
+ reason: tableRefusal,
1937
+ issues: [{
1938
+ path: "profile",
1939
+ message: tableRefusal
1940
+ }]
1941
+ };
1942
+ const tableEntry = typeof a.profile === "string" ? profileTable?.get(a.profile) : void 0;
1943
+ const resourcePaths = tableEntry === void 0 ? await resolveSpawnResourcePaths(a.profile, opts.spawnResourceReader ?? opts.spawnResourceRoot) : {
1944
+ ok: true,
1945
+ profile: tableEntry.profile,
1946
+ resolved: []
1947
+ };
1831
1948
  if (!resourcePaths.ok) return {
1832
1949
  error: "invalid-profile",
1833
1950
  reason: `resources.${resourcePaths.at}: ${resourcePaths.reason}`,
@@ -1854,6 +1971,22 @@ function createCoordinationToolsForManager(opts, lifetime) {
1854
1971
  live: liveWorkerCount(),
1855
1972
  freeSlots: freeWorkerSlots()
1856
1973
  });
1974
+ const successorOf = a.successorOf === void 0 ? void 0 : str(a.successorOf, "successorOf");
1975
+ if (successorOf !== void 0) {
1976
+ const predecessor = nodeForWorker(successorOf);
1977
+ if (predecessor === void 0 || predecessor.parent !== opts.scope.view.root) return {
1978
+ error: "successor-unknown",
1979
+ reason: `'${successorOf}' is not a worker this manager spawned — successorOf takes a workerId from one of your own spawn_worker results`,
1980
+ live: liveWorkerCount(),
1981
+ freeSlots: freeWorkerSlots()
1982
+ };
1983
+ if (isLiveNodeStatus(predecessor.status)) return {
1984
+ error: "successor-live",
1985
+ reason: `worker '${successorOf}' has not settled — await_event until it does, then spawn its successor (steer_agent redirects a live worker instead)`,
1986
+ live: liveWorkerCount(),
1987
+ freeSlots: freeWorkerSlots()
1988
+ };
1989
+ }
1857
1990
  const task = detachedFrozen(a.task);
1858
1991
  const label = typeof a.label === "string" ? a.label : "worker";
1859
1992
  if (opts.preflightSpawn) {
@@ -1887,13 +2020,15 @@ function createCoordinationToolsForManager(opts, lifetime) {
1887
2020
  ...key !== void 0 ? { key } : {},
1888
2021
  continuity: continuity.continuity,
1889
2022
  ...continuity.continuity === "resume" ? { resume: continuity.resume } : {},
2023
+ ...successorOf !== void 0 ? { successorOf } : {},
1890
2024
  ...peerMailUrl !== void 0 ? { peerMailUrl } : {}
1891
2025
  });
1892
2026
  const res = opts.scope.spawn(() => opts.makeWorkerAgent(profile, context), task, {
1893
2027
  budget,
1894
2028
  label,
1895
2029
  assignmentId,
1896
- ...key !== void 0 ? { key } : {}
2030
+ ...key !== void 0 ? { key } : {},
2031
+ ...successorOf !== void 0 ? { successorOf } : {}
1897
2032
  });
1898
2033
  if (res.ok && res.prior?.state === "completed") {
1899
2034
  const s = res.prior.settled;
@@ -1932,6 +2067,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
1932
2067
  ...res.handle.executionBindings === void 0 ? {} : { executionBindings: res.handle.executionBindings },
1933
2068
  continuity: continuity.continuity,
1934
2069
  ...continuity.continuity === "resume" ? { resume: continuity.resume } : {},
2070
+ ...successorOf !== void 0 ? { successorOf } : {},
1935
2071
  live: liveWorkerCount(),
1936
2072
  freeSlots: freeWorkerSlots(),
1937
2073
  ...priorHistory,
@@ -2045,24 +2181,50 @@ function createCoordinationToolsForManager(opts, lifetime) {
2045
2181
  },
2046
2182
  {
2047
2183
  name: "await_event",
2048
- 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.",
2184
+ 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.",
2049
2185
  inputSchema: {
2050
2186
  type: "object",
2051
- properties: { kinds: {
2052
- type: "array",
2053
- items: {
2054
- type: "string",
2055
- enum: [...awaitableEventKinds]
2187
+ properties: {
2188
+ kinds: {
2189
+ type: "array",
2190
+ items: {
2191
+ type: "string",
2192
+ enum: [...awaitableEventKinds]
2193
+ },
2194
+ description: "Restrict to these event kinds (any if omitted)."
2056
2195
  },
2057
- description: "Restrict to these event kinds (any if omitted)."
2058
- } }
2196
+ acknowledge: {
2197
+ type: "array",
2198
+ items: {
2199
+ type: "integer",
2200
+ minimum: 0
2201
+ },
2202
+ description: "The eventSeq of each earlier event you have now processed."
2203
+ }
2204
+ }
2059
2205
  },
2060
2206
  handler: async (raw) => {
2061
- const k = obj(raw).kinds;
2207
+ const args = raw === void 0 ? {} : obj(raw);
2208
+ const k = args.kinds;
2062
2209
  const kinds = Array.isArray(k) ? k.filter(isAwaitableEventKind) : void 0;
2063
- let ev = bus.pull(kinds);
2210
+ if (Array.isArray(args.acknowledge)) {
2211
+ const named = new Set(args.acknowledge.filter((value) => typeof value === "number" && Number.isInteger(value)));
2212
+ await acknowledge(deliveries.filter((delivery) => named.has(delivery.record.seq)), "manager");
2213
+ }
2214
+ const deliver = (record) => {
2215
+ deliveries.push({
2216
+ record,
2217
+ attempt: driverAttempt,
2218
+ acknowledged: false
2219
+ });
2220
+ return {
2221
+ ...projectEvent(record.event),
2222
+ eventSeq: record.seq
2223
+ };
2224
+ };
2225
+ let ev = bus.pullRecord(kinds);
2064
2226
  if (ev) return {
2065
- ...projectEvent(ev),
2227
+ ...deliver(ev),
2066
2228
  freeSlots: freeWorkerSlots()
2067
2229
  };
2068
2230
  const raced = await raceDrainWithTimeout(ensureDrain());
@@ -2071,13 +2233,13 @@ function createCoordinationToolsForManager(opts, lifetime) {
2071
2233
  live: liveSnapshot(),
2072
2234
  freeSlots: freeWorkerSlots()
2073
2235
  };
2074
- ev = bus.pull(kinds);
2236
+ ev = bus.pullRecord(kinds);
2075
2237
  if (!ev) return {
2076
2238
  idle: !raced.drained,
2077
2239
  freeSlots: freeWorkerSlots()
2078
2240
  };
2079
2241
  return {
2080
- ...projectEvent(ev),
2242
+ ...deliver(ev),
2081
2243
  freeSlots: freeWorkerSlots()
2082
2244
  };
2083
2245
  }
@@ -2253,6 +2415,18 @@ function createCoordinationToolsForManager(opts, lifetime) {
2253
2415
  };
2254
2416
  const a = obj(raw);
2255
2417
  if (!Object.hasOwn(a, "result")) throw new Error("submit_result: \"result\" is required");
2418
+ const open = openWorkRefusal("submit_result");
2419
+ if (open !== void 0) {
2420
+ lastRejection = {
2421
+ at: Date.now(),
2422
+ reason: String(open.reason)
2423
+ };
2424
+ return {
2425
+ accepted: false,
2426
+ stop: false,
2427
+ ...open
2428
+ };
2429
+ }
2256
2430
  const result = structuredClone(a.result);
2257
2431
  let accepted = false;
2258
2432
  let thrown;
@@ -2271,10 +2445,15 @@ function createCoordinationToolsForManager(opts, lifetime) {
2271
2445
  } catch (error) {
2272
2446
  diagnosticError = error instanceof Error ? error.message : String(error);
2273
2447
  }
2448
+ const refusal = thrown === void 0 ? `the independent check did not pass on this result${explanation ? `. ${explanation}` : deliverable.describe ? `. Expected: ${deliverable.describe}` : ""}` : `the independent check THREW, so nothing was accepted: ${thrown}. This is a fault in the check, not necessarily in your result — report it rather than resubmitting unchanged`;
2449
+ lastRejection = {
2450
+ at: Date.now(),
2451
+ reason: refusal
2452
+ };
2274
2453
  return {
2275
2454
  accepted: false,
2276
2455
  stop: false,
2277
- reason: thrown === void 0 ? `the independent check did not pass on this result${explanation ? `. ${explanation}` : deliverable.describe ? `. Expected: ${deliverable.describe}` : ""}` : `the independent check THREW, so nothing was accepted: ${thrown}. This is a fault in the check, not necessarily in your result — report it rather than resubmitting unchanged`,
2456
+ reason: refusal,
2278
2457
  ...diagnosticError === void 0 ? {} : { diagnosticError }
2279
2458
  };
2280
2459
  }
@@ -2307,6 +2486,7 @@ function createCoordinationToolsForManager(opts, lifetime) {
2307
2486
  } finally {
2308
2487
  if (submissionInFlight === commit) submissionInFlight = void 0;
2309
2488
  }
2489
+ await acknowledge(deliveries, "result-accepted");
2310
2490
  return {
2311
2491
  accepted: true,
2312
2492
  retained: "this-result",
@@ -2336,6 +2516,11 @@ function createCoordinationToolsForManager(opts, lifetime) {
2336
2516
  ...unheard.length > 0 ? { unheardQuestionIds: unheard.map((q) => q.id) } : {}
2337
2517
  });
2338
2518
  }
2519
+ const open = openWorkRefusal("stop");
2520
+ if (open !== void 0) return Promise.resolve({
2521
+ stopped: false,
2522
+ ...open
2523
+ });
2339
2524
  stopped = true;
2340
2525
  const r = obj(raw).reason;
2341
2526
  reason = typeof r === "string" ? r : void 0;
@@ -2343,6 +2528,97 @@ function createCoordinationToolsForManager(opts, lifetime) {
2343
2528
  return Promise.resolve({ stopped: true });
2344
2529
  }
2345
2530
  },
2531
+ {
2532
+ name: "report_blocked",
2533
+ description: [
2534
+ "Report that a tool you need keeps failing, so the run cannot go on.",
2535
+ "Name the tool, the arguments you called it with, and the error you saw.",
2536
+ "The coordinator calls that tool again, with those arguments, under your identity.",
2537
+ "When the call succeeds you are not blocked: the reply carries its result, and you continue.",
2538
+ "When it fails again, the run ends as blocked and the record keeps both errors.",
2539
+ "submit_result, stop and report_blocked cannot be probed."
2540
+ ].join(" "),
2541
+ inputSchema: {
2542
+ type: "object",
2543
+ properties: {
2544
+ tool: {
2545
+ type: "string",
2546
+ description: "The tool that failed, as you called it."
2547
+ },
2548
+ arguments: {
2549
+ type: "object",
2550
+ description: "The arguments you called it with. Omit for none."
2551
+ },
2552
+ error: {
2553
+ type: "string",
2554
+ description: "The error the tool returned to you."
2555
+ }
2556
+ },
2557
+ required: ["tool", "error"],
2558
+ additionalProperties: false
2559
+ },
2560
+ handler: async (raw) => {
2561
+ const a = obj(raw);
2562
+ const named = str(a.tool, "tool");
2563
+ const reported = str(a.error, "error");
2564
+ const bare = named.replace(/^mcp__.+?__/u, "").replace(/^.*?coordination_+/u, "");
2565
+ if (unprobeableVerbs.has(bare)) return {
2566
+ blocked: false,
2567
+ error: "unprobeable",
2568
+ reason: `${bare} changes the run, so the coordinator does not call it for you`
2569
+ };
2570
+ const target = opts.resolveProbeTool?.(bare) ?? tools.find((tool) => tool.name === bare);
2571
+ if (target === void 0) return {
2572
+ blocked: false,
2573
+ error: "unknown-tool",
2574
+ reason: `no tool named ${JSON.stringify(bare)} is served to you, so there is nothing to probe; call the tools you were given`
2575
+ };
2576
+ const args = a.arguments === void 0 ? {} : typeof a.arguments === "object" && a.arguments !== null && !Array.isArray(a.arguments) ? a.arguments : void 0;
2577
+ if (args === void 0) return {
2578
+ blocked: false,
2579
+ error: "invalid-arguments",
2580
+ reason: "\"arguments\" must be an object"
2581
+ };
2582
+ let probe;
2583
+ try {
2584
+ probe = {
2585
+ ok: true,
2586
+ result: await runWithin(target.handler(structuredClone(args)), REPORT_BLOCKED_PROBE_MS, `the probe of ${bare} did not answer within ${REPORT_BLOCKED_PROBE_MS}ms`)
2587
+ };
2588
+ } catch (error) {
2589
+ probe = {
2590
+ ok: false,
2591
+ error: error instanceof Error ? error.message : String(error)
2592
+ };
2593
+ }
2594
+ if (probe.ok) return {
2595
+ blocked: false,
2596
+ probe: {
2597
+ tool: bare,
2598
+ ok: true,
2599
+ result: probe.result
2600
+ },
2601
+ guidance: "The call worked when the coordinator made it under your identity, so the tool is not blocked. Use this result and continue the objective."
2602
+ };
2603
+ blockedEvidence = Object.freeze({
2604
+ tool: bare,
2605
+ reported,
2606
+ probed: probe.error
2607
+ });
2608
+ stopped = true;
2609
+ reason = `blocked: ${bare} failed when the coordinator probed it: ${probe.error}`;
2610
+ notifyStop();
2611
+ return {
2612
+ blocked: true,
2613
+ stopped: true,
2614
+ probe: {
2615
+ tool: bare,
2616
+ ok: false,
2617
+ error: probe.error
2618
+ }
2619
+ };
2620
+ }
2621
+ },
2346
2622
  {
2347
2623
  name: "read_journal",
2348
2624
  description: [
@@ -2563,9 +2839,74 @@ function createCoordinationToolsForManager(opts, lifetime) {
2563
2839
  definedAnalysts: () => definedAnalysts,
2564
2840
  drainResolved,
2565
2841
  abortWorker,
2842
+ beginDriverAttempt: (attempt) => {
2843
+ driverAttempt = attempt;
2844
+ },
2845
+ endDriverAttempt: async (outcome) => {
2846
+ const attempt = driverAttempt;
2847
+ if (outcome === "completed") await acknowledge(deliveries.filter((delivery) => delivery.attempt === attempt), "turn-completed");
2848
+ },
2849
+ reentryState: () => {
2850
+ const { unqueued, queued } = openWork();
2851
+ const deliveredSettled = new Set(deliveries.flatMap((delivery) => delivery.record.event.type === "settled" ? [delivery.record.event.worker.id] : []));
2852
+ return detachedFrozen({
2853
+ journalRows: priorJournal.length + bus.history().length,
2854
+ journalReadTo,
2855
+ live: (opts.scope.view?.nodes ?? []).filter((node) => isLiveNodeStatus(node.status)).map((node) => ({
2856
+ id: node.id,
2857
+ label: node.label,
2858
+ status: node.status
2859
+ })),
2860
+ settled: [...ledger.map((worker) => ({
2861
+ id: worker.id,
2862
+ status: worker.status,
2863
+ ...worker.status === "done" && worker.valid !== void 0 ? { valid: worker.valid } : {},
2864
+ delivered: deliveredSettled.has(worker.id)
2865
+ })), ...unqueued.map((node) => ({
2866
+ id: node.id,
2867
+ status: node.status === "done" ? "done" : "down",
2868
+ delivered: false
2869
+ }))],
2870
+ waiting: [...queued.map((record) => ({
2871
+ type: record.event.type,
2872
+ ...eventWorker(record.event) === void 0 ? {} : { worker: eventWorker(record.event) }
2873
+ })), ...unqueued.map((node) => ({
2874
+ type: "settled",
2875
+ worker: node.id
2876
+ }))],
2877
+ unacknowledged: deliveries.filter((delivery) => !delivery.acknowledged).map((delivery) => ({
2878
+ seq: delivery.record.seq,
2879
+ type: delivery.record.event.type,
2880
+ ...eventWorker(delivery.record.event) === void 0 ? {} : { worker: eventWorker(delivery.record.event) },
2881
+ ...delivery.attempt === void 0 ? {} : { attempt: delivery.attempt }
2882
+ })),
2883
+ ...lastRejection === void 0 ? {} : { lastRejection }
2884
+ });
2885
+ },
2886
+ blocked: () => blockedEvidence,
2566
2887
  ...peerMail ? { peerMail } : {}
2567
2888
  };
2568
2889
  }
2890
+ /** The verbs `report_blocked` never calls on a manager's behalf: each one changes the run. */
2891
+ const unprobeableVerbs = /* @__PURE__ */ new Set([
2892
+ "submit_result",
2893
+ "stop",
2894
+ "report_blocked"
2895
+ ]);
2896
+ /** How long one `report_blocked` probe may run before it counts as a failure. */
2897
+ const REPORT_BLOCKED_PROBE_MS = 6e4;
2898
+ async function runWithin(work, ms, message) {
2899
+ let timer;
2900
+ const timeout = new Promise((_, reject) => {
2901
+ timer = setTimeout(() => reject(new Error(message)), ms);
2902
+ if (typeof timer?.unref === "function") timer.unref();
2903
+ });
2904
+ try {
2905
+ return await Promise.race([work, timeout]);
2906
+ } finally {
2907
+ if (timer) clearTimeout(timer);
2908
+ }
2909
+ }
2569
2910
  function nextUnkeyedAssignmentOrdinal(scope) {
2570
2911
  let next = 0;
2571
2912
  const views = [scope.resume?.view, scope.view];
@@ -3273,13 +3614,13 @@ function formatOverspend(violation) {
3273
3614
  * (can't afford a worker) and usd (a usd-capped pool whose ceiling the driver's own metered
3274
3615
  * inference has drained — `meter` debits usd, so without this a huge-token/small-usd pool would
3275
3616
  * overspend usd up to the turn tripwire). */
3276
- function poolStarved(scope, perWorker) {
3617
+ function poolStarved(scope, perWorker, preserveOwnerTurns = false) {
3277
3618
  const b = scope.budget;
3278
3619
  if (scope.view.inFlight > 0 || scope.view.waiting > 0) return false;
3279
- const tokenStarved = b.tokensLeft < perWorker.maxTokens;
3620
+ const tokenStarved = preserveOwnerTurns ? b.tokensLeft <= 0 : b.tokensLeft < perWorker.maxTokens;
3280
3621
  const iterationStarved = b.iterationsLeft <= 0;
3281
- const usdStarved = b.usdCapped && (b.usdLeft <= 0 || perWorker.maxUsd !== void 0 && b.usdLeft < perWorker.maxUsd);
3282
- const resourceStarved = Object.entries(b.resources ?? {}).some(([name, value]) => !value.known || value.remaining <= 0 || value.remaining < (perWorker.resources?.[name]?.limit ?? 0));
3622
+ const usdStarved = b.usdCapped && (b.usdLeft <= 0 || !preserveOwnerTurns && perWorker.maxUsd !== void 0 && b.usdLeft < perWorker.maxUsd);
3623
+ const resourceStarved = Object.entries(b.resources ?? {}).some(([name, value]) => !value.known || value.remaining <= 0 || !preserveOwnerTurns && value.remaining < (perWorker.resources?.[name]?.limit ?? 0));
3283
3624
  return tokenStarved || iterationStarved || usdStarved || resourceStarved;
3284
3625
  }
3285
3626
  /** The absolute wall-clock deadline (when the root set one) has passed. */
@@ -3680,6 +4021,7 @@ function driverAgent(opts) {
3680
4021
  },
3681
4022
  async act(task, scope) {
3682
4023
  const ownerReader = opts.spawnResourceReader ?? (opts.spawnResourceRoot === void 0 ? scopeRetainedOwnerResourceReader(scope) : void 0);
4024
+ let probeableByName;
3683
4025
  const coord = createCoordinationTools({
3684
4026
  scope,
3685
4027
  blobs: opts.blobs,
@@ -3697,6 +4039,7 @@ function driverAgent(opts) {
3697
4039
  ...opts.preflightSpawn ? { preflightSpawn: opts.preflightSpawn } : {},
3698
4040
  ...opts.resolveSpawnProfile ? { resolveSpawnProfile: opts.resolveSpawnProfile } : {},
3699
4041
  ...opts.composeSpawnProfile ? { composeSpawnProfile: opts.composeSpawnProfile } : {},
4042
+ ...opts.profiles ? { profiles: opts.profiles } : {},
3700
4043
  ...opts.spawnResourceRoot ? { spawnResourceRoot: opts.spawnResourceRoot } : {},
3701
4044
  ...ownerReader ? { spawnResourceReader: ownerReader } : {},
3702
4045
  ...opts.escalateQuestion ? { escalateQuestion: opts.escalateQuestion } : {},
@@ -3705,7 +4048,8 @@ function driverAgent(opts) {
3705
4048
  ...opts.priorCoordination?.questions.length ? { priorQuestions: opts.priorCoordination.questions } : {},
3706
4049
  ...opts.priorCoordination?.escalations?.length ? { priorEscalations: opts.priorCoordination.escalations } : {},
3707
4050
  ...opts.priorCoordination?.records.length ? { priorJournal: opts.priorCoordination.records } : {},
3708
- ...opts.priorCoordination?.analystDefinitions?.length ? { priorAnalystDefinitions: opts.priorCoordination.analystDefinitions } : {}
4051
+ ...opts.priorCoordination?.analystDefinitions?.length ? { priorAnalystDefinitions: opts.priorCoordination.analystDefinitions } : {},
4052
+ resolveProbeTool: (name) => probeableByName?.get(name)
3709
4053
  });
3710
4054
  await coord.ready();
3711
4055
  const availableTools = [...coord.tools, ...opts.nodeTools ?? []];
@@ -3725,6 +4069,7 @@ function driverAgent(opts) {
3725
4069
  };
3726
4070
  });
3727
4071
  const modelTools = selectedTools.flatMap((selected) => selected.kind === "descriptor" ? [selected.descriptor] : []);
4072
+ probeableByName = new Map(modelTools.map((tool) => [tool.name, tool]));
3728
4073
  const selectedExtraNames = new Set(selectedTools.flatMap((selected) => selected.kind === "extra" ? [selected.extra.name] : []));
3729
4074
  opts.onCoordinationTools?.(modelTools);
3730
4075
  const acknowledger = opts.controlDir === void 0 ? void 0 : createCancelAcknowledger({
@@ -3905,7 +4250,7 @@ function driverAgent(opts) {
3905
4250
  });
3906
4251
  },
3907
4252
  stopBefore: () => {
3908
- if (coord.isStopped() || scope.signal.aborted || poolStarved(scope, opts.perWorker) || deadlinePassed(scope, now)) return true;
4253
+ if (coord.isStopped() || scope.signal.aborted || poolStarved(scope, opts.perWorker, opts.preserveOwnerTurns) || deadlinePassed(scope, now)) return true;
3909
4254
  if (!opts.stopRule || !tracker) return false;
3910
4255
  const decision = progressStop(tracker, opts.stopRule, coord, scope, now, opts.stallAfterMs);
3911
4256
  if (!decision.stop) return false;
@@ -4036,4 +4381,4 @@ function safeJson(v) {
4036
4381
  //#endregion
4037
4382
  export { downMessageRefusalReasons as A, ANALYST_DEFINITION_BOUNDS as C, coordinationVerbNames as D, canonicalFindingEvent as E, defaultToolDetectors as F, watchTrace as I, parseAuthoredAnalystDefinition as M, questionEscalationTargets as N, createCoordinationTools as O, createEventBus as P, watchRunCancellation as S, analystToolGroupNames as T, renderAnytimeTable as _, allOf as a, FileCoordinationLog as b, createProgressTracker as c, progressStop as d, sampleFromSettled as f, plateauLength as g, bestSoFar as h, finalizeBestDelivered as i, normalizeAnalyzeOnSettle as j, createCoordinationToolsForManager as k, noProgressFor as l, areaUnderCurve as m, createSteerAcknowledger as n, allWorkersStalled as o, anytimeReport as p, driverAgent as r, anyOf as s, createCancelAcknowledger as t, plateau as u, createFileRunContext as v, DEFAULT_AWAIT_EVENT_TIMEOUT_MS as w, applyRunCancellation as x, createInMemoryRunContext as y };
4038
4383
 
4039
- //# sourceMappingURL=coordination-driver-BmtrkNPu.js.map
4384
+ //# sourceMappingURL=coordination-driver-COGC8FK2.js.map