@astrosheep/keiyaku 1.0.0 → 1.0.2
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 +73 -56
- package/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms_v2.js +103 -0
- package/build/agents/harness/activity-values.js +54 -0
- package/build/agents/harness/event-channel.js +55 -20
- package/build/agents/harness/events.js +47 -1
- package/build/agents/harness/execution-handle.js +292 -61
- package/build/agents/harness/index.js +103 -121
- package/build/agents/harness/pump.js +36 -47
- package/build/agents/harness/runtime.js +3 -0
- package/build/agents/launch-snapshot_v2.js +348 -0
- package/build/agents/opencode-sdk.js +42 -169
- package/build/agents/providers/claude-agent-sdk.js +240 -79
- package/build/agents/providers/codex-app-server.js +280 -72
- package/build/agents/providers/codex-sdk.js +159 -41
- package/build/agents/providers/event-type-tail.js +16 -0
- package/build/agents/providers/opencode-sdk.js +165 -59
- package/build/agents/providers/pi.js +254 -42
- package/build/agents/selector_v2.js +122 -0
- package/build/cli/commands/akuma.js +120 -42
- package/build/cli/completion.js +6 -7
- package/build/cli/flags.js +36 -10
- package/build/cli/help.js +42 -26
- package/build/cli/index.js +225 -93
- package/build/cli/parse.js +194 -75
- package/build/cli/projection-address.js +11 -0
- package/build/cli/render/address.js +88 -0
- package/build/cli/render/arc.js +10 -10
- package/build/cli/render/call.js +59 -0
- package/build/cli/render/compact-text.js +3 -0
- package/build/cli/render/errors.js +4 -2
- package/build/cli/render/format.js +6 -0
- package/build/cli/render/line-width.js +70 -0
- package/build/cli/render/misc.js +7 -4
- package/build/cli/render/petition.js +4 -3
- package/build/cli/render/projection-activity.js +201 -0
- package/build/cli/render/shared.js +46 -12
- package/build/cli/render/status.js +59 -10
- package/build/cli/render/tool-ledger-rollup.js +74 -0
- package/build/cli/render/tool-presentation.js +97 -0
- package/build/cli/render/wait.js +229 -0
- package/build/cli/skills-install.js +42 -24
- package/build/cli/subagent-guard.js +1 -1
- package/build/config/akuma-loader_v2.js +222 -0
- package/build/config/env-keys.js +0 -4
- package/build/config/env.js +0 -6
- package/build/config/settings.js +325 -12
- package/build/core/addressing.js +224 -0
- package/build/core/amend.js +30 -47
- package/build/core/arc.js +68 -60
- package/build/core/bind.js +105 -25
- package/build/core/call-persist.js +69 -0
- package/build/core/call.js +658 -0
- package/build/core/claim.js +72 -44
- package/build/core/command-io.js +19 -19
- package/build/core/context.js +11 -36
- package/build/core/draft.js +2 -3
- package/build/core/entry.js +101 -6
- package/build/core/execution-coordinate.js +62 -0
- package/build/core/execution-pact.js +141 -0
- package/build/core/forfeit.js +2 -3
- package/build/core/hints.js +10 -10
- package/build/core/ids.js +6 -0
- package/build/core/ledger.js +16 -1
- package/build/core/petition-claim-gates.js +14 -12
- package/build/core/petition-claim.js +1 -0
- package/build/core/petition-run.js +6 -2
- package/build/core/petition.js +63 -21
- package/build/core/places.js +106 -13
- package/build/core/projection/generation.js +412 -0
- package/build/core/projection/heart.js +316 -0
- package/build/core/projection/identity.js +81 -0
- package/build/core/projection/leash.js +87 -0
- package/build/core/projection/mint.js +154 -0
- package/build/core/projection-activity.js +219 -0
- package/build/core/projection-coordinate.js +35 -0
- package/build/core/projection-core.js +69 -463
- package/build/core/projection-generation-continuation.js +31 -0
- package/build/core/projection-generation-execution.js +148 -0
- package/build/core/projection-generation-identity.js +17 -0
- package/build/core/projection-generation-launcher.js +90 -0
- package/build/core/projection-generation-process.js +43 -0
- package/build/core/projection-generation-runner.js +144 -0
- package/build/core/projection-generation-runtime.js +15 -0
- package/build/core/projection-generation-store.js +707 -0
- package/build/core/projection-identity.js +11 -0
- package/build/core/projection-life-observer.js +87 -0
- package/build/core/projection-life-protocol.js +95 -0
- package/build/core/projection-mint.js +96 -24
- package/build/core/projection-runner-lock.js +230 -0
- package/build/core/projection-status.js +207 -107
- package/build/core/projection-tells.js +401 -0
- package/build/core/projection-wait.js +155 -0
- package/build/core/projection-wake.js +109 -231
- package/build/core/queue_v2.js +342 -0
- package/build/core/registry.js +6 -3
- package/build/core/render.js +63 -1
- package/build/core/renew.js +80 -53
- package/build/core/scope.js +186 -137
- package/build/core/seal.js +16 -19
- package/build/core/status.js +88 -25
- package/build/core/stored-agent-event.js +101 -0
- package/build/core/transcripts.js +214 -228
- package/build/core/verdict.js +27 -15
- package/build/core/worktree-bootstrap.js +187 -0
- package/build/core/worktree-path.js +72 -18
- package/build/flow-error.js +4 -6
- package/build/generated/version.js +1 -1
- package/build/git/branches.js +6 -1
- package/build/index.js +8 -5
- package/build/keiyaku.js +1 -3
- package/package.json +6 -5
- package/skills/keiyaku/SKILL.md +6 -47
- package/skills/keiyaku-akuma/SKILL.md +75 -0
- package/build/agents/effective-policy.js +0 -32
- package/build/agents/index.js +0 -114
- package/build/agents/selector.js +0 -28
- package/build/cli/render/summon.js +0 -17
- package/build/cli/render/tell.js +0 -11
- package/build/config/akuma-loader.js +0 -268
- package/build/core/queue.js +0 -73
- package/build/core/summon-persist.js +0 -73
- package/build/core/summon.js +0 -377
|
@@ -3,22 +3,111 @@ import { z } from "zod";
|
|
|
3
3
|
import { appendDebugLog } from "../../telemetry/debug-log.js";
|
|
4
4
|
import { SUBAGENT_SESSION_VERSION } from "../session.js";
|
|
5
5
|
import { createProjectionDriver } from "../harness/execution-handle.js";
|
|
6
|
+
import { boundActivityExcerpt, diffstatFromUnifiedPatch } from "../harness/activity-values.js";
|
|
7
|
+
import { AGENT_PLAN_ITEM_TEXT_MAX_CHARS, AGENT_PLAN_MAX_ITEMS, AGENT_THOUGHT_TEXT_MAX_CHARS, } from "../harness/events.js";
|
|
6
8
|
import { buildSubagentEnv, createAbortError, emitProviderEvidence, sha256Utf8 } from "../harness/runtime.js";
|
|
7
|
-
import { coerceString } from "
|
|
9
|
+
import { coerceString } from "../harness/runtime.js";
|
|
10
|
+
/** Identity-only opacity boundary for codex-app-server turn/start effort. */
|
|
11
|
+
function toCodexAppServerEffort(effort) {
|
|
12
|
+
return effort;
|
|
13
|
+
}
|
|
14
|
+
const CODEX_APP_SERVER_NOTIFICATION_ACKNOWLEDGED = new Set(["item/agentMessage/delta"]);
|
|
15
|
+
const CODEX_APP_SERVER_NOTIFICATION_MAPPED = new Set([
|
|
16
|
+
"item/completed",
|
|
17
|
+
"turn/started",
|
|
18
|
+
"turn/completed",
|
|
19
|
+
"error",
|
|
20
|
+
]);
|
|
21
|
+
function codexAppServerNotificationDisposition(method) {
|
|
22
|
+
if (CODEX_APP_SERVER_NOTIFICATION_ACKNOWLEDGED.has(method))
|
|
23
|
+
return "acknowledged-unpersisted";
|
|
24
|
+
if (CODEX_APP_SERVER_NOTIFICATION_MAPPED.has(method))
|
|
25
|
+
return "mapped";
|
|
26
|
+
return "unknown";
|
|
27
|
+
}
|
|
8
28
|
/** Session handle for codex-app-server: thread id plus optional CODEX_HOME for cross-process resume. */
|
|
9
29
|
export const codexAppServerSessionSchema = z.object({
|
|
10
30
|
threadId: z.string().trim().min(1),
|
|
11
31
|
codexHome: z.string().trim().min(1).optional(),
|
|
12
32
|
});
|
|
33
|
+
function appServerRecord(value) {
|
|
34
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
35
|
+
? value
|
|
36
|
+
: undefined;
|
|
37
|
+
}
|
|
38
|
+
const CODEX_APP_SERVER_ACTIVITY_ITEM_TYPES = [
|
|
39
|
+
"commandExecution",
|
|
40
|
+
"fileChange",
|
|
41
|
+
"webSearch",
|
|
42
|
+
"mcpToolCall",
|
|
43
|
+
];
|
|
44
|
+
function isCodexAppServerActivityItemType(value) {
|
|
45
|
+
return CODEX_APP_SERVER_ACTIVITY_ITEM_TYPES.includes(value);
|
|
46
|
+
}
|
|
47
|
+
function appServerActivityCall(itemType, item) {
|
|
48
|
+
switch (itemType) {
|
|
49
|
+
case "commandExecution":
|
|
50
|
+
return typeof item.command === "string"
|
|
51
|
+
? {
|
|
52
|
+
kind: "run",
|
|
53
|
+
command: item.command,
|
|
54
|
+
...(typeof item.description === "string" && item.description ? { description: item.description } : {}),
|
|
55
|
+
}
|
|
56
|
+
: { kind: "other", display: itemType };
|
|
57
|
+
case "fileChange": {
|
|
58
|
+
const changes = Array.isArray(item.changes)
|
|
59
|
+
? item.changes.flatMap((entry) => {
|
|
60
|
+
const change = appServerRecord(entry);
|
|
61
|
+
if (!change || typeof change.path !== "string")
|
|
62
|
+
return [];
|
|
63
|
+
if (change.kind !== "add" && change.kind !== "update" && change.kind !== "delete")
|
|
64
|
+
return [];
|
|
65
|
+
const op = change.kind;
|
|
66
|
+
return [{ op, path: change.path }];
|
|
67
|
+
})
|
|
68
|
+
: [];
|
|
69
|
+
if (changes.length > 0)
|
|
70
|
+
return { kind: "fileChange", changes };
|
|
71
|
+
return { kind: "other", display: typeof item.path === "string" ? `fileChange ${item.path}` : itemType };
|
|
72
|
+
}
|
|
73
|
+
case "webSearch":
|
|
74
|
+
return typeof item.query === "string" ? { kind: "search", query: item.query } : { kind: "other", display: itemType };
|
|
75
|
+
case "mcpToolCall":
|
|
76
|
+
return typeof item.server === "string" && typeof item.tool === "string"
|
|
77
|
+
? { kind: "other", display: `${item.server}.${item.tool}` }
|
|
78
|
+
: { kind: "other", display: itemType };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function appServerActivityResult(item) {
|
|
82
|
+
const exitCode = typeof item.exitCode === "number" && Number.isFinite(item.exitCode) ? item.exitCode : undefined;
|
|
83
|
+
const message = typeof item.aggregatedOutput === "string" && item.aggregatedOutput
|
|
84
|
+
? boundActivityExcerpt(item.aggregatedOutput)
|
|
85
|
+
: typeof item.output === "string" && item.output
|
|
86
|
+
? boundActivityExcerpt(item.output)
|
|
87
|
+
: typeof item.error === "string" && item.error
|
|
88
|
+
? boundActivityExcerpt(item.error)
|
|
89
|
+
: undefined;
|
|
90
|
+
const details = item.details !== null && typeof item.details === "object" && !Array.isArray(item.details)
|
|
91
|
+
? item.details
|
|
92
|
+
: undefined;
|
|
93
|
+
const patch = typeof details?.patch === "string" ? details.patch : undefined;
|
|
94
|
+
const diffstat = patch ? diffstatFromUnifiedPatch(patch) : undefined;
|
|
95
|
+
return {
|
|
96
|
+
status: item.status === "failed" || (exitCode !== undefined && exitCode !== 0) ? "error" : "ok",
|
|
97
|
+
...(message ? { message } : {}),
|
|
98
|
+
...(exitCode === undefined ? {} : { exitCode }),
|
|
99
|
+
...(diffstat ? { diffstat } : {}),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
13
102
|
const CODEX_APP_SERVER_PROVIDER = "codex-app-server";
|
|
14
103
|
const MINIMUM_CODEX_APP_SERVER_VERSION = { major: 0, minor: 143, patch: 0 };
|
|
15
104
|
/** Non-interactive defaults for turn/start (faye #316 policy A). */
|
|
16
105
|
export const CODEX_APP_SERVER_TURN_APPROVAL_POLICY = "never";
|
|
17
|
-
export function
|
|
106
|
+
export function buildCodexAppServerWorkspaceWriteSandboxPolicy(input) {
|
|
18
107
|
return {
|
|
19
108
|
type: "workspaceWrite",
|
|
20
|
-
writableRoots: [
|
|
21
|
-
networkAccess:
|
|
109
|
+
writableRoots: [...input.writableRoots],
|
|
110
|
+
networkAccess: input.networkAccess,
|
|
22
111
|
excludeTmpdirEnvVar: false,
|
|
23
112
|
excludeSlashTmp: false,
|
|
24
113
|
};
|
|
@@ -43,6 +132,40 @@ export function configOwnsSandboxPolicy(config) {
|
|
|
43
132
|
}
|
|
44
133
|
return false;
|
|
45
134
|
}
|
|
135
|
+
function extractReasoningSummary(item) {
|
|
136
|
+
const summary = item.summary;
|
|
137
|
+
const text = typeof summary === "string"
|
|
138
|
+
? summary
|
|
139
|
+
: Array.isArray(summary)
|
|
140
|
+
? summary.map((part) => {
|
|
141
|
+
if (typeof part === "string")
|
|
142
|
+
return part;
|
|
143
|
+
if (!part || typeof part !== "object")
|
|
144
|
+
return "";
|
|
145
|
+
const record = part;
|
|
146
|
+
if (record.type !== "summary_text" && record.type !== "text")
|
|
147
|
+
return "";
|
|
148
|
+
return typeof record.text === "string" ? record.text : "";
|
|
149
|
+
}).join("\n")
|
|
150
|
+
: "";
|
|
151
|
+
return text.trim().length > 0 ? text : undefined;
|
|
152
|
+
}
|
|
153
|
+
function extractPlanItems(item) {
|
|
154
|
+
if (!Array.isArray(item.items))
|
|
155
|
+
return [];
|
|
156
|
+
return item.items.slice(0, AGENT_PLAN_MAX_ITEMS).flatMap((value) => {
|
|
157
|
+
if (!value || typeof value !== "object")
|
|
158
|
+
return [];
|
|
159
|
+
const record = value;
|
|
160
|
+
if (typeof record.text !== "string" || record.text.trim().length === 0)
|
|
161
|
+
return [];
|
|
162
|
+
return [{
|
|
163
|
+
text: record.text.slice(0, AGENT_PLAN_ITEM_TEXT_MAX_CHARS),
|
|
164
|
+
done: record.completed === true || record.done === true,
|
|
165
|
+
...(record.active === true ? { active: true } : {}),
|
|
166
|
+
}];
|
|
167
|
+
});
|
|
168
|
+
}
|
|
46
169
|
function parseSemver(version) {
|
|
47
170
|
const match = version.trim().match(/(\d+)\.(\d+)\.(\d+)/);
|
|
48
171
|
if (!match)
|
|
@@ -304,15 +427,19 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
304
427
|
const resumeThreadId = options.threadId?.trim();
|
|
305
428
|
let server;
|
|
306
429
|
let activeTurnId;
|
|
430
|
+
const responseSeenTurnIds = new Set();
|
|
431
|
+
const completedBeforeResponseTurnIds = new Set();
|
|
307
432
|
let activeTurnSource;
|
|
308
433
|
let activeTurnAcceptingSteer = false;
|
|
309
434
|
let activeThreadId;
|
|
310
435
|
let interruptRequested = false;
|
|
311
436
|
let lastAgentMessage = "";
|
|
312
437
|
let builderDiagnostic;
|
|
438
|
+
let emitTurnStarted;
|
|
313
439
|
const pendingTells = [];
|
|
314
440
|
let drainingTells = false;
|
|
315
441
|
let failActiveTurn;
|
|
442
|
+
let finishAfterTellDrain;
|
|
316
443
|
const rejectPendingTells = (error) => {
|
|
317
444
|
for (const pending of pendingTells.splice(0))
|
|
318
445
|
pending.reject(error);
|
|
@@ -331,6 +458,15 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
331
458
|
}
|
|
332
459
|
return activeTurnId;
|
|
333
460
|
};
|
|
461
|
+
const recordTurnStartResponse = (candidate) => {
|
|
462
|
+
const turnId = coerceString(candidate);
|
|
463
|
+
if (!turnId)
|
|
464
|
+
throw new Error(`${CODEX_APP_SERVER_PROVIDER} response omitted active turn id`);
|
|
465
|
+
if (completedBeforeResponseTurnIds.delete(turnId))
|
|
466
|
+
return turnId;
|
|
467
|
+
responseSeenTurnIds.add(turnId);
|
|
468
|
+
return recordActiveTurnId(turnId, "response");
|
|
469
|
+
};
|
|
334
470
|
appendDebugLog(`startCodexAppServer: executable=${executable} model=${options.model ?? "default"} mode=${resumeThreadId ? "resume" : "fresh"}`, { cwd, section: CODEX_APP_SERVER_PROVIDER });
|
|
335
471
|
const submitSteer = async (tell, turnId) => {
|
|
336
472
|
// turn/steer response {turnId} = enqueue acceptance (submitted), not consumption.
|
|
@@ -346,6 +482,8 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
346
482
|
if (acknowledgedTurnId !== turnId) {
|
|
347
483
|
throw new Error(`${CODEX_APP_SERVER_PROVIDER} turn/steer acknowledgement mismatched active turn: expected=${turnId}, actual=${acknowledgedTurnId}`);
|
|
348
484
|
}
|
|
485
|
+
// Accepted same-native-turn steer opens the next public conversation turn.
|
|
486
|
+
emitTurnStarted?.();
|
|
349
487
|
if (options.onEvidence) {
|
|
350
488
|
emitProviderEvidence(options.onEvidence, {
|
|
351
489
|
type: "ack",
|
|
@@ -361,14 +499,21 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
361
499
|
threadId: activeThreadId,
|
|
362
500
|
input: [{ type: "text", text: tell.text }],
|
|
363
501
|
...(options.model ? { model: options.model } : {}),
|
|
364
|
-
...(tell.effort ? { effort: tell.effort } : {}),
|
|
365
|
-
...(!configOwnsApprovalPolicy(options.config) ? { approvalPolicy: CODEX_APP_SERVER_TURN_APPROVAL_POLICY } : {}),
|
|
366
|
-
...(!configOwnsSandboxPolicy(options.config)
|
|
502
|
+
...(tell.effort ? { effort: toCodexAppServerEffort(tell.effort) } : {}),
|
|
503
|
+
...(!configOwnsApprovalPolicy(options.config) ? { approvalPolicy: options.approvalPolicy ?? CODEX_APP_SERVER_TURN_APPROVAL_POLICY } : {}),
|
|
504
|
+
...(!configOwnsSandboxPolicy(options.config)
|
|
505
|
+
? {
|
|
506
|
+
sandboxPolicy: options.sandboxPolicy ?? buildCodexAppServerWorkspaceWriteSandboxPolicy({
|
|
507
|
+
writableRoots: [cwd],
|
|
508
|
+
networkAccess: false,
|
|
509
|
+
}),
|
|
510
|
+
}
|
|
511
|
+
: {}),
|
|
367
512
|
});
|
|
368
513
|
const startedTurn = started && typeof started === "object"
|
|
369
514
|
? (started.turn ?? undefined)
|
|
370
515
|
: undefined;
|
|
371
|
-
const newTurnId =
|
|
516
|
+
const newTurnId = recordTurnStartResponse(startedTurn?.id);
|
|
372
517
|
if (options.onEvidence)
|
|
373
518
|
emitProviderEvidence(options.onEvidence, { type: "ack", provider: CODEX_APP_SERVER_PROVIDER, fence: { kind: "turn", turnId: newTurnId }, outbound: "run" }, builderDiagnostic);
|
|
374
519
|
return { fence: { kind: "turn", turnId: newTurnId } };
|
|
@@ -400,6 +545,9 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
400
545
|
}
|
|
401
546
|
finally {
|
|
402
547
|
drainingTells = false;
|
|
548
|
+
const finish = finishAfterTellDrain;
|
|
549
|
+
finishAfterTellDrain = undefined;
|
|
550
|
+
finish?.();
|
|
403
551
|
}
|
|
404
552
|
};
|
|
405
553
|
const enqueue = async (tell) => {
|
|
@@ -413,7 +561,9 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
413
561
|
};
|
|
414
562
|
return createProjectionDriver({
|
|
415
563
|
steerMode: "mid-execution",
|
|
564
|
+
initialTurn: options.initialTurn,
|
|
416
565
|
enqueue,
|
|
566
|
+
onIngress: options.onIngress,
|
|
417
567
|
async abort() {
|
|
418
568
|
interruptRequested = true;
|
|
419
569
|
if (server && activeThreadId && activeTurnId) {
|
|
@@ -432,6 +582,7 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
432
582
|
},
|
|
433
583
|
async run(builder) {
|
|
434
584
|
builderDiagnostic = (text) => builder.emit({ type: "diagnostic", text });
|
|
585
|
+
emitTurnStarted = () => builder.emit({ type: "turn", phase: "started" });
|
|
435
586
|
const env = buildSubagentEnv();
|
|
436
587
|
server = new CodexAppServerProcess(executable, env, options.codexHome, options.onEvidence, (text) => builder.emit({ type: "diagnostic", text }));
|
|
437
588
|
const turnCompleted = new Promise((resolve, reject) => {
|
|
@@ -456,58 +607,72 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
456
607
|
failTurn(new Error(message));
|
|
457
608
|
};
|
|
458
609
|
unsubServerRequest = server.onServerRequest((request) => {
|
|
459
|
-
|
|
610
|
+
builder.ingress(CODEX_APP_SERVER_PROVIDER, request.method, request, "mapped", () => {
|
|
611
|
+
failServerRequest(request);
|
|
612
|
+
});
|
|
460
613
|
});
|
|
461
614
|
unsubNotifications = server.onNotification((notification) => {
|
|
462
615
|
try {
|
|
463
|
-
builder.
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
builder.emit({ type: "message", text: lastAgentMessage });
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
if (notification.method === "item/completed") {
|
|
472
|
-
const item = notification.params?.item;
|
|
473
|
-
if (item && (item.type === "agentMessage" || item.type === "agent_message")) {
|
|
474
|
-
const text = coerceString(item.text);
|
|
475
|
-
if (text) {
|
|
476
|
-
lastAgentMessage = text;
|
|
477
|
-
builder.emit({ type: "message", text });
|
|
616
|
+
builder.ingress(CODEX_APP_SERVER_PROVIDER, notification.method, notification, codexAppServerNotificationDisposition(notification.method), () => {
|
|
617
|
+
if (notification.method === "item/agentMessage/delta") {
|
|
618
|
+
const delta = coerceString(notification.params?.delta);
|
|
619
|
+
if (delta) {
|
|
620
|
+
lastAgentMessage = `${lastAgentMessage}${delta}`;
|
|
478
621
|
}
|
|
479
622
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
type
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
623
|
+
if (notification.method === "item/completed") {
|
|
624
|
+
const item = notification.params?.item;
|
|
625
|
+
if (!item) {
|
|
626
|
+
throw new Error(`${CODEX_APP_SERVER_PROVIDER} item/completed lacked required item`);
|
|
627
|
+
}
|
|
628
|
+
const id = coerceString(item.id);
|
|
629
|
+
const itemType = coerceString(item.type);
|
|
630
|
+
if (!id || !itemType) {
|
|
631
|
+
throw new Error(`${CODEX_APP_SERVER_PROVIDER} item/completed lacked required item id or type`);
|
|
632
|
+
}
|
|
633
|
+
if (itemType === "agentMessage") {
|
|
634
|
+
const text = coerceString(item.text);
|
|
635
|
+
if (text) {
|
|
636
|
+
lastAgentMessage = text;
|
|
637
|
+
builder.emit({ type: "message", text });
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
else if (itemType === "reasoning") {
|
|
641
|
+
const text = extractReasoningSummary(item);
|
|
642
|
+
if (text) {
|
|
643
|
+
const truncated = text.length > AGENT_THOUGHT_TEXT_MAX_CHARS;
|
|
644
|
+
builder.emit({
|
|
645
|
+
type: "thought",
|
|
646
|
+
id,
|
|
647
|
+
text: text.slice(0, AGENT_THOUGHT_TEXT_MAX_CHARS),
|
|
648
|
+
final: true,
|
|
649
|
+
...(truncated ? { truncated: true } : {}),
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
else if (itemType === "todo_list" || itemType === "todoList") {
|
|
654
|
+
builder.emit({
|
|
655
|
+
type: "plan",
|
|
656
|
+
id,
|
|
657
|
+
items: extractPlanItems(item),
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
else if (isCodexAppServerActivityItemType(itemType)) {
|
|
661
|
+
builder.emit({
|
|
662
|
+
type: "activity",
|
|
663
|
+
phase: "completed",
|
|
664
|
+
id,
|
|
665
|
+
tool: itemType,
|
|
666
|
+
call: appServerActivityCall(itemType, item),
|
|
667
|
+
result: appServerActivityResult(item),
|
|
668
|
+
});
|
|
669
|
+
}
|
|
493
670
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
if (notification.method === "turn/completed") {
|
|
500
|
-
const turn = notification.params?.turn ?? {};
|
|
501
|
-
const status = coerceString(turn.status) ?? "unknown";
|
|
502
|
-
// Either response or notification may mint the turn fence first;
|
|
503
|
-
// every later native source must agree with it.
|
|
504
|
-
const turnId = recordActiveTurnId(turn.id, "notification");
|
|
505
|
-
// This must stay in the native notification call stack: the harness
|
|
506
|
-
// checkpoint and its observer evidence describe this exact crossing.
|
|
507
|
-
if (status === "completed") {
|
|
508
|
-
activeTurnAcceptingSteer = false;
|
|
509
|
-
activeTurnId = undefined;
|
|
510
|
-
activeTurnSource = undefined;
|
|
671
|
+
if (notification.method === "turn/started") {
|
|
672
|
+
const turn = notification.params?.turn;
|
|
673
|
+
const turnId = recordActiveTurnId(turn?.id, "notification");
|
|
674
|
+
builder.emit({ type: "turn", phase: "started" });
|
|
675
|
+
activeTurnAcceptingSteer = true;
|
|
511
676
|
const checkpoint = { fence: { kind: "turn", turnId } };
|
|
512
677
|
if (options.onEvidence) {
|
|
513
678
|
emitProviderEvidence(options.onEvidence, {
|
|
@@ -517,23 +682,63 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
517
682
|
source: "notification",
|
|
518
683
|
}, builderDiagnostic);
|
|
519
684
|
}
|
|
685
|
+
// turn/start may respond before the server has installed its active
|
|
686
|
+
// turn. The native notification is the first steer-safe boundary.
|
|
520
687
|
options.onSyncCheckpoint?.({ enqueue }, checkpoint);
|
|
521
688
|
void drainPendingTells();
|
|
522
|
-
|
|
523
|
-
|
|
689
|
+
}
|
|
690
|
+
if (notification.method === "turn/completed") {
|
|
691
|
+
const turn = notification.params?.turn ?? {};
|
|
692
|
+
const status = coerceString(turn.status) ?? "unknown";
|
|
693
|
+
// Either response or notification may mint the turn fence first;
|
|
694
|
+
// every later native source must agree with it.
|
|
695
|
+
const turnId = recordActiveTurnId(turn.id, "notification");
|
|
696
|
+
if (!responseSeenTurnIds.delete(turnId)) {
|
|
697
|
+
completedBeforeResponseTurnIds.add(turnId);
|
|
524
698
|
}
|
|
699
|
+
// Public completed only for exact native status completed.
|
|
700
|
+
if (status === "completed") {
|
|
701
|
+
builder.emit({ type: "turn", phase: "completed" });
|
|
702
|
+
// This must stay in the native notification call stack: the harness
|
|
703
|
+
// checkpoint and its observer evidence describe this exact crossing.
|
|
704
|
+
activeTurnAcceptingSteer = false;
|
|
705
|
+
activeTurnId = undefined;
|
|
706
|
+
activeTurnSource = undefined;
|
|
707
|
+
const checkpoint = { fence: { kind: "turn", turnId } };
|
|
708
|
+
if (options.onEvidence) {
|
|
709
|
+
emitProviderEvidence(options.onEvidence, {
|
|
710
|
+
type: "checkpoint",
|
|
711
|
+
provider: CODEX_APP_SERVER_PROVIDER,
|
|
712
|
+
...checkpoint,
|
|
713
|
+
source: "notification",
|
|
714
|
+
}, builderDiagnostic);
|
|
715
|
+
}
|
|
716
|
+
options.onSyncCheckpoint?.({ enqueue }, checkpoint);
|
|
717
|
+
void drainPendingTells();
|
|
718
|
+
if (pendingTells.length > 0 || drainingTells) {
|
|
719
|
+
finishAfterTellDrain = () => {
|
|
720
|
+
if (settled || activeTurnId !== undefined || pendingTells.length > 0)
|
|
721
|
+
return;
|
|
722
|
+
settled = true;
|
|
723
|
+
unsubNotifications();
|
|
724
|
+
unsubServerRequest();
|
|
725
|
+
resolve({ status, turn });
|
|
726
|
+
};
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
if (settled)
|
|
731
|
+
return;
|
|
732
|
+
settled = true;
|
|
733
|
+
unsubNotifications();
|
|
734
|
+
unsubServerRequest();
|
|
735
|
+
resolve({ status, turn });
|
|
525
736
|
}
|
|
526
|
-
if (
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
resolve({ status, turn });
|
|
532
|
-
}
|
|
533
|
-
if (notification.method === "error") {
|
|
534
|
-
const message = coerceString(notification.params?.message) ?? `${CODEX_APP_SERVER_PROVIDER} error`;
|
|
535
|
-
builder.emit({ type: "diagnostic", text: message });
|
|
536
|
-
}
|
|
737
|
+
if (notification.method === "error") {
|
|
738
|
+
const message = coerceString(notification.params?.message) ?? `${CODEX_APP_SERVER_PROVIDER} error`;
|
|
739
|
+
builder.emit({ type: "diagnostic", text: message });
|
|
740
|
+
}
|
|
741
|
+
});
|
|
537
742
|
}
|
|
538
743
|
catch (error) {
|
|
539
744
|
// Notification listeners run outside the driver's await chain;
|
|
@@ -601,13 +806,16 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
601
806
|
threadId: activeThreadId,
|
|
602
807
|
input: [{ type: "text", text: prompt }],
|
|
603
808
|
...(options.model ? { model: options.model } : {}),
|
|
604
|
-
...(options.effort ? { effort: options.effort } : {}),
|
|
809
|
+
...(options.effort ? { effort: toCodexAppServerEffort(options.effort) } : {}),
|
|
605
810
|
};
|
|
606
811
|
if (!configOwnsApprovalPolicy(options.config)) {
|
|
607
|
-
turnStartParams.approvalPolicy = CODEX_APP_SERVER_TURN_APPROVAL_POLICY;
|
|
812
|
+
turnStartParams.approvalPolicy = options.approvalPolicy ?? CODEX_APP_SERVER_TURN_APPROVAL_POLICY;
|
|
608
813
|
}
|
|
609
814
|
if (!configOwnsSandboxPolicy(options.config)) {
|
|
610
|
-
turnStartParams.sandboxPolicy =
|
|
815
|
+
turnStartParams.sandboxPolicy = options.sandboxPolicy ?? buildCodexAppServerWorkspaceWriteSandboxPolicy({
|
|
816
|
+
writableRoots: [cwd],
|
|
817
|
+
networkAccess: false,
|
|
818
|
+
});
|
|
611
819
|
}
|
|
612
820
|
activeTurnId = undefined;
|
|
613
821
|
activeTurnSource = undefined;
|
|
@@ -616,9 +824,9 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
616
824
|
const turn = turnStart && typeof turnStart === "object"
|
|
617
825
|
? (turnStart.turn ?? undefined)
|
|
618
826
|
: undefined;
|
|
619
|
-
|
|
827
|
+
const turnId = recordTurnStartResponse(turn?.id);
|
|
620
828
|
if (options.onEvidence)
|
|
621
|
-
emitProviderEvidence(options.onEvidence, { type: "checkpoint", provider: CODEX_APP_SERVER_PROVIDER, fence: { kind: "turn", turnId
|
|
829
|
+
emitProviderEvidence(options.onEvidence, { type: "checkpoint", provider: CODEX_APP_SERVER_PROVIDER, fence: { kind: "turn", turnId }, source: "response" }, builderDiagnostic);
|
|
622
830
|
const completed = await turnCompleted;
|
|
623
831
|
if (completed.status === "interrupted" || interruptRequested) {
|
|
624
832
|
throw createAbortError(`${CODEX_APP_SERVER_PROVIDER} turn interrupted`);
|