@the-open-engine/zeroshot 6.38.1 → 6.39.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 (377) hide show
  1. package/cli/event-copy.js +8 -7
  2. package/cli/event-copy.ts +12 -0
  3. package/cli/index.js +7 -31
  4. package/cli/json-export.js +61 -64
  5. package/cli/json-export.ts +112 -0
  6. package/cli/message-formatter-utils.js +68 -56
  7. package/cli/message-formatter-utils.ts +121 -0
  8. package/cli/message-formatters-normal.js +124 -259
  9. package/cli/message-formatters-normal.ts +250 -0
  10. package/cli/message-formatters-watch.js +81 -84
  11. package/cli/message-formatters-watch.ts +189 -0
  12. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  13. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  14. package/lib/cluster/generated/protocol.d.cts +8 -0
  15. package/lib/cluster/generated/protocol.d.mts +8 -0
  16. package/lib/cluster/generated/protocol.d.ts +8 -0
  17. package/lib/clusters-registry.d.ts +23 -0
  18. package/lib/clusters-registry.js +17 -29
  19. package/lib/completion.d.ts +12 -0
  20. package/lib/completion.js +84 -94
  21. package/lib/compose-utils.d.ts +32 -0
  22. package/lib/compose-utils.js +57 -72
  23. package/lib/detached-startup.d.ts +83 -0
  24. package/lib/detached-startup.js +231 -302
  25. package/lib/docker-config.d.ts +43 -0
  26. package/lib/docker-config.js +150 -325
  27. package/lib/docker-env-auth.d.ts +17 -0
  28. package/lib/docker-env-auth.js +75 -0
  29. package/lib/git-remote-utils.d.ts +48 -0
  30. package/lib/git-remote-utils.js +147 -213
  31. package/lib/id-detector.d.ts +15 -0
  32. package/lib/id-detector.js +37 -41
  33. package/lib/path-check.d.ts +30 -0
  34. package/lib/path-check.js +42 -45
  35. package/lib/process-liveness.d.ts +16 -0
  36. package/lib/process-liveness.js +19 -12
  37. package/lib/provider-credential-path.d.ts +16 -0
  38. package/lib/provider-credential-path.js +31 -29
  39. package/lib/provider-defaults.d.ts +30 -0
  40. package/lib/provider-defaults.js +47 -42
  41. package/lib/provider-detection.d.ts +11 -0
  42. package/lib/provider-detection.js +91 -54
  43. package/lib/provider-names.d.ts +38 -0
  44. package/lib/provider-names.js +56 -64
  45. package/lib/repo-settings.d.ts +28 -0
  46. package/lib/repo-settings.js +83 -59
  47. package/lib/run-mode.d.ts +21 -0
  48. package/lib/run-mode.js +21 -20
  49. package/lib/run-plan.d.ts +28 -0
  50. package/lib/run-plan.js +17 -16
  51. package/lib/settings/claude-auth.d.ts +35 -0
  52. package/lib/settings/claude-auth.js +30 -47
  53. package/lib/settings-defaults.d.ts +20 -0
  54. package/lib/settings-defaults.js +149 -0
  55. package/lib/settings-error.d.ts +7 -0
  56. package/lib/settings-error.js +8 -0
  57. package/lib/settings-issue-providers.d.ts +10 -0
  58. package/lib/settings-issue-providers.js +12 -0
  59. package/lib/settings-models.d.ts +22 -0
  60. package/lib/settings-models.js +93 -0
  61. package/lib/settings-storage.d.ts +23 -0
  62. package/lib/settings-storage.js +205 -0
  63. package/lib/settings-validation.d.ts +7 -0
  64. package/lib/settings-validation.js +182 -0
  65. package/lib/settings.d.ts +29 -0
  66. package/lib/settings.js +41 -736
  67. package/lib/setup-apply-types.d.ts +66 -0
  68. package/lib/setup-apply-types.js +2 -0
  69. package/lib/setup-apply.d.ts +39 -0
  70. package/lib/setup-apply.js +267 -264
  71. package/lib/setup-journal.d.ts +41 -0
  72. package/lib/setup-journal.js +119 -76
  73. package/lib/setup-plan-types.d.ts +102 -0
  74. package/lib/setup-plan-types.js +2 -0
  75. package/lib/setup-plan.d.ts +30 -0
  76. package/lib/setup-plan.js +300 -324
  77. package/lib/setup-undo.d.ts +44 -0
  78. package/lib/setup-undo.js +61 -74
  79. package/lib/start-cluster-config.d.ts +26 -0
  80. package/lib/start-cluster-config.js +56 -0
  81. package/lib/start-cluster-environment.d.ts +40 -0
  82. package/lib/start-cluster-environment.js +134 -0
  83. package/lib/start-cluster-run-options.d.ts +53 -0
  84. package/lib/start-cluster-run-options.js +147 -0
  85. package/lib/start-cluster.d.ts +64 -0
  86. package/lib/start-cluster.js +98 -454
  87. package/lib/stream-json-parser.d.ts +17 -0
  88. package/lib/stream-json-parser.js +51 -52
  89. package/npm-shrinkwrap.json +2 -2
  90. package/package.json +12 -6
  91. package/scripts/postinstall.js +27 -0
  92. package/scripts/rust-distribution.js +23 -14
  93. package/src/agent/agent-command-proofs-context.js +35 -45
  94. package/src/agent/agent-command-proofs-context.ts +87 -0
  95. package/src/agent/agent-config-settings.js +19 -0
  96. package/src/agent/agent-config-settings.ts +41 -0
  97. package/src/agent/agent-config.js +122 -231
  98. package/src/agent/agent-config.ts +285 -0
  99. package/src/agent/agent-context-builder.js +38 -273
  100. package/src/agent/agent-context-builder.ts +51 -0
  101. package/src/agent/agent-context-environment-sections.js +105 -0
  102. package/src/agent/agent-context-environment-sections.ts +134 -0
  103. package/src/agent/agent-context-packs.js +165 -0
  104. package/src/agent/agent-context-packs.ts +296 -0
  105. package/src/agent/agent-context-prompt-sections.js +100 -0
  106. package/src/agent/agent-context-prompt-sections.ts +148 -0
  107. package/src/agent/agent-context-sections.js +25 -334
  108. package/src/agent/agent-context-sections.ts +36 -0
  109. package/src/agent/agent-context-sources.js +96 -149
  110. package/src/agent/agent-context-sources.ts +253 -0
  111. package/src/agent/agent-context-types.js +2 -0
  112. package/src/agent/agent-context-types.ts +132 -0
  113. package/src/agent/agent-context-validation-sections.js +73 -0
  114. package/src/agent/agent-context-validation-sections.ts +129 -0
  115. package/src/agent/agent-input-injector.js +99 -118
  116. package/src/agent/agent-input-injector.ts +195 -0
  117. package/src/agent/agent-liveness-poll.js +74 -78
  118. package/src/agent/agent-liveness-poll.ts +163 -0
  119. package/src/agent/agent-quality-gate-schema.js +77 -86
  120. package/src/agent/agent-quality-gate-schema.ts +135 -0
  121. package/src/agent/agent-quality-gates-context.js +44 -50
  122. package/src/agent/agent-quality-gates-context.ts +91 -0
  123. package/src/agent/agent-stuck-detector.js +171 -239
  124. package/src/agent/agent-stuck-detector.ts +288 -0
  125. package/src/agent/agent-trigger-evaluator.js +29 -46
  126. package/src/agent/agent-trigger-evaluator.ts +98 -0
  127. package/src/agent/context-metrics.js +110 -141
  128. package/src/agent/context-metrics.ts +261 -0
  129. package/src/agent/context-pack-builder.js +72 -358
  130. package/src/agent/context-pack-builder.ts +105 -0
  131. package/src/agent/context-pack-core.js +70 -0
  132. package/src/agent/context-pack-core.ts +96 -0
  133. package/src/agent/context-pack-selection.js +119 -0
  134. package/src/agent/context-pack-selection.ts +187 -0
  135. package/src/agent/context-pack-truncation.js +139 -0
  136. package/src/agent/context-pack-truncation.ts +208 -0
  137. package/src/agent/context-pack-types.js +2 -0
  138. package/src/agent/context-pack-types.ts +98 -0
  139. package/src/agent/context-replay-policy.js +30 -39
  140. package/src/agent/context-replay-policy.ts +71 -0
  141. package/src/agent/critical-agent-policy.js +6 -10
  142. package/src/agent/critical-agent-policy.ts +20 -0
  143. package/src/agent/guidance-queue.js +74 -87
  144. package/src/agent/guidance-queue.ts +166 -0
  145. package/src/agent/output-extraction-error-detail.js +45 -0
  146. package/src/agent/output-extraction-error-detail.ts +49 -0
  147. package/src/agent/output-extraction-failures.js +125 -0
  148. package/src/agent/output-extraction-failures.ts +149 -0
  149. package/src/agent/output-extraction-json.js +234 -0
  150. package/src/agent/output-extraction-json.ts +235 -0
  151. package/src/agent/output-extraction-pi.js +124 -0
  152. package/src/agent/output-extraction-pi.ts +137 -0
  153. package/src/agent/output-extraction-types.js +2 -0
  154. package/src/agent/output-extraction-types.ts +49 -0
  155. package/src/agent/output-extraction.js +17 -617
  156. package/src/agent/output-extraction.ts +30 -0
  157. package/src/agent/output-reformatter-errors.js +83 -0
  158. package/src/agent/output-reformatter-errors.ts +106 -0
  159. package/src/agent/output-reformatter-types.js +2 -0
  160. package/src/agent/output-reformatter-types.ts +86 -0
  161. package/src/agent/output-reformatter.js +140 -185
  162. package/src/agent/output-reformatter.ts +238 -0
  163. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  164. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  165. package/src/agent/pi-terminal-lifecycle.js +186 -206
  166. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  167. package/src/agent/provider-control-plane.js +22 -21
  168. package/src/agent/provider-control-plane.ts +52 -0
  169. package/src/agent/provider-terminal-failure-types.js +2 -0
  170. package/src/agent/provider-terminal-failure-types.ts +60 -0
  171. package/src/agent/provider-terminal-failure.js +194 -191
  172. package/src/agent/provider-terminal-failure.ts +262 -0
  173. package/src/agent/rate-limit-backoff.js +31 -74
  174. package/src/agent/rate-limit-backoff.ts +71 -0
  175. package/src/agent/schema-utils.js +85 -125
  176. package/src/agent/schema-utils.ts +148 -0
  177. package/src/agent/structured-output-error.js +34 -33
  178. package/src/agent/structured-output-error.ts +105 -0
  179. package/src/agent/validation-platform.js +27 -27
  180. package/src/agent/validation-platform.ts +49 -0
  181. package/src/attach/attach-client.js +232 -405
  182. package/src/attach/attach-client.ts +300 -0
  183. package/src/attach/attach-server-cleanup.js +43 -0
  184. package/src/attach/attach-server-cleanup.ts +39 -0
  185. package/src/attach/attach-server-clients.js +117 -0
  186. package/src/attach/attach-server-clients.ts +122 -0
  187. package/src/attach/attach-server-events.js +38 -0
  188. package/src/attach/attach-server-events.ts +36 -0
  189. package/src/attach/attach-server-pty.js +45 -0
  190. package/src/attach/attach-server-pty.ts +64 -0
  191. package/src/attach/attach-server-runtime.js +73 -0
  192. package/src/attach/attach-server-runtime.ts +62 -0
  193. package/src/attach/attach-server-socket.js +28 -0
  194. package/src/attach/attach-server-socket.ts +23 -0
  195. package/src/attach/attach-server-types.js +2 -0
  196. package/src/attach/attach-server-types.ts +82 -0
  197. package/src/attach/attach-server.js +106 -523
  198. package/src/attach/attach-server.ts +158 -0
  199. package/src/attach/index.js +18 -35
  200. package/src/attach/index.ts +18 -0
  201. package/src/attach/protocol.js +95 -184
  202. package/src/attach/protocol.ts +181 -0
  203. package/src/attach/ring-buffer.js +76 -102
  204. package/src/attach/ring-buffer.ts +109 -0
  205. package/src/attach/send-input.js +64 -75
  206. package/src/attach/send-input.ts +94 -0
  207. package/src/attach/socket-discovery.js +164 -218
  208. package/src/attach/socket-discovery.ts +230 -0
  209. package/src/attach/socket-paths.js +42 -61
  210. package/src/attach/socket-paths.ts +81 -0
  211. package/src/claude-credentials.js +51 -54
  212. package/src/claude-credentials.ts +89 -0
  213. package/src/cluster/generated/protocol-schema.ts +1 -1
  214. package/src/cluster/generated/protocol.ts +2 -1
  215. package/src/command-proofs.js +110 -141
  216. package/src/command-proofs.ts +216 -0
  217. package/src/config-router.js +81 -73
  218. package/src/config-router.ts +131 -0
  219. package/src/copy-worker.js +53 -29
  220. package/src/copy-worker.ts +75 -0
  221. package/src/darwin-keychain-boundary.js +80 -111
  222. package/src/darwin-keychain-boundary.ts +148 -0
  223. package/src/guidance-topics.js +4 -5
  224. package/src/guidance-topics.ts +10 -0
  225. package/src/input-helpers.js +33 -54
  226. package/src/input-helpers.ts +58 -0
  227. package/src/ledger-sequence.js +45 -48
  228. package/src/ledger-sequence.ts +63 -0
  229. package/src/legacy-lib/clusters-registry.ts +40 -0
  230. package/src/legacy-lib/completion.ts +148 -0
  231. package/src/legacy-lib/compose-utils.ts +102 -0
  232. package/src/legacy-lib/detached-startup.ts +449 -0
  233. package/src/legacy-lib/docker-config.ts +282 -0
  234. package/src/legacy-lib/docker-env-auth.ts +116 -0
  235. package/src/legacy-lib/git-remote-utils.ts +244 -0
  236. package/src/legacy-lib/id-detector.ts +57 -0
  237. package/src/legacy-lib/js-yaml.d.ts +3 -0
  238. package/src/legacy-lib/omelette.d.ts +15 -0
  239. package/src/legacy-lib/path-check.ts +89 -0
  240. package/src/legacy-lib/process-liveness.ts +36 -0
  241. package/src/legacy-lib/provider-credential-path.ts +57 -0
  242. package/src/legacy-lib/provider-defaults.ts +114 -0
  243. package/src/legacy-lib/provider-detection.ts +67 -0
  244. package/src/legacy-lib/provider-names.ts +126 -0
  245. package/src/legacy-lib/repo-settings.ts +88 -0
  246. package/src/legacy-lib/run-mode.ts +58 -0
  247. package/src/legacy-lib/run-plan.ts +49 -0
  248. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  249. package/src/legacy-lib/settings-defaults.ts +212 -0
  250. package/src/legacy-lib/settings-error.ts +8 -0
  251. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  252. package/src/legacy-lib/settings-models.ts +124 -0
  253. package/src/legacy-lib/settings-storage.ts +277 -0
  254. package/src/legacy-lib/settings-validation.ts +220 -0
  255. package/src/legacy-lib/settings.ts +87 -0
  256. package/src/legacy-lib/setup-apply-types.ts +70 -0
  257. package/src/legacy-lib/setup-apply.ts +456 -0
  258. package/src/legacy-lib/setup-journal.ts +185 -0
  259. package/src/legacy-lib/setup-plan-types.ts +96 -0
  260. package/src/legacy-lib/setup-plan.ts +500 -0
  261. package/src/legacy-lib/setup-undo.ts +142 -0
  262. package/src/legacy-lib/start-cluster-config.ts +124 -0
  263. package/src/legacy-lib/start-cluster-environment.ts +165 -0
  264. package/src/legacy-lib/start-cluster-run-options.ts +279 -0
  265. package/src/legacy-lib/start-cluster.ts +237 -0
  266. package/src/legacy-lib/stream-json-parser.ts +88 -0
  267. package/src/message-buffer.js +55 -71
  268. package/src/message-buffer.ts +107 -0
  269. package/src/message-bus-bridge.js +92 -133
  270. package/src/message-bus-bridge.ts +149 -0
  271. package/src/name-generator-shared.js +220 -0
  272. package/src/name-generator-shared.ts +231 -0
  273. package/src/name-generator.js +8 -217
  274. package/src/name-generator.ts +27 -0
  275. package/src/omp-blob-root.js +83 -64
  276. package/src/omp-blob-root.ts +116 -0
  277. package/src/omp-config-overlay.js +65 -38
  278. package/src/omp-config-overlay.ts +110 -0
  279. package/src/omp-execution-fingerprint.js +38 -43
  280. package/src/omp-execution-fingerprint.ts +92 -0
  281. package/src/omp-session-limits.js +10 -15
  282. package/src/omp-session-limits.ts +53 -0
  283. package/src/omp-session-partition.js +2 -2
  284. package/src/omp-session-verifier.js +1 -1
  285. package/src/orchestrator.js +19 -4
  286. package/src/providers/anthropic/index.js +3 -1
  287. package/src/providers/anthropic/index.ts +13 -0
  288. package/src/providers/capabilities.js +19 -27
  289. package/src/providers/capabilities.ts +44 -0
  290. package/src/providers/google/index.js +3 -1
  291. package/src/providers/google/index.ts +13 -0
  292. package/src/providers/openai/index.js +3 -1
  293. package/src/providers/openai/index.ts +13 -0
  294. package/src/providers/opencode/index.js +3 -1
  295. package/src/providers/opencode/index.ts +13 -0
  296. package/src/quality-gates.js +67 -127
  297. package/src/quality-gates.ts +149 -0
  298. package/src/repo-settings-access.js +40 -0
  299. package/src/repo-settings-access.ts +64 -0
  300. package/src/schemas/sub-cluster.js +127 -183
  301. package/src/schemas/sub-cluster.ts +238 -0
  302. package/src/state-snapshot-normalization.js +224 -0
  303. package/src/state-snapshot-normalization.ts +222 -0
  304. package/src/state-snapshot.js +192 -359
  305. package/src/state-snapshot.ts +291 -0
  306. package/src/state-snapshotter.js +118 -130
  307. package/src/state-snapshotter.ts +167 -0
  308. package/src/sub-cluster-wrapper.js +4 -13
  309. package/src/task-run-model-args.js +87 -124
  310. package/src/task-run-model-args.ts +204 -0
  311. package/src/task-runner.js +5 -25
  312. package/src/task-runner.ts +28 -0
  313. package/src/task-startup-error.js +73 -58
  314. package/src/task-startup-error.ts +126 -0
  315. package/src/template-validation/consensus-gate-contracts.js +2 -0
  316. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  317. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  318. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  319. package/src/template-validation/consensus-gate-stage.js +34 -0
  320. package/src/template-validation/consensus-gate-stage.ts +56 -0
  321. package/src/template-validation/random-topology-contracts.js +2 -0
  322. package/src/template-validation/random-topology-contracts.ts +54 -0
  323. package/src/template-validation/random-topology-dispatch.js +25 -0
  324. package/src/template-validation/random-topology-dispatch.ts +33 -0
  325. package/src/template-validation/random-topology-message-loop.js +53 -0
  326. package/src/template-validation/random-topology-message-loop.ts +73 -0
  327. package/src/template-validation/random-topology-operations.js +79 -0
  328. package/src/template-validation/random-topology-operations.ts +101 -0
  329. package/src/template-validation/random-topology-runtime.js +25 -0
  330. package/src/template-validation/random-topology-runtime.ts +43 -0
  331. package/src/template-validation/random-topology-scenario.js +52 -0
  332. package/src/template-validation/random-topology-scenario.ts +57 -0
  333. package/src/template-validation/random-topology-schema.js +159 -0
  334. package/src/template-validation/random-topology-schema.ts +190 -0
  335. package/src/template-validation/random-topology-state.js +28 -0
  336. package/src/template-validation/random-topology-state.ts +30 -0
  337. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  338. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  339. package/src/template-validation/random-topology-trigger.js +75 -0
  340. package/src/template-validation/random-topology-trigger.ts +88 -0
  341. package/src/template-validation/report-formatter.js +40 -46
  342. package/src/template-validation/report-formatter.ts +101 -0
  343. package/src/template-validation/simulate-consensus-gates.js +111 -302
  344. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  345. package/src/template-validation/simulate-random-topology.js +26 -519
  346. package/src/template-validation/simulate-random-topology.ts +57 -0
  347. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  348. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  349. package/src/template-validation/simulation-agent-runtime.js +25 -0
  350. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  351. package/src/template-validation/simulation-agent.js +29 -0
  352. package/src/template-validation/simulation-agent.ts +73 -0
  353. package/src/template-validation/simulation-runtime.js +34 -0
  354. package/src/template-validation/simulation-runtime.ts +72 -0
  355. package/src/template-validation/two-stage-contracts.js +2 -0
  356. package/src/template-validation/two-stage-contracts.ts +41 -0
  357. package/src/template-validation/two-stage-inputs.js +21 -0
  358. package/src/template-validation/two-stage-inputs.ts +29 -0
  359. package/src/template-validation/two-stage-results.js +30 -0
  360. package/src/template-validation/two-stage-results.ts +40 -0
  361. package/src/template-validation/two-stage-scenario.js +86 -0
  362. package/src/template-validation/two-stage-scenario.ts +120 -0
  363. package/src/worktree-claude-config.js +182 -220
  364. package/src/worktree-claude-config.ts +272 -0
  365. package/src/worktree-tooling-env.js +103 -125
  366. package/src/worktree-tooling-env.ts +142 -0
  367. package/task-lib/completion.js +2 -3
  368. package/task-lib/completion.ts +9 -0
  369. package/task-lib/config.js +1 -4
  370. package/task-lib/config.ts +11 -0
  371. package/task-lib/name-generator.js +4 -226
  372. package/task-lib/name-generator.ts +11 -0
  373. package/task-lib/omp-session-cleanup.js +1 -1
  374. package/task-lib/omp-storage-root.js +8 -12
  375. package/task-lib/omp-storage-root.ts +62 -0
  376. package/task-lib/process-termination.js +143 -166
  377. package/task-lib/process-termination.ts +268 -0
