@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
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import crypto = require('crypto');
|
|
2
|
+
import stateSnapshot = require('./state-snapshot');
|
|
3
|
+
import normalization = require('./state-snapshot-normalization');
|
|
4
|
+
|
|
5
|
+
interface SnapshotMessageBus {
|
|
6
|
+
subscribeTopics(topics: string[], handler: (message: unknown) => void): () => void;
|
|
7
|
+
findLast(query: { cluster_id: string; topic: string }): unknown;
|
|
8
|
+
publish(message: {
|
|
9
|
+
cluster_id: string;
|
|
10
|
+
topic: 'STATE_SNAPSHOT';
|
|
11
|
+
sender: 'state-snapshotter';
|
|
12
|
+
receiver: 'broadcast';
|
|
13
|
+
content: { text: string; data: object };
|
|
14
|
+
}): unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface StateSnapshotterOptions {
|
|
18
|
+
messageBus: SnapshotMessageBus;
|
|
19
|
+
clusterId: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type SnapshotState = ReturnType<typeof stateSnapshot.initStateFromIssue>;
|
|
23
|
+
const SNAPSHOT_TOPICS = [
|
|
24
|
+
'ISSUE_OPENED',
|
|
25
|
+
'PLAN_READY',
|
|
26
|
+
'WORKER_PROGRESS',
|
|
27
|
+
'IMPLEMENTATION_READY',
|
|
28
|
+
'VALIDATION_RESULT',
|
|
29
|
+
'INVESTIGATION_COMPLETE',
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
function messageTimestamp(message: unknown): number {
|
|
33
|
+
const timestamp = normalization.asRecord(message)?.timestamp;
|
|
34
|
+
return timestamp ? Number(timestamp) : 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class StateSnapshotter {
|
|
38
|
+
messageBus: SnapshotMessageBus;
|
|
39
|
+
clusterId: string;
|
|
40
|
+
state: object | null;
|
|
41
|
+
lastHash: string | null;
|
|
42
|
+
unsubscribe: (() => void) | null;
|
|
43
|
+
|
|
44
|
+
constructor({ messageBus, clusterId }: StateSnapshotterOptions) {
|
|
45
|
+
this.messageBus = messageBus;
|
|
46
|
+
this.clusterId = clusterId;
|
|
47
|
+
this.state = null;
|
|
48
|
+
this.lastHash = null;
|
|
49
|
+
this.unsubscribe = null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
start(): void {
|
|
53
|
+
if (this.unsubscribe) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this._bootstrapFromLedger();
|
|
58
|
+
|
|
59
|
+
this.unsubscribe = this.messageBus.subscribeTopics(SNAPSHOT_TOPICS, (message: unknown) => {
|
|
60
|
+
if (normalization.asRecord(message)?.cluster_id !== this.clusterId) return;
|
|
61
|
+
this._handleMessage(message);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
stop(): void {
|
|
66
|
+
if (!this.unsubscribe) return;
|
|
67
|
+
this.unsubscribe();
|
|
68
|
+
this.unsubscribe = null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_bootstrapFromLedger(): void {
|
|
72
|
+
const existing = this.messageBus.findLast({
|
|
73
|
+
cluster_id: this.clusterId,
|
|
74
|
+
topic: 'STATE_SNAPSHOT',
|
|
75
|
+
});
|
|
76
|
+
const existingData = normalization.asRecord(normalization.asRecord(existing)?.content)?.data;
|
|
77
|
+
|
|
78
|
+
if (existingData && typeof existingData === 'object') {
|
|
79
|
+
this.state = existingData;
|
|
80
|
+
this.lastHash = this._hashState(this.state);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const messages = SNAPSHOT_TOPICS.map((topic) =>
|
|
85
|
+
this.messageBus.findLast({ cluster_id: this.clusterId, topic })
|
|
86
|
+
).filter(Boolean);
|
|
87
|
+
|
|
88
|
+
if (messages.length === 0) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
messages.sort((left, right) => messageTimestamp(left) - messageTimestamp(right));
|
|
93
|
+
|
|
94
|
+
let state: object | null = null;
|
|
95
|
+
for (const message of messages) {
|
|
96
|
+
state = this._applyMessage(state, message);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (state) {
|
|
100
|
+
this.state = state;
|
|
101
|
+
this._publishSnapshot(state);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
_handleMessage(message: unknown): void {
|
|
106
|
+
const nextState = this._applyMessage(this.state, message);
|
|
107
|
+
if (!nextState) return;
|
|
108
|
+
|
|
109
|
+
this.state = nextState;
|
|
110
|
+
this._publishSnapshot(nextState);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_applyMessage(state: object | null, message: unknown): SnapshotState | object | null {
|
|
114
|
+
switch (normalization.asRecord(message)?.topic) {
|
|
115
|
+
case 'ISSUE_OPENED':
|
|
116
|
+
return state
|
|
117
|
+
? stateSnapshot.applyIssueOpened(state, message)
|
|
118
|
+
: stateSnapshot.initStateFromIssue(message);
|
|
119
|
+
case 'PLAN_READY':
|
|
120
|
+
return stateSnapshot.applyPlanReady(state, message);
|
|
121
|
+
case 'WORKER_PROGRESS':
|
|
122
|
+
return stateSnapshot.applyWorkerProgress(state, message);
|
|
123
|
+
case 'IMPLEMENTATION_READY':
|
|
124
|
+
return stateSnapshot.applyImplementationReady(state, message);
|
|
125
|
+
case 'VALIDATION_RESULT':
|
|
126
|
+
return stateSnapshot.applyValidationResult(state, message);
|
|
127
|
+
case 'INVESTIGATION_COMPLETE':
|
|
128
|
+
return stateSnapshot.applyInvestigationComplete(state, message);
|
|
129
|
+
default:
|
|
130
|
+
return state;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
_publishSnapshot(state: object): void {
|
|
135
|
+
const hash = this._hashState(state);
|
|
136
|
+
if (this._hashEquals(hash, this.lastHash)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
this.lastHash = hash;
|
|
140
|
+
|
|
141
|
+
this.messageBus.publish({
|
|
142
|
+
cluster_id: this.clusterId,
|
|
143
|
+
topic: 'STATE_SNAPSHOT',
|
|
144
|
+
sender: 'state-snapshotter',
|
|
145
|
+
receiver: 'broadcast',
|
|
146
|
+
content: {
|
|
147
|
+
text: stateSnapshot.renderStateSummary(state),
|
|
148
|
+
data: state,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
_hashState(state: object): string {
|
|
154
|
+
const serialized = JSON.stringify(state);
|
|
155
|
+
return crypto.createHash('sha256').update(serialized).digest('hex');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
_hashEquals(left: string | null, right: string | null): boolean {
|
|
159
|
+
if (!left || !right) return false;
|
|
160
|
+
const leftBuffer = Buffer.from(left, 'utf8');
|
|
161
|
+
const rightBuffer = Buffer.from(right, 'utf8');
|
|
162
|
+
if (leftBuffer.length !== rightBuffer.length) return false;
|
|
163
|
+
return crypto.timingSafeEqual(leftBuffer, rightBuffer);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export = StateSnapshotter;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
const LogicEngine = require('./logic-engine');
|
|
16
16
|
const MessageBusBridge = require('./message-bus-bridge');
|
|
17
17
|
const { DEFAULT_MAX_ITERATIONS } = require('./agent/agent-config');
|
|
18
|
+
const { findMatchingTrigger } = require('./agent/agent-trigger-evaluator');
|
|
18
19
|
const { bufferMessage, scheduleDrain, drainBufferedMessages } = require('./message-buffer');
|
|
19
20
|
|
|
20
21
|
function normalizeParentTopicConfig(entry) {
|
|
@@ -217,19 +218,9 @@ class SubClusterWrapper {
|
|
|
217
218
|
* @private
|
|
218
219
|
*/
|
|
219
220
|
_findMatchingTrigger(message) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return this.config.triggers.find((trigger) => {
|
|
225
|
-
if (trigger.topic === '*' || trigger.topic === message.topic) {
|
|
226
|
-
return true;
|
|
227
|
-
}
|
|
228
|
-
if (trigger.topic.endsWith('*')) {
|
|
229
|
-
const prefix = trigger.topic.slice(0, -1);
|
|
230
|
-
return message.topic.startsWith(prefix);
|
|
231
|
-
}
|
|
232
|
-
return false;
|
|
221
|
+
return findMatchingTrigger({
|
|
222
|
+
triggers: this.config.triggers,
|
|
223
|
+
message,
|
|
233
224
|
});
|
|
234
225
|
}
|
|
235
226
|
|
|
@@ -1,38 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* @returns {string[]}
|
|
14
|
-
*/
|
|
1
|
+
"use strict";
|
|
2
|
+
function isUnknownRecord(value) {
|
|
3
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
function isProviderNamesModule(value) {
|
|
6
|
+
return isUnknownRecord(value) && typeof value.providerSupportsCapability === 'function';
|
|
7
|
+
}
|
|
8
|
+
const providerNames = require('../lib/provider-names');
|
|
9
|
+
if (!isProviderNamesModule(providerNames)) {
|
|
10
|
+
throw new TypeError('provider-names must expose provider capability lookup');
|
|
11
|
+
}
|
|
12
|
+
const { providerSupportsCapability } = providerNames;
|
|
15
13
|
function appendTaskRunModelArgs(args, modelSpec, modelSpecSource = 'direct') {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
if (modelSpecSource === 'provider-level') {
|
|
15
|
+
if (!modelSpec?.level) {
|
|
16
|
+
throw new Error('Provider-level task model selections require a model level');
|
|
17
|
+
}
|
|
18
|
+
args.push('--model-level', modelSpec.level);
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
args
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return args;
|
|
20
|
+
else if (modelSpec?.model) {
|
|
21
|
+
args.push('--model', modelSpec.model);
|
|
22
|
+
}
|
|
23
|
+
if (modelSpec?.reasoningEffort) {
|
|
24
|
+
args.push('--reasoning-effort', modelSpec.reasoningEffort);
|
|
25
|
+
}
|
|
26
|
+
return args;
|
|
30
27
|
}
|
|
31
|
-
|
|
32
28
|
const ISOLATED_SETTINGS_FILE_ENV = 'ZEROSHOT_SETTINGS_FILE';
|
|
33
29
|
const ISOLATED_SETTINGS_FILE_MARKER = 'ZEROSHOT_DOCKER_SETTINGS_FILE';
|
|
34
30
|
const LEGACY_ISOLATED_PROVIDER_SETTINGS_ENV = 'ZEROSHOT_ISOLATED_PROVIDER_SETTINGS_JSON';
|
|
35
|
-
const SETTINGS_BOOTSTRAP_SCRIPT = String.raw`
|
|
31
|
+
const SETTINGS_BOOTSTRAP_SCRIPT = String.raw `
|
|
36
32
|
const childProcess = require('node:child_process');
|
|
37
33
|
const fs = require('node:fs');
|
|
38
34
|
const os = require('node:os');
|
|
@@ -60,114 +56,81 @@ try {
|
|
|
60
56
|
fs.rmSync(directory, { recursive: true, force: true });
|
|
61
57
|
}
|
|
62
58
|
`.trim();
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Wrap an isolated task command with a Docker-only, temporary settings-file
|
|
66
|
-
* bootstrap. The snapshot is a closed projection containing only an enabled
|
|
67
|
-
* native-search control and, when needed, the selected OpenCode level/model.
|
|
68
|
-
* It never contains credentials or caller-owned keys.
|
|
69
|
-
*
|
|
70
|
-
* @param {string[]} command
|
|
71
|
-
* @param {{providerName: string, settings: Object, modelSpecSource: 'direct'|'provider-level', modelSpec: Object|null|undefined}} context
|
|
72
|
-
* @returns {string[]}
|
|
73
|
-
*/
|
|
74
59
|
function wrapTaskRunWithIsolatedSettings(command, context) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
providerName === 'opencode' && modelSpecSource === 'provider-level';
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
);
|
|
84
|
-
if (snapshot === null) return command;
|
|
85
|
-
return ['node', '-e', SETTINGS_BOOTSTRAP_SCRIPT, snapshot, ...command];
|
|
60
|
+
const { providerName, settings, modelSpecSource, modelSpec } = context;
|
|
61
|
+
if (!providerSupportsCapability(providerName, 'webSearch'))
|
|
62
|
+
return command;
|
|
63
|
+
const includesOpencodeModel = providerName === 'opencode' && modelSpecSource === 'provider-level';
|
|
64
|
+
const snapshot = buildIsolatedSettingsSnapshot(settings, providerName, includesOpencodeModel ? modelSpec : null);
|
|
65
|
+
if (snapshot === null)
|
|
66
|
+
return command;
|
|
67
|
+
return ['node', '-e', SETTINGS_BOOTSTRAP_SCRIPT, snapshot, ...command];
|
|
86
68
|
}
|
|
87
|
-
|
|
88
69
|
function buildIsolatedSettingsSnapshot(settings, providerName, opencodeModelSpec) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
);
|
|
95
|
-
const webSearch = selectedSettings?.webSearch;
|
|
96
|
-
if (webSearch !== undefined && typeof webSearch !== 'boolean') {
|
|
97
|
-
throw permanentError(`settings.providerSettings.${providerName}.webSearch must be a boolean.`);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const snapshot = {};
|
|
101
|
-
if (webSearch === true) snapshot.webSearch = true;
|
|
102
|
-
if (opencodeModelSpec !== null) {
|
|
103
|
-
const level = opencodeModelSpec?.level;
|
|
104
|
-
if (!['level1', 'level2', 'level3'].includes(level)) {
|
|
105
|
-
throw permanentError(
|
|
106
|
-
'Provider-level isolated OpenCode selections require a valid model level.'
|
|
107
|
-
);
|
|
70
|
+
const providerSettings = ownRecordValue(settings, 'providerSettings', 'settings') ?? {};
|
|
71
|
+
const selectedSettings = ownRecordValue(providerSettings, providerName, 'settings.providerSettings');
|
|
72
|
+
const webSearch = selectedSettings?.webSearch;
|
|
73
|
+
if (webSearch !== undefined && typeof webSearch !== 'boolean') {
|
|
74
|
+
throw permanentError(`settings.providerSettings.${providerName}.webSearch must be a boolean.`);
|
|
108
75
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
76
|
+
const snapshot = {};
|
|
77
|
+
if (webSearch === true)
|
|
78
|
+
snapshot.webSearch = true;
|
|
79
|
+
if (opencodeModelSpec !== null) {
|
|
80
|
+
const levelOverrides = resolveIsolatedOpenCodeOverrides(selectedSettings, opencodeModelSpec);
|
|
81
|
+
if (levelOverrides !== undefined)
|
|
82
|
+
snapshot.levelOverrides = levelOverrides;
|
|
83
|
+
}
|
|
84
|
+
if (Object.keys(snapshot).length === 0)
|
|
85
|
+
return null;
|
|
86
|
+
return JSON.stringify({
|
|
87
|
+
providerSettings: {
|
|
88
|
+
[providerName]: snapshot,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function resolveIsolatedOpenCodeOverrides(selectedSettings, modelSpec) {
|
|
93
|
+
const level = modelSpec?.level;
|
|
94
|
+
if (level !== 'level1' && level !== 'level2' && level !== 'level3') {
|
|
95
|
+
throw permanentError('Provider-level isolated OpenCode selections require a valid model level.');
|
|
96
|
+
}
|
|
97
|
+
const levelOverrides = ownRecordValue(selectedSettings, 'levelOverrides', 'settings.providerSettings.opencode');
|
|
98
|
+
const levelOverride = ownRecordValue(levelOverrides, level, 'settings.providerSettings.opencode.levelOverrides');
|
|
99
|
+
const configuredModel = levelOverride && Object.prototype.hasOwnProperty.call(levelOverride, 'model')
|
|
122
100
|
? levelOverride.model
|
|
123
101
|
: null;
|
|
124
102
|
if (configuredModel !== null && typeof configuredModel !== 'string') {
|
|
125
|
-
|
|
103
|
+
throw permanentError(`Configured isolated OpenCode ${level} model must be a string or null.`);
|
|
126
104
|
}
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
);
|
|
105
|
+
if (modelSpec?.model !== configuredModel) {
|
|
106
|
+
throw permanentError(`Provider-level model "${modelSpec?.model}" does not match ` +
|
|
107
|
+
`the effective isolated ${level} model "${configuredModel}".`);
|
|
131
108
|
}
|
|
132
|
-
|
|
133
|
-
snapshot.levelOverrides = {
|
|
134
|
-
[level]: { model: configuredModel },
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (Object.keys(snapshot).length === 0) return null;
|
|
140
|
-
return JSON.stringify({
|
|
141
|
-
providerSettings: {
|
|
142
|
-
[providerName]: snapshot,
|
|
143
|
-
},
|
|
144
|
-
});
|
|
109
|
+
return configuredModel === null ? undefined : { [level]: { model: configuredModel } };
|
|
145
110
|
}
|
|
146
|
-
|
|
147
111
|
function ownRecordValue(record, key, field) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
112
|
+
if (record === null || record === undefined)
|
|
113
|
+
return undefined;
|
|
114
|
+
if (!isUnknownRecord(record)) {
|
|
115
|
+
throw permanentError(`${field} must be an object.`);
|
|
116
|
+
}
|
|
117
|
+
if (!Object.prototype.hasOwnProperty.call(record, key))
|
|
118
|
+
return undefined;
|
|
119
|
+
const value = record[key];
|
|
120
|
+
if (value === null || value === undefined)
|
|
121
|
+
return undefined;
|
|
122
|
+
if (!isUnknownRecord(value)) {
|
|
123
|
+
throw permanentError(`${field}.${key} must be an object.`);
|
|
124
|
+
}
|
|
125
|
+
return value;
|
|
159
126
|
}
|
|
160
|
-
|
|
161
127
|
function permanentError(message) {
|
|
162
|
-
|
|
163
|
-
error.permanent = true;
|
|
164
|
-
return error;
|
|
128
|
+
return Object.assign(new Error(message), { permanent: true });
|
|
165
129
|
}
|
|
166
|
-
|
|
167
130
|
module.exports = {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
131
|
+
ISOLATED_SETTINGS_FILE_ENV,
|
|
132
|
+
ISOLATED_SETTINGS_FILE_MARKER,
|
|
133
|
+
LEGACY_ISOLATED_PROVIDER_SETTINGS_ENV,
|
|
134
|
+
appendTaskRunModelArgs,
|
|
135
|
+
wrapTaskRunWithIsolatedSettings,
|
|
173
136
|
};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
type ModelSpecSource = 'direct' | 'provider-level';
|
|
2
|
+
type ModelLevel = 'level1' | 'level2' | 'level3';
|
|
3
|
+
type UnknownRecord = Record<string, unknown>;
|
|
4
|
+
|
|
5
|
+
interface ProviderNamesModule {
|
|
6
|
+
providerSupportsCapability(providerName: string, capability: string): boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ModelSpec {
|
|
10
|
+
level?: ModelLevel;
|
|
11
|
+
model?: string | null;
|
|
12
|
+
reasoningEffort?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IsolatedSettingsContext {
|
|
16
|
+
providerName: string;
|
|
17
|
+
settings: unknown;
|
|
18
|
+
modelSpecSource: ModelSpecSource;
|
|
19
|
+
modelSpec: ModelSpec | null | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface IsolatedProviderSnapshot {
|
|
23
|
+
webSearch?: true;
|
|
24
|
+
levelOverrides?: Partial<Record<ModelLevel, { model: string }>>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isUnknownRecord(value: unknown): value is UnknownRecord {
|
|
28
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isProviderNamesModule(value: unknown): value is ProviderNamesModule {
|
|
32
|
+
return isUnknownRecord(value) && typeof value.providerSupportsCapability === 'function';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const providerNames: unknown = require('../lib/provider-names');
|
|
36
|
+
if (!isProviderNamesModule(providerNames)) {
|
|
37
|
+
throw new TypeError('provider-names must expose provider capability lookup');
|
|
38
|
+
}
|
|
39
|
+
const { providerSupportsCapability } = providerNames;
|
|
40
|
+
|
|
41
|
+
function appendTaskRunModelArgs(
|
|
42
|
+
args: string[],
|
|
43
|
+
modelSpec: ModelSpec | null | undefined,
|
|
44
|
+
modelSpecSource: ModelSpecSource = 'direct'
|
|
45
|
+
): string[] {
|
|
46
|
+
if (modelSpecSource === 'provider-level') {
|
|
47
|
+
if (!modelSpec?.level) {
|
|
48
|
+
throw new Error('Provider-level task model selections require a model level');
|
|
49
|
+
}
|
|
50
|
+
args.push('--model-level', modelSpec.level);
|
|
51
|
+
} else if (modelSpec?.model) {
|
|
52
|
+
args.push('--model', modelSpec.model);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (modelSpec?.reasoningEffort) {
|
|
56
|
+
args.push('--reasoning-effort', modelSpec.reasoningEffort);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return args;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const ISOLATED_SETTINGS_FILE_ENV = 'ZEROSHOT_SETTINGS_FILE';
|
|
63
|
+
const ISOLATED_SETTINGS_FILE_MARKER = 'ZEROSHOT_DOCKER_SETTINGS_FILE';
|
|
64
|
+
const LEGACY_ISOLATED_PROVIDER_SETTINGS_ENV = 'ZEROSHOT_ISOLATED_PROVIDER_SETTINGS_JSON';
|
|
65
|
+
const SETTINGS_BOOTSTRAP_SCRIPT = String.raw`
|
|
66
|
+
const childProcess = require('node:child_process');
|
|
67
|
+
const fs = require('node:fs');
|
|
68
|
+
const os = require('node:os');
|
|
69
|
+
const path = require('node:path');
|
|
70
|
+
|
|
71
|
+
const snapshot = process.argv[1];
|
|
72
|
+
const command = process.argv[2];
|
|
73
|
+
const args = process.argv.slice(3);
|
|
74
|
+
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'zeroshot-isolated-settings-'));
|
|
75
|
+
const settingsFile = path.join(directory, 'settings.json');
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
fs.writeFileSync(settingsFile, snapshot, { encoding: 'utf8', flag: 'wx', mode: 0o600 });
|
|
79
|
+
const result = childProcess.spawnSync(command, args, {
|
|
80
|
+
stdio: 'inherit',
|
|
81
|
+
env: {
|
|
82
|
+
...process.env,
|
|
83
|
+
${ISOLATED_SETTINGS_FILE_ENV}: settingsFile,
|
|
84
|
+
${ISOLATED_SETTINGS_FILE_MARKER}: '1',
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
if (result.error) throw result.error;
|
|
88
|
+
process.exitCode = result.status === null ? 1 : result.status;
|
|
89
|
+
} finally {
|
|
90
|
+
fs.rmSync(directory, { recursive: true, force: true });
|
|
91
|
+
}
|
|
92
|
+
`.trim();
|
|
93
|
+
|
|
94
|
+
function wrapTaskRunWithIsolatedSettings(
|
|
95
|
+
command: string[],
|
|
96
|
+
context: IsolatedSettingsContext
|
|
97
|
+
): string[] {
|
|
98
|
+
const { providerName, settings, modelSpecSource, modelSpec } = context;
|
|
99
|
+
if (!providerSupportsCapability(providerName, 'webSearch')) return command;
|
|
100
|
+
const includesOpencodeModel =
|
|
101
|
+
providerName === 'opencode' && modelSpecSource === 'provider-level';
|
|
102
|
+
const snapshot = buildIsolatedSettingsSnapshot(
|
|
103
|
+
settings,
|
|
104
|
+
providerName,
|
|
105
|
+
includesOpencodeModel ? modelSpec : null
|
|
106
|
+
);
|
|
107
|
+
if (snapshot === null) return command;
|
|
108
|
+
return ['node', '-e', SETTINGS_BOOTSTRAP_SCRIPT, snapshot, ...command];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function buildIsolatedSettingsSnapshot(
|
|
112
|
+
settings: unknown,
|
|
113
|
+
providerName: string,
|
|
114
|
+
opencodeModelSpec: ModelSpec | null | undefined
|
|
115
|
+
): string | null {
|
|
116
|
+
const providerSettings = ownRecordValue(settings, 'providerSettings', 'settings') ?? {};
|
|
117
|
+
const selectedSettings = ownRecordValue(
|
|
118
|
+
providerSettings,
|
|
119
|
+
providerName,
|
|
120
|
+
'settings.providerSettings'
|
|
121
|
+
);
|
|
122
|
+
const webSearch = selectedSettings?.webSearch;
|
|
123
|
+
if (webSearch !== undefined && typeof webSearch !== 'boolean') {
|
|
124
|
+
throw permanentError(`settings.providerSettings.${providerName}.webSearch must be a boolean.`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const snapshot: IsolatedProviderSnapshot = {};
|
|
128
|
+
if (webSearch === true) snapshot.webSearch = true;
|
|
129
|
+
if (opencodeModelSpec !== null) {
|
|
130
|
+
const levelOverrides = resolveIsolatedOpenCodeOverrides(selectedSettings, opencodeModelSpec);
|
|
131
|
+
if (levelOverrides !== undefined) snapshot.levelOverrides = levelOverrides;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (Object.keys(snapshot).length === 0) return null;
|
|
135
|
+
return JSON.stringify({
|
|
136
|
+
providerSettings: {
|
|
137
|
+
[providerName]: snapshot,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
function resolveIsolatedOpenCodeOverrides(
|
|
144
|
+
selectedSettings: UnknownRecord | undefined,
|
|
145
|
+
modelSpec: ModelSpec | undefined
|
|
146
|
+
): IsolatedProviderSnapshot['levelOverrides'] {
|
|
147
|
+
const level = modelSpec?.level;
|
|
148
|
+
if (level !== 'level1' && level !== 'level2' && level !== 'level3') {
|
|
149
|
+
throw permanentError(
|
|
150
|
+
'Provider-level isolated OpenCode selections require a valid model level.'
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const levelOverrides = ownRecordValue(
|
|
155
|
+
selectedSettings,
|
|
156
|
+
'levelOverrides',
|
|
157
|
+
'settings.providerSettings.opencode'
|
|
158
|
+
);
|
|
159
|
+
const levelOverride = ownRecordValue(
|
|
160
|
+
levelOverrides,
|
|
161
|
+
level,
|
|
162
|
+
'settings.providerSettings.opencode.levelOverrides'
|
|
163
|
+
);
|
|
164
|
+
const configuredModel =
|
|
165
|
+
levelOverride && Object.prototype.hasOwnProperty.call(levelOverride, 'model')
|
|
166
|
+
? levelOverride.model
|
|
167
|
+
: null;
|
|
168
|
+
if (configuredModel !== null && typeof configuredModel !== 'string') {
|
|
169
|
+
throw permanentError(`Configured isolated OpenCode ${level} model must be a string or null.`);
|
|
170
|
+
}
|
|
171
|
+
if (modelSpec?.model !== configuredModel) {
|
|
172
|
+
throw permanentError(
|
|
173
|
+
`Provider-level model "${modelSpec?.model}" does not match ` +
|
|
174
|
+
`the effective isolated ${level} model "${configuredModel}".`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
return configuredModel === null ? undefined : { [level]: { model: configuredModel } };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function ownRecordValue(record: unknown, key: string, field: string): UnknownRecord | undefined {
|
|
181
|
+
if (record === null || record === undefined) return undefined;
|
|
182
|
+
if (!isUnknownRecord(record)) {
|
|
183
|
+
throw permanentError(`${field} must be an object.`);
|
|
184
|
+
}
|
|
185
|
+
if (!Object.prototype.hasOwnProperty.call(record, key)) return undefined;
|
|
186
|
+
const value = record[key];
|
|
187
|
+
if (value === null || value === undefined) return undefined;
|
|
188
|
+
if (!isUnknownRecord(value)) {
|
|
189
|
+
throw permanentError(`${field}.${key} must be an object.`);
|
|
190
|
+
}
|
|
191
|
+
return value;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function permanentError(message: string): Error & { permanent: true } {
|
|
195
|
+
return Object.assign(new Error(message), { permanent: true as const });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export = {
|
|
199
|
+
ISOLATED_SETTINGS_FILE_ENV,
|
|
200
|
+
ISOLATED_SETTINGS_FILE_MARKER,
|
|
201
|
+
LEGACY_ISOLATED_PROVIDER_SETTINGS_ENV,
|
|
202
|
+
appendTaskRunModelArgs,
|
|
203
|
+
wrapTaskRunWithIsolatedSettings,
|
|
204
|
+
};
|
package/src/task-runner.js
CHANGED
|
@@ -1,30 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
|
-
* TaskRunner - Strategy Pattern interface for executing provider tasks
|
|
3
|
-
*
|
|
4
|
-
* Implementations must provide a `run()` method that executes a task
|
|
5
|
-
* with the given context and options. Different runners can implement various
|
|
6
|
-
* execution strategies (CLI, mock responses, etc).
|
|
3
|
+
* TaskRunner - Strategy Pattern interface for executing provider tasks.
|
|
7
4
|
*/
|
|
8
5
|
class TaskRunner {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* @param {string} _context - Full prompt/context for the provider to process
|
|
13
|
-
* @param {Object} _options - Execution options
|
|
14
|
-
* @param {string} _options.agentId - Identifier for this agent/task
|
|
15
|
-
* @param {string} _options.model - Model to use (provider-specific model id)
|
|
16
|
-
* @param {string} [_options.provider] - Provider to use (claude|codex|gemini)
|
|
17
|
-
* @param {object} [_options.modelSpec] - Resolved model spec (level/model/reasoningEffort)
|
|
18
|
-
* @param {string} [_options.outputFormat] - Output format ('text', 'json', 'stream-json')
|
|
19
|
-
* @param {Object} [_options.jsonSchema] - JSON schema for structured output validation
|
|
20
|
-
* @param {string} [_options.cwd] - Working directory for task execution
|
|
21
|
-
* @param {boolean} [_options.isolation] - Whether to run in isolated container
|
|
22
|
-
*
|
|
23
|
-
* @returns {Promise<{success: boolean, output: string, error: string|null, taskId?: string}>} Result object with success status, output, error message, and optional taskId
|
|
24
|
-
*/
|
|
25
|
-
run(_context, _options) {
|
|
26
|
-
throw new Error('TaskRunner.run() not implemented');
|
|
27
|
-
}
|
|
6
|
+
run(_context, _options) {
|
|
7
|
+
throw new Error('TaskRunner.run() not implemented');
|
|
8
|
+
}
|
|
28
9
|
}
|
|
29
|
-
|
|
30
10
|
module.exports = TaskRunner;
|