@the-open-engine/zeroshot 6.9.0 → 6.9.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@the-open-engine/zeroshot",
3
- "version": "6.9.0",
3
+ "version": "6.9.1",
4
4
  "description": "Multi-agent orchestration engine for Claude, Codex, and Gemini",
5
5
  "main": "src/orchestrator.js",
6
6
  "bin": {
@@ -574,6 +574,7 @@ async function runTaskAttempt(agent, triggeringMessage) {
574
574
  const error = new Error(result.error || 'Task execution failed');
575
575
  error.code = result.code || result.errorType || null;
576
576
  error.taskId = result.taskId || null;
577
+ error.vertexModelError = result.vertexModelError || null;
577
578
  throw error;
578
579
  }
579
580
 
@@ -604,6 +605,20 @@ ${'='.repeat(80)}`);
604
605
  console.error(`🔴 TASK EXECUTION FAILED - AGENT: ${agent.id} (Attempt ${attempt}/${maxRetries})`);
605
606
  console.error(`${'='.repeat(80)}`);
606
607
  console.error(`Error: ${error.message}`);
608
+
609
+ const vertexError = error.vertexModelError;
610
+ if (vertexError) {
611
+ const model = vertexError.model ? `"${vertexError.model}" is` : 'Selected model is';
612
+ console.error(`
613
+ ⚠️ ${model} not available on your Vertex AI deployment.
614
+ Fix: set explicit model IDs that are enabled on your deployment:
615
+
616
+ zeroshot settings set providerSettings.claude.levelOverrides '{"level1": {"model": "claude-sonnet-4-6"}, "level2": {"model": "claude-sonnet-4-6"}, "level3": {"model": "claude-sonnet-4-6"}}'
617
+
618
+ Replace "claude-sonnet-4-6" with whichever Claude model your deployment has enabled.
619
+ You can test a model with: claude --dangerously-skip-permissions -p "hi" --model <model-id>
620
+ `);
621
+ }
607
622
  }
608
623
 
609
624
  async function handleLockContention() {
@@ -692,6 +707,22 @@ ${'='.repeat(80)}`);
692
707
  });
693
708
  }
694
709
 
