@the-open-engine/zeroshot 5.4.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 (295) hide show
  1. package/CHANGELOG.md +539 -0
  2. package/LICENSE +21 -0
  3. package/README.md +508 -0
  4. package/cli/commands/inspect-render.js +135 -0
  5. package/cli/commands/inspect.js +294 -0
  6. package/cli/commands/providers.js +149 -0
  7. package/cli/index.js +5431 -0
  8. package/cli/lib/first-run.js +211 -0
  9. package/cli/lib/update-checker.js +281 -0
  10. package/cli/message-formatter-utils.js +75 -0
  11. package/cli/message-formatters-normal.js +275 -0
  12. package/cli/message-formatters-watch.js +185 -0
  13. package/cluster-templates/base-templates/debug-workflow.json +422 -0
  14. package/cluster-templates/base-templates/full-workflow.json +727 -0
  15. package/cluster-templates/base-templates/heavy-validation.json +272 -0
  16. package/cluster-templates/base-templates/quick-validation.json +285 -0
  17. package/cluster-templates/base-templates/single-worker.json +71 -0
  18. package/cluster-templates/base-templates/worker-validator.json +230 -0
  19. package/cluster-templates/conductor-bootstrap.json +130 -0
  20. package/docker/zeroshot-cluster/Dockerfile +153 -0
  21. package/docker/zeroshot-cluster/pre-baked-deps.json +28 -0
  22. package/lib/agent-cli-provider/adapters/claude-parser.d.ts +3 -0
  23. package/lib/agent-cli-provider/adapters/claude-parser.d.ts.map +1 -0
  24. package/lib/agent-cli-provider/adapters/claude-parser.js +122 -0
  25. package/lib/agent-cli-provider/adapters/claude-parser.js.map +1 -0
  26. package/lib/agent-cli-provider/adapters/claude-recovery.d.ts +15 -0
  27. package/lib/agent-cli-provider/adapters/claude-recovery.d.ts.map +1 -0
  28. package/lib/agent-cli-provider/adapters/claude-recovery.js +165 -0
  29. package/lib/agent-cli-provider/adapters/claude-recovery.js.map +1 -0
  30. package/lib/agent-cli-provider/adapters/claude.d.ts +3 -0
  31. package/lib/agent-cli-provider/adapters/claude.d.ts.map +1 -0
  32. package/lib/agent-cli-provider/adapters/claude.js +181 -0
  33. package/lib/agent-cli-provider/adapters/claude.js.map +1 -0
  34. package/lib/agent-cli-provider/adapters/codex-parser.d.ts +3 -0
  35. package/lib/agent-cli-provider/adapters/codex-parser.d.ts.map +1 -0
  36. package/lib/agent-cli-provider/adapters/codex-parser.js +192 -0
  37. package/lib/agent-cli-provider/adapters/codex-parser.js.map +1 -0
  38. package/lib/agent-cli-provider/adapters/codex.d.ts +3 -0
  39. package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -0
  40. package/lib/agent-cli-provider/adapters/codex.js +151 -0
  41. package/lib/agent-cli-provider/adapters/codex.js.map +1 -0
  42. package/lib/agent-cli-provider/adapters/common.d.ts +28 -0
  43. package/lib/agent-cli-provider/adapters/common.d.ts.map +1 -0
  44. package/lib/agent-cli-provider/adapters/common.js +71 -0
  45. package/lib/agent-cli-provider/adapters/common.js.map +1 -0
  46. package/lib/agent-cli-provider/adapters/gemini.d.ts +3 -0
  47. package/lib/agent-cli-provider/adapters/gemini.d.ts.map +1 -0
  48. package/lib/agent-cli-provider/adapters/gemini.js +176 -0
  49. package/lib/agent-cli-provider/adapters/gemini.js.map +1 -0
  50. package/lib/agent-cli-provider/adapters/index.d.ts +9 -0
  51. package/lib/agent-cli-provider/adapters/index.d.ts.map +1 -0
  52. package/lib/agent-cli-provider/adapters/index.js +95 -0
  53. package/lib/agent-cli-provider/adapters/index.js.map +1 -0
  54. package/lib/agent-cli-provider/adapters/opencode.d.ts +3 -0
  55. package/lib/agent-cli-provider/adapters/opencode.d.ts.map +1 -0
  56. package/lib/agent-cli-provider/adapters/opencode.js +228 -0
  57. package/lib/agent-cli-provider/adapters/opencode.js.map +1 -0
  58. package/lib/agent-cli-provider/contract-actions.d.ts +5 -0
  59. package/lib/agent-cli-provider/contract-actions.d.ts.map +1 -0
  60. package/lib/agent-cli-provider/contract-actions.js +140 -0
  61. package/lib/agent-cli-provider/contract-actions.js.map +1 -0
  62. package/lib/agent-cli-provider/contract-env.d.ts +11 -0
  63. package/lib/agent-cli-provider/contract-env.d.ts.map +1 -0
  64. package/lib/agent-cli-provider/contract-env.js +113 -0
  65. package/lib/agent-cli-provider/contract-env.js.map +1 -0
  66. package/lib/agent-cli-provider/contract-envelope.d.ts +49 -0
  67. package/lib/agent-cli-provider/contract-envelope.d.ts.map +1 -0
  68. package/lib/agent-cli-provider/contract-envelope.js +52 -0
  69. package/lib/agent-cli-provider/contract-envelope.js.map +1 -0
  70. package/lib/agent-cli-provider/contract-errors.d.ts +22 -0
  71. package/lib/agent-cli-provider/contract-errors.d.ts.map +1 -0
  72. package/lib/agent-cli-provider/contract-errors.js +71 -0
  73. package/lib/agent-cli-provider/contract-errors.js.map +1 -0
  74. package/lib/agent-cli-provider/contract-fallback.d.ts +7 -0
  75. package/lib/agent-cli-provider/contract-fallback.d.ts.map +1 -0
  76. package/lib/agent-cli-provider/contract-fallback.js +102 -0
  77. package/lib/agent-cli-provider/contract-fallback.js.map +1 -0
  78. package/lib/agent-cli-provider/contract-invoke.d.ts +5 -0
  79. package/lib/agent-cli-provider/contract-invoke.d.ts.map +1 -0
  80. package/lib/agent-cli-provider/contract-invoke.js +89 -0
  81. package/lib/agent-cli-provider/contract-invoke.js.map +1 -0
  82. package/lib/agent-cli-provider/contract-options.d.ts +3 -0
  83. package/lib/agent-cli-provider/contract-options.d.ts.map +1 -0
  84. package/lib/agent-cli-provider/contract-options.js +140 -0
  85. package/lib/agent-cli-provider/contract-options.js.map +1 -0
  86. package/lib/agent-cli-provider/contract-parse.d.ts +15 -0
  87. package/lib/agent-cli-provider/contract-parse.d.ts.map +1 -0
  88. package/lib/agent-cli-provider/contract-parse.js +81 -0
  89. package/lib/agent-cli-provider/contract-parse.js.map +1 -0
  90. package/lib/agent-cli-provider/contract-support.d.ts +18 -0
  91. package/lib/agent-cli-provider/contract-support.d.ts.map +1 -0
  92. package/lib/agent-cli-provider/contract-support.js +154 -0
  93. package/lib/agent-cli-provider/contract-support.js.map +1 -0
  94. package/lib/agent-cli-provider/contract.d.ts +13 -0
  95. package/lib/agent-cli-provider/contract.d.ts.map +1 -0
  96. package/lib/agent-cli-provider/contract.js +30 -0
  97. package/lib/agent-cli-provider/contract.js.map +1 -0
  98. package/lib/agent-cli-provider/env-safety.d.ts +11 -0
  99. package/lib/agent-cli-provider/env-safety.d.ts.map +1 -0
  100. package/lib/agent-cli-provider/env-safety.js +83 -0
  101. package/lib/agent-cli-provider/env-safety.js.map +1 -0
  102. package/lib/agent-cli-provider/errors.d.ts +5 -0
  103. package/lib/agent-cli-provider/errors.d.ts.map +1 -0
  104. package/lib/agent-cli-provider/errors.js +115 -0
  105. package/lib/agent-cli-provider/errors.js.map +1 -0
  106. package/lib/agent-cli-provider/executable.d.ts +3 -0
  107. package/lib/agent-cli-provider/executable.d.ts.map +1 -0
  108. package/lib/agent-cli-provider/executable.js +24 -0
  109. package/lib/agent-cli-provider/executable.js.map +1 -0
  110. package/lib/agent-cli-provider/index.d.ts +8 -0
  111. package/lib/agent-cli-provider/index.d.ts.map +1 -0
  112. package/lib/agent-cli-provider/index.js +31 -0
  113. package/lib/agent-cli-provider/index.js.map +1 -0
  114. package/lib/agent-cli-provider/invoke-evidence.d.ts +4 -0
  115. package/lib/agent-cli-provider/invoke-evidence.d.ts.map +1 -0
  116. package/lib/agent-cli-provider/invoke-evidence.js +17 -0
  117. package/lib/agent-cli-provider/invoke-evidence.js.map +1 -0
  118. package/lib/agent-cli-provider/json.d.ts +16 -0
  119. package/lib/agent-cli-provider/json.d.ts.map +1 -0
  120. package/lib/agent-cli-provider/json.js +110 -0
  121. package/lib/agent-cli-provider/json.js.map +1 -0
  122. package/lib/agent-cli-provider/log-prefix.d.ts +2 -0
  123. package/lib/agent-cli-provider/log-prefix.d.ts.map +1 -0
  124. package/lib/agent-cli-provider/log-prefix.js +22 -0
  125. package/lib/agent-cli-provider/log-prefix.js.map +1 -0
  126. package/lib/agent-cli-provider/process-runner.d.ts +17 -0
  127. package/lib/agent-cli-provider/process-runner.d.ts.map +1 -0
  128. package/lib/agent-cli-provider/process-runner.js +89 -0
  129. package/lib/agent-cli-provider/process-runner.js.map +1 -0
  130. package/lib/agent-cli-provider/redaction.d.ts +9 -0
  131. package/lib/agent-cli-provider/redaction.d.ts.map +1 -0
  132. package/lib/agent-cli-provider/redaction.js +227 -0
  133. package/lib/agent-cli-provider/redaction.js.map +1 -0
  134. package/lib/agent-cli-provider/schema.d.ts +5 -0
  135. package/lib/agent-cli-provider/schema.d.ts.map +1 -0
  136. package/lib/agent-cli-provider/schema.js +136 -0
  137. package/lib/agent-cli-provider/schema.js.map +1 -0
  138. package/lib/agent-cli-provider/single-agent-runtime.d.ts +15 -0
  139. package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -0
  140. package/lib/agent-cli-provider/single-agent-runtime.js +228 -0
  141. package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -0
  142. package/lib/agent-cli-provider/types.d.ts +194 -0
  143. package/lib/agent-cli-provider/types.d.ts.map +1 -0
  144. package/lib/agent-cli-provider/types.js +12 -0
  145. package/lib/agent-cli-provider/types.js.map +1 -0
  146. package/lib/completion.js +174 -0
  147. package/lib/detached-startup.js +220 -0
  148. package/lib/docker-config.js +220 -0
  149. package/lib/git-remote-utils.js +165 -0
  150. package/lib/id-detector.js +55 -0
  151. package/lib/provider-defaults.js +62 -0
  152. package/lib/provider-detection.js +59 -0
  153. package/lib/provider-names.js +57 -0
  154. package/lib/repo-settings.js +69 -0
  155. package/lib/settings/claude-auth.js +78 -0
  156. package/lib/settings.js +542 -0
  157. package/lib/start-cluster.js +321 -0
  158. package/lib/stream-json-parser.js +67 -0
  159. package/package.json +162 -0
  160. package/scripts/fix-node-pty-permissions.js +75 -0
  161. package/scripts/record-demo.sh +279 -0
  162. package/scripts/setup-merge-queue.sh +170 -0
  163. package/scripts/test-install.sh +40 -0
  164. package/scripts/validate-templates.js +107 -0
  165. package/src/agent/agent-config.js +266 -0
  166. package/src/agent/agent-context-builder.js +189 -0
  167. package/src/agent/agent-context-sections.js +338 -0
  168. package/src/agent/agent-context-sources.js +147 -0
  169. package/src/agent/agent-hook-executor.js +721 -0
  170. package/src/agent/agent-input-injector.js +141 -0
  171. package/src/agent/agent-lifecycle.js +982 -0
  172. package/src/agent/agent-quality-gate-schema.js +93 -0
  173. package/src/agent/agent-quality-gates-context.js +51 -0
  174. package/src/agent/agent-stuck-detector.js +256 -0
  175. package/src/agent/agent-task-executor.js +2028 -0
  176. package/src/agent/agent-trigger-evaluator.js +67 -0
  177. package/src/agent/context-metrics.js +160 -0
  178. package/src/agent/context-pack-builder.js +367 -0
  179. package/src/agent/context-replay-policy.js +51 -0
  180. package/src/agent/guidance-queue.js +77 -0
  181. package/src/agent/output-extraction.js +367 -0
  182. package/src/agent/output-reformatter.js +175 -0
  183. package/src/agent/pr-verification.js +653 -0
  184. package/src/agent/rate-limit-backoff.js +82 -0
  185. package/src/agent/schema-utils.js +146 -0
  186. package/src/agent/validation-platform.js +35 -0
  187. package/src/agent-cli-provider/adapters/claude-parser.ts +133 -0
  188. package/src/agent-cli-provider/adapters/claude-recovery.ts +203 -0
  189. package/src/agent-cli-provider/adapters/claude.ts +247 -0
  190. package/src/agent-cli-provider/adapters/codex-parser.ts +211 -0
  191. package/src/agent-cli-provider/adapters/codex.ts +217 -0
  192. package/src/agent-cli-provider/adapters/common.ts +124 -0
  193. package/src/agent-cli-provider/adapters/gemini.ts +243 -0
  194. package/src/agent-cli-provider/adapters/index.ts +126 -0
  195. package/src/agent-cli-provider/adapters/opencode.ts +286 -0
  196. package/src/agent-cli-provider/contract-actions.ts +150 -0
  197. package/src/agent-cli-provider/contract-env.ts +111 -0
  198. package/src/agent-cli-provider/contract-envelope.ts +110 -0
  199. package/src/agent-cli-provider/contract-errors.ts +66 -0
  200. package/src/agent-cli-provider/contract-fallback.ts +121 -0
  201. package/src/agent-cli-provider/contract-invoke.ts +104 -0
  202. package/src/agent-cli-provider/contract-options.ts +173 -0
  203. package/src/agent-cli-provider/contract-parse.ts +94 -0
  204. package/src/agent-cli-provider/contract-support.ts +167 -0
  205. package/src/agent-cli-provider/contract.ts +56 -0
  206. package/src/agent-cli-provider/env-safety.ts +82 -0
  207. package/src/agent-cli-provider/errors.ts +122 -0
  208. package/src/agent-cli-provider/executable.ts +24 -0
  209. package/src/agent-cli-provider/index.ts +83 -0
  210. package/src/agent-cli-provider/invoke-evidence.ts +18 -0
  211. package/src/agent-cli-provider/json.ts +114 -0
  212. package/src/agent-cli-provider/log-prefix.ts +20 -0
  213. package/src/agent-cli-provider/process-runner.ts +145 -0
  214. package/src/agent-cli-provider/redaction.ts +282 -0
  215. package/src/agent-cli-provider/schema.ts +115 -0
  216. package/src/agent-cli-provider/single-agent-runtime.ts +311 -0
  217. package/src/agent-cli-provider/types.ts +237 -0
  218. package/src/agent-wrapper.js +615 -0
  219. package/src/agents/git-pusher-template.js +705 -0
  220. package/src/attach/attach-client.js +438 -0
  221. package/src/attach/attach-server.js +543 -0
  222. package/src/attach/index.js +37 -0
  223. package/src/attach/protocol.js +220 -0
  224. package/src/attach/ring-buffer.js +121 -0
  225. package/src/attach/send-input.js +88 -0
  226. package/src/attach/socket-discovery.js +267 -0
  227. package/src/claude-task-runner.js +661 -0
  228. package/src/config-router.js +89 -0
  229. package/src/config-validator.js +2202 -0
  230. package/src/copy-worker.js +43 -0
  231. package/src/guidance-topics.js +10 -0
  232. package/src/input-helpers.js +65 -0
  233. package/src/isolation-manager.js +1734 -0
  234. package/src/issue-providers/README.md +305 -0
  235. package/src/issue-providers/azure-devops-provider.js +307 -0
  236. package/src/issue-providers/base-provider.js +232 -0
  237. package/src/issue-providers/github-provider.js +210 -0
  238. package/src/issue-providers/gitlab-provider.js +262 -0
  239. package/src/issue-providers/index.js +196 -0
  240. package/src/issue-providers/jira-provider.js +260 -0
  241. package/src/ledger.js +692 -0
  242. package/src/lib/gc.js +232 -0
  243. package/src/lib/safe-exec.js +88 -0
  244. package/src/logic-engine.js +201 -0
  245. package/src/message-buffer.js +81 -0
  246. package/src/message-bus-bridge.js +144 -0
  247. package/src/message-bus.js +256 -0
  248. package/src/name-generator.js +232 -0
  249. package/src/orchestrator.js +3924 -0
  250. package/src/preflight.js +712 -0
  251. package/src/process-metrics.js +608 -0
  252. package/src/providers/anthropic/index.js +3 -0
  253. package/src/providers/base-provider.js +355 -0
  254. package/src/providers/capabilities.js +60 -0
  255. package/src/providers/google/index.js +3 -0
  256. package/src/providers/index.js +293 -0
  257. package/src/providers/openai/index.js +3 -0
  258. package/src/providers/opencode/index.js +3 -0
  259. package/src/quality-gates.js +143 -0
  260. package/src/schemas/sub-cluster.js +208 -0
  261. package/src/state-snapshot.js +398 -0
  262. package/src/state-snapshotter.js +142 -0
  263. package/src/status-footer.js +1026 -0
  264. package/src/sub-cluster-wrapper.js +693 -0
  265. package/src/task-runner.js +30 -0
  266. package/src/template-resolver.js +425 -0
  267. package/src/template-validation/index.js +338 -0
  268. package/src/template-validation/simulate-consensus-gates.js +324 -0
  269. package/src/template-validation/simulate-random-topology.js +541 -0
  270. package/src/template-validation/simulate-two-stage-validation.js +270 -0
  271. package/src/worktree-claude-config.js +135 -0
  272. package/src/worktree-tooling-env.js +150 -0
  273. package/task-lib/attachable-watcher.js +381 -0
  274. package/task-lib/commands/clean.js +50 -0
  275. package/task-lib/commands/episodes.js +105 -0
  276. package/task-lib/commands/get-log-path.js +23 -0
  277. package/task-lib/commands/kill.js +32 -0
  278. package/task-lib/commands/list.js +105 -0
  279. package/task-lib/commands/logs.js +439 -0
  280. package/task-lib/commands/resume.js +42 -0
  281. package/task-lib/commands/run.js +57 -0
  282. package/task-lib/commands/schedule.js +105 -0
  283. package/task-lib/commands/scheduler-cmd.js +96 -0
  284. package/task-lib/commands/schedules.js +148 -0
  285. package/task-lib/commands/status.js +44 -0
  286. package/task-lib/commands/unschedule.js +16 -0
  287. package/task-lib/completion.js +9 -0
  288. package/task-lib/config.js +11 -0
  289. package/task-lib/name-generator.js +230 -0
  290. package/task-lib/package.json +3 -0
  291. package/task-lib/provider-helper-runtime.js +29 -0
  292. package/task-lib/runner.js +190 -0
  293. package/task-lib/scheduler.js +252 -0
  294. package/task-lib/store.js +529 -0
  295. package/task-lib/watcher.js +305 -0