@@ -1,264 +1,155 @@
1
- /**
2
- * AgentConfig - Agent configuration validation and defaults
3
- *
4
- * Provides:
5
- * - Config validation and normalization
6
- * - Default values for optional fields
7
- * - Model configuration setup
8
- * - Safety checks for test mode
9
- * - maxModel ceiling enforcement at config time
10
- */
11
-
12
- const { loadSettings, validateModelAgainstMax, VALID_MODELS } = require('../../lib/settings');
13
- const { applyValidatorQualityGateDefaults } = require('./agent-quality-gate-schema');
14
-
1
+ "use strict";
2
+ /** Agent configuration validation and defaults. */
3
+ const qualityGateSchema = require("./agent-quality-gate-schema");
4
+ const settingsFacade = require("./agent-config-settings");
15
5
  const VALID_LEVELS = ['level1', 'level2', 'level3'];
16
-
17
- // Default max iterations (high limit - let the user decide when to give up)
18
6
  const DEFAULT_MAX_ITERATIONS = 100;
19
-
20
- // Default timeout: 0 = no timeout (task runs until completion or explicit kill)
21
- // Use positive number for timeout in milliseconds
22
7
  const DEFAULT_TIMEOUT = 0;
23
-
24
- // Output-silence detection is opt-in because healthy provider operations may be quiet for
25
- // longer than the stale threshold. Explicit task timeouts remain independently supported.
26
- const DEFAULT_STALE_DURATION_MS = 30 * 60 * 1000; // 30 minutes before triggering analysis
8
+ const DEFAULT_STALE_DURATION_MS = 30 * 60 * 1000;
27
9
  const DEFAULT_LIVENESS_CHECK_ENABLED = false;
