@the-open-engine/zeroshot 6.38.0 → 6.39.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/cli/event-copy.js +8 -7
- package/cli/event-copy.ts +12 -0
- package/cli/index.js +7 -31
- package/cli/json-export.js +61 -64
- package/cli/json-export.ts +112 -0
- package/cli/message-formatter-utils.js +68 -56
- package/cli/message-formatter-utils.ts +121 -0
- package/cli/message-formatters-normal.js +124 -259
- package/cli/message-formatters-normal.ts +250 -0
- package/cli/message-formatters-watch.js +81 -84
- package/cli/message-formatters-watch.ts +189 -0
- package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
- package/lib/agent-cli-provider/adapters/codex.js +3 -1
- package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
- package/lib/cluster/generated/protocol-schema.cjs +1 -1
- package/lib/cluster/generated/protocol-schema.mjs +1 -1
- package/lib/cluster/generated/protocol.d.cts +8 -0
- package/lib/cluster/generated/protocol.d.mts +8 -0
- package/lib/cluster/generated/protocol.d.ts +8 -0
- package/lib/clusters-registry.d.ts +23 -0
- package/lib/clusters-registry.js +17 -29
- package/lib/completion.d.ts +12 -0
- package/lib/completion.js +84 -94
- package/lib/compose-utils.d.ts +32 -0
- package/lib/compose-utils.js +57 -72
- package/lib/detached-startup.d.ts +83 -0
- package/lib/detached-startup.js +231 -302
- package/lib/docker-config.d.ts +43 -0
- package/lib/docker-config.js +150 -325
- package/lib/docker-env-auth.d.ts +17 -0
- package/lib/docker-env-auth.js +75 -0
- package/lib/git-remote-utils.d.ts +48 -0
- package/lib/git-remote-utils.js +147 -213
- package/lib/id-detector.d.ts +15 -0
- package/lib/id-detector.js +37 -41
- package/lib/path-check.d.ts +30 -0
- package/lib/path-check.js +42 -45
- package/lib/process-liveness.d.ts +16 -0
- package/lib/process-liveness.js +19 -12
- package/lib/provider-credential-path.d.ts +16 -0
- package/lib/provider-credential-path.js +31 -29
- package/lib/provider-defaults.d.ts +30 -0
- package/lib/provider-defaults.js +47 -42
- package/lib/provider-detection.d.ts +11 -0
- package/lib/provider-detection.js +91 -54
- package/lib/provider-names.d.ts +38 -0
- package/lib/provider-names.js +56 -64
- package/lib/repo-settings.d.ts +28 -0
- package/lib/repo-settings.js +83 -59
- package/lib/run-mode.d.ts +21 -0
- package/lib/run-mode.js +21 -20
- package/lib/run-plan.d.ts +28 -0
- package/lib/run-plan.js +17 -16
- package/lib/settings/claude-auth.d.ts +35 -0
- package/lib/settings/claude-auth.js +30 -47
- package/lib/settings-defaults.d.ts +20 -0
- package/lib/settings-defaults.js +149 -0
- package/lib/settings-error.d.ts +7 -0
- package/lib/settings-error.js +8 -0
- package/lib/settings-issue-providers.d.ts +10 -0
- package/lib/settings-issue-providers.js +12 -0
- package/lib/settings-models.d.ts +22 -0
- package/lib/settings-models.js +93 -0
- package/lib/settings-storage.d.ts +23 -0
- package/lib/settings-storage.js +205 -0
- package/lib/settings-validation.d.ts +7 -0
- package/lib/settings-validation.js +182 -0
- package/lib/settings.d.ts +29 -0
- package/lib/settings.js +41 -736
- package/lib/setup-apply-types.d.ts +66 -0
- package/lib/setup-apply-types.js +2 -0
- package/lib/setup-apply.d.ts +39 -0
- package/lib/setup-apply.js +267 -264
- package/lib/setup-journal.d.ts +41 -0
- package/lib/setup-journal.js +119 -76
- package/lib/setup-plan-types.d.ts +102 -0
- package/lib/setup-plan-types.js +2 -0
- package/lib/setup-plan.d.ts +30 -0
- package/lib/setup-plan.js +300 -324
- package/lib/setup-undo.d.ts +44 -0
- package/lib/setup-undo.js +61 -74
- package/lib/start-cluster-config.d.ts +26 -0
- package/lib/start-cluster-config.js +56 -0
- package/lib/start-cluster-environment.d.ts +40 -0
- package/lib/start-cluster-environment.js +134 -0
- package/lib/start-cluster-run-options.d.ts +53 -0
- package/lib/start-cluster-run-options.js +147 -0
- package/lib/start-cluster.d.ts +64 -0
- package/lib/start-cluster.js +98 -454
- package/lib/stream-json-parser.d.ts +17 -0
- package/lib/stream-json-parser.js +51 -52
- package/npm-shrinkwrap.json +2 -2
- package/package.json +12 -6
- package/scripts/postinstall.js +27 -0
- package/scripts/rust-distribution.js +23 -14
- package/src/agent/agent-command-proofs-context.js +35 -45
- package/src/agent/agent-command-proofs-context.ts +87 -0
- package/src/agent/agent-config-settings.js +19 -0
- package/src/agent/agent-config-settings.ts +41 -0
- package/src/agent/agent-config.js +122 -231
- package/src/agent/agent-config.ts +285 -0
- package/src/agent/agent-context-builder.js +38 -273
- package/src/agent/agent-context-builder.ts +51 -0
- package/src/agent/agent-context-environment-sections.js +105 -0
- package/src/agent/agent-context-environment-sections.ts +134 -0
- package/src/agent/agent-context-packs.js +165 -0
- package/src/agent/agent-context-packs.ts +296 -0
- package/src/agent/agent-context-prompt-sections.js +100 -0
- package/src/agent/agent-context-prompt-sections.ts +148 -0
- package/src/agent/agent-context-sections.js +25 -334
- package/src/agent/agent-context-sections.ts +36 -0
- package/src/agent/agent-context-sources.js +96 -149
- package/src/agent/agent-context-sources.ts +253 -0
- package/src/agent/agent-context-types.js +2 -0
- package/src/agent/agent-context-types.ts +132 -0
- package/src/agent/agent-context-validation-sections.js +73 -0
- package/src/agent/agent-context-validation-sections.ts +129 -0
- package/src/agent/agent-input-injector.js +99 -118
- package/src/agent/agent-input-injector.ts +195 -0
- package/src/agent/agent-liveness-poll.js +74 -78
- package/src/agent/agent-liveness-poll.ts +163 -0
- package/src/agent/agent-quality-gate-schema.js +77 -86
- package/src/agent/agent-quality-gate-schema.ts +135 -0
- package/src/agent/agent-quality-gates-context.js +44 -50
- package/src/agent/agent-quality-gates-context.ts +91 -0
- package/src/agent/agent-stuck-detector.js +171 -239
- package/src/agent/agent-stuck-detector.ts +288 -0
- package/src/agent/agent-trigger-evaluator.js +29 -46
- package/src/agent/agent-trigger-evaluator.ts +98 -0
- package/src/agent/context-metrics.js +110 -141
- package/src/agent/context-metrics.ts +261 -0
- package/src/agent/context-pack-builder.js +72 -358
- package/src/agent/context-pack-builder.ts +105 -0
- package/src/agent/context-pack-core.js +70 -0
- package/src/agent/context-pack-core.ts +96 -0
- package/src/agent/context-pack-selection.js +119 -0
- package/src/agent/context-pack-selection.ts +187 -0
- package/src/agent/context-pack-truncation.js +139 -0
- package/src/agent/context-pack-truncation.ts +208 -0
- package/src/agent/context-pack-types.js +2 -0
- package/src/agent/context-pack-types.ts +98 -0
- package/src/agent/context-replay-policy.js +30 -39
- package/src/agent/context-replay-policy.ts +71 -0
- package/src/agent/critical-agent-policy.js +6 -10
- package/src/agent/critical-agent-policy.ts +20 -0
- package/src/agent/guidance-queue.js +74 -87
- package/src/agent/guidance-queue.ts +166 -0
- package/src/agent/output-extraction-error-detail.js +45 -0
- package/src/agent/output-extraction-error-detail.ts +49 -0
- package/src/agent/output-extraction-failures.js +125 -0
- package/src/agent/output-extraction-failures.ts +149 -0
- package/src/agent/output-extraction-json.js +234 -0
- package/src/agent/output-extraction-json.ts +235 -0
- package/src/agent/output-extraction-pi.js +124 -0
- package/src/agent/output-extraction-pi.ts +137 -0
- package/src/agent/output-extraction-types.js +2 -0
- package/src/agent/output-extraction-types.ts +49 -0
- package/src/agent/output-extraction.js +17 -617
- package/src/agent/output-extraction.ts +30 -0
- package/src/agent/output-reformatter-errors.js +83 -0
- package/src/agent/output-reformatter-errors.ts +106 -0
- package/src/agent/output-reformatter-types.js +2 -0
- package/src/agent/output-reformatter-types.ts +86 -0
- package/src/agent/output-reformatter.js +140 -185
- package/src/agent/output-reformatter.ts +238 -0
- package/src/agent/pi-terminal-lifecycle-types.js +2 -0
- package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
- package/src/agent/pi-terminal-lifecycle.js +186 -206
- package/src/agent/pi-terminal-lifecycle.ts +297 -0
- package/src/agent/provider-control-plane.js +22 -21
- package/src/agent/provider-control-plane.ts +52 -0
- package/src/agent/provider-terminal-failure-types.js +2 -0
- package/src/agent/provider-terminal-failure-types.ts +60 -0
- package/src/agent/provider-terminal-failure.js +194 -191
- package/src/agent/provider-terminal-failure.ts +262 -0
- package/src/agent/rate-limit-backoff.js +31 -74
- package/src/agent/rate-limit-backoff.ts +71 -0
- package/src/agent/schema-utils.js +85 -125
- package/src/agent/schema-utils.ts +148 -0
- package/src/agent/structured-output-error.js +34 -33
- package/src/agent/structured-output-error.ts +105 -0
- package/src/agent/validation-platform.js +27 -27
- package/src/agent/validation-platform.ts +49 -0
- package/src/agent-cli-provider/adapters/codex.ts +3 -1
- package/src/attach/attach-client.js +232 -405
- package/src/attach/attach-client.ts +300 -0
- package/src/attach/attach-server-cleanup.js +43 -0
- package/src/attach/attach-server-cleanup.ts +39 -0
- package/src/attach/attach-server-clients.js +117 -0
- package/src/attach/attach-server-clients.ts +122 -0
- package/src/attach/attach-server-events.js +38 -0
- package/src/attach/attach-server-events.ts +36 -0
- package/src/attach/attach-server-pty.js +45 -0
- package/src/attach/attach-server-pty.ts +64 -0
- package/src/attach/attach-server-runtime.js +73 -0
- package/src/attach/attach-server-runtime.ts +62 -0
- package/src/attach/attach-server-socket.js +28 -0
- package/src/attach/attach-server-socket.ts +23 -0
- package/src/attach/attach-server-types.js +2 -0
- package/src/attach/attach-server-types.ts +82 -0
- package/src/attach/attach-server.js +106 -523
- package/src/attach/attach-server.ts +158 -0
- package/src/attach/index.js +18 -35
- package/src/attach/index.ts +18 -0
- package/src/attach/protocol.js +95 -184
- package/src/attach/protocol.ts +181 -0
- package/src/attach/ring-buffer.js +76 -102
- package/src/attach/ring-buffer.ts +109 -0
- package/src/attach/send-input.js +64 -75
- package/src/attach/send-input.ts +94 -0
- package/src/attach/socket-discovery.js +164 -218
- package/src/attach/socket-discovery.ts +230 -0
- package/src/attach/socket-paths.js +42 -61
- package/src/attach/socket-paths.ts +81 -0
- package/src/claude-credentials.js +51 -54
- package/src/claude-credentials.ts +89 -0
- package/src/cluster/generated/protocol-schema.ts +1 -1
- package/src/cluster/generated/protocol.ts +2 -1
- package/src/command-proofs.js +110 -141
- package/src/command-proofs.ts +216 -0
- package/src/config-router.js +81 -73
- package/src/config-router.ts +131 -0
- package/src/copy-worker.js +53 -29
- package/src/copy-worker.ts +75 -0
- package/src/darwin-keychain-boundary.js +80 -111
- package/src/darwin-keychain-boundary.ts +148 -0
- package/src/guidance-topics.js +4 -5
- package/src/guidance-topics.ts +10 -0
- package/src/input-helpers.js +33 -54
- package/src/input-helpers.ts +58 -0
- package/src/ledger-sequence.js +45 -48
- package/src/ledger-sequence.ts +63 -0
- package/src/legacy-lib/clusters-registry.ts +40 -0
- package/src/legacy-lib/completion.ts +148 -0
- package/src/legacy-lib/compose-utils.ts +102 -0
- package/src/legacy-lib/detached-startup.ts +449 -0
- package/src/legacy-lib/docker-config.ts +282 -0
- package/src/legacy-lib/docker-env-auth.ts +116 -0
- package/src/legacy-lib/git-remote-utils.ts +244 -0
- package/src/legacy-lib/id-detector.ts +57 -0
- package/src/legacy-lib/js-yaml.d.ts +3 -0
- package/src/legacy-lib/omelette.d.ts +15 -0
- package/src/legacy-lib/path-check.ts +89 -0
- package/src/legacy-lib/process-liveness.ts +36 -0
- package/src/legacy-lib/provider-credential-path.ts +57 -0
- package/src/legacy-lib/provider-defaults.ts +114 -0
- package/src/legacy-lib/provider-detection.ts +67 -0
- package/src/legacy-lib/provider-names.ts +126 -0
- package/src/legacy-lib/repo-settings.ts +88 -0
- package/src/legacy-lib/run-mode.ts +58 -0
- package/src/legacy-lib/run-plan.ts +49 -0
- package/src/legacy-lib/settings/claude-auth.ts +80 -0
- package/src/legacy-lib/settings-defaults.ts +212 -0
- package/src/legacy-lib/settings-error.ts +8 -0
- package/src/legacy-lib/settings-issue-providers.ts +18 -0
- package/src/legacy-lib/settings-models.ts +124 -0
- package/src/legacy-lib/settings-storage.ts +277 -0
- package/src/legacy-lib/settings-validation.ts +220 -0
- package/src/legacy-lib/settings.ts +87 -0
- package/src/legacy-lib/setup-apply-types.ts +70 -0
- package/src/legacy-lib/setup-apply.ts +456 -0
- package/src/legacy-lib/setup-journal.ts +185 -0
- package/src/legacy-lib/setup-plan-types.ts +96 -0
- package/src/legacy-lib/setup-plan.ts +500 -0
- package/src/legacy-lib/setup-undo.ts +142 -0
- package/src/legacy-lib/start-cluster-config.ts +124 -0
- package/src/legacy-lib/start-cluster-environment.ts +165 -0
- package/src/legacy-lib/start-cluster-run-options.ts +279 -0
- package/src/legacy-lib/start-cluster.ts +237 -0
- package/src/legacy-lib/stream-json-parser.ts +88 -0
- package/src/message-buffer.js +55 -71
- package/src/message-buffer.ts +107 -0
- package/src/message-bus-bridge.js +92 -133
- package/src/message-bus-bridge.ts +149 -0
- package/src/name-generator-shared.js +220 -0
- package/src/name-generator-shared.ts +231 -0
- package/src/name-generator.js +8 -217
- package/src/name-generator.ts +27 -0
- package/src/omp-blob-root.js +83 -64
- package/src/omp-blob-root.ts +116 -0
- package/src/omp-config-overlay.js +65 -38
- package/src/omp-config-overlay.ts +110 -0
- package/src/omp-execution-fingerprint.js +38 -43
- package/src/omp-execution-fingerprint.ts +92 -0
- package/src/omp-session-limits.js +10 -15
- package/src/omp-session-limits.ts +53 -0
- package/src/omp-session-partition.js +2 -2
- package/src/omp-session-verifier.js +1 -1
- package/src/orchestrator.js +19 -4
- package/src/providers/anthropic/index.js +3 -1
- package/src/providers/anthropic/index.ts +13 -0
- package/src/providers/capabilities.js +19 -27
- package/src/providers/capabilities.ts +44 -0
- package/src/providers/google/index.js +3 -1
- package/src/providers/google/index.ts +13 -0
- package/src/providers/openai/index.js +3 -1
- package/src/providers/openai/index.ts +13 -0
- package/src/providers/opencode/index.js +3 -1
- package/src/providers/opencode/index.ts +13 -0
- package/src/quality-gates.js +67 -127
- package/src/quality-gates.ts +149 -0
- package/src/repo-settings-access.js +40 -0
- package/src/repo-settings-access.ts +64 -0
- package/src/schemas/sub-cluster.js +127 -183
- package/src/schemas/sub-cluster.ts +238 -0
- package/src/state-snapshot-normalization.js +224 -0
- package/src/state-snapshot-normalization.ts +222 -0
- package/src/state-snapshot.js +192 -359
- package/src/state-snapshot.ts +291 -0
- package/src/state-snapshotter.js +118 -130
- package/src/state-snapshotter.ts +167 -0
- package/src/sub-cluster-wrapper.js +4 -13
- package/src/task-run-model-args.js +87 -124
- package/src/task-run-model-args.ts +204 -0
- package/src/task-runner.js +5 -25
- package/src/task-runner.ts +28 -0
- package/src/task-startup-error.js +73 -58
- package/src/task-startup-error.ts +126 -0
- package/src/template-validation/consensus-gate-contracts.js +2 -0
- package/src/template-validation/consensus-gate-contracts.ts +70 -0
- package/src/template-validation/consensus-gate-scenarios.js +76 -0
- package/src/template-validation/consensus-gate-scenarios.ts +130 -0
- package/src/template-validation/consensus-gate-stage.js +34 -0
- package/src/template-validation/consensus-gate-stage.ts +56 -0
- package/src/template-validation/random-topology-contracts.js +2 -0
- package/src/template-validation/random-topology-contracts.ts +54 -0
- package/src/template-validation/random-topology-dispatch.js +25 -0
- package/src/template-validation/random-topology-dispatch.ts +33 -0
- package/src/template-validation/random-topology-message-loop.js +53 -0
- package/src/template-validation/random-topology-message-loop.ts +73 -0
- package/src/template-validation/random-topology-operations.js +79 -0
- package/src/template-validation/random-topology-operations.ts +101 -0
- package/src/template-validation/random-topology-runtime.js +25 -0
- package/src/template-validation/random-topology-runtime.ts +43 -0
- package/src/template-validation/random-topology-scenario.js +52 -0
- package/src/template-validation/random-topology-scenario.ts +57 -0
- package/src/template-validation/random-topology-schema.js +159 -0
- package/src/template-validation/random-topology-schema.ts +190 -0
- package/src/template-validation/random-topology-state.js +28 -0
- package/src/template-validation/random-topology-state.ts +30 -0
- package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
- package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
- package/src/template-validation/random-topology-trigger.js +75 -0
- package/src/template-validation/random-topology-trigger.ts +88 -0
- package/src/template-validation/report-formatter.js +40 -46
- package/src/template-validation/report-formatter.ts +101 -0
- package/src/template-validation/simulate-consensus-gates.js +111 -302
- package/src/template-validation/simulate-consensus-gates.ts +196 -0
- package/src/template-validation/simulate-random-topology.js +26 -519
- package/src/template-validation/simulate-random-topology.ts +57 -0
- package/src/template-validation/simulate-two-stage-validation.js +41 -265
- package/src/template-validation/simulate-two-stage-validation.ts +55 -0
- package/src/template-validation/simulation-agent-runtime.js +25 -0
- package/src/template-validation/simulation-agent-runtime.ts +40 -0
- package/src/template-validation/simulation-agent.js +29 -0
- package/src/template-validation/simulation-agent.ts +73 -0
- package/src/template-validation/simulation-runtime.js +34 -0
- package/src/template-validation/simulation-runtime.ts +72 -0
- package/src/template-validation/two-stage-contracts.js +2 -0
- package/src/template-validation/two-stage-contracts.ts +41 -0
- package/src/template-validation/two-stage-inputs.js +21 -0
- package/src/template-validation/two-stage-inputs.ts +29 -0
- package/src/template-validation/two-stage-results.js +30 -0
- package/src/template-validation/two-stage-results.ts +40 -0
- package/src/template-validation/two-stage-scenario.js +86 -0
- package/src/template-validation/two-stage-scenario.ts +120 -0
- package/src/worktree-claude-config.js +182 -220
- package/src/worktree-claude-config.ts +272 -0
- package/src/worktree-tooling-env.js +103 -125
- package/src/worktree-tooling-env.ts +142 -0
- package/task-lib/completion.js +2 -3
- package/task-lib/completion.ts +9 -0
- package/task-lib/config.js +1 -4
- package/task-lib/config.ts +11 -0
- package/task-lib/name-generator.js +4 -226
- package/task-lib/name-generator.ts +11 -0
- package/task-lib/omp-session-cleanup.js +1 -1
- package/task-lib/omp-storage-root.js +8 -12
- package/task-lib/omp-storage-root.ts +62 -0
- package/task-lib/process-termination.js +143 -166
- package/task-lib/process-termination.ts +268 -0
|
@@ -1,619 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
* Provider formats:
|
|
8
|
-
* - Claude: {"type":"result","result":{...}} or {"type":"result","structured_output":{...}}
|
|
9
|
-
* - Codex: Raw text in item.created events, turn.completed has NO result field
|
|
10
|
-
* - Gemini: Raw text in message events, result event may have NO result field
|
|
11
|
-
*
|
|
12
|
-
* Extraction priority (most specific → least specific):
|
|
13
|
-
* 1. Result wrapper with content (type:result + result/structured_output field)
|
|
14
|
-
* 2. Accumulated text from provider parser events
|
|
15
|
-
* 3. Markdown code block extraction
|
|
16
|
-
* 4. Direct JSON parse of entire output
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const { createHash } = require('node:crypto');
|
|
20
|
-
const { parseProviderChunk } = require('../providers');
|
|
21
|
-
|
|
22
|
-
const MAX_CLI_ERROR_BYTES = 4096;
|
|
23
|
-
const CLI_ERROR_TRUNCATION_SUFFIX = '… [truncated]';
|
|
24
|
-
|
|
25
|
-
function truncateUtf8(text, maxBytes = MAX_CLI_ERROR_BYTES) {
|
|
26
|
-
if (Buffer.byteLength(text) <= maxBytes) return text;
|
|
27
|
-
|
|
28
|
-
const suffixBytes = Buffer.byteLength(CLI_ERROR_TRUNCATION_SUFFIX);
|
|
29
|
-
const contentBudget = Math.max(0, maxBytes - suffixBytes);
|
|
30
|
-
let bytes = 0;
|
|
31
|
-
let truncated = '';
|
|
32
|
-
for (const character of text) {
|
|
33
|
-
const characterBytes = Buffer.byteLength(character);
|
|
34
|
-
if (bytes + characterBytes > contentBudget) break;
|
|
35
|
-
truncated += character;
|
|
36
|
-
bytes += characterBytes;
|
|
37
|
-
}
|
|
38
|
-
return `${truncated}${CLI_ERROR_TRUNCATION_SUFFIX}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function primitiveErrorText(value) {
|
|
42
|
-
return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean'
|
|
43
|
-
? String(value)
|
|
44
|
-
: '';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function cliErrorDetail(value, fallback) {
|
|
48
|
-
const candidate = Array.isArray(value)
|
|
49
|
-
? value
|
|
50
|
-
.map(primitiveErrorText)
|
|
51
|
-
.filter((message) => message.trim())
|
|
52
|
-
.join('; ')
|
|
53
|
-
: primitiveErrorText(value);
|
|
54
|
-
const raw = candidate.trim() ? candidate : fallback;
|
|
55
|
-
return {
|
|
56
|
-
error: truncateUtf8(raw.trim()),
|
|
57
|
-
diagnostic: {
|
|
58
|
-
byteLength: Buffer.byteLength(raw),
|
|
59
|
-
sha256: createHash('sha256').update(raw).digest('hex'),
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Strip timestamp prefix from log lines.
|
|
66
|
-
* Format: [epochMs]content or [epochMs]{json...}
|
|
67
|
-
*
|
|
68
|
-
* @param {string} line - Raw log line
|
|
69
|
-
* @returns {string} Content without timestamp prefix
|
|
70
|
-
*/
|
|
71
|
-
function stripTimestamp(line) {
|
|
72
|
-
if (!line || typeof line !== 'string') return '';
|
|
73
|
-
let trimmed = line.trim().replace(/\r$/, '');
|
|
74
|
-
if (!trimmed) return '';
|
|
75
|
-
|
|
76
|
-
const tsMatch = trimmed.match(/^\[(\d{13})\](.*)$/);
|
|
77
|
-
if (tsMatch) trimmed = (tsMatch[2] || '').trimStart();
|
|
78
|
-
|
|
79
|
-
// In cluster logs, lines are often prefixed like:
|
|
80
|
-
// "validator | {json...}"
|
|
81
|
-
// Strip the "<agent> | " prefix so we can JSON.parse the event line.
|
|
82
|
-
if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
|
|
83
|
-
const pipeMatch = trimmed.match(/^[^|]{1,40}\|\s*(.*)$/);
|
|
84
|
-
if (pipeMatch) {
|
|
85
|
-
const afterPipe = (pipeMatch[1] || '').trimStart();
|
|
86
|
-
if (afterPipe.startsWith('{') || afterPipe.startsWith('[')) return afterPipe;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return trimmed;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Strategy 1: Extract from result wrapper
|
|
95
|
-
* Handles Claude CLI format: {"type":"result","result":{...}}
|
|
96
|
-
*
|
|
97
|
-
* @param {string} output - Raw output
|
|
98
|
-
* @returns {object|null} Extracted JSON or null
|
|
99
|
-
*/
|
|
100
|
-
function extractFromResultWrapper(output) {
|
|
101
|
-
const lines = output.split('\n');
|
|
102
|
-
|
|
103
|
-
for (const line of lines) {
|
|
104
|
-
const content = stripTimestamp(line);
|
|
105
|
-
if (!content.startsWith('{')) continue;
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
const obj = JSON.parse(content);
|
|
109
|
-
const extracted = extractResultContent(obj);
|
|
110
|
-
if (extracted) return extracted;
|
|
111
|
-
} catch {
|
|
112
|
-
// Not valid JSON, continue to next line
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function extractResultContent(obj) {
|
|
120
|
-
// Must be type:result WITH actual content
|
|
121
|
-
if (obj?.type !== 'result') return null;
|
|
122
|
-
|
|
123
|
-
// Check structured_output first (standard CLI format)
|
|
124
|
-
if (obj.structured_output && typeof obj.structured_output === 'object') {
|
|
125
|
-
return obj.structured_output;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Check result field - can be object or string
|
|
129
|
-
if (!obj.result) return null;
|
|
130
|
-
|
|
131
|
-
if (typeof obj.result === 'object') {
|
|
132
|
-
return obj.result;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (typeof obj.result !== 'string') return null;
|
|
136
|
-
|
|
137
|
-
// Result is string - might contain markdown-wrapped JSON
|
|
138
|
-
return extractFromMarkdown(obj.result) || extractDirectJson(obj.result);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Strategy 2: Extract from accumulated text events
|
|
143
|
-
* Handles non-Claude providers where JSON is in text content
|
|
144
|
-
*
|
|
145
|
-
* @param {string} output - Raw output
|
|
146
|
-
* @param {string} providerName - Provider name for parser selection
|
|
147
|
-
* @returns {object|null} Extracted JSON or null
|
|
148
|
-
*/
|
|
149
|
-
function extractFromTextEvents(output, providerName) {
|
|
150
|
-
const normalized = output
|
|
151
|
-
.split('\n')
|
|
152
|
-
.map((line) => stripTimestamp(line))
|
|
153
|
-
.filter(Boolean)
|
|
154
|
-
.join('\n');
|
|
155
|
-
const events = parseProviderChunk(providerName, normalized);
|
|
156
|
-
|
|
157
|
-
// Fast-path: many providers eventually emit the full JSON as a single text event.
|
|
158
|
-
// Scan from the end to find the last parseable JSON snippet without requiring
|
|
159
|
-
// the entire concatenated stream to be valid JSON.
|
|
160
|
-
for (let i = events.length - 1; i >= 0; i--) {
|
|
161
|
-
const e = events[i];
|
|
162
|
-
if (e.type !== 'text' || typeof e.text !== 'string') continue;
|
|
163
|
-
const direct = extractDirectJson(e.text) || extractFromMarkdown(e.text);
|
|
164
|
-
if (direct) return direct;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Accumulate all text events
|
|
168
|
-
const textEvents = events.filter((e) => e.type === 'text').map((e) => e.text);
|
|
169
|
-
const textContent = textEvents.join('');
|
|
170
|
-
|
|
171
|
-
if (!textContent.trim()) return null;
|
|
172
|
-
|
|
173
|
-
// Try parsing accumulated text as JSON
|
|
174
|
-
const combined = extractDirectJson(textContent) || extractFromMarkdown(textContent);
|
|
175
|
-
if (combined) return combined;
|
|
176
|
-
|
|
177
|
-
for (let i = textEvents.length - 1; i >= 0; i--) {
|
|
178
|
-
const candidate = textEvents[i];
|
|
179
|
-
const parsed = extractDirectJson(candidate) || extractFromMarkdown(candidate);
|
|
180
|
-
if (parsed) return parsed;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Assemble assistant text through the active provider parser. Recovery prompts
|
|
188
|
-
* use this instead of exposing raw event envelopes when model text exists.
|
|
189
|
-
*
|
|
190
|
-
* @param {string} output
|
|
191
|
-
* @param {string} providerName
|
|
192
|
-
* @returns {string|null}
|
|
193
|
-
*/
|
|
194
|
-
function extractModelTextFromOutput(output, providerName) {
|
|
195
|
-
if (!output || typeof output !== 'string') return null;
|
|
196
|
-
const normalized = output
|
|
197
|
-
.split('\n')
|
|
198
|
-
.map((line) => stripTimestamp(line))
|
|
199
|
-
.filter(Boolean)
|
|
200
|
-
.join('\n');
|
|
201
|
-
const text = parseProviderChunk(providerName, normalized)
|
|
202
|
-
.filter((event) => event.type === 'text' && typeof event.text === 'string')
|
|
203
|
-
.map((event) => event.text)
|
|
204
|
-
.join('');
|
|
205
|
-
return text.trim() ? text : null;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Strategy 3: Extract JSON from markdown code block
|
|
210
|
-
* Handles: ```json\n{...}\n```
|
|
211
|
-
*
|
|
212
|
-
* @param {string} text - Text that may contain markdown
|
|
213
|
-
* @returns {object|null} Extracted JSON or null
|
|
214
|
-
*/
|
|
215
|
-
function extractFromMarkdown(text) {
|
|
216
|
-
if (!text) return null;
|
|
217
|
-
|
|
218
|
-
// Match ```json ... ``` with any whitespace
|
|
219
|
-
const match = text.match(/```json\s*([\s\S]*?)```/);
|
|
220
|
-
if (!match) return null;
|
|
221
|
-
|
|
222
|
-
try {
|
|
223
|
-
const parsed = JSON.parse(match[1].trim());
|
|
224
|
-
if (typeof parsed === 'object' && parsed !== null) {
|
|
225
|
-
return parsed;
|
|
226
|
-
}
|
|
227
|
-
} catch {
|
|
228
|
-
// Invalid JSON in markdown block
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return null;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* CLI metadata fields that indicate raw provider output (not agent content).
|
|
236
|
-
* These objects should be rejected - they're wrapper metadata, not actual output.
|
|
237
|
-
*/
|
|
238
|
-
const CLI_METADATA_FIELDS = new Set([
|
|
239
|
-
'duration_ms',
|
|
240
|
-
'duration_api_ms',
|
|
241
|
-
'total_cost_usd',
|
|
242
|
-
'session_id',
|
|
243
|
-
'num_turns',
|
|
244
|
-
'permission_denials',
|
|
245
|
-
'modelUsage',
|
|
246
|
-
]);
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Check if an object looks like CLI metadata rather than agent output.
|
|
250
|
-
* CLI metadata has specific fields like duration_ms, session_id, etc.
|
|
251
|
-
*
|
|
252
|
-
* @param {object} obj - Parsed JSON object
|
|
253
|
-
* @returns {boolean} True if this looks like CLI metadata
|
|
254
|
-
*/
|
|
255
|
-
function isCliMetadata(obj) {
|
|
256
|
-
if (!obj || typeof obj !== 'object') return false;
|
|
257
|
-
|
|
258
|
-
// If it has type:result, it's definitely CLI wrapper (should have been handled by extractFromResultWrapper)
|
|
259
|
-
if (obj.type === 'result') return true;
|
|
260
|
-
|
|
261
|
-
// Check for CLI-specific metadata fields
|
|
262
|
-
const keys = Object.keys(obj);
|
|
263
|
-
const metadataFieldCount = keys.filter((k) => CLI_METADATA_FIELDS.has(k)).length;
|
|
264
|
-
|
|
265
|
-
// If 2+ CLI metadata fields present, reject as CLI output
|
|
266
|
-
return metadataFieldCount >= 2;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Strategy 4: Direct JSON parse
|
|
271
|
-
* Handles raw JSON output (single-line or multi-line)
|
|
272
|
-
*
|
|
273
|
-
* IMPORTANT: Rejects CLI metadata objects to prevent schema validation
|
|
274
|
-
* against wrong data structure (e.g., validating {duration_ms, session_id}
|
|
275
|
-
* against agent schema expecting {summary, completionStatus}).
|
|
276
|
-
*
|
|
277
|
-
* @param {string} text - Text to parse
|
|
278
|
-
* @returns {object|null} Parsed JSON or null
|
|
279
|
-
*/
|
|
280
|
-
function extractDirectJson(text) {
|
|
281
|
-
if (!text) return null;
|
|
282
|
-
|
|
283
|
-
const trimmed = text.trim();
|
|
284
|
-
if (!trimmed) return null;
|
|
285
|
-
|
|
286
|
-
try {
|
|
287
|
-
const parsed = JSON.parse(trimmed);
|
|
288
|
-
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
289
|
-
// Reject CLI metadata - this is wrapper output, not agent content
|
|
290
|
-
if (isCliMetadata(parsed)) {
|
|
291
|
-
return null;
|
|
292
|
-
}
|
|
293
|
-
return parsed;
|
|
294
|
-
}
|
|
295
|
-
} catch {
|
|
296
|
-
// Not valid JSON
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
return null;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Extract deterministic Claude Vertex model-unavailability metadata from the raw CLI envelope.
|
|
304
|
-
*
|
|
305
|
-
* @param {string} output - Raw Claude CLI output
|
|
306
|
-
* @param {{useVertex?: boolean}} [options] - Whether the Claude task was configured for Vertex
|
|
307
|
-
* @returns {{model: string}|null} Vertex model metadata or null
|
|
308
|
-
*/
|
|
309
|
-
function extractClaudeVertexModelError(output, { useVertex = false } = {}) {
|
|
310
|
-
if (!output || typeof output !== 'string') return null;
|
|
311
|
-
|
|
312
|
-
for (const line of output.split('\n')) {
|
|
313
|
-
const content = stripTimestamp(line);
|
|
314
|
-
if (!content.startsWith('{')) continue;
|
|
315
|
-
|
|
316
|
-
try {
|
|
317
|
-
const parsed = JSON.parse(content);
|
|
318
|
-
if (
|
|
319
|
-
parsed.type !== 'result' ||
|
|
320
|
-
parsed.is_error !== true ||
|
|
321
|
-
parsed.api_error_status !== 404 ||
|
|
322
|
-
typeof parsed.result !== 'string'
|
|
323
|
-
) {
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
const modelMatch = parsed.result.match(/model\s+\(([^)]+)\)/);
|
|
327
|
-
const hasExplicitVertexSignal = parsed.result.includes('vertex deployment');
|
|
328
|
-
const isVertexFallback =
|
|
329
|
-
useVertex && parsed.result.includes('may not exist or you may not have access');
|
|
330
|
-
if (!modelMatch || (!hasExplicitVertexSignal && !isVertexFallback)) continue;
|
|
331
|
-
|
|
332
|
-
return { model: modelMatch[1] };
|
|
333
|
-
} catch {
|
|
334
|
-
// Not a JSON result envelope.
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
return null;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Extract CLI error from provider output (all providers).
|
|
343
|
-
* Returns the error message if the CLI reported an error, null otherwise.
|
|
344
|
-
*
|
|
345
|
-
* Provider error formats:
|
|
346
|
-
* - Claude: {type:"result", is_error:true, errors:["msg"]} or {type:"result", subtype:"error"}
|
|
347
|
-
* - Codex: {type:"turn.failed", error:{message:"msg"}}
|
|
348
|
-
* - Gemini: {type:"result", status:"error", error:{message:"msg"}} or {type:"error", severity:"error"}
|
|
349
|
-
* - Opencode: {type:"session.error", error:{message:"msg"}}
|
|
350
|
-
* - Pi: latest assistant message_end, finalized only by a later agent_settled
|
|
351
|
-
*
|
|
352
|
-
* @param {string} providerName - Active provider whose terminal errors may be inspected
|
|
353
|
-
* @returns {{error: string, provider: string}|null} Error info or null
|
|
354
|
-
*/
|
|
355
|
-
function claudeFailureFromObject(obj) {
|
|
356
|
-
if (obj.type !== 'result') return null;
|
|
357
|
-
if (obj.is_error === true) {
|
|
358
|
-
const detail = cliErrorDetail(
|
|
359
|
-
Array.isArray(obj.errors) ? obj.errors : obj.error || obj.result,
|
|
360
|
-
'Unknown CLI error'
|
|
361
|
-
);
|
|
362
|
-
return { ...detail, provider: 'claude' };
|
|
363
|
-
}
|
|
364
|
-
if (obj.subtype !== 'error') return null;
|
|
365
|
-
return {
|
|
366
|
-
...cliErrorDetail(obj.error || obj.result, 'CLI returned error'),
|
|
367
|
-
provider: 'claude',
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
function codexFailureFromObject(obj) {
|
|
372
|
-
if (obj.type !== 'turn.failed') return null;
|
|
373
|
-
return {
|
|
374
|
-
...cliErrorDetail(obj.error?.message || obj.error?.code || obj.error, 'Turn failed'),
|
|
375
|
-
provider: 'codex',
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
function geminiFailureFromObject(obj) {
|
|
380
|
-
const geminiFailure =
|
|
381
|
-
(obj.type === 'result' && obj.status === 'error') ||
|
|
382
|
-
(obj.type === 'error' && obj.severity === 'error');
|
|
383
|
-
if (!geminiFailure) return null;
|
|
384
|
-
return {
|
|
385
|
-
...cliErrorDetail(obj.error?.message || obj.message, 'Gemini CLI error'),
|
|
386
|
-
provider: 'gemini',
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
function opencodeFailureFromObject(obj) {
|
|
391
|
-
if (obj.type !== 'session.error' && obj.type !== 'error') return null;
|
|
392
|
-
return {
|
|
393
|
-
...cliErrorDetail(
|
|
394
|
-
obj.error?.data?.message || obj.error?.message || obj.error?.name,
|
|
395
|
-
'Session error'
|
|
396
|
-
),
|
|
397
|
-
provider: 'opencode',
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function piFailureFromMessage(message) {
|
|
402
|
-
const stopReason = message.stopReason;
|
|
403
|
-
const errorMessage = message.errorMessage;
|
|
404
|
-
if (stopReason === 'deferred') {
|
|
405
|
-
return {
|
|
406
|
-
...cliErrorDetail('Pi turn deferred without completing.', 'Pi turn deferred'),
|
|
407
|
-
provider: 'pi',
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
if (stopReason !== 'error' && stopReason !== 'aborted' && !errorMessage) return null;
|
|
411
|
-
return {
|
|
412
|
-
...cliErrorDetail(errorMessage || stopReason, 'Pi turn failed'),
|
|
413
|
-
provider: 'pi',
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function failureFromProviderObject(obj, providerName) {
|
|
418
|
-
if (providerName === 'claude') return claudeFailureFromObject(obj);
|
|
419
|
-
if (providerName === 'codex') return codexFailureFromObject(obj);
|
|
420
|
-
if (providerName === 'gemini') return geminiFailureFromObject(obj);
|
|
421
|
-
if (providerName === 'opencode') return opencodeFailureFromObject(obj);
|
|
422
|
-
return null;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
function piProtocolFailure(message) {
|
|
426
|
-
return { ...cliErrorDetail(message, message), provider: 'pi' };
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const PI_STOP_REASONS = new Set(['stop', 'length', 'toolUse', 'error', 'aborted', 'deferred']);
|
|
430
|
-
const PI_USAGE_FIELDS = ['input', 'output', 'cacheRead', 'cacheWrite', 'totalTokens'];
|
|
431
|
-
const PI_COST_FIELDS = ['input', 'output', 'cacheRead', 'cacheWrite', 'total'];
|
|
432
|
-
|
|
433
|
-
function parsePiProtocolObject(content) {
|
|
434
|
-
if (!content.startsWith('{')) return null;
|
|
435
|
-
try {
|
|
436
|
-
const parsed = JSON.parse(content);
|
|
437
|
-
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
|
|
438
|
-
} catch {
|
|
439
|
-
return null;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
function isPiRecord(value) {
|
|
444
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
function hasPiNumericFields(value, fields) {
|
|
448
|
-
return isPiRecord(value) && fields.every((field) => typeof value[field] === 'number');
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function isValidPiUsage(usage) {
|
|
452
|
-
if (!hasPiNumericFields(usage, PI_USAGE_FIELDS)) return false;
|
|
453
|
-
if (!hasPiNumericFields(usage.cost, PI_COST_FIELDS)) return false;
|
|
454
|
-
return (
|
|
455
|
-
(usage.cacheWrite1h === undefined || typeof usage.cacheWrite1h === 'number') &&
|
|
456
|
-
(usage.reasoning === undefined || typeof usage.reasoning === 'number')
|
|
457
|
-
);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function isValidPiAssistantMessage(message) {
|
|
461
|
-
return (
|
|
462
|
-
isPiRecord(message) &&
|
|
463
|
-
message.role === 'assistant' &&
|
|
464
|
-
Array.isArray(message.content) &&
|
|
465
|
-
isValidPiUsage(message.usage) &&
|
|
466
|
-
PI_STOP_REASONS.has(message.stopReason)
|
|
467
|
-
);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
function piMessageRole(message) {
|
|
471
|
-
if (!message || typeof message !== 'object' || Array.isArray(message)) return null;
|
|
472
|
-
return typeof message.role === 'string' ? message.role : null;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
function applyPiProtocolLine(content, state) {
|
|
476
|
-
if (!content) return null;
|
|
477
|
-
if (
|
|
478
|
-
content.startsWith('[ZEROSHOT] Earlier provider output omitted') ||
|
|
479
|
-
content.startsWith('[ZEROSHOT] Provider output record retained') ||
|
|
480
|
-
content.startsWith('[ZEROSHOT][PROVIDER_STDERR] ')
|
|
481
|
-
) {
|
|
482
|
-
return null;
|
|
483
|
-
}
|
|
484
|
-
if (state.settled) return piProtocolFailure('Pi emitted output after agent_settled.');
|
|
485
|
-
const parsed = parsePiProtocolObject(content);
|
|
486
|
-
if (parsed === null) return piProtocolFailure('Pi JSON stream contained malformed output.');
|
|
487
|
-
if (typeof parsed.type !== 'string') {
|
|
488
|
-
return piProtocolFailure('Pi JSON stream contained an event without a valid type.');
|
|
489
|
-
}
|
|
490
|
-
if (parsed.type === 'message_end') {
|
|
491
|
-
const role = piMessageRole(parsed.message);
|
|
492
|
-
if (role === null) return piProtocolFailure('Pi message_end did not contain a valid message.');
|
|
493
|
-
if (role !== 'assistant') return null;
|
|
494
|
-
if (!isValidPiAssistantMessage(parsed.message)) {
|
|
495
|
-
return piProtocolFailure('Pi message_end did not contain a valid assistant message.');
|
|
496
|
-
}
|
|
497
|
-
state.latestAssistant = parsed.message;
|
|
498
|
-
} else if (parsed.type === 'agent_settled') {
|
|
499
|
-
state.settled = true;
|
|
500
|
-
}
|
|
501
|
-
return null;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
function extractSettledPiFailure(lines) {
|
|
505
|
-
const state = { latestAssistant: null, settled: false };
|
|
506
|
-
for (const line of lines) {
|
|
507
|
-
const content = stripTimestamp(line);
|
|
508
|
-
const failure = applyPiProtocolLine(content, state);
|
|
509
|
-
if (failure) return failure;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
if (!state.settled) return piProtocolFailure('Pi JSON stream ended before agent_settled.');
|
|
513
|
-
if (state.latestAssistant === null) {
|
|
514
|
-
return piProtocolFailure('Pi settled without a valid assistant message_end.');
|
|
515
|
-
}
|
|
516
|
-
return piFailureFromMessage(state.latestAssistant);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
function extractCliFailure(output, providerName = 'claude') {
|
|
520
|
-
if (providerName === 'pi') {
|
|
521
|
-
const lines = typeof output === 'string' ? output.split('\n') : [];
|
|
522
|
-
return extractSettledPiFailure(lines);
|
|
523
|
-
}
|
|
524
|
-
if (!output || typeof output !== 'string') return null;
|
|
525
|
-
|
|
526
|
-
const lines = output.split('\n');
|
|
527
|
-
// Codex terminal truth is a turn.failed record at the newest end of JSONL output.
|
|
528
|
-
// Search it newest-first so a preserved terminal tail wins over older provider chatter.
|
|
529
|
-
if (providerName === 'codex') lines.reverse();
|
|
530
|
-
|
|
531
|
-
for (const line of lines) {
|
|
532
|
-
const content = stripTimestamp(line);
|
|
533
|
-
if (!content.startsWith('{')) continue;
|
|
534
|
-
try {
|
|
535
|
-
const failure = failureFromProviderObject(JSON.parse(content), providerName);
|
|
536
|
-
if (failure) return failure;
|
|
537
|
-
} catch {
|
|
538
|
-
// Ignore non-JSON output lines.
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
return null;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
function extractCliError(output, providerName = 'claude') {
|
|
546
|
-
const failure = extractCliFailure(output, providerName);
|
|
547
|
-
return failure ? { error: failure.error, provider: failure.provider } : null;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Detects fatal standalone output lines that indicate no task output was produced.
|
|
552
|
-
* Only matches when the line itself is the fatal message (not when it appears inside JSON).
|
|
553
|
-
*
|
|
554
|
-
* @param {string} output - Raw output text
|
|
555
|
-
* @returns {boolean} True if a standalone fatal line is present
|
|
556
|
-
*/
|
|
557
|
-
function hasFatalStandaloneOutput(output) {
|
|
558
|
-
if (!output || typeof output !== 'string') return false;
|
|
559
|
-
const lines = output.split('\n');
|
|
560
|
-
for (const line of lines) {
|
|
561
|
-
const stripped = stripTimestamp(line).trim();
|
|
562
|
-
if (!stripped) continue;
|
|
563
|
-
if (/^(task not found|process terminated)\b/i.test(stripped)) {
|
|
564
|
-
return true;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
return false;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
/**
|
|
571
|
-
* Main extraction function - tries all strategies in priority order
|
|
572
|
-
*
|
|
573
|
-
* @param {string} output - Raw output from AI provider CLI
|
|
574
|
-
* @param {string} providerName - Provider name ('claude', 'codex', 'gemini')
|
|
575
|
-
* @returns {object|null} Extracted JSON object or null if extraction failed
|
|
576
|
-
*/
|
|
577
|
-
function extractJsonFromOutput(output, providerName = 'claude') {
|
|
578
|
-
if (!output || typeof output !== 'string') return null;
|
|
579
|
-
|
|
580
|
-
const trimmedOutput = output.trim();
|
|
581
|
-
if (!trimmedOutput) return null;
|
|
582
|
-
|
|
583
|
-
// Strategy 1: Result wrapper (Claude format)
|
|
584
|
-
const fromWrapper = extractFromResultWrapper(trimmedOutput);
|
|
585
|
-
if (fromWrapper) return fromWrapper;
|
|
586
|
-
|
|
587
|
-
// Strategy 2: Text events (non-Claude providers)
|
|
588
|
-
const fromText = extractFromTextEvents(trimmedOutput, providerName);
|
|
589
|
-
if (fromText) return fromText;
|
|
590
|
-
|
|
591
|
-
// Strategy 3: Markdown extraction
|
|
592
|
-
const fromMarkdown = extractFromMarkdown(trimmedOutput);
|
|
593
|
-
if (fromMarkdown) return fromMarkdown;
|
|
594
|
-
|
|
595
|
-
// Strategy 4: Direct JSON parse (raw output)
|
|
596
|
-
const fromDirect = extractDirectJson(trimmedOutput);
|
|
597
|
-
if (fromDirect) return fromDirect;
|
|
598
|
-
|
|
599
|
-
if (hasFatalStandaloneOutput(trimmedOutput)) {
|
|
600
|
-
return null;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
return null;
|
|
604
|
-
}
|
|
605
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
const failureExtraction = require("./output-extraction-failures");
|
|
3
|
+
const jsonExtraction = require("./output-extraction-json");
|
|
4
|
+
const { MAX_CLI_ERROR_BYTES, extractClaudeVertexModelError, extractCliError, extractCliFailure } = failureExtraction;
|
|
5
|
+
const { extractDirectJson, extractFromMarkdown, extractFromResultWrapper, extractFromTextEvents, extractJsonFromOutput, extractModelTextFromOutput, hasFatalStandaloneOutput, stripTimestamp, } = jsonExtraction;
|
|
606
6
|
module.exports = {
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
7
|
+
MAX_CLI_ERROR_BYTES,
|
|
8
|
+
extractJsonFromOutput,
|
|
9
|
+
extractModelTextFromOutput,
|
|
10
|
+
extractCliFailure,
|
|
11
|
+
extractCliError,
|
|
12
|
+
extractClaudeVertexModelError,
|
|
13
|
+
extractFromResultWrapper,
|
|
14
|
+
extractFromTextEvents,
|
|
15
|
+
extractFromMarkdown,
|
|
16
|
+
extractDirectJson,
|
|
17
|
+
stripTimestamp,
|
|
18
|
+
hasFatalStandaloneOutput,
|
|
619
19
|
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import failureExtraction = require('./output-extraction-failures');
|
|
2
|
+
import jsonExtraction = require('./output-extraction-json');
|
|
3
|
+
|
|
4
|
+
const { MAX_CLI_ERROR_BYTES, extractClaudeVertexModelError, extractCliError, extractCliFailure } =
|
|
5
|
+
failureExtraction;
|
|
6
|
+
const {
|
|
7
|
+
extractDirectJson,
|
|
8
|
+
extractFromMarkdown,
|
|
9
|
+
extractFromResultWrapper,
|
|
10
|
+
extractFromTextEvents,
|
|
11
|
+
extractJsonFromOutput,
|
|
12
|
+
extractModelTextFromOutput,
|
|
13
|
+
hasFatalStandaloneOutput,
|
|
14
|
+
stripTimestamp,
|
|
15
|
+
} = jsonExtraction;
|
|
16
|
+
|
|
17
|
+
export = {
|
|
18
|
+
MAX_CLI_ERROR_BYTES,
|
|
19
|
+
extractJsonFromOutput,
|
|
20
|
+
extractModelTextFromOutput,
|
|
21
|
+
extractCliFailure,
|
|
22
|
+
extractCliError,
|
|
23
|
+
extractClaudeVertexModelError,
|
|
24
|
+
extractFromResultWrapper,
|
|
25
|
+
extractFromTextEvents,
|
|
26
|
+
extractFromMarkdown,
|
|
27
|
+
extractDirectJson,
|
|
28
|
+
stripTimestamp,
|
|
29
|
+
hasFatalStandaloneOutput,
|
|
30
|
+
};
|