@@ -0,0 +1,266 @@
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
+
15
+ const VALID_LEVELS = ['level1', 'level2', 'level3'];
16
+
17
+ // Default max iterations (high limit - let the user decide when to give up)
18
+ 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
+ const DEFAULT_TIMEOUT = 0;
23
+
24
+ // Stale detection - ENABLED by default using multi-indicator analysis (safe from false positives)
25
+ // Multi-indicator approach checks: process state, CPU usage, context switches, network I/O
26
+ // Only flags as stuck when ALL indicators show inactivity (score >= 3.5)
27
+ // Single-indicator detection (just output freshness) was too risky - this is safe.
28
+ const DEFAULT_STALE_DURATION_MS = 30 * 60 * 1000; // 30 minutes before triggering analysis
29
+ const DEFAULT_LIVENESS_CHECK_ENABLED = true; // Safe with multi-indicator detection
30
+
31
+ function applyOutputDefaults(config) {
32
+ // CRITICAL: Enforce JSON schema output by default to prevent parse failures and crashes
33
+ if (!config.outputFormat) {
34
+ config.outputFormat = 'json';
35
+ }
36
+
37
+ // Map structuredOutput → jsonSchema (structuredOutput is the user-facing API name,
38
+ // jsonSchema is the internal key used by task executor and CLI args).
39
+ // Explicit jsonSchema takes precedence over structuredOutput.
40
+ if (config.structuredOutput && !config.jsonSchema) {
41
+ config.jsonSchema = config.structuredOutput;
42
+ }
43
+
44
+ // If outputFormat is json but no schema defined, use a minimal default schema
45
+ if (config.outputFormat === 'json' && !config.jsonSchema) {
46
+ config.jsonSchema = {
47
+ type: 'object',
48
+ properties: {
49
+ summary: {
50
+ type: 'string',
51
+ description: 'Brief summary of what was done',
52
+ },
53
+ result: {
54
+ type: 'string',
55
+ description: 'Detailed result or output',
56
+ },
57
+ },
58
+ required: ['summary', 'result'],
59
+ };
60
+ }
61
+
62
+ applyValidatorQualityGateDefaults(config);
63
+ }
64
+
65
+ function buildModelConfig(config) {
66
+ if (config.modelRules) {
67
+ return { type: 'rules', rules: config.modelRules };
68
+ }
69
+ return {
70
+ type: 'static',
71
+ model: config.model || null,
72
+ modelLevel: config.modelLevel || null,
73
+ };
74
+ }
75
+
76
+ function applyStrictSchemaDefault(config, settings) {
77
+ if (config.strictSchema === undefined) {
78
+ config.strictSchema = settings.strictSchema !== false; // Default true if not set
79
+ }
80
+ }
81
+
82
+ function validateStaticModelConfig(configId, modelConfig, maxModel, minModel) {
83
+ if (modelConfig.model && VALID_MODELS.includes(modelConfig.model)) {
84
+ try {
85
+ validateModelAgainstMax(modelConfig.model, maxModel, minModel);
86
+ } catch (error) {
87
+ throw new Error(`Agent "${configId}": ${error.message}`);
88
+ }
89
+ }
90
+
91
+ if (modelConfig.modelLevel && !VALID_LEVELS.includes(modelConfig.modelLevel)) {
92
+ throw new Error(
93
+ `Agent "${configId}": invalid modelLevel "${modelConfig.modelLevel}". ` +
94
+ `Valid: ${VALID_LEVELS.join(', ')}`
95
+ );
96
+ }
97
+ }
98
+
99
+ function validateModelRule(configId, rule, maxModel, minModel) {
100
+ if (rule.model && VALID_MODELS.includes(rule.model)) {
101
+ try {
102
+ validateModelAgainstMax(rule.model, maxModel, minModel);
103
+ } catch {
104
+ throw new Error(
105
+ `Agent "${configId}": modelRule "${rule.iterations}" requests "${rule.model}" ` +
106
+ `but maxModel is "${maxModel}"${minModel ? ` and minModel is "${minModel}"` : ''}. ` +
107
+ `Either adjust the rule's model or change maxModel/minModel settings.`
108
+ );
109
+ }
110
+ }
111
+
112
+ if (rule.modelLevel && !VALID_LEVELS.includes(rule.modelLevel)) {
113
+ throw new Error(
114
+ `Agent "${configId}": modelRule "${rule.iterations}" has invalid modelLevel ` +
115
+ `"${rule.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`
116
+ );
117
+ }
118
+ }
119
+
120
+ function validateModelConfig(config, modelConfig, maxModel, minModel) {
121
+ if (modelConfig.type === 'static') {
122
+ validateStaticModelConfig(config.id, modelConfig, maxModel, minModel);
123
+ return;
124
+ }
125
+
126
+ if (modelConfig.type === 'rules') {
127
+ for (const rule of modelConfig.rules) {
128
+ validateModelRule(config.id, rule, maxModel, minModel);
129
+ }
130
+ }
131
+ }
132
+
133
+ function buildInitialPromptRules(prompt) {
134
+ if (prompt?.initial || prompt?.subsequent) {
135
+ const rules = [];
136
+ if (prompt.initial) rules.push({ match: '1', system: prompt.initial });
137
+ if (prompt.subsequent) rules.push({ match: '2+', system: prompt.subsequent });
138
+ return rules;
139
+ }
140
+
141
+ return null;
142
+ }
143
+
144
+ function buildPromptConfig(config) {
145
+ const prompt = config.prompt;
146
+ if (prompt?.iterations) {
147
+ return { type: 'rules', rules: prompt.iterations };
148
+ }
149
+
150
+ const initialRules = buildInitialPromptRules(prompt);
151
+ if (initialRules) {
152
+ return { type: 'rules', rules: initialRules };
153
+ }
154
+
155
+ if (typeof prompt === 'string') {
156
+ return { type: 'static', system: prompt };
157
+ }
158
+
159
+ if (prompt?.system) {
160
+ return { type: 'static', system: prompt.system };
161
+ }
162
+
163
+ if (prompt) {
164
+ throw new Error(`Agent "${config.id}": invalid prompt format`);
165
+ }
166
+
167
+ return null;
168
+ }
169
+
170
+ function normalizeTimeout(config) {
171
+ if (config.timeout === undefined || config.timeout === null || config.timeout === '') {
172
+ config.timeout = DEFAULT_TIMEOUT;
173
+ } else {
174
+ config.timeout = Number(config.timeout);
175
+ }
176
+
177
+ if (!Number.isFinite(config.timeout) || config.timeout < 0) {
178
+ throw new Error(
179
+ `Agent "${config.id}": timeout must be a non-negative number (got ${config.timeout}).`
180
+ );
181
+ }
182
+
183
+ return config.timeout;
184
+ }
185
+
186
+ function buildNormalizedConfig(config, modelConfig, promptConfig) {
187
+ return {
188
+ ...config,
189
+ modelConfig,
190
+ promptConfig,
191
+ maxIterations: config.maxIterations || DEFAULT_MAX_ITERATIONS,
192
+ timeout: config.timeout,
193
+ staleDuration: config.staleDuration || DEFAULT_STALE_DURATION_MS,
194
+ enableLivenessCheck: config.enableLivenessCheck ?? DEFAULT_LIVENESS_CHECK_ENABLED,
195
+ };
196
+ }
197
+
198
+ function assertTestModeSafety(config, options) {
199
+ const executesTask = config.triggers?.some(
200
+ (trigger) => !trigger.action || trigger.action === 'execute_task'
201
+ );
202
+ const hasMock = options.mockSpawnFn || options.taskRunner;
203
+
204
+ if (options.testMode && !hasMock && executesTask) {
205
+ throw new Error(
206
+ `AgentWrapper: testMode=true but no mockSpawnFn/taskRunner provided for agent '${config.id}'. ` +
207
+ `This would cause real Claude API calls. ABORTING.`
208
+ );
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Validate and normalize agent configuration
214
+ * @param {Object} config - Raw agent configuration
215
+ * @param {Object} options - Agent wrapper options
216
+ * @returns {Object} Normalized configuration
217
+ */
218
+ function validateAgentConfig(config, options = {}) {
219
+ applyOutputDefaults(config);
220
+
221
+ // Model configuration: support both static model and dynamic rules
222
+ // If no model specified, model is null - _selectModel() will use provider defaults
223
+ const modelConfig = buildModelConfig(config);
224
+
225
+ // COST CEILING/FLOOR ENFORCEMENT: Validate model(s) against maxModel and minModel at config time
226
+ // Catches violations EARLY (config load) instead of at runtime (iteration N)
227
+ const settings = loadSettings();
228
+ const maxModel = settings.maxModel;
229
+ const minModel = settings.minModel || null;
230
+
231
+ // STRICT SCHEMA PROPAGATION: Issue #52 fix
232
+ // If agent config doesn't explicitly set strictSchema, inherit from global settings
233
+ // This allows `zeroshot settings set strictSchema false` to actually affect agents
234
+ // Default behavior: strictSchema=true (reliable JSON output, no streaming)
235
+ applyStrictSchemaDefault(config, settings);
236
+ validateModelConfig(config, modelConfig, maxModel, minModel);
237
+
238
+ // Prompt configuration: support static prompt OR iteration-based rules
239
+ // Formats:
240
+ // prompt: "string" -> static
241
+ // prompt: { system: "string" } -> static
242
+ // prompt: { initial: "...", subsequent: "..." } -> iteration 1 vs 2+
243
+ // prompt: { iterations: [...] } -> full control
244
+ const promptConfig = buildPromptConfig(config);
245
+
246
+ // Default timeout to 0 (no timeout) if not specified
247
+ // Use positive number for timeout in milliseconds
248
+ // ROBUST: Handle undefined, null, AND string values from template resolution
249
+ normalizeTimeout(config);
250
+
251
+ // Build normalized config
252
+ const normalizedConfig = buildNormalizedConfig(config, modelConfig, promptConfig);
253
+
254
+ // SAFETY: In test mode, verify mock is provided for agents that execute tasks
255
+ // Check if this agent executes tasks (vs orchestrator agents that only publish messages)
256
+ assertTestModeSafety(config, options);
257
+
258
+ return normalizedConfig;
259
+ }
260
+
261
+ module.exports = {
262
+ validateAgentConfig,
263
+ DEFAULT_MAX_ITERATIONS,
264
+ DEFAULT_STALE_DURATION_MS,
265
+ DEFAULT_LIVENESS_CHECK_ENABLED,
266
+ };
@@ -0,0 +1,189 @@
1
+ /**
2
+ * AgentContextBuilder - Build agent execution context from ledger
3
+ *
4
+ * Provides:
5
+ * - Context assembly from multiple message sources
6
+ * - Context strategy evaluation (topics, limits, since timestamps)
7
+ * - Prompt injection and formatting
8
+ * - Token-budgeted context packs
9
+ * - Defensive context overflow prevention
10
+ */
11
+
12
+ // Defensive limit: 500,000 chars ≈ 125k tokens (safe buffer below 200k limit)
13
+ // Prevents "Prompt is too long" errors that kill tasks
14
+ const MAX_CONTEXT_CHARS = 500000;
15
+ const {
16
+ buildContextMetrics,
17
+ emitContextMetrics,
18
+ resolveLegacyMaxTokens,
19
+ updateTotalMetrics,
20
+ } = require('./context-metrics');
21
+ const { buildContextPacks } = require('./context-pack-builder');
22
+ const { buildSourcePack } = require('./agent-context-sources');
23
+ const {
24
+ buildHeaderContext,
25
+ buildInstructionsSection,
26
+ buildJsonSchemaSection,
27
+ buildLegacyOutputSchemaSection,
28
+ buildRepoToolingSection,
29
+ buildTriggeringMessageSection,
30
+ buildValidatorSkipSection,
31
+ } = require('./agent-context-sections');
32
+ const { buildRequiredQualityGatesSection } = require('./agent-quality-gates-context');
33
+
34
+ function pushStaticPack({ packs, packId, section, text, order, options = {} }) {
35
+ if (!text) {
36
+ return order;
37
+ }
38
+
39
+ packs.push({
40
+ id: packId,
41
+ section,
42
+ priority: 'required',
43
+ order,
44
+ preserve: options.preserve || false,
45
+ render: () => text,
46
+ });
47
+
48
+ return order + 1;
49
+ }
50
+
51
+ function appendSourcePacks(packs, strategy, params, startingOrder) {
52
+ if (!Array.isArray(strategy.sources)) {
53
+ return startingOrder;
54
+ }
55
+
56
+ let order = startingOrder;
57
+ strategy.sources.forEach((source, index) => {
58
+ packs.push({ ...buildSourcePack({ source, index, ...params }), order });
59
+ order += 1;
60
+ });
61
+
62
+ return order;
63
+ }
64
+
65
+ function buildStaticSections(params) {
66
+ const {
67
+ id,
68
+ role,
69
+ iteration,
70
+ config,
71
+ selectedPrompt,
72
+ queuedGuidance,
73
+ messageBus,
74
+ cluster,
75
+ triggeringMessage,
76
+ worktree,
77
+ isolation,
78
+ } = params;
79
+ const isIsolated = !!(worktree?.enabled || isolation?.enabled);
80
+
81
+ return {
82
+ header: buildHeaderContext({ id, role, iteration, isIsolated }),
83
+ instructions: buildInstructionsSection({ config, selectedPrompt, id }),
84
+ repoTooling: buildRepoToolingSection({ config, worktree }),
85
+ legacyOutputSchema: buildLegacyOutputSchemaSection(config),
86
+ queuedGuidance: queuedGuidance || '',
87
+ requiredQualityGates: buildRequiredQualityGatesSection(config),
88
+ jsonSchema: buildJsonSchemaSection(config),
89
+ validatorSkip: buildValidatorSkipSection({ role, messageBus, cluster, isolation }),
90
+ triggeringMessage: buildTriggeringMessageSection(triggeringMessage),
91
+ };
92
+ }
93
+
94
+ function buildPacks(params) {
95
+ const { strategy, messageBus, cluster, lastTaskEndTime, lastAgentStartTime } = params;
96
+ const sections = buildStaticSections(params);
97
+ const packs = [];
98
+ let order = 0;
99
+ const staticPackIds = [
100
+ 'header',
101
+ 'instructions',
102
+ 'repoTooling',
103
+ 'queuedGuidance',
104
+ 'legacyOutputSchema',
105
+ 'requiredQualityGates',
106
+ 'jsonSchema',
107
+ ];
108
+
109
+ for (const packId of staticPackIds) {
110
+ order = pushStaticPack({ packs, packId, section: packId, text: sections[packId], order });
111
+ }
112
+
113
+ order = appendSourcePacks(
114
+ packs,
115
+ strategy,
116
+ { messageBus, cluster, lastTaskEndTime, lastAgentStartTime },
117
+ order
118
+ );
119
+ order = pushStaticPack({
120
+ packs,
121
+ packId: 'validatorSkip',
122
+ section: 'validatorSkip',
123
+ text: sections.validatorSkip,
124
+ order,
125
+ });
126
+ pushStaticPack({
127
+ packs,
128
+ packId: 'triggeringMessage',
129
+ section: 'triggeringMessage',
130
+ text: sections.triggeringMessage,
131
+ order,
132
+ options: { preserve: true },
133
+ });
134
+
135
+ return packs;
136
+ }
137
+
138
+ /**
139
+ * Build execution context for an agent
140
+ * @param {object} params - Context building parameters
141
+ * @param {string} params.id - Agent ID
142
+ * @param {string} params.role - Agent role
143
+ * @param {number} params.iteration - Current iteration number
144
+ * @param {any} params.config - Agent configuration
145
+ * @param {any} params.messageBus - Message bus for querying ledger
146
+ * @param {any} params.cluster - Cluster object
147
+ * @param {number} [params.lastTaskEndTime] - Timestamp of last task completion
148
+ * @param {number} [params.lastAgentStartTime] - Timestamp when this agent last started work
149
+ * @param {any} params.triggeringMessage - Message that triggered this execution
150
+ * @param {string} [params.selectedPrompt] - Pre-selected prompt from _selectPrompt() (iteration-based)
151
+ * @param {object} [params.worktree] - Worktree isolation state (if running in worktree mode)
152
+ * @param {object} [params.isolation] - Docker isolation state (if running in Docker mode)
153
+ * @returns {string} Assembled context string
154
+ */
155
+ function buildContext(params) {
156
+ const strategy = params.config.contextStrategy || { sources: [] };
157
+ const packs = buildPacks({ ...params, strategy });
158
+ const maxTokens = resolveLegacyMaxTokens(strategy);
159
+ const packResult = buildContextPacks({
160
+ packs,
161
+ maxTokens,
162
+ maxChars: MAX_CONTEXT_CHARS,
163
+ });
164
+
165
+ const metrics = buildContextMetrics({
166
+ clusterId: params.cluster.id,
167
+ agentId: params.id,
168
+ role: params.role,
169
+ iteration: params.iteration,
170
+ triggeringMessage: params.triggeringMessage,
171
+ strategy,
172
+ packs: packResult.packDecisions,
173
+ budget: packResult.budget,
174
+ truncation: packResult.truncation,
175
+ });
176
+
177
+ updateTotalMetrics(metrics, packResult.context.length);
178
+ emitContextMetrics(metrics, {
179
+ messageBus: params.messageBus,
180
+ clusterId: params.cluster.id,
181
+ agentId: params.id,
182
+ });
183
+
184
+ return packResult.context;
185
+ }
186
+
187
+ module.exports = {
188
+ buildContext,
189
+ };