710
+ if (error?.vertexModelError) {
711
+ agent._publish({
712
+ topic: 'CLUSTER_FAILED',
713
+ receiver: 'broadcast',
714
+ content: {
715
+ text: `Cluster failed: Claude model is unavailable on Vertex for ${agent.id}`,
716
+ data: {
717
+ reason: 'vertex_model_unavailable',
718
+ agentId: agent.id,
719
+ role: agent.role,
720
+ model: error.vertexModelError.model,
721
+ },
722
+ },
723
+ });
724
+ }
725
+
695
726
  if (error?.terminationExhausted) {
696
727
  agent._publish({
697
728
  topic: 'CLUSTER_FAILED',
@@ -985,6 +1016,20 @@ async function executeTask(agent, triggeringMessage) {
985
1016
  await handleFinalFailure(agent, triggeringMessage, error, 1);
986
1017
  return;
987
1018
  }
1019
+ if (error.vertexModelError) {
1020
+ agent._publishLifecycle('TASK_FAILED', {
1021
+ iteration: agent.iteration,
1022
+ taskId: error.taskId || agent.currentTaskId,
1023
+ error: error.message,
1024
+ code: error.code || null,
1025
+ attempt,
1026
+ });
1027
+ clearTransientTaskState(agent);
1028
+ logTaskAttemptFailure(agent, attempt, maxRetries, error);
1029
+ // Model unavailability on Vertex is deterministic — retrying wastes nothing but time.
1030
+ await handleFinalFailure(agent, triggeringMessage, error, attempt);
1031
+ return;
1032
+ }
988
1033
  agent._publishLifecycle('TASK_FAILED', {
989
1034
  iteration: agent.iteration,
990
1035
  taskId: error.taskId || agent.currentTaskId,
@@ -28,6 +28,7 @@ const {
28
28
  wrapTaskRunWithIsolatedSettings,
29
29
  } = require('../task-run-model-args.js');
30
30
  const { buildRawLogOnlyMetadata } = require('./context-replay-policy');
31
+ const { extractClaudeVertexModelError } = require('./output-extraction');
31
32
 
32
33
  function runCommandWithTimeout(command, args, options = {}, callback = null) {
33
34
  const timeout = options.timeout ?? 30000;
@@ -1213,6 +1214,15 @@ function buildFailureContext({ agent, taskId, providerName, state, stdout }) {
1213
1214
 
1214
1215
  async function buildCompletionResult({ agent, taskId, providerName, state, stdout, success }) {
1215
1216
  const classified = await evaluateStructuredSuccess({ agent, taskId, state, success });
1217
+ const vertexModelError =
1218
+ providerName === 'claude'
1219
+ ? extractClaudeVertexModelError(state.output, {
1220
+ useVertex: process.env.CLAUDE_CODE_USE_VERTEX === '1',
1221
+ })
1222
+ : null;
1223
+ if (vertexModelError) {
1224
+ classified.success = false;
1225
+ }
1216
1226
  let errorContext = classified.error;
1217
1227
  if (!errorContext && !classified.success) {
1218
1228
  errorContext = buildFailureContext({ agent, taskId, providerName, state, stdout });
@@ -1223,6 +1233,7 @@ async function buildCompletionResult({ agent, taskId, providerName, state, stdou
1223
1233
  output: state.output,
1224
1234
  error: errorContext,
1225
1235
  tokenUsage: extractTokenUsage(state.output, providerName),
1236
+ vertexModelError,
1226
1237
  };
1227
1238
  }
1228
1239
 
@@ -1797,7 +1808,13 @@ function settleIsolatedTerminalStatus({
1797
1808
  }
1798
1809
  }
1799
1810
 
1800
- const success = status === 'completed';
1811
+ const vertexModelError =
1812
+ providerName === 'claude'
1813
+ ? extractClaudeVertexModelError(state.fullOutput, {
1814
+ useVertex: process.env.CLAUDE_CODE_USE_VERTEX === '1',
1815
+ })
1816
+ : null;
1817
+ const success = status === 'completed' && !vertexModelError;
1801
1818
  const errorContext = !success
1802
1819
  ? extractErrorContext({
1803
1820
  output: state.fullOutput,
@@ -1816,7 +1833,7 @@ function settleIsolatedTerminalStatus({
1816
1833
  },
1817
1834
  })
1818
1835
  : null;
1819
- const parsedResult = await agent._parseResultOutput(state.fullOutput);
1836
+ const parsedResult = vertexModelError ? null : await agent._parseResultOutput(state.fullOutput);
1820
1837
 
1821
1838
  settleIsolatedFollower({
1822
1839
  agent,
@@ -1830,6 +1847,7 @@ function settleIsolatedTerminalStatus({
1830
1847
  result: parsedResult,
1831
1848
  error: errorContext,
1832
1849
  tokenUsage: extractTokenUsage(state.fullOutput, providerName),
1850
+ vertexModelError,
1833
1851
  },
1834
1852
  });
1835
1853
  })().catch((error) => {
@@ -234,6 +234,45 @@ function extractDirectJson(text) {
234
234
  return null;
235
235
  }
236
236
 
237
+ /**
238
+ * Extract deterministic Claude Vertex model-unavailability metadata from the raw CLI envelope.
239
+ *
240
+ * @param {string} output - Raw Claude CLI output
241
+ * @param {{useVertex?: boolean}} [options] - Whether the Claude task was configured for Vertex
242
+ * @returns {{model: string}|null} Vertex model metadata or null
243
+ */
244
+ function extractClaudeVertexModelError(output, { useVertex = false } = {}) {
245
+ if (!output || typeof output !== 'string') return null;
246
+
247
+ for (const line of output.split('\n')) {
248
+ const content = stripTimestamp(line);
249
+ if (!content.startsWith('{')) continue;
250
+
251
+ try {
252
+ const parsed = JSON.parse(content);
253
+ if (
254
+ parsed.type !== 'result' ||
255
+ parsed.is_error !== true ||
256
+ parsed.api_error_status !== 404 ||
257
+ typeof parsed.result !== 'string'
258
+ ) {
259
+ continue;
260
+ }
261
+ const modelMatch = parsed.result.match(/model\s+\(([^)]+)\)/);
262
+ const hasExplicitVertexSignal = parsed.result.includes('vertex deployment');
263
+ const isVertexFallback =
264
+ useVertex && parsed.result.includes('may not exist or you may not have access');
265
+ if (!modelMatch || (!hasExplicitVertexSignal && !isVertexFallback)) continue;
266
+
267
+ return { model: modelMatch[1] };
268
+ } catch {
269
+ // Not a JSON result envelope.
270
+ }
271
+ }
272
+
273
+ return null;
274
+ }
275
+
237
276
  /**
238
277
  * Extract CLI error from provider output (all providers).
239
278
  * Returns the error message if the CLI reported an error, null otherwise.
@@ -358,6 +397,7 @@ function extractJsonFromOutput(output, providerName = 'claude') {
358
397
  module.exports = {
359
398
  extractJsonFromOutput,
360
399
  extractCliError,
400
+ extractClaudeVertexModelError,
361
401
  extractFromResultWrapper,
362
402
  extractFromTextEvents,
363
403
  extractFromMarkdown,