@the-open-engine/zeroshot 6.39.1 → 6.40.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 (121) hide show
  1. package/README.md +45 -1
  2. package/cli/agent-provider-boundary.js +19 -0
  3. package/cli/agent-provider-boundary.ts +79 -0
  4. package/cli/export-stream.js +94 -0
  5. package/cli/export-stream.ts +118 -0
  6. package/cli/index.js +132 -61
  7. package/cli/json-export.js +2 -38
  8. package/cli/json-export.ts +2 -56
  9. package/cli/semantic-canonical.js +60 -0
  10. package/cli/semantic-canonical.ts +59 -0
  11. package/cli/semantic-contract.js +97 -0
  12. package/cli/semantic-contract.ts +153 -0
  13. package/cli/semantic-events.js +53 -0
  14. package/cli/semantic-events.ts +65 -0
  15. package/cli/semantic-evidence.js +63 -0
  16. package/cli/semantic-evidence.ts +65 -0
  17. package/cli/semantic-export.js +186 -0
  18. package/cli/semantic-export.ts +245 -0
  19. package/cli/semantic-json.js +69 -0
  20. package/cli/semantic-json.ts +69 -0
  21. package/cli/semantic-line-scanner.js +56 -0
  22. package/cli/semantic-line-scanner.ts +54 -0
  23. package/cli/semantic-parser.js +78 -0
  24. package/cli/semantic-parser.ts +95 -0
  25. package/cli/semantic-provider-line.js +91 -0
  26. package/cli/semantic-provider-line.ts +106 -0
  27. package/cli/trace-evidence.js +86 -0
  28. package/cli/trace-evidence.ts +115 -0
  29. package/cli/trace-export.js +120 -0
  30. package/cli/trace-export.ts +164 -0
  31. package/cli/trace-output-record.js +15 -0
  32. package/cli/trace-output-record.ts +18 -0
  33. package/cli/trace-output.js +98 -0
  34. package/cli/trace-output.ts +119 -0
  35. package/cluster-templates/conductor-bootstrap.json +1 -1
  36. package/lib/agent-cli-provider/adapters/claude.js +1 -1
  37. package/lib/agent-cli-provider/adapters/claude.js.map +1 -1
  38. package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
  39. package/lib/agent-cli-provider/adapters/codex.js +26 -1
  40. package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
  41. package/lib/agent-cli-provider/adapters/omp.d.ts.map +1 -1
  42. package/lib/agent-cli-provider/adapters/omp.js +1 -1
  43. package/lib/agent-cli-provider/adapters/omp.js.map +1 -1
  44. package/lib/agent-cli-provider/log-prefix.d.ts.map +1 -1
  45. package/lib/agent-cli-provider/log-prefix.js +8 -6
  46. package/lib/agent-cli-provider/log-prefix.js.map +1 -1
  47. package/lib/agent-cli-provider/omp/sdk-environment-policy.d.ts +4 -0
  48. package/lib/agent-cli-provider/omp/sdk-environment-policy.d.ts.map +1 -0
  49. package/lib/agent-cli-provider/omp/sdk-environment-policy.js +37 -0
  50. package/lib/agent-cli-provider/omp/sdk-environment-policy.js.map +1 -0
  51. package/lib/agent-cli-provider/omp/sdk-process-private-runtime.d.ts.map +1 -1
  52. package/lib/agent-cli-provider/omp/sdk-process-private-runtime.js +4 -15
  53. package/lib/agent-cli-provider/omp/sdk-process-private-runtime.js.map +1 -1
  54. package/lib/agent-cli-provider/omp/sdk-process-result.d.ts +2 -0
  55. package/lib/agent-cli-provider/omp/sdk-process-result.d.ts.map +1 -1
  56. package/lib/agent-cli-provider/omp/sdk-process-result.js +2 -2
  57. package/lib/agent-cli-provider/omp/sdk-process-result.js.map +1 -1
  58. package/lib/agent-cli-provider/omp/sdk-process-runner.d.ts.map +1 -1
  59. package/lib/agent-cli-provider/omp/sdk-process-runner.js +6 -1
  60. package/lib/agent-cli-provider/omp/sdk-process-runner.js.map +1 -1
  61. package/lib/agent-cli-provider/provider-registry.d.ts +3 -1
  62. package/lib/agent-cli-provider/provider-registry.d.ts.map +1 -1
  63. package/lib/agent-cli-provider/provider-registry.js +9 -2
  64. package/lib/agent-cli-provider/provider-registry.js.map +1 -1
  65. package/lib/agent-cli-provider/single-agent-runtime.d.ts +4 -1
  66. package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -1
  67. package/lib/agent-cli-provider/single-agent-runtime.js +18 -15
  68. package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -1
  69. package/lib/agent-cli-provider/types.d.ts +3 -0
  70. package/lib/agent-cli-provider/types.d.ts.map +1 -1
  71. package/lib/agent-cli-provider/types.js.map +1 -1
  72. package/lib/cluster-worker/engine-adapter-common.js +18 -0
  73. package/lib/cluster-worker/engine-adapter.js +2 -1
  74. package/lib/git-remote-utils.js +22 -5
  75. package/lib/stream-json-parser.js +6 -5
  76. package/npm-shrinkwrap.json +2 -2
  77. package/package.json +7 -4
  78. package/scripts/omp/runtime-identities.js +31 -18
  79. package/scripts/omp/runtime.js +2 -0
  80. package/src/agent/agent-lifecycle.js +17 -1
  81. package/src/agent/agent-task-executor.js +36 -40
  82. package/src/agent/output-extraction-failures.js +73 -0
  83. package/src/agent/output-extraction-failures.ts +100 -0
  84. package/src/agent/output-extraction-json.js +5 -6
  85. package/src/agent/output-extraction-json.ts +4 -7
  86. package/src/agent/output-extraction-types.ts +5 -0
  87. package/src/agent/provider-terminal-failure.js +2 -2
  88. package/src/agent/provider-terminal-failure.ts +4 -2
  89. package/src/agent-cli-provider/adapters/claude.ts +1 -1
  90. package/src/agent-cli-provider/adapters/codex.ts +36 -1
  91. package/src/agent-cli-provider/adapters/omp.ts +2 -1
  92. package/src/agent-cli-provider/log-prefix.ts +12 -7
  93. package/src/agent-cli-provider/omp/sdk-environment-policy.ts +38 -0
  94. package/src/agent-cli-provider/omp/sdk-process-private-runtime.ts +4 -16
  95. package/src/agent-cli-provider/omp/sdk-process-result.ts +4 -2
  96. package/src/agent-cli-provider/omp/sdk-process-runner.ts +7 -1
  97. package/src/agent-cli-provider/provider-registry.ts +10 -2
  98. package/src/agent-cli-provider/single-agent-runtime.ts +24 -15
  99. package/src/agent-cli-provider/types.ts +3 -0
  100. package/src/agents/git-pusher-template.js +61 -71
  101. package/src/attach/socket-paths.js +1 -1
  102. package/src/attach/socket-paths.ts +1 -1
  103. package/src/claude-task-runner.js +9 -9
  104. package/src/foreground-benchmark-run.js +24 -12
  105. package/src/legacy-lib/git-remote-utils.ts +23 -5
  106. package/src/legacy-lib/stream-json-parser.ts +10 -5
  107. package/src/omp-session-verifier.js +8 -5
  108. package/src/orchestrator.js +42 -0
  109. package/src/preflight.js +31 -6
  110. package/src/providers/index.js +4 -22
  111. package/src/task-execution-context.js +22 -0
  112. package/src/task-log-line.d.ts +20 -0
  113. package/src/task-log-line.js +80 -0
  114. package/src/watcher-prompt-channel.js +1 -1
  115. package/src/worktree-claude-config.js +25 -0
  116. package/src/worktree-claude-config.ts +28 -0
  117. package/task-lib/commands/logs.js +5 -8
  118. package/task-lib/runner.js +57 -22
  119. package/task-lib/sdk-watcher-output.js +31 -0
  120. package/task-lib/sdk-watcher.js +4 -11
  121. package/task-lib/watcher-output-runtime.js +30 -16
