@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
package/dist/sdd/index.js CHANGED
@@ -2614,6 +2614,13 @@ var SubagentBudget = class _SubagentBudget {
2614
2614
  tokenOutput = 0;
2615
2615
  costUsd = 0;
2616
2616
  startTime = null;
2617
+ /**
2618
+ * Timestamp of the most recent activity (iteration / tool call / token
2619
+ * usage / streamed progress). Drives the idle timeout — reset by
2620
+ * `markActivity()`. Initialised to `start()` time so a never-active agent
2621
+ * still eventually trips its idle window.
2622
+ */
2623
+ lastActivityTime = null;
2617
2624
  _onThreshold;
2618
2625
  /**
2619
2626
  * Hard cap on how long `_negotiateExtension` waits for the coordinator to
@@ -2657,6 +2664,24 @@ var SubagentBudget = class _SubagentBudget {
2657
2664
  }
2658
2665
  start() {
2659
2666
  this.startTime = Date.now();
2667
+ this.lastActivityTime = this.startTime;
2668
+ }
2669
+ /**
2670
+ * Reset the idle clock. Called on any sign of forward progress —
2671
+ * iterations, tool calls, token usage, and streamed tool/text progress —
2672
+ * so a long-but-productive subagent never trips its `idleTimeoutMs`.
2673
+ */
2674
+ markActivity() {
2675
+ this.lastActivityTime = Date.now();
2676
+ }
2677
+ /**
2678
+ * Milliseconds since the last activity signal. Returns 0 before `start()`
2679
+ * (nothing to measure yet). Used by the coordinator watchdog to decide
2680
+ * whether to re-arm (still active) or reap (genuinely idle).
2681
+ */
2682
+ idleMs() {
2683
+ const since = this.lastActivityTime ?? this.startTime;
2684
+ return since === null ? 0 : Date.now() - since;
2660
2685
  }
2661
2686
  /** Returns true if we're within 10% of any limit — useful for pre-flight checks. */
2662
2687
  isNearLimit() {
@@ -2704,8 +2729,13 @@ var SubagentBudget = class _SubagentBudget {
2704
2729
  if (this.limits.maxCostUsd !== void 0 && this.costUsd > this.limits.maxCostUsd) {
2705
2730
  exceeded.push({ kind: "cost", used: this.costUsd, limit: this.limits.maxCostUsd });
2706
2731
  }
2707
- if (elapsedMs !== void 0 && this.limits.timeoutMs !== void 0 && elapsedMs > this.limits.timeoutMs) {
2708
- exceeded.push({ kind: "timeout", used: elapsedMs, limit: this.limits.timeoutMs });
2732
+ if (elapsedMs !== void 0) {
2733
+ const idle = this.idleMs();
2734
+ if (this.limits.idleTimeoutMs !== void 0 && idle > this.limits.idleTimeoutMs) {
2735
+ exceeded.push({ kind: "timeout", used: idle, limit: this.limits.idleTimeoutMs });
2736
+ } else if (this.limits.timeoutMs !== void 0 && elapsedMs > this.limits.timeoutMs) {
2737
+ exceeded.push({ kind: "timeout", used: elapsedMs, limit: this.limits.timeoutMs });
2738
+ }
2709
2739
  }
2710
2740
  if (exceeded.length === 0) return [];
2711
2741
  if (!this._onThreshold) {
@@ -2810,6 +2840,9 @@ var SubagentBudget = class _SubagentBudget {
2810
2840
  if (ext.timeoutMs !== void 0) {
2811
2841
  this.limits.timeoutMs = ext.timeoutMs;
2812
2842
  }
2843
+ if (ext.idleTimeoutMs !== void 0) {
2844
+ this.limits.idleTimeoutMs = ext.idleTimeoutMs;
2845
+ }
2813
2846
  return decision;
2814
2847
  } finally {
2815
2848
  this._pendingNegotiations.delete(kind);
@@ -2817,16 +2850,19 @@ var SubagentBudget = class _SubagentBudget {
2817
2850
  }
2818
2851
  recordIteration() {
2819
2852
  this.iterations++;
2853
+ this.markActivity();
2820
2854
  void this.checkLimits();
2821
2855
  }
2822
2856
  recordToolCall() {
2823
2857
  this.toolCalls++;
2858
+ this.markActivity();
2824
2859
  void this.checkLimits();
2825
2860
  }
2826
2861
  recordUsage(usage, costUsd = 0) {
2827
2862
  this.tokenInput += usage.input;
2828
2863
  this.tokenOutput += usage.output;
2829
2864
  this.costUsd += costUsd;
2865
+ this.markActivity();
2830
2866
  void this.checkLimits();
2831
2867
  }
2832
2868
  /**
@@ -2841,15 +2877,22 @@ var SubagentBudget = class _SubagentBudget {
2841
2877
  * - `mode === 'auto'` + listener → throw `BudgetExceededError` (timeout is not extendable)
2842
2878
  */
2843
2879
  checkTimeout() {
2844
- if (this.startTime === null || this.limits.timeoutMs === void 0) return;
2880
+ if (this.startTime === null) return;
2881
+ const { timeoutMs, idleTimeoutMs } = this.limits;
2882
+ if (timeoutMs === void 0 && idleTimeoutMs === void 0) return;
2845
2883
  const elapsed = Date.now() - this.startTime;
2846
- if (elapsed <= this.limits.timeoutMs) return;
2884
+ const wallTripped = timeoutMs !== void 0 && elapsed > timeoutMs;
2885
+ const idleTripped = idleTimeoutMs !== void 0 && this.idleMs() > idleTimeoutMs;
2886
+ if (!wallTripped && !idleTripped) return;
2847
2887
  void this.checkLimits(elapsed);
2848
2888
  }
2849
- /** Returns true if a timeout has occurred without throwing. Useful for races. */
2889
+ /** Returns true if a wall-clock or idle timeout has occurred without throwing. */
2850
2890
  isTimedOut() {
2851
- if (this.startTime === null || this.limits.timeoutMs === void 0) return false;
2852
- return Date.now() - this.startTime > this.limits.timeoutMs;
2891
+ if (this.startTime === null) return false;
2892
+ const { timeoutMs, idleTimeoutMs } = this.limits;
2893
+ if (timeoutMs !== void 0 && Date.now() - this.startTime > timeoutMs) return true;
2894
+ if (idleTimeoutMs !== void 0 && this.idleMs() > idleTimeoutMs) return true;
2895
+ return false;
2853
2896
  }
2854
2897
  usage() {
2855
2898
  return {
@@ -2956,6 +2999,7 @@ function makeAgentSubagentRunner(opts) {
2956
2999
  // Cheap: O(1) per progress event, and the budget short-circuits
2957
3000
  // when timeoutMs is unset (most subagents have one set anyway).
2958
3001
  events.on("tool.progress", () => {
3002
+ ctx.budget.markActivity();
2959
3003
  try {
2960
3004
  ctx.budget.checkTimeout();
2961
3005
  } catch (e) {
@@ -2972,6 +3016,7 @@ function makeAgentSubagentRunner(opts) {
2972
3016
  currentToolName = e.name;
2973
3017
  }),
2974
3018
  events.on("provider.text_delta", (e) => {
3019
+ ctx.budget.markActivity();
2975
3020
  streamingTextAcc = (streamingTextAcc + e.text).slice(-200);
2976
3021
  })
2977
3022
  );
@@ -5309,6 +5354,7 @@ var ALL_AGENT_DEFINITIONS = [
5309
5354
  ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, d.config])
5310
5355
  )
5311
5356
  });
5357
+ var DEFAULT_IDLE_TIMEOUT_MS = 15 * 60 * 1e3;
5312
5358
  var FLEET_ROSTER_BUDGETS = {
5313
5359
  "audit-log": { timeoutMs: 7.5 * 60 * 60 * 1e3, maxIterations: 5e3, maxToolCalls: 15e3 },
5314
5360
  "bug-hunter": { timeoutMs: 10 * 60 * 60 * 1e3, maxIterations: 8e3, maxToolCalls: 2e4 },
@@ -5320,7 +5366,7 @@ var FLEET_ROSTER_BUDGETS = {
5320
5366
  )
5321
5367
  };
5322
5368
  var GENERIC_SUBAGENT_BUDGET = {
5323
- timeoutMs: 3 * 60 * 60 * 1e3,
5369
+ idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
5324
5370
  maxIterations: 5e3,
5325
5371
  maxToolCalls: 15e3
5326
5372
  };
@@ -5330,7 +5376,13 @@ function applyRosterBudget(cfg) {
5330
5376
  if (!defaultBudget) return cfg;
5331
5377
  return {
5332
5378
  ...cfg,
5333
- timeoutMs: cfg.timeoutMs ?? defaultBudget.timeoutMs,
5379
+ // Wall-clock cap is opt-in only: forward an explicit `cfg.timeoutMs`, but
5380
+ // do NOT impose the roster's historical multi-hour wall-clock default — it
5381
+ // killed agents that were still actively working. Reaping is idle-based.
5382
+ timeoutMs: cfg.timeoutMs,
5383
+ // Idle window is the default reaper. Resets on activity, so a long-but-
5384
+ // productive run is never killed; only a genuine stall is reaped.
5385
+ idleTimeoutMs: cfg.idleTimeoutMs ?? defaultBudget.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS,
5334
5386
  maxIterations: cfg.maxIterations ?? defaultBudget.maxIterations,
5335
5387
  maxToolCalls: cfg.maxToolCalls ?? defaultBudget.maxToolCalls,
5336
5388
  maxTokens: cfg.maxTokens ?? defaultBudget.maxTokens,
@@ -5890,13 +5942,17 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
5890
5942
  const rawMaxTokens = subagent.config.maxTokens;
5891
5943
  const rawMaxCostUsd = subagent.config.maxCostUsd;
5892
5944
  const rawTimeoutMs = subagent.config.timeoutMs;
5945
+ const rawIdleTimeoutMs = subagent.config.idleTimeoutMs;
5893
5946
  const configWithRosterDefaults = applyRosterBudget(subagent.config);
5894
5947
  const budget = new SubagentBudget({
5895
5948
  maxIterations: rawMaxIterations ?? this.config.defaultBudget?.maxIterations ?? configWithRosterDefaults.maxIterations,
5896
5949
  maxToolCalls: rawMaxToolCalls ?? this.config.defaultBudget?.maxToolCalls ?? configWithRosterDefaults.maxToolCalls,
5897
5950
  maxTokens: rawMaxTokens ?? this.config.defaultBudget?.maxTokens ?? configWithRosterDefaults.maxTokens,
5898
5951
  maxCostUsd: rawMaxCostUsd ?? this.config.defaultBudget?.maxCostUsd ?? configWithRosterDefaults.maxCostUsd,
5899
- timeoutMs: rawTimeoutMs ?? this.config.defaultBudget?.timeoutMs ?? configWithRosterDefaults.timeoutMs
5952
+ // Wall-clock cap is opt-in (explicit config / defaultBudget only); the
5953
+ // roster no longer supplies one. Idle is the default reaper.
5954
+ timeoutMs: rawTimeoutMs ?? this.config.defaultBudget?.timeoutMs ?? configWithRosterDefaults.timeoutMs,
5955
+ idleTimeoutMs: rawIdleTimeoutMs ?? this.config.defaultBudget?.idleTimeoutMs ?? configWithRosterDefaults.idleTimeoutMs
5900
5956
  });
5901
5957
  subagent.activeBudget = budget;
5902
5958
  if (!this.runner) {
@@ -5943,63 +5999,79 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
5943
5999
  }
5944
6000
  async executeWithTimeout(runner, task, ctx, budget) {
5945
6001
  const initialTimeoutMs = budget.limits.timeoutMs;
5946
- if (initialTimeoutMs === void 0) return runner(task, ctx);
6002
+ const idleLimitMs = budget.limits.idleTimeoutMs;
6003
+ if (initialTimeoutMs === void 0 && idleLimitMs === void 0) {
6004
+ return runner(task, ctx);
6005
+ }
5947
6006
  const start = Date.now();
5948
6007
  let timer = null;
5949
6008
  const timeoutPromise = new Promise((_, reject) => {
5950
6009
  const armFor = (ms) => {
5951
6010
  if (timer) clearTimeout(timer);
5952
- timer = setTimeout(async () => {
5953
- const elapsed = Date.now() - start;
5954
- const limit = budget.limits.timeoutMs ?? initialTimeoutMs;
5955
- if (!budget.onThreshold) {
5956
- this.subagents.get(ctx.subagentId)?.abortController.abort();
5957
- reject(new BudgetExceededError("timeout", limit, elapsed));
6011
+ timer = setTimeout(onTick, Math.max(0, ms));
6012
+ };
6013
+ const scheduleNext = () => {
6014
+ const wallRemaining = initialTimeoutMs === void 0 ? Number.POSITIVE_INFINITY : (budget.limits.timeoutMs ?? initialTimeoutMs) - (Date.now() - start);
6015
+ const idleRemaining = idleLimitMs === void 0 ? Number.POSITIVE_INFINITY : (budget.limits.idleTimeoutMs ?? idleLimitMs) - budget.idleMs();
6016
+ armFor(Math.max(25, Math.min(wallRemaining, idleRemaining)));
6017
+ };
6018
+ const onTick = async () => {
6019
+ const elapsed = Date.now() - start;
6020
+ const wallLimit = initialTimeoutMs === void 0 ? void 0 : budget.limits.timeoutMs ?? initialTimeoutMs;
6021
+ const idleLimit = idleLimitMs === void 0 ? void 0 : budget.limits.idleTimeoutMs ?? idleLimitMs;
6022
+ const wallExceeded = wallLimit !== void 0 && elapsed >= wallLimit;
6023
+ const idleExceeded = idleLimit !== void 0 && budget.idleMs() >= idleLimit;
6024
+ if (idleExceeded && !wallExceeded) {
6025
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
6026
+ reject(new BudgetExceededError("timeout", idleLimit, budget.idleMs()));
6027
+ return;
6028
+ }
6029
+ if (!wallExceeded) {
6030
+ scheduleNext();
6031
+ return;
6032
+ }
6033
+ const limit = wallLimit;
6034
+ if (!budget.onThreshold) {
6035
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
6036
+ reject(new BudgetExceededError("timeout", limit, elapsed));
6037
+ return;
6038
+ }
6039
+ try {
6040
+ const result = budget.onThreshold({
6041
+ kind: "timeout",
6042
+ used: elapsed,
6043
+ limit,
6044
+ requestDecision: () => new Promise((resolveDecision) => {
6045
+ budget._events?.emit("budget.threshold_reached", {
6046
+ kind: "timeout",
6047
+ used: elapsed,
6048
+ limit,
6049
+ timeoutMs: 6e4,
6050
+ extend: (extra) => resolveDecision({ extend: extra }),
6051
+ deny: () => resolveDecision("stop")
6052
+ });
6053
+ })
6054
+ });
6055
+ const decision = typeof result === "string" ? result : await result;
6056
+ if (decision === "continue" || decision === "throw" || decision === "stop") {
6057
+ armFor(Math.max(1e3, limit));
5958
6058
  return;
5959
6059
  }
5960
- try {
5961
- const result = budget.onThreshold({
5962
- kind: "timeout",
5963
- used: elapsed,
5964
- limit,
5965
- requestDecision: () => new Promise((resolveDecision) => {
5966
- budget._events?.emit("budget.threshold_reached", {
5967
- kind: "timeout",
5968
- used: elapsed,
5969
- limit,
5970
- timeoutMs: 6e4,
5971
- extend: (extra) => resolveDecision({ extend: extra }),
5972
- deny: () => resolveDecision("stop")
5973
- });
5974
- })
5975
- });
5976
- const decision = typeof result === "string" ? result : await result;
5977
- if (decision === "continue") {
5978
- armFor(Math.max(1e3, limit));
5979
- return;
5980
- }
5981
- if (decision === "throw" || decision === "stop") {
5982
- armFor(Math.max(1e3, limit));
5983
- return;
5984
- }
5985
- if (decision.extend.timeoutMs !== void 0) {
5986
- budget.limits.timeoutMs = decision.extend.timeoutMs;
5987
- const newLimit = decision.extend.timeoutMs;
5988
- const remaining = Math.max(1e3, newLimit - elapsed);
5989
- armFor(remaining);
5990
- return;
5991
- }
5992
- this.subagents.get(ctx.subagentId)?.abortController.abort();
5993
- reject(new BudgetExceededError("timeout", limit, elapsed));
5994
- } catch (err) {
5995
- this.subagents.get(ctx.subagentId)?.abortController.abort();
5996
- reject(
5997
- err instanceof BudgetExceededError ? err : new BudgetExceededError("timeout", limit, elapsed)
5998
- );
6060
+ if (decision.extend.timeoutMs !== void 0) {
6061
+ budget.limits.timeoutMs = decision.extend.timeoutMs;
6062
+ scheduleNext();
6063
+ return;
5999
6064
  }
6000
- }, ms);
6065
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
6066
+ reject(new BudgetExceededError("timeout", limit, elapsed));
6067
+ } catch (err) {
6068
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
6069
+ reject(
6070
+ err instanceof BudgetExceededError ? err : new BudgetExceededError("timeout", limit, elapsed)
6071
+ );
6072
+ }
6001
6073
  };
6002
- armFor(initialTimeoutMs);
6074
+ scheduleNext();
6003
6075
  });
6004
6076
  try {
6005
6077
  return await Promise.race([runner(task, ctx), timeoutPromise]);