@wrongstack/core 0.9.20 → 0.10.2

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 (67) hide show
  1. package/README.md +37 -33
  2. package/dist/{agent-bridge-Dti3KXGk.d.ts → agent-bridge-DBBGP5O4.d.ts} +1 -1
  3. package/dist/{agent-subagent-runner-U-rs7kk7.d.ts → agent-subagent-runner-KwufTWwn.d.ts} +3 -3
  4. package/dist/{compactor-D7X96RLZ.d.ts → compactor-D1RHFRmF.d.ts} +1 -1
  5. package/dist/{config-CLXMDOSs.d.ts → config-CJXBka2r.d.ts} +38 -2
  6. package/dist/{context-zkZeILpr.d.ts → context-7u93AcGD.d.ts} +94 -0
  7. package/dist/coordination/index.d.ts +12 -12
  8. package/dist/coordination/index.js +130 -58
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/{default-config-Uzla85H-.d.ts → default-config-DEXI4jsl.d.ts} +10 -1
  11. package/dist/defaults/index.d.ts +24 -24
  12. package/dist/defaults/index.js +611 -95
  13. package/dist/defaults/index.js.map +1 -1
  14. package/dist/{events-DH-9r-_C.d.ts → events-Bw1K5E6K.d.ts} +8 -1
  15. package/dist/execution/index.d.ts +18 -15
  16. package/dist/execution/index.js +309 -61
  17. package/dist/execution/index.js.map +1 -1
  18. package/dist/extension/index.d.ts +6 -6
  19. package/dist/extension/index.js.map +1 -1
  20. package/dist/goal-store-BeRsj7YX.d.ts +188 -0
  21. package/dist/{index-CFO9QmJo.d.ts → index-DIt5TIaF.d.ts} +8 -8
  22. package/dist/{index-BIHJ4uII.d.ts → index-DgQWnZxP.d.ts} +5 -5
  23. package/dist/index.d.ts +56 -35
  24. package/dist/index.js +742 -203
  25. package/dist/index.js.map +1 -1
  26. package/dist/infrastructure/index.d.ts +6 -6
  27. package/dist/kernel/index.d.ts +9 -9
  28. package/dist/kernel/index.js +57 -8
  29. package/dist/kernel/index.js.map +1 -1
  30. package/dist/{mcp-servers-DkESgh0G.d.ts → mcp-servers-BgINZzuo.d.ts} +3 -3
  31. package/dist/models/index.d.ts +3 -3
  32. package/dist/models/index.js +163 -10
  33. package/dist/models/index.js.map +1 -1
  34. package/dist/models-registry-gwMAo6E3.d.ts +86 -0
  35. package/dist/{multi-agent-DNp6lAzg.d.ts → multi-agent-C1O8EFzb.d.ts} +45 -4
  36. package/dist/{multi-agent-coordinator-CAhsegPz.d.ts → multi-agent-coordinator-DoVSBFNx.d.ts} +2 -2
  37. package/dist/{null-fleet-bus-Dnl19vmf.d.ts → null-fleet-bus-T-s3JaOt.d.ts} +8 -6
  38. package/dist/observability/index.d.ts +2 -2
  39. package/dist/{path-resolver-CHiBL0DD.d.ts → path-resolver-BfyK-I7w.d.ts} +2 -2
  40. package/dist/{permission-H35s9Evv.d.ts → permission-B6sldrSp.d.ts} +1 -1
  41. package/dist/{permission-policy-CT-nRmTn.d.ts → permission-policy-CtNscWOA.d.ts} +10 -9
  42. package/dist/{plan-templates-Bs8iRwi6.d.ts → plan-templates-BWs6Je7j.d.ts} +8 -8
  43. package/dist/{provider-runner-BZdDrWrS.d.ts → provider-runner-BmPe2RuU.d.ts} +3 -3
  44. package/dist/{retry-policy-J9N_PM40.d.ts → retry-policy-KF18W4dg.d.ts} +1 -1
  45. package/dist/sdd/index.d.ts +8 -8
  46. package/dist/sdd/index.js +130 -58
  47. package/dist/sdd/index.js.map +1 -1
  48. package/dist/security/index.d.ts +65 -4
  49. package/dist/security/index.js +67 -19
  50. package/dist/security/index.js.map +1 -1
  51. package/dist/{selector-CFTh3Z6p.d.ts → selector-DmXxpFyM.d.ts} +1 -1
  52. package/dist/{session-reader-C7JJlxOw.d.ts → session-reader-CCSBfQmd.d.ts} +1 -1
  53. package/dist/storage/index.d.ts +7 -7
  54. package/dist/storage/index.js +125 -6
  55. package/dist/storage/index.js.map +1 -1
  56. package/dist/{system-prompt-CneIxVip.d.ts → system-prompt-CM6zOhd2.d.ts} +19 -1
  57. package/dist/{tool-executor-flTuxsqO.d.ts → tool-executor-D7RxLtg4.d.ts} +4 -4
  58. package/dist/types/index.d.ts +16 -16
  59. package/dist/types/index.js +344 -14
  60. package/dist/types/index.js.map +1 -1
  61. package/dist/utils/index.d.ts +23 -3
  62. package/dist/utils/index.js +66 -1
  63. package/dist/utils/index.js.map +1 -1
  64. package/dist/{wstack-paths-BCgmTNlG.d.ts → wstack-paths-eMXnY1_X.d.ts} +8 -0
  65. package/package.json +1 -1
  66. package/dist/goal-store-C7jcumEh.d.ts +0 -96
  67. package/dist/models-registry-OG_30xqZ.d.ts +0 -46
