nexus-agents 3.15.0 → 4.1.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 (124) hide show
  1. package/dist/{child-mcp-config-P3IMY3SJ.js → child-mcp-config-BV3OSP24.js} +2 -2
  2. package/dist/{chunk-GVGH5NFB.js → chunk-2HCONJES.js} +2 -2
  3. package/dist/{chunk-ALAWHZGZ.js → chunk-3OM2W7H7.js} +2 -2
  4. package/dist/{chunk-CVXS5BGE.js → chunk-4O7TU6R3.js} +2 -2
  5. package/dist/{chunk-OUE5RIYB.js → chunk-4XRV4MIQ.js} +397 -564
  6. package/dist/chunk-4XRV4MIQ.js.map +1 -0
  7. package/dist/{chunk-5XDHMVYV.js → chunk-4XWRSCZ2.js} +3 -3
  8. package/dist/{chunk-IQJUVQXT.js → chunk-4Z2Z52C7.js} +7 -7
  9. package/dist/{chunk-4LD5TWZ5.js → chunk-5HPJB35V.js} +2 -2
  10. package/dist/{chunk-PKJMR6LK.js → chunk-6Q2RAJYX.js} +8 -8
  11. package/dist/{chunk-PKJMR6LK.js.map → chunk-6Q2RAJYX.js.map} +1 -1
  12. package/dist/{chunk-J4VCW54Q.js → chunk-6SBSQDCX.js} +2 -2
  13. package/dist/{chunk-4L7OIPPC.js → chunk-ADIMVMAB.js} +2 -2
  14. package/dist/{chunk-XFWFCNBH.js → chunk-AMEVOGE7.js} +8 -8
  15. package/dist/{chunk-TXZVEYXX.js → chunk-BMEJLPAE.js} +3 -3
  16. package/dist/{chunk-VJIHSPXE.js → chunk-BYDUN7A5.js} +2 -2
  17. package/dist/{chunk-AWMFJK5J.js → chunk-C3KZXEBR.js} +4 -4
  18. package/dist/{chunk-6RMLXVDE.js → chunk-CNB4PA7Q.js} +5 -5
  19. package/dist/{chunk-YQWTGCN4.js → chunk-DQ3GEMM4.js} +5 -5
  20. package/dist/{chunk-GNSY44I6.js → chunk-EXX6WINJ.js} +2 -2
  21. package/dist/{chunk-BWP3SQRB.js → chunk-FD3I5B4X.js} +2 -2
  22. package/dist/{chunk-V5OV5KMM.js → chunk-FRTNZUUF.js} +2 -2
  23. package/dist/{chunk-FMEZ3J4A.js → chunk-HNC2G7AS.js} +2 -2
  24. package/dist/{chunk-ZUHUAKX7.js → chunk-JJEOBIOI.js} +2 -2
  25. package/dist/{chunk-SR5LZ5ZU.js → chunk-JRU5G6VW.js} +2 -2
  26. package/dist/{chunk-PKFOCPWL.js → chunk-KLN7TJLT.js} +2 -2
  27. package/dist/{chunk-3J7AZXDA.js → chunk-KVHA4AEF.js} +4 -4
  28. package/dist/{chunk-Z3EIIXYW.js → chunk-N7YLNXHT.js} +6 -6
  29. package/dist/{chunk-ZD37OJIB.js → chunk-NZHI7FHX.js} +5 -5
  30. package/dist/{chunk-ACR53LYN.js → chunk-QJKXF2MY.js} +31 -8
  31. package/dist/chunk-QJKXF2MY.js.map +1 -0
  32. package/dist/{chunk-WIHC4JQB.js → chunk-S645LGB6.js} +2 -2
  33. package/dist/{chunk-SH3A7WBR.js → chunk-TN7HF2SQ.js} +8 -24
  34. package/dist/{chunk-SH3A7WBR.js.map → chunk-TN7HF2SQ.js.map} +1 -1
  35. package/dist/{chunk-I7GXJESU.js → chunk-UM376MEM.js} +2 -2
  36. package/dist/{chunk-SEIKS6JB.js → chunk-VKLMXCI2.js} +4 -4
  37. package/dist/{chunk-AKFSWIMY.js → chunk-VOLQTAV4.js} +4 -4
  38. package/dist/chunk-VOLQTAV4.js.map +1 -0
  39. package/dist/{chunk-GFQI6SWN.js → chunk-WXCRNJNO.js} +3 -3
  40. package/dist/{cli-circuit-breaker-5XIYJDMM.js → cli-circuit-breaker-NRGM3VBL.js} +3 -3
  41. package/dist/cli.js +41 -41
  42. package/dist/{composite-router-RNU4YHES.js → composite-router-TSPOS57H.js} +2 -2
  43. package/dist/{consensus-vote-CPZ6E5NS.js → consensus-vote-U3OPVEUE.js} +16 -16
  44. package/dist/{context-retriever-HS2TOSPT.js → context-retriever-SGJTQUCI.js} +8 -8
  45. package/dist/{doctor-deep-WULFW3CA.js → doctor-deep-33C5GGB3.js} +3 -3
  46. package/dist/{doctor-live-U5AUMZGG.js → doctor-live-XRIVOJLP.js} +9 -9
  47. package/dist/{expert-bridge-S6SBBQGK.js → expert-bridge-UH44L5CN.js} +4 -4
  48. package/dist/{factory-SOAR6BIV.js → factory-GUDAJED7.js} +9 -9
  49. package/dist/{factory-MZGIHXPG.js → factory-HYFTOF35.js} +5 -5
  50. package/dist/{improvement-review-ZZE67B4L.js → improvement-review-KTOY6EEF.js} +5 -5
  51. package/dist/index.d.ts +66 -202
  52. package/dist/index.js +30 -30
  53. package/dist/{init-opencode-3BV3QDQX.js → init-opencode-PXLOY7XY.js} +6 -6
  54. package/dist/issue-triage-B3KU37U3.js +17 -0
  55. package/dist/{pr-reviewer-helpers-X2F4GXAU.js → pr-reviewer-helpers-QU4F2A3X.js} +4 -4
  56. package/dist/{registry-command-PNBED2PE.js → registry-command-2LQLUUXG.js} +2 -2
  57. package/dist/{repo-security-plan-UHYMCN54.js → repo-security-plan-E2MTJPSC.js} +3 -3
  58. package/dist/{research-helpers-synthesize-QBW2J7OI.js → research-helpers-synthesize-4YBZF2LZ.js} +4 -4
  59. package/dist/{routing-memory-NOXXAXQG.js → routing-memory-EIF5XALW.js} +2 -2
  60. package/dist/{session-memory-OOOKYNUT.js → session-memory-5GVHJR26.js} +3 -3
  61. package/dist/{setup-command-GAUYRBED.js → setup-command-VWTOGR2N.js} +14 -14
  62. package/dist/{setup-config-C5SBEC56.js → setup-config-PMGHQJ6O.js} +3 -3
  63. package/dist/{setup-custom-api-DOE4TSAW.js → setup-custom-api-JXXGF5QD.js} +4 -4
  64. package/dist/{tool-memory-G3FU2RMU.js → tool-memory-YFXJCJFI.js} +5 -5
  65. package/dist/{unified-registry-G4HGJYBH.js → unified-registry-OGXE4772.js} +10 -10
  66. package/dist/{weather-report-HQCHYA6M.js → weather-report-FV6YYGT4.js} +2 -2
  67. package/package.json +1 -1
  68. package/dist/chunk-ACR53LYN.js.map +0 -1
  69. package/dist/chunk-AKFSWIMY.js.map +0 -1
  70. package/dist/chunk-OUE5RIYB.js.map +0 -1
  71. package/dist/issue-triage-NLIV37LO.js +0 -17
  72. /package/dist/{child-mcp-config-P3IMY3SJ.js.map → child-mcp-config-BV3OSP24.js.map} +0 -0
  73. /package/dist/{chunk-GVGH5NFB.js.map → chunk-2HCONJES.js.map} +0 -0
  74. /package/dist/{chunk-ALAWHZGZ.js.map → chunk-3OM2W7H7.js.map} +0 -0
  75. /package/dist/{chunk-CVXS5BGE.js.map → chunk-4O7TU6R3.js.map} +0 -0
  76. /package/dist/{chunk-5XDHMVYV.js.map → chunk-4XWRSCZ2.js.map} +0 -0
  77. /package/dist/{chunk-IQJUVQXT.js.map → chunk-4Z2Z52C7.js.map} +0 -0
  78. /package/dist/{chunk-4LD5TWZ5.js.map → chunk-5HPJB35V.js.map} +0 -0
  79. /package/dist/{chunk-J4VCW54Q.js.map → chunk-6SBSQDCX.js.map} +0 -0
  80. /package/dist/{chunk-4L7OIPPC.js.map → chunk-ADIMVMAB.js.map} +0 -0
  81. /package/dist/{chunk-XFWFCNBH.js.map → chunk-AMEVOGE7.js.map} +0 -0
  82. /package/dist/{chunk-TXZVEYXX.js.map → chunk-BMEJLPAE.js.map} +0 -0
  83. /package/dist/{chunk-VJIHSPXE.js.map → chunk-BYDUN7A5.js.map} +0 -0
  84. /package/dist/{chunk-AWMFJK5J.js.map → chunk-C3KZXEBR.js.map} +0 -0
  85. /package/dist/{chunk-6RMLXVDE.js.map → chunk-CNB4PA7Q.js.map} +0 -0
  86. /package/dist/{chunk-YQWTGCN4.js.map → chunk-DQ3GEMM4.js.map} +0 -0
  87. /package/dist/{chunk-GNSY44I6.js.map → chunk-EXX6WINJ.js.map} +0 -0
  88. /package/dist/{chunk-BWP3SQRB.js.map → chunk-FD3I5B4X.js.map} +0 -0
  89. /package/dist/{chunk-V5OV5KMM.js.map → chunk-FRTNZUUF.js.map} +0 -0
  90. /package/dist/{chunk-FMEZ3J4A.js.map → chunk-HNC2G7AS.js.map} +0 -0
  91. /package/dist/{chunk-ZUHUAKX7.js.map → chunk-JJEOBIOI.js.map} +0 -0
  92. /package/dist/{chunk-SR5LZ5ZU.js.map → chunk-JRU5G6VW.js.map} +0 -0
  93. /package/dist/{chunk-PKFOCPWL.js.map → chunk-KLN7TJLT.js.map} +0 -0
  94. /package/dist/{chunk-3J7AZXDA.js.map → chunk-KVHA4AEF.js.map} +0 -0
  95. /package/dist/{chunk-Z3EIIXYW.js.map → chunk-N7YLNXHT.js.map} +0 -0
  96. /package/dist/{chunk-ZD37OJIB.js.map → chunk-NZHI7FHX.js.map} +0 -0
  97. /package/dist/{chunk-WIHC4JQB.js.map → chunk-S645LGB6.js.map} +0 -0
  98. /package/dist/{chunk-I7GXJESU.js.map → chunk-UM376MEM.js.map} +0 -0
  99. /package/dist/{chunk-SEIKS6JB.js.map → chunk-VKLMXCI2.js.map} +0 -0
  100. /package/dist/{chunk-GFQI6SWN.js.map → chunk-WXCRNJNO.js.map} +0 -0
  101. /package/dist/{cli-circuit-breaker-5XIYJDMM.js.map → cli-circuit-breaker-NRGM3VBL.js.map} +0 -0
  102. /package/dist/{composite-router-RNU4YHES.js.map → composite-router-TSPOS57H.js.map} +0 -0
  103. /package/dist/{consensus-vote-CPZ6E5NS.js.map → consensus-vote-U3OPVEUE.js.map} +0 -0
  104. /package/dist/{context-retriever-HS2TOSPT.js.map → context-retriever-SGJTQUCI.js.map} +0 -0
  105. /package/dist/{doctor-deep-WULFW3CA.js.map → doctor-deep-33C5GGB3.js.map} +0 -0
  106. /package/dist/{doctor-live-U5AUMZGG.js.map → doctor-live-XRIVOJLP.js.map} +0 -0
  107. /package/dist/{expert-bridge-S6SBBQGK.js.map → expert-bridge-UH44L5CN.js.map} +0 -0
  108. /package/dist/{factory-MZGIHXPG.js.map → factory-GUDAJED7.js.map} +0 -0
  109. /package/dist/{factory-SOAR6BIV.js.map → factory-HYFTOF35.js.map} +0 -0
  110. /package/dist/{improvement-review-ZZE67B4L.js.map → improvement-review-KTOY6EEF.js.map} +0 -0
  111. /package/dist/{init-opencode-3BV3QDQX.js.map → init-opencode-PXLOY7XY.js.map} +0 -0
  112. /package/dist/{issue-triage-NLIV37LO.js.map → issue-triage-B3KU37U3.js.map} +0 -0
  113. /package/dist/{pr-reviewer-helpers-X2F4GXAU.js.map → pr-reviewer-helpers-QU4F2A3X.js.map} +0 -0
  114. /package/dist/{registry-command-PNBED2PE.js.map → registry-command-2LQLUUXG.js.map} +0 -0
  115. /package/dist/{repo-security-plan-UHYMCN54.js.map → repo-security-plan-E2MTJPSC.js.map} +0 -0
  116. /package/dist/{research-helpers-synthesize-QBW2J7OI.js.map → research-helpers-synthesize-4YBZF2LZ.js.map} +0 -0
  117. /package/dist/{routing-memory-NOXXAXQG.js.map → routing-memory-EIF5XALW.js.map} +0 -0
  118. /package/dist/{session-memory-OOOKYNUT.js.map → session-memory-5GVHJR26.js.map} +0 -0
  119. /package/dist/{setup-command-GAUYRBED.js.map → setup-command-VWTOGR2N.js.map} +0 -0
  120. /package/dist/{setup-config-C5SBEC56.js.map → setup-config-PMGHQJ6O.js.map} +0 -0
  121. /package/dist/{setup-custom-api-DOE4TSAW.js.map → setup-custom-api-JXXGF5QD.js.map} +0 -0
  122. /package/dist/{tool-memory-G3FU2RMU.js.map → tool-memory-YFXJCJFI.js.map} +0 -0
  123. /package/dist/{unified-registry-G4HGJYBH.js.map → unified-registry-OGXE4772.js.map} +0 -0
  124. /package/dist/{weather-report-HQCHYA6M.js.map → weather-report-FV6YYGT4.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  generateSecurityPlan
3
- } from "./chunk-BWP3SQRB.js";
3
+ } from "./chunk-FD3I5B4X.js";
4
4
  import {
5
5
  analyzeGitHubRepo
6
6
  } from "./chunk-HFOQKCD2.js";
