@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
|
@@ -9,37 +9,38 @@ import { startOpencode, opencodeSessionSchema, } from "../providers/opencode-sdk
|
|
|
9
9
|
import { startPi, piSessionSchema, } from "../providers/pi.js";
|
|
10
10
|
import { SubagentFailure, } from "../types.js";
|
|
11
11
|
import { createEventChannel } from "./event-channel.js";
|
|
12
|
+
import { overflowMarkerFromDropped } from "./execution-handle.js";
|
|
12
13
|
import { buildSyncCheckpointCallback, createReplayRunStartGate, markReplayCompleted, pumpSupervisor, snapshotReplayPrompt } from "./pump.js";
|
|
13
14
|
import { createAbortError, renderCapturedText } from "./runtime.js";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
export function
|
|
15
|
+
import { demoteSubmittedTellsForReplay, listTellIds, markTellSubmitted } from "../../core/projection-core.js";
|
|
16
|
+
export { activityEventBodySchema, AGENT_EVENT_TEXT_MAX_CHARS, AGENT_UNKNOWN_PAYLOAD_MAX_CHARS, } from "./events.js";
|
|
17
|
+
export function call(terms) {
|
|
17
18
|
return createProjection(terms);
|
|
18
19
|
}
|
|
19
|
-
export function
|
|
20
|
+
export function revive(terms) {
|
|
20
21
|
return createProjection(terms, terms);
|
|
21
22
|
}
|
|
22
23
|
function mintOutcome(draft) {
|
|
23
24
|
return draft;
|
|
24
25
|
}
|
|
25
|
-
function
|
|
26
|
-
return
|
|
26
|
+
export function restoreOutcome(record) {
|
|
27
|
+
return { ...record };
|
|
27
28
|
}
|
|
28
|
-
function createProjection(terms,
|
|
29
|
+
function createProjection(terms, reviveTerms) {
|
|
29
30
|
switch (terms.provider) {
|
|
30
31
|
case "pi":
|
|
31
32
|
case "claude-agent-sdk":
|
|
32
33
|
case "codex-app-server":
|
|
33
|
-
return createSteerableProjection(terms,
|
|
34
|
+
return createSteerableProjection(terms, reviveTerms);
|
|
34
35
|
case "codex-sdk":
|
|
35
36
|
case "opencode-sdk":
|
|
36
|
-
return createReplayProjection(terms,
|
|
37
|
+
return createReplayProjection(terms, reviveTerms);
|
|
37
38
|
default:
|
|
38
39
|
return assertNever(terms);
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
|
-
function createSteerableProjection(terms,
|
|
42
|
-
const shared = createProjectionState(terms,
|
|
42
|
+
function createSteerableProjection(terms, reviveTerms) {
|
|
43
|
+
const shared = createProjectionState(terms, reviveTerms);
|
|
43
44
|
const pendingTells = [];
|
|
44
45
|
let flushActive = false;
|
|
45
46
|
const flushPendingTells = async () => {
|
|
@@ -69,7 +70,7 @@ function createSteerableProjection(terms, resumeTerms) {
|
|
|
69
70
|
shared.live = live;
|
|
70
71
|
void flushPendingTells();
|
|
71
72
|
};
|
|
72
|
-
const outcome = settleProjection(shared)
|
|
73
|
+
const outcome = settleProjection(shared);
|
|
73
74
|
return {
|
|
74
75
|
mode: "steerable",
|
|
75
76
|
get id() {
|
|
@@ -95,12 +96,12 @@ function createSteerableProjection(terms, resumeTerms) {
|
|
|
95
96
|
},
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
|
-
function createReplayProjection(terms,
|
|
99
|
-
const shared = createProjectionState(terms,
|
|
99
|
+
function createReplayProjection(terms, reviveTerms) {
|
|
100
|
+
const shared = createProjectionState(terms, reviveTerms);
|
|
100
101
|
shared.onLive = (live) => {
|
|
101
102
|
shared.live = live;
|
|
102
103
|
};
|
|
103
|
-
const outcome = settleProjection(shared)
|
|
104
|
+
const outcome = settleProjection(shared);
|
|
104
105
|
return {
|
|
105
106
|
mode: "replay",
|
|
106
107
|
get id() {
|
|
@@ -117,12 +118,14 @@ function createReplayProjection(terms, resumeTerms) {
|
|
|
117
118
|
},
|
|
118
119
|
};
|
|
119
120
|
}
|
|
120
|
-
function createProjectionState(terms,
|
|
121
|
+
function createProjectionState(terms, reviveTerms) {
|
|
121
122
|
const shared = {
|
|
122
123
|
id: randomUUID(),
|
|
123
124
|
terms,
|
|
124
|
-
|
|
125
|
-
publicEvents: createEventChannel(
|
|
125
|
+
reviveTerms,
|
|
126
|
+
publicEvents: createEventChannel({
|
|
127
|
+
createOverflowMarker: overflowMarkerFromDropped,
|
|
128
|
+
}),
|
|
126
129
|
lifecycleAbort: new AbortController(),
|
|
127
130
|
dismissed: false,
|
|
128
131
|
externallyAborted: false,
|
|
@@ -143,37 +146,6 @@ function createProjectionState(terms, resumeTerms) {
|
|
|
143
146
|
}
|
|
144
147
|
return shared;
|
|
145
148
|
}
|
|
146
|
-
function finalizeProjectionLedger(shared, outcome) {
|
|
147
|
-
const directory = shared.terms.projectionDir;
|
|
148
|
-
const executionId = shared.terms.projectionExecutionId;
|
|
149
|
-
if (!directory || !executionId)
|
|
150
|
-
return outcome;
|
|
151
|
-
const now = Date.now();
|
|
152
|
-
publishGenerationResult(directory, {
|
|
153
|
-
version: 1,
|
|
154
|
-
executionId,
|
|
155
|
-
status: outcome.status,
|
|
156
|
-
createdAt: new Date(now).toISOString(),
|
|
157
|
-
session: outcome.session,
|
|
158
|
-
responsePath: generationResultPath(directory, executionId),
|
|
159
|
-
detail: outcome.status === "failed" ? outcome.error?.message : undefined,
|
|
160
|
-
});
|
|
161
|
-
// A stale/duplicate child must never replace a later generation's verdict.
|
|
162
|
-
if (readAdmissionLock(directory)?.executionId !== executionId)
|
|
163
|
-
return outcome;
|
|
164
|
-
const pending = ["inbox", "inflight", "submitted"].some((layer) => listTellIds(directory, layer).length > 0);
|
|
165
|
-
if (pending && outcome.status === "completed") {
|
|
166
|
-
// The resume lock is acquired by the one wake orchestrator before it releases
|
|
167
|
-
// this generation's admission; a crash leaves result-without-done for self-heal.
|
|
168
|
-
wakeProjection(directory, "sweep-wake", { handoffExecutionId: executionId });
|
|
169
|
-
return outcome;
|
|
170
|
-
}
|
|
171
|
-
publishVerdict(directory, outcome.status === "completed" ? "done" : outcome.status === "dismissed" ? "dismissed" : "failed", now, outcome.status === "failed" ? outcome.error?.message : undefined);
|
|
172
|
-
releaseAdmissionLockOwned(directory, executionId);
|
|
173
|
-
if (listTellIds(directory, "inbox").length > 0)
|
|
174
|
-
wakeProjection(directory, "sweep-wake");
|
|
175
|
-
return outcome;
|
|
176
|
-
}
|
|
177
149
|
function dismissProjection(shared) {
|
|
178
150
|
if (shared.dismissed || shared.terminal)
|
|
179
151
|
return;
|
|
@@ -196,14 +168,8 @@ async function settleProjection(shared) {
|
|
|
196
168
|
diagnosticsBuffer: new StringTailBuffer(shared.terms.maxCaptureChars),
|
|
197
169
|
warnings: [],
|
|
198
170
|
};
|
|
199
|
-
let timedOut = false;
|
|
200
171
|
let idleTimedOut = false;
|
|
201
172
|
let abortRequested = false;
|
|
202
|
-
const timeout = setTimeout(() => {
|
|
203
|
-
timedOut = true;
|
|
204
|
-
shared.lifecycleAbort.abort(createAbortError(`${shared.terms.provider} exec timed out`));
|
|
205
|
-
}, shared.terms.timeoutMs);
|
|
206
|
-
timeout.unref?.();
|
|
207
173
|
let idleTimeout;
|
|
208
174
|
const refreshIdleTimeout = () => {
|
|
209
175
|
if (idleTimeout)
|
|
@@ -224,16 +190,12 @@ async function settleProjection(shared) {
|
|
|
224
190
|
shared.lifecycleAbort.signal.addEventListener("abort", requestLiveAbort, { once: true });
|
|
225
191
|
try {
|
|
226
192
|
if (shared.terms.projectionDir) {
|
|
227
|
-
const executionId = shared.terms.projectionExecutionId
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
throw new FlowError("INTERNAL_STATE", "projection already has an active generation");
|
|
231
|
-
touchHeartbeat(shared.terms.projectionDir, Date.now());
|
|
193
|
+
const executionId = shared.terms.projectionExecutionId;
|
|
194
|
+
if (!executionId)
|
|
195
|
+
throw new FlowError("INTERNAL_STATE", "projection execution id is required in supervisor mode");
|
|
232
196
|
demoteSubmittedTellsForReplay(shared.terms.projectionDir, executionId);
|
|
233
197
|
}
|
|
234
|
-
const launchTellFence = shared.terms.
|
|
235
|
-
? readGenerationLaunch(shared.terms.projectionDir, shared.terms.projectionExecutionId).inputs.tellFence
|
|
236
|
-
: undefined;
|
|
198
|
+
const launchTellFence = shared.terms.projectionTellFence;
|
|
237
199
|
const tellFence = launchTellFence === undefined
|
|
238
200
|
? []
|
|
239
201
|
: Array.isArray(launchTellFence) && launchTellFence.every((tellId) => typeof tellId === "string")
|
|
@@ -244,35 +206,41 @@ async function settleProjection(shared) {
|
|
|
244
206
|
: undefined;
|
|
245
207
|
const launchTerms = launchSnapshot
|
|
246
208
|
? shared.terms.provider === "codex-sdk" && launchSnapshot.effort
|
|
247
|
-
? { ...shared.terms, prompt: launchSnapshot.prompt, threadOptions: { ...shared.terms.threadOptions, modelReasoningEffort: launchSnapshot.effort
|
|
209
|
+
? { ...shared.terms, prompt: launchSnapshot.prompt, threadOptions: { ...shared.terms.threadOptions, modelReasoningEffort: launchSnapshot.effort } }
|
|
248
210
|
: { ...shared.terms, prompt: launchSnapshot.prompt }
|
|
249
211
|
: shared.terms;
|
|
250
|
-
const live = await startLiveProjection(launchTerms, shared.lifecycleAbort.signal, shared.resumeTerms, launchSnapshot?.tellIds);
|
|
251
212
|
// A constructed driver is not an SDK run acknowledgement. Tier-2 has no
|
|
252
213
|
// live steer surface, so the first provider event is the earliest harness
|
|
253
214
|
// observable start; a successful no-event completion is the only fallback.
|
|
254
215
|
const replayStartGate = launchSnapshot && shared.terms.provider !== "codex-app-server" && shared.terms.projectionDir && shared.terms.projectionExecutionId
|
|
255
216
|
? createReplayRunStartGate(shared.terms.projectionDir, shared.terms.projectionExecutionId, launchSnapshot.tellIds)
|
|
256
217
|
: undefined;
|
|
218
|
+
const live = await startLiveProjection(launchTerms, shared.lifecycleAbort.signal, shared.reviveTerms, launchSnapshot?.tellIds, refreshIdleTimeout);
|
|
257
219
|
shared.onLive(live);
|
|
258
220
|
if (shared.lifecycleAbort.signal.aborted) {
|
|
259
221
|
requestLiveAbort();
|
|
260
222
|
}
|
|
261
223
|
const projectionDir = shared.terms.projectionDir;
|
|
262
224
|
if (projectionDir) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
225
|
+
const executionId = shared.terms.projectionExecutionId;
|
|
226
|
+
if (!executionId) {
|
|
227
|
+
throw new Error("projection execution id is required in supervisor mode");
|
|
228
|
+
}
|
|
229
|
+
// Supervisor mode: persist events, checkpoint, and claim heart-backed tells.
|
|
230
|
+
await pumpSupervisor(live, projectionDir, executionId, shared.publicEvents, {
|
|
231
|
+
onEvent: (event) => {
|
|
232
|
+
replayStartGate?.observeProviderEvent();
|
|
233
|
+
refreshIdleTimeout();
|
|
234
|
+
processEvent(state, event);
|
|
235
|
+
},
|
|
268
236
|
});
|
|
269
237
|
}
|
|
270
238
|
else {
|
|
271
239
|
// Legacy mode: direct event loop without supervisor pump.
|
|
272
240
|
for await (const event of live.events) {
|
|
273
241
|
replayStartGate?.observeProviderEvent();
|
|
274
|
-
shared.publicEvents.push(event);
|
|
275
242
|
refreshIdleTimeout();
|
|
243
|
+
shared.publicEvents.push(event);
|
|
276
244
|
processEvent(state, event);
|
|
277
245
|
}
|
|
278
246
|
}
|
|
@@ -282,16 +250,16 @@ async function settleProjection(shared) {
|
|
|
282
250
|
return failFromFailEvent(shared, state, state.failEvent);
|
|
283
251
|
}
|
|
284
252
|
if (!completionResult.ok) {
|
|
285
|
-
return classifyFailure(shared, state, completionResult.error,
|
|
253
|
+
return classifyFailure(shared, state, completionResult.error, idleTimedOut);
|
|
286
254
|
}
|
|
287
255
|
if (shared.lifecycleAbort.signal.aborted) {
|
|
288
|
-
return classifyFailure(shared, state, shared.lifecycleAbort.signal.reason,
|
|
256
|
+
return classifyFailure(shared, state, shared.lifecycleAbort.signal.reason, idleTimedOut);
|
|
289
257
|
}
|
|
290
258
|
if (!state.doneEvent && !completionOutcome) {
|
|
291
259
|
return failWithError(shared, state, {
|
|
292
260
|
code: "SUBAGENT_EXEC_ERROR",
|
|
293
261
|
message: `${shared.terms.provider} exec ended before completion`,
|
|
294
|
-
timeoutMs:
|
|
262
|
+
timeoutMs: null,
|
|
295
263
|
exitCode: null,
|
|
296
264
|
}, state.finalMessageCandidate);
|
|
297
265
|
}
|
|
@@ -304,7 +272,7 @@ async function settleProjection(shared) {
|
|
|
304
272
|
return failWithError(shared, state, {
|
|
305
273
|
code: "SUBAGENT_EXEC_ERROR",
|
|
306
274
|
message: `${shared.terms.provider} exec ended without a session handle`,
|
|
307
|
-
timeoutMs:
|
|
275
|
+
timeoutMs: null,
|
|
308
276
|
exitCode: null,
|
|
309
277
|
}, finalMessage);
|
|
310
278
|
}
|
|
@@ -321,17 +289,15 @@ async function settleProjection(shared) {
|
|
|
321
289
|
diagnostics: renderCapturedText(state.diagnosticsBuffer),
|
|
322
290
|
session,
|
|
323
291
|
warnings: [...state.warnings],
|
|
324
|
-
...(effectivePolicyFor(shared) ? { effectivePolicy: effectivePolicyFor(shared) } : {}),
|
|
325
292
|
});
|
|
326
293
|
}
|
|
327
294
|
catch (error) {
|
|
328
295
|
if (error instanceof FlowError) {
|
|
329
296
|
throw error;
|
|
330
297
|
}
|
|
331
|
-
return classifyFailure(shared, state, error,
|
|
298
|
+
return classifyFailure(shared, state, error, idleTimedOut);
|
|
332
299
|
}
|
|
333
300
|
finally {
|
|
334
|
-
clearTimeout(timeout);
|
|
335
301
|
if (idleTimeout)
|
|
336
302
|
clearTimeout(idleTimeout);
|
|
337
303
|
shared.lifecycleAbort.signal.removeEventListener("abort", requestLiveAbort);
|
|
@@ -341,9 +307,6 @@ async function settleProjection(shared) {
|
|
|
341
307
|
}
|
|
342
308
|
function processEvent(state, event) {
|
|
343
309
|
switch (event.type) {
|
|
344
|
-
case "output":
|
|
345
|
-
state.outputBuffer.append(`${JSON.stringify(event.value)}\n`);
|
|
346
|
-
return;
|
|
347
310
|
case "diagnostic":
|
|
348
311
|
state.diagnosticsBuffer.append(event.text);
|
|
349
312
|
return;
|
|
@@ -366,6 +329,14 @@ function processEvent(state, event) {
|
|
|
366
329
|
state.diagnosticsBuffer.append(event.diagnostics);
|
|
367
330
|
}
|
|
368
331
|
return;
|
|
332
|
+
case "activity":
|
|
333
|
+
case "unknown":
|
|
334
|
+
case "turn":
|
|
335
|
+
case "usage":
|
|
336
|
+
case "thought":
|
|
337
|
+
case "plan":
|
|
338
|
+
case "truncation":
|
|
339
|
+
return;
|
|
369
340
|
}
|
|
370
341
|
}
|
|
371
342
|
function failFromFailEvent(shared, state, failEvent) {
|
|
@@ -378,11 +349,11 @@ function failFromFailEvent(shared, state, failEvent) {
|
|
|
378
349
|
return failWithError(shared, state, {
|
|
379
350
|
code,
|
|
380
351
|
message: failEvent.message,
|
|
381
|
-
timeoutMs:
|
|
352
|
+
timeoutMs: null,
|
|
382
353
|
exitCode: failEvent.exitCode ?? null,
|
|
383
354
|
}, state.finalMessageCandidate, failEvent.diagnostics ?? diagnostics);
|
|
384
355
|
}
|
|
385
|
-
function classifyFailure(shared, state, error,
|
|
356
|
+
function classifyFailure(shared, state, error, idleTimedOut) {
|
|
386
357
|
if (shared.dismissed || shared.externallyAborted) {
|
|
387
358
|
return mintOutcome({
|
|
388
359
|
status: "dismissed",
|
|
@@ -391,17 +362,8 @@ function classifyFailure(shared, state, error, timedOut, idleTimedOut) {
|
|
|
391
362
|
diagnostics: renderCapturedText(state.diagnosticsBuffer),
|
|
392
363
|
session: state.session ?? fallbackSession(shared),
|
|
393
364
|
warnings: [...state.warnings],
|
|
394
|
-
...(effectivePolicyFor(shared) ? { effectivePolicy: effectivePolicyFor(shared) } : {}),
|
|
395
365
|
});
|
|
396
366
|
}
|
|
397
|
-
if (timedOut) {
|
|
398
|
-
return failWithError(shared, state, {
|
|
399
|
-
code: "SUBAGENT_TIMEOUT",
|
|
400
|
-
message: `${shared.terms.provider} exec timed out`,
|
|
401
|
-
timeoutMs: shared.terms.timeoutMs,
|
|
402
|
-
exitCode: null,
|
|
403
|
-
}, state.finalMessageCandidate);
|
|
404
|
-
}
|
|
405
367
|
if (idleTimedOut) {
|
|
406
368
|
return failWithError(shared, state, {
|
|
407
369
|
code: "SUBAGENT_TIMEOUT",
|
|
@@ -436,11 +398,10 @@ function failWithError(shared, state, error, finalMessage, diagnostics = renderC
|
|
|
436
398
|
diagnostics,
|
|
437
399
|
session: state.session ?? fallbackSession(shared),
|
|
438
400
|
warnings: [...state.warnings],
|
|
439
|
-
...(effectivePolicyFor(shared) ? { effectivePolicy: effectivePolicyFor(shared) } : {}),
|
|
440
401
|
});
|
|
441
402
|
}
|
|
442
403
|
function fallbackSession(shared) {
|
|
443
|
-
return shared.
|
|
404
|
+
return shared.reviveTerms?.session ?? {
|
|
444
405
|
provider: shared.terms.provider,
|
|
445
406
|
version: SUBAGENT_SESSION_VERSION,
|
|
446
407
|
handle: null,
|
|
@@ -472,8 +433,10 @@ function admitResumeShape(provider, schema, session, resumePath) {
|
|
|
472
433
|
}
|
|
473
434
|
return shapeResult.data;
|
|
474
435
|
}
|
|
475
|
-
async function startLiveProjection(terms, signal,
|
|
476
|
-
const projectionCheckpoint = terms.projectionDir
|
|
436
|
+
async function startLiveProjection(terms, signal, reviveTerms, initialTellIds = [], onIngress) {
|
|
437
|
+
const projectionCheckpoint = terms.projectionDir && terms.projectionExecutionId
|
|
438
|
+
? buildSyncCheckpointCallback(terms.projectionDir, terms.projectionExecutionId)
|
|
439
|
+
: undefined;
|
|
477
440
|
let appServerInitialFencePending = terms.provider === "codex-app-server" && initialTellIds.length > 0;
|
|
478
441
|
const onSyncCheckpoint = terms.projectionDir
|
|
479
442
|
? (control, checkpoint) => {
|
|
@@ -493,8 +456,8 @@ async function startLiveProjection(terms, signal, resumeTerms, initialTellIds =
|
|
|
493
456
|
: undefined;
|
|
494
457
|
switch (terms.provider) {
|
|
495
458
|
case "pi": {
|
|
496
|
-
if (
|
|
497
|
-
const session = admitResumeShape("pi", piSessionSchema,
|
|
459
|
+
if (reviveTerms) {
|
|
460
|
+
const session = admitResumeShape("pi", piSessionSchema, reviveTerms.session, reviveTerms.resumePath);
|
|
498
461
|
return startPi(terms.prompt, terms.workdir, {
|
|
499
462
|
model: terms.model,
|
|
500
463
|
thinkingLevel: terms.thinkingLevel,
|
|
@@ -503,6 +466,8 @@ async function startLiveProjection(terms, signal, resumeTerms, initialTellIds =
|
|
|
503
466
|
appendSystemPromptOverride: terms.appendSystemPromptOverride,
|
|
504
467
|
onSyncCheckpoint,
|
|
505
468
|
onEvidence: terms.onEvidence,
|
|
469
|
+
onIngress,
|
|
470
|
+
initialTurn: terms.initialTurn,
|
|
506
471
|
});
|
|
507
472
|
}
|
|
508
473
|
return startPi(terms.prompt, terms.workdir, {
|
|
@@ -512,44 +477,45 @@ async function startLiveProjection(terms, signal, resumeTerms, initialTellIds =
|
|
|
512
477
|
appendSystemPromptOverride: terms.appendSystemPromptOverride,
|
|
513
478
|
onSyncCheckpoint,
|
|
514
479
|
onEvidence: terms.onEvidence,
|
|
480
|
+
onIngress,
|
|
481
|
+
initialTurn: terms.initialTurn,
|
|
515
482
|
});
|
|
516
483
|
}
|
|
517
484
|
case "claude-agent-sdk": {
|
|
518
|
-
|
|
519
|
-
const session = admitResumeShape("claude-agent-sdk", claudeSessionSchema, resumeTerms.session, resumeTerms.resumePath);
|
|
520
|
-
return startClaudeAgentSdk(terms.prompt, terms.workdir, {
|
|
521
|
-
model: terms.model,
|
|
522
|
-
executable: terms.executable,
|
|
523
|
-
effort: terms.effort,
|
|
524
|
-
signal,
|
|
525
|
-
permissionMode: terms.permissionMode,
|
|
526
|
-
settingSources: terms.settingSources,
|
|
527
|
-
systemPrompt: terms.systemPrompt,
|
|
528
|
-
sessionId: session.sessionId,
|
|
529
|
-
onSyncCheckpoint,
|
|
530
|
-
onEvidence: terms.onEvidence,
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
return startClaudeAgentSdk(terms.prompt, terms.workdir, {
|
|
485
|
+
const claudeOptions = {
|
|
534
486
|
model: terms.model,
|
|
535
487
|
executable: terms.executable,
|
|
536
488
|
effort: terms.effort,
|
|
537
489
|
signal,
|
|
538
490
|
permissionMode: terms.permissionMode,
|
|
539
491
|
settingSources: terms.settingSources,
|
|
492
|
+
allowDangerouslySkipPermissions: terms.allowDangerouslySkipPermissions,
|
|
493
|
+
disallowedTools: terms.disallowedTools,
|
|
540
494
|
systemPrompt: terms.systemPrompt,
|
|
541
495
|
onSyncCheckpoint,
|
|
542
496
|
onEvidence: terms.onEvidence,
|
|
543
|
-
|
|
497
|
+
onIngress,
|
|
498
|
+
initialTurn: terms.initialTurn,
|
|
499
|
+
};
|
|
500
|
+
if (reviveTerms) {
|
|
501
|
+
const session = admitResumeShape("claude-agent-sdk", claudeSessionSchema, reviveTerms.session, reviveTerms.resumePath);
|
|
502
|
+
return startClaudeAgentSdk(terms.prompt, terms.workdir, {
|
|
503
|
+
...claudeOptions,
|
|
504
|
+
sessionId: session.sessionId,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
return startClaudeAgentSdk(terms.prompt, terms.workdir, claudeOptions);
|
|
544
508
|
}
|
|
545
509
|
case "codex-app-server": {
|
|
546
|
-
if (
|
|
547
|
-
const session = admitResumeShape("codex-app-server", codexAppServerSessionSchema,
|
|
510
|
+
if (reviveTerms) {
|
|
511
|
+
const session = admitResumeShape("codex-app-server", codexAppServerSessionSchema, reviveTerms.session, reviveTerms.resumePath);
|
|
548
512
|
return startCodexAppServer(terms.prompt, terms.workdir, {
|
|
549
513
|
model: terms.model,
|
|
550
514
|
effort: terms.effort,
|
|
551
515
|
profile: terms.profile,
|
|
552
516
|
config: terms.config,
|
|
517
|
+
sandboxPolicy: terms.sandboxPolicy,
|
|
518
|
+
approvalPolicy: terms.approvalPolicy,
|
|
553
519
|
executable: terms.executable,
|
|
554
520
|
signal,
|
|
555
521
|
threadId: session.threadId,
|
|
@@ -557,6 +523,8 @@ async function startLiveProjection(terms, signal, resumeTerms, initialTellIds =
|
|
|
557
523
|
developerInstructions: terms.developerInstructions,
|
|
558
524
|
onSyncCheckpoint,
|
|
559
525
|
onEvidence: terms.onEvidence,
|
|
526
|
+
onIngress,
|
|
527
|
+
initialTurn: terms.initialTurn,
|
|
560
528
|
});
|
|
561
529
|
}
|
|
562
530
|
return startCodexAppServer(terms.prompt, terms.workdir, {
|
|
@@ -564,16 +532,20 @@ async function startLiveProjection(terms, signal, resumeTerms, initialTellIds =
|
|
|
564
532
|
effort: terms.effort,
|
|
565
533
|
profile: terms.profile,
|
|
566
534
|
config: terms.config,
|
|
535
|
+
sandboxPolicy: terms.sandboxPolicy,
|
|
536
|
+
approvalPolicy: terms.approvalPolicy,
|
|
567
537
|
executable: terms.executable,
|
|
568
538
|
signal,
|
|
569
539
|
developerInstructions: terms.developerInstructions,
|
|
570
540
|
onSyncCheckpoint,
|
|
571
541
|
onEvidence: terms.onEvidence,
|
|
542
|
+
onIngress,
|
|
543
|
+
initialTurn: terms.initialTurn,
|
|
572
544
|
});
|
|
573
545
|
}
|
|
574
546
|
case "codex-sdk": {
|
|
575
|
-
if (
|
|
576
|
-
const session = admitResumeShape("codex-sdk", codexThreadSchema,
|
|
547
|
+
if (reviveTerms) {
|
|
548
|
+
const session = admitResumeShape("codex-sdk", codexThreadSchema, reviveTerms.session, reviveTerms.resumePath);
|
|
577
549
|
return startCodexSdk(terms.prompt, terms.workdir, {
|
|
578
550
|
model: terms.model,
|
|
579
551
|
profile: terms.profile,
|
|
@@ -583,6 +555,8 @@ async function startLiveProjection(terms, signal, resumeTerms, initialTellIds =
|
|
|
583
555
|
signal,
|
|
584
556
|
threadId: session.threadId,
|
|
585
557
|
onEvidence: terms.onEvidence,
|
|
558
|
+
onIngress,
|
|
559
|
+
initialTurn: terms.initialTurn,
|
|
586
560
|
});
|
|
587
561
|
}
|
|
588
562
|
return startCodexSdk(terms.prompt, terms.workdir, {
|
|
@@ -593,24 +567,32 @@ async function startLiveProjection(terms, signal, resumeTerms, initialTellIds =
|
|
|
593
567
|
executable: terms.executable,
|
|
594
568
|
signal,
|
|
595
569
|
onEvidence: terms.onEvidence,
|
|
570
|
+
onIngress,
|
|
571
|
+
initialTurn: terms.initialTurn,
|
|
596
572
|
});
|
|
597
573
|
}
|
|
598
574
|
case "opencode-sdk": {
|
|
599
|
-
if (
|
|
600
|
-
const session = admitResumeShape("opencode-sdk", opencodeSessionSchema,
|
|
575
|
+
if (reviveTerms) {
|
|
576
|
+
const session = admitResumeShape("opencode-sdk", opencodeSessionSchema, reviveTerms.session, reviveTerms.resumePath);
|
|
601
577
|
return startOpencode(terms.prompt, terms.workdir, {
|
|
602
578
|
model: terms.model,
|
|
579
|
+
effort: terms.effort,
|
|
603
580
|
executable: terms.executable,
|
|
604
581
|
signal,
|
|
605
582
|
sessionId: session.sessionId,
|
|
606
583
|
onEvidence: terms.onEvidence,
|
|
584
|
+
onIngress,
|
|
585
|
+
initialTurn: terms.initialTurn,
|
|
607
586
|
});
|
|
608
587
|
}
|
|
609
588
|
return startOpencode(terms.prompt, terms.workdir, {
|
|
610
589
|
model: terms.model,
|
|
590
|
+
effort: terms.effort,
|
|
611
591
|
executable: terms.executable,
|
|
612
592
|
signal,
|
|
613
593
|
onEvidence: terms.onEvidence,
|
|
594
|
+
onIngress,
|
|
595
|
+
initialTurn: terms.initialTurn,
|
|
614
596
|
});
|
|
615
597
|
}
|
|
616
598
|
default:
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { claimAllInbox, claimFencedTells, listTellIds, markTellSubmitted, markTellConsumed, readTellSubmitted, readTellOriginal, readAdmissionLock, isTellCausallyConsumed, touchHeartbeat as touchHeartbeatFile, } from "../../core/projection-core.js";
|
|
1
|
+
import { claimAllInbox, claimFencedTells, listTellIds, markTellSubmitted, markTellConsumed, readTellSubmitted, readTellOriginal, isTellCausallyConsumed, appendGenerationEvent, } from "../../core/projection-core.js";
|
|
2
|
+
import { prepareAgentEventForPersistence, } from "./execution-handle.js";
|
|
4
3
|
/** Tier-2 boundary snapshot. No tells leaves prompt byte-identical. */
|
|
5
4
|
export function snapshotReplayPrompt(projectionDirectory, prompt, tellFence, executionId) {
|
|
6
5
|
const tellIds = claimFencedTells(projectionDirectory, tellFence, executionId);
|
|
@@ -43,79 +42,73 @@ export function createReplayRunStartGate(projectionDirectory, executionId, tellI
|
|
|
43
42
|
};
|
|
44
43
|
return { observeProviderEvent: start, observeSuccessfulCompletion: start };
|
|
45
44
|
}
|
|
46
|
-
/** Heartbeat throttle: no more than one utimes call per 5000ms. */
|
|
47
|
-
export const HEARTBEAT_MIN_INTERVAL_MS = 5_000;
|
|
48
45
|
/**
|
|
49
46
|
* Supervisor pump: iterates handle.events, forwards to publicChannel,
|
|
50
|
-
*
|
|
51
|
-
* and on final sweep publishes verdict.
|
|
47
|
+
* persists public events and checks the tell ledger at checkpoints.
|
|
52
48
|
*/
|
|
53
|
-
export async function pumpSupervisor(handle, projectionDirectory, publicChannel,
|
|
54
|
-
let
|
|
55
|
-
let
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
49
|
+
export async function pumpSupervisor(handle, projectionDirectory, executionId, publicChannel, callbacks = {}, dependencies = {}) {
|
|
50
|
+
let persistenceEnabled = true;
|
|
51
|
+
let persistenceDiagnosticQueued = false;
|
|
52
|
+
const pendingDiagnostics = [];
|
|
53
|
+
const appendEvent = dependencies.appendGenerationEvent ?? appendGenerationEvent;
|
|
54
|
+
const dispatch = (event, persist = true) => {
|
|
55
|
+
if (persist && persistenceEnabled) {
|
|
56
|
+
try {
|
|
57
|
+
appendEvent(projectionDirectory, executionId, prepareAgentEventForPersistence(event));
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
persistenceEnabled = false;
|
|
61
|
+
if (!persistenceDiagnosticQueued) {
|
|
62
|
+
persistenceDiagnosticQueued = true;
|
|
63
|
+
pendingDiagnostics.push({
|
|
64
|
+
text: `event persistence degraded: ${String(error)}`,
|
|
65
|
+
persist: false,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
71
68
|
}
|
|
72
|
-
heartbeatDegraded = true;
|
|
73
69
|
}
|
|
70
|
+
publicChannel.push(event);
|
|
71
|
+
callbacks.onEvent?.(event);
|
|
74
72
|
};
|
|
75
|
-
const heartbeatTimer = setInterval(heartbeat, HEARTBEAT_MIN_INTERVAL_MS);
|
|
76
|
-
const stopHeartbeatTimer = () => clearInterval(heartbeatTimer);
|
|
77
73
|
try {
|
|
78
74
|
for await (const event of handle.events) {
|
|
79
|
-
|
|
80
|
-
onEvent?.(event);
|
|
81
|
-
heartbeat();
|
|
82
|
-
if (event.type === "done" || event.type === "fail")
|
|
83
|
-
stopHeartbeatTimer();
|
|
75
|
+
dispatch(event);
|
|
84
76
|
}
|
|
85
77
|
}
|
|
86
78
|
catch (error) {
|
|
87
79
|
if (error instanceof Error && error.code === "PROJECTION_STATE_ERROR") {
|
|
88
|
-
|
|
80
|
+
const event = handle.mintEvent({
|
|
89
81
|
type: "fail",
|
|
90
82
|
code: "PROJECTION_STATE_ERROR",
|
|
91
83
|
message: error.message,
|
|
92
84
|
});
|
|
85
|
+
if (event)
|
|
86
|
+
dispatch(event);
|
|
93
87
|
}
|
|
94
88
|
else {
|
|
95
|
-
|
|
89
|
+
const event = handle.mintEvent({
|
|
96
90
|
type: "diagnostic",
|
|
97
91
|
text: `pump error: ${String(error)}`,
|
|
98
92
|
});
|
|
93
|
+
if (event)
|
|
94
|
+
dispatch(event);
|
|
99
95
|
}
|
|
100
96
|
}
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
for (const pending of pendingDiagnostics) {
|
|
98
|
+
const event = handle.mintEvent({ type: "diagnostic", text: pending.text });
|
|
99
|
+
if (event)
|
|
100
|
+
dispatch(event, pending.persist);
|
|
103
101
|
}
|
|
104
102
|
}
|
|
105
|
-
function readTellOriginalText(projectionDirPath, tellId, layer = "inflight") {
|
|
106
|
-
const content = JSON.parse(fs.readFileSync(path.join(projectionDirPath, layer, tellId), "utf8"));
|
|
107
|
-
return content.text;
|
|
108
|
-
}
|
|
109
103
|
/**
|
|
110
104
|
* Build an onSyncCheckpoint callback that claims all inbox tells
|
|
111
105
|
* and delivers them via the given SteerControl.
|
|
112
106
|
* Intended for use inside adapter start() calls as the onSyncCheckpoint callback.
|
|
113
107
|
*/
|
|
114
|
-
export function buildSyncCheckpointCallback(projectionDirectory) {
|
|
108
|
+
export function buildSyncCheckpointCallback(projectionDirectory, executionId) {
|
|
115
109
|
const submitting = new Set();
|
|
116
110
|
return (control, checkpoint) => {
|
|
117
111
|
claimAllInbox(projectionDirectory);
|
|
118
|
-
const executionId = readAdmissionLock(projectionDirectory)?.executionId;
|
|
119
112
|
for (const tellId of listTellIds(projectionDirectory, "inflight")) {
|
|
120
113
|
if (submitting.has(tellId))
|
|
121
114
|
continue;
|
|
@@ -129,8 +122,6 @@ export function buildSyncCheckpointCallback(projectionDirectory) {
|
|
|
129
122
|
};
|
|
130
123
|
void control.enqueue(tell)
|
|
131
124
|
.then((ack) => {
|
|
132
|
-
if (!executionId)
|
|
133
|
-
throw new Error("projection checkpoint has no execution admission");
|
|
134
125
|
if (!ack)
|
|
135
126
|
throw new Error("provider enqueue resolved without TellSubmitAck");
|
|
136
127
|
markTellSubmitted(projectionDirectory, tellId, { executionId, fence: ack.fence });
|
|
@@ -140,8 +131,6 @@ export function buildSyncCheckpointCallback(projectionDirectory) {
|
|
|
140
131
|
})
|
|
141
132
|
.finally(() => submitting.delete(tellId));
|
|
142
133
|
}
|
|
143
|
-
if (!executionId)
|
|
144
|
-
return;
|
|
145
134
|
for (const tellId of listTellIds(projectionDirectory, "submitted")) {
|
|
146
135
|
const submitted = readTellSubmitted(projectionDirectory, tellId);
|
|
147
136
|
if (submitted.executionId === executionId && submitted.fence && isTellCausallyConsumed(submitted.fence, checkpoint.fence)) {
|
|
@@ -38,6 +38,9 @@ export function createAbortError(message) {
|
|
|
38
38
|
error.name = "AbortError";
|
|
39
39
|
return error;
|
|
40
40
|
}
|
|
41
|
+
export function coerceString(value) {
|
|
42
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
43
|
+
}
|
|
41
44
|
export function renderTruncationSuffix(truncatedChars) {
|
|
42
45
|
if (truncatedChars <= 0)
|
|
43
46
|
return "";
|