@covibes/zeroshot 5.3.0 → 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.
- package/README.md +94 -14
- package/cli/commands/providers.js +8 -9
- package/cli/index.js +3032 -2409
- package/cli/message-formatters-normal.js +28 -6
- package/cluster-templates/base-templates/debug-workflow.json +1 -1
- package/cluster-templates/base-templates/full-workflow.json +72 -188
- package/cluster-templates/base-templates/worker-validator.json +59 -3
- package/cluster-templates/conductor-bootstrap.json +4 -4
- package/lib/docker-config.js +8 -0
- package/lib/git-remote-utils.js +165 -0
- package/lib/id-detector.js +10 -7
- package/lib/provider-defaults.js +62 -0
- package/lib/provider-names.js +2 -1
- package/lib/settings/claude-auth.js +78 -0
- package/lib/settings.js +161 -63
- package/package.json +7 -2
- package/scripts/setup-merge-queue.sh +170 -0
- package/src/agent/agent-config.js +135 -82
- package/src/agent/agent-context-builder.js +297 -188
- package/src/agent/agent-hook-executor.js +310 -113
- package/src/agent/agent-lifecycle.js +385 -325
- package/src/agent/agent-stuck-detector.js +7 -7
- package/src/agent/agent-task-executor.js +824 -565
- package/src/agent/output-extraction.js +41 -24
- package/src/agent/output-reformatter.js +1 -1
- package/src/agent/schema-utils.js +108 -73
- package/src/agent-wrapper.js +10 -1
- package/src/agents/git-pusher-template.js +285 -0
- package/src/claude-task-runner.js +85 -34
- package/src/config-validator.js +922 -657
- package/src/input-helpers.js +65 -0
- package/src/isolation-manager.js +289 -199
- package/src/issue-providers/README.md +305 -0
- package/src/issue-providers/azure-devops-provider.js +273 -0
- package/src/issue-providers/base-provider.js +232 -0
- package/src/issue-providers/github-provider.js +179 -0
- package/src/issue-providers/gitlab-provider.js +241 -0
- package/src/issue-providers/index.js +196 -0
- package/src/issue-providers/jira-provider.js +239 -0
- package/src/ledger.js +22 -5
- package/src/lib/safe-exec.js +88 -0
- package/src/orchestrator.js +1107 -811
- package/src/preflight.js +313 -159
- package/src/process-metrics.js +98 -56
- package/src/providers/anthropic/cli-builder.js +53 -25
- package/src/providers/anthropic/index.js +72 -2
- package/src/providers/anthropic/output-parser.js +32 -14
- package/src/providers/base-provider.js +70 -0
- package/src/providers/capabilities.js +9 -0
- package/src/providers/google/output-parser.js +47 -38
- package/src/providers/index.js +19 -3
- package/src/providers/openai/cli-builder.js +14 -3
- package/src/providers/openai/index.js +1 -0
- package/src/providers/openai/output-parser.js +44 -30
- package/src/providers/opencode/cli-builder.js +42 -0
- package/src/providers/opencode/index.js +103 -0
- package/src/providers/opencode/models.js +55 -0
- package/src/providers/opencode/output-parser.js +122 -0
- package/src/schemas/sub-cluster.js +68 -39
- package/src/status-footer.js +94 -48
- package/src/sub-cluster-wrapper.js +76 -35
- package/src/template-resolver.js +12 -9
- package/src/tui/data-poller.js +123 -99
- package/src/tui/formatters.js +4 -3
- package/src/tui/keybindings.js +259 -318
- package/src/tui/renderer.js +11 -21
- package/task-lib/attachable-watcher.js +118 -81
- package/task-lib/claude-recovery.js +61 -24
- package/task-lib/commands/episodes.js +105 -0
- package/task-lib/commands/list.js +2 -2
- package/task-lib/commands/logs.js +231 -189
- package/task-lib/commands/schedules.js +111 -61
- package/task-lib/config.js +0 -2
- package/task-lib/runner.js +84 -27
- package/task-lib/scheduler.js +1 -1
- package/task-lib/store.js +467 -168
- package/task-lib/tui/formatters.js +94 -45
- package/task-lib/tui/renderer.js +13 -3
- package/task-lib/tui.js +73 -32
- package/task-lib/watcher.js +128 -90
- package/src/agents/git-pusher-agent.json +0 -20
- package/src/github.js +0 -139
|
@@ -27,21 +27,13 @@ const DEFAULT_TIMEOUT = 0;
|
|
|
27
27
|
const DEFAULT_STALE_DURATION_MS = 30 * 60 * 1000; // 30 minutes before triggering analysis
|
|
28
28
|
const DEFAULT_LIVENESS_CHECK_ENABLED = true; // Safe with multi-indicator detection
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
* Validate and normalize agent configuration
|
|
32
|
-
* @param {Object} config - Raw agent configuration
|
|
33
|
-
* @param {Object} options - Agent wrapper options
|
|
34
|
-
* @returns {Object} Normalized configuration
|
|
35
|
-
*/
|
|
36
|
-
function validateAgentConfig(config, options = {}) {
|
|
30
|
+
function applyOutputDefaults(config) {
|
|
37
31
|
// CRITICAL: Enforce JSON schema output by default to prevent parse failures and crashes
|
|
38
|
-
// Agents MUST return structured output so hooks can safely use {{result.*}} templates
|
|
39
32
|
if (!config.outputFormat) {
|
|
40
33
|
config.outputFormat = 'json';
|
|
41
34
|
}
|
|
42
35
|
|
|
43
36
|
// If outputFormat is json but no schema defined, use a minimal default schema
|
|
44
|
-
// This prevents uncaught exceptions when parsing agent output
|
|
45
37
|
if (config.outputFormat === 'json' && !config.jsonSchema) {
|
|
46
38
|
config.jsonSchema = {
|
|
47
39
|
type: 'object',
|
|
@@ -58,121 +50,135 @@ function validateAgentConfig(config, options = {}) {
|
|
|
58
50
|
required: ['summary', 'result'],
|
|
59
51
|
};
|
|
60
52
|
}
|
|
53
|
+
}
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
// If no model specified, model is null - _selectModel() will use provider defaults
|
|
64
|
-
let modelConfig;
|
|
55
|
+
function buildModelConfig(config) {
|
|
65
56
|
if (config.modelRules) {
|
|
66
|
-
|
|
67
|
-
} else {
|
|
68
|
-
modelConfig = {
|
|
69
|
-
type: 'static',
|
|
70
|
-
model: config.model || null,
|
|
71
|
-
modelLevel: config.modelLevel || null,
|
|
72
|
-
};
|
|
57
|
+
return { type: 'rules', rules: config.modelRules };
|
|
73
58
|
}
|
|
59
|
+
return {
|
|
60
|
+
type: 'static',
|
|
61
|
+
model: config.model || null,
|
|
62
|
+
modelLevel: config.modelLevel || null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
74
65
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
66
|
+
function applyStrictSchemaDefault(config, settings) {
|
|
67
|
+
if (config.strictSchema === undefined) {
|
|
68
|
+
config.strictSchema = settings.strictSchema !== false; // Default true if not set
|
|
69
|
+
}
|
|
70
|
+
}
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
throw new Error(`Agent "${config.id}": ${error.message}`);
|
|
88
|
-
}
|
|
72
|
+
function validateStaticModelConfig(configId, modelConfig, maxModel, minModel) {
|
|
73
|
+
if (modelConfig.model && VALID_MODELS.includes(modelConfig.model)) {
|
|
74
|
+
try {
|
|
75
|
+
validateModelAgainstMax(modelConfig.model, maxModel, minModel);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
throw new Error(`Agent "${configId}": ${error.message}`);
|
|
89
78
|
}
|
|
79
|
+
}
|
|
90
80
|
|
|
91
|
-
|
|
81
|
+
if (modelConfig.modelLevel && !VALID_LEVELS.includes(modelConfig.modelLevel)) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Agent "${configId}": invalid modelLevel "${modelConfig.modelLevel}". ` +
|
|
84
|
+
`Valid: ${VALID_LEVELS.join(', ')}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function validateModelRule(configId, rule, maxModel, minModel) {
|
|
90
|
+
if (rule.model && VALID_MODELS.includes(rule.model)) {
|
|
91
|
+
try {
|
|
92
|
+
validateModelAgainstMax(rule.model, maxModel, minModel);
|
|
93
|
+
} catch {
|
|
92
94
|
throw new Error(
|
|
93
|
-
`Agent "${
|
|
94
|
-
`
|
|
95
|
+
`Agent "${configId}": modelRule "${rule.iterations}" requests "${rule.model}" ` +
|
|
96
|
+
`but maxModel is "${maxModel}"${minModel ? ` and minModel is "${minModel}"` : ''}. ` +
|
|
97
|
+
`Either adjust the rule's model or change maxModel/minModel settings.`
|
|
95
98
|
);
|
|
96
99
|
}
|
|
97
|
-
}
|
|
98
|
-
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (rule.modelLevel && !VALID_LEVELS.includes(rule.modelLevel)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Agent "${configId}": modelRule "${rule.iterations}" has invalid modelLevel ` +
|
|
105
|
+
`"${rule.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function validateModelConfig(config, modelConfig, maxModel, minModel) {
|
|
111
|
+
if (modelConfig.type === 'static') {
|
|
112
|
+
validateStaticModelConfig(config.id, modelConfig, maxModel, minModel);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (modelConfig.type === 'rules') {
|
|
99
117
|
for (const rule of modelConfig.rules) {
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
validateModelAgainstMax(rule.model, maxModel, minModel);
|
|
103
|
-
} catch {
|
|
104
|
-
throw new Error(
|
|
105
|
-
`Agent "${config.id}": 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 "${config.id}": modelRule "${rule.iterations}" has invalid modelLevel ` +
|
|
115
|
-
`"${rule.modelLevel}". Valid: ${VALID_LEVELS.join(', ')}`
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
+
validateModelRule(config.id, rule, maxModel, minModel);
|
|
118
119
|
}
|
|
119
120
|
}
|
|
121
|
+
}
|
|
120
122
|
|
|
121
|
-
|
|
122
|
-
// Formats:
|
|
123
|
-
// prompt: "string" -> static
|
|
124
|
-
// prompt: { system: "string" } -> static
|
|
125
|
-
// prompt: { initial: "...", subsequent: "..." } -> iteration 1 vs 2+
|
|
126
|
-
// prompt: { iterations: [...] } -> full control
|
|
127
|
-
let promptConfig = null;
|
|
123
|
+
function buildPromptConfig(config) {
|
|
128
124
|
if (config.prompt?.iterations) {
|
|
129
|
-
|
|
130
|
-
}
|
|
125
|
+
return { type: 'rules', rules: config.prompt.iterations };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (config.prompt?.initial || config.prompt?.subsequent) {
|
|
131
129
|
const rules = [];
|
|
132
130
|
if (config.prompt.initial) rules.push({ match: '1', system: config.prompt.initial });
|
|
133
131
|
if (config.prompt.subsequent) rules.push({ match: '2+', system: config.prompt.subsequent });
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
132
|
+
return { type: 'rules', rules };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (typeof config.prompt === 'string') {
|
|
136
|
+
return { type: 'static', system: config.prompt };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (config.prompt?.system) {
|
|
140
|
+
return { type: 'static', system: config.prompt.system };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (config.prompt) {
|
|
140
144
|
throw new Error(`Agent "${config.id}": invalid prompt format`);
|
|
141
145
|
}
|
|
142
146
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function normalizeTimeout(config) {
|
|
146
151
|
if (config.timeout === undefined || config.timeout === null || config.timeout === '') {
|
|
147
152
|
config.timeout = DEFAULT_TIMEOUT;
|
|
148
153
|
} else {
|
|
149
|
-
// Coerce to number (handles string "0" from template resolution)
|
|
150
154
|
config.timeout = Number(config.timeout);
|
|
151
155
|
}
|
|
156
|
+
|
|
152
157
|
if (!Number.isFinite(config.timeout) || config.timeout < 0) {
|
|
153
158
|
throw new Error(
|
|
154
159
|
`Agent "${config.id}": timeout must be a non-negative number (got ${config.timeout}).`
|
|
155
160
|
);
|
|
156
161
|
}
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
return config.timeout;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function buildNormalizedConfig(config, modelConfig, promptConfig) {
|
|
167
|
+
return {
|
|
160
168
|
...config,
|
|
161
169
|
modelConfig,
|
|
162
170
|
promptConfig,
|
|
163
171
|
maxIterations: config.maxIterations || DEFAULT_MAX_ITERATIONS,
|
|
164
|
-
timeout: config.timeout,
|
|
172
|
+
timeout: config.timeout,
|
|
165
173
|
staleDuration: config.staleDuration || DEFAULT_STALE_DURATION_MS,
|
|
166
|
-
enableLivenessCheck: config.enableLivenessCheck ?? DEFAULT_LIVENESS_CHECK_ENABLED,
|
|
174
|
+
enableLivenessCheck: config.enableLivenessCheck ?? DEFAULT_LIVENESS_CHECK_ENABLED,
|
|
167
175
|
};
|
|
176
|
+
}
|
|
168
177
|
|
|
169
|
-
|
|
170
|
-
// Check if this agent executes tasks (vs orchestrator agents that only publish messages)
|
|
178
|
+
function assertTestModeSafety(config, options) {
|
|
171
179
|
const executesTask = config.triggers?.some(
|
|
172
180
|
(trigger) => !trigger.action || trigger.action === 'execute_task'
|
|
173
181
|
);
|
|
174
|
-
|
|
175
|
-
// Accept either mockSpawnFn OR taskRunner as valid mock sources
|
|
176
182
|
const hasMock = options.mockSpawnFn || options.taskRunner;
|
|
177
183
|
|
|
178
184
|
if (options.testMode && !hasMock && executesTask) {
|
|
@@ -181,6 +187,53 @@ function validateAgentConfig(config, options = {}) {
|
|
|
181
187
|
`This would cause real Claude API calls. ABORTING.`
|
|
182
188
|
);
|
|
183
189
|
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Validate and normalize agent configuration
|
|
194
|
+
* @param {Object} config - Raw agent configuration
|
|
195
|
+
* @param {Object} options - Agent wrapper options
|
|
196
|
+
* @returns {Object} Normalized configuration
|
|
197
|
+
*/
|
|
198
|
+
function validateAgentConfig(config, options = {}) {
|
|
199
|
+
applyOutputDefaults(config);
|
|
200
|
+
|
|
201
|
+
// Model configuration: support both static model and dynamic rules
|
|
202
|
+
// If no model specified, model is null - _selectModel() will use provider defaults
|
|
203
|
+
const modelConfig = buildModelConfig(config);
|
|
204
|
+
|
|
205
|
+
// COST CEILING/FLOOR ENFORCEMENT: Validate model(s) against maxModel and minModel at config time
|
|
206
|
+
// Catches violations EARLY (config load) instead of at runtime (iteration N)
|
|
207
|
+
const settings = loadSettings();
|
|
208
|
+
const maxModel = settings.maxModel || 'sonnet';
|
|
209
|
+
const minModel = settings.minModel || null;
|
|
210
|
+
|
|
211
|
+
// STRICT SCHEMA PROPAGATION: Issue #52 fix
|
|
212
|
+
// If agent config doesn't explicitly set strictSchema, inherit from global settings
|
|
213
|
+
// This allows `zeroshot settings set strictSchema false` to actually affect agents
|
|
214
|
+
// Default behavior: strictSchema=true (reliable JSON output, no streaming)
|
|
215
|
+
applyStrictSchemaDefault(config, settings);
|
|
216
|
+
validateModelConfig(config, modelConfig, maxModel, minModel);
|
|
217
|
+
|
|
218
|
+
// Prompt configuration: support static prompt OR iteration-based rules
|
|
219
|
+
// Formats:
|
|
220
|
+
// prompt: "string" -> static
|
|
221
|
+
// prompt: { system: "string" } -> static
|
|
222
|
+
// prompt: { initial: "...", subsequent: "..." } -> iteration 1 vs 2+
|
|
223
|
+
// prompt: { iterations: [...] } -> full control
|
|
224
|
+
const promptConfig = buildPromptConfig(config);
|
|
225
|
+
|
|
226
|
+
// Default timeout to 0 (no timeout) if not specified
|
|
227
|
+
// Use positive number for timeout in milliseconds
|
|
228
|
+
// ROBUST: Handle undefined, null, AND string values from template resolution
|
|
229
|
+
normalizeTimeout(config);
|
|
230
|
+
|
|
231
|
+
// Build normalized config
|
|
232
|
+
const normalizedConfig = buildNormalizedConfig(config, modelConfig, promptConfig);
|
|
233
|
+
|
|
234
|
+
// SAFETY: In test mode, verify mock is provided for agents that execute tasks
|
|
235
|
+
// Check if this agent executes tasks (vs orchestrator agents that only publish messages)
|
|
236
|
+
assertTestModeSafety(config, options);
|
|
184
237
|
|
|
185
238
|
return normalizedConfig;
|
|
186
239
|
}
|