@@ -22,10 +22,10 @@ import {
22
22
  DEFAULT_TASK_TTL_MS,
23
23
  DEFAULT_TOOL_RATE_LIMITS,
24
24
  clampTaskTtl
25
- } from "./chunk-PKJMR6LK.js";
25
+ } from "./chunk-6Q2RAJYX.js";
26
26
  import {
27
27
  executeExpert
28
- } from "./chunk-IQJUVQXT.js";
28
+ } from "./chunk-4Z2Z52C7.js";
29
29
  import {
30
30
  JobStatusSchema,
31
31
  abortJob,
@@ -46,24 +46,24 @@ import {
46
46
  simulationDeniedResult,
47
47
  toJobSummary,
48
48
  writeJobCancelled
49
- } from "./chunk-ACR53LYN.js";
49
+ } from "./chunk-QJKXF2MY.js";
50
50
  import {
51
51
  allOf
52
52
  } from "./chunk-OQB3XC5O.js";
53
53
  import {
54
54
  normalizeTopicToCanonical,
55
55
  synthesizeResearch
56
- } from "./chunk-TXZVEYXX.js";
56
+ } from "./chunk-BMEJLPAE.js";
57
57
  import {
58
58
  IssueTriage
59
- } from "./chunk-Z3EIIXYW.js";
59
+ } from "./chunk-N7YLNXHT.js";
60
60
  import {
61
61
  resolveEnvMode,
62
62
  sanitizeInput
63
- } from "./chunk-4LD5TWZ5.js";
63
+ } from "./chunk-5HPJB35V.js";
64
64
  import {
65
65
  withPrerequisite
66
- } from "./chunk-GFQI6SWN.js";
66
+ } from "./chunk-WXCRNJNO.js";
67
67
  import {
68
68
  NOOP_NOTIFIER,
69
69
  RateLimiter,
@@ -87,18 +87,18 @@ import {
87
87
  withAuditTrail,
88
88
  withProgressHeartbeat,
89
89
  wrapToolWithTimeout
90
- } from "./chunk-AKFSWIMY.js";
90
+ } from "./chunk-VOLQTAV4.js";
91
91
  import {
92
92
  createAuditTrail,
93
93
  createGraphAuditBridge,
94
94
  emitPipelinePolicyEvent
95
- } from "./chunk-4L7OIPPC.js";
95
+ } from "./chunk-ADIMVMAB.js";
96
96
  import {
97
97
  EventTopics,
98
98
  createEvent,
99
99
  getGlobalEventBus,
100
100
  getGlobalRegistry
101
- } from "./chunk-SEIKS6JB.js";
101
+ } from "./chunk-VKLMXCI2.js";
102
102
  import {
103
103
  IDENTIFIER_RE,
104
104
  LANG_VALUES,
@@ -131,31 +131,31 @@ import {
131
131
  parseRegistry,
132
132
  sourceExistsInRegistry,
133
133
  summarizeContextForPrompt
134
- } from "./chunk-6RMLXVDE.js";
134
+ } from "./chunk-CNB4PA7Q.js";
135
135
  import {
136
136
  loadPapersRegistry,
137
137
  loadTechniquesRegistry
138
- } from "./chunk-I7GXJESU.js";
138
+ } from "./chunk-UM376MEM.js";
139
139
  import {
140
140
  resolveInsideRoot
141
141
  } from "./chunk-NUBSJGQZ.js";
142
142
  import {
143
143
  getTokenEnvVars,
144
144
  resolveToken
145
- } from "./chunk-ALAWHZGZ.js";
145
+ } from "./chunk-3OM2W7H7.js";
146
146
  import {
147
147
  DEFAULT_RELEVANCE_CONFIG,
148
148
  MemoryImportance,
149
149
  calculateTextJaccardSimilarity,
150
150
  getToolMemory
151
- } from "./chunk-3J7AZXDA.js";
151
+ } from "./chunk-KVHA4AEF.js";
152
152
  import {
153
153
  STOPWORDS,
154
154
  truncateWithInfo
155
155
  } from "./chunk-6T3EPABN.js";