28
-
10
+ function isRecord(value) {
11
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
12
+ }
13
+ function isModelLevel(value) {
14
+ return value === 'level1' || value === 'level2' || value === 'level3';
15
+ }
16
+ const { loadSettings, validateModelAgainstMax, VALID_MODELS } = settingsFacade;
17
+ const { applyValidatorQualityGateDefaults } = qualityGateSchema;
29
18
  function applyOutputDefaults(config) {
30
- // CRITICAL: Enforce JSON schema output by default to prevent parse failures and crashes
31
- if (!config.outputFormat) {
32
- config.outputFormat = 'json';
33
- }
34
-
35
- // Map structuredOutput → jsonSchema (structuredOutput is the user-facing API name,
36
- // jsonSchema is the internal key used by task executor and CLI args).
37
- // Explicit jsonSchema takes precedence over structuredOutput.
38
- if (config.structuredOutput && !config.jsonSchema) {
39
- config.jsonSchema = config.structuredOutput;
40
- }
41
-
42
- // If outputFormat is json but no schema defined, use a minimal default schema
43
- if (config.outputFormat === 'json' && !config.jsonSchema) {
44
- config.jsonSchema = {
45
- type: 'object',
46
- properties: {
47
- summary: {
48
- type: 'string',
49
- description: 'Brief summary of what was done',
50
- },
51
- result: {
52
- type: 'string',
53
- description: 'Detailed result or output',
54
- },
55
- },
56
- required: ['summary', 'result'],
57
- };
58
- }
59
-
60
- applyValidatorQualityGateDefaults(config);
19
+ if (!config.outputFormat)
20
+ config.outputFormat = 'json';
21
+ if (config.structuredOutput && !config.jsonSchema)
22
+ config.jsonSchema = config.structuredOutput;
23
+ if (config.outputFormat === 'json' && !config.jsonSchema) {
24
+ config.jsonSchema = {
25
+ type: 'object',
26
+ properties: {
27
+ summary: { type: 'string', description: 'Brief summary of what was done' },
28
+ result: { type: 'string', description: 'Detailed result or output' },
29
+ },
30
+ required: ['summary', 'result'],
31
+ };
32
+ }
33
+ applyValidatorQualityGateDefaults(config);
61
34
  }