@@ -10,6 +10,7 @@ const BUN_PACKAGE_NAME = 'bun';
10
10
  const BUN_RUNTIME_VERSION = '1.3.14';
11
11
  const SIDECAR_RELATIVE_PATH = path.join('scripts', 'omp', 'sidecar.ts');
12
12
  const HOST_SUPERVISOR_RELATIVE_PATH = path.join('scripts', 'omp', 'host-supervisor.ts');
13
+ const ACTIVE_CONTAINER_INVOCATION = Symbol('active-container-invocation');
13
14
  const HOST_SDK_PLATFORM_KEYS = Object.freeze(['linux:arm64', 'linux:x64']);
14
15
 
15
16
  const BUN_PLATFORM_PACKAGES = Object.freeze({
@@ -227,24 +228,26 @@ function resolveOmpSdkRuntime(options = {}) {
227
228
  if (!fileExists(hostSupervisorPath)) {
228
229
  throw new Error(`OMP SDK host supervisor is missing: ${hostSupervisorPath}`);
229
230
  }
230
- let containmentProbe;
231
- try {
232
- containmentProbe = JSON.parse(
233
- String(readContainmentProbe(bunExecutable, hostSupervisorPath)).trim()
234
- );
235
- } catch (error) {
236
- throw new Error(`Unable to attest Linux subreaper/pidfd containment: ${error.message}`);
237
- }
238
- if (
239
- containmentProbe?.protocolVersion !== 1 ||
240
- containmentProbe?.type !== 'cleanup-attestation' ||
241
- containmentProbe?.status !== 'clean' ||
242
- containmentProbe?.mode !== 'linux-subreaper-pidfd' ||
243
- containmentProbe?.subreaper !== true ||
244
- containmentProbe?.pidfd !== true ||
245
- containmentProbe?.ownedProcessCount !== 0
246
- ) {
247
- throw new Error('Linux subreaper/pidfd containment probe returned invalid evidence');
231
+ if (runtimeOptions.activeInvocation !== ACTIVE_CONTAINER_INVOCATION) {
232
+ let containmentProbe;
233
+ try {
234
+ containmentProbe = JSON.parse(
235
+ String(readContainmentProbe(bunExecutable, hostSupervisorPath)).trim()
236
+ );
237
+ } catch (error) {
238
+ throw new Error(`Unable to attest Linux subreaper/pidfd containment: ${error.message}`);
239
+ }
240
+ if (
241
+ containmentProbe?.protocolVersion !== 1 ||
242
+ containmentProbe?.type !== 'cleanup-attestation' ||
243
+ containmentProbe?.status !== 'clean' ||
244
+ containmentProbe?.mode !== 'linux-subreaper-pidfd' ||
245
+ containmentProbe?.subreaper !== true ||
246
+ containmentProbe?.pidfd !== true ||
247
+ containmentProbe?.ownedProcessCount !== 0
248
+ ) {
249
+ throw new Error('Linux subreaper/pidfd containment probe returned invalid evidence');
250
+ }
248
251
  }
249
252
  return Object.freeze({
250
253
  bunExecutable,
@@ -261,6 +264,15 @@ function resolveOmpSdkRuntime(options = {}) {
261
264
  sidecarPath,
262
265
  });
263
266
  }
267
+
268
+ function resolveOmpSdkContainerRuntime(options = {}) {
269
+ // Image inspection may run as PID 1, where no parent process exists to supervise. The actual
270
+ // provider invocation still starts the supervisor and requires its final cleanup attestation.
271
+ return resolveOmpSdkRuntime({
272
+ ...options,
273
+ activeInvocation: ACTIVE_CONTAINER_INVOCATION,
274
+ });
275
+ }
264
276
  module.exports = {
265
277
  BUN_PACKAGE_INTEGRITY,
266
278
  BUN_PACKAGE_NAME,
@@ -279,5 +291,6 @@ module.exports = {
279
291
  REQUIRED_OMP_SDK_SOURCES,
280
292
  SIDECAR_RELATIVE_PATH,
281
293
  assertPackageIdentity,
294
+ resolveOmpSdkContainerRuntime,
282
295
  resolveOmpSdkRuntime,
283
296
  };
@@ -12,6 +12,7 @@ const {
12
12
  REQUIRED_OMP_SDK_SOURCES,
13
13
  SIDECAR_RELATIVE_PATH,
14
14
  assertPackageIdentity,
15
+ resolveOmpSdkContainerRuntime,
15
16
  resolveOmpSdkRuntime,
16
17
  } = require('./runtime-identities');
17
18
  const { validateOmpSdkReleaseAssets } = require('./runtime-release');
@@ -28,6 +29,7 @@ module.exports = {
28
29
  REQUIRED_OMP_SDK_SOURCES,
29
30
  SIDECAR_RELATIVE_PATH,
30
31
  assertPackageIdentity,
32
+ resolveOmpSdkContainerRuntime,
31
33
  resolveOmpSdkRuntime,
32
34
  validateOmpSdkReleaseAssets,
33
35
  };
@@ -221,6 +221,7 @@ function start(agent) {
221
221
  */
222
222
  async function stop(agent) {
223
223
  stopLivenessCheck(agent);
224
+ agent._cancelStartDelay?.();
224
225
 
225
226
  const hasNestedExecutions = agent.nestedExecutions?.hasActive === true;
226
227
  if (!agent.running && !agent.currentTask && !hasNestedExecutions && !agent._currentExecution) {
@@ -440,7 +441,21 @@ async function applyValidatorJitter(agent) {
440
441
  `[Agent ${agent.id}] Adding ${Math.round(jitterMs / 1000)}s jitter to prevent lock contention`
441
442
  );
442
443
  }
443
- await new Promise((resolve) => setTimeout(resolve, jitterMs));
444
+ await new Promise((resolve) => {
445
+ let settled = false;
446
+ let timer;
447
+ let cancel;
448
+ const finish = () => {
449
+ if (settled) return;
450
+ settled = true;
451
+ clearTimeout(timer);
452
+ if (agent._cancelStartDelay === cancel) agent._cancelStartDelay = null;
453
+ resolve();
454
+ };
455
+ cancel = finish;
456
+ timer = setTimeout(finish, jitterMs);
457
+ agent._cancelStartDelay = cancel;
458
+ });
444
459
  }
445
460
 
446
461
  function publishTaskStarted(agent, triggeringMessage) {
@@ -641,6 +656,7 @@ async function runTaskAttempt(agent, triggeringMessage) {
641
656
  // Spawn provider task
642
657
  agent.state = 'executing_task';
643
658
  await applyValidatorJitter(agent);
659
+ if (!agent.running) return;
644
660
  publishTaskStarted(agent, triggeringMessage);
645
661
 
646
662
  let result;
@@ -18,6 +18,7 @@ const { StringDecoder } = require('string_decoder');
18
18
  const { getNestedExecutionRegistry, TaskExecutionHandle } = require('./task-execution-handle');
19
19
  const os = require('os');
20
20
  const { parseProviderChunk, getProvider } = require('../providers');
21
+ const { decodeTaskLogLine } = require('../task-log-line');
21
22
  const { getTask, getTaskBySpawnOwnershipToken } = require('../../task-lib/store.js');
22
23
  const { OMP_SESSIONLESS_ENV } = require('../../task-lib/omp-storage-root.js');
23
24
  const { loadSettings } = require('../../lib/settings.js');
@@ -1268,9 +1269,10 @@ async function waitForTaskReady(agent, taskId, maxRetries = 10, delayMs = 200) {
1268
1269
 
1269
1270
  const MAX_STATUS_FAILURES = 30;
1270
1271
 
1271
- function createLogFollowState() {
1272
+ function createLogFollowState(taskId = null) {
1272
1273
  const state = {
1273
1274
  controlPlaneOutput: createControlPlaneOutputState(),
1275
+ taskId,
1274
1276
  logFilePath: null,
1275
1277
  lastSize: 0,
1276
1278
  pollInterval: null,
@@ -1471,28 +1473,26 @@ function lookupLogFilePath(ctPath, taskId) {
1471
1473
  }
1472
1474
 
1473
1475
  function parseTimestampedLine(line) {
1474
- let timestamp = Date.now();
1475
- let content = line.replace(/\r$/, '');
1476
- let timestamped = false;
1477
-
1478
- const timestampMatch = content.match(/^\[(\d{13})\](.*)$/);
1479
- if (timestampMatch) {
1480
- timestamp = parseInt(timestampMatch[1], 10);
1481
- content = timestampMatch[2];
1482
- timestamped = true;
1483
- }
1484
-
1485
- return { timestamp, content, timestamped };
1476
+ const decoded = decodeTaskLogLine(line);
1477
+ return {
1478
+ timestamp: decoded.timestamp ?? Date.now(),
1479
+ content: decoded.content,
1480
+ timestamped: decoded.timestamped,
1481
+ providerOutput: decoded.providerOutput,
1482
+ providerStdoutFramed: decoded.channel === 'provider_stdout',
1483
+ };
1486
1484
  }
1487
1485
 
1488
- function shouldSkipLogLine(content, providerName, timestamped) {
1486
+ function shouldSkipLogLine(
1487
+ content,
1488
+ providerName,
1489
+ timestamped,
1490
+ providerOutput,
1491
+ providerStdoutFramed = false
1492
+ ) {
1493
+ if (!providerOutput) return true;
1494
+ if (providerStdoutFramed) return false;
1489
1495
  if (providerName === 'pi') {
1490
- if (
1491
- content.startsWith('[ZEROSHOT][PROVIDER_STDERR] ') ||
1492
- content.startsWith('[ZEROSHOT][FATAL] ')
1493
- ) {
1494
- return true;
1495
- }
1496
1496
  if (timestamped) return false;
1497
1497
  return (
1498
1498
  /^={50}$/.test(content) ||
@@ -1504,7 +1504,6 @@ function shouldSkipLogLine(content, providerName, timestamped) {
1504
1504
  content.startsWith('===') ||
1505
1505
  content.startsWith('Finished:') ||
1506
1506
  content.startsWith('Exit code:') ||
1507
- content.startsWith('[ZEROSHOT][PROVIDER_STDERR] ') ||
1508
1507
  (content.includes('"type":"system"') && content.includes('"subtype":"init"'))
1509
1508
  );
1510
1509
  }
@@ -1522,7 +1521,7 @@ function isValidJsonLine(content) {
1522
1521
  }
1523
1522
  }
1524
1523
 
1525
- function publishAgentOutputRecord(agent, providerName, record) {
1524
+ function publishAgentOutputRecord(agent, providerName, taskId, record) {
1526
1525
  agent._publish({
1527
1526
  topic: 'AGENT_OUTPUT',
1528
1527
  receiver: 'broadcast',
@@ -1536,6 +1535,7 @@ function publishAgentOutputRecord(agent, providerName, record) {
1536
1535
  role: agent.role,
1537
1536
  iteration: agent.iteration,
1538
1537
  provider: providerName,
1538
+ ...(taskId ? { taskId } : {}),
1539
1539
  },
1540
1540
  },
1541
1541
  });
@@ -1545,8 +1545,9 @@ function broadcastAgentLine({ agent, providerName, state, line }) {
1545
1545
  const followerState = ensureControlPlaneOutputState(state);
1546
1546
  if (!line.trim()) return;
1547
1547
 
1548
- const { timestamp, content, timestamped } = parseTimestampedLine(line);
1549
- if (shouldSkipLogLine(content, providerName, timestamped)) {
1548
+ const { timestamp, content, timestamped, providerOutput, providerStdoutFramed } =
1549
+ parseTimestampedLine(line);
1550
+ if (shouldSkipLogLine(content, providerName, timestamped, providerOutput, providerStdoutFramed)) {
1550
1551
  return;
1551
1552
  }
1552
1553
  const controlPlaneContent = redactTerminalFailureForControlPlane(
@@ -1567,14 +1568,14 @@ function broadcastAgentLine({ agent, providerName, state, line }) {
1567
1568
  }
1568
1569
 
1569
1570
  publishLiveControlPlaneRecord(followerState.controlPlaneOutput, record, (item) =>
1570
- publishAgentOutputRecord(agent, providerName, item)
1571
+ publishAgentOutputRecord(agent, providerName, followerState.taskId, item)
1571
1572
  );
1572
1573
  }
1573
1574
 
1574
1575
  function flushAgentOutput(agent, providerName, state) {
1575
1576
  const followerState = ensureControlPlaneOutputState(state);
1576
1577
  flushTerminalControlPlaneOutput(followerState.controlPlaneOutput, (record) =>
1577
- publishAgentOutputRecord(agent, providerName, record)
1578
+ publishAgentOutputRecord(agent, providerName, followerState.taskId, record)
1578
1579
  );
1579
1580
  }
1580
1581
 
@@ -2117,7 +2118,7 @@ function createLogFollower({
2117
2118
  executionHandle = null,
2118
2119
  }) {
2119
2120
  return new Promise((resolve, reject) => {
2120
- const state = createLogFollowState();
2121
+ const state = createLogFollowState(taskId);
2121
2122
  state.skipStructuredResultCheck = skipStructuredResultCheck;
2122
2123
  state.nested = nested;
2123
2124
  state.logFilePath = lookupLogFilePath(ctPath, taskId);
@@ -3022,17 +3023,6 @@ function buildIsolatedLifecycleHandle({
3022
3023
  };
3023
3024
  }
3024
3025
 
3025
- function parseIsolatedLogLine(line) {
3026
- const timestampMatch = line.match(/^\[(\d{13}|\d{4}-\d{2}-\d{2}T[^\]]+)\]\s*(.*)$/);
3027
- const timestamp = timestampMatch
3028
- ? /^\d{13}$/.test(timestampMatch[1])
3029
- ? Number.parseInt(timestampMatch[1], 10)
3030
- : new Date(timestampMatch[1]).getTime()
3031
- : Date.now();
3032
- const content = timestampMatch ? timestampMatch[2] : line;
3033
- return { timestamp, content, timestamped: timestampMatch !== null };
3034
- }
3035
-
3036
3026
  function publishIsolatedOutputRecord(agent, providerName, taskId, record) {
3037
3027
  agent.messageBus.publish({
3038
3028
  cluster_id: agent.cluster.id,
@@ -3052,8 +3042,14 @@ function publishIsolatedOutputRecord(agent, providerName, taskId, record) {
3052
3042
  }
3053
3043
 
3054
3044
  function retainIsolatedLine(state, providerName, line) {
3055
- const { timestamp, content, timestamped } = parseIsolatedLogLine(line);
3056
- if (!content.trim() || shouldSkipLogLine(content, providerName, timestamped)) return null;
3045
+ const { timestamp, content, timestamped, providerOutput, providerStdoutFramed } =
3046
+ parseTimestampedLine(line);
3047
+ if (
3048
+ !content.trim() ||
3049
+ shouldSkipLogLine(content, providerName, timestamped, providerOutput, providerStdoutFramed)
3050
+ ) {
3051
+ return null;
3052
+ }
3057
3053
  const controlPlaneContent = redactTerminalFailureForControlPlane(state, providerName, content);
3058
3054
  return appendControlPlaneRecord(state.controlPlaneOutput, {
3059
3055
  content: controlPlaneContent,
@@ -5,6 +5,20 @@ const piExtraction = require("./output-extraction-pi");
5
5
  const { MAX_CLI_ERROR_BYTES, cliErrorDetail } = errorDetail;
6
6
  const { isObjectRecord, parseJsonRecordLine } = jsonExtraction;
7
7
  const { extractSettledPiFailure } = piExtraction;
8
+ const OMP_SDK_ERROR_CODES = new Map([
9
+ ['invalid-request', 'request'],
10
+ ['model-resolution', 'model'],
11
+ ['model-fallback', 'model'],
12
+ ['provider-auth', 'auth'],
13
+ ['provider-rate-limit', 'rate-limit'],
14
+ ['provider-timeout', 'timeout'],
15
+ ['provider-error', 'provider'],
16
+ ['schema-violation', 'schema'],
17
+ ['cancelled', 'cancelled'],
18
+ ['sdk-error', 'sdk'],
19
+ ['cleanup-error', 'cleanup'],
20
+ ['internal-error', 'internal'],
21
+ ]);
8
22
  function firstTruthyValue(...values) {
9
23
  for (const value of values) {
10
24
  if (value)
@@ -54,6 +68,63 @@ function opencodeFailureFromObject(value) {
54
68
  const source = firstTruthyValue(recordField(recordField(error, 'data'), 'message'), recordField(error, 'message'), recordField(error, 'name'));
55
69
  return { ...cliErrorDetail(source, 'Session error'), provider: 'opencode' };
56
70
  }
71
+ function hasExactKeys(value, expected) {
72
+ return (Object.keys(value).length === expected.length &&
73
+ expected.every((key) => Object.prototype.hasOwnProperty.call(value, key)));
74
+ }
75
+ function isOmpSdkIdentity(value, nameField, expectedName, expectedVersion) {
76
+ return (isObjectRecord(value) &&
77
+ value[nameField] === expectedName &&
78
+ value.version === expectedVersion &&
79
+ hasExactKeys(value, [nameField, 'version']));
80
+ }
81
+ function ompSdkErrorMetadata(value) {
82
+ if (!isObjectRecord(value))
83
+ return null;
84
+ const { category, code, redacted, retryable } = value;
85
+ if (typeof code !== 'string' ||
86
+ typeof category !== 'string' ||
87
+ OMP_SDK_ERROR_CODES.get(code) !== category ||
88
+ typeof retryable !== 'boolean' ||
89
+ redacted !== true ||
90
+ !hasExactKeys(value, ['category', 'code', 'redacted', 'retryable'])) {
91
+ return null;
92
+ }
93
+ return { category, code, retryable };
94
+ }
95
+ function ompProviderCategory(error) {
96
+ if (error.category === 'auth')
97
+ return 'authentication';
98
+ return error.retryable ? 'transient' : 'permanent';
99
+ }
100
+ function isOmpSdkRunId(value) {
101
+ return (typeof value === 'string' &&
102
+ value.length <= 128 &&
103
+ /^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(value));
104
+ }
105
+ function isOmpSdkErrorEnvelope(value) {
106
+ return (value.protocolVersion === 1 &&
107
+ value.type === 'error' &&
108
+ isOmpSdkRunId(value.runId) &&
109
+ hasExactKeys(value, ['backend', 'error', 'protocolVersion', 'runId', 'runtime', 'type']) &&
110
+ isOmpSdkIdentity(value.backend, 'id', 'omp-sdk', '17.2.1') &&
111
+ isOmpSdkIdentity(value.runtime, 'name', 'bun', '1.3.14'));
112
+ }
113
+ function ompSdkFailureFromObject(value) {
114
+ const error = ompSdkErrorMetadata(value.error);
115
+ if (error === null || !isOmpSdkErrorEnvelope(value))
116
+ return null;
117
+ const detail = `OMP SDK ${error.code} (${error.category})`;
118
+ return {
119
+ ...cliErrorDetail(detail, 'OMP SDK turn failed'),
120
+ provider: 'omp',
121
+ providerCategory: ompProviderCategory(error),
122
+ providerClassification: {
123
+ retryable: error.retryable,
124
+ kind: error.retryable ? 'unknown-retryable' : 'permanent-pattern',
125
+ },
126
+ };
127
+ }
57
128
  function failureFromProviderObject(value, providerName) {
58
129
  if (!isObjectRecord(value))
59
130
  return null;
@@ -65,6 +136,8 @@ function failureFromProviderObject(value, providerName) {
65
136
  return geminiFailureFromObject(value);
66
137
  if (providerName === 'opencode')
67
138
  return opencodeFailureFromObject(value);
139
+ if (providerName === 'omp')
140
+ return ompSdkFailureFromObject(value);
68
141
  return null;
69
142
  }
70
143
  function vertexModelFromResult(parsed, useVertex) {
@@ -12,6 +12,21 @@ const { MAX_CLI_ERROR_BYTES, cliErrorDetail } = errorDetail;
12
12
  const { isObjectRecord, parseJsonRecordLine } = jsonExtraction;
13
13
  const { extractSettledPiFailure } = piExtraction;
14
14
 
15
+ const OMP_SDK_ERROR_CODES = new Map([
16
+ ['invalid-request', 'request'],
17
+ ['model-resolution', 'model'],
18
+ ['model-fallback', 'model'],
19
+ ['provider-auth', 'auth'],
20
+ ['provider-rate-limit', 'rate-limit'],
21
+ ['provider-timeout', 'timeout'],
22
+ ['provider-error', 'provider'],
23
+ ['schema-violation', 'schema'],
24
+ ['cancelled', 'cancelled'],
25
+ ['sdk-error', 'sdk'],
26
+ ['cleanup-error', 'cleanup'],
27
+ ['internal-error', 'internal'],
28
+ ]);
29
+
15
30
  function firstTruthyValue(...values: readonly unknown[]): unknown {
16
31
  for (const value of values) {
17
32
  if (value) return value;
@@ -71,12 +86,97 @@ function opencodeFailureFromObject(value: JsonRecord): CliFailure | null {
71
86
  return { ...cliErrorDetail(source, 'Session error'), provider: 'opencode' };
72
87
  }
73
88
 
89
+ function hasExactKeys(value: JsonRecord, expected: readonly string[]): boolean {
90
+ return (
91
+ Object.keys(value).length === expected.length &&
92
+ expected.every((key) => Object.prototype.hasOwnProperty.call(value, key))
93
+ );
94
+ }
95
+
96
+ function isOmpSdkIdentity(
97
+ value: unknown,
98
+ nameField: 'id' | 'name',
99
+ expectedName: string,
100
+ expectedVersion: string
101
+ ): boolean {
102
+ return (
103
+ isObjectRecord(value) &&
104
+ value[nameField] === expectedName &&
105
+ value.version === expectedVersion &&
106
+ hasExactKeys(value, [nameField, 'version'])
107
+ );
108
+ }
109
+
110
+ interface OmpSdkErrorMetadata {
111
+ readonly category: string;
112
+ readonly code: string;
113
+ readonly retryable: boolean;
114
+ }
115
+
116
+ function ompSdkErrorMetadata(value: unknown): OmpSdkErrorMetadata | null {
117
+ if (!isObjectRecord(value)) return null;
118
+ const { category, code, redacted, retryable } = value;
119
+ if (
120
+ typeof code !== 'string' ||
121
+ typeof category !== 'string' ||
122
+ OMP_SDK_ERROR_CODES.get(code) !== category ||
123
+ typeof retryable !== 'boolean' ||
124
+ redacted !== true ||
125
+ !hasExactKeys(value, ['category', 'code', 'redacted', 'retryable'])
126
+ ) {
127
+ return null;
128
+ }
129
+ return { category, code, retryable };
130
+ }
131
+
132
+ function ompProviderCategory(
133
+ error: OmpSdkErrorMetadata
134
+ ): NonNullable<CliFailure['providerCategory']> {
135
+ if (error.category === 'auth') return 'authentication';
136
+ return error.retryable ? 'transient' : 'permanent';
137
+ }
138
+
139
+ function isOmpSdkRunId(value: unknown): value is string {
140
+ return (
141
+ typeof value === 'string' &&
142
+ value.length <= 128 &&
143
+ /^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(value)
144
+ );
145
+ }
146
+
147
+ function isOmpSdkErrorEnvelope(value: JsonRecord): boolean {
148
+ return (
149
+ value.protocolVersion === 1 &&
150
+ value.type === 'error' &&
151
+ isOmpSdkRunId(value.runId) &&
152
+ hasExactKeys(value, ['backend', 'error', 'protocolVersion', 'runId', 'runtime', 'type']) &&
153
+ isOmpSdkIdentity(value.backend, 'id', 'omp-sdk', '17.2.1') &&
154
+ isOmpSdkIdentity(value.runtime, 'name', 'bun', '1.3.14')
155
+ );
156
+ }
157
+
158
+ function ompSdkFailureFromObject(value: JsonRecord): CliFailure | null {
159
+ const error = ompSdkErrorMetadata(value.error);
160
+ if (error === null || !isOmpSdkErrorEnvelope(value)) return null;
161
+ const detail = `OMP SDK ${error.code} (${error.category})`;
162
+ return {
163
+ ...cliErrorDetail(detail, 'OMP SDK turn failed'),
164
+ provider: 'omp',
165
+ providerCategory: ompProviderCategory(error),
166
+ providerClassification: {
167
+ retryable: error.retryable,
168
+ kind: error.retryable ? 'unknown-retryable' : 'permanent-pattern',
169
+ },
170
+ };
171
+ }
172
+
74
173
  function failureFromProviderObject(value: unknown, providerName: string): CliFailure | null {
75
174
  if (!isObjectRecord(value)) return null;
76
175
  if (providerName === 'claude') return claudeFailureFromObject(value);
77
176
  if (providerName === 'codex') return codexFailureFromObject(value);
78
177
  if (providerName === 'gemini') return geminiFailureFromObject(value);
79
178
  if (providerName === 'opencode') return opencodeFailureFromObject(value);
179
+ if (providerName === 'omp') return ompSdkFailureFromObject(value);
80
180
  return null;
81
181
  }
82
182
 
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ const task_log_line_1 = require("../task-log-line");
2
3
  function isObjectRecord(value) {
3
4
  return value !== null && typeof value === 'object' && !Array.isArray(value);
4
5
  }
@@ -14,10 +15,6 @@ if (!isProvidersParserBoundary(rawProviders)) {
14
15
  throw new TypeError('providers module must expose parseProviderChunk');
15
16
  }
16
17
  const { parseProviderChunk } = rawProviders;
17
- function timestampBody(text) {
18
- const match = /^\[(\d{13})\](.*)$/.exec(text);
19
- return match ? (match[2] || '').trimStart() : null;
20
- }
21
18
  function prefixedJsonBody(text) {
22
19
  if (text.startsWith('{') || text.startsWith('['))
23
20
  return null;
@@ -33,8 +30,10 @@ function stripTimestamp(line) {
33
30
  const normalized = line.trim().replace(/\r$/, '');
34
31
  if (!normalized)
35
32
  return '';
36
- const withoutTimestamp = timestampBody(normalized) ?? normalized;
37
- return prefixedJsonBody(withoutTimestamp) ?? withoutTimestamp;
33
+ const decoded = (0, task_log_line_1.decodeTaskLogLine)(normalized);
34
+ if (!decoded.providerOutput)
35
+ return '';
36
+ return prefixedJsonBody(decoded.content) ?? decoded.content;
38
37
  }
39
38
  function parseJsonRecordLine(line) {
40
39
  const content = stripTimestamp(line);
@@ -1,4 +1,5 @@
1
1
  import type { JsonRecord, ProvidersParserBoundary } from './output-extraction-types';
2
+ import { decodeTaskLogLine } from '../task-log-line';
2
3
 
3
4
  function isObjectRecord(value: unknown): value is JsonRecord {
4
5
  return value !== null && typeof value === 'object' && !Array.isArray(value);
@@ -20,11 +21,6 @@ if (!isProvidersParserBoundary(rawProviders)) {
20
21
  }
21
22
  const { parseProviderChunk } = rawProviders;
22
23
 
23
- function timestampBody(text: string): string | null {
24
- const match = /^\[(\d{13})\](.*)$/.exec(text);
25
- return match ? (match[2] || '').trimStart() : null;
26
- }
27
-
28
24
  function prefixedJsonBody(text: string): string | null {
29
25
  if (text.startsWith('{') || text.startsWith('[')) return null;
30
26
  const separatorIndex = text.indexOf('|');
@@ -38,8 +34,9 @@ function stripTimestamp(line: unknown): string {
38
34
  const normalized = line.trim().replace(/\r$/, '');
39
35
  if (!normalized) return '';
40
36
 
41
- const withoutTimestamp = timestampBody(normalized) ?? normalized;
42
- return prefixedJsonBody(withoutTimestamp) ?? withoutTimestamp;
37
+ const decoded = decodeTaskLogLine(normalized);
38
+ if (!decoded.providerOutput) return '';
39
+ return prefixedJsonBody(decoded.content) ?? decoded.content;
43
40
  }
44
41
 
45
42
  function parseJsonRecordLine(line: string): JsonRecord | null {
@@ -16,6 +16,11 @@ export interface CliErrorDetail {
16
16
 
17
17
  export interface CliFailure extends CliErrorDetail {
18
18
  provider: string;
19
+ providerCategory?: 'authentication' | 'permanent' | 'transient';
20
+ providerClassification?: {
21
+ retryable: boolean;
22
+ kind: 'permanent-pattern' | 'unknown-retryable';
23
+ };
19
24
  }
20
25
 
21
26
  export interface CliError {
@@ -73,8 +73,8 @@ function extractProviderFailure(output, providerName) {
73
73
  const cliError = extractCliFailure(output, providerName);
74
74
  if (!cliError)
75
75
  return null;
76
- const classification = classifyProviderFailure(providerName, cliError.error);
77
- const category = categoryForProviderFailure(cliError.error, classification);
76
+ const classification = cliError.providerClassification ?? classifyProviderFailure(providerName, cliError.error);
77
+ const category = cliError.providerCategory ?? categoryForProviderFailure(cliError.error, classification);
78
78
  return {
79
79
  error: `Provider ${cliError.provider} failed (${category}; ${classification.kind})`,
80
80
  provider: cliError.provider,
@@ -89,8 +89,10 @@ function extractProviderFailure(output: string, providerName: string): ProviderF
89
89
  const cliError = extractCliFailure(output, providerName);
90
90
  if (!cliError) return null;
91
91
 
92
- const classification = classifyProviderFailure(providerName, cliError.error);
93
- const category = categoryForProviderFailure(cliError.error, classification);
92
+ const classification =
93
+ cliError.providerClassification ?? classifyProviderFailure(providerName, cliError.error);
94
+ const category =
95
+ cliError.providerCategory ?? categoryForProviderFailure(cliError.error, classification);
94
96
  return {
95
97
  error: `Provider ${cliError.provider} failed (${category}; ${classification.kind})`,
96
98
  provider: cliError.provider,
@@ -315,7 +315,7 @@ export const claudeAdapter: StructuredOutputRecoveryAdapter = {
315
315
  displayName: 'Claude',
316
316
  binary: 'claude',
317
317
  adapterVersion: '1',
318
- credentialEnvKeys: ['ANTHROPIC_API_KEY', 'CLAUDE_API_KEY'],
318
+ credentialEnvKeys: ['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'CLAUDE_API_KEY'],
319
319
  modelCatalog: MODEL_CATALOG,
320
320
  levelMapping: LEVEL_MAPPING,
321
321
  defaultLevel: 'level2',