156
156
  import {
157
157
  createSessionMemory
158
- } from "./chunk-SR5LZ5ZU.js";
158
+ } from "./chunk-JRU5G6VW.js";
159
159
  import {
160
160
  BUILT_IN_EXPERTS,
161
161
  BuiltInExpertTypeSchema,
@@ -173,25 +173,25 @@ import {
173
173
  getAvailableClis,
174
174
  sleep,
175
175
  withTimeout
176
- } from "./chunk-XFWFCNBH.js";
176
+ } from "./chunk-AMEVOGE7.js";
177
177
  import {
178
178
  BaseAdapter,
179
179
  createStream,
180
180
  requireApiKey,
181
181
  validateApiKeyPresence
182
- } from "./chunk-PKFOCPWL.js";
182
+ } from "./chunk-KLN7TJLT.js";
183
183
  import {
184
184
  DEFAULTS
185
- } from "./chunk-FMEZ3J4A.js";
185
+ } from "./chunk-HNC2G7AS.js";
186
186
  import {
187
187
  getAvailabilityCache,
188
188
  getCliForModelId,
189
189
  resolveFallback
190
- } from "./chunk-WIHC4JQB.js";
190
+ } from "./chunk-S645LGB6.js";
191
191
  import {
192
192
  generateHyphenId,
193
193
  generateUUID
194
- } from "./chunk-V5OV5KMM.js";
194
+ } from "./chunk-FRTNZUUF.js";
195
195
  import {
196
196
  AGENT_ROUTER_TIMEOUTS,
197
197
  API_TIMEOUTS,
@@ -291,7 +291,7 @@ import {
291
291
  selectStrategyByManifest,
292
292
  toExpertTaskAnalysisResult,
293
293
  withStep
294
- } from "./chunk-SH3A7WBR.js";
294
+ } from "./chunk-TN7HF2SQ.js";
295
295
  import {
296
296
  ensureLearningDir,
297
297
  getMetaOutcomesFile,
@@ -5215,6 +5215,13 @@ var MIN_EXPERTS_FOR_PATTERN = {
5215
5215
  // Single agent with execution feedback (arXiv:2304.05128)
5216
5216
  };
5217
5217
 
5218
+ // src/agents/collaboration/token-usage-summary.ts
5219
+ function summarizeTokenUsage(contributors) {
5220
+ const totalTokensUsed = contributors.filter((m) => m.tokensMeasured !== false).reduce((sum, m) => sum + m.tokensUsed, 0);
5221
+ const unmeasuredResults = contributors.filter((m) => m.tokensMeasured === false).length;
5222
+ return unmeasuredResults > 0 ? { totalTokensUsed, unmeasuredResults } : { totalTokensUsed };
5223
+ }
5224
+
5218
5225
  // src/agents/collaboration/session-helpers.ts
5219
5226
  function getSequentialAssignments(config, participants, results) {
5220
5227
  const assignments = [];
@@ -5371,7 +5378,9 @@ function buildAggregatedResult(input) {
5371
5378
  resultCount: results.length,
5372
5379
  conflictCount: 0,
5373
5380
  averageConfidence: 1,
5374
- totalTokensUsed: results.reduce((sum, r) => sum + r.metadata.tokensUsed, 0),
5381
+ // #4743: shared with result-aggregator so the two cannot drift — they
5382
+ // were duplicate expressions computing the same thing.
5383
+ ...summarizeTokenUsage(results.map((r) => r.metadata)),
5375
5384
  aggregatedAt: endTime.toISOString()
5376
5385
  }
5377
5386
  };
@@ -9205,7 +9214,7 @@ var WaveScheduler = class {
9205
9214
  if (aborted) break;
9206
9215
  if (this.isTokenBudgetExhausted(totalTokensUsed)) {
9207
9216
  aborted = true;
9208
- abortReason = `Token budget exhausted: ${String(totalTokensUsed)}/${String(this.config.maxTotalTokens)}`;
9217
+ abortReason = `Estimated token budget exhausted: ${String(totalTokensUsed)}/${String(this.config.maxTotalTokens)} (estimate excludes input and failed tasks)`;
9209
9218
  break;
9210
9219
  }
9211
9220
  const wave = taskWaves[waveIdx];
@@ -9240,9 +9249,13 @@ var WaveScheduler = class {
9240
9249
  if (this.config.maxTotalTokens <= 0 || totalTokensUsed < this.config.maxTotalTokens) {
9241
9250
  return false;
9242
9251
  }
9243
- this.logger.warn("Wave execution aborted: token budget exhausted", {
9252
+ this.logger.warn("Wave execution aborted: estimated token budget exhausted", {
9244
9253
  totalTokensUsed,
9245
- maxTotalTokens: this.config.maxTotalTokens
9254
+ maxTotalTokens: this.config.maxTotalTokens,
9255
+ // #4761: say what the figure is. It sums output-char estimates, ignores
9256
+ // input, and counts failed tasks as zero — so the real spend at the point
9257
+ // of abort is HIGHER than the number that triggered it.
9258
+ basis: "sum of outputChars/4 estimates; excludes input and failed tasks"
9246
9259
  });
9247
9260
  return true;
9248
9261
  }
@@ -9309,6 +9322,10 @@ var WaveScheduler = class {
9309
9322
  output: "",
9310
9323
  truncated: false,
9311
9324
  originalLength: 0,
9325
+ // #4761: a task that ran and then threw did not cost nothing — this 0
9326
+ // is "unknown", and it under-counts any budget summing it. There is no
9327
+ // better number available: the executor threw instead of returning
9328
+ // output, and it reports no usage.
9312
9329
  estimatedTokens: 0,
9313
9330
  durationMs,
9314
9331
  error: message
@@ -13838,7 +13855,7 @@ var ResultAggregator = class {
13838
13855
  return ok(void 0);
13839
13856
  }
13840
13857
  buildResult(results, output2, strategy, conflicts, qualityScore) {
13841
- const totalTokensUsed = results.reduce((s, r) => s + r.result.metadata.tokensUsed, 0);
13858
+ const usage = summarizeTokenUsage(results.map((r) => r.result.metadata));
13842
13859
  const avgConfidence = results.reduce((s, r) => s + (r.confidence ?? 0.5), 0) / results.length;
13843
13860
  return {
13844
13861
  output: output2,
@@ -13849,7 +13866,7 @@ var ResultAggregator = class {
13849
13866
  resultCount: results.length,
13850
13867
  conflictCount: conflicts.length,
13851
13868
  averageConfidence: Math.round(avgConfidence * 100) / 100,
13852
- totalTokensUsed,
13869
+ ...usage,
13853
13870
  aggregatedAt: getTimeProvider().nowIso()
13854
13871
  }
13855
13872
  };
@@ -14137,7 +14154,8 @@ function emitPhaseCompleted(eventBus, params) {
14137
14154
  iteration: params.iteration,
14138
14155
  phase: params.phase,
14139
14156
  durationMs: params.durationMs,
14140
- tokensUsed: params.tokensUsed
14157
+ tokensUsed: params.tokensUsed,
14158
+ ...params.tokensMeasured !== void 0 ? { tokensMeasured: params.tokensMeasured } : {}
14141
14159
  },
14142
14160
  { sessionId: params.sessionId }
14143
14161
  );
@@ -14272,23 +14290,25 @@ var TrinityCoordinator = class {
14272
14290
  const result = await ctx.agent.execute(task);
14273
14291
  const durationMs = time.now() - phaseStart;
14274
14292
  const tokensUsed = result.ok ? result.value.metadata.tokensUsed : 0;
14293
+ const tokensMeasured = result.ok ? result.value.metadata.tokensMeasured : void 0;
14275
14294
  emitPhaseCompleted(this.eventBus, {
14276
14295
  iteration: 0,
14277
14296
  phase: "thinker",
14278
14297
  durationMs,
14279
14298
  tokensUsed,
14299
+ // #4743: a failed phase emits this event with tokensUsed 0. Without the
14300
+ // flag that 0 is indistinguishable from a phase that genuinely spent
14301
+ // nothing — and this event is the only observable record of a failure.
14302
+ tokensMeasured: result.ok ? result.value.metadata.tokensMeasured : false,
14280
14303
  sessionId: ctx.sessionId
14281
14304
  });
14282
14305
  if (!result.ok) return err(new AgentError("Thinker phase failed", { cause: result.error }));
14283
14306
  const output2 = String(result.value.output);
14284
14307
  ctx.history.push(
14285
- this.createPhaseResult(
14286
- "thinking",
14287
- "thinker",
14288
- output2,
14289
- phaseStart,
14290
- result.value.metadata.tokensUsed
14291
- )
14308
+ this.createPhaseResult("thinking", "thinker", output2, phaseStart, {
14309
+ tokensUsed,
14310
+ ...tokensMeasured !== void 0 ? { tokensMeasured } : {}
14311
+ })
14292
14312
  );
14293
14313
  return ok(parseThinkerOutput(output2));
14294
14314
  }
@@ -14316,16 +14336,26 @@ Previous Attempt Feedback:
14316
14336
  const result = await ctx.agent.execute(task);
14317
14337
  const durationMs = time.now() - phaseStart;
14318
14338
  const tokensUsed = result.ok ? result.value.metadata.tokensUsed : 0;
14339
+ const tokensMeasured = result.ok ? result.value.metadata.tokensMeasured : void 0;
14319
14340
  emitPhaseCompleted(this.eventBus, {
14320
14341
  iteration,
14321
14342
  phase: "worker",
14322
14343
  durationMs,
14323
14344
  tokensUsed,
14345
+ // #4743: a failed phase emits this event with tokensUsed 0. Without the
14346
+ // flag that 0 is indistinguishable from a phase that genuinely spent
14347
+ // nothing — and this event is the only observable record of a failure.
14348
+ tokensMeasured: result.ok ? result.value.metadata.tokensMeasured : false,
14324
14349
  sessionId: ctx.sessionId
14325
14350
  });
14326
14351
  if (!result.ok) return err(new AgentError("Worker phase failed", { cause: result.error }));
14327
14352
  const output2 = String(result.value.output);
14328
- ctx.history.push(this.createPhaseResult("working", "worker", output2, phaseStart, tokensUsed));
14353
+ ctx.history.push(
14354
+ this.createPhaseResult("working", "worker", output2, phaseStart, {
14355
+ tokensUsed,
14356
+ ...tokensMeasured !== void 0 ? { tokensMeasured } : {}
14357
+ })
14358
+ );
14329
14359
  return ok(parseWorkerOutput(output2));
14330
14360
  }
14331
14361
  async runVerifier(ctx, thinker, worker, iteration) {
@@ -14348,22 +14378,37 @@ ${worker.implementation}`;
14348
14378
  const result = await ctx.agent.execute(task);
14349
14379
  const durationMs = time.now() - phaseStart;
14350
14380
  const tokensUsed = result.ok ? result.value.metadata.tokensUsed : 0;
14381
+ const tokensMeasured = result.ok ? result.value.metadata.tokensMeasured : void 0;
14351
14382
  emitPhaseCompleted(this.eventBus, {
14352
14383
  iteration,
14353
14384
  phase: "verifier",
14354
14385
  durationMs,
14355
14386
  tokensUsed,
14387
+ // #4743: a failed phase emits this event with tokensUsed 0. Without the
14388
+ // flag that 0 is indistinguishable from a phase that genuinely spent
14389
+ // nothing — and this event is the only observable record of a failure.
14390
+ tokensMeasured: result.ok ? result.value.metadata.tokensMeasured : false,
14356
14391
  sessionId: ctx.sessionId
14357
14392
  });
14358
14393
  if (!result.ok) return err(new AgentError("Verifier phase failed", { cause: result.error }));
14359
14394
  const output2 = String(result.value.output);
14360
14395
  ctx.history.push(
14361
- this.createPhaseResult("verifying", "verifier", output2, phaseStart, tokensUsed)
14396
+ this.createPhaseResult("verifying", "verifier", output2, phaseStart, {
14397
+ tokensUsed,
14398
+ ...tokensMeasured !== void 0 ? { tokensMeasured } : {}
14399
+ })
14362
14400
  );
14363
14401
  return ok(parseVerifierOutput(output2));
14364
14402
  }
14365
- createPhaseResult(phase, role, output2, startTime, tokensUsed) {
14366
- return { phase, role, output: output2, durationMs: getTimeProvider().now() - startTime, tokensUsed };
14403
+ createPhaseResult(phase, role, output2, startTime, usage) {
14404
+ return {
14405
+ phase,
14406
+ role,
14407
+ output: output2,
14408
+ durationMs: getTimeProvider().now() - startTime,
14409
+ tokensUsed: usage.tokensUsed,
14410
+ ...usage.tokensMeasured !== void 0 ? { tokensMeasured: usage.tokensMeasured } : {}
14411
+ };
14367
14412
  }
14368
14413
  isTimedOut(ctx) {
14369
14414
  return getTimeProvider().now() - ctx.startTime > this.config.timeoutMs;
@@ -17634,7 +17679,9 @@ var SicaVersionManager = class {
17634
17679
  const count = history.length;
17635
17680
  const successes = history.filter((e) => e.success).length;
17636
17681
  const avgDuration = history.reduce((s, e) => s + e.durationMs, 0) / count;
17637
- const avgTokens = history.reduce((s, e) => s + e.tokensUsed, 0) / count;
17682
+ const measuredTokens = history.filter((e) => e.tokensMeasured !== false);
17683
+ const avgTokens = measuredTokens.length > 0 ? measuredTokens.reduce((s, e) => s + e.tokensUsed, 0) / measuredTokens.length : 0;
17684
+ const unmeasuredExecutions = count - measuredTokens.length;
17638
17685
  const qualityScores = history.filter((e) => e.qualityScore !== void 0);
17639
17686
  const avgQuality = qualityScores.length > 0 ? qualityScores.reduce((s, e) => s + (e.qualityScore ?? 0), 0) / qualityScores.length : void 0;
17640
17687
  entry.metrics = {
@@ -17644,6 +17691,7 @@ var SicaVersionManager = class {
17644
17691
  successRate: count > 0 ? successes / count : 0,
17645
17692
  avgDurationMs: avgDuration,
17646
17693
  avgTokensUsed: avgTokens,
17694
+ ...unmeasuredExecutions > 0 && { unmeasuredExecutions },
17647
17695
  ...avgQuality !== void 0 && { avgQualityScore: avgQuality },
17648
17696
  lastUpdatedAt: new Date(getTimeProvider().now())
17649
17697
  };
@@ -17946,6 +17994,9 @@ var SicaAgent = class {
17946
17994
  return {
17947
17995
  durationMs,
17948
17996
  tokensUsed: 0,
17997
+ // #4743: a failed execution produced no measurement; this 0 is unknown,
17998
+ // not a measured zero, and averaging it in understates cost.
17999
+ tokensMeasured: false,
17949
18000
  success: false,
17950
18001
  errorType: result.error.message
17951
18002
  };
@@ -17953,6 +18004,9 @@ var SicaAgent = class {
17953
18004
  return {
17954
18005
  durationMs,
17955
18006
  tokensUsed: result.value.metadata.tokensUsed,
18007
+ ...result.value.metadata.tokensMeasured !== void 0 && {
18008
+ tokensMeasured: result.value.metadata.tokensMeasured
18009
+ },
17956
18010
  success: true,
17957
18011
  qualityScore: estimateQuality(result.value)
17958
18012
  };
@@ -22708,407 +22762,6 @@ function createStepExecutor(deps) {
22708
22762
  return new StepExecutor(deps);
22709
22763
  }
22710
22764
 
22711
- // src/workflows/budget-circuit-breaker-types.ts
22712
- import { z as z37 } from "zod";
22713
- var BudgetCircuitBreakerConfigSchema = z37.object({
22714
- /** Warning threshold as percentage (0-1) of budget (default: 0.8) */
22715
- warningThreshold: z37.number().min(0).max(1).default(0.8),
22716
- /** Critical threshold as percentage (0-1) that opens circuit (default: 0.95) */
22717
- criticalThreshold: z37.number().min(0).max(1).default(0.95),
22718
- /** Time in ms to wait before allowing half-open probes (default: 5000) */
22719
- cooldownMs: z37.number().positive().default(5e3),
22720
- /** Number of successful low-usage probes to close circuit (default: 2) */
22721
- recoveryProbes: z37.number().int().positive().default(2),
22722
- /** Whether to enforce hard stops (default: true) */
22723
- hardStop: z37.boolean().default(true),
22724
- /** Reserve percentage for step completion (default: 0.1) */
22725
- stepReserve: z37.number().min(0).max(0.5).default(0.1)
22726
- });
22727
- var DEFAULT_BUDGET_CIRCUIT_CONFIG = {
22728
- warningThreshold: 0.8,
22729
- criticalThreshold: 0.95,
22730
- cooldownMs: 5e3,
22731
- recoveryProbes: 2,
22732
- hardStop: true,
22733
- stepReserve: 0.1
22734
- };
22735
- var BudgetCircuitError = class extends NexusError {
22736
- budgetErrorCode;
22737
- circuitState;
22738
- usage;
22739
- constructor(message, options) {
22740
- const baseOptions = {
22741
- code: ErrorCode.RATE_LIMIT_ERROR,
22742
- context: {
22743
- budgetErrorCode: options.budgetErrorCode,
22744
- circuitState: options.circuitState,
22745
- currentTokens: options.usage.currentTokens,
22746
- maxTokens: options.usage.maxTokens,
22747
- usagePercent: options.usage.usagePercent
22748
- }
22749
- };
22750
- if (options.cause !== void 0) {
22751
- baseOptions.cause = options.cause;
22752
- }
22753
- super(message, baseOptions);
22754
- this.name = "BudgetCircuitError";
22755
- this.budgetErrorCode = options.budgetErrorCode;
22756
- this.circuitState = options.circuitState;
22757
- this.usage = options.usage;
22758
- }
22759
- };
22760
-
22761
- // src/workflows/budget-circuit-breaker.ts
22762
- var BudgetCircuitBreaker = class {
22763
- constructor(maxTokens, config, logger59) {
22764
- this.maxTokens = maxTokens;
22765
- this.config = { ...DEFAULT_BUDGET_CIRCUIT_CONFIG, ...config };
22766
- this.lastStateChange = getTimeProvider().now();
22767
- this.logger = logger59 ?? createLogger({ component: "budget-circuit-breaker" });
22768
- }
22769
- maxTokens;
22770
- state = "closed";
22771
- lastStateChange;
22772
- violationCount = 0;
22773
- recoveryProbeCount = 0;
22774
- lastUsage = null;
22775
- currentTokens = 0;
22776
- listeners = /* @__PURE__ */ new Set();
22777
- logger;
22778
- config;
22779
- checkBudget(estimatedTokens) {
22780
- this.checkCooldown();
22781
- const usage = this.createUsageSnapshot();
22782
- const projectedUsage = this.calculateProjectedUsage(estimatedTokens);
22783
- if (this.state === "open") {
22784
- return this.createBlockedResult(usage, "Circuit is open - budget exceeded");
22785
- }
22786
- if (this.state === "half-open") {
22787
- return this.handleHalfOpenCheck(estimatedTokens, usage, projectedUsage);
22788
- }
22789
- return this.handleClosedCheck(estimatedTokens, usage, projectedUsage);
22790
- }
22791
- recordUsage(actualTokens) {
22792
- this.currentTokens += actualTokens;
22793
- this.lastUsage = this.createUsageSnapshot();
22794
- this.logger.debug("Budget usage recorded", {
22795
- actualTokens,
22796
- totalUsed: this.currentTokens,
22797
- maxTokens: this.maxTokens,
22798
- usagePercent: this.lastUsage.usagePercent
22799
- });
22800
- if (this.state === "closed" && this.lastUsage.usagePercent >= this.config.criticalThreshold) {
22801
- this.transitionTo("open", "Usage exceeded critical threshold after recording");
22802
- }
22803
- }
22804
- allocateForStep(stepId, remainingSteps) {
22805
- const available = Math.max(0, this.maxTokens - this.currentTokens);
22806
- const reserveForOthers = remainingSteps > 1 ? this.config.stepReserve * available : 0;
22807
- const allocatable = available - reserveForOthers;
22808
- const perStepAllocation = Math.floor(allocatable / Math.max(1, remainingSteps));
22809
- this.logger.debug("Step budget allocated", {
22810
- stepId,
22811
- remainingSteps,
22812
- available,
22813
- allocated: perStepAllocation,
22814
- reserveForOthers: Math.floor(reserveForOthers)
22815
- });
22816
- return {
22817
- stepId,
22818
- allocatedTokens: perStepAllocation,
22819
- remainingForOtherSteps: available - perStepAllocation,
22820
- remainingStepCount: remainingSteps - 1
22821
- };
22822
- }
22823
- getState() {
22824
- this.checkCooldown();
22825
- return this.state;
22826
- }
22827
- getSnapshot() {
22828
- this.checkCooldown();
22829
- return {
22830
- state: this.state,
22831
- lastStateChange: this.lastStateChange,
22832
- violationCount: this.violationCount,
22833
- recoveryProbeCount: this.recoveryProbeCount,
22834
- lastUsage: this.lastUsage,
22835
- config: this.config
22836
- };
22837
- }
22838
- reset() {
22839
- const previousState = this.state;
22840
- this.state = "closed";
22841
- this.violationCount = 0;
22842
- this.recoveryProbeCount = 0;
22843
- this.currentTokens = 0;
22844
- this.lastStateChange = getTimeProvider().now();
22845
- this.lastUsage = null;
22846
- if (previousState !== "closed") {
22847
- this.emitStateChange(previousState, "closed", "Manual reset");
22848
- }
22849
- this.logger.info("Budget circuit breaker reset");
22850
- }
22851
- forceOpen(reason) {
22852
- if (this.state !== "open") {
22853
- this.transitionTo("open", `Forced open: ${reason}`);
22854
- }
22855
- }
22856
- addStateChangeListener(listener) {
22857
- this.listeners.add(listener);
22858
- }
22859
- removeStateChangeListener(listener) {
22860
- this.listeners.delete(listener);
22861
- }
22862
- // -------------------------------------------------------------------------
22863
- // Private Methods - State Transitions
22864
- // -------------------------------------------------------------------------
22865
- checkCooldown() {
22866
- if (this.state !== "open") return;
22867
- const elapsed = getTimeProvider().now() - this.lastStateChange;
22868
- if (elapsed >= this.config.cooldownMs) {
22869
- this.transitionTo("half-open", "Cooldown elapsed");
22870
- }
22871
- }
22872
- transitionTo(newState, reason) {
22873
- const previousState = this.state;
22874
- this.state = newState;
22875
- this.lastStateChange = getTimeProvider().now();
22876
- if (newState === "closed") {
22877
- this.violationCount = 0;
22878
- this.recoveryProbeCount = 0;
22879
- } else if (newState === "half-open") {
22880
- this.recoveryProbeCount = 0;
22881
- }
22882
- this.emitStateChange(previousState, newState, reason);
22883
- }
22884
- emitStateChange(previousState, newState, reason) {
22885
- const event = {
22886
- previousState,
22887
- newState,
22888
- timestamp: this.lastStateChange,
22889
- reason,
22890
- usage: this.lastUsage ?? this.createUsageSnapshot()
22891
- };
22892
- this.logger.info("Budget circuit state changed", {
22893
- previousState,
22894
- newState,
22895
- reason,
22896
- usagePercent: event.usage.usagePercent
22897
- });
22898
- for (const listener of this.listeners) {
22899
- try {
22900
- listener(event);
22901
- } catch {
22902
- }
22903
- }
22904
- }
22905
- // -------------------------------------------------------------------------
22906
- // Private Methods - Budget Checks
22907
- // -------------------------------------------------------------------------
22908
- handleClosedCheck(estimatedTokens, usage, projectedUsage) {
22909
- if (projectedUsage >= this.config.criticalThreshold) {
22910
- this.violationCount++;
22911
- if (this.config.hardStop) {
22912
- this.transitionTo("open", "Projected usage exceeds critical threshold");
22913
- return this.createBlockedResult(usage, "Budget exceeded - circuit opened");
22914
- }
22915
- }
22916
- const warning = projectedUsage >= this.config.warningThreshold ? this.createWarningMessage(projectedUsage) : void 0;
22917
- return this.createAllowedResult(usage, estimatedTokens, warning);
22918
- }
22919
- handleHalfOpenCheck(estimatedTokens, usage, projectedUsage) {
22920
- if (projectedUsage < this.config.warningThreshold) {
22921
- this.recoveryProbeCount++;
22922
- if (this.recoveryProbeCount >= this.config.recoveryProbes) {
22923
- this.transitionTo("closed", "Recovery probes successful");
22924
- }
22925
- return this.createAllowedResult(usage, estimatedTokens, "Recovery probe allowed");
22926
- }
22927
- this.transitionTo("open", "Recovery probe failed - usage still high");
22928
- return this.createBlockedResult(usage, "Recovery probe failed");
22929
- }
22930
- calculateProjectedUsage(estimatedTokens) {
22931
- const projected = this.currentTokens + estimatedTokens;
22932
- return this.maxTokens > 0 ? projected / this.maxTokens : 0;
22933
- }
22934
- createUsageSnapshot() {
22935
- const usagePercent = this.maxTokens > 0 ? this.currentTokens / this.maxTokens : 0;
22936
- return {
22937
- currentTokens: this.currentTokens,
22938
- maxTokens: this.maxTokens,
22939
- usagePercent,
22940
- availableTokens: Math.max(0, this.maxTokens - this.currentTokens),
22941
- timestamp: getTimeProvider().now()
22942
- };
22943
- }
22944
- // -------------------------------------------------------------------------
22945
- // Private Methods - Result Creation
22946
- // -------------------------------------------------------------------------
22947
- createBlockedResult(usage, reason) {
22948
- return {
22949
- allowed: false,
22950
- reason,
22951
- usage,
22952
- circuitState: this.state
22953
- };
22954
- }
22955
- createAllowedResult(usage, estimatedTokens, warning) {
22956
- const result = {
22957
- allowed: true,
22958
- reason: "Within budget",
22959
- usage,
22960
- circuitState: this.state,
22961
- allocatedTokens: estimatedTokens
22962
- };
22963
- if (warning !== void 0) {
22964
- return { ...result, warning };
22965
- }
22966
- return result;
22967
- }
22968
- createWarningMessage(projectedUsage) {
22969
- const percentUsed = Math.round(projectedUsage * 100);
22970
- return `Budget warning: ${String(percentUsed)}% of budget will be used`;
22971
- }
22972
- };
22973
- function createBudgetCircuitBreaker(maxTokens, config, logger59) {
22974
- const mergedConfig = {
22975
- ...DEFAULT_BUDGET_CIRCUIT_CONFIG,
22976
- ...config
22977
- };
22978
- return new BudgetCircuitBreaker(maxTokens, mergedConfig, logger59);
22979
- }
22980
-
22981
- // src/workflows/budget-enforcement.ts
22982
- function applyBudgetEnforcement(step, contextManager, budgetEvents, config) {
22983
- if (contextManager === void 0) {
22984
- return;
22985
- }
22986
- const { budget, source } = resolveStepBudget(step, config);
22987
- const stats = contextManager.getStats();
22988
- const statsBefore = {
22989
- totalTokens: stats.totalTokens,
22990
- availableTokens: stats.availableTokens,
22991
- usagePercentage: stats.usagePercentage
22992
- };
22993
- const event = {
22994
- timestamp: getTimeProvider().now(),
22995
- stepId: step.id,
22996
- budget,
22997
- source,
22998
- statsBefore
22999
- };
23000
- budgetEvents.push(event);
23001
- config.logger.debug("Budget enforcement applied for step", {
23002
- stepId: step.id,
23003
- source,
23004
- budget,
23005
- currentUsage: Math.round(statsBefore.usagePercentage * 100)
23006
- });
23007
- }
23008
- function enforceBudgetForStep(options) {
23009
- const { step, contextManager, circuitBreaker, budgetEvents, config, estimatedTokens } = options;
23010
- if (contextManager === void 0) {
23011
- return ok(createSkippedResult());
23012
- }
23013
- const { budget, source } = resolveStepBudget(step, config);
23014
- const stats = contextManager.getStats();
23015
- const statsBefore = {
23016
- totalTokens: stats.totalTokens,
23017
- availableTokens: stats.availableTokens,
23018
- usagePercentage: stats.usagePercentage
23019
- };
23020
- const enforcementResult = circuitBreaker.checkBudget(estimatedTokens);
23021
- const event = {
23022
- timestamp: getTimeProvider().now(),
23023
- stepId: step.id,
23024
- budget,
23025
- source,
23026
- statsBefore,
23027
- enforcementResult,
23028
- blocked: !enforcementResult.allowed
23029
- };
23030
- budgetEvents.push(event);
23031
- logEnforcementResult(config.logger, step.id, enforcementResult, statsBefore.usagePercentage);
23032
- if (!enforcementResult.allowed) {
23033
- return err(
23034
- new BudgetCircuitError(enforcementResult.reason, {
23035
- budgetErrorCode: "BUDGET_EXCEEDED",
23036
- circuitState: enforcementResult.circuitState,
23037
- usage: enforcementResult.usage
23038
- })
23039
- );
23040
- }
23041
- return ok(enforcementResult);
23042
- }
23043
- function createWorkflowCircuitBreaker(contextManager, config) {
23044
- if (contextManager === void 0) {
23045
- return void 0;
23046
- }
23047
- const stats = contextManager.getStats();
23048
- const maxTokens = Math.round(stats.availableTokens + stats.totalTokens);
23049
- const cbConfig = config.circuitBreakerConfig;
23050
- return new BudgetCircuitBreaker(maxTokens, cbConfig, config.logger);
23051
- }
23052
- function resolveStepBudget(step, config) {
23053
- if (step.contextBudget !== void 0) {
23054
- const baseBudget = config.workflowDefaultBudget ?? config.engineDefaultBudget;
23055
- const mergedBudget = {
23056
- system: step.contextBudget.system ?? baseBudget.system,
23057
- task: step.contextBudget.task ?? baseBudget.task,
23058
- active: step.contextBudget.active ?? baseBudget.active,
23059
- reserved: step.contextBudget.reserved ?? baseBudget.reserved
23060
- };
23061
- return { budget: mergedBudget, source: "step" };
23062
- }
23063
- if (config.workflowDefaultBudget !== void 0) {
23064
- return { budget: config.workflowDefaultBudget, source: "workflow" };
23065
- }
23066
- return { budget: config.engineDefaultBudget, source: "engine" };
23067
- }
23068
- function copyBudgetEvents(events) {
23069
- return [...events];
23070
- }
23071
- function createSkippedResult() {
23072
- return {
23073
- allowed: true,
23074
- reason: "No context manager - enforcement skipped",
23075
- usage: {
23076
- currentTokens: 0,
23077
- maxTokens: 0,
23078
- usagePercent: 0,
23079
- availableTokens: 0,
23080
- timestamp: getTimeProvider().now()
23081
- },
23082
- circuitState: "closed"
23083
- };
23084
- }
23085
- function logEnforcementResult(logger59, stepId, result, currentUsagePercent) {
23086
- const usagePercent = Math.round(currentUsagePercent * 100);
23087
- if (!result.allowed) {
23088
- logger59.warn("Budget enforcement blocked step", {
23089
- stepId,
23090
- reason: result.reason,
23091
- circuitState: result.circuitState,
23092
- currentUsage: usagePercent,
23093
- budgetUsage: Math.round(result.usage.usagePercent * 100)
23094
- });
23095
- return;
23096
- }
23097
- if (result.warning !== void 0) {
23098
- logger59.warn("Budget enforcement warning", {
23099
- stepId,
23100
- warning: result.warning,
23101
- currentUsage: usagePercent
23102
- });
23103
- return;
23104
- }
23105
- logger59.debug("Budget enforcement passed for step", {
23106
- stepId,
23107
- currentUsage: usagePercent,
23108
- allocatedTokens: result.allocatedTokens
23109
- });
23110
- }
23111
-
23112
22765
  // src/workflows/workflow-engine-helpers.ts
23113
22766
  var DEFAULT_TIMEOUT_MS2 = 3e5;
23114
22767
  var DEFAULT_MAX_CONCURRENCY = 5;
@@ -23118,9 +22771,7 @@ var DEFAULT_RESOLVED_CONFIG = {
23118
22771
  maxConcurrency: DEFAULT_MAX_CONCURRENCY,
23119
22772
  templatePaths: [],
23120
22773
  contextManagerConfig: void 0,
23121
- defaultBudget: DEFAULT_BUDGET,
23122
- budgetCircuitBreakerConfig: void 0,
23123
- enableBudgetEnforcement: false
22774
+ defaultBudget: DEFAULT_BUDGET
23124
22775
  };
23125
22776
  function resolveConfig2(config) {
23126
22777
  if (config === void 0) {
@@ -23143,19 +22794,6 @@ function createContextManagerForWorkflow(config, workflow, logger59) {
23143
22794
  const budget = workflow.defaultBudget ?? config.defaultBudget;
23144
22795
  return new ContextManager({ ...config.contextManagerConfig, budget, logger: logger59 });
23145
22796
  }
23146
- function createBudgetCircuitBreakerForWorkflow(contextManager, workflow, config, logger59) {
23147
- const budgetConfig = {
23148
- engineDefaultBudget: config.defaultBudget,
23149
- logger: logger59
23150
- };
23151
- if (workflow.defaultBudget !== void 0) {
23152
- budgetConfig.workflowDefaultBudget = workflow.defaultBudget;
23153
- }
23154
- if (config.budgetCircuitBreakerConfig !== void 0) {
23155
- budgetConfig.circuitBreakerConfig = config.budgetCircuitBreakerConfig;
23156
- }
23157
- return createWorkflowCircuitBreaker(contextManager, budgetConfig);
23158
- }
23159
22797
  function cleanupOldExecutions(executions) {
23160
22798
  if (executions.size < MAX_TRACKED_EXECUTIONS) return;
23161
22799
  const completed = [];
@@ -23186,7 +22824,6 @@ function initializeExecution(params) {
23186
22824
  const startTime = getTimeProvider().now();
23187
22825
  const resolvedInputs = applyInputDefaults(workflow, inputs);
23188
22826
  const contextManager = createContextManagerForWorkflow(config, workflow, logger59);
23189
- const budgetCircuitBreaker = config.enableBudgetEnforcement ? createBudgetCircuitBreakerForWorkflow(contextManager, workflow, config, logger59) : void 0;
23190
22827
  const context = {
23191
22828
  workflowId: workflow.name,
23192
22829
  executionId,
@@ -23194,9 +22831,7 @@ function initializeExecution(params) {
23194
22831
  stepResults: /* @__PURE__ */ new Map(),
23195
22832
  variables: /* @__PURE__ */ new Map(),
23196
22833
  abortController: new AbortController(),
23197
- contextManager,
23198
- budgetEvents: [],
23199
- budgetCircuitBreaker
22834
+ contextManager
23200
22835
  };
23201
22836
  const execution = {
23202
22837
  executionId,
@@ -23214,48 +22849,7 @@ function initializeExecution(params) {
23214
22849
  }
23215
22850
  return { executionId, context, startTime, execution };
23216
22851
  }
23217
- function enforceStepBudgets(options) {
23218
- const { steps, context, workflow, totalSteps, config, logger: logger59 } = options;
23219
- const budgetConfig = {
23220
- engineDefaultBudget: config.defaultBudget,
23221
- logger: logger59
23222
- };
23223
- if (workflow.defaultBudget !== void 0) {
23224
- budgetConfig.workflowDefaultBudget = workflow.defaultBudget;
23225
- }
23226
- if (config.budgetCircuitBreakerConfig !== void 0) {
23227
- budgetConfig.circuitBreakerConfig = config.budgetCircuitBreakerConfig;
23228
- }
23229
- for (const step of steps) {
23230
- if (context.budgetCircuitBreaker !== void 0) {
23231
- const remainingSteps = totalSteps - context.stepResults.size;
23232
- const allocation = context.budgetCircuitBreaker.allocateForStep(step.id, remainingSteps);
23233
- const result = enforceBudgetForStep({
23234
- step,
23235
- contextManager: context.contextManager,
23236
- circuitBreaker: context.budgetCircuitBreaker,
23237
- budgetEvents: context.budgetEvents,
23238
- config: budgetConfig,
23239
- estimatedTokens: allocation.allocatedTokens
23240
- });
23241
- if (!result.ok) {
23242
- return err(
23243
- new WorkflowError(`Budget exceeded for step '${step.id}': ${result.error.message}`, {
23244
- context: { stepId: step.id, circuitState: result.error.circuitState },
23245
- cause: result.error
23246
- })
23247
- );
23248
- }
23249
- } else {
23250
- applyBudgetEnforcement(step, context.contextManager, context.budgetEvents, budgetConfig);
23251
- }
23252
- }
23253
- return ok(void 0);
23254
- }
23255
- function recordPhaseUsage(results, context) {
23256
- if (context.budgetCircuitBreaker === void 0) {
23257
- return { recordedSteps: 0, unmeasuredSteps: 0, tokensRecorded: 0 };
23258
- }
22852
+ function recordPhaseUsage(results) {
23259
22853
  let unmeasuredSteps = 0;
23260
22854
  let recordedSteps = 0;
23261
22855
  let tokensRecorded = 0;
@@ -23264,7 +22858,6 @@ function recordPhaseUsage(results, context) {
23264
22858
  unmeasuredSteps += 1;
23265
22859
  continue;
23266
22860
  }
23267
- context.budgetCircuitBreaker.recordUsage(result.tokensUsed);
23268
22861
  recordedSteps += 1;
23269
22862
  tokensRecorded += result.tokensUsed;
23270
22863
  }
@@ -23360,16 +22953,9 @@ var WorkflowEngine = class {
23360
22953
  const exec2 = this.executions.get(executionId);
23361
22954
  return exec2 ? exec2.status : { state: "failed", error: "Execution not found" };
23362
22955
  }
23363
- getBudgetEvents(executionId) {
23364
- const exec2 = this.executions.get(executionId);
23365
- return exec2 ? copyBudgetEvents(exec2.context.budgetEvents) : [];
23366
- }
23367
22956
  getContextManager(executionId) {
23368
22957
  return this.executions.get(executionId)?.context.contextManager;
23369
22958
  }
23370
- getBudgetCircuitBreaker(executionId) {
23371
- return this.executions.get(executionId)?.context.budgetCircuitBreaker;
23372
- }
23373
22959
  cancel(executionId) {
23374
22960
  const exec2 = this.executions.get(executionId);
23375
22961
  if (!exec2) {
@@ -23472,15 +23058,6 @@ var WorkflowEngine = class {
23472
23058
  currentStep,
23473
23059
  progress: completedSteps / totalSteps
23474
23060
  });
23475
- const enforceResult = enforceStepBudgets({
23476
- steps: phase.steps,
23477
- context,
23478
- workflow,
23479
- totalSteps,
23480
- config: this.config,
23481
- logger: this.logger
23482
- });
23483
- if (!enforceResult.ok) return enforceResult;
23484
23061
  const options = {
23485
23062
  maxConcurrency: this.config.maxConcurrency,
23486
23063
  failFast: true,
@@ -23488,7 +23065,7 @@ var WorkflowEngine = class {
23488
23065
  };
23489
23066
  const phaseResult = await this.deps.executePhase(phase.steps, context, options);
23490
23067
  if (!phaseResult.ok) return phaseResult;
23491
- this.reportUsageCoverage(recordPhaseUsage(phaseResult.value, context), workflow.name);
23068
+ this.reportUsageCoverage(recordPhaseUsage(phaseResult.value), workflow.name);
23492
23069
  for (const result of phaseResult.value) {
23493
23070
  context.stepResults.set(result.stepId, result);
23494
23071
  allResults.push(result);
@@ -23818,41 +23395,286 @@ async function createProductionWorkflowEngine(config) {
23818
23395
  }
23819
23396
 
23820
23397
  // src/workflows/self-evolving/sew-types.ts
23821
- import { z as z38 } from "zod";
23822
- var EvolutionConfigSchema = z38.object({
23823
- mutationRate: z38.number().min(0).max(1).default(0.3),
23824
- populationSize: z38.number().int().min(2).max(20).default(5),
23825
- generations: z38.number().int().min(1).max(100).default(10),
23826
- minExecutionsForEval: z38.number().int().min(1).default(5),
23827
- promotionThreshold: z38.number().min(0).max(1).default(0.7),
23828
- regressionThreshold: z38.number().min(0).max(1).default(0.1),
23829
- selectionPressure: z38.number().min(1).max(3).default(1.5),
23830
- crossoverRate: z38.number().min(0).max(1).default(0.3),
23831
- elitismCount: z38.number().int().min(0).default(1),
23832
- timeoutAdjustmentRange: z38.tuple([z38.number().min(0.1), z38.number().max(10)]).default([0.5, 2]),
23833
- retryAdjustmentRange: z38.tuple([z38.number().int(), z38.number().int()]).default([-2, 2])
23398
+ import { z as z37 } from "zod";
23399
+ var EvolutionConfigSchema = z37.object({
23400
+ mutationRate: z37.number().min(0).max(1).default(0.3),
23401
+ populationSize: z37.number().int().min(2).max(20).default(5),
23402
+ generations: z37.number().int().min(1).max(100).default(10),
23403
+ minExecutionsForEval: z37.number().int().min(1).default(5),
23404
+ promotionThreshold: z37.number().min(0).max(1).default(0.7),
23405
+ regressionThreshold: z37.number().min(0).max(1).default(0.1),
23406
+ selectionPressure: z37.number().min(1).max(3).default(1.5),
23407
+ crossoverRate: z37.number().min(0).max(1).default(0.3),
23408
+ elitismCount: z37.number().int().min(0).default(1),
23409
+ timeoutAdjustmentRange: z37.tuple([z37.number().min(0.1), z37.number().max(10)]).default([0.5, 2]),
23410
+ retryAdjustmentRange: z37.tuple([z37.number().int(), z37.number().int()]).default([-2, 2])
23834
23411
  });
23835
23412
 
23836
23413
  // src/workflows/aflow/aflow-types.ts
23837
- import { z as z39 } from "zod";
23838
- var AFlowConfigSchema = z39.object({
23839
- maxIterations: z39.number().int().positive().default(100),
23840
- maxDepth: z39.number().int().positive().default(10),
23841
- explorationConstant: z39.number().positive().default(Math.SQRT2),
23842
- simulationsPerExpansion: z39.number().int().positive().default(5),
23843
- acceptanceThreshold: z39.number().min(0).max(1).default(0.7),
23844
- maxSteps: z39.number().int().positive().default(20),
23845
- minSteps: z39.number().int().positive().default(2),
23846
- evaluationTimeoutMs: z39.number().int().positive().default(SINGLE_LLM_EVAL_TIMEOUT_MS),
23847
- enableEarlyTermination: z39.boolean().default(true),
23848
- earlyTerminationThreshold: z39.number().min(0).max(1).default(0.9),
23849
- temperature: z39.number().positive().default(1),
23850
- seed: z39.number().int().nullable().default(null)
23414
+ import { z as z38 } from "zod";
23415
+ var AFlowConfigSchema = z38.object({
23416
+ maxIterations: z38.number().int().positive().default(100),
23417
+ maxDepth: z38.number().int().positive().default(10),
23418
+ explorationConstant: z38.number().positive().default(Math.SQRT2),
23419
+ simulationsPerExpansion: z38.number().int().positive().default(5),
23420
+ acceptanceThreshold: z38.number().min(0).max(1).default(0.7),
23421
+ maxSteps: z38.number().int().positive().default(20),
23422
+ minSteps: z38.number().int().positive().default(2),
23423
+ evaluationTimeoutMs: z38.number().int().positive().default(SINGLE_LLM_EVAL_TIMEOUT_MS),
23424
+ enableEarlyTermination: z38.boolean().default(true),
23425
+ earlyTerminationThreshold: z38.number().min(0).max(1).default(0.9),
23426
+ temperature: z38.number().positive().default(1),
23427
+ seed: z38.number().int().nullable().default(null)
23851
23428
  });
23852
23429
 
23853
23430
  // src/workflows/aflow/aflow-generator.ts
23854
23431
  var logger11 = createLogger({ component: "AFlow" });
23855
23432
 
23433
+ // src/workflows/budget-circuit-breaker-types.ts
23434
+ import { z as z39 } from "zod";
23435
+ var BudgetCircuitBreakerConfigSchema = z39.object({
23436
+ /** Warning threshold as percentage (0-1) of budget (default: 0.8) */
23437
+ warningThreshold: z39.number().min(0).max(1).default(0.8),
23438
+ /** Critical threshold as percentage (0-1) that opens circuit (default: 0.95) */
23439
+ criticalThreshold: z39.number().min(0).max(1).default(0.95),
23440
+ /** Time in ms to wait before allowing half-open probes (default: 5000) */
23441
+ cooldownMs: z39.number().positive().default(5e3),
23442
+ /** Number of successful low-usage probes to close circuit (default: 2) */
23443
+ recoveryProbes: z39.number().int().positive().default(2),
23444
+ /** Whether to enforce hard stops (default: true) */
23445
+ hardStop: z39.boolean().default(true),
23446
+ /** Reserve percentage for step completion (default: 0.1) */
23447
+ stepReserve: z39.number().min(0).max(0.5).default(0.1)
23448
+ });
23449
+ var DEFAULT_BUDGET_CIRCUIT_CONFIG = {
23450
+ warningThreshold: 0.8,
23451
+ criticalThreshold: 0.95,
23452
+ cooldownMs: 5e3,
23453
+ recoveryProbes: 2,
23454
+ hardStop: true,
23455
+ stepReserve: 0.1
23456
+ };
23457
+
23458
+ // src/workflows/budget-circuit-breaker.ts
23459
+ var BudgetCircuitBreaker = class {
23460
+ constructor(maxTokens, config, logger59) {
23461
+ this.maxTokens = maxTokens;
23462
+ this.config = { ...DEFAULT_BUDGET_CIRCUIT_CONFIG, ...config };
23463
+ this.lastStateChange = getTimeProvider().now();
23464
+ this.logger = logger59 ?? createLogger({ component: "budget-circuit-breaker" });
23465
+ }
23466
+ maxTokens;
23467
+ state = "closed";
23468
+ lastStateChange;
23469
+ violationCount = 0;
23470
+ recoveryProbeCount = 0;
23471
+ lastUsage = null;
23472
+ currentTokens = 0;
23473
+ listeners = /* @__PURE__ */ new Set();
23474
+ logger;
23475
+ config;
23476
+ checkBudget(estimatedTokens) {
23477
+ this.checkCooldown();
23478
+ const usage = this.createUsageSnapshot();
23479
+ const projectedUsage = this.calculateProjectedUsage(estimatedTokens);
23480
+ if (this.state === "open") {
23481
+ return this.createBlockedResult(usage, "Circuit is open - budget exceeded");
23482
+ }
23483
+ if (this.state === "half-open") {
23484
+ return this.handleHalfOpenCheck(estimatedTokens, usage, projectedUsage);
23485
+ }
23486
+ return this.handleClosedCheck(estimatedTokens, usage, projectedUsage);
23487
+ }
23488
+ recordUsage(actualTokens) {
23489
+ this.currentTokens += actualTokens;
23490
+ this.lastUsage = this.createUsageSnapshot();
23491
+ this.logger.debug("Budget usage recorded", {
23492
+ actualTokens,
23493
+ totalUsed: this.currentTokens,
23494
+ maxTokens: this.maxTokens,
23495
+ usagePercent: this.lastUsage.usagePercent
23496
+ });
23497
+ if (this.state === "closed" && this.lastUsage.usagePercent >= this.config.criticalThreshold) {
23498
+ this.transitionTo("open", "Usage exceeded critical threshold after recording");
23499
+ }
23500
+ }
23501
+ allocateForStep(stepId, remainingSteps) {
23502
+ const available = Math.max(0, this.maxTokens - this.currentTokens);
23503
+ const reserveForOthers = remainingSteps > 1 ? this.config.stepReserve * available : 0;
23504
+ const allocatable = available - reserveForOthers;
23505
+ const perStepAllocation = Math.floor(allocatable / Math.max(1, remainingSteps));
23506
+ this.logger.debug("Step budget allocated", {
23507
+ stepId,
23508
+ remainingSteps,
23509
+ available,
23510
+ allocated: perStepAllocation,
23511
+ reserveForOthers: Math.floor(reserveForOthers)
23512
+ });
23513
+ return {
23514
+ stepId,
23515
+ allocatedTokens: perStepAllocation,
23516
+ remainingForOtherSteps: available - perStepAllocation,
23517
+ remainingStepCount: remainingSteps - 1
23518
+ };
23519
+ }
23520
+ getState() {
23521
+ this.checkCooldown();
23522
+ return this.state;
23523
+ }
23524
+ getSnapshot() {
23525
+ this.checkCooldown();
23526
+ return {
23527
+ state: this.state,
23528
+ lastStateChange: this.lastStateChange,
23529
+ violationCount: this.violationCount,
23530
+ recoveryProbeCount: this.recoveryProbeCount,
23531
+ lastUsage: this.lastUsage,
23532
+ config: this.config
23533
+ };
23534
+ }
23535
+ reset() {
23536
+ const previousState = this.state;
23537
+ this.state = "closed";
23538
+ this.violationCount = 0;
23539
+ this.recoveryProbeCount = 0;
23540
+ this.currentTokens = 0;
23541
+ this.lastStateChange = getTimeProvider().now();
23542
+ this.lastUsage = null;
23543
+ if (previousState !== "closed") {
23544
+ this.emitStateChange(previousState, "closed", "Manual reset");
23545
+ }
23546
+ this.logger.info("Budget circuit breaker reset");
23547
+ }
23548
+ forceOpen(reason) {
23549
+ if (this.state !== "open") {
23550
+ this.transitionTo("open", `Forced open: ${reason}`);
23551
+ }
23552
+ }
23553
+ addStateChangeListener(listener) {
23554
+ this.listeners.add(listener);
23555
+ }
23556
+ removeStateChangeListener(listener) {
23557
+ this.listeners.delete(listener);
23558
+ }
23559
+ // -------------------------------------------------------------------------
23560
+ // Private Methods - State Transitions
23561
+ // -------------------------------------------------------------------------
23562
+ checkCooldown() {
23563
+ if (this.state !== "open") return;
23564
+ const elapsed = getTimeProvider().now() - this.lastStateChange;
23565
+ if (elapsed >= this.config.cooldownMs) {
23566
+ this.transitionTo("half-open", "Cooldown elapsed");
23567
+ }
23568
+ }
23569
+ transitionTo(newState, reason) {
23570
+ const previousState = this.state;
23571
+ this.state = newState;
23572
+ this.lastStateChange = getTimeProvider().now();
23573
+ if (newState === "closed") {
23574
+ this.violationCount = 0;
23575
+ this.recoveryProbeCount = 0;
23576
+ } else if (newState === "half-open") {
23577
+ this.recoveryProbeCount = 0;
23578
+ }
23579
+ this.emitStateChange(previousState, newState, reason);
23580
+ }
23581
+ emitStateChange(previousState, newState, reason) {
23582
+ const event = {
23583
+ previousState,
23584
+ newState,
23585
+ timestamp: this.lastStateChange,
23586
+ reason,
23587
+ usage: this.lastUsage ?? this.createUsageSnapshot()
23588
+ };
23589
+ this.logger.info("Budget circuit state changed", {
23590
+ previousState,
23591
+ newState,
23592
+ reason,
23593
+ usagePercent: event.usage.usagePercent
23594
+ });
23595
+ for (const listener of this.listeners) {
23596
+ try {
23597
+ listener(event);
23598
+ } catch {
23599
+ }
23600
+ }
23601
+ }
23602
+ // -------------------------------------------------------------------------
23603
+ // Private Methods - Budget Checks
23604
+ // -------------------------------------------------------------------------
23605
+ handleClosedCheck(estimatedTokens, usage, projectedUsage) {
23606
+ if (projectedUsage >= this.config.criticalThreshold) {
23607
+ this.violationCount++;
23608
+ if (this.config.hardStop) {
23609
+ this.transitionTo("open", "Projected usage exceeds critical threshold");
23610
+ return this.createBlockedResult(usage, "Budget exceeded - circuit opened");
23611
+ }
23612
+ }
23613
+ const warning = projectedUsage >= this.config.warningThreshold ? this.createWarningMessage(projectedUsage) : void 0;
23614
+ return this.createAllowedResult(usage, estimatedTokens, warning);
23615
+ }
23616
+ handleHalfOpenCheck(estimatedTokens, usage, projectedUsage) {
23617
+ if (projectedUsage < this.config.warningThreshold) {
23618
+ this.recoveryProbeCount++;
23619
+ if (this.recoveryProbeCount >= this.config.recoveryProbes) {
23620
+ this.transitionTo("closed", "Recovery probes successful");
23621
+ }
23622
+ return this.createAllowedResult(usage, estimatedTokens, "Recovery probe allowed");
23623
+ }
23624
+ this.transitionTo("open", "Recovery probe failed - usage still high");
23625
+ return this.createBlockedResult(usage, "Recovery probe failed");
23626
+ }
23627
+ calculateProjectedUsage(estimatedTokens) {
23628
+ const projected = this.currentTokens + estimatedTokens;
23629
+ return this.maxTokens > 0 ? projected / this.maxTokens : 0;
23630
+ }
23631
+ createUsageSnapshot() {
23632
+ const usagePercent = this.maxTokens > 0 ? this.currentTokens / this.maxTokens : 0;
23633
+ return {
23634
+ currentTokens: this.currentTokens,
23635
+ maxTokens: this.maxTokens,
23636
+ usagePercent,
23637
+ availableTokens: Math.max(0, this.maxTokens - this.currentTokens),
23638
+ timestamp: getTimeProvider().now()
23639
+ };
23640
+ }
23641
+ // -------------------------------------------------------------------------
23642
+ // Private Methods - Result Creation
23643
+ // -------------------------------------------------------------------------
23644
+ createBlockedResult(usage, reason) {
23645
+ return {
23646
+ allowed: false,
23647
+ reason,
23648
+ usage,
23649
+ circuitState: this.state
23650
+ };
23651
+ }
23652
+ createAllowedResult(usage, estimatedTokens, warning) {
23653
+ const result = {
23654
+ allowed: true,
23655
+ reason: "Within budget",
23656
+ usage,
23657
+ circuitState: this.state,
23658
+ allocatedTokens: estimatedTokens
23659
+ };
23660
+ if (warning !== void 0) {
23661
+ return { ...result, warning };
23662
+ }
23663
+ return result;
23664
+ }
23665
+ createWarningMessage(projectedUsage) {
23666
+ const percentUsed = Math.round(projectedUsage * 100);
23667
+ return `Budget warning: ${String(percentUsed)}% of budget will be used`;
23668
+ }
23669
+ };
23670
+ function createBudgetCircuitBreaker(maxTokens, config, logger59) {
23671
+ const mergedConfig = {
23672
+ ...DEFAULT_BUDGET_CIRCUIT_CONFIG,
23673
+ ...config
23674
+ };
23675
+ return new BudgetCircuitBreaker(maxTokens, mergedConfig, logger59);
23676
+ }
23677
+
23856
23678
  // src/workflows/latts-types.ts
23857
23679
  import { z as z40 } from "zod";
23858
23680
  var LattsConfigSchema = z40.object({
@@ -28422,7 +28244,7 @@ function execIdFields(executionId) {
28422
28244
  async function populateUnifiedContextOnState(state, options) {
28423
28245
  const taskCandidate = state["task"];
28424
28246
  if (typeof taskCandidate !== "string" || taskCandidate === "") return;
28425
- const { getContextForTask: getContextForTask2, inferTaskCategory: inferTaskCategory2 } = await import("./context-retriever-HS2TOSPT.js");
28247
+ const { getContextForTask: getContextForTask2, inferTaskCategory: inferTaskCategory2 } = await import("./context-retriever-SGJTQUCI.js");
28426
28248
  const category = inferTaskCategory2(taskCandidate);
28427
28249
  const executionId = options?.executionId;
28428
28250
  const execFields = execIdFields(executionId);
@@ -38196,6 +38018,9 @@ function observeExpertContextIfOk(result, expert, task, durationMs, logger59) {
38196
38018
  role: expert.role,
38197
38019
  modelId: expertModelId,
38198
38020
  tokensUsed: result.value.metadata.tokensUsed,
38021
+ // #4743: provenance travels with the number, so a consumer can tell a
38022
+ // measured zero from an unreported one.
38023
+ ...result.value.metadata.tokensMeasured !== void 0 ? { tokensMeasured: result.value.metadata.tokensMeasured } : {},
38199
38024
  taskDescription: task.description,
38200
38025
  durationMs
38201
38026
  };
@@ -44102,7 +43927,7 @@ async function tryIssueTriage(task) {
44102
43927
  try {
44103
43928
  const issueMatch = task.match(/github\.com\/([^/]+\/[^/]+)\/issues\/(\d+)/);
44104
43929
  if (issueMatch === null) return null;
44105
- const { createIssueTriage } = await import("./issue-triage-NLIV37LO.js");
43930
+ const { createIssueTriage } = await import("./issue-triage-B3KU37U3.js");
44106
43931
  const triage = createIssueTriage();
44107
43932
  const owner = issueMatch[1] ?? "";
44108
43933
  const num = issueMatch[2] ?? "";
@@ -44130,7 +43955,7 @@ var VALID_TEMPLATES = /* @__PURE__ */ new Set([
44130
43955
  ]);
44131
43956
  async function classifyWithLLM(task) {
44132
43957
  try {
44133
- const { executeExpert: executeExpert2 } = await import("./expert-bridge-S6SBBQGK.js");
43958
+ const { executeExpert: executeExpert2 } = await import("./expert-bridge-UH44L5CN.js");
44134
43959
  const prompt = [
44135
43960
  "Classify this task into exactly one pipeline template.",
44136
43961
  "Templates: dev (implementation/bug fix/refactor), research (investigate/evaluate/compare),",
@@ -44658,7 +44483,11 @@ function buildDryRunResult(planResult) {
44658
44483
  tasks: [],
44659
44484
  voteIterations: planResult.iterations,
44660
44485
  qaIterations: 0,
44661
- securityPassed: false
44486
+ // #4772: a dry run stops before security by design. `false` alone read as
44487
+ // "the security gate rejected this"; `securityRan: false` says it never ran.
44488
+ securityPassed: false,
44489
+ securityRan: false,
44490
+ ...planResult.plan.trim() === "" ? { planStatus: "empty" } : {}
44662
44491
  };
44663
44492
  }
44664
44493
  async function resolveResearch(prior, task, stages, options) {
@@ -44816,6 +44645,10 @@ async function planVoteLoop(task, research, stages, sessionId) {
44816
44645
  { name: `plan (i=${String(i)})`, kind: "pipeline.stage", attrs: { iteration: i } },
44817
44646
  () => stages.plan(task, research, feedback)
44818
44647
  );
44648
+ if (plan.trim() === "") {
44649
+ logger42.warn("Planner returned no plan \u2014 stopping before vote", { iteration: i, sessionId });
44650
+ return { plan: "", iterations: i, conditional: false, conditions: [], caveats: [] };
44651
+ }
44819
44652
  const vote = await withStep(
44820
44653
  { name: `vote (i=${String(i)})`, kind: "consensus.vote", attrs: { iteration: i } },
44821
44654
  async (ctx) => {
@@ -45857,7 +45690,7 @@ var memoryInitPromise = null;
45857
45690
  async function initPipelineMemory() {
45858
45691
  if (cachedMemory !== null) return cachedMemory;
45859
45692
  try {
45860
- const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-OOOKYNUT.js");
45693
+ const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-5GVHJR26.js");
45861
45694
  const { getLearningDir } = await import("./learning-persistence-EGY4VKKO.js");
45862
45695
  const mem = createSessionMemory2(getLearningDir());
45863
45696
  mem.startSession(`pipeline-${String(getTimeProvider().now())}`);
@@ -45919,7 +45752,7 @@ function recordRoutingExperience(category, success, durationMs, tokensUsed = 0,
45919
45752
  callRecord(routingMemoryCache);
45920
45753
  return;
45921
45754
  }
45922
- routingMemoryInitPromise ??= import("./routing-memory-NOXXAXQG.js").then(({ createRoutingMemory }) => {
45755
+ routingMemoryInitPromise ??= import("./routing-memory-EIF5XALW.js").then(({ createRoutingMemory }) => {
45923
45756
  routingMemoryCache ??= createRoutingMemory();
45924
45757
  return routingMemoryCache;
45925
45758
  }).catch((error) => {
@@ -45953,7 +45786,7 @@ ${text}` : "";
45953
45786
  }
45954
45787
  async function getWeatherContext() {
45955
45788
  try {
45956
- const { generateWeatherReport: generateWeatherReport2 } = await import("./weather-report-HQCHYA6M.js");
45789
+ const { generateWeatherReport: generateWeatherReport2 } = await import("./weather-report-FV6YYGT4.js");
45957
45790
  const report = generateWeatherReport2({ includeAdaptive: true });
45958
45791
  const mappings = "recommendedMappings" in report ? report.recommendedMappings : [];
45959
45792
  if (!Array.isArray(mappings) || mappings.length === 0) return "";
@@ -45971,7 +45804,7 @@ ${lines}
45971
45804
  }
45972
45805
  async function getMemoryContext(task) {
45973
45806
  try {
45974
- const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-OOOKYNUT.js");
45807
+ const { createSessionMemory: createSessionMemory2 } = await import("./session-memory-5GVHJR26.js");
45975
45808
  const { getLearningDir } = await import("./learning-persistence-EGY4VKKO.js");
45976
45809
  const memory = createSessionMemory2(getLearningDir(), { maxLearningsInContext: 10 });
45977
45810
  const learnings = memory.searchLearnings(task.slice(0, 200));
@@ -46082,7 +45915,7 @@ ${contextBlock}`;
46082
45915
  durationMs: r.durationMs
46083
45916
  });
46084
45917
  await postProgress(config, "Plan", `Done (${r.text.length} chars, ${r.durationMs}ms)`);
46085
- return r.text || prompt;
45918
+ return r.text;
46086
45919
  },
46087
45920
  vote: async (plan, research) => {
46088
45921
  startStage("vote");
@@ -46090,7 +45923,7 @@ ${contextBlock}`;
46090
45923
  const strategy = config.votingStrategy ?? "higher_order";
46091
45924
  await postProgress(config, "Vote", `Running consensus with ${strategy} strategy...`);
46092
45925
  try {
46093
- const { executeVoting } = await import("./consensus-vote-CPZ6E5NS.js");
45926
+ const { executeVoting } = await import("./consensus-vote-U3OPVEUE.js");
46094
45927
  const votingResult = await executeVoting(
46095
45928
  {
46096
45929
  proposal: buildVoteProposal(plan, research),
@@ -46529,7 +46362,7 @@ async function searchCodebaseForTask(task) {
46529
46362
  }
46530
46363
  async function queryResearchRegistry(task) {
46531
46364
  try {
46532
- const { synthesizeResearch: synthesizeResearch2 } = await import("./research-helpers-synthesize-QBW2J7OI.js");
46365
+ const { synthesizeResearch: synthesizeResearch2 } = await import("./research-helpers-synthesize-4YBZF2LZ.js");
46533
46366
  const topic = task.split(/[.!?\n]/).filter((s) => s.trim().length > 10)[0]?.trim();
46534
46367
  if (topic === void 0) return null;
46535
46368
  const result = await synthesizeResearch2(topic.slice(0, 50));
@@ -46600,7 +46433,7 @@ function createScanStageWrapper() {
46600
46433
  try {
46601
46434
  const slug = ctx.task.match(/([a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+)/)?.[1];
46602
46435
  if (slug !== void 0) {
46603
- const { generateSecurityPlan: generateSecurityPlan2 } = await import("./repo-security-plan-UHYMCN54.js");
46436
+ const { generateSecurityPlan: generateSecurityPlan2 } = await import("./repo-security-plan-E2MTJPSC.js");
46604
46437
  const plan = await generateSecurityPlan2({ repo: slug, maxScanners: 10 });
46605
46438
  const recs = plan.recommendations.slice(0, 5).map((r) => `${r.priority}: ${r.displayName} (${r.category})`).join("; ");
46606
46439
  return output(PIPELINE_STATE_KEYS.FINDINGS, recs, getTimeProvider().now() - start, true);
@@ -49689,7 +49522,7 @@ var GitHubTaskTracker = class {
49689
49522
  cachedProvider = null;
49690
49523
  async getProvider() {
49691
49524
  if (this.cachedProvider !== null) return this.cachedProvider;
49692
- const { createScmProvider } = await import("./factory-MZGIHXPG.js");
49525
+ const { createScmProvider } = await import("./factory-HYFTOF35.js");
49693
49526
  const result = await createScmProvider({ repo: this.config.repo ?? "" });
49694
49527
  if (!result.ok) throw new Error(`SCM provider error: ${result.error.message}`);
49695
49528
  this.cachedProvider = result.value;
@@ -50539,7 +50372,7 @@ async function probeSource(source, includeModelIds) {
50539
50372
  }
50540
50373
  }
50541
50374
  async function defaultSources(includeOpenRouter) {
50542
- const { createAllAdapters: createAllAdapters2 } = await import("./factory-SOAR6BIV.js");
50375
+ const { createAllAdapters: createAllAdapters2 } = await import("./factory-GUDAJED7.js");
50543
50376
  const adapters = createAllAdapters2();
50544
50377
  return buildDefaultModelSources(adapters, { includeOpenRouter });
50545
50378
  }
@@ -54581,4 +54414,4 @@ export {
54581
54414
  shutdownFeedbackSubscriber,
54582
54415
  createEventBusBridge
54583
54416
  };
54584
- //# sourceMappingURL=chunk-OUE5RIYB.js.map
54417
+ //# sourceMappingURL=chunk-4XRV4MIQ.js.map