62
-
63
35
  function buildModelConfig(config) {
64
- if (config.modelRules) {
65
- return { type: 'rules', rules: config.modelRules };
66
- }
67
- return {
68
- type: 'static',
69
- model: config.model || null,
70
- modelLevel: config.modelLevel || null,
71
- };
36
+ if (config.modelRules)
37
+ return { type: 'rules', rules: config.modelRules };
38
+ return { type: 'static', model: config.model || null, modelLevel: config.modelLevel || null };
72
39
  }
73
-
74
40
  function applyStrictSchemaDefault(config, settings) {
75
- if (config.strictSchema === undefined) {
76
- config.strictSchema = settings.strictSchema !== false; // Default true if not set
77
- }
41
+ if (config.strictSchema === undefined)
42
+ config.strictSchema = settings.strictSchema !== false;
43
+ }
44
+ function errorMessage(error) {
45
+ return isRecord(error) ? error.message : undefined;
78
46
  }
79
-
80
47
  function validateStaticModelConfig(configId, modelConfig, maxModel, minModel) {
81
- if (modelConfig.model && VALID_MODELS.includes(modelConfig.model)) {
82
- try {
83
- validateModelAgainstMax(modelConfig.model, maxModel, minModel);
84
- } catch (error) {
85
- throw new Error(`Agent "${configId}": ${error.message}`);
48
+ if (modelConfig.model && VALID_MODELS.includes(modelConfig.model)) {
49
+ try {
50
+ validateModelAgainstMax(modelConfig.model, maxModel, minModel);
51
+ }
52
+ catch (error) {
53
+ throw new Error(`Agent "${configId}": ${String(errorMessage(error))}`);
54
+ }
55
+ }
56
+ if (modelConfig.modelLevel && !isModelLevel(modelConfig.modelLevel)) {
57
+ throw new Error(`Agent "${configId}": invalid modelLevel "${modelConfig.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`);
86
58
  }
87
- }
88
-
89
- if (modelConfig.modelLevel && !VALID_LEVELS.includes(modelConfig.modelLevel)) {
90
- throw new Error(
91
- `Agent "${configId}": invalid modelLevel "${modelConfig.modelLevel}". ` +
92
- `Valid: ${VALID_LEVELS.join(', ')}`
93
- );
94
- }
95
59
  }
96
-
97
60
  function validateModelRule(configId, rule, maxModel, minModel) {
98
- if (rule.model && VALID_MODELS.includes(rule.model)) {
99
- try {
100
- validateModelAgainstMax(rule.model, maxModel, minModel);
101
- } catch {
102
- throw new Error(
103
- `Agent "${configId}": modelRule "${rule.iterations}" requests "${rule.model}" ` +
104
- `but maxModel is "${maxModel}"${minModel ? ` and minModel is "${minModel}"` : ''}. ` +
105
- `Either adjust the rule's model or change maxModel/minModel settings.`
106
- );
61
+ if (rule.model && VALID_MODELS.includes(rule.model)) {
62
+ try {
63
+ validateModelAgainstMax(rule.model, maxModel, minModel);
64
+ }
65
+ catch {
66
+ throw new Error(`Agent "${configId}": modelRule "${String(rule.iterations)}" requests "${rule.model}" ` +
67
+ `but maxModel is "${maxModel}"${minModel ? ` and minModel is "${minModel}"` : ''}. ` +
68
+ `Either adjust the rule's model or change maxModel/minModel settings.`);
69
+ }
70
+ }
71
+ if (rule.modelLevel && !isModelLevel(rule.modelLevel)) {
72
+ throw new Error(`Agent "${configId}": modelRule "${String(rule.iterations)}" has invalid modelLevel ` +
73
+ `"${rule.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`);
107
74
  }
108
- }
109
-
110
- if (rule.modelLevel && !VALID_LEVELS.includes(rule.modelLevel)) {
111
- throw new Error(
112
- `Agent "${configId}": modelRule "${rule.iterations}" has invalid modelLevel ` +
113
- `"${rule.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`
114
- );
115
- }
116
75
  }
117
-
118
76
  function validateModelConfig(config, modelConfig, maxModel, minModel) {
119
- if (modelConfig.type === 'static') {
120
- validateStaticModelConfig(config.id, modelConfig, maxModel, minModel);
121
- return;
122
- }
123
-
124
- if (modelConfig.type === 'rules') {
125
- for (const rule of modelConfig.rules) {
126
- validateModelRule(config.id, rule, maxModel, minModel);
77
+ if (modelConfig.type === 'static') {
78
+ validateStaticModelConfig(config.id, modelConfig, maxModel, minModel);
79
+ }
80
+ else {
81
+ for (const rule of modelConfig.rules)
82
+ validateModelRule(config.id, rule, maxModel, minModel);
127
83
  }
128
- }
129
84
  }
130
-
131
85
  function buildInitialPromptRules(prompt) {
132
- if (prompt?.initial || prompt?.subsequent) {
86
+ if (!prompt.initial && !prompt.subsequent)
87
+ return null;
133
88
  const rules = [];
134
- if (prompt.initial) rules.push({ match: '1', system: prompt.initial });
135
- if (prompt.subsequent) rules.push({ match: '2+', system: prompt.subsequent });
89
+ if (prompt.initial)
90
+ rules.push({ match: '1', system: prompt.initial });
91
+ if (prompt.subsequent)
92
+ rules.push({ match: '2+', system: prompt.subsequent });
136
93
  return rules;
137
- }
138
-
139
- return null;
140
94
  }
141
-
142
95
  function buildPromptConfig(config) {
143
- const prompt = config.prompt;
144
- if (prompt?.iterations) {
145
- return { type: 'rules', rules: prompt.iterations };
146
- }
147
-
148
- const initialRules = buildInitialPromptRules(prompt);
149
- if (initialRules) {
150
- return { type: 'rules', rules: initialRules };
151
- }
152
-
153
- if (typeof prompt === 'string') {
154
- return { type: 'static', system: prompt };
155
- }
156
-
157
- if (prompt?.system) {
158
- return { type: 'static', system: prompt.system };
159
- }
160
-
161
- if (prompt) {
162
- throw new Error(`Agent "${config.id}": invalid prompt format`);
163
- }
164
-
165
- return null;
96
+ const prompt = config.prompt;
97
+ if (prompt && typeof prompt !== 'string' && prompt.iterations) {
98
+ return { type: 'rules', rules: prompt.iterations };
99
+ }
100
+ if (prompt && typeof prompt !== 'string') {
101
+ const initialRules = buildInitialPromptRules(prompt);
102
+ if (initialRules)
103
+ return { type: 'rules', rules: initialRules };
104
+ }
105
+ if (typeof prompt === 'string')
106
+ return { type: 'static', system: prompt };
107
+ if (prompt?.system)
108
+ return { type: 'static', system: prompt.system };
109
+ if (prompt)
110
+ throw new Error(`Agent "${config.id}": invalid prompt format`);
111
+ return null;
166
112
  }
167
-
168
113
  function normalizeTimeout(config) {
169
- if (config.timeout === undefined || config.timeout === null || config.timeout === '') {
170
- config.timeout = DEFAULT_TIMEOUT;
171
- } else {
172
- config.timeout = Number(config.timeout);
173
- }
174
-
175
- if (!Number.isFinite(config.timeout) || config.timeout < 0) {
176
- throw new Error(
177
- `Agent "${config.id}": timeout must be a non-negative number (got ${config.timeout}).`
178
- );
179
- }
180
-
181
- return config.timeout;
182
- }
183
-
184
- function buildNormalizedConfig(config, modelConfig, promptConfig) {
185
- return {
186
- ...config,
187
- modelConfig,
188
- promptConfig,
189
- maxIterations: config.maxIterations || DEFAULT_MAX_ITERATIONS,
190
- timeout: config.timeout,
191
- staleDuration: config.staleDuration || DEFAULT_STALE_DURATION_MS,
192
- enableLivenessCheck: config.enableLivenessCheck ?? DEFAULT_LIVENESS_CHECK_ENABLED,
193
- };
114
+ const timeout = config.timeout === undefined || config.timeout === null || config.timeout === ''
115
+ ? DEFAULT_TIMEOUT
116
+ : Number(config.timeout);
117
+ config.timeout = timeout;
118
+ if (!Number.isFinite(timeout) || timeout < 0) {
119
+ throw new Error(`Agent "${config.id}": timeout must be a non-negative number (got ${timeout}).`);
120
+ }
121
+ return timeout;
194
122
  }
195
-
196
123
  function assertTestModeSafety(config, options) {
197
- const executesTask = config.triggers?.some(
198
- (trigger) => !trigger.action || trigger.action === 'execute_task'
199
- );
200
- const hasMock = options.mockSpawnFn || options.taskRunner;
201
-
202
- if (options.testMode && !hasMock && executesTask) {
203
- throw new Error(
204
- `AgentWrapper: testMode=true but no mockSpawnFn/taskRunner provided for agent '${config.id}'. ` +
205
- `This would cause real Claude API calls. ABORTING.`
206
- );
207
- }
124
+ const executesTask = config.triggers?.some((trigger) => !trigger.action || trigger.action === 'execute_task');
125
+ if (options.testMode && !options.mockSpawnFn && !options.taskRunner && executesTask) {
126
+ throw new Error(`AgentWrapper: testMode=true but no mockSpawnFn/taskRunner provided for agent '${config.id}'. ` +
127
+ `This would cause real Claude API calls. ABORTING.`);
128
+ }
208
129
  }
209
-
210
- /**
211
- * Validate and normalize agent configuration
212
- * @param {Object} config - Raw agent configuration
213
- * @param {Object} options - Agent wrapper options
214
- * @returns {Object} Normalized configuration
215
- */
216
130
  function validateAgentConfig(config, options = {}) {
217
- applyOutputDefaults(config);
218
-
219
- // Model configuration: support both static model and dynamic rules
220
- // If no model specified, model is null - _selectModel() will use provider defaults
221
- const modelConfig = buildModelConfig(config);
222
-
223
- // COST CEILING/FLOOR ENFORCEMENT: Validate model(s) against maxModel and minModel at config time
224
- // Catches violations EARLY (config load) instead of at runtime (iteration N)
225
- const settings = loadSettings();
226
- const maxModel = settings.maxModel;
227
- const minModel = settings.minModel || null;
228
-
229
- // STRICT SCHEMA PROPAGATION: Issue #52 fix
230
- // If agent config doesn't explicitly set strictSchema, inherit from global settings
231
- // This allows `zeroshot settings set strictSchema false` to actually affect agents
232
- // Default behavior: strictSchema=true (reliable JSON output, no streaming)
233
- applyStrictSchemaDefault(config, settings);
234
- validateModelConfig(config, modelConfig, maxModel, minModel);
235
-
236
- // Prompt configuration: support static prompt OR iteration-based rules
237
- // Formats:
238
- // prompt: "string" -> static
239
- // prompt: { system: "string" } -> static
240
- // prompt: { initial: "...", subsequent: "..." } -> iteration 1 vs 2+
241
- // prompt: { iterations: [...] } -> full control
242
- const promptConfig = buildPromptConfig(config);
243
-
244
- // Default timeout to 0 (no timeout) if not specified
245
- // Use positive number for timeout in milliseconds
246
- // ROBUST: Handle undefined, null, AND string values from template resolution
247
- normalizeTimeout(config);
248
-
249
- // Build normalized config
250
- const normalizedConfig = buildNormalizedConfig(config, modelConfig, promptConfig);
251
-
252
- // SAFETY: In test mode, verify mock is provided for agents that execute tasks
253
- // Check if this agent executes tasks (vs orchestrator agents that only publish messages)
254
- assertTestModeSafety(config, options);
255
-
256
- return normalizedConfig;
131
+ applyOutputDefaults(config);
132
+ const modelConfig = buildModelConfig(config);
133
+ const settings = loadSettings();
134
+ const minModel = settings.minModel || null;
135
+ applyStrictSchemaDefault(config, settings);
136
+ validateModelConfig(config, modelConfig, settings.maxModel, minModel);
137
+ const promptConfig = buildPromptConfig(config);
138
+ const timeout = normalizeTimeout(config);
139
+ assertTestModeSafety(config, options);
140
+ return {
141
+ ...config,
142
+ modelConfig,
143
+ promptConfig,
144
+ maxIterations: config.maxIterations || DEFAULT_MAX_ITERATIONS,
145
+ timeout,
146
+ staleDuration: config.staleDuration || DEFAULT_STALE_DURATION_MS,
147
+ enableLivenessCheck: config.enableLivenessCheck ?? DEFAULT_LIVENESS_CHECK_ENABLED,
148
+ };
257
149
  }
258
-
259
150
  module.exports = {
260
- validateAgentConfig,
261
- DEFAULT_MAX_ITERATIONS,
262
- DEFAULT_STALE_DURATION_MS,
263
- DEFAULT_LIVENESS_CHECK_ENABLED,
151
+ validateAgentConfig,
152
+ DEFAULT_MAX_ITERATIONS,
153
+ DEFAULT_STALE_DURATION_MS,
154
+ DEFAULT_LIVENESS_CHECK_ENABLED,
264
155
  };
@@ -0,0 +1,285 @@
1
+ /** Agent configuration validation and defaults. */
2
+
3
+ import qualityGateSchema = require('./agent-quality-gate-schema');
4
+ import settingsFacade = require('./agent-config-settings');
5
+
6
+ type ModelLevel = 'level1' | 'level2' | 'level3';
7
+ type JsonSchemaType = 'array' | 'boolean' | 'integer' | 'number' | 'object' | 'string';
8
+
9
+ interface JsonSchema {
10
+ type?: JsonSchemaType;
11
+ description?: string;
12
+ enum?: string[];
13
+ items?: JsonSchema;
14
+ properties?: Record<string, JsonSchema>;
15
+ required?: string[];
16
+ anyOf?: JsonSchema[];
17
+ }
18
+
19
+ interface ModelRule extends Record<string, unknown> {
20
+ iterations?: unknown;
21
+ model?: string;
22
+ modelLevel?: string;
23
+ }
24
+
25
+ interface PromptRule extends Record<string, unknown> {}
26
+
27
+ interface PromptOptions extends Record<string, unknown> {
28
+ initial?: string;
29
+ subsequent?: string;
30
+ iterations?: PromptRule[];
31
+ system?: string;
32
+ }
33
+
34
+ interface AgentTrigger extends Record<string, unknown> {
35
+ action?: string;
36
+ }
37
+
38
+ interface AgentConfig extends Record<string, unknown> {
39
+ id: string;
40
+ outputFormat?: string;
41
+ structuredOutput?: JsonSchema;
42
+ jsonSchema?: JsonSchema;
43
+ modelRules?: ModelRule[];
44
+ model?: string;
45
+ modelLevel?: string;
46
+ strictSchema?: boolean;
47
+ prompt?: string | PromptOptions | null;
48
+ timeout?: number | string | null;
49
+ maxIterations?: number;
50
+ staleDuration?: number;
51
+ enableLivenessCheck?: boolean;
52
+ triggers?: AgentTrigger[];
53
+ role?: string;
54
+ requiredQualityGates?: unknown;
55
+ hooks?: {
56
+ onComplete?: {
57
+ config?: {
58
+ content?: {
59
+ data?: {
60
+ qualityGates?: unknown;
61
+ [key: string]: unknown;
62
+ };
63
+ };
64
+ };
65
+ };
66
+ };
67
+ }
68
+
69
+ interface AgentConfigOptions extends Record<string, unknown> {
70
+ mockSpawnFn?: unknown;
71
+ taskRunner?: unknown;
72
+ testMode?: boolean;
73
+ }
74
+
75
+ type SettingsRecord = ReturnType<typeof settingsFacade.loadSettings>;
76
+
77
+ interface StaticModelConfig {
78
+ type: 'static';
79
+ model: string | null;
80
+ modelLevel: string | null;
81
+ }
82
+
83
+ interface RulesModelConfig {
84
+ type: 'rules';
85
+ rules: ModelRule[];
86
+ }
87
+
88
+ type ModelConfig = StaticModelConfig | RulesModelConfig;
89
+ type PromptConfig =
90
+ | { type: 'static'; system: string }
91
+ | { type: 'rules'; rules: PromptRule[] }
92
+ | null;
93
+
94
+ type NormalizedAgentConfig = Omit<AgentConfig, 'timeout'> & {
95
+ modelConfig: ModelConfig;
96
+ promptConfig: PromptConfig;
97
+ maxIterations: number;
98
+ timeout: number;
99
+ staleDuration: number;
100
+ enableLivenessCheck: boolean;
101
+ };
102
+
103
+ const VALID_LEVELS: readonly ModelLevel[] = ['level1', 'level2', 'level3'];
104
+ const DEFAULT_MAX_ITERATIONS = 100;
105
+ const DEFAULT_TIMEOUT = 0;
106
+ const DEFAULT_STALE_DURATION_MS = 30 * 60 * 1000;
107
+ const DEFAULT_LIVENESS_CHECK_ENABLED = false;
108
+
109
+ function isRecord(value: unknown): value is Record<string, unknown> {
110
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
111
+ }
112
+
113
+ function isModelLevel(value: string): value is ModelLevel {
114
+ return value === 'level1' || value === 'level2' || value === 'level3';
115
+ }
116
+
117
+ const { loadSettings, validateModelAgainstMax, VALID_MODELS } = settingsFacade;
118
+ const { applyValidatorQualityGateDefaults } = qualityGateSchema;
119
+
120
+ function applyOutputDefaults(config: AgentConfig): void {
121
+ if (!config.outputFormat) config.outputFormat = 'json';
122
+ if (config.structuredOutput && !config.jsonSchema) config.jsonSchema = config.structuredOutput;
123
+ if (config.outputFormat === 'json' && !config.jsonSchema) {
124
+ config.jsonSchema = {
125
+ type: 'object',
126
+ properties: {
127
+ summary: { type: 'string', description: 'Brief summary of what was done' },
128
+ result: { type: 'string', description: 'Detailed result or output' },
129
+ },
130
+ required: ['summary', 'result'],
131
+ };
132
+ }
133
+ applyValidatorQualityGateDefaults(config);
134
+ }
135
+
136
+ function buildModelConfig(config: AgentConfig): ModelConfig {
137
+ if (config.modelRules) return { type: 'rules', rules: config.modelRules };
138
+ return { type: 'static', model: config.model || null, modelLevel: config.modelLevel || null };
139
+ }
140
+
141
+ function applyStrictSchemaDefault(config: AgentConfig, settings: SettingsRecord): void {
142
+ if (config.strictSchema === undefined) config.strictSchema = settings.strictSchema !== false;
143
+ }
144
+
145
+ function errorMessage(error: unknown): unknown {
146
+ return isRecord(error) ? error.message : undefined;
147
+ }
148
+
149
+ function validateStaticModelConfig(
150
+ configId: string,
151
+ modelConfig: StaticModelConfig,
152
+ maxModel: string,
153
+ minModel: string | null
154
+ ): void {
155
+ if (modelConfig.model && VALID_MODELS.includes(modelConfig.model)) {
156
+ try {
157
+ validateModelAgainstMax(modelConfig.model, maxModel, minModel);
158
+ } catch (error: unknown) {
159
+ throw new Error(`Agent "${configId}": ${String(errorMessage(error))}`);
160
+ }
161
+ }
162
+ if (modelConfig.modelLevel && !isModelLevel(modelConfig.modelLevel)) {
163
+ throw new Error(
164
+ `Agent "${configId}": invalid modelLevel "${modelConfig.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`
165
+ );
166
+ }
167
+ }
168
+
169
+ function validateModelRule(
170
+ configId: string,
171
+ rule: ModelRule,
172
+ maxModel: string,
173
+ minModel: string | null
174
+ ): void {
175
+ if (rule.model && VALID_MODELS.includes(rule.model)) {
176
+ try {
177
+ validateModelAgainstMax(rule.model, maxModel, minModel);
178
+ } catch {
179
+ throw new Error(
180
+ `Agent "${configId}": modelRule "${String(rule.iterations)}" requests "${rule.model}" ` +
181
+ `but maxModel is "${maxModel}"${minModel ? ` and minModel is "${minModel}"` : ''}. ` +
182
+ `Either adjust the rule's model or change maxModel/minModel settings.`
183
+ );
184
+ }
185
+ }
186
+ if (rule.modelLevel && !isModelLevel(rule.modelLevel)) {
187
+ throw new Error(
188
+ `Agent "${configId}": modelRule "${String(rule.iterations)}" has invalid modelLevel ` +
189
+ `"${rule.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`
190
+ );
191
+ }
192
+ }
193
+
194
+ function validateModelConfig(
195
+ config: AgentConfig,
196
+ modelConfig: ModelConfig,
197
+ maxModel: string,
198
+ minModel: string | null
199
+ ): void {
200
+ if (modelConfig.type === 'static') {
201
+ validateStaticModelConfig(config.id, modelConfig, maxModel, minModel);
202
+ } else {
203
+ for (const rule of modelConfig.rules) validateModelRule(config.id, rule, maxModel, minModel);
204
+ }
205
+ }
206
+
207
+ function buildInitialPromptRules(prompt: PromptOptions): PromptRule[] | null {
208
+ if (!prompt.initial && !prompt.subsequent) return null;
209
+ const rules: PromptRule[] = [];
210
+ if (prompt.initial) rules.push({ match: '1', system: prompt.initial });
211
+ if (prompt.subsequent) rules.push({ match: '2+', system: prompt.subsequent });
212
+ return rules;
213
+ }
214
+
215
+ function buildPromptConfig(config: AgentConfig): PromptConfig {
216
+ const prompt = config.prompt;
217
+ if (prompt && typeof prompt !== 'string' && prompt.iterations) {
218
+ return { type: 'rules', rules: prompt.iterations };
219
+ }
220
+ if (prompt && typeof prompt !== 'string') {
221
+ const initialRules = buildInitialPromptRules(prompt);
222
+ if (initialRules) return { type: 'rules', rules: initialRules };
223
+ }
224
+ if (typeof prompt === 'string') return { type: 'static', system: prompt };
225
+ if (prompt?.system) return { type: 'static', system: prompt.system };
226
+ if (prompt) throw new Error(`Agent "${config.id}": invalid prompt format`);
227
+ return null;
228
+ }
229
+
230
+ function normalizeTimeout(config: AgentConfig): number {
231
+ const timeout =
232
+ config.timeout === undefined || config.timeout === null || config.timeout === ''
233
+ ? DEFAULT_TIMEOUT
234
+ : Number(config.timeout);
235
+ config.timeout = timeout;
236
+ if (!Number.isFinite(timeout) || timeout < 0) {
237
+ throw new Error(
238
+ `Agent "${config.id}": timeout must be a non-negative number (got ${timeout}).`
239
+ );
240
+ }
241
+ return timeout;
242
+ }
243
+
244
+ function assertTestModeSafety(config: AgentConfig, options: AgentConfigOptions): void {
245
+ const executesTask = config.triggers?.some(
246
+ (trigger) => !trigger.action || trigger.action === 'execute_task'
247
+ );
248
+ if (options.testMode && !options.mockSpawnFn && !options.taskRunner && executesTask) {
249
+ throw new Error(
250
+ `AgentWrapper: testMode=true but no mockSpawnFn/taskRunner provided for agent '${config.id}'. ` +
251
+ `This would cause real Claude API calls. ABORTING.`
252
+ );
253
+ }
254
+ }
255
+
256
+ function validateAgentConfig(
257
+ config: AgentConfig,
258
+ options: AgentConfigOptions = {}
259
+ ): NormalizedAgentConfig {
260
+ applyOutputDefaults(config);
261
+ const modelConfig = buildModelConfig(config);
262
+ const settings = loadSettings();
263
+ const minModel = settings.minModel || null;
264
+ applyStrictSchemaDefault(config, settings);
265
+ validateModelConfig(config, modelConfig, settings.maxModel, minModel);
266
+ const promptConfig = buildPromptConfig(config);
267
+ const timeout = normalizeTimeout(config);
268
+ assertTestModeSafety(config, options);
269
+ return {
270
+ ...config,
271
+ modelConfig,
272
+ promptConfig,
273
+ maxIterations: config.maxIterations || DEFAULT_MAX_ITERATIONS,
274
+ timeout,
275
+ staleDuration: config.staleDuration || DEFAULT_STALE_DURATION_MS,
276
+ enableLivenessCheck: config.enableLivenessCheck ?? DEFAULT_LIVENESS_CHECK_ENABLED,
277
+ };
278
+ }
279
+
280
+ export = {
281
+ validateAgentConfig,
282
+ DEFAULT_MAX_ITERATIONS,
283
+ DEFAULT_STALE_DURATION_MS,
284
+ DEFAULT_LIVENESS_CHECK_ENABLED,
285
+ };