@@ -880,6 +880,13 @@ var SubagentBudget = class _SubagentBudget {
880
880
  tokenOutput = 0;
881
881
  costUsd = 0;
882
882
  startTime = null;
883
+ /**
884
+ * Timestamp of the most recent activity (iteration / tool call / token
885
+ * usage / streamed progress). Drives the idle timeout — reset by
886
+ * `markActivity()`. Initialised to `start()` time so a never-active agent
887
+ * still eventually trips its idle window.
888
+ */
889
+ lastActivityTime = null;
883
890
  _onThreshold;
884
891
  /**
885
892
  * Hard cap on how long `_negotiateExtension` waits for the coordinator to
@@ -923,6 +930,24 @@ var SubagentBudget = class _SubagentBudget {
923
930
  }
924
931
  start() {
925
932
  this.startTime = Date.now();
933
+ this.lastActivityTime = this.startTime;
934
+ }
935
+ /**
936
+ * Reset the idle clock. Called on any sign of forward progress —
937
+ * iterations, tool calls, token usage, and streamed tool/text progress —
938
+ * so a long-but-productive subagent never trips its `idleTimeoutMs`.
939
+ */
940
+ markActivity() {
941
+ this.lastActivityTime = Date.now();
942
+ }
943
+ /**
944
+ * Milliseconds since the last activity signal. Returns 0 before `start()`
945
+ * (nothing to measure yet). Used by the coordinator watchdog to decide
946
+ * whether to re-arm (still active) or reap (genuinely idle).
947
+ */
948
+ idleMs() {
949
+ const since = this.lastActivityTime ?? this.startTime;
950
+ return since === null ? 0 : Date.now() - since;
926
951
  }
927
952
  /** Returns true if we're within 10% of any limit — useful for pre-flight checks. */
928
953
  isNearLimit() {
@@ -970,8 +995,13 @@ var SubagentBudget = class _SubagentBudget {
970
995
  if (this.limits.maxCostUsd !== void 0 && this.costUsd > this.limits.maxCostUsd) {
971
996
  exceeded.push({ kind: "cost", used: this.costUsd, limit: this.limits.maxCostUsd });
972
997
  }
973
- if (elapsedMs !== void 0 && this.limits.timeoutMs !== void 0 && elapsedMs > this.limits.timeoutMs) {
974
- exceeded.push({ kind: "timeout", used: elapsedMs, limit: this.limits.timeoutMs });
998
+ if (elapsedMs !== void 0) {
999
+ const idle = this.idleMs();
1000
+ if (this.limits.idleTimeoutMs !== void 0 && idle > this.limits.idleTimeoutMs) {
1001
+ exceeded.push({ kind: "timeout", used: idle, limit: this.limits.idleTimeoutMs });
1002
+ } else if (this.limits.timeoutMs !== void 0 && elapsedMs > this.limits.timeoutMs) {
1003
+ exceeded.push({ kind: "timeout", used: elapsedMs, limit: this.limits.timeoutMs });
1004
+ }
975
1005
  }
976
1006
  if (exceeded.length === 0) return [];
977
1007
  if (!this._onThreshold) {
@@ -1076,6 +1106,9 @@ var SubagentBudget = class _SubagentBudget {
1076
1106
  if (ext.timeoutMs !== void 0) {
1077
1107
  this.limits.timeoutMs = ext.timeoutMs;
1078
1108
  }
1109
+ if (ext.idleTimeoutMs !== void 0) {
1110
+ this.limits.idleTimeoutMs = ext.idleTimeoutMs;
1111
+ }
1079
1112
  return decision;
1080
1113
  } finally {
1081
1114
  this._pendingNegotiations.delete(kind);
@@ -1083,16 +1116,19 @@ var SubagentBudget = class _SubagentBudget {
1083
1116
  }
1084
1117
  recordIteration() {
1085
1118
  this.iterations++;
1119
+ this.markActivity();
1086
1120
  void this.checkLimits();
1087
1121
  }
1088
1122
  recordToolCall() {
1089
1123
  this.toolCalls++;
1124
+ this.markActivity();
1090
1125
  void this.checkLimits();
1091
1126
  }
1092
1127
  recordUsage(usage, costUsd = 0) {
1093
1128
  this.tokenInput += usage.input;
1094
1129
  this.tokenOutput += usage.output;
1095
1130
  this.costUsd += costUsd;
1131
+ this.markActivity();
1096
1132
  void this.checkLimits();
1097
1133
  }
1098
1134
  /**
@@ -1107,15 +1143,22 @@ var SubagentBudget = class _SubagentBudget {
1107
1143
  * - `mode === 'auto'` + listener → throw `BudgetExceededError` (timeout is not extendable)
1108
1144
  */
1109
1145
  checkTimeout() {
1110
- if (this.startTime === null || this.limits.timeoutMs === void 0) return;
1146
+ if (this.startTime === null) return;
1147
+ const { timeoutMs, idleTimeoutMs } = this.limits;
1148
+ if (timeoutMs === void 0 && idleTimeoutMs === void 0) return;
1111
1149
  const elapsed = Date.now() - this.startTime;
1112
- if (elapsed <= this.limits.timeoutMs) return;
1150
+ const wallTripped = timeoutMs !== void 0 && elapsed > timeoutMs;
1151
+ const idleTripped = idleTimeoutMs !== void 0 && this.idleMs() > idleTimeoutMs;
1152
+ if (!wallTripped && !idleTripped) return;
1113
1153
  void this.checkLimits(elapsed);
1114
1154
  }
1115
- /** Returns true if a timeout has occurred without throwing. Useful for races. */
1155
+ /** Returns true if a wall-clock or idle timeout has occurred without throwing. */
1116
1156
  isTimedOut() {
1117
- if (this.startTime === null || this.limits.timeoutMs === void 0) return false;
1118
- return Date.now() - this.startTime > this.limits.timeoutMs;
1157
+ if (this.startTime === null) return false;
1158
+ const { timeoutMs, idleTimeoutMs } = this.limits;
1159
+ if (timeoutMs !== void 0 && Date.now() - this.startTime > timeoutMs) return true;
1160
+ if (idleTimeoutMs !== void 0 && this.idleMs() > idleTimeoutMs) return true;
1161
+ return false;
1119
1162
  }
1120
1163
  usage() {
1121
1164
  return {
@@ -3517,6 +3560,7 @@ var FLEET_ROSTER = {
3517
3560
  ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, d.config])
3518
3561
  )
3519
3562
  };
3563
+ var DEFAULT_IDLE_TIMEOUT_MS = 15 * 60 * 1e3;
3520
3564
  var FLEET_ROSTER_BUDGETS = {
3521
3565
  "audit-log": { timeoutMs: 7.5 * 60 * 60 * 1e3, maxIterations: 5e3, maxToolCalls: 15e3 },
3522
3566
  "bug-hunter": { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 },
@@ -3528,7 +3572,7 @@ var FLEET_ROSTER_BUDGETS = {
3528
3572
  )
3529
3573
  };
3530
3574
  var GENERIC_SUBAGENT_BUDGET = {
3531
- timeoutMs: 3 * 60 * 60 * 1e3,
3575
+ idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
3532
3576
  maxIterations: 5e3,
3533
3577
  maxToolCalls: 15e3
3534
3578
  };
@@ -3538,7 +3582,13 @@ function applyRosterBudget(cfg) {
3538
3582
  if (!defaultBudget) return cfg;
3539
3583
  return {
3540
3584
  ...cfg,
3541
- timeoutMs: cfg.timeoutMs ?? defaultBudget.timeoutMs,
3585
+ // Wall-clock cap is opt-in only: forward an explicit `cfg.timeoutMs`, but
3586
+ // do NOT impose the roster's historical multi-hour wall-clock default — it
3587
+ // killed agents that were still actively working. Reaping is idle-based.
3588
+ timeoutMs: cfg.timeoutMs,
3589
+ // Idle window is the default reaper. Resets on activity, so a long-but-
3590
+ // productive run is never killed; only a genuine stall is reaped.
3591
+ idleTimeoutMs: cfg.idleTimeoutMs ?? defaultBudget.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS,
3542
3592
  maxIterations: cfg.maxIterations ?? defaultBudget.maxIterations,
3543
3593
  maxToolCalls: cfg.maxToolCalls ?? defaultBudget.maxToolCalls,
3544
3594
  maxTokens: cfg.maxTokens ?? defaultBudget.maxTokens,
@@ -3999,13 +4049,17 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
3999
4049
  const rawMaxTokens = subagent.config.maxTokens;
4000
4050
  const rawMaxCostUsd = subagent.config.maxCostUsd;
4001
4051
  const rawTimeoutMs = subagent.config.timeoutMs;
4052
+ const rawIdleTimeoutMs = subagent.config.idleTimeoutMs;
4002
4053
  const configWithRosterDefaults = applyRosterBudget(subagent.config);
4003
4054
  const budget = new SubagentBudget({
4004
4055
  maxIterations: rawMaxIterations ?? this.config.defaultBudget?.maxIterations ?? configWithRosterDefaults.maxIterations,
4005
4056
  maxToolCalls: rawMaxToolCalls ?? this.config.defaultBudget?.maxToolCalls ?? configWithRosterDefaults.maxToolCalls,
4006
4057
  maxTokens: rawMaxTokens ?? this.config.defaultBudget?.maxTokens ?? configWithRosterDefaults.maxTokens,
4007
4058
  maxCostUsd: rawMaxCostUsd ?? this.config.defaultBudget?.maxCostUsd ?? configWithRosterDefaults.maxCostUsd,
4008
- timeoutMs: rawTimeoutMs ?? this.config.defaultBudget?.timeoutMs ?? configWithRosterDefaults.timeoutMs
4059
+ // Wall-clock cap is opt-in (explicit config / defaultBudget only); the
4060
+ // roster no longer supplies one. Idle is the default reaper.
4061
+ timeoutMs: rawTimeoutMs ?? this.config.defaultBudget?.timeoutMs ?? configWithRosterDefaults.timeoutMs,
4062
+ idleTimeoutMs: rawIdleTimeoutMs ?? this.config.defaultBudget?.idleTimeoutMs ?? configWithRosterDefaults.idleTimeoutMs
4009
4063
  });
4010
4064
  subagent.activeBudget = budget;
4011
4065
  if (!this.runner) {
@@ -4052,63 +4106,79 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
4052
4106
  }
4053
4107
  async executeWithTimeout(runner, task, ctx, budget) {
4054
4108
  const initialTimeoutMs = budget.limits.timeoutMs;
4055
- if (initialTimeoutMs === void 0) return runner(task, ctx);
4109
+ const idleLimitMs = budget.limits.idleTimeoutMs;
4110
+ if (initialTimeoutMs === void 0 && idleLimitMs === void 0) {
4111
+ return runner(task, ctx);
4112
+ }
4056
4113
  const start = Date.now();
4057
4114
  let timer = null;
4058
4115
  const timeoutPromise = new Promise((_, reject) => {
4059
4116
  const armFor = (ms) => {
4060
4117
  if (timer) clearTimeout(timer);
4061
- timer = setTimeout(async () => {
4062
- const elapsed = Date.now() - start;
4063
- const limit = budget.limits.timeoutMs ?? initialTimeoutMs;
4064
- if (!budget.onThreshold) {
4065
- this.subagents.get(ctx.subagentId)?.abortController.abort();
4066
- reject(new BudgetExceededError("timeout", limit, elapsed));
4118
+ timer = setTimeout(onTick, Math.max(0, ms));
4119
+ };
4120
+ const scheduleNext = () => {
4121
+ const wallRemaining = initialTimeoutMs === void 0 ? Number.POSITIVE_INFINITY : (budget.limits.timeoutMs ?? initialTimeoutMs) - (Date.now() - start);
4122
+ const idleRemaining = idleLimitMs === void 0 ? Number.POSITIVE_INFINITY : (budget.limits.idleTimeoutMs ?? idleLimitMs) - budget.idleMs();
4123
+ armFor(Math.max(25, Math.min(wallRemaining, idleRemaining)));
4124
+ };
4125
+ const onTick = async () => {
4126
+ const elapsed = Date.now() - start;
4127
+ const wallLimit = initialTimeoutMs === void 0 ? void 0 : budget.limits.timeoutMs ?? initialTimeoutMs;
4128
+ const idleLimit = idleLimitMs === void 0 ? void 0 : budget.limits.idleTimeoutMs ?? idleLimitMs;
4129
+ const wallExceeded = wallLimit !== void 0 && elapsed >= wallLimit;
4130
+ const idleExceeded = idleLimit !== void 0 && budget.idleMs() >= idleLimit;
4131
+ if (idleExceeded && !wallExceeded) {
4132
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
4133
+ reject(new BudgetExceededError("timeout", idleLimit, budget.idleMs()));
4134
+ return;
4135
+ }
4136
+ if (!wallExceeded) {
4137
+ scheduleNext();
4138
+ return;
4139
+ }
4140
+ const limit = wallLimit;
4141
+ if (!budget.onThreshold) {
4142
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
4143
+ reject(new BudgetExceededError("timeout", limit, elapsed));
4144
+ return;
4145
+ }
4146
+ try {
4147
+ const result = budget.onThreshold({
4148
+ kind: "timeout",
4149
+ used: elapsed,
4150
+ limit,
4151
+ requestDecision: () => new Promise((resolveDecision) => {
4152
+ budget._events?.emit("budget.threshold_reached", {
4153
+ kind: "timeout",
4154
+ used: elapsed,
4155
+ limit,
4156
+ timeoutMs: 6e4,
4157
+ extend: (extra) => resolveDecision({ extend: extra }),
4158
+ deny: () => resolveDecision("stop")
4159
+ });
4160
+ })
4161
+ });
4162
+ const decision = typeof result === "string" ? result : await result;
4163
+ if (decision === "continue" || decision === "throw" || decision === "stop") {
4164
+ armFor(Math.max(1e3, limit));
4067
4165
  return;
4068
4166
  }
4069
- try {
4070
- const result = budget.onThreshold({
4071
- kind: "timeout",
4072
- used: elapsed,
4073
- limit,
4074
- requestDecision: () => new Promise((resolveDecision) => {
4075
- budget._events?.emit("budget.threshold_reached", {
4076
- kind: "timeout",
4077
- used: elapsed,
4078
- limit,
4079
- timeoutMs: 6e4,
4080
- extend: (extra) => resolveDecision({ extend: extra }),
4081
- deny: () => resolveDecision("stop")
4082
- });
4083
- })
4084
- });
4085
- const decision = typeof result === "string" ? result : await result;
4086
- if (decision === "continue") {
4087
- armFor(Math.max(1e3, limit));
4088
- return;
4089
- }
4090
- if (decision === "throw" || decision === "stop") {
4091
- armFor(Math.max(1e3, limit));
4092
- return;
4093
- }
4094
- if (decision.extend.timeoutMs !== void 0) {
4095
- budget.limits.timeoutMs = decision.extend.timeoutMs;
4096
- const newLimit = decision.extend.timeoutMs;
4097
- const remaining = Math.max(1e3, newLimit - elapsed);
4098
- armFor(remaining);
4099
- return;
4100
- }
4101
- this.subagents.get(ctx.subagentId)?.abortController.abort();
4102
- reject(new BudgetExceededError("timeout", limit, elapsed));
4103
- } catch (err) {
4104
- this.subagents.get(ctx.subagentId)?.abortController.abort();
4105
- reject(
4106
- err instanceof BudgetExceededError ? err : new BudgetExceededError("timeout", limit, elapsed)
4107
- );
4167
+ if (decision.extend.timeoutMs !== void 0) {
4168
+ budget.limits.timeoutMs = decision.extend.timeoutMs;
4169
+ scheduleNext();
4170
+ return;
4108
4171
  }
4109
- }, ms);
4172
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
4173
+ reject(new BudgetExceededError("timeout", limit, elapsed));
4174
+ } catch (err) {
4175
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
4176
+ reject(
4177
+ err instanceof BudgetExceededError ? err : new BudgetExceededError("timeout", limit, elapsed)
4178
+ );
4179
+ }
4110
4180
  };
4111
- armFor(initialTimeoutMs);
4181
+ scheduleNext();
4112
4182
  });
4113
4183
  try {
4114
4184
  return await Promise.race([runner(task, ctx), timeoutPromise]);
@@ -6747,6 +6817,7 @@ function makeAgentSubagentRunner(opts) {
6747
6817
  // Cheap: O(1) per progress event, and the budget short-circuits
6748
6818
  // when timeoutMs is unset (most subagents have one set anyway).
6749
6819
  events.on("tool.progress", () => {
6820
+ ctx.budget.markActivity();
6750
6821
  try {
6751
6822
  ctx.budget.checkTimeout();
6752
6823
  } catch (e) {
@@ -6763,6 +6834,7 @@ function makeAgentSubagentRunner(opts) {
6763
6834
  currentToolName = e.name;
6764
6835
  }),
6765
6836
  events.on("provider.text_delta", (e) => {
6837
+ ctx.budget.markActivity();
6766
6838
  streamingTextAcc = (streamingTextAcc + e.text).slice(-200);
6767
6839
  })
6768
6840
  );