@astrosheep/keiyaku 2.8.5 → 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/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,557 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { FlowError } from "../../flow-error.js";
|
|
3
|
-
import { appendDebugLog } from "../../telemetry/debug-log.js";
|
|
4
|
-
import { SUBAGENT_SESSION_VERSION } from "../session.js";
|
|
5
|
-
import { createProjectionDriver } from "../harness/execution-handle.js";
|
|
6
|
-
import { activityCallFromNamedTool, boundActivityExcerpt, diffstatFromUnifiedPatch } from "../harness/activity-values.js";
|
|
7
|
-
import { AGENT_THOUGHT_TEXT_MAX_CHARS } from "../harness/events.js";
|
|
8
|
-
import { createAbortError, emitProviderEvidence, sha256Utf8 } from "../harness/runtime.js";
|
|
9
|
-
import { SubagentFailure, } from "../types.js";
|
|
10
|
-
/** Opaque Pi resume handle: exact session file path (UUID alone is ambiguous). */
|
|
11
|
-
export const piSessionSchema = z.object({
|
|
12
|
-
sessionFile: z.string().trim().min(1),
|
|
13
|
-
sessionId: z.string().trim().min(1).optional(),
|
|
14
|
-
});
|
|
15
|
-
const PI_PROVIDER = "pi";
|
|
16
|
-
/** Exact model shape: `<provider>/<id>` (single slash separating non-empty sides). */
|
|
17
|
-
const PI_MODEL_PATTERN = /^[^/]+\/[^/]+$/;
|
|
18
|
-
const PI_ACKNOWLEDGED_UNPERSISTED = new Set(["message_update", "queue_update"]);
|
|
19
|
-
const PI_MAPPED = new Set([
|
|
20
|
-
"agent_start",
|
|
21
|
-
"agent_end",
|
|
22
|
-
"turn_start",
|
|
23
|
-
"turn_end",
|
|
24
|
-
"message_start",
|
|
25
|
-
"message_end",
|
|
26
|
-
"tool_execution_start",
|
|
27
|
-
"tool_execution_update",
|
|
28
|
-
"tool_execution_end",
|
|
29
|
-
"compaction_start",
|
|
30
|
-
"compaction_end",
|
|
31
|
-
"session_info_changed",
|
|
32
|
-
"thinking_level_changed",
|
|
33
|
-
"auto_retry_start",
|
|
34
|
-
"auto_retry_end",
|
|
35
|
-
]);
|
|
36
|
-
function piIngressDisposition(type) {
|
|
37
|
-
if (PI_ACKNOWLEDGED_UNPERSISTED.has(type))
|
|
38
|
-
return "acknowledged-unpersisted";
|
|
39
|
-
if (PI_MAPPED.has(type))
|
|
40
|
-
return "mapped";
|
|
41
|
-
return "unknown";
|
|
42
|
-
}
|
|
43
|
-
function toPiSdkThinkingLevel(effort) {
|
|
44
|
-
return effort; // opacity boundary
|
|
45
|
-
}
|
|
46
|
-
let piSdkLoader;
|
|
47
|
-
const importPiSdk = new Function("specifier", "return import(specifier)");
|
|
48
|
-
async function loadPiSdk() {
|
|
49
|
-
if (piSdkLoader) {
|
|
50
|
-
return piSdkLoader();
|
|
51
|
-
}
|
|
52
|
-
return (await importPiSdk("@earendil-works/pi-coding-agent"));
|
|
53
|
-
}
|
|
54
|
-
export function setPiSdkLoaderForTests(loader) {
|
|
55
|
-
piSdkLoader = loader;
|
|
56
|
-
}
|
|
57
|
-
export function resetPiSdkLoaderForTests() {
|
|
58
|
-
piSdkLoader = undefined;
|
|
59
|
-
}
|
|
60
|
-
export function parsePiModelRef(model) {
|
|
61
|
-
const trimmed = model.trim();
|
|
62
|
-
if (!PI_MODEL_PATTERN.test(trimmed)) {
|
|
63
|
-
throw new FlowError("INVALID_SETTINGS", `Invalid pi model '${model}'. Expected exact shape '<provider>/<id>'.`);
|
|
64
|
-
}
|
|
65
|
-
const slash = trimmed.indexOf("/");
|
|
66
|
-
return {
|
|
67
|
-
provider: trimmed.slice(0, slash),
|
|
68
|
-
id: trimmed.slice(slash + 1),
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function extractAssistantText(event) {
|
|
72
|
-
if (event.type === "message_end") {
|
|
73
|
-
const message = event.message;
|
|
74
|
-
if (message?.role !== "assistant")
|
|
75
|
-
return undefined;
|
|
76
|
-
return extractContentText(message.content);
|
|
77
|
-
}
|
|
78
|
-
return undefined;
|
|
79
|
-
}
|
|
80
|
-
function extractContentText(content) {
|
|
81
|
-
if (typeof content === "string") {
|
|
82
|
-
const trimmed = content.trim();
|
|
83
|
-
return trimmed || undefined;
|
|
84
|
-
}
|
|
85
|
-
if (!Array.isArray(content))
|
|
86
|
-
return undefined;
|
|
87
|
-
const text = content
|
|
88
|
-
.map((block) => {
|
|
89
|
-
if (typeof block === "string")
|
|
90
|
-
return block;
|
|
91
|
-
if (block &&
|
|
92
|
-
typeof block === "object" &&
|
|
93
|
-
block.type === "text") {
|
|
94
|
-
const candidate = block.text;
|
|
95
|
-
return typeof candidate === "string" ? candidate : "";
|
|
96
|
-
}
|
|
97
|
-
return "";
|
|
98
|
-
})
|
|
99
|
-
.join("")
|
|
100
|
-
.trim();
|
|
101
|
-
return text || undefined;
|
|
102
|
-
}
|
|
103
|
-
function emitPiThoughts(builder, event, turnOrdinal, messageOrdinal) {
|
|
104
|
-
if (event.type !== "message_end")
|
|
105
|
-
return;
|
|
106
|
-
const message = event.message;
|
|
107
|
-
if (message?.role !== "assistant" || !Array.isArray(message.content))
|
|
108
|
-
return;
|
|
109
|
-
message.content.forEach((block, blockIndex) => {
|
|
110
|
-
if (!block || typeof block !== "object")
|
|
111
|
-
return;
|
|
112
|
-
const record = block;
|
|
113
|
-
if (record.type !== "thinking" || record.redacted === true)
|
|
114
|
-
return;
|
|
115
|
-
if (typeof record.thinking !== "string" || record.thinking.trim().length === 0)
|
|
116
|
-
return;
|
|
117
|
-
const truncated = record.thinking.length > AGENT_THOUGHT_TEXT_MAX_CHARS;
|
|
118
|
-
builder.emit({
|
|
119
|
-
type: "thought",
|
|
120
|
-
id: `t${turnOrdinal}:m${messageOrdinal}:b${blockIndex}`,
|
|
121
|
-
text: record.thinking.slice(0, AGENT_THOUGHT_TEXT_MAX_CHARS),
|
|
122
|
-
final: true,
|
|
123
|
-
...(truncated ? { truncated: true } : {}),
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
function piRecord(value) {
|
|
128
|
-
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
129
|
-
? value
|
|
130
|
-
: undefined;
|
|
131
|
-
}
|
|
132
|
-
function piCallFacts(args) {
|
|
133
|
-
const value = piRecord(args);
|
|
134
|
-
if (!value)
|
|
135
|
-
return {};
|
|
136
|
-
return {
|
|
137
|
-
...(typeof value.command === "string" ? { command: value.command } : {}),
|
|
138
|
-
...(typeof value.description === "string" ? { description: value.description } : {}),
|
|
139
|
-
...(typeof value.path === "string" ? { path: value.path } : {}),
|
|
140
|
-
...(typeof value.offset === "number" && Number.isFinite(value.offset) ? { offset: value.offset } : {}),
|
|
141
|
-
...(typeof value.limit === "number" && Number.isFinite(value.limit) ? { limit: value.limit } : {}),
|
|
142
|
-
...(typeof value.query === "string" ? { query: value.query } : {}),
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
function piResult(value, isError) {
|
|
146
|
-
const payload = piRecord(value);
|
|
147
|
-
const content = Array.isArray(payload?.content)
|
|
148
|
-
? payload.content.flatMap((entry) => {
|
|
149
|
-
const block = piRecord(entry);
|
|
150
|
-
return block?.type === "text" && typeof block.text === "string" ? [block.text] : [];
|
|
151
|
-
}).join("\n")
|
|
152
|
-
: undefined;
|
|
153
|
-
const details = piRecord(payload?.details);
|
|
154
|
-
const diffstat = typeof details?.patch === "string" ? diffstatFromUnifiedPatch(details.patch) : undefined;
|
|
155
|
-
return {
|
|
156
|
-
status: isError ? "error" : "ok",
|
|
157
|
-
...(content ? { message: boundActivityExcerpt(content) } : {}),
|
|
158
|
-
...(diffstat ? { diffstat } : {}),
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
function piActivityBody(event, calls) {
|
|
162
|
-
if (event.type !== "tool_execution_start" &&
|
|
163
|
-
event.type !== "tool_execution_update" &&
|
|
164
|
-
event.type !== "tool_execution_end") {
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
167
|
-
if (typeof event.toolCallId !== "string" || typeof event.toolName !== "string")
|
|
168
|
-
return undefined;
|
|
169
|
-
const phase = event.type === "tool_execution_start"
|
|
170
|
-
? "started"
|
|
171
|
-
: event.type === "tool_execution_update"
|
|
172
|
-
? "updated"
|
|
173
|
-
: "completed";
|
|
174
|
-
if (event.type === "tool_execution_start") {
|
|
175
|
-
calls.set(event.toolCallId, activityCallFromNamedTool(event.toolName, piCallFacts(event.args)));
|
|
176
|
-
}
|
|
177
|
-
const call = calls.get(event.toolCallId) ?? (event.type === "tool_execution_end"
|
|
178
|
-
? { kind: "other", display: event.toolName }
|
|
179
|
-
: activityCallFromNamedTool(event.toolName, piCallFacts(event.args)));
|
|
180
|
-
if (event.type === "tool_execution_end")
|
|
181
|
-
calls.delete(event.toolCallId);
|
|
182
|
-
return {
|
|
183
|
-
type: "activity",
|
|
184
|
-
phase,
|
|
185
|
-
id: event.toolCallId,
|
|
186
|
-
tool: event.toolName,
|
|
187
|
-
call,
|
|
188
|
-
...(event.type === "tool_execution_start"
|
|
189
|
-
? {}
|
|
190
|
-
: { result: piResult(event.type === "tool_execution_update" ? event.partialResult : event.result, event.type === "tool_execution_end" && event.isError) }),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
function piUsageBody(event) {
|
|
194
|
-
if (event.type !== "message_end")
|
|
195
|
-
return undefined;
|
|
196
|
-
const message = event.message;
|
|
197
|
-
if (message?.role !== "assistant")
|
|
198
|
-
return undefined;
|
|
199
|
-
const usage = message.usage;
|
|
200
|
-
if (!usage || typeof usage.input !== "number" || typeof usage.output !== "number")
|
|
201
|
-
return undefined;
|
|
202
|
-
return {
|
|
203
|
-
type: "usage",
|
|
204
|
-
inputTokens: usage.input,
|
|
205
|
-
outputTokens: usage.output,
|
|
206
|
-
...(typeof usage.cacheRead === "number" ? { cachedInputTokens: usage.cacheRead } : {}),
|
|
207
|
-
...(typeof usage.cost?.total === "number" ? { costUsd: usage.cost.total } : {}),
|
|
208
|
-
...(typeof message.responseModel === "string"
|
|
209
|
-
? { model: message.responseModel }
|
|
210
|
-
: typeof message.model === "string"
|
|
211
|
-
? { model: message.model }
|
|
212
|
-
: {}),
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
/** True when native messages prove the run stopped via abort (stopReason aborted). */
|
|
216
|
-
function agentEndLooksAborted(event) {
|
|
217
|
-
if (event.type !== "agent_end")
|
|
218
|
-
return false;
|
|
219
|
-
const messages = event.messages;
|
|
220
|
-
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
221
|
-
const message = messages[i];
|
|
222
|
-
if (!message || message.role !== "assistant")
|
|
223
|
-
continue;
|
|
224
|
-
if (message.stopReason === "aborted")
|
|
225
|
-
return true;
|
|
226
|
-
// Last assistant message is the terminal one for this run.
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
return false;
|
|
230
|
-
}
|
|
231
|
-
/** Returns the terminal Pi provider error, if the final assistant message ended in error. */
|
|
232
|
-
function agentEndProviderError(event) {
|
|
233
|
-
if (event.type !== "agent_end")
|
|
234
|
-
return undefined;
|
|
235
|
-
const messages = event.messages;
|
|
236
|
-
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
237
|
-
const message = messages[i];
|
|
238
|
-
if (!message || message.role !== "assistant")
|
|
239
|
-
continue;
|
|
240
|
-
if (message.stopReason !== "error")
|
|
241
|
-
return undefined;
|
|
242
|
-
if (typeof message.errorMessage === "string" && message.errorMessage.trim()) {
|
|
243
|
-
return message.errorMessage;
|
|
244
|
-
}
|
|
245
|
-
return `${PI_PROVIDER} provider error (stopReason error)`;
|
|
246
|
-
}
|
|
247
|
-
return undefined;
|
|
248
|
-
}
|
|
249
|
-
function normalizeClearQueue(result) {
|
|
250
|
-
if (Array.isArray(result))
|
|
251
|
-
return result;
|
|
252
|
-
return [...(result.steering ?? []), ...(result.followUp ?? [])];
|
|
253
|
-
}
|
|
254
|
-
function buildPiSessionOutcome(session, finalMessage) {
|
|
255
|
-
const sessionFile = session.sessionFile;
|
|
256
|
-
if (!sessionFile) {
|
|
257
|
-
return new SubagentFailure("SUBAGENT_EXEC_ERROR", `${PI_PROVIDER} exec ended without a session file`);
|
|
258
|
-
}
|
|
259
|
-
return {
|
|
260
|
-
finalMessage,
|
|
261
|
-
session: {
|
|
262
|
-
provider: "pi",
|
|
263
|
-
version: SUBAGENT_SESSION_VERSION,
|
|
264
|
-
handle: {
|
|
265
|
-
sessionFile,
|
|
266
|
-
sessionId: session.sessionId,
|
|
267
|
-
},
|
|
268
|
-
},
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
function bindPiSessionEvents(session, builder, options, steerControl, state, setTurnOrdinal, settle) {
|
|
272
|
-
return session.subscribe((event) => {
|
|
273
|
-
builder.ingress(PI_PROVIDER, event.type, event, piIngressDisposition(event.type), () => {
|
|
274
|
-
if (event.type === "agent_start") {
|
|
275
|
-
builder.emit({ type: "turn", phase: "started" });
|
|
276
|
-
}
|
|
277
|
-
if (event.type === "turn_start") {
|
|
278
|
-
state.thoughtTurnOrdinal += 1;
|
|
279
|
-
state.assistantMessageOrdinal = -1;
|
|
280
|
-
state.activeAssistantMessageOrdinal = undefined;
|
|
281
|
-
}
|
|
282
|
-
if (event.type === "message_start") {
|
|
283
|
-
const message = event.message;
|
|
284
|
-
if (message?.role === "assistant") {
|
|
285
|
-
state.assistantMessageOrdinal += 1;
|
|
286
|
-
state.activeAssistantMessageOrdinal = state.assistantMessageOrdinal;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
const activity = piActivityBody(event, state.activityCalls);
|
|
290
|
-
if (activity)
|
|
291
|
-
builder.emit(activity);
|
|
292
|
-
if (event.type === "message_end") {
|
|
293
|
-
const message = event.message;
|
|
294
|
-
if (message?.role === "assistant") {
|
|
295
|
-
if (state.activeAssistantMessageOrdinal === undefined) {
|
|
296
|
-
state.assistantMessageOrdinal += 1;
|
|
297
|
-
state.activeAssistantMessageOrdinal = state.assistantMessageOrdinal;
|
|
298
|
-
}
|
|
299
|
-
emitPiThoughts(builder, event, state.thoughtTurnOrdinal, state.activeAssistantMessageOrdinal);
|
|
300
|
-
state.activeAssistantMessageOrdinal = undefined;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
const assistantText = extractAssistantText(event);
|
|
304
|
-
if (assistantText) {
|
|
305
|
-
state.lastAssistantMessage = assistantText;
|
|
306
|
-
builder.emit({ type: "message", text: assistantText });
|
|
307
|
-
}
|
|
308
|
-
const usage = piUsageBody(event);
|
|
309
|
-
if (usage)
|
|
310
|
-
builder.emit(usage);
|
|
311
|
-
if (event.type === "turn_end" && !state.abortIntent) {
|
|
312
|
-
state.turnOrdinal += 1;
|
|
313
|
-
setTurnOrdinal(state.turnOrdinal);
|
|
314
|
-
const checkpoint = { fence: { kind: "ordinal", ordinal: state.turnOrdinal } };
|
|
315
|
-
// Evidence identifies the native turn_end before the synchronous pump can
|
|
316
|
-
// consume tells at this checkpoint.
|
|
317
|
-
if (options.onEvidence) {
|
|
318
|
-
emitProviderEvidence(options.onEvidence, { type: "checkpoint", provider: PI_PROVIDER, ...checkpoint, source: "notification" }, (text) => builder.emit({ type: "diagnostic", text }));
|
|
319
|
-
}
|
|
320
|
-
// Sync checkpoint window: claim/steer must run before returning from turn_end.
|
|
321
|
-
options.onSyncCheckpoint?.(steerControl, checkpoint);
|
|
322
|
-
}
|
|
323
|
-
if (event.type !== "agent_end" || state.settled) {
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
if (state.abortIntent || agentEndLooksAborted(event)) {
|
|
327
|
-
settle.reject(createAbortError(`${PI_PROVIDER} exec cancelled by client`));
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
if (event.willRetry) {
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
const providerError = agentEndProviderError(event);
|
|
334
|
-
if (providerError) {
|
|
335
|
-
const failure = new SubagentFailure("SUBAGENT_EXEC_ERROR", providerError);
|
|
336
|
-
builder.emit({ type: "fail", message: failure.message });
|
|
337
|
-
settle.reject(failure);
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
const outcome = buildPiSessionOutcome(session, state.lastAssistantMessage);
|
|
341
|
-
if (outcome instanceof SubagentFailure) {
|
|
342
|
-
builder.emit({ type: "fail", message: outcome.message });
|
|
343
|
-
settle.reject(outcome);
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
builder.emit({ type: "turn", phase: "completed" });
|
|
347
|
-
builder.emit({ type: "done", finalMessage: outcome.finalMessage, session: outcome.session });
|
|
348
|
-
settle.resolve(outcome);
|
|
349
|
-
});
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
export async function startPi(prompt, cwd, options = {}) {
|
|
353
|
-
const resumeSessionFile = options.sessionFile?.trim();
|
|
354
|
-
appendDebugLog(`startPi: mode=${resumeSessionFile ? "resume" : "fresh"} model=${options.model ?? "default"}`, { cwd, section: PI_PROVIDER });
|
|
355
|
-
const sdk = await loadPiSdk();
|
|
356
|
-
const sessionManagerApi = readSessionManager(sdk);
|
|
357
|
-
const sessionManager = resumeSessionFile
|
|
358
|
-
? sessionManagerApi.open(resumeSessionFile)
|
|
359
|
-
: sessionManagerApi.create(cwd);
|
|
360
|
-
let model;
|
|
361
|
-
let authStorage;
|
|
362
|
-
let modelRegistry;
|
|
363
|
-
if (options.model !== undefined && options.model.trim().length > 0) {
|
|
364
|
-
const original = options.model.trim();
|
|
365
|
-
const ref = parsePiModelRef(original);
|
|
366
|
-
authStorage = sdk.AuthStorage.create();
|
|
367
|
-
modelRegistry = sdk.ModelRegistry.create(authStorage);
|
|
368
|
-
model = modelRegistry.find(ref.provider, ref.id);
|
|
369
|
-
if (!model) {
|
|
370
|
-
throw new SubagentFailure("SUBAGENT_PROVIDER_UNAVAILABLE", `${PI_PROVIDER} model '${original}' is not available`);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
// With an Akuma body, retain the default loader's discovery and override only its append list.
|
|
374
|
-
// The override deliberately suppresses discovered APPEND_SYSTEM.md content.
|
|
375
|
-
if (options.appendSystemPromptOverride && (!sdk.DefaultResourceLoader || !sdk.getAgentDir)) {
|
|
376
|
-
throw new Error(`${PI_PROVIDER} SDK does not expose DefaultResourceLoader and getAgentDir`);
|
|
377
|
-
}
|
|
378
|
-
let emittedAppendEvidence = false;
|
|
379
|
-
let pendingEvidenceDiagnostics = 0;
|
|
380
|
-
let reportEvidenceDiagnostic = () => {
|
|
381
|
-
pendingEvidenceDiagnostics += 1;
|
|
382
|
-
appendDebugLog("provider evidence callback failed before Pi driver start", { cwd, section: PI_PROVIDER });
|
|
383
|
-
};
|
|
384
|
-
const observedAppendOverride = options.appendSystemPromptOverride && options.onEvidence
|
|
385
|
-
? () => {
|
|
386
|
-
const body = options.appendSystemPromptOverride();
|
|
387
|
-
if (!emittedAppendEvidence) {
|
|
388
|
-
emittedAppendEvidence = true;
|
|
389
|
-
emitProviderEvidence(options.onEvidence, { type: "outbound", provider: PI_PROVIDER, direction: "input", kind: "system-prompt", ...sha256Utf8(body.join("\n")) }, reportEvidenceDiagnostic);
|
|
390
|
-
}
|
|
391
|
-
return body;
|
|
392
|
-
}
|
|
393
|
-
: options.appendSystemPromptOverride;
|
|
394
|
-
const resourceLoader = observedAppendOverride
|
|
395
|
-
? new sdk.DefaultResourceLoader({
|
|
396
|
-
cwd,
|
|
397
|
-
agentDir: sdk.getAgentDir(),
|
|
398
|
-
appendSystemPromptOverride: observedAppendOverride,
|
|
399
|
-
})
|
|
400
|
-
: undefined;
|
|
401
|
-
await resourceLoader?.reload();
|
|
402
|
-
// Empty bodies retain the SDK's default ResourceLoader path unchanged.
|
|
403
|
-
const created = await sdk.createAgentSession({
|
|
404
|
-
cwd,
|
|
405
|
-
sessionManager,
|
|
406
|
-
...(options.thinkingLevel ? { thinkingLevel: toPiSdkThinkingLevel(options.thinkingLevel) } : {}),
|
|
407
|
-
...(model ? { model, authStorage, modelRegistry } : {}),
|
|
408
|
-
...(resourceLoader ? { resourceLoader } : {}),
|
|
409
|
-
});
|
|
410
|
-
const session = created.session;
|
|
411
|
-
if (options.onEvidence)
|
|
412
|
-
emitProviderEvidence(options.onEvidence, { type: "session", provider: PI_PROVIDER, sessionId: session.sessionId, ...(session.sessionFile ? { sessionFile: session.sessionFile } : {}) }, reportEvidenceDiagnostic);
|
|
413
|
-
session.setSteeringMode("one-at-a-time");
|
|
414
|
-
let submittedAtTurn = 0;
|
|
415
|
-
let emitTurnStarted;
|
|
416
|
-
const enqueue = async (tell) => {
|
|
417
|
-
// Acceptance into volatile queue only. text is core-rendered; send byte-for-byte.
|
|
418
|
-
if (options.onEvidence)
|
|
419
|
-
emitProviderEvidence(options.onEvidence, { type: "outbound", provider: PI_PROVIDER, direction: "input", kind: "steer", ...sha256Utf8(tell.text) }, reportEvidenceDiagnostic);
|
|
420
|
-
if (tell.effort) {
|
|
421
|
-
if (!session.setThinkingLevel)
|
|
422
|
-
throw new Error(`${PI_PROVIDER} session does not support thinking level control`);
|
|
423
|
-
session.setThinkingLevel(toPiSdkThinkingLevel(tell.effort));
|
|
424
|
-
}
|
|
425
|
-
await session.steer(tell.text);
|
|
426
|
-
emitTurnStarted?.();
|
|
427
|
-
if (options.onEvidence)
|
|
428
|
-
emitProviderEvidence(options.onEvidence, { type: "ack", provider: PI_PROVIDER, fence: { kind: "ordinal", ordinal: submittedAtTurn }, outbound: "steer" }, reportEvidenceDiagnostic);
|
|
429
|
-
return { fence: { kind: "ordinal", ordinal: submittedAtTurn } };
|
|
430
|
-
};
|
|
431
|
-
const steerControl = { enqueue };
|
|
432
|
-
let disposed = false;
|
|
433
|
-
let unsub;
|
|
434
|
-
const disposeSession = () => {
|
|
435
|
-
if (disposed)
|
|
436
|
-
return;
|
|
437
|
-
disposed = true;
|
|
438
|
-
unsub?.();
|
|
439
|
-
try {
|
|
440
|
-
session.dispose();
|
|
441
|
-
}
|
|
442
|
-
catch {
|
|
443
|
-
// best-effort
|
|
444
|
-
}
|
|
445
|
-
};
|
|
446
|
-
let abortRequested;
|
|
447
|
-
const requestAbort = async (state) => {
|
|
448
|
-
state.abortIntent = true;
|
|
449
|
-
if (abortRequested) {
|
|
450
|
-
await abortRequested;
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
abortRequested = (async () => {
|
|
454
|
-
// Publish abortRequested before clearQueue can synchronously emit queue_update.
|
|
455
|
-
await Promise.resolve();
|
|
456
|
-
try {
|
|
457
|
-
session.clearQueue();
|
|
458
|
-
await session.abort();
|
|
459
|
-
}
|
|
460
|
-
finally {
|
|
461
|
-
if (state.settled) {
|
|
462
|
-
disposeSession();
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
})();
|
|
466
|
-
await abortRequested;
|
|
467
|
-
};
|
|
468
|
-
return createProjectionDriver({
|
|
469
|
-
steerMode: "mid-execution",
|
|
470
|
-
initialTurn: options.initialTurn,
|
|
471
|
-
enqueue,
|
|
472
|
-
onIngress: options.onIngress,
|
|
473
|
-
async abort() {
|
|
474
|
-
await requestAbort({ abortIntent: true, settled: false });
|
|
475
|
-
},
|
|
476
|
-
async run(builder) {
|
|
477
|
-
reportEvidenceDiagnostic = () => builder.emit({ type: "diagnostic", text: "provider evidence callback failed" });
|
|
478
|
-
emitTurnStarted = () => builder.emit({ type: "turn", phase: "started" });
|
|
479
|
-
while (pendingEvidenceDiagnostics > 0) {
|
|
480
|
-
pendingEvidenceDiagnostics -= 1;
|
|
481
|
-
reportEvidenceDiagnostic();
|
|
482
|
-
}
|
|
483
|
-
const state = {
|
|
484
|
-
abortIntent: false,
|
|
485
|
-
lastAssistantMessage: "",
|
|
486
|
-
settled: false,
|
|
487
|
-
turnOrdinal: 0,
|
|
488
|
-
thoughtTurnOrdinal: 0,
|
|
489
|
-
assistantMessageOrdinal: -1,
|
|
490
|
-
activityCalls: new Map(),
|
|
491
|
-
};
|
|
492
|
-
let settleOutcome;
|
|
493
|
-
const outcome = new Promise((resolve, reject) => {
|
|
494
|
-
settleOutcome = {
|
|
495
|
-
resolve(value) {
|
|
496
|
-
if (state.settled)
|
|
497
|
-
return;
|
|
498
|
-
state.settled = true;
|
|
499
|
-
resolve(value);
|
|
500
|
-
},
|
|
501
|
-
reject(error) {
|
|
502
|
-
if (state.settled)
|
|
503
|
-
return;
|
|
504
|
-
state.settled = true;
|
|
505
|
-
reject(error);
|
|
506
|
-
},
|
|
507
|
-
};
|
|
508
|
-
unsub = bindPiSessionEvents(session, builder, options, steerControl, state, (ordinal) => { submittedAtTurn = ordinal; }, settleOutcome);
|
|
509
|
-
});
|
|
510
|
-
outcome.catch(() => undefined);
|
|
511
|
-
const onAbort = () => {
|
|
512
|
-
void requestAbort(state)
|
|
513
|
-
.catch((error) => {
|
|
514
|
-
settleOutcome.reject(error);
|
|
515
|
-
})
|
|
516
|
-
.finally(() => {
|
|
517
|
-
if (!state.settled) {
|
|
518
|
-
settleOutcome.reject(createAbortError(`${PI_PROVIDER} exec cancelled by client`));
|
|
519
|
-
}
|
|
520
|
-
});
|
|
521
|
-
};
|
|
522
|
-
builder.signal.addEventListener("abort", onAbort, { once: true });
|
|
523
|
-
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
524
|
-
try {
|
|
525
|
-
if (builder.signal.aborted || options.signal?.aborted) {
|
|
526
|
-
await requestAbort(state);
|
|
527
|
-
throw createAbortError(`${PI_PROVIDER} exec cancelled by client`);
|
|
528
|
-
}
|
|
529
|
-
const promptPromise = session.prompt(prompt).catch((error) => {
|
|
530
|
-
if (state.settled) {
|
|
531
|
-
return;
|
|
532
|
-
}
|
|
533
|
-
settleOutcome.reject(state.abortIntent ? createAbortError(`${PI_PROVIDER} exec cancelled by client`) : error);
|
|
534
|
-
});
|
|
535
|
-
const result = await outcome;
|
|
536
|
-
await promptPromise;
|
|
537
|
-
return result;
|
|
538
|
-
}
|
|
539
|
-
catch (error) {
|
|
540
|
-
if (state.abortIntent) {
|
|
541
|
-
throw createAbortError(`${PI_PROVIDER} exec cancelled by client`);
|
|
542
|
-
}
|
|
543
|
-
throw error;
|
|
544
|
-
}
|
|
545
|
-
finally {
|
|
546
|
-
builder.signal.removeEventListener("abort", onAbort);
|
|
547
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
548
|
-
await abortRequested?.catch(() => undefined);
|
|
549
|
-
disposeSession();
|
|
550
|
-
}
|
|
551
|
-
},
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
function readSessionManager(sdk) {
|
|
555
|
-
const store = sdk[`Session${"Man"}${"ager"}`];
|
|
556
|
-
return store;
|
|
557
|
-
}
|