@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.
- package/README.md +45 -1
- package/cli/agent-provider-boundary.js +19 -0
- package/cli/agent-provider-boundary.ts +79 -0
- package/cli/export-stream.js +94 -0
- package/cli/export-stream.ts +118 -0
- package/cli/index.js +132 -61
- package/cli/json-export.js +2 -38
- package/cli/json-export.ts +2 -56
- package/cli/semantic-canonical.js +60 -0
- package/cli/semantic-canonical.ts +59 -0
- package/cli/semantic-contract.js +97 -0
- package/cli/semantic-contract.ts +153 -0
- package/cli/semantic-events.js +53 -0
- package/cli/semantic-events.ts +65 -0
- package/cli/semantic-evidence.js +63 -0
- package/cli/semantic-evidence.ts +65 -0
- package/cli/semantic-export.js +186 -0
- package/cli/semantic-export.ts +245 -0
- package/cli/semantic-json.js +69 -0
- package/cli/semantic-json.ts +69 -0
- package/cli/semantic-line-scanner.js +56 -0
- package/cli/semantic-line-scanner.ts +54 -0
- package/cli/semantic-parser.js +78 -0
- package/cli/semantic-parser.ts +95 -0
- package/cli/semantic-provider-line.js +91 -0
- package/cli/semantic-provider-line.ts +106 -0
- package/cli/trace-evidence.js +86 -0
- package/cli/trace-evidence.ts +115 -0
- package/cli/trace-export.js +120 -0
- package/cli/trace-export.ts +164 -0
- package/cli/trace-output-record.js +15 -0
- package/cli/trace-output-record.ts +18 -0
- package/cli/trace-output.js +98 -0
- package/cli/trace-output.ts +119 -0
- package/cluster-templates/conductor-bootstrap.json +1 -1
- package/lib/agent-cli-provider/adapters/claude.js +1 -1
- package/lib/agent-cli-provider/adapters/claude.js.map +1 -1
- package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/codex.js +26 -1
- package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
- package/lib/agent-cli-provider/adapters/omp.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/omp.js +1 -1
- package/lib/agent-cli-provider/adapters/omp.js.map +1 -1
- package/lib/agent-cli-provider/log-prefix.d.ts.map +1 -1
- package/lib/agent-cli-provider/log-prefix.js +8 -6
- package/lib/agent-cli-provider/log-prefix.js.map +1 -1
- package/lib/agent-cli-provider/omp/sdk-environment-policy.d.ts +4 -0
- package/lib/agent-cli-provider/omp/sdk-environment-policy.d.ts.map +1 -0
- package/lib/agent-cli-provider/omp/sdk-environment-policy.js +37 -0
- package/lib/agent-cli-provider/omp/sdk-environment-policy.js.map +1 -0
- package/lib/agent-cli-provider/omp/sdk-process-private-runtime.d.ts.map +1 -1
- package/lib/agent-cli-provider/omp/sdk-process-private-runtime.js +4 -15
- package/lib/agent-cli-provider/omp/sdk-process-private-runtime.js.map +1 -1
- package/lib/agent-cli-provider/omp/sdk-process-result.d.ts +2 -0
- package/lib/agent-cli-provider/omp/sdk-process-result.d.ts.map +1 -1
- package/lib/agent-cli-provider/omp/sdk-process-result.js +2 -2
- package/lib/agent-cli-provider/omp/sdk-process-result.js.map +1 -1
- package/lib/agent-cli-provider/omp/sdk-process-runner.d.ts.map +1 -1
- package/lib/agent-cli-provider/omp/sdk-process-runner.js +6 -1
- package/lib/agent-cli-provider/omp/sdk-process-runner.js.map +1 -1
- package/lib/agent-cli-provider/provider-registry.d.ts +3 -1
- package/lib/agent-cli-provider/provider-registry.d.ts.map +1 -1
- package/lib/agent-cli-provider/provider-registry.js +9 -2
- package/lib/agent-cli-provider/provider-registry.js.map +1 -1
- package/lib/agent-cli-provider/single-agent-runtime.d.ts +4 -1
- package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -1
- package/lib/agent-cli-provider/single-agent-runtime.js +18 -15
- package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -1
- package/lib/agent-cli-provider/types.d.ts +3 -0
- package/lib/agent-cli-provider/types.d.ts.map +1 -1
- package/lib/agent-cli-provider/types.js.map +1 -1
- package/lib/cluster-worker/engine-adapter-common.js +18 -0
- package/lib/cluster-worker/engine-adapter.js +2 -1
- package/lib/git-remote-utils.js +22 -5
- package/lib/stream-json-parser.js +6 -5
- package/npm-shrinkwrap.json +2 -2
- package/package.json +7 -4
- package/scripts/omp/runtime-identities.js +31 -18
- package/scripts/omp/runtime.js +2 -0
- package/src/agent/agent-lifecycle.js +17 -1
- package/src/agent/agent-task-executor.js +36 -40
- package/src/agent/output-extraction-failures.js +73 -0
- package/src/agent/output-extraction-failures.ts +100 -0
- package/src/agent/output-extraction-json.js +5 -6
- package/src/agent/output-extraction-json.ts +4 -7
- package/src/agent/output-extraction-types.ts +5 -0
- package/src/agent/provider-terminal-failure.js +2 -2
- package/src/agent/provider-terminal-failure.ts +4 -2
- package/src/agent-cli-provider/adapters/claude.ts +1 -1
- package/src/agent-cli-provider/adapters/codex.ts +36 -1
- package/src/agent-cli-provider/adapters/omp.ts +2 -1
- package/src/agent-cli-provider/log-prefix.ts +12 -7
- package/src/agent-cli-provider/omp/sdk-environment-policy.ts +38 -0
- package/src/agent-cli-provider/omp/sdk-process-private-runtime.ts +4 -16
- package/src/agent-cli-provider/omp/sdk-process-result.ts +4 -2
- package/src/agent-cli-provider/omp/sdk-process-runner.ts +7 -1
- package/src/agent-cli-provider/provider-registry.ts +10 -2
- package/src/agent-cli-provider/single-agent-runtime.ts +24 -15
- package/src/agent-cli-provider/types.ts +3 -0
- package/src/agents/git-pusher-template.js +61 -71
- package/src/attach/socket-paths.js +1 -1
- package/src/attach/socket-paths.ts +1 -1
- package/src/claude-task-runner.js +9 -9
- package/src/foreground-benchmark-run.js +24 -12
- package/src/legacy-lib/git-remote-utils.ts +23 -5
- package/src/legacy-lib/stream-json-parser.ts +10 -5
- package/src/omp-session-verifier.js +8 -5
- package/src/orchestrator.js +42 -0
- package/src/preflight.js +31 -6
- package/src/providers/index.js +4 -22
- package/src/task-execution-context.js +22 -0
- package/src/task-log-line.d.ts +20 -0
- package/src/task-log-line.js +80 -0
- package/src/watcher-prompt-channel.js +1 -1
- package/src/worktree-claude-config.js +25 -0
- package/src/worktree-claude-config.ts +28 -0
- package/task-lib/commands/logs.js +5 -8
- package/task-lib/runner.js +57 -22
- package/task-lib/sdk-watcher-output.js +31 -0
- package/task-lib/sdk-watcher.js +4 -11
- 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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
};
|
package/scripts/omp/runtime.js
CHANGED
|
@@ -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) =>
|
|
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
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
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(
|
|
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 } =
|
|
1549
|
-
|
|
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 } =
|
|
3056
|
-
|
|
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
|
|
37
|
-
|
|
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
|
|
42
|
-
|
|
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 =
|
|
93
|
-
|
|
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',
|