@astrosheep/keiyaku 2.8.4 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -15
- package/build/.tsbuildinfo +1 -1
- package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
- package/build/agents/harness/control-types.js +1 -0
- package/build/agents/harness/execution-handle.js +23 -3
- package/build/agents/harness/index.js +6 -607
- package/build/agents/harness/outcome.js +141 -0
- package/build/agents/harness/projection.js +310 -0
- package/build/agents/harness/router.js +201 -0
- package/build/agents/harness/runtime.js +2 -1
- package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
- package/build/agents/launch-snapshot/resolve.js +72 -0
- package/build/agents/opencode-sdk.js +24 -3
- package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
- package/build/agents/providers/claude-agent-sdk/events.js +218 -0
- package/build/agents/providers/claude-agent-sdk/session.js +158 -0
- package/build/agents/providers/codex-app-server/adapter.js +347 -0
- package/build/agents/providers/codex-app-server/events.js +352 -0
- package/build/agents/providers/codex-app-server/session.js +266 -0
- package/build/agents/providers/codex-sdk.js +23 -5
- package/build/agents/providers/opencode-sdk/adapter.js +344 -0
- package/build/agents/providers/opencode-sdk/events.js +354 -0
- package/build/agents/providers/opencode-sdk/session.js +180 -0
- package/build/agents/providers/pi/adapter.js +269 -0
- package/build/agents/providers/pi/checkpoint.js +41 -0
- package/build/agents/providers/pi/events.js +282 -0
- package/build/agents/{selector_v2.js → selector.js} +8 -6
- package/build/cli/commands/akuma/akuma/handler.js +4 -0
- package/build/cli/commands/akuma/akuma/meta.js +16 -0
- package/build/cli/commands/akuma/catalog.js +8 -0
- package/build/cli/commands/akuma/list/handler.js +15 -0
- package/build/cli/commands/akuma/list/meta-ls.js +9 -0
- package/build/cli/commands/akuma/view/handler.js +34 -0
- package/build/cli/commands/akuma/view/meta.js +8 -0
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +10 -0
- package/build/cli/commands/contract/amend/meta.js +12 -0
- package/build/cli/commands/contract/arc/handler.js +9 -0
- package/build/cli/commands/contract/arc/meta.js +26 -0
- package/build/cli/commands/contract/bind/handler.js +23 -0
- package/build/cli/commands/contract/bind/meta.js +30 -0
- package/build/cli/commands/contract/catalog.js +16 -0
- package/build/cli/commands/contract/forfeit/handler.js +13 -0
- package/build/cli/commands/contract/forfeit/meta.js +12 -0
- package/build/cli/commands/contract/log/handler.js +12 -0
- package/build/cli/commands/contract/log/meta.js +12 -0
- package/build/cli/commands/contract/petition/handler.js +26 -0
- package/build/cli/commands/contract/petition/meta.js +23 -0
- package/build/cli/commands/contract/renew/handler.js +10 -0
- package/build/cli/commands/contract/renew/meta.js +17 -0
- package/build/cli/commands/projection/call/handler.js +39 -0
- package/build/cli/commands/projection/call/meta.js +9 -0
- package/build/cli/commands/projection/catalog.js +14 -0
- package/build/cli/commands/projection/kill/handler.js +35 -0
- package/build/cli/commands/projection/kill/meta.js +11 -0
- package/build/cli/commands/projection/revive/handler.js +53 -0
- package/build/cli/commands/projection/revive/meta.js +9 -0
- package/build/cli/commands/projection/status/handler.js +23 -0
- package/build/cli/commands/projection/status/meta.js +9 -0
- package/build/cli/commands/projection/tell/handler.js +34 -0
- package/build/cli/commands/projection/tell/meta.js +9 -0
- package/build/cli/commands/projection/wait/handler.js +21 -0
- package/build/cli/commands/projection/wait/meta.js +11 -0
- package/build/cli/commands/registry.js +100 -0
- package/build/cli/commands/shared.js +71 -0
- package/build/cli/commands/skills/catalog.js +6 -0
- package/build/cli/commands/skills/install/handler.js +10 -0
- package/build/cli/commands/skills/install/meta.js +9 -0
- package/build/cli/commands/skills/skills/handler.js +4 -0
- package/build/cli/commands/skills/skills/meta.js +10 -0
- package/build/cli/commands/system/catalog.js +8 -0
- package/build/cli/commands/system/completion/handler.js +10 -0
- package/build/cli/commands/system/completion/meta.js +9 -0
- package/build/cli/commands/system/dump-env/handler.js +3 -0
- package/build/cli/commands/system/dump-env/meta.js +10 -0
- package/build/cli/commands/system/guide/handler.js +4 -0
- package/build/cli/commands/system/guide/meta.js +9 -0
- package/build/cli/commands/task/add/handler.js +21 -0
- package/build/cli/commands/task/add/meta.js +8 -0
- package/build/cli/commands/task/catalog.js +22 -0
- package/build/cli/commands/task/doctor/handler.js +4 -0
- package/build/cli/commands/task/doctor/meta.js +8 -0
- package/build/cli/commands/task/done/handler.js +17 -0
- package/build/cli/commands/task/done/meta.js +8 -0
- package/build/cli/commands/task/drop/handler.js +6 -0
- package/build/cli/commands/task/drop/meta.js +8 -0
- package/build/cli/commands/task/ls/handler.js +13 -0
- package/build/cli/commands/task/ls/meta.js +8 -0
- package/build/cli/commands/task/shared.js +131 -0
- package/build/cli/commands/task/start/handler.js +6 -0
- package/build/cli/commands/task/start/meta.js +8 -0
- package/build/cli/commands/task/stop/handler.js +17 -0
- package/build/cli/commands/task/stop/meta.js +8 -0
- package/build/cli/commands/task/task/handler.js +5 -0
- package/build/cli/commands/task/task/meta.js +11 -0
- package/build/cli/commands/task/update/handler.js +18 -0
- package/build/cli/commands/task/update/meta.js +8 -0
- package/build/cli/commands/task/view/handler.js +14 -0
- package/build/cli/commands/task/view/meta.js +8 -0
- package/build/cli/completion.js +26 -27
- package/build/cli/flags.js +79 -2
- package/build/cli/help.js +27 -49
- package/build/cli/index.js +121 -374
- package/build/cli/output-stream-error-policy.js +17 -0
- package/build/cli/parse.js +159 -72
- package/build/cli/projection-address.js +5 -0
- package/build/cli/render/arc.js +1 -1
- package/build/cli/render/errors.js +4 -3
- package/build/cli/render/format.js +14 -0
- package/build/cli/render/kanshi.js +106 -0
- package/build/cli/render/petition.js +24 -1
- package/build/cli/render/projection-activity.js +5 -1
- package/build/cli/render/shared.js +2 -2
- package/build/cli/render/status.js +79 -13
- package/build/cli/render/task.js +113 -0
- package/build/cli/render/wait.js +23 -3
- package/build/cli/types.js +1 -1
- package/build/config/{akuma-loader_v2.js → akuma-loader.js} +2 -2
- package/build/config/env.js +9 -4
- package/build/config/settings/disease.js +26 -0
- package/build/config/settings/knobs.js +8 -0
- package/build/config/settings/loader.js +244 -0
- package/build/config/settings/schema.js +276 -0
- package/build/core/addressing.js +1 -1
- package/build/core/amend.js +3 -3
- package/build/core/arc.js +5 -4
- package/build/core/bind-workspace.js +123 -0
- package/build/core/bind.js +75 -155
- package/build/core/call/call.js +224 -0
- package/build/core/call/context.js +238 -0
- package/build/core/call/execution.js +217 -0
- package/build/core/call/prompt.js +42 -0
- package/build/core/call/reference.js +24 -0
- package/build/core/call-persist.js +1 -1
- package/build/core/claim-delivery.js +247 -0
- package/build/core/claim.js +39 -277
- package/build/core/context.js +2 -1
- package/build/core/{render.js → contract-view.js} +12 -140
- package/build/core/draft.js +107 -9
- package/build/core/entry.js +9 -1
- package/build/core/execution-coordinate.js +4 -20
- package/build/core/execution-pact.js +16 -31
- package/build/core/forfeit.js +35 -22
- package/build/core/hints.js +2 -2
- package/build/core/log.js +2 -2
- package/build/core/petition-claim-gates.js +8 -6
- package/build/core/petition-preview.js +97 -0
- package/build/core/petition-run.js +3 -2
- package/build/core/petition.js +39 -26
- package/build/core/projection/generation/database.js +306 -0
- package/build/core/projection/generation/identity.js +84 -0
- package/build/core/projection/generation/model.js +201 -0
- package/build/core/projection/generation/store.js +73 -0
- package/build/core/projection/generation/transitions.js +258 -0
- package/build/core/projection/heart.js +0 -307
- package/build/core/projection/tell/database.js +109 -0
- package/build/core/projection/tell/model.js +97 -0
- package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
- package/build/core/projection-activity.js +23 -2
- package/build/core/projection-core.js +2 -1
- package/build/core/projection-execution-observer.js +259 -0
- package/build/core/projection-generation-continuation.js +1 -1
- package/build/core/projection-generation-execution.js +90 -20
- package/build/core/projection-generation-launcher.js +1 -1
- package/build/core/projection-generation-runner.js +198 -4
- package/build/core/projection-identity.js +1 -1
- package/build/core/projection-kill.js +50 -17
- package/build/core/projection-life-observer.js +1 -1
- package/build/core/projection-life-protocol.js +10 -0
- package/build/core/projection-mint.js +1 -1
- package/build/core/projection-status.js +45 -32
- package/build/core/projection-wait.js +12 -2
- package/build/core/projection-wake.js +5 -2
- package/build/core/{queue_v2.js → queue.js} +2 -1
- package/build/core/registry.js +1 -1
- package/build/core/renew.js +7 -7
- package/build/core/response-artifact-catalog-sqlite.js +112 -0
- package/build/core/response-artifact-catalog.js +7 -0
- package/build/core/seal.js +44 -16
- package/build/core/status/board.js +286 -0
- package/build/core/status/drift.js +99 -0
- package/build/core/status/lifecycle.js +84 -0
- package/build/core/status/reconciliation.js +131 -0
- package/build/core/stored-agent-event.js +28 -4
- package/build/core/target-ref.js +10 -0
- package/build/core/task/board.js +175 -0
- package/build/core/task/commands.js +211 -0
- package/build/core/task/document.js +189 -0
- package/build/core/task/model.js +1 -0
- package/build/core/task/settlement-git.js +207 -0
- package/build/core/task/settlement-policy.js +82 -0
- package/build/core/task/source-board.js +84 -0
- package/build/core/task/source-model.js +1 -0
- package/build/core/task/validation.js +44 -0
- package/build/core/task-contract.js +224 -0
- package/build/core/task-doctor.js +14 -0
- package/build/core/task-git-actor.js +38 -0
- package/build/core/task-git-runtime.js +34 -0
- package/build/core/task-git-store.js +375 -0
- package/build/core/task-repository.js +1 -0
- package/build/core/task-store-repository.js +86 -0
- package/build/core/task-store.js +1 -0
- package/build/core/task-worktree.js +51 -0
- package/build/core/task.js +4 -0
- package/build/core/transcripts.js +138 -56
- package/build/core/validation.js +17 -0
- package/build/core/verdict.js +2 -2
- package/build/core/worktree-path.js +24 -6
- package/build/flow-error.js +3 -2
- package/build/generated/version.js +1 -1
- package/build/git/commits.js +3 -0
- package/build/git/diff/parsers.js +0 -94
- package/build/index.js +2 -0
- package/build/keiyaku-constants.js +2 -0
- package/build/keiyaku.js +4 -3
- package/package.json +3 -2
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +11 -6
- package/build/agents/harness/pump.js +0 -158
- package/build/agents/providers/codex-app-server.js +0 -864
- package/build/agents/providers/opencode-sdk.js +0 -363
- package/build/agents/providers/pi.js +0 -557
- package/build/config/settings.js +0 -533
- package/build/core/call.js +0 -686
- package/build/core/projection/generation.js +0 -412
- package/build/core/projection/identity.js +0 -81
- package/build/core/projection/mint.js +0 -174
- package/build/core/projection-generation-store.js +0 -707
- package/build/core/status.js +0 -539
|
@@ -1,380 +1,33 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { appendDebugLog } from "
|
|
3
|
-
import { SUBAGENT_SESSION_VERSION } from "
|
|
4
|
-
import { createProjectionDriver } from "
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const CLAUDE_ACKNOWLEDGED_UNPERSISTED = new Set([
|
|
10
|
-
"stream_event",
|
|
11
|
-
"rate_limit_event",
|
|
12
|
-
"control_cancel_request",
|
|
13
|
-
"control_request",
|
|
14
|
-
"control_response",
|
|
15
|
-
"conversation_reset",
|
|
16
|
-
"keep_alive",
|
|
17
|
-
"local",
|
|
18
|
-
"prompt_suggestion",
|
|
19
|
-
"tool_progress",
|
|
20
|
-
"tool_use_summary",
|
|
21
|
-
"auth_status",
|
|
22
|
-
]);
|
|
23
|
-
function claudeIngressDisposition(type) {
|
|
24
|
-
if (CLAUDE_MAPPED.has(type))
|
|
25
|
-
return "mapped";
|
|
26
|
-
if (CLAUDE_ACKNOWLEDGED_UNPERSISTED.has(type))
|
|
27
|
-
return "acknowledged-unpersisted";
|
|
28
|
-
return "unknown";
|
|
29
|
-
}
|
|
2
|
+
import { appendDebugLog } from "../../../telemetry/debug-log.js";
|
|
3
|
+
import { SUBAGENT_SESSION_VERSION } from "../../session.js";
|
|
4
|
+
import { createProjectionDriver } from "../../harness/execution-handle.js";
|
|
5
|
+
import { buildSubagentEnv, createAbortError, emitProviderEvidence, linkAbortSignal, sha256Utf8 } from "../../harness/runtime.js";
|
|
6
|
+
import { SubagentFailure } from "../../types.js";
|
|
7
|
+
import { claudeIngressDisposition, emitClaudeThoughts, emitClaudeToolResults, emitClaudeToolStarts, emitClaudeUsage, extractAssistantMessage, extractAssistantMessageId, extractAssistantMessageModel, extractOverloadFallbackWarning, extractResultText, extractResumeToken, isClaudeApiRetryEvent, isClaudeModelRefusalFallbackEvent, isClaudeModelRefusalNoFallbackEvent, mapClaudeApiRetryWarning, } from "./events.js";
|
|
8
|
+
import { CLAUDE_AGENT_SDK_PROVIDER, createPushableUserMessageStream, toClaudeUserMessage, } from "./session.js";
|
|
30
9
|
function toClaudeSdkEffort(effort) {
|
|
31
10
|
return effort; // opacity boundary
|
|
32
11
|
}
|
|
33
12
|
export const claudeSessionSchema = z.object({ sessionId: z.string().trim().min(1) });
|
|
34
|
-
const CLAUDE_AGENT_SDK_PROVIDER = "claude-agent-sdk";
|
|
35
13
|
let claudeAgentSdkLoader;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const DONE_SENTINEL = undefined;
|
|
40
|
-
function extractMessageText(content) {
|
|
41
|
-
if (!Array.isArray(content))
|
|
42
|
-
return undefined;
|
|
43
|
-
const text = content
|
|
44
|
-
.map((block) => {
|
|
45
|
-
if (typeof block !== "object" || block === null || !("text" in block))
|
|
46
|
-
return "";
|
|
47
|
-
const candidate = block.text;
|
|
48
|
-
return typeof candidate === "string" ? candidate : "";
|
|
49
|
-
})
|
|
50
|
-
.join("")
|
|
51
|
-
.trim();
|
|
52
|
-
return text || undefined;
|
|
53
|
-
}
|
|
54
|
-
function extractAssistantMessage(event) {
|
|
55
|
-
return extractMessageText(event.message.content);
|
|
56
|
-
}
|
|
57
|
-
function extractAssistantMessageModel(event) {
|
|
58
|
-
return coerceString(event.message.model);
|
|
59
|
-
}
|
|
60
|
-
function claudeActivityCall(name, input) {
|
|
61
|
-
if (!isRecord(input))
|
|
62
|
-
return { kind: "other", display: name };
|
|
63
|
-
return activityCallFromNamedTool(name, {
|
|
64
|
-
...(typeof input.command === "string" ? { command: input.command } : {}),
|
|
65
|
-
...(typeof input.description === "string" ? { description: input.description } : {}),
|
|
66
|
-
...(typeof input.file_path === "string" ? { path: input.file_path } : {}),
|
|
67
|
-
...(typeof input.offset === "number" && Number.isFinite(input.offset) ? { offset: input.offset } : {}),
|
|
68
|
-
...(typeof input.limit === "number" && Number.isFinite(input.limit) ? { limit: input.limit } : {}),
|
|
69
|
-
...(typeof input.query === "string" ? { query: input.query } : {}),
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
function claudeResultMessage(content) {
|
|
73
|
-
if (typeof content === "string")
|
|
74
|
-
return content ? boundActivityExcerpt(content) : undefined;
|
|
75
|
-
if (!Array.isArray(content))
|
|
76
|
-
return undefined;
|
|
77
|
-
const text = content.flatMap((entry) => {
|
|
78
|
-
if (!isRecord(entry) || entry.type !== "text" || typeof entry.text !== "string")
|
|
79
|
-
return [];
|
|
80
|
-
return [entry.text];
|
|
81
|
-
}).join("\n");
|
|
82
|
-
return text ? boundActivityExcerpt(text) : undefined;
|
|
83
|
-
}
|
|
84
|
-
function emitClaudeToolStarts(builder, event, seenToolUses) {
|
|
85
|
-
if (!Array.isArray(event.message.content))
|
|
86
|
-
return;
|
|
87
|
-
for (const block of event.message.content) {
|
|
88
|
-
if (!isRecord(block) || block.type !== "tool_use")
|
|
89
|
-
continue;
|
|
90
|
-
const id = coerceString(block.id);
|
|
91
|
-
const name = coerceString(block.name);
|
|
92
|
-
if (!id || !name)
|
|
93
|
-
continue;
|
|
94
|
-
const call = claudeActivityCall(name, block.input);
|
|
95
|
-
seenToolUses.set(id, { tool: name, call });
|
|
96
|
-
builder.emit({
|
|
97
|
-
type: "activity",
|
|
98
|
-
phase: "started",
|
|
99
|
-
id,
|
|
100
|
-
tool: name,
|
|
101
|
-
call,
|
|
102
|
-
});
|
|
103
|
-
if (name === "TodoWrite" && isRecord(block.input) && Array.isArray(block.input.todos)) {
|
|
104
|
-
const items = block.input.todos.slice(0, AGENT_PLAN_MAX_ITEMS).flatMap((todo) => {
|
|
105
|
-
if (!isRecord(todo) || typeof todo.content !== "string" || typeof todo.status !== "string") {
|
|
106
|
-
return [];
|
|
107
|
-
}
|
|
108
|
-
return [{
|
|
109
|
-
text: todo.content.slice(0, AGENT_PLAN_ITEM_TEXT_MAX_CHARS),
|
|
110
|
-
done: todo.status === "completed",
|
|
111
|
-
...(todo.status === "in_progress" ? { active: true } : {}),
|
|
112
|
-
}];
|
|
113
|
-
});
|
|
114
|
-
builder.emit({ type: "plan", id, items });
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
function emitClaudeThoughts(builder, event) {
|
|
119
|
-
if (!Array.isArray(event.message.content))
|
|
120
|
-
return;
|
|
121
|
-
event.message.content.forEach((block, blockIndex) => {
|
|
122
|
-
if (!isRecord(block) || block.type !== "thinking" || typeof block.thinking !== "string")
|
|
123
|
-
return;
|
|
124
|
-
const truncated = block.thinking.length > AGENT_THOUGHT_TEXT_MAX_CHARS;
|
|
125
|
-
builder.emit({
|
|
126
|
-
type: "thought",
|
|
127
|
-
id: `${event.uuid}:${blockIndex}`,
|
|
128
|
-
text: block.thinking.slice(0, AGENT_THOUGHT_TEXT_MAX_CHARS),
|
|
129
|
-
final: true,
|
|
130
|
-
...(truncated ? { truncated: true } : {}),
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
function emitClaudeToolResults(builder, event, seenToolUses) {
|
|
135
|
-
const content = event.message.content;
|
|
136
|
-
if (!Array.isArray(content))
|
|
137
|
-
return;
|
|
138
|
-
for (const block of content) {
|
|
139
|
-
if (!isRecord(block) || block.type !== "tool_result")
|
|
140
|
-
continue;
|
|
141
|
-
const id = coerceString(block.tool_use_id);
|
|
142
|
-
if (!id)
|
|
143
|
-
continue;
|
|
144
|
-
const observed = seenToolUses.get(id);
|
|
145
|
-
if (!observed)
|
|
146
|
-
continue;
|
|
147
|
-
seenToolUses.delete(id);
|
|
148
|
-
const message = claudeResultMessage(block.content);
|
|
149
|
-
builder.emit({
|
|
150
|
-
type: "activity",
|
|
151
|
-
phase: "completed",
|
|
152
|
-
id,
|
|
153
|
-
tool: observed.tool,
|
|
154
|
-
call: observed.call,
|
|
155
|
-
result: {
|
|
156
|
-
status: block.is_error === true ? "error" : "ok",
|
|
157
|
-
...(message ? { message } : {}),
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
function emitClaudeUsage(builder, event, model) {
|
|
163
|
-
const usage = event.usage;
|
|
164
|
-
builder.emit({
|
|
165
|
-
type: "usage",
|
|
166
|
-
inputTokens: usage.input_tokens,
|
|
167
|
-
outputTokens: usage.output_tokens,
|
|
168
|
-
cachedInputTokens: usage.cache_read_input_tokens,
|
|
169
|
-
...(typeof event.total_cost_usd === "number" ? { costUsd: event.total_cost_usd } : {}),
|
|
170
|
-
...(model ? { model } : {}),
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
function isRecord(value) {
|
|
174
|
-
return typeof value === "object" && value !== null;
|
|
175
|
-
}
|
|
176
|
-
function isClaudeModelRefusalFallbackEvent(event) {
|
|
177
|
-
return event.type === "system" && event.subtype === "model_refusal_fallback";
|
|
178
|
-
}
|
|
179
|
-
function isClaudeModelRefusalNoFallbackEvent(event) {
|
|
180
|
-
return event.type === "system" && event.subtype === "model_refusal_no_fallback";
|
|
181
|
-
}
|
|
182
|
-
function extractFallbackRequestId(value) {
|
|
183
|
-
if (value === null)
|
|
184
|
-
return null;
|
|
185
|
-
return coerceString(value);
|
|
186
|
-
}
|
|
187
|
-
function extractOverloadFallbackWarning(event) {
|
|
188
|
-
if (!isRecord(event) || event.type !== "fallback") {
|
|
189
|
-
return undefined;
|
|
190
|
-
}
|
|
191
|
-
const originalModel = coerceString(event.original_model);
|
|
192
|
-
const fallbackModel = coerceString(event.fallback_model);
|
|
193
|
-
const direction = coerceString(event.direction);
|
|
194
|
-
const requestId = extractFallbackRequestId(event.request_id);
|
|
195
|
-
return {
|
|
196
|
-
reason: "overload",
|
|
197
|
-
...(originalModel ? { originalModel } : {}),
|
|
198
|
-
...(fallbackModel ? { fallbackModel } : {}),
|
|
199
|
-
...(direction ? { direction } : {}),
|
|
200
|
-
...(requestId !== undefined ? { requestId } : {}),
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
function extractResumeToken(event) {
|
|
204
|
-
return coerceString(event.session_id);
|
|
205
|
-
}
|
|
206
|
-
function extractResultText(event) {
|
|
207
|
-
if (event.subtype === "success") {
|
|
208
|
-
return coerceString(event.result);
|
|
14
|
+
async function loadClaudeAgentSdk(loader) {
|
|
15
|
+
if (loader) {
|
|
16
|
+
return loader();
|
|
209
17
|
}
|
|
210
|
-
const errorText = event.errors.join("\n").trim();
|
|
211
|
-
return errorText || undefined;
|
|
212
|
-
}
|
|
213
|
-
async function loadClaudeAgentSdk() {
|
|
214
18
|
if (claudeAgentSdkLoader) {
|
|
215
19
|
return claudeAgentSdkLoader();
|
|
216
20
|
}
|
|
217
21
|
return (await import("@anthropic-ai/claude-agent-sdk"));
|
|
218
22
|
}
|
|
23
|
+
/** @deprecated Use ClaudeProviderOptions.loader instead. Kept for pipeline-based tests pending loader channel. */
|
|
219
24
|
export function setClaudeAgentSdkLoaderForTests(loader) {
|
|
220
25
|
claudeAgentSdkLoader = loader;
|
|
221
26
|
}
|
|
27
|
+
/** @deprecated Use ClaudeProviderOptions.loader instead. */
|
|
222
28
|
export function resetClaudeAgentSdkLoaderForTests() {
|
|
223
29
|
claudeAgentSdkLoader = undefined;
|
|
224
30
|
}
|
|
225
|
-
function createMessageAck() {
|
|
226
|
-
let resolve;
|
|
227
|
-
let reject;
|
|
228
|
-
const promise = new Promise((res, rej) => {
|
|
229
|
-
resolve = res;
|
|
230
|
-
reject = rej;
|
|
231
|
-
});
|
|
232
|
-
// Prevent unhandled rejection if nobody awaits before reject-on-end.
|
|
233
|
-
promise.catch(() => undefined);
|
|
234
|
-
const ack = {
|
|
235
|
-
settled: false,
|
|
236
|
-
settleResolve() {
|
|
237
|
-
if (ack.settled)
|
|
238
|
-
return;
|
|
239
|
-
ack.settled = true;
|
|
240
|
-
resolve();
|
|
241
|
-
},
|
|
242
|
-
settleReject(error) {
|
|
243
|
-
if (ack.settled)
|
|
244
|
-
return;
|
|
245
|
-
ack.settled = true;
|
|
246
|
-
reject(error);
|
|
247
|
-
},
|
|
248
|
-
wait() {
|
|
249
|
-
return promise;
|
|
250
|
-
},
|
|
251
|
-
};
|
|
252
|
-
return ack;
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Long-lived push source for Claude Query.
|
|
256
|
-
* Submitted fence is per-yield: entering next() first acknowledges the previously
|
|
257
|
-
* yielded message, then yields the next item. That next-entry after a yield is the
|
|
258
|
-
* post-yield ack (transport.write completed for the prior yield).
|
|
259
|
-
*/
|
|
260
|
-
export function createPushableUserMessageStream(onYield) {
|
|
261
|
-
const queue = [];
|
|
262
|
-
const waiters = [];
|
|
263
|
-
/** Ack for the message most recently yielded; resolved on the subsequent next() entry. */
|
|
264
|
-
let pendingYieldAck;
|
|
265
|
-
let closed = false;
|
|
266
|
-
let failure;
|
|
267
|
-
let pullCount = 0;
|
|
268
|
-
const terminalError = (error) => error ?? new Error(`${CLAUDE_AGENT_SDK_PROVIDER} input stream ended before submitted ack`);
|
|
269
|
-
const rejectUnresolvedAcks = (error) => {
|
|
270
|
-
const err = terminalError(error);
|
|
271
|
-
if (pendingYieldAck) {
|
|
272
|
-
pendingYieldAck.settleReject(err);
|
|
273
|
-
pendingYieldAck = undefined;
|
|
274
|
-
}
|
|
275
|
-
while (queue.length > 0) {
|
|
276
|
-
queue.shift().ack.settleReject(err);
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
/** First action on every next() entry: post-yield ack for the prior yield. */
|
|
280
|
-
const acknowledgePreviousYield = () => {
|
|
281
|
-
if (!pendingYieldAck)
|
|
282
|
-
return;
|
|
283
|
-
pendingYieldAck.settleResolve();
|
|
284
|
-
pendingYieldAck = undefined;
|
|
285
|
-
};
|
|
286
|
-
const yieldQueued = (entry) => {
|
|
287
|
-
pullCount += 1;
|
|
288
|
-
pendingYieldAck = entry.ack;
|
|
289
|
-
onYield?.(entry.message);
|
|
290
|
-
return { value: entry.message, done: false };
|
|
291
|
-
};
|
|
292
|
-
return {
|
|
293
|
-
get pullCount() {
|
|
294
|
-
return pullCount;
|
|
295
|
-
},
|
|
296
|
-
get queueLength() {
|
|
297
|
-
return queue.length;
|
|
298
|
-
},
|
|
299
|
-
push(message) {
|
|
300
|
-
const ack = createMessageAck();
|
|
301
|
-
if (closed || failure !== undefined) {
|
|
302
|
-
ack.settleReject(terminalError(failure));
|
|
303
|
-
return { waitSubmitted: () => ack.wait() };
|
|
304
|
-
}
|
|
305
|
-
const waiter = waiters.shift();
|
|
306
|
-
if (waiter) {
|
|
307
|
-
// Consumer is already inside next() (previous yield already acked at entry).
|
|
308
|
-
pullCount += 1;
|
|
309
|
-
pendingYieldAck = ack;
|
|
310
|
-
onYield?.(message);
|
|
311
|
-
waiter.resolve({ value: message, done: false });
|
|
312
|
-
return { waitSubmitted: () => ack.wait() };
|
|
313
|
-
}
|
|
314
|
-
queue.push({ message, ack });
|
|
315
|
-
return { waitSubmitted: () => ack.wait() };
|
|
316
|
-
},
|
|
317
|
-
end(error) {
|
|
318
|
-
if (closed)
|
|
319
|
-
return;
|
|
320
|
-
closed = true;
|
|
321
|
-
if (error !== undefined) {
|
|
322
|
-
failure = error;
|
|
323
|
-
// Failure: reject every unresolved ack (yielded + still queued) so enqueue cannot hang.
|
|
324
|
-
rejectUnresolvedAcks(error);
|
|
325
|
-
while (waiters.length > 0) {
|
|
326
|
-
waiters.shift().reject(failure);
|
|
327
|
-
}
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
// Clean end: leave queued messages readable for a late consumer drain.
|
|
331
|
-
// Only reject a yielded-but-not-post-acked message (no further next() will ack it
|
|
332
|
-
// if the consumer has already stopped). If a consumer is parked, they get done
|
|
333
|
-
// after any remaining queue is taken on subsequent next() calls — parked waiters
|
|
334
|
-
// here mean queue is empty, so resolve done.
|
|
335
|
-
if (pendingYieldAck) {
|
|
336
|
-
pendingYieldAck.settleReject(terminalError());
|
|
337
|
-
pendingYieldAck = undefined;
|
|
338
|
-
}
|
|
339
|
-
while (waiters.length > 0) {
|
|
340
|
-
waiters.shift().resolve({ value: DONE_SENTINEL, done: true });
|
|
341
|
-
}
|
|
342
|
-
},
|
|
343
|
-
iterable: {
|
|
344
|
-
[Symbol.asyncIterator]() {
|
|
345
|
-
return {
|
|
346
|
-
next() {
|
|
347
|
-
// Per-yield submitted fence: next entry acks the previously yielded message.
|
|
348
|
-
acknowledgePreviousYield();
|
|
349
|
-
if (queue.length > 0) {
|
|
350
|
-
return Promise.resolve(yieldQueued(queue.shift()));
|
|
351
|
-
}
|
|
352
|
-
if (failure !== undefined) {
|
|
353
|
-
return Promise.reject(failure);
|
|
354
|
-
}
|
|
355
|
-
if (closed) {
|
|
356
|
-
return Promise.resolve({ value: DONE_SENTINEL, done: true });
|
|
357
|
-
}
|
|
358
|
-
return new Promise((resolve, reject) => {
|
|
359
|
-
waiters.push({ resolve, reject });
|
|
360
|
-
});
|
|
361
|
-
},
|
|
362
|
-
};
|
|
363
|
-
},
|
|
364
|
-
},
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
function toUserMessage(text) {
|
|
368
|
-
return {
|
|
369
|
-
type: "user",
|
|
370
|
-
message: {
|
|
371
|
-
role: "user",
|
|
372
|
-
content: text,
|
|
373
|
-
},
|
|
374
|
-
parent_tool_use_id: null,
|
|
375
|
-
session_id: "",
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
31
|
export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
379
32
|
const sessionId = options.sessionId?.trim();
|
|
380
33
|
let liveQuery;
|
|
@@ -450,7 +103,7 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
450
103
|
// The pump calls enqueue at a successful result checkpoint. Push now;
|
|
451
104
|
// waiting for another result before pushing would deadlock the next turn.
|
|
452
105
|
// text is already core-rendered; send byte-for-byte. id is for the frame only (inside text).
|
|
453
|
-
const submitted = inputStream.push(
|
|
106
|
+
const submitted = inputStream.push(toClaudeUserMessage(message.text));
|
|
454
107
|
// submitted = NEXT source next() after this tell is yielded (not the yield pull itself).
|
|
455
108
|
await submitted.waitSubmitted();
|
|
456
109
|
emitTurnStarted?.();
|
|
@@ -470,10 +123,16 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
470
123
|
initialTurn: options.initialTurn,
|
|
471
124
|
enqueue,
|
|
472
125
|
onIngress: options.onIngress,
|
|
473
|
-
async abort() {
|
|
126
|
+
async abort(mode) {
|
|
474
127
|
queryEnded = true;
|
|
475
128
|
queryActive = false;
|
|
476
129
|
const abortError = createAbortError(`${CLAUDE_AGENT_SDK_PROVIDER} exec cancelled by client`);
|
|
130
|
+
if (mode === "force") {
|
|
131
|
+
inputStream?.end(abortError);
|
|
132
|
+
rejectPendingEnqueueWaiters(abortError);
|
|
133
|
+
liveQuery?.close();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
477
136
|
try {
|
|
478
137
|
await liveQuery?.interrupt();
|
|
479
138
|
}
|
|
@@ -491,12 +150,12 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
491
150
|
pendingEvidenceDiagnostics -= 1;
|
|
492
151
|
builderDiagnostic("provider evidence callback failed");
|
|
493
152
|
}
|
|
494
|
-
const sdk = await loadClaudeAgentSdk();
|
|
153
|
+
const sdk = await loadClaudeAgentSdk(options.loader);
|
|
495
154
|
const queryAbortController = new AbortController();
|
|
496
155
|
const unlinkBuilderAbort = linkAbortSignal(builder.signal, queryAbortController, () => undefined);
|
|
497
156
|
const unlinkOuterAbort = linkAbortSignal(options.signal, queryAbortController, () => undefined);
|
|
498
157
|
try {
|
|
499
|
-
const initialMessage =
|
|
158
|
+
const initialMessage = toClaudeUserMessage(prompt);
|
|
500
159
|
inputStream = createPushableUserMessageStream((message) => {
|
|
501
160
|
if (!options.onEvidence)
|
|
502
161
|
return;
|
|
@@ -515,7 +174,7 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
515
174
|
cwd,
|
|
516
175
|
model: options.model,
|
|
517
176
|
resume: sessionId,
|
|
518
|
-
env: buildSubagentEnv(),
|
|
177
|
+
env: buildSubagentEnv(options.env),
|
|
519
178
|
abortController: queryAbortController,
|
|
520
179
|
persistSession: true,
|
|
521
180
|
...(options.systemPrompt ? { systemPrompt: options.systemPrompt } : {}),
|
|
@@ -554,10 +213,23 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
554
213
|
let resumedSessionId = sessionId;
|
|
555
214
|
let finalMessage;
|
|
556
215
|
let latestAssistantMessageModel;
|
|
216
|
+
// Provider acceptance / pre-terminal retry evidence for no-turn classification.
|
|
217
|
+
// turn.started is a harness-local pre-query event and is not acceptance.
|
|
218
|
+
let acceptedTurn = false;
|
|
219
|
+
let lastPreTerminalEvidenceWasRetry = false;
|
|
557
220
|
const seenToolUses = new Map();
|
|
558
221
|
for await (const event of query) {
|
|
559
222
|
builder.ingress(CLAUDE_AGENT_SDK_PROVIDER, event.type, event, claudeIngressDisposition(event.type), () => {
|
|
560
223
|
resumedSessionId = extractResumeToken(event) ?? resumedSessionId;
|
|
224
|
+
if (isClaudeApiRetryEvent(event)) {
|
|
225
|
+
lastPreTerminalEvidenceWasRetry = true;
|
|
226
|
+
builder.emit({ type: "warning", warning: mapClaudeApiRetryWarning(event) });
|
|
227
|
+
}
|
|
228
|
+
else if (!(event.type === "result" && event.subtype !== "success")) {
|
|
229
|
+
// Any other non-terminal-failure native event clears the last-retry predicate.
|
|
230
|
+
// Failed result itself is terminal and must not overwrite prior evidence.
|
|
231
|
+
lastPreTerminalEvidenceWasRetry = false;
|
|
232
|
+
}
|
|
561
233
|
const overloadWarning = extractOverloadFallbackWarning(event);
|
|
562
234
|
if (overloadWarning) {
|
|
563
235
|
builder.emit({ type: "warning", warning: overloadWarning });
|
|
@@ -588,22 +260,25 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
588
260
|
}
|
|
589
261
|
switch (event.type) {
|
|
590
262
|
case "assistant": {
|
|
263
|
+
acceptedTurn = true;
|
|
591
264
|
latestAssistantMessageModel = extractAssistantMessageModel(event) ?? latestAssistantMessageModel;
|
|
592
265
|
emitClaudeThoughts(builder, event);
|
|
593
266
|
emitClaudeToolStarts(builder, event, seenToolUses);
|
|
594
267
|
finalMessage = extractAssistantMessage(event) ?? finalMessage;
|
|
595
268
|
if (finalMessage) {
|
|
596
|
-
builder.emit({ type: "message", text: finalMessage });
|
|
269
|
+
builder.emit({ type: "message", id: extractAssistantMessageId(event), text: finalMessage });
|
|
597
270
|
}
|
|
598
271
|
break;
|
|
599
272
|
}
|
|
600
273
|
case "user": {
|
|
274
|
+
acceptedTurn = true;
|
|
601
275
|
emitClaudeToolResults(builder, event, seenToolUses);
|
|
602
276
|
break;
|
|
603
277
|
}
|
|
604
278
|
case "result": {
|
|
605
279
|
const resultText = extractResultText(event);
|
|
606
280
|
if (event.subtype === "success") {
|
|
281
|
+
acceptedTurn = true;
|
|
607
282
|
finalMessage = resultText ?? finalMessage;
|
|
608
283
|
emitClaudeUsage(builder, event, latestAssistantMessageModel);
|
|
609
284
|
builder.emit({ type: "turn", phase: "completed" });
|
|
@@ -612,6 +287,7 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
612
287
|
bumpResultOrdinal();
|
|
613
288
|
const checkpoint = {
|
|
614
289
|
fence: { kind: "ordinal", ordinal: completedResultOrdinal },
|
|
290
|
+
consumptionEvidence: true,
|
|
615
291
|
};
|
|
616
292
|
// Record the native result before the synchronous pump can
|
|
617
293
|
// consume any tell fenced to an earlier result.
|
|
@@ -619,7 +295,7 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
619
295
|
emitProviderEvidence(options.onEvidence, {
|
|
620
296
|
type: "checkpoint",
|
|
621
297
|
provider: CLAUDE_AGENT_SDK_PROVIDER,
|
|
622
|
-
|
|
298
|
+
fence: checkpoint.fence,
|
|
623
299
|
source: "response",
|
|
624
300
|
}, (text) => builder.emit({ type: "diagnostic", text }));
|
|
625
301
|
}
|
|
@@ -634,9 +310,11 @@ export async function startClaudeAgentSdk(prompt, cwd, options) {
|
|
|
634
310
|
builder.emit({ type: "diagnostic", text: resultText });
|
|
635
311
|
}
|
|
636
312
|
const message = resultText ?? `${CLAUDE_AGENT_SDK_PROVIDER} exec failed`;
|
|
637
|
-
|
|
313
|
+
const unavailable = !acceptedTurn && lastPreTerminalEvidenceWasRetry;
|
|
314
|
+
const failCode = unavailable ? "SUBAGENT_PROVIDER_UNAVAILABLE" : "SUBAGENT_EXEC_ERROR";
|
|
315
|
+
builder.emit({ type: "fail", message, code: failCode });
|
|
638
316
|
inputStream?.end();
|
|
639
|
-
throw new
|
|
317
|
+
throw new SubagentFailure(failCode, message);
|
|
640
318
|
}
|
|
641
319
|
default:
|
|
642
320
|
break;
|