@astrosheep/keiyaku 2.9.3 → 2.9.5
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/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms.js +14 -94
- package/build/agents/harness/activity-values.js +16 -0
- package/build/agents/harness/event-persistence.js +218 -0
- package/build/agents/harness/execution-handle.js +26 -222
- package/build/agents/harness/index.js +3 -1
- package/build/agents/harness/outcome.js +68 -5
- package/build/agents/harness/projection.js +179 -124
- package/build/agents/harness/provider-adapter.js +58 -0
- package/build/agents/harness/router.js +11 -187
- package/build/agents/harness/runtime.js +17 -4
- package/build/agents/harness/session.js +15 -0
- package/build/agents/launch-snapshot/model.js +15 -236
- package/build/agents/launch-snapshot/parse-helpers.js +114 -0
- package/build/agents/launch-snapshot/resolve.js +17 -43
- package/build/agents/opencode-sdk.js +45 -12
- package/build/agents/providers/claude-agent-sdk/adapter.js +6 -17
- package/build/agents/providers/claude-agent-sdk/registration.js +214 -0
- package/build/agents/providers/claude-agent-sdk/session-schema.js +2 -0
- package/build/agents/providers/codex-app-server/adapter.js +82 -53
- package/build/agents/providers/codex-app-server/events.js +90 -11
- package/build/agents/providers/codex-app-server/identity.js +1 -0
- package/build/agents/providers/codex-app-server/policy.js +29 -0
- package/build/agents/providers/codex-app-server/registration.js +248 -0
- package/build/agents/providers/codex-app-server/session-schema.js +6 -0
- package/build/agents/providers/codex-app-server/session.js +23 -17
- package/build/agents/providers/codex-app-server/terms.js +1 -0
- package/build/agents/providers/opencode-sdk/adapter.js +94 -50
- package/build/agents/providers/opencode-sdk/events.js +8 -4
- package/build/agents/providers/opencode-sdk/registration.js +135 -0
- package/build/agents/providers/opencode-sdk/session-schema.js +2 -0
- package/build/agents/providers/opencode-sdk/session.js +21 -14
- package/build/agents/providers/opencode-sdk/terms.js +1 -0
- package/build/agents/providers/pi/adapter.js +36 -30
- package/build/agents/providers/pi/events.js +4 -3
- package/build/agents/providers/pi/registration.js +145 -0
- package/build/agents/providers/pi/session-schema.js +6 -0
- package/build/agents/providers/pi/terms.js +1 -0
- package/build/agents/providers/registration.js +7 -0
- package/build/agents/providers/registry.js +76 -0
- package/build/agents/selector.js +2 -29
- package/build/agents/types.js +10 -0
- package/build/artifact-directories.js +22 -0
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +1 -1
- package/build/cli/commands/akuma/list/meta-ls.js +1 -1
- package/build/cli/commands/akuma/view/handler.js +5 -4
- package/build/cli/commands/akuma/view/meta.js +1 -1
- package/build/cli/commands/akuma.js +6 -0
- package/build/cli/commands/contract/amend/handler.js +8 -2
- package/build/cli/commands/contract/amend/meta.js +4 -4
- package/build/cli/commands/contract/arc/handler.js +8 -2
- package/build/cli/commands/contract/arc/meta.js +4 -4
- package/build/cli/commands/contract/audit/handler.js +16 -0
- package/build/cli/commands/contract/audit/meta.js +16 -0
- package/build/cli/commands/contract/bind/handler.js +4 -3
- package/build/cli/commands/contract/bind/meta.js +44 -8
- package/build/cli/commands/contract/catalog.js +2 -0
- package/build/cli/commands/contract/forfeit/handler.js +4 -4
- package/build/cli/commands/contract/forfeit/meta.js +1 -1
- package/build/cli/commands/contract/log/handler.js +3 -3
- package/build/cli/commands/contract/log/meta.js +1 -1
- package/build/cli/commands/contract/petition/handler.js +5 -8
- package/build/cli/commands/contract/petition/meta.js +6 -6
- package/build/cli/commands/contract/renew/handler.js +20 -6
- package/build/cli/commands/contract/renew/meta.js +6 -5
- package/build/cli/commands/metadata.js +59 -0
- package/build/cli/commands/projection/call/handler.js +6 -5
- package/build/cli/commands/projection/call/meta.js +4 -1
- package/build/cli/commands/projection/kill/handler.js +16 -32
- package/build/cli/commands/projection/kill/meta.js +1 -1
- package/build/cli/commands/projection/revive/meta.js +4 -1
- package/build/cli/commands/projection/shared.js +28 -0
- package/build/cli/commands/projection/status/handler.js +1 -1
- package/build/cli/commands/projection/status/meta.js +1 -1
- package/build/cli/commands/projection/tell/handler.js +14 -30
- package/build/cli/commands/projection/tell/meta.js +4 -1
- package/build/cli/commands/projection/wait/handler.js +45 -22
- package/build/cli/commands/projection/wait/meta.js +8 -3
- package/build/cli/commands/registry.js +2 -54
- package/build/cli/commands/shared.js +10 -7
- package/build/cli/commands/skills/install/handler.js +2 -5
- package/build/cli/commands/skills/install/meta.js +1 -1
- package/build/cli/commands/skills/skills/handler.js +1 -1
- package/build/cli/commands/skills/skills/meta.js +1 -1
- package/build/cli/commands/system/completion/meta.js +1 -1
- package/build/cli/commands/system/dump-env/meta.js +1 -1
- package/build/cli/commands/system/guide/meta.js +1 -1
- package/build/cli/commands/task/add/handler.js +7 -15
- package/build/cli/commands/task/add/meta.js +4 -1
- package/build/cli/commands/task/catalog.js +2 -2
- package/build/cli/commands/task/doctor/meta.js +1 -1
- package/build/cli/commands/task/done/handler.js +4 -8
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/handler.js +3 -6
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/ls/handler.js +12 -8
- package/build/cli/commands/task/ls/meta.js +3 -3
- package/build/cli/commands/task/shared.js +14 -4
- package/build/cli/commands/task/{view → show}/handler.js +7 -8
- package/build/cli/commands/task/show/meta.js +8 -0
- package/build/cli/commands/task/start/handler.js +3 -6
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +4 -8
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/task/handler.js +1 -1
- package/build/cli/commands/task/task/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +6 -11
- package/build/cli/commands/task/update/meta.js +4 -1
- package/build/cli/completion.js +1 -1
- package/build/cli/flags.js +37 -6
- package/build/cli/help.js +7 -14
- package/build/cli/index.js +112 -154
- package/build/cli/missing-subcommand.js +7 -0
- package/build/cli/output-stream-error-policy.js +19 -5
- package/build/cli/parse-flags.js +33 -7
- package/build/cli/parse-metadata.js +3 -9
- package/build/cli/parse-selectors.js +2 -1
- package/build/cli/parse.js +35 -5
- package/build/cli/projection-address.js +12 -12
- package/build/cli/render/address.js +41 -37
- package/build/cli/render/arc.js +24 -12
- package/build/cli/render/audit.js +121 -0
- package/build/cli/render/call.js +11 -5
- package/build/cli/render/errors.js +36 -1
- package/build/cli/render/format.js +4 -0
- package/build/cli/render/kanshi.js +6 -12
- package/build/cli/render/kill.js +9 -0
- package/build/cli/render/misc.js +58 -13
- package/build/cli/render/petition.js +20 -15
- package/build/cli/render/projection-activity.js +15 -6
- package/build/cli/render/shared.js +60 -21
- package/build/cli/render/skills.js +10 -0
- package/build/cli/render/status.js +56 -23
- package/build/cli/render/success-response.js +78 -0
- package/build/cli/render/task.js +66 -57
- package/build/cli/render/tell.js +5 -0
- package/build/cli/render/terminal-failure.js +63 -0
- package/build/cli/render/types.js +1 -0
- package/build/cli/render/wait.js +68 -38
- package/build/cli/types.js +1 -1
- package/build/config/akuma-loader.js +0 -5
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +3 -0
- package/build/config/provider-policy-ownership.js +3 -32
- package/build/config/settings/disease.js +8 -1
- package/build/config/settings/loader.js +11 -3
- package/build/config/settings/provider-instance-fields.js +51 -0
- package/build/config/settings/schema.js +6 -176
- package/build/core/addressing.js +66 -16
- package/build/core/amend.js +61 -18
- package/build/core/arc.js +33 -73
- package/build/core/audit.js +650 -0
- package/build/core/bind.js +82 -35
- package/build/core/call/call.js +15 -9
- package/build/core/call/context.js +6 -51
- package/build/core/call/execution.js +22 -22
- package/build/core/call/prompt.js +14 -1
- package/build/core/command-markdown.js +45 -0
- package/build/core/context.js +13 -7
- package/build/core/contract-view.js +22 -6
- package/build/core/draft.js +139 -19
- package/build/core/entry.js +3 -4
- package/build/core/forfeit.js +5 -2
- package/build/core/hints.js +1 -75
- package/build/core/identifier-slug.js +66 -0
- package/build/core/ids.js +25 -11
- package/build/core/ledger.js +20 -68
- package/build/core/markdown/lex.js +2 -1
- package/build/core/markdown/parser.js +0 -68
- package/build/core/markdown/render.js +68 -0
- package/build/core/markdown/sections.js +2 -1
- package/build/core/outcome-base.js +4 -0
- package/build/core/projection/generation/database.js +41 -52
- package/build/core/projection/generation/model.js +63 -2
- package/build/core/{projection-generation-continuation.js → projection/generation/projection-generation-continuation.js} +3 -3
- package/build/core/{projection-generation-execution.js → projection/generation/projection-generation-execution.js} +36 -53
- package/build/core/{projection-generation-identity.js → projection/generation/projection-generation-identity.js} +2 -2
- package/build/core/{projection-generation-launcher.js → projection/generation/projection-generation-launcher.js} +9 -7
- package/build/core/{projection-generation-process.js → projection/generation/projection-generation-process.js} +2 -1
- package/build/core/{projection-generation-runner.js → projection/generation/projection-generation-runner.js} +19 -3
- package/build/core/projection/generation/store.js +3 -3
- package/build/core/projection/generation/transitions.js +19 -3
- package/build/core/projection/index.js +27 -0
- package/build/core/{projection-activity.js → projection/projection-activity.js} +12 -0
- package/build/core/{projection-alias.js → projection/projection-alias.js} +13 -13
- package/build/core/projection/projection-coordinate.js +61 -0
- package/build/core/{projection-core.js → projection/projection-core.js} +9 -9
- package/build/core/{projection-execution-observer.js → projection/projection-execution-observer.js} +37 -78
- package/build/core/{projection-identity.js → projection/projection-identity.js} +1 -1
- package/build/core/{projection-kill.js → projection/projection-kill.js} +1 -1
- package/build/core/{projection-life-observer.js → projection/projection-life-observer.js} +16 -2
- package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
- package/build/core/{projection-status.js → projection/projection-status.js} +163 -45
- package/build/core/projection/projection-terminal-failure.js +106 -0
- package/build/core/projection/projection-wait.js +275 -0
- package/build/core/projection/projection-wake.js +227 -0
- package/build/core/provider-loader-ports.js +4 -0
- package/build/core/ref-log.js +65 -40
- package/build/core/registry.js +63 -10
- package/build/core/renew-session.js +128 -0
- package/build/core/renew.js +448 -102
- package/build/core/scope.js +272 -68
- package/build/core/seal.js +165 -40
- package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +8 -8
- package/build/core/{claim.js → settlement/claim.js} +32 -8
- package/build/core/settlement/index.js +19 -0
- package/build/core/{petition-claim-gates.js → settlement/petition-claim-gates.js} +24 -49
- package/build/core/{petition-forfeit.js → settlement/petition-forfeit.js} +2 -2
- package/build/core/{petition-head-guard.js → settlement/petition-head-guard.js} +2 -2
- package/build/core/settlement/petition-io.js +1 -0
- package/build/core/{petition-preview.js → settlement/petition-preview.js} +2 -2
- package/build/core/{petition.js → settlement/petition.js} +21 -12
- package/build/core/settlement/queue-read-model.js +143 -0
- package/build/core/settlement/queue-seat-allocation.js +156 -0
- package/build/core/settlement/queue.js +6 -0
- package/build/core/settlement/settlement.js +288 -0
- package/build/core/{verdict.js → settlement/verdict.js} +9 -37
- package/build/core/settlement/verification.js +59 -0
- package/build/core/status/board.js +62 -41
- package/build/core/status/ledger-batch.js +158 -0
- package/build/core/status/reconciliation.js +10 -4
- package/build/core/stored-agent-event.js +6 -2
- package/build/core/task/board.js +41 -4
- package/build/core/task/commands.js +45 -28
- package/build/core/task/document.js +5 -0
- package/build/core/task/index.js +12 -0
- package/build/core/task/model.js +8 -1
- package/build/core/task/query.js +172 -0
- package/build/core/task/settlement-git.js +265 -74
- package/build/core/task/settlement-policy.js +67 -29
- package/build/core/task/source-board.js +1 -0
- package/build/core/task/task-contract.js +444 -0
- package/build/core/{task-doctor.js → task/task-doctor.js} +1 -1
- package/build/core/{task-git-actor.js → task/task-git-actor.js} +5 -10
- package/build/core/{task-git-runtime.js → task/task-git-runtime.js} +3 -3
- package/build/core/{task-git-store.js → task/task-git-store.js} +90 -19
- package/build/core/task/task-repository.js +1 -0
- package/build/core/{task-store-repository.js → task/task-store-repository.js} +6 -4
- package/build/core/task/task-store.js +1 -0
- package/build/core/{task-worktree.js → task/task-worktree.js} +2 -1
- package/build/core/task/task.js +7 -0
- package/build/core/task/tree.js +37 -0
- package/build/core/task/validation.js +5 -2
- package/build/core/transcripts.js +15 -3
- package/build/core/worktree-path.js +43 -28
- package/build/flow-error.js +83 -39
- package/build/fs/path-coordinate.js +16 -0
- package/build/generated/version.js +3 -2
- package/build/git/branches.js +2 -1
- package/build/git/core.js +106 -2
- package/build/git/diff/parsers.js +23 -13
- package/build/git/diff/structured.js +127 -0
- package/build/git/path-coordinate.js +17 -0
- package/build/git/refs.js +57 -0
- package/build/git/streaming-batch.js +301 -0
- package/build/git/worktree.js +65 -0
- package/build/index.js +9 -9
- package/build/keiyaku.js +2 -36
- package/build/telemetry/logger.js +4 -2
- package/package.json +4 -10
- package/skills/keiyaku/SKILL.md +5 -4
- package/skills/keiyaku-akuma/SKILL.md +25 -11
- package/skills/keiyaku-task/SKILL.md +17 -8
- package/skills/keiyaku-workflow/SKILL.md +58 -9
- package/build/agents/providers/codex-sdk.js +0 -329
- package/build/cli/commands/task/view/meta.js +0 -8
- package/build/core/command-io.js +0 -174
- package/build/core/path-coordinate.js +0 -27
- package/build/core/petition-claim.js +0 -117
- package/build/core/petition-run.js +0 -83
- package/build/core/projection-coordinate.js +0 -63
- package/build/core/projection-wait.js +0 -165
- package/build/core/projection-wake.js +0 -136
- package/build/core/queue.js +0 -343
- package/build/core/task-contract.js +0 -237
- package/build/core/task.js +0 -4
- /package/build/{core/task-repository.js → agents/launch-snapshot/types.js} +0 -0
- /package/build/{core/task-store.js → agents/providers/claude-agent-sdk/terms.js} +0 -0
- /package/build/core/{projection-generation-runtime.js → projection/generation/projection-generation-runtime.js} +0 -0
- /package/build/core/{projection-life-protocol.js → projection/projection-life-protocol.js} +0 -0
- /package/build/core/{projection-runner-lock.js → projection/projection-runner-lock.js} +0 -0
|
@@ -1,30 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SUBAGENT_SESSION_VERSION, subagentSessionEnvelopeSchema, } from "../session.js";
|
|
3
|
-
import { startClaudeAgentSdk, claudeSessionSchema, } from "../providers/claude-agent-sdk/adapter.js";
|
|
4
|
-
import { startCodexAppServer, codexAppServerSessionSchema, } from "../providers/codex-app-server/adapter.js";
|
|
5
|
-
import { startCodexSdk, codexThreadSchema, } from "../providers/codex-sdk.js";
|
|
6
|
-
import { startOpencode, opencodeSessionSchema, } from "../providers/opencode-sdk/adapter.js";
|
|
7
|
-
import { startPi, piSessionSchema, } from "../providers/pi/adapter.js";
|
|
8
|
-
function admitResumeShape(provider, schema, session, resumePath) {
|
|
9
|
-
const envelopeResult = subagentSessionEnvelopeSchema.safeParse(session);
|
|
10
|
-
if (!envelopeResult.success) {
|
|
11
|
-
throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' includes an invalid session envelope.`);
|
|
12
|
-
}
|
|
13
|
-
if (session.provider !== provider) {
|
|
14
|
-
throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' was created with provider '${session.provider}', but the selected subagent resolves to '${provider}'. Cross-provider resume is not supported.`);
|
|
15
|
-
}
|
|
16
|
-
if (session.version !== SUBAGENT_SESSION_VERSION) {
|
|
17
|
-
throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' uses unsupported session version '${session.version}' for provider '${session.provider}'.`);
|
|
18
|
-
}
|
|
19
|
-
const shapeResult = schema.safeParse(session.handle);
|
|
20
|
-
if (!shapeResult.success) {
|
|
21
|
-
throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' includes an invalid session handle for provider '${session.provider}'.`);
|
|
22
|
-
}
|
|
23
|
-
return shapeResult.data;
|
|
24
|
-
}
|
|
25
|
-
function assertNever(_value) {
|
|
26
|
-
throw new Error("Unhandled provider");
|
|
27
|
-
}
|
|
1
|
+
import { getProviderRegistration } from "../providers/registry.js";
|
|
28
2
|
export async function startLiveProjection(terms, signal, reviveTerms, onIngress, observer) {
|
|
29
3
|
const onSyncCheckpoint = observer
|
|
30
4
|
? (control, checkpoint) => {
|
|
@@ -38,164 +12,14 @@ export async function startLiveProjection(terms, signal, reviveTerms, onIngress,
|
|
|
38
12
|
observer.onDeliveryOpportunity(control);
|
|
39
13
|
}
|
|
40
14
|
: undefined;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
onSyncCheckpoint,
|
|
52
|
-
onEvidence: terms.onEvidence,
|
|
53
|
-
onIngress,
|
|
54
|
-
initialTurn: terms.initialTurn,
|
|
55
|
-
loader: terms.loader,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
return startPi(terms.prompt, terms.workdir, {
|
|
59
|
-
model: terms.model,
|
|
60
|
-
thinkingLevel: terms.thinkingLevel,
|
|
61
|
-
signal,
|
|
62
|
-
appendSystemPromptOverride: terms.appendSystemPromptOverride,
|
|
63
|
-
onSyncCheckpoint,
|
|
64
|
-
onEvidence: terms.onEvidence,
|
|
65
|
-
onIngress,
|
|
66
|
-
initialTurn: terms.initialTurn,
|
|
67
|
-
loader: terms.loader,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
case "claude-agent-sdk": {
|
|
71
|
-
const claudeOptions = {
|
|
72
|
-
model: terms.model,
|
|
73
|
-
executable: terms.executable,
|
|
74
|
-
effort: terms.effort,
|
|
75
|
-
env: terms.env,
|
|
76
|
-
signal,
|
|
77
|
-
permissionMode: terms.permissionMode,
|
|
78
|
-
settingSources: terms.settingSources,
|
|
79
|
-
allowDangerouslySkipPermissions: terms.allowDangerouslySkipPermissions,
|
|
80
|
-
disallowedTools: terms.disallowedTools,
|
|
81
|
-
systemPrompt: terms.systemPrompt,
|
|
82
|
-
onSyncCheckpoint,
|
|
83
|
-
onEvidence: terms.onEvidence,
|
|
84
|
-
onIngress,
|
|
85
|
-
initialTurn: terms.initialTurn,
|
|
86
|
-
loader: terms.loader,
|
|
87
|
-
};
|
|
88
|
-
if (reviveTerms) {
|
|
89
|
-
const session = admitResumeShape("claude-agent-sdk", claudeSessionSchema, reviveTerms.session, reviveTerms.resumePath);
|
|
90
|
-
return startClaudeAgentSdk(terms.prompt, terms.workdir, {
|
|
91
|
-
...claudeOptions,
|
|
92
|
-
sessionId: session.sessionId,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
return startClaudeAgentSdk(terms.prompt, terms.workdir, claudeOptions);
|
|
96
|
-
}
|
|
97
|
-
case "codex-app-server": {
|
|
98
|
-
if (reviveTerms) {
|
|
99
|
-
const session = admitResumeShape("codex-app-server", codexAppServerSessionSchema, reviveTerms.session, reviveTerms.resumePath);
|
|
100
|
-
return startCodexAppServer(terms.prompt, terms.workdir, {
|
|
101
|
-
model: terms.model,
|
|
102
|
-
effort: terms.effort,
|
|
103
|
-
profile: terms.profile,
|
|
104
|
-
config: terms.config,
|
|
105
|
-
sandboxPolicy: terms.sandboxPolicy,
|
|
106
|
-
approvalPolicy: terms.approvalPolicy,
|
|
107
|
-
executable: terms.executable,
|
|
108
|
-
env: terms.env,
|
|
109
|
-
signal,
|
|
110
|
-
threadId: session.threadId,
|
|
111
|
-
codexHome: session.codexHome,
|
|
112
|
-
developerInstructions: terms.developerInstructions,
|
|
113
|
-
onSyncCheckpoint,
|
|
114
|
-
onDeliveryOpportunity,
|
|
115
|
-
onEvidence: terms.onEvidence,
|
|
116
|
-
onIngress,
|
|
117
|
-
initialTurn: terms.initialTurn,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
return startCodexAppServer(terms.prompt, terms.workdir, {
|
|
121
|
-
model: terms.model,
|
|
122
|
-
effort: terms.effort,
|
|
123
|
-
profile: terms.profile,
|
|
124
|
-
config: terms.config,
|
|
125
|
-
sandboxPolicy: terms.sandboxPolicy,
|
|
126
|
-
approvalPolicy: terms.approvalPolicy,
|
|
127
|
-
executable: terms.executable,
|
|
128
|
-
env: terms.env,
|
|
129
|
-
signal,
|
|
130
|
-
developerInstructions: terms.developerInstructions,
|
|
131
|
-
onSyncCheckpoint,
|
|
132
|
-
onDeliveryOpportunity,
|
|
133
|
-
onEvidence: terms.onEvidence,
|
|
134
|
-
onIngress,
|
|
135
|
-
initialTurn: terms.initialTurn,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
case "codex-sdk": {
|
|
139
|
-
if (reviveTerms) {
|
|
140
|
-
const session = admitResumeShape("codex-sdk", codexThreadSchema, reviveTerms.session, reviveTerms.resumePath);
|
|
141
|
-
return startCodexSdk(terms.prompt, terms.workdir, {
|
|
142
|
-
model: terms.model,
|
|
143
|
-
profile: terms.profile,
|
|
144
|
-
config: terms.config,
|
|
145
|
-
threadOptions: terms.threadOptions,
|
|
146
|
-
executable: terms.executable,
|
|
147
|
-
signal,
|
|
148
|
-
threadId: session.threadId,
|
|
149
|
-
onEvidence: terms.onEvidence,
|
|
150
|
-
onIngress,
|
|
151
|
-
initialTurn: terms.initialTurn,
|
|
152
|
-
codexConstructor: terms.codexConstructor,
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
return startCodexSdk(terms.prompt, terms.workdir, {
|
|
156
|
-
model: terms.model,
|
|
157
|
-
profile: terms.profile,
|
|
158
|
-
config: terms.config,
|
|
159
|
-
threadOptions: terms.threadOptions,
|
|
160
|
-
executable: terms.executable,
|
|
161
|
-
signal,
|
|
162
|
-
onEvidence: terms.onEvidence,
|
|
163
|
-
onIngress,
|
|
164
|
-
initialTurn: terms.initialTurn,
|
|
165
|
-
codexConstructor: terms.codexConstructor,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
case "opencode-sdk": {
|
|
169
|
-
if (reviveTerms) {
|
|
170
|
-
const session = admitResumeShape("opencode-sdk", opencodeSessionSchema, reviveTerms.session, reviveTerms.resumePath);
|
|
171
|
-
return startOpencode(terms.prompt, terms.workdir, {
|
|
172
|
-
model: terms.model,
|
|
173
|
-
effort: terms.effort,
|
|
174
|
-
executable: terms.executable,
|
|
175
|
-
env: terms.env,
|
|
176
|
-
signal,
|
|
177
|
-
sessionId: session.sessionId,
|
|
178
|
-
onSyncCheckpoint,
|
|
179
|
-
onDeliveryOpportunity,
|
|
180
|
-
onEvidence: terms.onEvidence,
|
|
181
|
-
onIngress,
|
|
182
|
-
initialTurn: terms.initialTurn,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
return startOpencode(terms.prompt, terms.workdir, {
|
|
186
|
-
model: terms.model,
|
|
187
|
-
effort: terms.effort,
|
|
188
|
-
executable: terms.executable,
|
|
189
|
-
env: terms.env,
|
|
190
|
-
signal,
|
|
191
|
-
onSyncCheckpoint,
|
|
192
|
-
onDeliveryOpportunity,
|
|
193
|
-
onEvidence: terms.onEvidence,
|
|
194
|
-
onIngress,
|
|
195
|
-
initialTurn: terms.initialTurn,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
default:
|
|
199
|
-
return assertNever(terms);
|
|
200
|
-
}
|
|
15
|
+
const registration = getProviderRegistration(terms.provider);
|
|
16
|
+
return registration.startLive({
|
|
17
|
+
terms,
|
|
18
|
+
signal,
|
|
19
|
+
reviveTerms,
|
|
20
|
+
onSyncCheckpoint,
|
|
21
|
+
onDeliveryOpportunity,
|
|
22
|
+
onIngress,
|
|
23
|
+
observer,
|
|
24
|
+
});
|
|
201
25
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { getConfig } from "../../config/env.js";
|
|
3
3
|
import { DISABLE_SUBAGENT_SPAWN_ENV_KEY } from "../../config/env-keys.js";
|
|
4
|
+
export const PROVIDER_ABORT_SETTLEMENT_TIMEOUT_MS = 5_000;
|
|
4
5
|
export function sha256Utf8(value) {
|
|
5
6
|
const bytes = Buffer.from(value, "utf8");
|
|
6
7
|
return { sha256: createHash("sha256").update(bytes).digest("hex"), byteLength: bytes.byteLength };
|
|
@@ -33,10 +34,22 @@ export function emitProviderEvidence(callback, evidence, diagnostic) {
|
|
|
33
34
|
reportFailure();
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
|
-
export
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
export { createAbortError } from "./provider-adapter.js";
|
|
38
|
+
export async function awaitProviderAbortSettlement(provider, settlement, operation = "graceful abort could not prove provider terminal settlement") {
|
|
39
|
+
let timer;
|
|
40
|
+
const deadline = new Promise((_, reject) => {
|
|
41
|
+
timer = setTimeout(() => {
|
|
42
|
+
reject(new Error(`${provider} ${operation} within ${PROVIDER_ABORT_SETTLEMENT_TIMEOUT_MS}ms`));
|
|
43
|
+
}, PROVIDER_ABORT_SETTLEMENT_TIMEOUT_MS);
|
|
44
|
+
timer.unref?.();
|
|
45
|
+
});
|
|
46
|
+
try {
|
|
47
|
+
return await Promise.race([settlement, deadline]);
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
if (timer)
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
}
|
|
40
53
|
}
|
|
41
54
|
export function coerceString(value) {
|
|
42
55
|
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isSubagentProvider } from "../../keiyaku.js";
|
|
2
|
+
import { SUBAGENT_SESSION_VERSION, subagentSessionEnvelopeSchema, } from "../session.js";
|
|
3
|
+
import { getProviderRegistration } from "../providers/registry.js";
|
|
4
|
+
/** Validate a continuation envelope through its owning provider schema. */
|
|
5
|
+
export function isRecoverableSessionEnvelope(provider, value) {
|
|
6
|
+
if (!isSubagentProvider(provider))
|
|
7
|
+
return false;
|
|
8
|
+
const envelope = subagentSessionEnvelopeSchema.safeParse(value);
|
|
9
|
+
if (!envelope.success)
|
|
10
|
+
return false;
|
|
11
|
+
if (envelope.data.provider !== provider || envelope.data.version !== SUBAGENT_SESSION_VERSION) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
return getProviderRegistration(provider).sessionSchema.safeParse(envelope.data.handle).success;
|
|
15
|
+
}
|
|
@@ -1,91 +1,11 @@
|
|
|
1
|
-
import * as path from "node:path";
|
|
2
1
|
import { FlowError } from "../../flow-error.js";
|
|
2
|
+
import { getProviderRegistration, isSubagentProvider, } from "../providers/registry.js";
|
|
3
|
+
import { exactKeys, objectAt, optionalString, requiredEnum, requiredString, snapshotError, } from "./parse-helpers.js";
|
|
3
4
|
const ACCESS_VALUES = new Set(["read", "write", "auto"]);
|
|
4
5
|
const NETWORK_VALUES = new Set(["disabled", "enabled"]);
|
|
5
6
|
const WEB_SEARCH_VALUES = new Set(["disabled", "cached", "live"]);
|
|
6
7
|
const AKUMA_SOURCES = new Set(["builtin", "user", "project"]);
|
|
7
8
|
const PROVIDER_SOURCES = new Set(["builtin", "global", "project"]);
|
|
8
|
-
const CLAUDE_SETTING_SOURCES = new Set(["project", "user", "local"]);
|
|
9
|
-
function snapshotError(fieldPath, message) {
|
|
10
|
-
return new Error(`Invalid resolved Akuma launch snapshot at ${fieldPath}: ${message}`);
|
|
11
|
-
}
|
|
12
|
-
function isPlainObject(value) {
|
|
13
|
-
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
14
|
-
return false;
|
|
15
|
-
const prototype = Object.getPrototypeOf(value);
|
|
16
|
-
return prototype === Object.prototype || prototype === null;
|
|
17
|
-
}
|
|
18
|
-
function objectAt(value, fieldPath) {
|
|
19
|
-
if (!isPlainObject(value))
|
|
20
|
-
throw snapshotError(fieldPath, "must be a plain JSON object");
|
|
21
|
-
return value;
|
|
22
|
-
}
|
|
23
|
-
function exactKeys(value, allowed, fieldPath) {
|
|
24
|
-
const allowedSet = new Set(allowed);
|
|
25
|
-
for (const key of Object.keys(value)) {
|
|
26
|
-
if (!allowedSet.has(key))
|
|
27
|
-
throw snapshotError(`${fieldPath}.${key}`, "is an unknown field");
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function requiredString(value, key, fieldPath, allowBlank = false) {
|
|
31
|
-
const item = value[key];
|
|
32
|
-
if (typeof item !== "string" || (!allowBlank && item.trim().length === 0)) {
|
|
33
|
-
throw snapshotError(`${fieldPath}.${key}`, allowBlank ? "must be a string" : "must be a nonblank string");
|
|
34
|
-
}
|
|
35
|
-
return item;
|
|
36
|
-
}
|
|
37
|
-
function optionalString(value, key, fieldPath) {
|
|
38
|
-
if (!(key in value))
|
|
39
|
-
return undefined;
|
|
40
|
-
return requiredString(value, key, fieldPath);
|
|
41
|
-
}
|
|
42
|
-
function requiredEnum(value, key, fieldPath, values) {
|
|
43
|
-
const item = requiredString(value, key, fieldPath);
|
|
44
|
-
if (!values.has(item))
|
|
45
|
-
throw snapshotError(`${fieldPath}.${key}`, `has invalid value '${item}'`);
|
|
46
|
-
return item;
|
|
47
|
-
}
|
|
48
|
-
function cloneJson(value, fieldPath, ancestors = new Set()) {
|
|
49
|
-
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
50
|
-
return value;
|
|
51
|
-
if (typeof value === "number") {
|
|
52
|
-
if (!Number.isFinite(value))
|
|
53
|
-
throw snapshotError(fieldPath, "contains a non-finite number");
|
|
54
|
-
return value;
|
|
55
|
-
}
|
|
56
|
-
if (typeof value !== "object")
|
|
57
|
-
throw snapshotError(fieldPath, "contains a non-JSON value");
|
|
58
|
-
if (ancestors.has(value))
|
|
59
|
-
throw snapshotError(fieldPath, "contains a cycle");
|
|
60
|
-
ancestors.add(value);
|
|
61
|
-
try {
|
|
62
|
-
if (Array.isArray(value)) {
|
|
63
|
-
return Object.freeze(value.map((item, index) => cloneJson(item, `${fieldPath}[${index}]`, ancestors)));
|
|
64
|
-
}
|
|
65
|
-
if (!isPlainObject(value))
|
|
66
|
-
throw snapshotError(fieldPath, "contains a non-plain JSON object");
|
|
67
|
-
const result = {};
|
|
68
|
-
for (const [key, item] of Object.entries(value)) {
|
|
69
|
-
Object.defineProperty(result, key, {
|
|
70
|
-
value: cloneJson(item, `${fieldPath}.${key}`, ancestors),
|
|
71
|
-
enumerable: true,
|
|
72
|
-
configurable: true,
|
|
73
|
-
writable: true,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
return Object.freeze(result);
|
|
77
|
-
}
|
|
78
|
-
finally {
|
|
79
|
-
ancestors.delete(value);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function cloneJsonObject(value, fieldPath) {
|
|
83
|
-
const cloned = cloneJson(value, fieldPath);
|
|
84
|
-
if (!isPlainObject(cloned)) {
|
|
85
|
-
throw snapshotError(fieldPath, "must be a plain JSON object");
|
|
86
|
-
}
|
|
87
|
-
return cloned;
|
|
88
|
-
}
|
|
89
9
|
function effortOptionsFrom(akuma) {
|
|
90
10
|
if (!("effortOptions" in akuma))
|
|
91
11
|
return undefined;
|
|
@@ -118,21 +38,7 @@ function assertEffortRequiresModel(model, effort, kind, akumaName) {
|
|
|
118
38
|
throw new FlowError("INVALID_EFFORT_OVERRIDE", `Effort '${effort}' requires an explicit model.`);
|
|
119
39
|
}
|
|
120
40
|
function providerEffortAndModel(provider) {
|
|
121
|
-
|
|
122
|
-
case "codex-sdk": {
|
|
123
|
-
const model = typeof provider.threadOptions.model === "string" ? provider.threadOptions.model : undefined;
|
|
124
|
-
const effort = typeof provider.threadOptions.modelReasoningEffort === "string"
|
|
125
|
-
? provider.threadOptions.modelReasoningEffort
|
|
126
|
-
: undefined;
|
|
127
|
-
return { model, effort };
|
|
128
|
-
}
|
|
129
|
-
case "codex-app-server":
|
|
130
|
-
case "claude-agent-sdk":
|
|
131
|
-
case "opencode-sdk":
|
|
132
|
-
return { model: provider.model, effort: provider.effort };
|
|
133
|
-
case "pi":
|
|
134
|
-
return { model: provider.model, effort: provider.thinkingLevel };
|
|
135
|
-
}
|
|
41
|
+
return getProviderRegistration(provider.kind).providerEffortAndModel(provider);
|
|
136
42
|
}
|
|
137
43
|
function assertSnapshotEffortRequiresModel(snapshot) {
|
|
138
44
|
const fromAkuma = { model: snapshot.akuma.model, effort: snapshot.akuma.effort };
|
|
@@ -141,7 +47,8 @@ function assertSnapshotEffortRequiresModel(snapshot) {
|
|
|
141
47
|
}
|
|
142
48
|
const fromProvider = providerEffortAndModel(snapshot.provider);
|
|
143
49
|
if (fromProvider.effort !== undefined && fromProvider.model === undefined) {
|
|
144
|
-
|
|
50
|
+
const effortField = getProviderRegistration(snapshot.provider.kind).effortField;
|
|
51
|
+
throw snapshotError(`provider.${effortField}`, "requires an explicit model");
|
|
145
52
|
}
|
|
146
53
|
}
|
|
147
54
|
function parsePolicy(value) {
|
|
@@ -184,133 +91,14 @@ function parseProviderCommon(provider) {
|
|
|
184
91
|
source: requiredEnum(provider, "source", "provider", PROVIDER_SOURCES),
|
|
185
92
|
};
|
|
186
93
|
}
|
|
187
|
-
function optionalJsonObject(provider, key) {
|
|
188
|
-
return key in provider ? cloneJsonObject(provider[key], `provider.${key}`) : undefined;
|
|
189
|
-
}
|
|
190
|
-
function optionalStringRecord(provider, key) {
|
|
191
|
-
if (!(key in provider))
|
|
192
|
-
return undefined;
|
|
193
|
-
const value = provider[key];
|
|
194
|
-
if (!isPlainObject(value))
|
|
195
|
-
throw snapshotError(`provider.${key}`, "must be a plain JSON object");
|
|
196
|
-
const result = {};
|
|
197
|
-
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
198
|
-
if (typeof entryValue !== "string") {
|
|
199
|
-
throw snapshotError(`provider.${key}.${entryKey}`, "must be a string");
|
|
200
|
-
}
|
|
201
|
-
result[entryKey] = entryValue;
|
|
202
|
-
}
|
|
203
|
-
return Object.freeze(result);
|
|
204
|
-
}
|
|
205
|
-
function parseSandboxPolicy(value) {
|
|
206
|
-
const sandbox = objectAt(value, "provider.sandboxPolicy");
|
|
207
|
-
exactKeys(sandbox, ["type", "writableRoots", "networkAccess", "excludeTmpdirEnvVar", "excludeSlashTmp"], "provider.sandboxPolicy");
|
|
208
|
-
if (sandbox.type !== "workspaceWrite")
|
|
209
|
-
throw snapshotError("provider.sandboxPolicy.type", "must equal 'workspaceWrite'");
|
|
210
|
-
if (!Array.isArray(sandbox.writableRoots) || sandbox.writableRoots.length === 0) {
|
|
211
|
-
throw snapshotError("provider.sandboxPolicy.writableRoots", "must be a nonempty array");
|
|
212
|
-
}
|
|
213
|
-
const roots = sandbox.writableRoots.map((root, index) => {
|
|
214
|
-
if (typeof root !== "string" || !path.isAbsolute(root) || path.resolve(root) !== root) {
|
|
215
|
-
throw snapshotError(`provider.sandboxPolicy.writableRoots[${index}]`, "must be a lexically normalized absolute path");
|
|
216
|
-
}
|
|
217
|
-
return root;
|
|
218
|
-
});
|
|
219
|
-
if (new Set(roots).size !== roots.length) {
|
|
220
|
-
throw snapshotError("provider.sandboxPolicy.writableRoots", "must not contain duplicates");
|
|
221
|
-
}
|
|
222
|
-
for (const key of ["networkAccess", "excludeTmpdirEnvVar", "excludeSlashTmp"]) {
|
|
223
|
-
if (typeof sandbox[key] !== "boolean")
|
|
224
|
-
throw snapshotError(`provider.sandboxPolicy.${key}`, "must be a boolean");
|
|
225
|
-
}
|
|
226
|
-
Object.freeze(roots);
|
|
227
|
-
return Object.freeze({
|
|
228
|
-
type: "workspaceWrite",
|
|
229
|
-
writableRoots: roots,
|
|
230
|
-
networkAccess: sandbox.networkAccess,
|
|
231
|
-
excludeTmpdirEnvVar: sandbox.excludeTmpdirEnvVar,
|
|
232
|
-
excludeSlashTmp: sandbox.excludeSlashTmp,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
94
|
function parseProvider(value) {
|
|
236
95
|
const provider = objectAt(value, "provider");
|
|
237
96
|
const kind = requiredString(provider, "kind", "provider");
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
case "codex-sdk": {
|
|
241
|
-
exactKeys(provider, ["name", "source", "kind", "executable", "profile", "config", "threadOptions"], "provider");
|
|
242
|
-
if (!("threadOptions" in provider))
|
|
243
|
-
throw snapshotError("provider.threadOptions", "is required");
|
|
244
|
-
const executable = optionalString(provider, "executable", "provider");
|
|
245
|
-
const profile = optionalString(provider, "profile", "provider");
|
|
246
|
-
const config = optionalJsonObject(provider, "config");
|
|
247
|
-
return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(profile !== undefined ? { profile } : {}), ...(config !== undefined ? { config } : {}), threadOptions: cloneJsonObject(provider.threadOptions, "provider.threadOptions") });
|
|
248
|
-
}
|
|
249
|
-
case "codex-app-server": {
|
|
250
|
-
exactKeys(provider, ["name", "source", "kind", "executable", "profile", "config", "model", "effort", "sandboxPolicy", "approvalPolicy", "env"], "provider");
|
|
251
|
-
if ("approvalPolicy" in provider && provider.approvalPolicy !== "never")
|
|
252
|
-
throw snapshotError("provider.approvalPolicy", "must equal 'never'");
|
|
253
|
-
const executable = optionalString(provider, "executable", "provider");
|
|
254
|
-
const profile = optionalString(provider, "profile", "provider");
|
|
255
|
-
const config = optionalJsonObject(provider, "config");
|
|
256
|
-
const model = optionalString(provider, "model", "provider");
|
|
257
|
-
const effort = optionalString(provider, "effort", "provider");
|
|
258
|
-
const sandboxPolicy = "sandboxPolicy" in provider ? parseSandboxPolicy(provider.sandboxPolicy) : undefined;
|
|
259
|
-
const env = optionalStringRecord(provider, "env");
|
|
260
|
-
return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(profile !== undefined ? { profile } : {}), ...(config !== undefined ? { config } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(sandboxPolicy !== undefined ? { sandboxPolicy } : {}), ...(provider.approvalPolicy === "never" ? { approvalPolicy: "never" } : {}), ...(env !== undefined ? { env } : {}) });
|
|
261
|
-
}
|
|
262
|
-
case "claude-agent-sdk": {
|
|
263
|
-
exactKeys(provider, ["name", "source", "kind", "executable", "model", "effort", "settingSources", "permissionMode", "allowDangerouslySkipPermissions", "disallowedTools", "env"], "provider");
|
|
264
|
-
const modes = new Set(["default", "plan", "acceptEdits", "bypassPermissions"]);
|
|
265
|
-
const permissionMode = requiredEnum(provider, "permissionMode", "provider", modes);
|
|
266
|
-
if (permissionMode === "bypassPermissions") {
|
|
267
|
-
if (provider.allowDangerouslySkipPermissions !== true)
|
|
268
|
-
throw snapshotError("provider.allowDangerouslySkipPermissions", "must be true for bypassPermissions");
|
|
269
|
-
}
|
|
270
|
-
else if ("allowDangerouslySkipPermissions" in provider) {
|
|
271
|
-
throw snapshotError("provider.allowDangerouslySkipPermissions", "is only valid for bypassPermissions");
|
|
272
|
-
}
|
|
273
|
-
let settingSources;
|
|
274
|
-
if ("settingSources" in provider) {
|
|
275
|
-
if (!Array.isArray(provider.settingSources))
|
|
276
|
-
throw snapshotError("provider.settingSources", "must be an array");
|
|
277
|
-
settingSources = Object.freeze(provider.settingSources.map((source, index) => {
|
|
278
|
-
if (typeof source !== "string" || !CLAUDE_SETTING_SOURCES.has(source))
|
|
279
|
-
throw snapshotError(`provider.settingSources[${index}]`, "has an invalid setting source");
|
|
280
|
-
return source;
|
|
281
|
-
}));
|
|
282
|
-
}
|
|
283
|
-
let disallowedTools;
|
|
284
|
-
if ("disallowedTools" in provider) {
|
|
285
|
-
if (!Array.isArray(provider.disallowedTools) || provider.disallowedTools.length !== 1 || provider.disallowedTools[0] !== "WebSearch") {
|
|
286
|
-
throw snapshotError("provider.disallowedTools", "must equal ['WebSearch']");
|
|
287
|
-
}
|
|
288
|
-
disallowedTools = Object.freeze(["WebSearch"]);
|
|
289
|
-
}
|
|
290
|
-
const executable = optionalString(provider, "executable", "provider");
|
|
291
|
-
const model = optionalString(provider, "model", "provider");
|
|
292
|
-
const effort = optionalString(provider, "effort", "provider");
|
|
293
|
-
const env = optionalStringRecord(provider, "env");
|
|
294
|
-
return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(settingSources !== undefined ? { settingSources } : {}), permissionMode, ...(permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}), ...(disallowedTools !== undefined ? { disallowedTools } : {}), ...(env !== undefined ? { env } : {}) });
|
|
295
|
-
}
|
|
296
|
-
case "opencode-sdk": {
|
|
297
|
-
exactKeys(provider, ["name", "source", "kind", "executable", "model", "effort", "env"], "provider");
|
|
298
|
-
const executable = optionalString(provider, "executable", "provider");
|
|
299
|
-
const model = optionalString(provider, "model", "provider");
|
|
300
|
-
const effort = optionalString(provider, "effort", "provider");
|
|
301
|
-
const env = optionalStringRecord(provider, "env");
|
|
302
|
-
return Object.freeze({ ...common, kind, ...(executable !== undefined ? { executable } : {}), ...(model !== undefined ? { model } : {}), ...(effort !== undefined ? { effort } : {}), ...(env !== undefined ? { env } : {}) });
|
|
303
|
-
}
|
|
304
|
-
case "pi": {
|
|
305
|
-
exactKeys(provider, ["name", "source", "kind", "model", "thinkingLevel", "env"], "provider");
|
|
306
|
-
const model = optionalString(provider, "model", "provider");
|
|
307
|
-
const thinkingLevel = optionalString(provider, "thinkingLevel", "provider");
|
|
308
|
-
const env = optionalStringRecord(provider, "env");
|
|
309
|
-
return Object.freeze({ ...common, kind, ...(model !== undefined ? { model } : {}), ...(thinkingLevel !== undefined ? { thinkingLevel } : {}), ...(env !== undefined ? { env } : {}) });
|
|
310
|
-
}
|
|
311
|
-
default:
|
|
312
|
-
throw snapshotError("provider.kind", `has invalid value '${kind}'`);
|
|
97
|
+
if (!isSubagentProvider(kind)) {
|
|
98
|
+
throw snapshotError("provider.kind", `has invalid value '${kind}'`);
|
|
313
99
|
}
|
|
100
|
+
const common = parseProviderCommon(provider);
|
|
101
|
+
return getProviderRegistration(kind).parseLaunchProvider(provider, common);
|
|
314
102
|
}
|
|
315
103
|
export function parseResolvedAkumaLaunchSnapshot(value) {
|
|
316
104
|
const snapshot = objectAt(value, "resolved Akuma launch snapshot");
|
|
@@ -321,7 +109,11 @@ export function parseResolvedAkumaLaunchSnapshot(value) {
|
|
|
321
109
|
throw snapshotError("akuma", "is required");
|
|
322
110
|
if (!("provider" in snapshot))
|
|
323
111
|
throw snapshotError("provider", "is required");
|
|
324
|
-
const parsed = Object.freeze({
|
|
112
|
+
const parsed = Object.freeze({
|
|
113
|
+
version: 1,
|
|
114
|
+
akuma: parseAkuma(snapshot.akuma),
|
|
115
|
+
provider: parseProvider(snapshot.provider),
|
|
116
|
+
});
|
|
325
117
|
assertSnapshotEffortRequiresModel(parsed);
|
|
326
118
|
return parsed;
|
|
327
119
|
}
|
|
@@ -329,20 +121,7 @@ export function applySnapshotEffort(snapshot, effort) {
|
|
|
329
121
|
assertEffortAllowed(effort, snapshot.akuma.effortOptions);
|
|
330
122
|
assertEffortRequiresModel(snapshot.akuma.model, effort, "override");
|
|
331
123
|
const akuma = { ...snapshot.akuma, effort };
|
|
332
|
-
|
|
333
|
-
switch (snapshot.provider.kind) {
|
|
334
|
-
case "codex-sdk":
|
|
335
|
-
provider = { ...snapshot.provider, threadOptions: { ...snapshot.provider.threadOptions, modelReasoningEffort: effort } };
|
|
336
|
-
break;
|
|
337
|
-
case "codex-app-server":
|
|
338
|
-
case "claude-agent-sdk":
|
|
339
|
-
case "opencode-sdk":
|
|
340
|
-
provider = { ...snapshot.provider, effort };
|
|
341
|
-
break;
|
|
342
|
-
case "pi":
|
|
343
|
-
provider = { ...snapshot.provider, thinkingLevel: effort };
|
|
344
|
-
break;
|
|
345
|
-
}
|
|
124
|
+
const provider = getProviderRegistration(snapshot.provider.kind).applyEffort(snapshot.provider, effort);
|
|
346
125
|
return parseResolvedAkumaLaunchSnapshot({ version: 1, akuma, provider });
|
|
347
126
|
}
|
|
348
127
|
export { assertEffortAllowed, assertEffortRequiresModel };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
export function snapshotError(fieldPath, message) {
|
|
3
|
+
return new Error(`Invalid resolved Akuma launch snapshot at ${fieldPath}: ${message}`);
|
|
4
|
+
}
|
|
5
|
+
export function isPlainObject(value) {
|
|
6
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
7
|
+
return false;
|
|
8
|
+
const prototype = Object.getPrototypeOf(value);
|
|
9
|
+
return prototype === Object.prototype || prototype === null;
|
|
10
|
+
}
|
|
11
|
+
export function objectAt(value, fieldPath) {
|
|
12
|
+
if (!isPlainObject(value))
|
|
13
|
+
throw snapshotError(fieldPath, "must be a plain JSON object");
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
export function exactKeys(value, allowed, fieldPath) {
|
|
17
|
+
const allowedSet = new Set(allowed);
|
|
18
|
+
for (const key of Object.keys(value)) {
|
|
19
|
+
if (!allowedSet.has(key))
|
|
20
|
+
throw snapshotError(`${fieldPath}.${key}`, "is an unknown field");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function requiredString(value, key, fieldPath, allowBlank = false) {
|
|
24
|
+
const item = value[key];
|
|
25
|
+
if (typeof item !== "string" || (!allowBlank && item.trim().length === 0)) {
|
|
26
|
+
throw snapshotError(`${fieldPath}.${key}`, allowBlank ? "must be a string" : "must be a nonblank string");
|
|
27
|
+
}
|
|
28
|
+
return item;
|
|
29
|
+
}
|
|
30
|
+
export function optionalString(value, key, fieldPath) {
|
|
31
|
+
if (!(key in value))
|
|
32
|
+
return undefined;
|
|
33
|
+
return requiredString(value, key, fieldPath);
|
|
34
|
+
}
|
|
35
|
+
export function requiredEnum(value, key, fieldPath, values) {
|
|
36
|
+
const item = requiredString(value, key, fieldPath);
|
|
37
|
+
if (!values.has(item))
|
|
38
|
+
throw snapshotError(`${fieldPath}.${key}`, `has invalid value '${item}'`);
|
|
39
|
+
return item;
|
|
40
|
+
}
|
|
41
|
+
function cloneJson(value, fieldPath, ancestors = new Set()) {
|
|
42
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
43
|
+
return value;
|
|
44
|
+
if (typeof value === "number") {
|
|
45
|
+
if (!Number.isFinite(value))
|
|
46
|
+
throw snapshotError(fieldPath, "contains a non-finite number");
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
if (typeof value !== "object")
|
|
50
|
+
throw snapshotError(fieldPath, "contains a non-JSON value");
|
|
51
|
+
if (ancestors.has(value))
|
|
52
|
+
throw snapshotError(fieldPath, "contains a cycle");
|
|
53
|
+
ancestors.add(value);
|
|
54
|
+
try {
|
|
55
|
+
if (Array.isArray(value)) {
|
|
56
|
+
return Object.freeze(value.map((item, index) => cloneJson(item, `${fieldPath}[${index}]`, ancestors)));
|
|
57
|
+
}
|
|
58
|
+
if (!isPlainObject(value))
|
|
59
|
+
throw snapshotError(fieldPath, "contains a non-plain JSON object");
|
|
60
|
+
const result = {};
|
|
61
|
+
for (const [key, item] of Object.entries(value)) {
|
|
62
|
+
Object.defineProperty(result, key, {
|
|
63
|
+
value: cloneJson(item, `${fieldPath}.${key}`, ancestors),
|
|
64
|
+
enumerable: true,
|
|
65
|
+
configurable: true,
|
|
66
|
+
writable: true,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return Object.freeze(result);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
ancestors.delete(value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function cloneJsonObject(value, fieldPath) {
|
|
76
|
+
const cloned = cloneJson(value, fieldPath);
|
|
77
|
+
if (!isPlainObject(cloned)) {
|
|
78
|
+
throw snapshotError(fieldPath, "must be a plain JSON object");
|
|
79
|
+
}
|
|
80
|
+
return cloned;
|
|
81
|
+
}
|
|
82
|
+
export function optionalJsonObject(provider, key) {
|
|
83
|
+
return key in provider ? cloneJsonObject(provider[key], `provider.${key}`) : undefined;
|
|
84
|
+
}
|
|
85
|
+
export function optionalStringRecord(provider, key) {
|
|
86
|
+
if (!(key in provider))
|
|
87
|
+
return undefined;
|
|
88
|
+
const value = provider[key];
|
|
89
|
+
if (!isPlainObject(value))
|
|
90
|
+
throw snapshotError(`provider.${key}`, "must be a plain JSON object");
|
|
91
|
+
const result = {};
|
|
92
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
93
|
+
if (typeof entryValue !== "string") {
|
|
94
|
+
throw snapshotError(`provider.${key}.${entryKey}`, "must be a string");
|
|
95
|
+
}
|
|
96
|
+
result[entryKey] = entryValue;
|
|
97
|
+
}
|
|
98
|
+
return Object.freeze(result);
|
|
99
|
+
}
|
|
100
|
+
export function parseAbsoluteRootList(value, fieldPath) {
|
|
101
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
102
|
+
throw snapshotError(fieldPath, "must be a nonempty array");
|
|
103
|
+
}
|
|
104
|
+
const roots = value.map((root, index) => {
|
|
105
|
+
if (typeof root !== "string" || !path.isAbsolute(root) || path.resolve(root) !== root) {
|
|
106
|
+
throw snapshotError(`${fieldPath}[${index}]`, "must be a lexically normalized absolute path");
|
|
107
|
+
}
|
|
108
|
+
return root;
|
|
109
|
+
});
|
|
110
|
+
if (new Set(roots).size !== roots.length) {
|
|
111
|
+
throw snapshotError(fieldPath, "must not contain duplicates");
|
|
112
|
+
}
|
|
113
|
+
return Object.freeze(roots);
|
|
114
|
+
}
|