agent-relay 4.0.35 → 4.0.36

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 (199) hide show
  1. package/README.md +3 -6
  2. package/dist/index.cjs +775 -40
  3. package/dist/src/cli/bootstrap.js.map +1 -1
  4. package/dist/src/cli/commands/cloud.js.map +1 -1
  5. package/dist/src/cli/commands/core.d.ts.map +1 -1
  6. package/dist/src/cli/commands/core.js.map +1 -1
  7. package/dist/src/cli/commands/messaging.d.ts.map +1 -1
  8. package/dist/src/cli/commands/messaging.js.map +1 -1
  9. package/dist/src/cli/commands/monitoring.d.ts.map +1 -1
  10. package/dist/src/cli/commands/monitoring.js.map +1 -1
  11. package/node_modules/@agent-relay/cloud/package.json +2 -2
  12. package/node_modules/@agent-relay/config/package.json +2 -2
  13. package/node_modules/@agent-relay/hooks/package.json +4 -4
  14. package/node_modules/@agent-relay/sdk/dist/relay.d.ts.map +1 -1
  15. package/node_modules/@agent-relay/sdk/dist/relay.js.map +1 -1
  16. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/budget-enforcement.test.d.ts +2 -0
  17. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/budget-enforcement.test.d.ts.map +1 -0
  18. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/budget-enforcement.test.js +437 -0
  19. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/budget-enforcement.test.js.map +1 -0
  20. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/budget-tracker.test.d.ts +2 -0
  21. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/budget-tracker.test.d.ts.map +1 -0
  22. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/budget-tracker.test.js +99 -0
  23. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/budget-tracker.test.js.map +1 -0
  24. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/proxy-env.test.d.ts +2 -0
  25. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/proxy-env.test.d.ts.map +1 -0
  26. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/proxy-env.test.js +135 -0
  27. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/proxy-env.test.js.map +1 -0
  28. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification-custom.test.d.ts +2 -0
  29. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification-custom.test.d.ts.map +1 -0
  30. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification-custom.test.js +236 -0
  31. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification-custom.test.js.map +1 -0
  32. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification-traceback.test.d.ts +2 -0
  33. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification-traceback.test.d.ts.map +1 -0
  34. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification-traceback.test.js +448 -0
  35. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification-traceback.test.js.map +1 -0
  36. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification.test.js +71 -4
  37. package/node_modules/@agent-relay/sdk/dist/workflows/__tests__/verification.test.js.map +1 -1
  38. package/node_modules/@agent-relay/sdk/dist/workflows/budget-tracker.d.ts +75 -0
  39. package/node_modules/@agent-relay/sdk/dist/workflows/budget-tracker.d.ts.map +1 -0
  40. package/node_modules/@agent-relay/sdk/dist/workflows/budget-tracker.js +180 -0
  41. package/node_modules/@agent-relay/sdk/dist/workflows/budget-tracker.js.map +1 -0
  42. package/node_modules/@agent-relay/sdk/dist/workflows/builder.d.ts +1 -0
  43. package/node_modules/@agent-relay/sdk/dist/workflows/builder.d.ts.map +1 -1
  44. package/node_modules/@agent-relay/sdk/dist/workflows/builder.js +17 -2
  45. package/node_modules/@agent-relay/sdk/dist/workflows/builder.js.map +1 -1
  46. package/node_modules/@agent-relay/sdk/dist/workflows/index.d.ts +2 -0
  47. package/node_modules/@agent-relay/sdk/dist/workflows/index.d.ts.map +1 -1
  48. package/node_modules/@agent-relay/sdk/dist/workflows/index.js +2 -0
  49. package/node_modules/@agent-relay/sdk/dist/workflows/index.js.map +1 -1
  50. package/node_modules/@agent-relay/sdk/dist/workflows/proxy-env.d.ts +52 -0
  51. package/node_modules/@agent-relay/sdk/dist/workflows/proxy-env.d.ts.map +1 -0
  52. package/node_modules/@agent-relay/sdk/dist/workflows/proxy-env.js +92 -0
  53. package/node_modules/@agent-relay/sdk/dist/workflows/proxy-env.js.map +1 -0
  54. package/node_modules/@agent-relay/sdk/dist/workflows/run-summary-table.d.ts +2 -1
  55. package/node_modules/@agent-relay/sdk/dist/workflows/run-summary-table.d.ts.map +1 -1
  56. package/node_modules/@agent-relay/sdk/dist/workflows/run-summary-table.js +41 -9
  57. package/node_modules/@agent-relay/sdk/dist/workflows/run-summary-table.js.map +1 -1
  58. package/node_modules/@agent-relay/sdk/dist/workflows/runner.d.ts +17 -0
  59. package/node_modules/@agent-relay/sdk/dist/workflows/runner.d.ts.map +1 -1
  60. package/node_modules/@agent-relay/sdk/dist/workflows/runner.js +390 -16
  61. package/node_modules/@agent-relay/sdk/dist/workflows/runner.js.map +1 -1
  62. package/node_modules/@agent-relay/sdk/dist/workflows/types.d.ts +47 -1
  63. package/node_modules/@agent-relay/sdk/dist/workflows/types.d.ts.map +1 -1
  64. package/node_modules/@agent-relay/sdk/dist/workflows/types.js.map +1 -1
  65. package/node_modules/@agent-relay/sdk/dist/workflows/verification.d.ts +9 -0
  66. package/node_modules/@agent-relay/sdk/dist/workflows/verification.d.ts.map +1 -1
  67. package/node_modules/@agent-relay/sdk/dist/workflows/verification.js +78 -2
  68. package/node_modules/@agent-relay/sdk/dist/workflows/verification.js.map +1 -1
  69. package/node_modules/@agent-relay/sdk/package.json +7 -3
  70. package/node_modules/@agent-relay/telemetry/dist/config.d.ts.map +1 -1
  71. package/node_modules/@agent-relay/telemetry/dist/config.js +2 -4
  72. package/node_modules/@agent-relay/telemetry/dist/config.js.map +1 -1
  73. package/node_modules/@agent-relay/telemetry/dist/events.d.ts +1 -2
  74. package/node_modules/@agent-relay/telemetry/dist/events.d.ts.map +1 -1
  75. package/node_modules/@agent-relay/telemetry/dist/index.d.ts +1 -1
  76. package/node_modules/@agent-relay/telemetry/dist/index.d.ts.map +1 -1
  77. package/node_modules/@agent-relay/telemetry/dist/index.js +1 -1
  78. package/node_modules/@agent-relay/telemetry/dist/index.js.map +1 -1
  79. package/node_modules/@agent-relay/telemetry/package.json +1 -1
  80. package/node_modules/@agent-relay/trajectory/package.json +2 -2
  81. package/node_modules/@agent-relay/user-directory/package.json +2 -2
  82. package/node_modules/@agent-relay/utils/package.json +2 -2
  83. package/node_modules/@aws-sdk/core/dist-cjs/index.js +2 -0
  84. package/node_modules/@aws-sdk/core/dist-cjs/submodules/client/index.js +3 -0
  85. package/node_modules/@aws-sdk/core/dist-es/submodules/client/setFeature.js +2 -0
  86. package/node_modules/@aws-sdk/core/dist-types/submodules/client/setFeature.d.ts +1 -1
  87. package/node_modules/@aws-sdk/core/package.json +6 -4
  88. package/node_modules/@aws-sdk/credential-provider-env/package.json +2 -2
  89. package/node_modules/@aws-sdk/credential-provider-http/package.json +5 -5
  90. package/node_modules/@aws-sdk/credential-provider-ini/package.json +9 -9
  91. package/node_modules/@aws-sdk/credential-provider-login/package.json +3 -3
  92. package/node_modules/@aws-sdk/credential-provider-node/package.json +7 -7
  93. package/node_modules/@aws-sdk/credential-provider-process/package.json +2 -2
  94. package/node_modules/@aws-sdk/credential-provider-sso/package.json +4 -4
  95. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +3 -3
  96. package/node_modules/@aws-sdk/middleware-flexible-checksums/package.json +4 -4
  97. package/node_modules/@aws-sdk/middleware-sdk-s3/package.json +5 -5
  98. package/node_modules/@aws-sdk/middleware-user-agent/package.json +5 -5
  99. package/node_modules/@aws-sdk/nested-clients/package.json +18 -18
  100. package/node_modules/@aws-sdk/region-config-resolver/package.json +2 -2
  101. package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +2 -2
  102. package/node_modules/@aws-sdk/token-providers/package.json +3 -3
  103. package/node_modules/@aws-sdk/util-endpoints/package.json +2 -2
  104. package/node_modules/@aws-sdk/util-user-agent-node/package.json +2 -2
  105. package/node_modules/axios/CHANGELOG.md +112 -44
  106. package/node_modules/axios/README.md +30 -0
  107. package/node_modules/axios/dist/axios.js +34 -11
  108. package/node_modules/axios/dist/axios.js.map +1 -1
  109. package/node_modules/axios/dist/axios.min.js +2 -2
  110. package/node_modules/axios/dist/axios.min.js.map +1 -1
  111. package/node_modules/axios/dist/browser/axios.cjs +32 -6
  112. package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
  113. package/node_modules/axios/dist/esm/axios.js +32 -6
  114. package/node_modules/axios/dist/esm/axios.js.map +1 -1
  115. package/node_modules/axios/dist/esm/axios.min.js +2 -2
  116. package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
  117. package/node_modules/axios/dist/node/axios.cjs +91 -37
  118. package/node_modules/axios/dist/node/axios.cjs.map +1 -1
  119. package/node_modules/axios/index.d.cts +1 -0
  120. package/node_modules/axios/index.d.ts +1 -0
  121. package/node_modules/axios/lib/adapters/http.js +69 -22
  122. package/node_modules/axios/lib/core/mergeConfig.js +13 -1
  123. package/node_modules/axios/lib/env/data.js +1 -1
  124. package/node_modules/axios/lib/helpers/resolveConfig.js +14 -2
  125. package/node_modules/axios/lib/helpers/validator.js +3 -1
  126. package/node_modules/axios/package.json +1 -1
  127. package/package.json +9 -9
  128. package/packages/cloud/package.json +2 -2
  129. package/packages/config/package.json +2 -2
  130. package/packages/hooks/package.json +4 -4
  131. package/packages/sdk/dist/relay.d.ts.map +1 -1
  132. package/packages/sdk/dist/relay.js.map +1 -1
  133. package/packages/sdk/dist/workflows/__tests__/budget-enforcement.test.d.ts +2 -0
  134. package/packages/sdk/dist/workflows/__tests__/budget-enforcement.test.d.ts.map +1 -0
  135. package/packages/sdk/dist/workflows/__tests__/budget-enforcement.test.js +437 -0
  136. package/packages/sdk/dist/workflows/__tests__/budget-enforcement.test.js.map +1 -0
  137. package/packages/sdk/dist/workflows/__tests__/budget-tracker.test.d.ts +2 -0
  138. package/packages/sdk/dist/workflows/__tests__/budget-tracker.test.d.ts.map +1 -0
  139. package/packages/sdk/dist/workflows/__tests__/budget-tracker.test.js +99 -0
  140. package/packages/sdk/dist/workflows/__tests__/budget-tracker.test.js.map +1 -0
  141. package/packages/sdk/dist/workflows/__tests__/proxy-env.test.d.ts +2 -0
  142. package/packages/sdk/dist/workflows/__tests__/proxy-env.test.d.ts.map +1 -0
  143. package/packages/sdk/dist/workflows/__tests__/proxy-env.test.js +135 -0
  144. package/packages/sdk/dist/workflows/__tests__/proxy-env.test.js.map +1 -0
  145. package/packages/sdk/dist/workflows/__tests__/verification-custom.test.d.ts +2 -0
  146. package/packages/sdk/dist/workflows/__tests__/verification-custom.test.d.ts.map +1 -0
  147. package/packages/sdk/dist/workflows/__tests__/verification-custom.test.js +236 -0
  148. package/packages/sdk/dist/workflows/__tests__/verification-custom.test.js.map +1 -0
  149. package/packages/sdk/dist/workflows/__tests__/verification-traceback.test.d.ts +2 -0
  150. package/packages/sdk/dist/workflows/__tests__/verification-traceback.test.d.ts.map +1 -0
  151. package/packages/sdk/dist/workflows/__tests__/verification-traceback.test.js +448 -0
  152. package/packages/sdk/dist/workflows/__tests__/verification-traceback.test.js.map +1 -0
  153. package/packages/sdk/dist/workflows/__tests__/verification.test.js +71 -4
  154. package/packages/sdk/dist/workflows/__tests__/verification.test.js.map +1 -1
  155. package/packages/sdk/dist/workflows/budget-tracker.d.ts +75 -0
  156. package/packages/sdk/dist/workflows/budget-tracker.d.ts.map +1 -0
  157. package/packages/sdk/dist/workflows/budget-tracker.js +180 -0
  158. package/packages/sdk/dist/workflows/budget-tracker.js.map +1 -0
  159. package/packages/sdk/dist/workflows/builder.d.ts +1 -0
  160. package/packages/sdk/dist/workflows/builder.d.ts.map +1 -1
  161. package/packages/sdk/dist/workflows/builder.js +17 -2
  162. package/packages/sdk/dist/workflows/builder.js.map +1 -1
  163. package/packages/sdk/dist/workflows/index.d.ts +2 -0
  164. package/packages/sdk/dist/workflows/index.d.ts.map +1 -1
  165. package/packages/sdk/dist/workflows/index.js +2 -0
  166. package/packages/sdk/dist/workflows/index.js.map +1 -1
  167. package/packages/sdk/dist/workflows/proxy-env.d.ts +52 -0
  168. package/packages/sdk/dist/workflows/proxy-env.d.ts.map +1 -0
  169. package/packages/sdk/dist/workflows/proxy-env.js +92 -0
  170. package/packages/sdk/dist/workflows/proxy-env.js.map +1 -0
  171. package/packages/sdk/dist/workflows/run-summary-table.d.ts +2 -1
  172. package/packages/sdk/dist/workflows/run-summary-table.d.ts.map +1 -1
  173. package/packages/sdk/dist/workflows/run-summary-table.js +41 -9
  174. package/packages/sdk/dist/workflows/run-summary-table.js.map +1 -1
  175. package/packages/sdk/dist/workflows/runner.d.ts +17 -0
  176. package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
  177. package/packages/sdk/dist/workflows/runner.js +390 -16
  178. package/packages/sdk/dist/workflows/runner.js.map +1 -1
  179. package/packages/sdk/dist/workflows/types.d.ts +47 -1
  180. package/packages/sdk/dist/workflows/types.d.ts.map +1 -1
  181. package/packages/sdk/dist/workflows/types.js.map +1 -1
  182. package/packages/sdk/dist/workflows/verification.d.ts +9 -0
  183. package/packages/sdk/dist/workflows/verification.d.ts.map +1 -1
  184. package/packages/sdk/dist/workflows/verification.js +78 -2
  185. package/packages/sdk/dist/workflows/verification.js.map +1 -1
  186. package/packages/sdk/package.json +7 -3
  187. package/packages/telemetry/dist/config.d.ts.map +1 -1
  188. package/packages/telemetry/dist/config.js +2 -4
  189. package/packages/telemetry/dist/config.js.map +1 -1
  190. package/packages/telemetry/dist/events.d.ts +1 -2
  191. package/packages/telemetry/dist/events.d.ts.map +1 -1
  192. package/packages/telemetry/dist/index.d.ts +1 -1
  193. package/packages/telemetry/dist/index.d.ts.map +1 -1
  194. package/packages/telemetry/dist/index.js +1 -1
  195. package/packages/telemetry/dist/index.js.map +1 -1
  196. package/packages/telemetry/package.json +1 -1
  197. package/packages/trajectory/package.json +2 -2
  198. package/packages/user-directory/package.json +2 -2
  199. package/packages/utils/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -20146,6 +20146,8 @@ __export(index_exports, {
20146
20146
  BUILT_IN_TEMPLATE_NAMES: () => BUILT_IN_TEMPLATE_NAMES,
20147
20147
  BarrierManager: () => BarrierManager,
20148
20148
  BrokerTransport: () => BrokerTransport,
20149
+ BudgetExceededError: () => BudgetExceededError,
20150
+ BudgetTracker: () => BudgetTracker,
20149
20151
  CLAUDE_MODEL_OPTIONS: () => CLAUDE_MODEL_OPTIONS,
20150
20152
  CLIRegistry: () => CLIRegistry,
20151
20153
  CLIVersions: () => CLIVersions,
@@ -20163,6 +20165,7 @@ __export(index_exports, {
20163
20165
  CustomStepResolutionError: () => CustomStepResolutionError,
20164
20166
  CustomStepsParseError: () => CustomStepsParseError,
20165
20167
  DEFAULT_INBOX_DIR: () => DEFAULT_INBOX_DIR,
20168
+ DEFAULT_PROXY_ENV_REGISTRY: () => DEFAULT_PROXY_ENV_REGISTRY,
20166
20169
  DefaultModels: () => DefaultModels,
20167
20170
  ERROR_SEARCH_HINT: () => ERROR_SEARCH_HINT,
20168
20171
  GEMINI_MODEL_OPTIONS: () => GEMINI_MODEL_OPTIONS,
@@ -20177,6 +20180,10 @@ __export(index_exports, {
20177
20180
  ModelOptions: () => ModelOptions,
20178
20181
  Models: () => Models,
20179
20182
  PROTOCOL_VERSION: () => PROTOCOL_VERSION,
20183
+ RELAY_PROXY_TOKEN_ENV: () => RELAY_PROXY_TOKEN_ENV,
20184
+ RELAY_PROXY_TOKEN_ENV_ALIAS: () => RELAY_PROXY_TOKEN_ENV_ALIAS,
20185
+ RELAY_PROXY_URL_ENV: () => RELAY_PROXY_URL_ENV,
20186
+ RELAY_PROXY_URL_ENV_ALIAS: () => RELAY_PROXY_URL_ENV_ALIAS,
20180
20187
  ReasoningEfforts: () => ReasoningEfforts,
20181
20188
  RelayAdapter: () => RelayAdapter,
20182
20189
  RelayCast: () => RelayCast,
@@ -20201,6 +20208,8 @@ __export(index_exports, {
20201
20208
  buildBlockReason: () => buildBlockReason,
20202
20209
  buildCommand: () => buildCommand,
20203
20210
  buildModelSwitchCommand: () => buildModelSwitchCommand,
20211
+ buildNormalizedProxyEnv: () => buildNormalizedProxyEnv,
20212
+ checkCustom: () => checkCustom,
20204
20213
  checkExitCode: () => checkExitCode,
20205
20214
  checkFileExists: () => checkFileExists,
20206
20215
  checkForUpdates: () => checkForUpdates,
@@ -20224,6 +20233,7 @@ __export(index_exports, {
20224
20233
  createMemoryService: () => createMemoryService,
20225
20234
  createProcessBackendExecutor: () => createProcessBackendExecutor,
20226
20235
  createProcessSpawner: () => createProcessSpawner,
20236
+ createProxyEnvResolver: () => createProxyEnvResolver,
20227
20237
  createRequestEnvelope: () => createRequestEnvelope,
20228
20238
  createRequestHandler: () => createRequestHandler,
20229
20239
  createTraceableError: () => createTraceableError,
@@ -20233,6 +20243,7 @@ __export(index_exports, {
20233
20243
  detectCompletion: () => detectCompletion,
20234
20244
  estimateContextTokens: () => estimateContextTokens,
20235
20245
  estimateTokens: () => estimateTokens,
20246
+ execCustomVerification: () => execCustomVerification,
20236
20247
  executeApiStep: () => executeApiStep,
20237
20248
  findGitRoot: () => findGitRoot,
20238
20249
  findRelayPtyBinary: () => findRelayPtyBinary,
@@ -20266,6 +20277,7 @@ __export(index_exports, {
20266
20277
  getPatternMetrics: () => getPatternMetrics,
20267
20278
  getRepoFullName: () => getRepoFullName,
20268
20279
  getRepoFullNameFromPath: () => getRepoFullNameFromPath,
20280
+ getStrippedApiKeyVars: () => getStrippedApiKeyVars,
20269
20281
  getSupportedPlatforms: () => getSupportedPlatforms,
20270
20282
  getSupportedReasoningEfforts: () => getSupportedReasoningEfforts,
20271
20283
  getTrajectoryHooks: () => getTrajectoryHooks,
@@ -20285,6 +20297,7 @@ __export(index_exports, {
20285
20297
  isModelSwitchSupported: () => isModelSwitchSupported,
20286
20298
  isPlaceholderTargetFast: () => isPlaceholderTargetFast,
20287
20299
  isPlatformSupported: () => isPlatformSupported,
20300
+ isProxyEnabled: () => isProxyEnabled,
20288
20301
  isRestrictedAgent: () => isRestrictedAgent,
20289
20302
  isSpawnOrReleaseCommandFast: () => isSpawnOrReleaseCommandFast,
20290
20303
  isTrajectoryTrackingAvailable: () => isTrajectoryTrackingAvailable,
@@ -20308,6 +20321,9 @@ __export(index_exports, {
20308
20321
  resolveCommand: () => resolveCommand,
20309
20322
  resolveCustomStep: () => resolveCustomStep,
20310
20323
  resolveDotPath: () => resolveDotPath,
20324
+ resolveProxyEnv: () => resolveProxyEnv,
20325
+ resolveProxyTokenFromEnv: () => resolveProxyTokenFromEnv,
20326
+ resolveProxyUrlFromEnv: () => resolveProxyUrlFromEnv,
20311
20327
  resolveSpawnPolicy: () => resolveSpawnPolicy,
20312
20328
  resolveStepOutputRef: () => resolveStepOutputRef,
20313
20329
  resolveTemplate: () => resolveTemplate,
@@ -45649,7 +45665,7 @@ function isAgentStep(step) {
45649
45665
  }
45650
45666
 
45651
45667
  // packages/sdk/dist/workflows/runner.js
45652
- var import_node_child_process7 = require("node:child_process");
45668
+ var import_node_child_process8 = require("node:child_process");
45653
45669
  var import_node_crypto7 = require("node:crypto");
45654
45670
  var import_node_fs20 = require("node:fs");
45655
45671
  var import_promises8 = require("node:fs/promises");
@@ -45981,6 +45997,97 @@ function resolveCliSync(cli) {
45981
45997
  return void 0;
45982
45998
  }
45983
45999
 
46000
+ // packages/sdk/dist/workflows/proxy-env.js
46001
+ var RELAY_PROXY_URL_ENV = "RELAY_LLM_PROXY";
46002
+ var RELAY_PROXY_URL_ENV_ALIAS = "RELAY_LLM_PROXY_URL";
46003
+ var RELAY_PROXY_TOKEN_ENV = "CREDENTIAL_PROXY_TOKEN";
46004
+ var RELAY_PROXY_TOKEN_ENV_ALIAS = "RELAY_LLM_PROXY_TOKEN";
46005
+ var OPENAI_COMPATIBLE_BINDINGS = [
46006
+ { baseUrlVar: "OPENAI_BASE_URL", apiKeyVar: "OPENAI_API_KEY" }
46007
+ ];
46008
+ var ANTHROPIC_BINDINGS = [
46009
+ { baseUrlVar: "ANTHROPIC_BASE_URL", apiKeyVar: "ANTHROPIC_API_KEY" }
46010
+ ];
46011
+ var AIDER_BINDINGS = [
46012
+ { baseUrlVar: "OPENAI_API_BASE", apiKeyVar: "OPENAI_API_KEY" }
46013
+ ];
46014
+ var GEMINI_BINDINGS = [
46015
+ { baseUrlVar: "GOOGLE_API_BASE", apiKeyVar: "GOOGLE_API_KEY" }
46016
+ ];
46017
+ var GENERIC_FALLBACK_BINDINGS = [
46018
+ ...OPENAI_COMPATIBLE_BINDINGS,
46019
+ ...ANTHROPIC_BINDINGS
46020
+ ];
46021
+ var STRIPPED_API_KEY_VARS = [
46022
+ "OPENAI_API_KEY",
46023
+ "ANTHROPIC_API_KEY",
46024
+ "OPENROUTER_API_KEY",
46025
+ "GOOGLE_API_KEY",
46026
+ "OPENAI_BASE_URL",
46027
+ "ANTHROPIC_BASE_URL",
46028
+ "OPENAI_API_BASE",
46029
+ "GOOGLE_API_BASE"
46030
+ ];
46031
+ var CLI_ALIASES = {
46032
+ agent: "cursor",
46033
+ "cursor-agent": "cursor"
46034
+ };
46035
+ var DEFAULT_PROXY_ENV_REGISTRY = {
46036
+ claude: ANTHROPIC_BINDINGS,
46037
+ codex: OPENAI_COMPATIBLE_BINDINGS,
46038
+ opencode: OPENAI_COMPATIBLE_BINDINGS,
46039
+ aider: AIDER_BINDINGS,
46040
+ gemini: GEMINI_BINDINGS,
46041
+ goose: OPENAI_COMPATIBLE_BINDINGS,
46042
+ droid: OPENAI_COMPATIBLE_BINDINGS,
46043
+ cursor: OPENAI_COMPATIBLE_BINDINGS
46044
+ };
46045
+ function normalizeCli(cli) {
46046
+ const baseCli = cli.includes(":") ? cli.split(":")[0] : cli;
46047
+ return CLI_ALIASES[baseCli] ?? baseCli;
46048
+ }
46049
+ function buildProxyEnv(bindings, proxyUrl, proxyToken) {
46050
+ return bindings.reduce((env, binding) => {
46051
+ env[binding.baseUrlVar] = proxyUrl;
46052
+ env[binding.apiKeyVar] = proxyToken;
46053
+ return env;
46054
+ }, {});
46055
+ }
46056
+ function createProxyEnvResolver(registry2 = DEFAULT_PROXY_ENV_REGISTRY) {
46057
+ return (cli, proxyUrl, proxyToken) => {
46058
+ const normalizedCli = normalizeCli(cli);
46059
+ const bindings = registry2[normalizedCli];
46060
+ if (bindings) {
46061
+ return buildProxyEnv(bindings, proxyUrl, proxyToken);
46062
+ }
46063
+ const knownCli = getCliDefinition(normalizedCli);
46064
+ const warningPrefix = knownCli ? "No proxy env registry entry" : "Unknown CLI";
46065
+ console.warn(`[proxy-env] ${warningPrefix} for "${normalizedCli}". Falling back to generic OpenAI/Anthropic proxy env overrides.`);
46066
+ return buildProxyEnv(GENERIC_FALLBACK_BINDINGS, proxyUrl, proxyToken);
46067
+ };
46068
+ }
46069
+ var resolveProxyEnv = createProxyEnvResolver();
46070
+ function resolveProxyUrlFromEnv(env = process.env) {
46071
+ return env[RELAY_PROXY_URL_ENV] ?? env[RELAY_PROXY_URL_ENV_ALIAS];
46072
+ }
46073
+ function resolveProxyTokenFromEnv(env = process.env) {
46074
+ return env[RELAY_PROXY_TOKEN_ENV] ?? env[RELAY_PROXY_TOKEN_ENV_ALIAS];
46075
+ }
46076
+ function buildNormalizedProxyEnv(proxyUrl, proxyToken) {
46077
+ return {
46078
+ [RELAY_PROXY_URL_ENV]: proxyUrl,
46079
+ [RELAY_PROXY_URL_ENV_ALIAS]: proxyUrl,
46080
+ [RELAY_PROXY_TOKEN_ENV]: proxyToken,
46081
+ [RELAY_PROXY_TOKEN_ENV_ALIAS]: proxyToken
46082
+ };
46083
+ }
46084
+ function getStrippedApiKeyVars() {
46085
+ return [...STRIPPED_API_KEY_VARS];
46086
+ }
46087
+ function isProxyEnabled(agentDef, swarmConfig) {
46088
+ return Boolean(agentDef?.credentials?.proxy && swarmConfig?.credentialProxy);
46089
+ }
46090
+
45984
46091
  // packages/sdk/dist/workflows/custom-steps.js
45985
46092
  var import_node_fs5 = require("node:fs");
45986
46093
  var import_node_path8 = __toESM(require("node:path"), 1);
@@ -52037,6 +52144,173 @@ async function executeApiStep(model, task, options = {}) {
52037
52144
  return response.content;
52038
52145
  }
52039
52146
 
52147
+ // packages/sdk/dist/workflows/budget-tracker.js
52148
+ function emptyUsage() {
52149
+ return { input: 0, output: 0, cacheRead: 0, total: 0 };
52150
+ }
52151
+ function toUsage(value) {
52152
+ if (typeof value === "number") {
52153
+ const input2 = Number.isFinite(value) ? Math.max(0, Math.round(value)) : 0;
52154
+ return { input: input2, output: 0, cacheRead: 0, total: input2 };
52155
+ }
52156
+ const input = Number.isFinite(value.input) ? Math.max(0, Math.round(value.input ?? 0)) : 0;
52157
+ const output = Number.isFinite(value.output) ? Math.max(0, Math.round(value.output ?? 0)) : 0;
52158
+ const cacheRead = Number.isFinite(value.cacheRead) ? Math.max(0, Math.round(value.cacheRead ?? 0)) : 0;
52159
+ return {
52160
+ input,
52161
+ output,
52162
+ cacheRead,
52163
+ total: input + output
52164
+ };
52165
+ }
52166
+ function addUsage(left, right) {
52167
+ const input = left.input + right.input;
52168
+ const output = left.output + right.output;
52169
+ const cacheRead = left.cacheRead + right.cacheRead;
52170
+ return {
52171
+ input,
52172
+ output,
52173
+ cacheRead,
52174
+ total: input + output
52175
+ };
52176
+ }
52177
+ var BudgetExceededError = class extends Error {
52178
+ stepName;
52179
+ budgetType;
52180
+ limit;
52181
+ actual;
52182
+ used;
52183
+ constructor(stepName, budgetType, limit, actual) {
52184
+ const qualifier = budgetType === "workflow" ? "workflow budget exhausted" : "agent budget exceeded";
52185
+ super(`Step "${stepName}" cannot continue: ${qualifier} (${actual}/${limit})`);
52186
+ this.name = "BudgetExceededError";
52187
+ this.stepName = stepName;
52188
+ this.budgetType = budgetType;
52189
+ this.limit = limit;
52190
+ this.actual = actual;
52191
+ this.used = actual;
52192
+ }
52193
+ };
52194
+ var BudgetTracker = class {
52195
+ defaultAgentBudget;
52196
+ workflowBudget;
52197
+ stepLimits = /* @__PURE__ */ new Map();
52198
+ stepUsage = /* @__PURE__ */ new Map();
52199
+ totalUsage = emptyUsage();
52200
+ workflowBudgetExhausted = false;
52201
+ constructor(options) {
52202
+ this.defaultAgentBudget = options.perAgent;
52203
+ this.workflowBudget = options.workflowBudget ?? options.perWorkflow;
52204
+ for (const step of options.steps ?? []) {
52205
+ this.stepLimits.set(step.stepName, step.maxTokens);
52206
+ }
52207
+ }
52208
+ recordUsage(stepName, usage) {
52209
+ const normalized = toUsage(usage);
52210
+ const current = this.stepUsage.get(stepName) ?? emptyUsage();
52211
+ const next = addUsage(current, normalized);
52212
+ this.stepUsage.set(stepName, next);
52213
+ this.totalUsage = addUsage(this.totalUsage, normalized);
52214
+ if (this.workflowBudget !== void 0 && this.totalUsage.total >= this.workflowBudget) {
52215
+ this.workflowBudgetExhausted = true;
52216
+ }
52217
+ }
52218
+ getStepUsage(stepName) {
52219
+ return this.stepUsage.get(stepName) ?? emptyUsage();
52220
+ }
52221
+ getTotalUsage() {
52222
+ return this.totalUsage;
52223
+ }
52224
+ getRemainingBudget() {
52225
+ return {
52226
+ agent: this.defaultAgentBudget !== void 0 ? Math.max(0, this.defaultAgentBudget - this.totalUsage.total) : void 0,
52227
+ workflow: this.workflowBudget !== void 0 ? Math.max(0, this.workflowBudget - this.totalUsage.total) : void 0
52228
+ };
52229
+ }
52230
+ checkCanSpawn(stepName) {
52231
+ if (this.workflowBudget !== void 0 && this.totalUsage.total >= this.workflowBudget) {
52232
+ return {
52233
+ allowed: false,
52234
+ reason: `Cannot spawn ${stepName}: workflow budget exceeded (${this.totalUsage.total}/${this.workflowBudget})`
52235
+ };
52236
+ }
52237
+ if (this.workflowBudget !== void 0) {
52238
+ const remainingWorkflowBudget = this.workflowBudget - this.totalUsage.total;
52239
+ const stepLimit = this.getStepLimit(stepName);
52240
+ const minimumHeadroom = stepLimit !== void 0 ? Math.min(stepLimit, this.workflowBudget) : this.defaultAgentBudget !== void 0 ? Math.ceil(this.defaultAgentBudget * 0.1) : Math.ceil(this.workflowBudget * 0.1);
52241
+ if (remainingWorkflowBudget <= minimumHeadroom) {
52242
+ return {
52243
+ allowed: false,
52244
+ reason: stepLimit !== void 0 ? `Cannot spawn ${stepName}: remaining workflow budget ${remainingWorkflowBudget} is below step budget ${stepLimit}` : this.defaultAgentBudget !== void 0 ? `Cannot spawn ${stepName}: remaining workflow budget ${remainingWorkflowBudget} is below 10% of per-agent budget ${this.defaultAgentBudget}` : `Cannot spawn ${stepName}: remaining workflow budget ${remainingWorkflowBudget} is below 10% headroom threshold for workflow budget ${this.workflowBudget}`
52245
+ };
52246
+ }
52247
+ }
52248
+ return { allowed: true };
52249
+ }
52250
+ isOverBudget(stepName) {
52251
+ const stepUsage = this.getStepUsage(stepName);
52252
+ const stepLimit = this.getStepLimit(stepName);
52253
+ if (stepLimit !== void 0 && stepUsage.total > stepLimit) {
52254
+ return {
52255
+ over: true,
52256
+ reason: `Step "${stepName}" exceeded per-agent budget (${stepUsage.total}/${stepLimit})`
52257
+ };
52258
+ }
52259
+ if (this.workflowBudget !== void 0 && this.totalUsage.total > this.workflowBudget) {
52260
+ return {
52261
+ over: true,
52262
+ reason: `Workflow exceeded total budget (${this.totalUsage.total}/${this.workflowBudget})`
52263
+ };
52264
+ }
52265
+ return { over: false };
52266
+ }
52267
+ getBudgetStatus(stepName) {
52268
+ const stepUsage = this.getStepUsage(stepName);
52269
+ const stepLimit = this.getStepLimit(stepName);
52270
+ return {
52271
+ agentLimitExceeded: stepLimit !== void 0 && stepUsage.total > stepLimit,
52272
+ workflowBudgetExceeded: this.workflowBudget !== void 0 && this.totalUsage.total > this.workflowBudget,
52273
+ workflowBudgetExhausted: this.workflowBudget !== void 0 && (this.workflowBudgetExhausted || this.totalUsage.total >= this.workflowBudget)
52274
+ };
52275
+ }
52276
+ getStepBudgetStatus(stepName) {
52277
+ const usage = this.stepUsage.get(stepName);
52278
+ const hasExplicitLimit = this.stepLimits.has(stepName);
52279
+ const limit = this.getStepLimit(stepName);
52280
+ if (!usage && !hasExplicitLimit && limit === void 0) {
52281
+ return void 0;
52282
+ }
52283
+ return {
52284
+ used: usage?.total,
52285
+ limit,
52286
+ over: limit !== void 0 && (usage?.total ?? 0) > limit
52287
+ };
52288
+ }
52289
+ getRunSummaryBudgetData() {
52290
+ const steps = /* @__PURE__ */ new Map();
52291
+ const stepNames = /* @__PURE__ */ new Set([...this.stepLimits.keys(), ...this.stepUsage.keys()]);
52292
+ for (const stepName of stepNames) {
52293
+ const status = this.getStepBudgetStatus(stepName);
52294
+ if (status) {
52295
+ steps.set(stepName, status);
52296
+ }
52297
+ }
52298
+ const workflow2 = this.workflowBudget !== void 0 || this.totalUsage.total > 0 ? {
52299
+ used: this.totalUsage.total,
52300
+ limit: this.workflowBudget,
52301
+ exhausted: this.workflowBudget !== void 0 && (this.workflowBudgetExhausted || this.totalUsage.total >= this.workflowBudget)
52302
+ } : void 0;
52303
+ if (steps.size === 0 && !workflow2) {
52304
+ return void 0;
52305
+ }
52306
+ return { steps, workflow: workflow2 };
52307
+ }
52308
+ getStepLimit(stepName) {
52309
+ const limit = this.stepLimits.get(stepName);
52310
+ return limit ?? this.defaultAgentBudget;
52311
+ }
52312
+ };
52313
+
52040
52314
  // packages/sdk/dist/workflows/channel-messenger.js
52041
52315
  async function sendToChannel(relay, channel, message) {
52042
52316
  await relay.send(channel, message);
@@ -52286,9 +52560,10 @@ var InMemoryWorkflowDb = class {
52286
52560
  };
52287
52561
 
52288
52562
  // packages/sdk/dist/workflows/process-spawner.js
52289
- var import_node_child_process6 = require("node:child_process");
52563
+ var import_node_child_process7 = require("node:child_process");
52290
52564
 
52291
52565
  // packages/sdk/dist/workflows/verification.js
52566
+ var import_node_child_process6 = require("node:child_process");
52292
52567
  var import_node_fs19 = require("node:fs");
52293
52568
  var import_node_path26 = __toESM(require("node:path"), 1);
52294
52569
  var WorkflowCompletionError = class extends Error {
@@ -52343,8 +52618,17 @@ function runVerification(check2, output, stepName, injectedTaskText, options = {
52343
52618
  return fail(`Verification failed for "${stepName}": file "${check2.value}" does not exist`);
52344
52619
  }
52345
52620
  break;
52346
- case "custom":
52347
- return { passed: false };
52621
+ case "custom": {
52622
+ if (check2.value) {
52623
+ const result = execCustomVerification(check2.value, cwd, check2.timeoutMs);
52624
+ if (!result.passed) {
52625
+ return fail('Verification failed for "' + stepName + '": custom check "' + check2.value + '" failed\n' + result.output);
52626
+ }
52627
+ } else {
52628
+ return { passed: false };
52629
+ }
52630
+ break;
52631
+ }
52348
52632
  default:
52349
52633
  break;
52350
52634
  }
@@ -52397,6 +52681,55 @@ function checkOutputContains(output, token, injectedTaskText) {
52397
52681
  }
52398
52682
  return stripInjectedTaskEcho(output, injectedTaskText).includes(token);
52399
52683
  }
52684
+ var DEFAULT_CUSTOM_VERIFY_TIMEOUT_MS = parseInt(process.env.CUSTOM_VERIFY_TIMEOUT_MS ?? "30000", 10);
52685
+ var REGEX_PREFIX = "regex:";
52686
+ function execCustomVerification(command, cwd, timeoutMs = DEFAULT_CUSTOM_VERIFY_TIMEOUT_MS) {
52687
+ try {
52688
+ const stdout = (0, import_node_child_process6.execSync)(command, {
52689
+ cwd,
52690
+ timeout: timeoutMs,
52691
+ killSignal: "SIGKILL",
52692
+ stdio: ["ignore", "pipe", "pipe"],
52693
+ encoding: "utf-8"
52694
+ });
52695
+ return { passed: true, output: stdout.trim() };
52696
+ } catch (error48) {
52697
+ const execError = error48;
52698
+ const stdout = typeof execError.stdout === "string" ? execError.stdout : execError.stdout?.toString("utf-8") ?? "";
52699
+ const stderr = typeof execError.stderr === "string" ? execError.stderr : execError.stderr?.toString("utf-8") ?? "";
52700
+ const combinedOutput = [stdout, stderr].filter((chunk) => chunk.length > 0).join("\n").trim();
52701
+ const truncated = combinedOutput.length > 2e3 ? combinedOutput.slice(-2e3) : combinedOutput;
52702
+ return {
52703
+ passed: false,
52704
+ output: truncated || execError.message
52705
+ };
52706
+ }
52707
+ }
52708
+ function checkCustom(value, output, cwd = process.cwd()) {
52709
+ if (value.startsWith(REGEX_PREFIX)) {
52710
+ const pattern = value.slice(REGEX_PREFIX.length);
52711
+ try {
52712
+ const re2 = new RegExp(pattern);
52713
+ const matched = re2.test(output);
52714
+ return matched ? { passed: true } : { passed: false, error: `output did not match pattern /${pattern}/` };
52715
+ } catch (err) {
52716
+ return { passed: false, error: `invalid regex: ${err.message}` };
52717
+ }
52718
+ }
52719
+ try {
52720
+ const result = (0, import_node_child_process6.execSync)(value, {
52721
+ cwd,
52722
+ env: { ...process.env, STEP_OUTPUT: output },
52723
+ timeout: DEFAULT_CUSTOM_VERIFY_TIMEOUT_MS,
52724
+ stdio: ["pipe", "pipe", "pipe"],
52725
+ maxBuffer: 1024 * 1024
52726
+ });
52727
+ return { passed: true, stdout: result.toString("utf-8").trim() };
52728
+ } catch (err) {
52729
+ const message = err?.stderr?.toString("utf-8")?.trim() || err.message;
52730
+ return { passed: false, error: message };
52731
+ }
52732
+ }
52400
52733
  function checkFileExists(filePath, cwd = process.cwd()) {
52401
52734
  const normalizedCwd = import_node_path26.default.resolve(cwd);
52402
52735
  const resolved = import_node_path26.default.isAbsolute(filePath) ? import_node_path26.default.resolve(filePath) : import_node_path26.default.resolve(normalizedCwd, filePath);
@@ -52427,7 +52760,7 @@ function buildCommand(cli, extraArgs = [], task) {
52427
52760
  }
52428
52761
  function spawnProcess(command, options) {
52429
52762
  const [bin, ...args] = command;
52430
- return (0, import_node_child_process6.spawn)(bin, args, options);
52763
+ return (0, import_node_child_process7.spawn)(bin, args, options);
52431
52764
  }
52432
52765
  function collectOutput(process8) {
52433
52766
  return new Promise((resolve4, reject) => {
@@ -52612,6 +52945,15 @@ function formatTokens(report) {
52612
52945
  const total = report.tokens.input + report.tokens.output + report.tokens.cacheRead;
52613
52946
  return total.toLocaleString("en-US");
52614
52947
  }
52948
+ function formatBudgetValue(value) {
52949
+ return typeof value === "number" ? value.toLocaleString("en-US") : "--";
52950
+ }
52951
+ function formatBudget(status) {
52952
+ if (!status)
52953
+ return "--";
52954
+ const rendered = `${formatBudgetValue(status.used)}/${formatBudgetValue(status.limit)}`;
52955
+ return status.over ? `${rendered} [OVER]` : rendered;
52956
+ }
52615
52957
  function formatDuration(durationMs) {
52616
52958
  if (typeof durationMs !== "number" || !Number.isFinite(durationMs))
52617
52959
  return "--";
@@ -52640,10 +52982,11 @@ function formatErrors(outcome, report) {
52640
52982
  return `${count} (fixed)`;
52641
52983
  return String(count);
52642
52984
  }
52643
- function formatRunSummaryTable(outcomes, reports) {
52985
+ function formatRunSummaryTable(outcomes, reports, budgetData) {
52644
52986
  const hasCost = Array.from(reports.values()).some((r) => typeof r.cost === "number" && r.cost > 0);
52645
- const headers = hasCost ? ["Step", "Status", "Model", "Cost", "Tokens", "Duration", "Errors"] : ["Step", "Status", "Model", "Tokens", "Duration", "Errors"];
52646
- const widths = hasCost ? [20, 6, 16, 8, 10, 10, 10] : [20, 6, 16, 10, 10, 10];
52987
+ const hasBudget = Boolean(budgetData);
52988
+ const headers = hasCost ? hasBudget ? ["Step", "Status", "Model", "Cost", "Tokens", "Budget", "Duration", "Errors"] : ["Step", "Status", "Model", "Cost", "Tokens", "Duration", "Errors"] : hasBudget ? ["Step", "Status", "Model", "Tokens", "Budget", "Duration", "Errors"] : ["Step", "Status", "Model", "Tokens", "Duration", "Errors"];
52989
+ const widths = hasCost ? hasBudget ? [20, 6, 16, 8, 10, 18, 10, 10] : [20, 6, 16, 8, 10, 10, 10] : hasBudget ? [20, 6, 16, 10, 18, 10, 10] : [20, 6, 16, 10, 10, 10];
52647
52990
  const lines = [];
52648
52991
  lines.push(headers.map((h, i) => {
52649
52992
  const align = i <= 2 ? "left" : "right";
@@ -52656,6 +52999,7 @@ function formatRunSummaryTable(outcomes, reports) {
52656
52999
  const report = reports.get(outcome.name);
52657
53000
  const reportDuration = report?.durationMs ?? outcome.durationMs;
52658
53001
  const reportTokens = report?.tokens ? report.tokens.input + report.tokens.output + report.tokens.cacheRead : 0;
53002
+ const budgetStatus = budgetData?.steps.get(outcome.name);
52659
53003
  if (typeof report?.cost === "number")
52660
53004
  totalCost += report.cost;
52661
53005
  totalTokens += reportTokens;
@@ -52670,8 +53014,12 @@ function formatRunSummaryTable(outcomes, reports) {
52670
53014
  cols.push(pad(formatCurrency(report?.cost), widths[3], "right"));
52671
53015
  const tokenIdx2 = hasCost ? 4 : 3;
52672
53016
  cols.push(pad(formatTokens(report), widths[tokenIdx2], "right"));
52673
- cols.push(pad(formatDuration(reportDuration), widths[tokenIdx2 + 1], "right"));
52674
- cols.push(pad(formatErrors(outcome, report), widths[tokenIdx2 + 2], "right"));
53017
+ if (hasBudget)
53018
+ cols.push(pad(formatBudget(budgetStatus), widths[tokenIdx2 + 1], "right"));
53019
+ const durationIdx2 = hasBudget ? tokenIdx2 + 2 : tokenIdx2 + 1;
53020
+ const errorsIdx2 = hasBudget ? tokenIdx2 + 3 : tokenIdx2 + 2;
53021
+ cols.push(pad(formatDuration(reportDuration), widths[durationIdx2], "right"));
53022
+ cols.push(pad(formatErrors(outcome, report), widths[errorsIdx2], "right"));
52675
53023
  lines.push(cols.join(" "));
52676
53024
  if (outcome.status === "failed") {
52677
53025
  const firstError = report?.errors[0];
@@ -52687,8 +53035,15 @@ function formatRunSummaryTable(outcomes, reports) {
52687
53035
  totalCols.push(pad(formatCurrency(totalCost), widths[3], "right"));
52688
53036
  const tokenIdx = hasCost ? 4 : 3;
52689
53037
  totalCols.push(pad(totalTokens > 0 ? totalTokens.toLocaleString("en-US") : "--", widths[tokenIdx], "right"));
52690
- totalCols.push(pad(formatDuration(totalDurationMs), widths[tokenIdx + 1], "right"));
52691
- totalCols.push(pad("", widths[tokenIdx + 2], "right"));
53038
+ if (hasBudget) {
53039
+ const workflowBudget = budgetData?.workflow;
53040
+ const budgetTotal = workflowBudget && (workflowBudget.limit !== void 0 || workflowBudget.used > 0) ? `${formatBudgetValue(workflowBudget.used)}/${formatBudgetValue(workflowBudget.limit)}` : "--";
53041
+ totalCols.push(pad(budgetTotal, widths[tokenIdx + 1], "right"));
53042
+ }
53043
+ const durationIdx = hasBudget ? tokenIdx + 2 : tokenIdx + 1;
53044
+ const errorsIdx = hasBudget ? tokenIdx + 3 : tokenIdx + 2;
53045
+ totalCols.push(pad(formatDuration(totalDurationMs), widths[durationIdx], "right"));
53046
+ totalCols.push(pad("", widths[errorsIdx], "right"));
52692
53047
  lines.push(totalCols.join(" "));
52693
53048
  return lines.map((line) => ` ${line}`).join("\n");
52694
53049
  }
@@ -54655,6 +55010,10 @@ var ENV_ALLOWLIST = /* @__PURE__ */ new Set([
54655
55010
  "RUST_BACKTRACE",
54656
55011
  "RELAY_API_KEY",
54657
55012
  "RELAYCAST_BASE_URL",
55013
+ "RELAY_LLM_PROXY",
55014
+ "RELAY_LLM_PROXY_URL",
55015
+ "CREDENTIAL_PROXY_TOKEN",
55016
+ "RELAY_LLM_PROXY_TOKEN",
54658
55017
  "AGENT_RELAY_DASHBOARD_PORT",
54659
55018
  "AGENT_RELAY_RUN_ID_FILE",
54660
55019
  "EDITOR",
@@ -54743,12 +55102,16 @@ var WorkflowRunner = class _WorkflowRunner {
54743
55102
  activeAgentHandles = /* @__PURE__ */ new Map();
54744
55103
  /** Per-agent workflow tokens for relay/relayfile auth across spawn modes. */
54745
55104
  agentTokens = /* @__PURE__ */ new Map();
55105
+ /** Per-agent credential proxy tokens keyed by logical agent definition name. */
55106
+ proxyTokens = /* @__PURE__ */ new Map();
54746
55107
  /** Per-agent relayfile mounts keyed by logical agent definition name. */
54747
55108
  agentMounts = /* @__PURE__ */ new Map();
54748
55109
  // PTY-based output capture: accumulate terminal output per-agent
54749
55110
  ptyOutputBuffers = /* @__PURE__ */ new Map();
54750
55111
  /** Snapshot of PTY output from the most recent failed attempt, keyed by step name. */
54751
55112
  lastFailedStepOutput = /* @__PURE__ */ new Map();
55113
+ /** Most recent custom verification failure details, keyed by step name. */
55114
+ lastCustomVerificationFailure = /* @__PURE__ */ new Map();
54752
55115
  ptyListeners = /* @__PURE__ */ new Map();
54753
55116
  ptyLogStreams = /* @__PURE__ */ new Map();
54754
55117
  /** Path to workers.json so `agents:kill` can find workflow-spawned agents */
@@ -54779,6 +55142,8 @@ var WorkflowRunner = class _WorkflowRunner {
54779
55142
  activeReviewers = /* @__PURE__ */ new Map();
54780
55143
  /** Structured CLI session reports captured during the current run, keyed by step name. */
54781
55144
  agentReports = /* @__PURE__ */ new Map();
55145
+ /** Optional per-run token budget tracker; only created when budgets are configured. */
55146
+ budgetTracker;
54782
55147
  static PTY_TASK_ARG_SIZE_LIMIT = 2 * 1024 * 1024;
54783
55148
  // 2 MB
54784
55149
  processBackend;
@@ -54839,6 +55204,45 @@ var WorkflowRunner = class _WorkflowRunner {
54839
55204
  }
54840
55205
  return { resolved, errors, warnings };
54841
55206
  }
55207
+ initializeBudgetTracker(config2, workflow2) {
55208
+ const agentMap = new Map(config2.agents.map((agent) => [agent.name, _WorkflowRunner.resolveAgentDef(agent)]));
55209
+ const stepConfigs = workflow2.steps.flatMap((step) => {
55210
+ if (step.type === "deterministic" || step.type === "worktree" || step.type === "integration" || !step.agent) {
55211
+ return [];
55212
+ }
55213
+ const agentDef = agentMap.get(step.agent);
55214
+ return [
55215
+ {
55216
+ stepName: step.name,
55217
+ agentName: step.agent,
55218
+ maxTokens: agentDef?.constraints?.maxTokens
55219
+ }
55220
+ ];
55221
+ });
55222
+ const hasWorkflowBudget = config2.swarm.tokenBudget !== void 0;
55223
+ const hasAgentBudgets = stepConfigs.some((step) => step.maxTokens !== void 0);
55224
+ this.budgetTracker = hasWorkflowBudget || hasAgentBudgets ? new BudgetTracker({
55225
+ workflowBudget: config2.swarm.tokenBudget,
55226
+ steps: stepConfigs
55227
+ }) : void 0;
55228
+ }
55229
+ ensureBudgetAllowsSpawn(stepName, agentName) {
55230
+ if (!this.budgetTracker)
55231
+ return;
55232
+ const budgetCheck = this.budgetTracker.checkCanSpawn(stepName);
55233
+ if (budgetCheck.allowed)
55234
+ return;
55235
+ const workflowBudget = this.budgetTracker.getRunSummaryBudgetData()?.workflow;
55236
+ const used = workflowBudget?.used.toLocaleString("en-US") ?? "0";
55237
+ const limit = workflowBudget?.limit?.toLocaleString("en-US") ?? "--";
55238
+ this.log(`[budget] Skipping step ${stepName} \u2014 workflow budget exhausted (used ${used} of ${limit})`);
55239
+ throw new BudgetExceededError(stepName, "workflow", workflowBudget?.limit ?? 0, workflowBudget?.used ?? 0);
55240
+ }
55241
+ getTotalReportTokens(report) {
55242
+ if (!report.tokens)
55243
+ return void 0;
55244
+ return report.tokens.input + report.tokens.output + report.tokens.cacheRead;
55245
+ }
54842
55246
  validatePermissions(agents, permissionProfiles, source = "<config>") {
54843
55247
  const errors = [];
54844
55248
  const warnings = [];
@@ -55643,21 +56047,161 @@ ${next}` : next;
55643
56047
  }).catch(() => {
55644
56048
  });
55645
56049
  }
55646
- getRelayEnv() {
55647
- if (!this.relayApiKey && !this.relayOptions.env) {
56050
+ async loadCredentialProxyModule() {
56051
+ try {
56052
+ const dynamicImport = new Function("specifier", "return import(specifier)");
56053
+ const module2 = await dynamicImport("@agent-relay/credential-proxy");
56054
+ return typeof module2.mintProxyToken === "function" ? module2 : null;
56055
+ } catch (error48) {
56056
+ if (error48?.code === "ERR_MODULE_NOT_FOUND") {
56057
+ return null;
56058
+ }
56059
+ throw error48;
56060
+ }
56061
+ }
56062
+ resolveCredentialProxyProvider(agentDef, config2) {
56063
+ const configuredProviders = Object.keys(config2.swarm.credentialProxy?.providers ?? {});
56064
+ const explicitProvider = agentDef.credentials?.provider?.trim().toLowerCase();
56065
+ if (explicitProvider === "openai" || explicitProvider === "anthropic" || explicitProvider === "openrouter") {
56066
+ return explicitProvider;
56067
+ }
56068
+ const model = agentDef.constraints?.model?.trim().toLowerCase() ?? "";
56069
+ if (model.includes("openrouter")) {
56070
+ return "openrouter";
56071
+ }
56072
+ if (model.includes("claude") || model.includes("anthropic")) {
56073
+ return "anthropic";
56074
+ }
56075
+ if (model.includes("openai") || model.includes("chatgpt") || model.includes("gpt") || /\bo[134](?:\b|-)/.test(model)) {
56076
+ return "openai";
56077
+ }
56078
+ if (configuredProviders.length === 1) {
56079
+ const [onlyProvider] = configuredProviders;
56080
+ if (onlyProvider === "openai" || onlyProvider === "anthropic" || onlyProvider === "openrouter") {
56081
+ return onlyProvider;
56082
+ }
56083
+ }
56084
+ switch (agentDef.cli) {
56085
+ case "claude":
56086
+ return "anthropic";
56087
+ case "codex":
56088
+ case "aider":
56089
+ case "goose":
56090
+ case "opencode":
56091
+ case "cursor":
56092
+ case "cursor-agent":
56093
+ return "openai";
56094
+ default:
56095
+ throw new Error(`Unable to resolve credential proxy provider for agent "${agentDef.name}". Set credentials.provider or constraints.model.`);
56096
+ }
56097
+ }
56098
+ resolveCredentialProxySecret(config2) {
56099
+ const configuredSecret = config2.swarm.credentialProxy?.jwtSecret;
56100
+ if (configuredSecret?.startsWith("$")) {
56101
+ const envSecret = process.env[configuredSecret.slice(1)];
56102
+ if (envSecret) {
56103
+ return envSecret;
56104
+ }
56105
+ } else if (configuredSecret) {
56106
+ return configuredSecret;
56107
+ }
56108
+ const defaultSecret = process.env.RELAY_PROXY_JWT_SECRET;
56109
+ if (defaultSecret) {
56110
+ return defaultSecret;
56111
+ }
56112
+ throw new Error("Credential proxy JWT secret is missing. Set swarm.credentialProxy.jwtSecret or RELAY_PROXY_JWT_SECRET.");
56113
+ }
56114
+ async mintAgentProxyToken(agentDef, config2) {
56115
+ const proxyConfig = config2.swarm?.credentialProxy;
56116
+ if (!proxyConfig?.proxyUrl || !agentDef.credentials?.proxy) {
56117
+ return void 0;
56118
+ }
56119
+ const provider = this.resolveCredentialProxyProvider(agentDef, config2);
56120
+ const providerConfig = proxyConfig.providers?.[provider];
56121
+ const credentialId = providerConfig?.credentialId;
56122
+ if (!credentialId) {
56123
+ throw new Error(`Credential proxy provider "${provider}" is not configured for agent "${agentDef.name}".`);
56124
+ }
56125
+ const budget = agentDef.constraints?.maxTokens ?? proxyConfig.defaultBudget;
56126
+ const cacheKey = `${agentDef.name}:${provider}:${credentialId}:${budget ?? "default"}`;
56127
+ const cachedToken = this.proxyTokens.get(cacheKey);
56128
+ if (cachedToken) {
56129
+ return cachedToken;
56130
+ }
56131
+ const credentialProxy = await this.loadCredentialProxyModule();
56132
+ if (!credentialProxy) {
56133
+ throw new Error('Credential proxy mode requires the optional peer dependency "@agent-relay/credential-proxy".');
56134
+ }
56135
+ const nowSeconds = Math.floor(Date.now() / 1e3);
56136
+ const token = await credentialProxy.mintProxyToken({
56137
+ sub: this.workspaceId,
56138
+ aud: "relay-llm-proxy",
56139
+ provider,
56140
+ credentialId,
56141
+ budget,
56142
+ exp: nowSeconds + 15 * 60
56143
+ }, this.resolveCredentialProxySecret(config2));
56144
+ this.proxyTokens.set(cacheKey, token);
56145
+ return token;
56146
+ }
56147
+ async resolveAgentProxyMode(agentDef, config2) {
56148
+ if (!agentDef.credentials?.proxy) {
56149
+ return void 0;
56150
+ }
56151
+ const env = this.getMergedRelayEnvSource();
56152
+ const configuredProxyUrl = config2?.swarm?.credentialProxy?.proxyUrl;
56153
+ const proxyUrl = configuredProxyUrl ?? resolveProxyUrlFromEnv(env);
56154
+ if (!proxyUrl) {
56155
+ return void 0;
56156
+ }
56157
+ if (!configuredProxyUrl) {
56158
+ const injectedToken = resolveProxyTokenFromEnv(env);
56159
+ if (!injectedToken) {
56160
+ return void 0;
56161
+ }
56162
+ return {
56163
+ url: proxyUrl,
56164
+ token: injectedToken
56165
+ };
56166
+ }
56167
+ const token = await this.mintAgentProxyToken(agentDef, config2);
56168
+ if (!token) {
55648
56169
  return void 0;
55649
56170
  }
56171
+ return {
56172
+ url: proxyUrl,
56173
+ token
56174
+ };
56175
+ }
56176
+ getMergedRelayEnvSource() {
55650
56177
  return {
55651
56178
  ...process.env,
55652
56179
  ...this.relayOptions.env ?? {},
55653
56180
  ...this.relayApiKey ? { RELAY_API_KEY: this.relayApiKey } : {}
55654
56181
  };
55655
56182
  }
56183
+ getRelayEnv(proxyMode) {
56184
+ const env = this.getMergedRelayEnvSource();
56185
+ const inheritedProxyUrl = resolveProxyUrlFromEnv(env);
56186
+ const inheritedProxyToken = resolveProxyTokenFromEnv(env);
56187
+ if (!this.relayApiKey && !this.relayOptions.env && !proxyMode && !(inheritedProxyUrl && inheritedProxyToken)) {
56188
+ return void 0;
56189
+ }
56190
+ const normalizedProxy = proxyMode?.url && proxyMode.token ? proxyMode : inheritedProxyUrl && inheritedProxyToken ? { url: inheritedProxyUrl, token: inheritedProxyToken } : void 0;
56191
+ if (normalizedProxy) {
56192
+ Object.assign(env, buildNormalizedProxyEnv(normalizedProxy.url, normalizedProxy.token));
56193
+ for (const key of getStrippedApiKeyVars()) {
56194
+ delete env[key];
56195
+ }
56196
+ }
56197
+ return env;
56198
+ }
55656
56199
  async provisionAgents(config2) {
55657
56200
  if (process.env.RELAY_CLOUD_PROVISIONING_DONE === "1") {
55658
56201
  return;
55659
56202
  }
55660
56203
  this.agentTokens.clear();
56204
+ this.proxyTokens.clear();
55661
56205
  await this.stopProvisionedMounts();
55662
56206
  const agentsToProvision = {};
55663
56207
  for (const agent of config2.agents) {
@@ -56499,6 +57043,7 @@ ${err.suggestion}`);
56499
57043
  this.runtimeStepAgents.clear();
56500
57044
  this.stepCompletionEvidence.clear();
56501
57045
  this.agentReports.clear();
57046
+ this.initializeBudgetTracker(config2, workflow2);
56502
57047
  this.log(`Starting workflow "${workflow2.name}" (${workflow2.steps.length} steps)`);
56503
57048
  this.trajectory = new WorkflowTrajectory(config2.trajectories, runId, this.cwd);
56504
57049
  try {
@@ -56786,6 +57331,7 @@ ${err.suggestion}`);
56786
57331
  }
56787
57332
  } finally {
56788
57333
  this.lastFailedStepOutput.clear();
57334
+ this.lastCustomVerificationFailure.clear();
56789
57335
  for (const stream of this.ptyLogStreams.values())
56790
57336
  stream.end();
56791
57337
  this.ptyLogStreams.clear();
@@ -56875,7 +57421,7 @@ ${err.suggestion}`);
56875
57421
  this.postToChannel(`**[preflight]** ${description}`);
56876
57422
  try {
56877
57423
  const output = await new Promise((resolve4, reject) => {
56878
- const child = (0, import_node_child_process7.spawn)("sh", ["-c", check2.command], {
57424
+ const child = (0, import_node_child_process8.spawn)("sh", ["-c", check2.command], {
56879
57425
  stdio: "pipe",
56880
57426
  cwd: this.cwd,
56881
57427
  env: filteredEnv()
@@ -57039,7 +57585,7 @@ ${executorResult.output}`);
57039
57585
  let commandStdout = "";
57040
57586
  let commandStderr = "";
57041
57587
  const output = await new Promise((resolve4, reject) => {
57042
- const child = (0, import_node_child_process7.spawn)("sh", ["-c", resolvedCommand], {
57588
+ const child = (0, import_node_child_process8.spawn)("sh", ["-c", resolvedCommand], {
57043
57589
  stdio: "pipe",
57044
57590
  cwd: stepCwd,
57045
57591
  env: filteredEnv()
@@ -57179,7 +57725,7 @@ ${stderr}`);
57179
57725
  const absoluteWorktreePath = import_node_path28.default.resolve(stepCwd, worktreePath);
57180
57726
  let branchExists = false;
57181
57727
  await new Promise((resolve4) => {
57182
- const checkChild = (0, import_node_child_process7.spawn)("git", ["rev-parse", "--verify", "--quiet", branch], {
57728
+ const checkChild = (0, import_node_child_process8.spawn)("git", ["rev-parse", "--verify", "--quiet", branch], {
57183
57729
  stdio: "pipe",
57184
57730
  cwd: stepCwd,
57185
57731
  env: filteredEnv()
@@ -57201,7 +57747,7 @@ ${stderr}`);
57201
57747
  let commandStdout = "";
57202
57748
  let commandStderr = "";
57203
57749
  const output = await new Promise((resolve4, reject) => {
57204
- const child = (0, import_node_child_process7.spawn)("git", worktreeArgs, {
57750
+ const child = (0, import_node_child_process8.spawn)("git", worktreeArgs, {
57205
57751
  stdio: "pipe",
57206
57752
  cwd: stepCwd,
57207
57753
  env: filteredEnv()
@@ -57360,6 +57906,7 @@ ${stderr}`);
57360
57906
  }
57361
57907
  const specialistDef = _WorkflowRunner.resolveAgentDef(rawAgentDef);
57362
57908
  if (specialistDef.cli === "api") {
57909
+ this.ensureBudgetAllowsSpawn(step.name, agentName);
57363
57910
  const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
57364
57911
  const resolvedTask = this.interpolateStepTask(step.task ?? "", stepOutputContext);
57365
57912
  state.row.status = "running";
@@ -57427,10 +57974,17 @@ ${stderr}`);
57427
57974
  let lastAttemptStartedAt;
57428
57975
  let lastEffectiveAgentDef;
57429
57976
  let lastEffectiveCwd;
57977
+ let lastAttemptReportCaptured = false;
57978
+ let lastDiagnosticResult = null;
57430
57979
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
57431
57980
  this.checkAborted();
57432
57981
  lastExitCode = void 0;
57433
57982
  lastExitSignal = void 0;
57983
+ lastAttemptStartedAt = void 0;
57984
+ lastEffectiveAgentDef = void 0;
57985
+ lastEffectiveCwd = void 0;
57986
+ lastAttemptReportCaptured = false;
57987
+ let stepOutputForDiagnostic = "";
57434
57988
  if (attempt > 0) {
57435
57989
  this.emit({ type: "step:retrying", runId, stepName: step.name, attempt });
57436
57990
  this.postToChannel(`**[${step.name}]** Retrying (attempt ${attempt + 1}/${maxRetries + 1})`);
@@ -57448,6 +58002,7 @@ ${stderr}`);
57448
58002
  await this.delay(retryDelay);
57449
58003
  }
57450
58004
  try {
58005
+ this.ensureBudgetAllowsSpawn(step.name, agentName);
57451
58006
  lastAttemptStartedAt = Date.now();
57452
58007
  state.row.status = "running";
57453
58008
  state.row.error = void 0;
@@ -57482,13 +58037,31 @@ ${stderr}`);
57482
58037
  const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
57483
58038
  let resolvedTask = this.interpolateStepTask(step.task ?? "", stepOutputContext);
57484
58039
  if (attempt > 0 && lastError) {
57485
- const priorOutput = (this.lastFailedStepOutput.get(step.name) ?? "").slice(-2e3);
57486
- resolvedTask = `[RETRY \u2014 Attempt ${attempt + 1}/${maxRetries + 1}]
58040
+ if (lastDiagnosticResult) {
58041
+ resolvedTask = `[RETRY \u2014 Attempt ${attempt + 1}/${maxRetries + 1}] Verification failed.
58042
+ Diagnostic analysis:
58043
+ ${lastDiagnosticResult.analysis}
58044
+
58045
+ Original error: ${lastError}
58046
+ ---
58047
+ ${resolvedTask}`;
58048
+ } else {
58049
+ const priorOutput = (this.lastFailedStepOutput.get(step.name) ?? "").slice(-2e3);
58050
+ const customVerificationFailure = this.lastCustomVerificationFailure.get(step.name);
58051
+ const verificationFailurePrompt = customVerificationFailure ? `[VERIFICATION FAILED] Your code did not pass the verification check.
58052
+ Command: ${customVerificationFailure.command}
58053
+ Output:
58054
+ ${customVerificationFailure.output}
58055
+
58056
+ Fix the issues above before proceeding.
58057
+ ` : "";
58058
+ resolvedTask = `[RETRY \u2014 Attempt ${attempt + 1}/${maxRetries + 1}]
57487
58059
  Previous attempt failed: ${lastError}
57488
- ` + (priorOutput ? `Previous output (last 2000 chars):
58060
+ ` + verificationFailurePrompt + (priorOutput ? `Previous output (last 2000 chars):
57489
58061
  ${priorOutput}
57490
58062
  ` : "") + `---
57491
58063
  ${resolvedTask}`;
58064
+ }
57492
58065
  }
57493
58066
  if (specialistDef.interactive !== false || ownerDef.interactive !== false) {
57494
58067
  const nonInteractiveInfo = this.buildNonInteractiveAwareness(agentMap, stepStates);
@@ -57526,6 +58099,7 @@ ${resolvedTask}`;
57526
58099
  if (usesDedicatedOwner) {
57527
58100
  const result = await this.executeSupervisedAgentStep(step, { specialist: effectiveSpecialist, owner: effectiveOwner, reviewer: reviewDef }, resolvedTask, timeoutMs, attempt);
57528
58101
  specialistOutput = result.specialistOutput;
58102
+ stepOutputForDiagnostic = result.specialistOutput;
57529
58103
  ownerOutput = result.ownerOutput;
57530
58104
  ownerElapsed = result.ownerElapsed;
57531
58105
  completionReason = result.completionReason;
@@ -57573,6 +58147,7 @@ ${resolvedTask}`;
57573
58147
  }
57574
58148
  }
57575
58149
  specialistOutput = output;
58150
+ stepOutputForDiagnostic = output;
57576
58151
  ownerOutput = output;
57577
58152
  }
57578
58153
  if (!usesOwnerFlow) {
@@ -57614,6 +58189,7 @@ ${resolvedTask}`;
57614
58189
  }
57615
58190
  }
57616
58191
  await this.captureAgentReport(runId, step.name, lastEffectiveAgentDef, lastEffectiveCwd, lastAttemptStartedAt, Date.now());
58192
+ lastAttemptReportCaptured = true;
57617
58193
  state.row.status = "completed";
57618
58194
  state.row.output = combinedOutput;
57619
58195
  state.row.completionReason = completionReason;
@@ -57640,6 +58216,22 @@ ${resolvedTask}`;
57640
58216
  } catch (err) {
57641
58217
  lastError = err instanceof Error ? err.message : String(err);
57642
58218
  lastCompletionReason = err instanceof WorkflowCompletionError ? err.completionReason : void 0;
58219
+ const diagnosticVerification = step.verification;
58220
+ if (err instanceof WorkflowCompletionError && err.completionReason === "failed_verification" && diagnosticVerification?.diagnosticAgent && attempt < maxRetries) {
58221
+ lastDiagnosticResult = await this.runDiagnosticAgent(step, lastError, stepOutputForDiagnostic || (this.lastFailedStepOutput.get(step.name) ?? ""), agentMap, runId);
58222
+ } else {
58223
+ lastDiagnosticResult = null;
58224
+ }
58225
+ if (lastCompletionReason !== "failed_verification") {
58226
+ this.lastCustomVerificationFailure.delete(step.name);
58227
+ }
58228
+ if (!(err instanceof BudgetExceededError) && !lastAttemptReportCaptured) {
58229
+ await this.captureAgentReport(runId, step.name, lastEffectiveAgentDef, lastEffectiveCwd, lastAttemptStartedAt, Date.now());
58230
+ lastAttemptReportCaptured = true;
58231
+ }
58232
+ if (err instanceof BudgetExceededError) {
58233
+ break;
58234
+ }
57643
58235
  if (lastCompletionReason === "retry_requested_by_owner" && attempt >= maxRetries) {
57644
58236
  lastError = this.buildOwnerRetryBudgetExceededMessage(step.name, maxRetries, lastError);
57645
58237
  }
@@ -57655,7 +58247,9 @@ ${resolvedTask}`;
57655
58247
  }
57656
58248
  const nonInteractive = ownerDef.interactive === false || ["worker", "reviewer", "analyst"].includes(ownerDef.preset ?? "");
57657
58249
  const verificationValue = typeof step.verification === "object" && "value" in step.verification ? String(step.verification.value) : void 0;
57658
- await this.captureAgentReport(runId, step.name, lastEffectiveAgentDef, lastEffectiveCwd, lastAttemptStartedAt, Date.now());
58250
+ if (!lastAttemptReportCaptured) {
58251
+ await this.captureAgentReport(runId, step.name, lastEffectiveAgentDef, lastEffectiveCwd, lastAttemptStartedAt, Date.now());
58252
+ }
57659
58253
  await this.trajectory?.stepFailed(step, lastError ?? "Unknown error", maxRetries + 1, maxRetries, {
57660
58254
  agent: agentName,
57661
58255
  nonInteractive,
@@ -57668,6 +58262,75 @@ ${resolvedTask}`;
57668
58262
  }, lastCompletionReason);
57669
58263
  throw new Error(`Step "${step.name}" failed after ${maxRetries} retries: ${lastError ?? "Unknown error"}`);
57670
58264
  }
58265
+ async runDiagnosticAgent(step, verificationError, stepOutput, agentMap, runId) {
58266
+ const verification = step.verification;
58267
+ const diagnosticAgentName = verification?.diagnosticAgent;
58268
+ if (!verification || !diagnosticAgentName) {
58269
+ return null;
58270
+ }
58271
+ const rawDiagnosticDef = agentMap.get(diagnosticAgentName);
58272
+ if (!rawDiagnosticDef) {
58273
+ this.log(`[${step.name}] Diagnostic agent "${diagnosticAgentName}" not found \u2014 falling back to standard retry`);
58274
+ return null;
58275
+ }
58276
+ const diagnosticAgentDef = {
58277
+ ..._WorkflowRunner.resolveAgentDef(rawDiagnosticDef),
58278
+ interactive: false
58279
+ };
58280
+ const verificationCommand = verification.type === "custom" ? verification.value : `${verification.type}: ${verification.value}`;
58281
+ const diagnosticTimeout = verification.diagnosticTimeout ?? 6e4;
58282
+ const diagnosticPrompt = `The following verification failed after step "${step.name}".
58283
+
58284
+ Verification command: ${verificationCommand}
58285
+ Verification output:
58286
+ ${verificationError}
58287
+
58288
+ Step task was:
58289
+ ${step.task ?? ""}
58290
+
58291
+ Step output (last 2000 chars):
58292
+ ${stepOutput.slice(-2e3)}
58293
+
58294
+ Analyze what went wrong. Be specific. Do NOT fix the code.`;
58295
+ const diagnosticStep = {
58296
+ ...step,
58297
+ name: `${step.name}-diagnostic-${runId.slice(0, 8)}`,
58298
+ agent: diagnosticAgentName,
58299
+ task: diagnosticPrompt,
58300
+ verification: void 0,
58301
+ retries: 0
58302
+ };
58303
+ const diagnosticCwd = this.resolveExecutionCwd(diagnosticStep, diagnosticAgentDef);
58304
+ const startedAt = Date.now();
58305
+ try {
58306
+ this.ensureBudgetAllowsSpawn(step.name, diagnosticAgentName);
58307
+ this.log(`[${step.name}] Verification failed \u2014 running diagnostic agent '${diagnosticAgentName}'...`);
58308
+ const diagnosticResult = await this.execNonInteractive(diagnosticAgentDef, diagnosticStep, diagnosticTimeout);
58309
+ const elapsedMs = Date.now() - startedAt;
58310
+ await this.captureAgentReport(runId, step.name, diagnosticAgentDef, diagnosticCwd, startedAt, Date.now());
58311
+ const analysis = diagnosticResult.output.trim();
58312
+ const tokenCount = Math.max(1, Math.ceil(analysis.length / 4));
58313
+ const firstLine = analysis.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? "(no analysis returned)";
58314
+ this.log(`[${step.name}] Diagnostic complete (${elapsedMs}ms, ${tokenCount} tokens): ${firstLine}`);
58315
+ return {
58316
+ analysis,
58317
+ metadata: {
58318
+ agentName: diagnosticAgentName,
58319
+ elapsedMs,
58320
+ tokenCount
58321
+ }
58322
+ };
58323
+ } catch (error48) {
58324
+ await this.captureAgentReport(runId, step.name, diagnosticAgentDef, diagnosticCwd, startedAt, Date.now());
58325
+ const message = error48 instanceof Error ? error48.message : String(error48);
58326
+ if (/\btimed out\b/i.test(message)) {
58327
+ this.log(`[${step.name}] Diagnostic timed out \u2014 falling back to standard retry`);
58328
+ } else {
58329
+ this.log(`[${step.name}] Diagnostic failed \u2014 falling back to standard retry: ${message}`);
58330
+ }
58331
+ return null;
58332
+ }
58333
+ }
57671
58334
  buildOwnerRetryBudgetExceededMessage(stepName, maxRetries, ownerDecisionError) {
57672
58335
  const attempts = maxRetries + 1;
57673
58336
  const prefix = `Step "${stepName}" `;
@@ -58577,7 +59240,11 @@ DO NOT:
58577
59240
  this.postToChannel(`**[${step.name}]** Assigned to \`${agentName}\` (non-interactive)`);
58578
59241
  const stdoutChunks = [];
58579
59242
  const stderrChunks = [];
58580
- const env = { ...this.getRelayEnv() ?? filteredEnv() };
59243
+ const proxyMode = await this.resolveAgentProxyMode(agentDef, this.currentConfig);
59244
+ const env = { ...this.getRelayEnv(proxyMode) ?? filteredEnv() };
59245
+ if (proxyMode?.url && proxyMode.token) {
59246
+ Object.assign(env, resolveProxyEnv(agentDef.cli, proxyMode.url, proxyMode.token));
59247
+ }
58581
59248
  const agentToken = this.agentTokens.get(agentDef.name);
58582
59249
  const mount = this.agentMounts.get(agentDef.name);
58583
59250
  if (agentToken) {
@@ -58591,7 +59258,7 @@ DO NOT:
58591
59258
  env.RELAY_WORKSPACE_ID = this.workspaceId;
58592
59259
  env.RELAY_DEFAULT_WORKSPACE = this.workspaceId;
58593
59260
  }
58594
- env.RELAYFILE_BASE_URL = env.RELAYFILE_BASE_URL ?? this.getRelayEnv()?.RELAYFILE_BASE_URL ?? process.env.RELAYFILE_BASE_URL ?? "http://127.0.0.1:8080";
59261
+ env.RELAYFILE_BASE_URL = env.RELAYFILE_BASE_URL ?? this.getRelayEnv(proxyMode)?.RELAYFILE_BASE_URL ?? process.env.RELAYFILE_BASE_URL ?? "http://127.0.0.1:8080";
58595
59262
  try {
58596
59263
  const { stdout: output, exitCode, exitSignal } = await new Promise((resolve4, reject) => {
58597
59264
  const spawnEnv = agentDef.cli === "opencode" ? {
@@ -58746,6 +59413,9 @@ DO NOT:
58746
59413
  RELAY_API_KEY: this.relayApiKey ?? "workflow-runner",
58747
59414
  AGENT_CHANNELS: (agentChannels ?? []).join(",")
58748
59415
  });
59416
+ const proxyMode = await this.resolveAgentProxyMode(agentDef, this.currentConfig);
59417
+ const baseEnv = this.getRelayEnv(proxyMode);
59418
+ const proxyEnvOverrides = proxyMode?.url && proxyMode.token ? resolveProxyEnv(agentDef.cli, proxyMode.url, proxyMode.token) : void 0;
58749
59419
  const spawnOptions = {
58750
59420
  name: agentName,
58751
59421
  model: agentDef.constraints?.model,
@@ -58754,7 +59424,8 @@ DO NOT:
58754
59424
  task: preparedTask.spawnTaskText,
58755
59425
  idleThresholdSecs: agentDef.constraints?.idleThresholdSecs,
58756
59426
  cwd: agentCwd,
58757
- agentToken: this.agentTokens.get(agentDef.name)
59427
+ agentToken: this.agentTokens.get(agentDef.name),
59428
+ env: proxyEnvOverrides ? { ...baseEnv, ...proxyEnvOverrides } : baseEnv
58758
59429
  };
58759
59430
  const sdkSpawner = getWorkflowSdkSpawner(this.relay, agentDef.cli);
58760
59431
  if (sdkSpawner) {
@@ -59092,10 +59763,31 @@ DO NOT:
59092
59763
  }
59093
59764
  // ── Verification ────────────────────────────────────────────────────────
59094
59765
  runVerification(check2, output, stepName, injectedTaskText, options) {
59095
- return runVerification(check2, output, stepName, injectedTaskText, { ...options, cwd: this.cwd }, {
59096
- recordStepToolSideEffect: (name, effect) => this.recordStepToolSideEffect(name, effect),
59097
- getOrCreateStepEvidenceRecord: (name) => this.getOrCreateStepEvidenceRecord(name),
59098
- log: (message) => this.log(message)
59766
+ try {
59767
+ const result = runVerification(check2, output, stepName, injectedTaskText, { ...options, cwd: this.cwd }, {
59768
+ recordStepToolSideEffect: (name, effect) => this.recordStepToolSideEffect(name, effect),
59769
+ getOrCreateStepEvidenceRecord: (name) => this.getOrCreateStepEvidenceRecord(name),
59770
+ log: (message) => this.log(message)
59771
+ });
59772
+ this.updateCustomVerificationFailure(stepName, check2, result.error);
59773
+ return result;
59774
+ } catch (error48) {
59775
+ this.updateCustomVerificationFailure(stepName, check2, error48 instanceof Error ? error48.message : String(error48));
59776
+ throw error48;
59777
+ }
59778
+ }
59779
+ updateCustomVerificationFailure(stepName, check2, errorMessage) {
59780
+ if (check2.type !== "custom" || !check2.value || !errorMessage) {
59781
+ this.lastCustomVerificationFailure.delete(stepName);
59782
+ return;
59783
+ }
59784
+ const marker = `custom check "${check2.value}" failed
59785
+ `;
59786
+ const markerIndex = errorMessage.indexOf(marker);
59787
+ const output = markerIndex === -1 ? errorMessage.trim() : errorMessage.slice(markerIndex + marker.length).trim();
59788
+ this.lastCustomVerificationFailure.set(stepName, {
59789
+ command: check2.value,
59790
+ output
59099
59791
  });
59100
59792
  }
59101
59793
  // ── State helpers ─────────────────────────────────────────────────────
@@ -59147,6 +59839,18 @@ DO NOT:
59147
59839
  });
59148
59840
  if (!report)
59149
59841
  return;
59842
+ const totalTokens = this.getTotalReportTokens(report);
59843
+ if (this.budgetTracker && report.tokens) {
59844
+ this.budgetTracker.recordUsage(stepName, report.tokens);
59845
+ this.budgetTracker.isOverBudget(stepName);
59846
+ const budgetStatus = this.budgetTracker.getBudgetStatus(stepName);
59847
+ if (budgetStatus.agentLimitExceeded) {
59848
+ const stepBudget = this.budgetTracker.getStepBudgetStatus(stepName);
59849
+ const used = stepBudget?.used?.toLocaleString("en-US") ?? totalTokens?.toLocaleString("en-US") ?? "0";
59850
+ const limit = stepBudget?.limit?.toLocaleString("en-US") ?? "--";
59851
+ this.log(`[budget] Step ${stepName} exceeded its agent budget (${used} of ${limit})`);
59852
+ }
59853
+ }
59150
59854
  this.agentReports.set(stepName, report);
59151
59855
  this.emit({ type: "step:agent-report", runId, stepName, report });
59152
59856
  await this.persistAgentReport(runId, stepName, report);
@@ -59292,7 +59996,7 @@ DO NOT:
59292
59996
  console.log(` Workflow "${workflowName}" \u2014 ${failed.length === 0 ? import_chalk.default.green("COMPLETED") : import_chalk.default.red("FAILED")}`);
59293
59997
  console.log(` ${import_chalk.default.green(`${completed.length} passed`)}, ${import_chalk.default.red(`${failed.length} failed`)}, ${import_chalk.default.dim(`${skipped.length} skipped`)}`);
59294
59998
  console.log(import_chalk.default.dim("\u2501".repeat(70)));
59295
- console.log(formatRunSummaryTable(outcomes, this.agentReports));
59999
+ console.log(formatRunSummaryTable(outcomes, this.agentReports, this.budgetTracker?.getRunSummaryBudgetData()));
59296
60000
  for (const outcome of outcomes) {
59297
60001
  if (outcome.status !== "failed")
59298
60002
  continue;
@@ -60322,8 +61026,7 @@ var WorkflowBuilder = class {
60322
61026
  this._errorHandling.notifyChannel = options.notifyChannel;
60323
61027
  return this;
60324
61028
  }
60325
- /** Build and return the RelayYamlConfig object. */
60326
- toConfig() {
61029
+ validateBuilderState() {
60327
61030
  const hasAgentSteps = this._steps.some((s3) => s3.type !== "deterministic" && s3.type !== "worktree");
60328
61031
  if (hasAgentSteps && this._agents.length === 0) {
60329
61032
  throw new Error("Workflow must have at least one agent when using agent steps");
@@ -60331,6 +61034,22 @@ var WorkflowBuilder = class {
60331
61034
  if (this._steps.length === 0) {
60332
61035
  throw new Error("Workflow must have at least one step");
60333
61036
  }
61037
+ const agentNames = new Set(this._agents.map((agent) => agent.name));
61038
+ for (const step of this._steps) {
61039
+ const diagnosticAgent = step.verification?.diagnosticAgent;
61040
+ if (!diagnosticAgent)
61041
+ continue;
61042
+ if (!agentNames.has(diagnosticAgent)) {
61043
+ throw new Error(`Step "${step.name}" references unknown diagnosticAgent "${diagnosticAgent}"`);
61044
+ }
61045
+ if (step.retries === void 0 || step.retries === 0) {
61046
+ console.warn(`Step "${step.name}": diagnosticAgent configured but no retries \u2014 diagnostic will never run`);
61047
+ }
61048
+ }
61049
+ }
61050
+ /** Build and return the RelayYamlConfig object. */
61051
+ toConfig() {
61052
+ this.validateBuilderState();
60334
61053
  const wfDef = {
60335
61054
  name: `${this._name}-workflow`,
60336
61055
  steps: [...this._steps]
@@ -62138,14 +62857,14 @@ function benchmarkPatterns(iterations = 1e4) {
62138
62857
  }
62139
62858
 
62140
62859
  // packages/utils/dist/command-resolver.js
62141
- var import_node_child_process8 = require("node:child_process");
62860
+ var import_node_child_process9 = require("node:child_process");
62142
62861
  var import_node_fs24 = __toESM(require("node:fs"), 1);
62143
62862
  function resolveCommand(command) {
62144
62863
  if (command.startsWith("/")) {
62145
62864
  return resolveSymlinks(command);
62146
62865
  }
62147
62866
  try {
62148
- const output = (0, import_node_child_process8.execSync)(`which ${command}`, {
62867
+ const output = (0, import_node_child_process9.execSync)(`which ${command}`, {
62149
62868
  encoding: "utf-8",
62150
62869
  stdio: ["pipe", "pipe", "pipe"],
62151
62870
  // Ensure we have a reasonable PATH
@@ -62179,7 +62898,7 @@ function resolveSymlinks(filePath) {
62179
62898
  }
62180
62899
  function commandExists(command) {
62181
62900
  try {
62182
- (0, import_node_child_process8.execSync)(`which ${command}`, {
62901
+ (0, import_node_child_process9.execSync)(`which ${command}`, {
62183
62902
  encoding: "utf-8",
62184
62903
  stdio: ["pipe", "pipe", "pipe"]
62185
62904
  });
@@ -62192,7 +62911,7 @@ function commandExists(command) {
62192
62911
  // packages/utils/dist/git-remote.js
62193
62912
  var fs8 = __toESM(require("node:fs"), 1);
62194
62913
  var path20 = __toESM(require("node:path"), 1);
62195
- var import_node_child_process9 = require("node:child_process");
62914
+ var import_node_child_process10 = require("node:child_process");
62196
62915
  function parseGitRemoteUrl(url2) {
62197
62916
  if (!url2)
62198
62917
  return null;
@@ -62212,7 +62931,7 @@ function getGitRemoteUrl(workingDirectory, remoteName = "origin") {
62212
62931
  if (!fs8.existsSync(gitDir)) {
62213
62932
  return null;
62214
62933
  }
62215
- const result = (0, import_node_child_process9.execSync)(`git remote get-url ${remoteName}`, {
62934
+ const result = (0, import_node_child_process10.execSync)(`git remote get-url ${remoteName}`, {
62216
62935
  cwd: workingDirectory,
62217
62936
  encoding: "utf-8",
62218
62937
  timeout: 5e3,
@@ -63343,7 +64062,7 @@ var HookRegistry = class {
63343
64062
  };
63344
64063
 
63345
64064
  // packages/trajectory/dist/integration.js
63346
- var import_node_child_process10 = require("node:child_process");
64065
+ var import_node_child_process11 = require("node:child_process");
63347
64066
 
63348
64067
  // packages/config/dist/project-namespace.js
63349
64068
  var import_node_crypto15 = __toESM(require("node:crypto"), 1);
@@ -63472,7 +64191,7 @@ function getTrajectoryEnvVars(projectRoot) {
63472
64191
  async function runTrail(args) {
63473
64192
  return new Promise((resolve4) => {
63474
64193
  const trajectoryEnv = getTrajectoryEnvVars();
63475
- const proc = (0, import_node_child_process10.spawn)("trail", args, {
64194
+ const proc = (0, import_node_child_process11.spawn)("trail", args, {
63476
64195
  cwd: getProjectPaths2().projectRoot,
63477
64196
  env: { ...process.env, ...trajectoryEnv },
63478
64197
  stdio: ["pipe", "pipe", "pipe"]
@@ -63743,7 +64462,7 @@ var TrajectoryIntegration = class {
63743
64462
  */
63744
64463
  isTrailInstalledSync() {
63745
64464
  try {
63746
- (0, import_node_child_process10.execSync)("which trail", { stdio: "pipe" });
64465
+ (0, import_node_child_process11.execSync)("which trail", { stdio: "pipe" });
63747
64466
  return true;
63748
64467
  } catch {
63749
64468
  return false;
@@ -64178,6 +64897,8 @@ init_dist2();
64178
64897
  BUILT_IN_TEMPLATE_NAMES,
64179
64898
  BarrierManager,
64180
64899
  BrokerTransport,
64900
+ BudgetExceededError,
64901
+ BudgetTracker,
64181
64902
  CLAUDE_MODEL_OPTIONS,
64182
64903
  CLIRegistry,
64183
64904
  CLIVersions,
@@ -64195,6 +64916,7 @@ init_dist2();
64195
64916
  CustomStepResolutionError,
64196
64917
  CustomStepsParseError,
64197
64918
  DEFAULT_INBOX_DIR,
64919
+ DEFAULT_PROXY_ENV_REGISTRY,
64198
64920
  DefaultModels,
64199
64921
  ERROR_SEARCH_HINT,
64200
64922
  GEMINI_MODEL_OPTIONS,
@@ -64209,6 +64931,10 @@ init_dist2();
64209
64931
  ModelOptions,
64210
64932
  Models,
64211
64933
  PROTOCOL_VERSION,
64934
+ RELAY_PROXY_TOKEN_ENV,
64935
+ RELAY_PROXY_TOKEN_ENV_ALIAS,
64936
+ RELAY_PROXY_URL_ENV,
64937
+ RELAY_PROXY_URL_ENV_ALIAS,
64212
64938
  ReasoningEfforts,
64213
64939
  RelayAdapter,
64214
64940
  RelayCast,
@@ -64233,6 +64959,8 @@ init_dist2();
64233
64959
  buildBlockReason,
64234
64960
  buildCommand,
64235
64961
  buildModelSwitchCommand,
64962
+ buildNormalizedProxyEnv,
64963
+ checkCustom,
64236
64964
  checkExitCode,
64237
64965
  checkFileExists,
64238
64966
  checkForUpdates,
@@ -64256,6 +64984,7 @@ init_dist2();
64256
64984
  createMemoryService,
64257
64985
  createProcessBackendExecutor,
64258
64986
  createProcessSpawner,
64987
+ createProxyEnvResolver,
64259
64988
  createRequestEnvelope,
64260
64989
  createRequestHandler,
64261
64990
  createTraceableError,
@@ -64265,6 +64994,7 @@ init_dist2();
64265
64994
  detectCompletion,
64266
64995
  estimateContextTokens,
64267
64996
  estimateTokens,
64997
+ execCustomVerification,
64268
64998
  executeApiStep,
64269
64999
  findGitRoot,
64270
65000
  findRelayPtyBinary,
@@ -64298,6 +65028,7 @@ init_dist2();
64298
65028
  getPatternMetrics,
64299
65029
  getRepoFullName,
64300
65030
  getRepoFullNameFromPath,
65031
+ getStrippedApiKeyVars,
64301
65032
  getSupportedPlatforms,
64302
65033
  getSupportedReasoningEfforts,
64303
65034
  getTrajectoryHooks,
@@ -64317,6 +65048,7 @@ init_dist2();
64317
65048
  isModelSwitchSupported,
64318
65049
  isPlaceholderTargetFast,
64319
65050
  isPlatformSupported,
65051
+ isProxyEnabled,
64320
65052
  isRestrictedAgent,
64321
65053
  isSpawnOrReleaseCommandFast,
64322
65054
  isTrajectoryTrackingAvailable,
@@ -64340,6 +65072,9 @@ init_dist2();
64340
65072
  resolveCommand,
64341
65073
  resolveCustomStep,
64342
65074
  resolveDotPath,
65075
+ resolveProxyEnv,
65076
+ resolveProxyTokenFromEnv,
65077
+ resolveProxyUrlFromEnv,
64343
65078
  resolveSpawnPolicy,
64344
65079
  resolveStepOutputRef,
64345
65080
  resolveTemplate,