@astrosheep/keiyaku 2.8.4 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -15
- package/build/.tsbuildinfo +1 -1
- package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
- package/build/agents/harness/control-types.js +1 -0
- package/build/agents/harness/execution-handle.js +23 -3
- package/build/agents/harness/index.js +6 -607
- package/build/agents/harness/outcome.js +141 -0
- package/build/agents/harness/projection.js +310 -0
- package/build/agents/harness/router.js +201 -0
- package/build/agents/harness/runtime.js +2 -1
- package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
- package/build/agents/launch-snapshot/resolve.js +72 -0
- package/build/agents/opencode-sdk.js +24 -3
- package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
- package/build/agents/providers/claude-agent-sdk/events.js +218 -0
- package/build/agents/providers/claude-agent-sdk/session.js +158 -0
- package/build/agents/providers/codex-app-server/adapter.js +347 -0
- package/build/agents/providers/codex-app-server/events.js +352 -0
- package/build/agents/providers/codex-app-server/session.js +266 -0
- package/build/agents/providers/codex-sdk.js +23 -5
- package/build/agents/providers/opencode-sdk/adapter.js +344 -0
- package/build/agents/providers/opencode-sdk/events.js +354 -0
- package/build/agents/providers/opencode-sdk/session.js +180 -0
- package/build/agents/providers/pi/adapter.js +269 -0
- package/build/agents/providers/pi/checkpoint.js +41 -0
- package/build/agents/providers/pi/events.js +282 -0
- package/build/agents/{selector_v2.js → selector.js} +8 -6
- package/build/cli/commands/akuma/akuma/handler.js +4 -0
- package/build/cli/commands/akuma/akuma/meta.js +16 -0
- package/build/cli/commands/akuma/catalog.js +8 -0
- package/build/cli/commands/akuma/list/handler.js +15 -0
- package/build/cli/commands/akuma/list/meta-ls.js +9 -0
- package/build/cli/commands/akuma/view/handler.js +34 -0
- package/build/cli/commands/akuma/view/meta.js +8 -0
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +10 -0
- package/build/cli/commands/contract/amend/meta.js +12 -0
- package/build/cli/commands/contract/arc/handler.js +9 -0
- package/build/cli/commands/contract/arc/meta.js +26 -0
- package/build/cli/commands/contract/bind/handler.js +23 -0
- package/build/cli/commands/contract/bind/meta.js +30 -0
- package/build/cli/commands/contract/catalog.js +16 -0
- package/build/cli/commands/contract/forfeit/handler.js +13 -0
- package/build/cli/commands/contract/forfeit/meta.js +12 -0
- package/build/cli/commands/contract/log/handler.js +12 -0
- package/build/cli/commands/contract/log/meta.js +12 -0
- package/build/cli/commands/contract/petition/handler.js +26 -0
- package/build/cli/commands/contract/petition/meta.js +23 -0
- package/build/cli/commands/contract/renew/handler.js +10 -0
- package/build/cli/commands/contract/renew/meta.js +17 -0
- package/build/cli/commands/projection/call/handler.js +39 -0
- package/build/cli/commands/projection/call/meta.js +9 -0
- package/build/cli/commands/projection/catalog.js +14 -0
- package/build/cli/commands/projection/kill/handler.js +35 -0
- package/build/cli/commands/projection/kill/meta.js +11 -0
- package/build/cli/commands/projection/revive/handler.js +53 -0
- package/build/cli/commands/projection/revive/meta.js +9 -0
- package/build/cli/commands/projection/status/handler.js +23 -0
- package/build/cli/commands/projection/status/meta.js +9 -0
- package/build/cli/commands/projection/tell/handler.js +34 -0
- package/build/cli/commands/projection/tell/meta.js +9 -0
- package/build/cli/commands/projection/wait/handler.js +21 -0
- package/build/cli/commands/projection/wait/meta.js +11 -0
- package/build/cli/commands/registry.js +100 -0
- package/build/cli/commands/shared.js +71 -0
- package/build/cli/commands/skills/catalog.js +6 -0
- package/build/cli/commands/skills/install/handler.js +10 -0
- package/build/cli/commands/skills/install/meta.js +9 -0
- package/build/cli/commands/skills/skills/handler.js +4 -0
- package/build/cli/commands/skills/skills/meta.js +10 -0
- package/build/cli/commands/system/catalog.js +8 -0
- package/build/cli/commands/system/completion/handler.js +10 -0
- package/build/cli/commands/system/completion/meta.js +9 -0
- package/build/cli/commands/system/dump-env/handler.js +3 -0
- package/build/cli/commands/system/dump-env/meta.js +10 -0
- package/build/cli/commands/system/guide/handler.js +4 -0
- package/build/cli/commands/system/guide/meta.js +9 -0
- package/build/cli/commands/task/add/handler.js +21 -0
- package/build/cli/commands/task/add/meta.js +8 -0
- package/build/cli/commands/task/catalog.js +22 -0
- package/build/cli/commands/task/doctor/handler.js +4 -0
- package/build/cli/commands/task/doctor/meta.js +8 -0
- package/build/cli/commands/task/done/handler.js +17 -0
- package/build/cli/commands/task/done/meta.js +8 -0
- package/build/cli/commands/task/drop/handler.js +6 -0
- package/build/cli/commands/task/drop/meta.js +8 -0
- package/build/cli/commands/task/ls/handler.js +13 -0
- package/build/cli/commands/task/ls/meta.js +8 -0
- package/build/cli/commands/task/shared.js +131 -0
- package/build/cli/commands/task/start/handler.js +6 -0
- package/build/cli/commands/task/start/meta.js +8 -0
- package/build/cli/commands/task/stop/handler.js +17 -0
- package/build/cli/commands/task/stop/meta.js +8 -0
- package/build/cli/commands/task/task/handler.js +5 -0
- package/build/cli/commands/task/task/meta.js +11 -0
- package/build/cli/commands/task/update/handler.js +18 -0
- package/build/cli/commands/task/update/meta.js +8 -0
- package/build/cli/commands/task/view/handler.js +14 -0
- package/build/cli/commands/task/view/meta.js +8 -0
- package/build/cli/completion.js +26 -27
- package/build/cli/flags.js +79 -2
- package/build/cli/help.js +27 -49
- package/build/cli/index.js +121 -374
- package/build/cli/output-stream-error-policy.js +17 -0
- package/build/cli/parse.js +159 -72
- package/build/cli/projection-address.js +5 -0
- package/build/cli/render/arc.js +1 -1
- package/build/cli/render/errors.js +4 -3
- package/build/cli/render/format.js +14 -0
- package/build/cli/render/kanshi.js +106 -0
- package/build/cli/render/petition.js +24 -1
- package/build/cli/render/projection-activity.js +5 -1
- package/build/cli/render/shared.js +2 -2
- package/build/cli/render/status.js +79 -13
- package/build/cli/render/task.js +113 -0
- package/build/cli/render/wait.js +23 -3
- package/build/cli/types.js +1 -1
- package/build/config/{akuma-loader_v2.js → akuma-loader.js} +2 -2
- package/build/config/env.js +9 -4
- package/build/config/settings/disease.js +26 -0
- package/build/config/settings/knobs.js +8 -0
- package/build/config/settings/loader.js +244 -0
- package/build/config/settings/schema.js +276 -0
- package/build/core/addressing.js +1 -1
- package/build/core/amend.js +3 -3
- package/build/core/arc.js +5 -4
- package/build/core/bind-workspace.js +123 -0
- package/build/core/bind.js +75 -155
- package/build/core/call/call.js +224 -0
- package/build/core/call/context.js +238 -0
- package/build/core/call/execution.js +217 -0
- package/build/core/call/prompt.js +42 -0
- package/build/core/call/reference.js +24 -0
- package/build/core/call-persist.js +1 -1
- package/build/core/claim-delivery.js +247 -0
- package/build/core/claim.js +39 -277
- package/build/core/context.js +2 -1
- package/build/core/{render.js → contract-view.js} +12 -140
- package/build/core/draft.js +107 -9
- package/build/core/entry.js +9 -1
- package/build/core/execution-coordinate.js +4 -20
- package/build/core/execution-pact.js +16 -31
- package/build/core/forfeit.js +35 -22
- package/build/core/hints.js +2 -2
- package/build/core/log.js +2 -2
- package/build/core/petition-claim-gates.js +8 -6
- package/build/core/petition-preview.js +97 -0
- package/build/core/petition-run.js +3 -2
- package/build/core/petition.js +39 -26
- package/build/core/projection/generation/database.js +306 -0
- package/build/core/projection/generation/identity.js +84 -0
- package/build/core/projection/generation/model.js +201 -0
- package/build/core/projection/generation/store.js +73 -0
- package/build/core/projection/generation/transitions.js +258 -0
- package/build/core/projection/heart.js +0 -307
- package/build/core/projection/tell/database.js +109 -0
- package/build/core/projection/tell/model.js +97 -0
- package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
- package/build/core/projection-activity.js +23 -2
- package/build/core/projection-core.js +2 -1
- package/build/core/projection-execution-observer.js +259 -0
- package/build/core/projection-generation-continuation.js +1 -1
- package/build/core/projection-generation-execution.js +90 -20
- package/build/core/projection-generation-launcher.js +1 -1
- package/build/core/projection-generation-runner.js +198 -4
- package/build/core/projection-identity.js +1 -1
- package/build/core/projection-kill.js +50 -17
- package/build/core/projection-life-observer.js +1 -1
- package/build/core/projection-life-protocol.js +10 -0
- package/build/core/projection-mint.js +1 -1
- package/build/core/projection-status.js +45 -32
- package/build/core/projection-wait.js +12 -2
- package/build/core/projection-wake.js +5 -2
- package/build/core/{queue_v2.js → queue.js} +2 -1
- package/build/core/registry.js +1 -1
- package/build/core/renew.js +7 -7
- package/build/core/response-artifact-catalog-sqlite.js +112 -0
- package/build/core/response-artifact-catalog.js +7 -0
- package/build/core/seal.js +44 -16
- package/build/core/status/board.js +286 -0
- package/build/core/status/drift.js +99 -0
- package/build/core/status/lifecycle.js +84 -0
- package/build/core/status/reconciliation.js +131 -0
- package/build/core/stored-agent-event.js +28 -4
- package/build/core/target-ref.js +10 -0
- package/build/core/task/board.js +175 -0
- package/build/core/task/commands.js +211 -0
- package/build/core/task/document.js +189 -0
- package/build/core/task/model.js +1 -0
- package/build/core/task/settlement-git.js +207 -0
- package/build/core/task/settlement-policy.js +82 -0
- package/build/core/task/source-board.js +84 -0
- package/build/core/task/source-model.js +1 -0
- package/build/core/task/validation.js +44 -0
- package/build/core/task-contract.js +224 -0
- package/build/core/task-doctor.js +14 -0
- package/build/core/task-git-actor.js +38 -0
- package/build/core/task-git-runtime.js +34 -0
- package/build/core/task-git-store.js +375 -0
- package/build/core/task-repository.js +1 -0
- package/build/core/task-store-repository.js +86 -0
- package/build/core/task-store.js +1 -0
- package/build/core/task-worktree.js +51 -0
- package/build/core/task.js +4 -0
- package/build/core/transcripts.js +138 -56
- package/build/core/validation.js +17 -0
- package/build/core/verdict.js +2 -2
- package/build/core/worktree-path.js +24 -6
- package/build/flow-error.js +3 -2
- package/build/generated/version.js +1 -1
- package/build/git/commits.js +3 -0
- package/build/git/diff/parsers.js +0 -94
- package/build/index.js +2 -0
- package/build/keiyaku-constants.js +2 -0
- package/build/keiyaku.js +4 -3
- package/package.json +3 -2
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +11 -6
- package/build/agents/harness/pump.js +0 -158
- package/build/agents/providers/codex-app-server.js +0 -864
- package/build/agents/providers/opencode-sdk.js +0 -363
- package/build/agents/providers/pi.js +0 -557
- package/build/config/settings.js +0 -533
- package/build/core/call.js +0 -686
- package/build/core/projection/generation.js +0 -412
- package/build/core/projection/identity.js +0 -81
- package/build/core/projection/mint.js +0 -174
- package/build/core/projection-generation-store.js +0 -707
- package/build/core/status.js +0 -539
|
@@ -9,6 +9,15 @@ function duration(first, last) {
|
|
|
9
9
|
return Math.max(0, last - first);
|
|
10
10
|
}
|
|
11
11
|
function warningIdentity(warning) {
|
|
12
|
+
if (warning.reason === "retry") {
|
|
13
|
+
return JSON.stringify({
|
|
14
|
+
reason: warning.reason,
|
|
15
|
+
attempt: warning.attempt,
|
|
16
|
+
maxRetries: warning.maxRetries,
|
|
17
|
+
retryDelayMs: warning.retryDelayMs,
|
|
18
|
+
errorStatus: warning.errorStatus,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
12
21
|
return JSON.stringify({
|
|
13
22
|
reason: warning.reason,
|
|
14
23
|
originalModel: warning.originalModel,
|
|
@@ -37,6 +46,7 @@ export function foldAgentActivity(events) {
|
|
|
37
46
|
const latestThought = new Map();
|
|
38
47
|
const firstThoughtAt = new Map();
|
|
39
48
|
const thoughtEventCount = new Map();
|
|
49
|
+
const latestMessage = new Map();
|
|
40
50
|
const warnings = new Map();
|
|
41
51
|
const usageByTurn = new Map();
|
|
42
52
|
const turns = [];
|
|
@@ -46,6 +56,9 @@ export function foldAgentActivity(events) {
|
|
|
46
56
|
for (const indexed of sorted) {
|
|
47
57
|
const event = indexed.event;
|
|
48
58
|
switch (event.type) {
|
|
59
|
+
case "message":
|
|
60
|
+
latestMessage.set(JSON.stringify([event.turn, event.id]), indexed);
|
|
61
|
+
break;
|
|
49
62
|
case "activity": {
|
|
50
63
|
latestActivity.set(event.id, indexed);
|
|
51
64
|
if (event.phase !== "updated" && !firstActivityCall.has(event.id))
|
|
@@ -96,8 +109,16 @@ export function foldAgentActivity(events) {
|
|
|
96
109
|
const ledgerActivities = [];
|
|
97
110
|
for (const indexed of sorted) {
|
|
98
111
|
const event = indexed.event;
|
|
99
|
-
if (event.type === "message") {
|
|
100
|
-
settled.push({
|
|
112
|
+
if (event.type === "message" && latestMessage.get(JSON.stringify([event.turn, event.id])) === indexed) {
|
|
113
|
+
settled.push({
|
|
114
|
+
kind: "said",
|
|
115
|
+
order: indexed.order,
|
|
116
|
+
at: event.at,
|
|
117
|
+
turn: event.turn,
|
|
118
|
+
id: event.id,
|
|
119
|
+
text: event.text,
|
|
120
|
+
settled: true,
|
|
121
|
+
});
|
|
101
122
|
continue;
|
|
102
123
|
}
|
|
103
124
|
if (event.type === "activity" && latestActivity.get(event.id) === indexed) {
|
|
@@ -4,7 +4,8 @@ import { isErrnoException } from "../errno.js";
|
|
|
4
4
|
import { projectionCoordinateRoot } from "./projection-coordinate.js";
|
|
5
5
|
import { ProjectionStateError, } from "./atomic-publish.js";
|
|
6
6
|
export { atomicPublishFile, ProjectionStateError, randomHex8 } from "./atomic-publish.js";
|
|
7
|
-
export {
|
|
7
|
+
export { isTellCausallyConsumed, } from "./projection/tell/model.js";
|
|
8
|
+
export { claimAllInbox, claimFencedTells, claimTellToInflight, demoteSubmittedTellsForReplay, listTellIds, markTellConsumed, markTellSubmitted, readTellOriginal, readTellSubmitted, snapshotPendingTells, writeInboxTell, } from "./projection/tell/store.js";
|
|
8
9
|
/** Relative segments for `.keiyaku/projection`. */
|
|
9
10
|
export const PROJECTION_ROOT_SEGMENTS = [".keiyaku", "projection"];
|
|
10
11
|
export const PROJECTION_ID_PATTERN = /^[a-zA-Z0-9]+(?:[.-][a-zA-Z0-9]+)*\/[0-9a-f]{8}$/;
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { claimAllInbox, claimFencedTells, listTellIds, markTellSubmitted, markTellConsumed, readTellSubmitted, readTellOriginal, isTellCausallyConsumed, appendGenerationEvent, } from "./projection-core.js";
|
|
2
|
+
import { openProjectionTellObserver, } from "./projection/tell/database.js";
|
|
3
|
+
function frameTellBodies(projectionDirectory, tellIds) {
|
|
4
|
+
const originals = tellIds.map((tellId) => readTellOriginal(projectionDirectory, "inflight", tellId));
|
|
5
|
+
const frames = originals
|
|
6
|
+
.map((original, index) => `--- tell ${tellIds[index]} ---\n${original.text}`)
|
|
7
|
+
.join("\n\n");
|
|
8
|
+
const effort = originals.reduce((value, original) => original.effort ?? value, undefined);
|
|
9
|
+
return { frames, ...(effort ? { effort } : {}) };
|
|
10
|
+
}
|
|
11
|
+
function operatorBodyForContinuation(prompt, tellFrames, sessionContinuationPromptPrefix) {
|
|
12
|
+
return sessionContinuationPromptPrefix === undefined
|
|
13
|
+
? `${prompt}\n\n${tellFrames}`
|
|
14
|
+
: `${sessionContinuationPromptPrefix}${tellFrames}`;
|
|
15
|
+
}
|
|
16
|
+
/** Tier-2 boundary snapshot. No tells leaves prompt byte-identical. */
|
|
17
|
+
export function snapshotReplayPrompt(projectionDirectory, prompt, tellFence, executionId, options = {}) {
|
|
18
|
+
const tellIds = claimFencedTells(projectionDirectory, tellFence, executionId);
|
|
19
|
+
if (tellIds.length === 0)
|
|
20
|
+
return { prompt, tellIds };
|
|
21
|
+
const { frames, effort } = frameTellBodies(projectionDirectory, tellIds);
|
|
22
|
+
const nextPrompt = operatorBodyForContinuation(prompt, frames, options.sessionContinuationPromptPrefix);
|
|
23
|
+
return { prompt: nextPrompt, tellIds, ...(effort ? { effort } : {}) };
|
|
24
|
+
}
|
|
25
|
+
/** Tier-2 has no steer acknowledgement: actual driver start is its ordinal-zero submission point. */
|
|
26
|
+
export function markReplayStarted(projectionDirectory, executionId, tellIds) {
|
|
27
|
+
for (const tellId of tellIds) {
|
|
28
|
+
if (listTellIds(projectionDirectory, "inflight").includes(tellId)) {
|
|
29
|
+
markTellSubmitted(projectionDirectory, tellId, { executionId, fence: { kind: "ordinal", ordinal: 0 } });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** A successful replay terminal is checkpoint ordinal one; failures intentionally do not consume. */
|
|
34
|
+
export function markReplayCompleted(projectionDirectory, executionId) {
|
|
35
|
+
for (const tellId of listTellIds(projectionDirectory, "submitted")) {
|
|
36
|
+
const submitted = readTellSubmitted(projectionDirectory, tellId);
|
|
37
|
+
if (submitted.executionId === executionId && submitted.fence && isTellCausallyConsumed(submitted.fence, { kind: "ordinal", ordinal: 1 })) {
|
|
38
|
+
markTellConsumed(projectionDirectory, tellId);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Tier-2's only submission acknowledgement. A created driver is deliberately
|
|
44
|
+
* insufficient: observe the first provider event, or a successful completion
|
|
45
|
+
* from a provider that emitted no events.
|
|
46
|
+
*/
|
|
47
|
+
export function createReplayRunStartGate(projectionDirectory, executionId, tellIds) {
|
|
48
|
+
let started = false;
|
|
49
|
+
const start = () => {
|
|
50
|
+
if (started)
|
|
51
|
+
return;
|
|
52
|
+
markReplayStarted(projectionDirectory, executionId, tellIds);
|
|
53
|
+
started = true;
|
|
54
|
+
};
|
|
55
|
+
return { observeProviderEvent: start, observeSuccessfulCompletion: start };
|
|
56
|
+
}
|
|
57
|
+
const LIVE_TELL_DELIVERY_THROTTLE_MS = 200;
|
|
58
|
+
function submitEligible(projectionDirectory, executionId, control, requireInbox, submitting, observer, pendingCompletionEvidence) {
|
|
59
|
+
if (requireInbox && !observer?.hasInbox())
|
|
60
|
+
return;
|
|
61
|
+
claimAllInbox(projectionDirectory);
|
|
62
|
+
for (const tellId of listTellIds(projectionDirectory, "inflight")) {
|
|
63
|
+
if (submitting.has(tellId))
|
|
64
|
+
continue;
|
|
65
|
+
// Construct before pin: a sync read/build failure must not leave submitting stuck.
|
|
66
|
+
const original = readTellOriginal(projectionDirectory, "inflight", tellId);
|
|
67
|
+
const tell = {
|
|
68
|
+
id: tellId,
|
|
69
|
+
text: `--- tell ${tellId} ---\n${original.text}`,
|
|
70
|
+
...(original.effort ? { effort: original.effort } : {}),
|
|
71
|
+
};
|
|
72
|
+
submitting.add(tellId);
|
|
73
|
+
void Promise.resolve()
|
|
74
|
+
.then(() => control.enqueue(tell))
|
|
75
|
+
.then((ack) => {
|
|
76
|
+
if (!ack)
|
|
77
|
+
throw new Error("provider enqueue resolved without TellSubmitAck");
|
|
78
|
+
markTellSubmitted(projectionDirectory, tellId, { executionId, fence: ack.fence });
|
|
79
|
+
const pending = pendingCompletionEvidence.get(tellId);
|
|
80
|
+
if (!pending)
|
|
81
|
+
return;
|
|
82
|
+
for (const evidence of pending) {
|
|
83
|
+
if (isTellCausallyConsumed(ack.fence, evidence)) {
|
|
84
|
+
markTellConsumed(projectionDirectory, tellId);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
pendingCompletionEvidence.delete(tellId);
|
|
89
|
+
})
|
|
90
|
+
.catch(() => {
|
|
91
|
+
// Leave in inflight for the next checkpoint or ingress opportunity.
|
|
92
|
+
// Reject means this crossing never accepted the tell; drop stale evidence.
|
|
93
|
+
pendingCompletionEvidence.delete(tellId);
|
|
94
|
+
})
|
|
95
|
+
.finally(() => submitting.delete(tellId));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export function createLiveTellDeliveryController(projectionDirectory, executionId, dependencies = {}) {
|
|
99
|
+
const now = dependencies.now ?? Date.now;
|
|
100
|
+
const setTimer = dependencies.setTimer ?? ((callback, delayMs) => setTimeout(callback, delayMs));
|
|
101
|
+
const clearTimer = dependencies.clearTimer ?? ((timer) => clearTimeout(timer));
|
|
102
|
+
const openObserver = dependencies.openObserver ?? openProjectionTellObserver;
|
|
103
|
+
const submitting = new Set();
|
|
104
|
+
// In-memory only: bridges completion-before-ack when a tell is still submitting.
|
|
105
|
+
const pendingCompletionEvidence = new Map();
|
|
106
|
+
let observer;
|
|
107
|
+
let timer;
|
|
108
|
+
let nextOpportunityAt = 0;
|
|
109
|
+
let checking = false;
|
|
110
|
+
let dirty = false;
|
|
111
|
+
let closed = false;
|
|
112
|
+
let latestControl;
|
|
113
|
+
let opportunityEpoch = 0;
|
|
114
|
+
const scheduleTrailing = () => {
|
|
115
|
+
if (closed || timer !== undefined || !dirty)
|
|
116
|
+
return;
|
|
117
|
+
const delayMs = Math.max(0, nextOpportunityAt - now());
|
|
118
|
+
timer = setTimer(() => {
|
|
119
|
+
timer = undefined;
|
|
120
|
+
if (closed || !dirty)
|
|
121
|
+
return;
|
|
122
|
+
if (now() < nextOpportunityAt) {
|
|
123
|
+
scheduleTrailing();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const control = latestControl;
|
|
127
|
+
if (control)
|
|
128
|
+
runOpportunity(control);
|
|
129
|
+
}, delayMs);
|
|
130
|
+
};
|
|
131
|
+
const discardObserver = () => {
|
|
132
|
+
try {
|
|
133
|
+
observer?.close();
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Observer close failures cannot change delivery policy.
|
|
137
|
+
}
|
|
138
|
+
observer = undefined;
|
|
139
|
+
};
|
|
140
|
+
const runOpportunity = (control) => {
|
|
141
|
+
if (closed)
|
|
142
|
+
return;
|
|
143
|
+
const epoch = opportunityEpoch;
|
|
144
|
+
dirty = false;
|
|
145
|
+
checking = true;
|
|
146
|
+
nextOpportunityAt = now() + LIVE_TELL_DELIVERY_THROTTLE_MS;
|
|
147
|
+
try {
|
|
148
|
+
observer ??= openObserver(projectionDirectory);
|
|
149
|
+
if (observer.hasDataVersionChanged()) {
|
|
150
|
+
submitEligible(projectionDirectory, executionId, control, true, submitting, observer, pendingCompletionEvidence);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Observation and event delivery failures never terminate provider execution.
|
|
155
|
+
discardObserver();
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
checking = false;
|
|
159
|
+
if (epoch === opportunityEpoch && dirty)
|
|
160
|
+
scheduleTrailing();
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const cancelOpportunity = () => {
|
|
164
|
+
opportunityEpoch += 1;
|
|
165
|
+
dirty = false;
|
|
166
|
+
if (timer !== undefined) {
|
|
167
|
+
clearTimer(timer);
|
|
168
|
+
timer = undefined;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
return {
|
|
172
|
+
requestDelivery(control) {
|
|
173
|
+
if (closed)
|
|
174
|
+
return;
|
|
175
|
+
latestControl = control;
|
|
176
|
+
dirty = true;
|
|
177
|
+
if (checking || now() < nextOpportunityAt) {
|
|
178
|
+
scheduleTrailing();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
runOpportunity(control);
|
|
182
|
+
},
|
|
183
|
+
checkpoint(control, checkpoint) {
|
|
184
|
+
if (closed)
|
|
185
|
+
return;
|
|
186
|
+
latestControl = control;
|
|
187
|
+
cancelOpportunity();
|
|
188
|
+
submitEligible(projectionDirectory, executionId, control, false, submitting, observer, pendingCompletionEvidence);
|
|
189
|
+
if (!checkpoint.consumptionEvidence)
|
|
190
|
+
return;
|
|
191
|
+
for (const tellId of listTellIds(projectionDirectory, "submitted")) {
|
|
192
|
+
const submitted = readTellSubmitted(projectionDirectory, tellId);
|
|
193
|
+
if (submitted.executionId === executionId && submitted.fence && isTellCausallyConsumed(submitted.fence, checkpoint.fence)) {
|
|
194
|
+
markTellConsumed(projectionDirectory, tellId);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Capture still-in-flight enqueues so a late ack can still see this evidence.
|
|
198
|
+
for (const tellId of submitting) {
|
|
199
|
+
const pending = pendingCompletionEvidence.get(tellId);
|
|
200
|
+
if (pending)
|
|
201
|
+
pending.push(checkpoint.fence);
|
|
202
|
+
else
|
|
203
|
+
pendingCompletionEvidence.set(tellId, [checkpoint.fence]);
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
close() {
|
|
207
|
+
if (closed)
|
|
208
|
+
return;
|
|
209
|
+
closed = true;
|
|
210
|
+
cancelOpportunity();
|
|
211
|
+
discardObserver();
|
|
212
|
+
// Do not drop pendingCompletionEvidence: in-flight acks may still submit/consume.
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Build an onSyncCheckpoint callback that claims all inbox tells
|
|
218
|
+
* and delivers them via the given SteerControl.
|
|
219
|
+
* Intended for use inside adapter start() calls as the onSyncCheckpoint callback.
|
|
220
|
+
*/
|
|
221
|
+
export function buildSyncCheckpointCallback(projectionDirectory, executionId) {
|
|
222
|
+
const controller = createLiveTellDeliveryController(projectionDirectory, executionId);
|
|
223
|
+
return (control, checkpoint) => controller.checkpoint(control, checkpoint);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Durable execution observer: appends prepared events, delivers live tells at
|
|
227
|
+
* checkpoints, and exposes the public ExecutionObserver surface for harness call/revive.
|
|
228
|
+
*/
|
|
229
|
+
export function createProjectionExecutionObserver(input, dependencies = {}) {
|
|
230
|
+
const appendEvent = dependencies.appendGenerationEvent ?? appendGenerationEvent;
|
|
231
|
+
const tellController = createLiveTellDeliveryController(input.projectionDirectory, input.executionId);
|
|
232
|
+
let closed = false;
|
|
233
|
+
const observer = {
|
|
234
|
+
onEvent(event) {
|
|
235
|
+
input.replayStartGate?.observeProviderEvent();
|
|
236
|
+
appendEvent(input.projectionDirectory, input.executionId, event);
|
|
237
|
+
},
|
|
238
|
+
onCheckpoint(control, checkpoint) {
|
|
239
|
+
tellController.checkpoint(control, checkpoint);
|
|
240
|
+
},
|
|
241
|
+
onDeliveryOpportunity(control) {
|
|
242
|
+
tellController.requestDelivery(control);
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
return {
|
|
246
|
+
observer,
|
|
247
|
+
close() {
|
|
248
|
+
if (closed)
|
|
249
|
+
return;
|
|
250
|
+
closed = true;
|
|
251
|
+
try {
|
|
252
|
+
tellController.close();
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// Controller cleanup cannot change provider completion.
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ProjectionStateError } from "./atomic-publish.js";
|
|
2
|
-
import { applySnapshotEffort, parseResolvedAkumaLaunchSnapshot, } from "../agents/launch-
|
|
2
|
+
import { applySnapshotEffort, parseResolvedAkumaLaunchSnapshot, } from "../agents/launch-snapshot/model.js";
|
|
3
3
|
import { listTellIds, readTellOriginal, readTellSubmitted, } from "./projection-core.js";
|
|
4
4
|
export function snapshotPendingTells(projectionDirectory) {
|
|
5
5
|
const pending = ["inbox", "inflight", "submitted"]
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { initializeConfig } from "../config/env.js";
|
|
2
|
-
import {
|
|
3
|
-
import { parseResolvedAkumaLaunchSnapshot, } from "../agents/launch-
|
|
4
|
-
import { revive, call } from "../agents/harness/index.js";
|
|
5
|
-
import { readProjectionEvents } from "./projection-core.js";
|
|
2
|
+
import { buildCallTerms } from "../agents/call-terms.js";
|
|
3
|
+
import { parseResolvedAkumaLaunchSnapshot, } from "../agents/launch-snapshot/model.js";
|
|
4
|
+
import { revive, call, } from "../agents/harness/index.js";
|
|
5
|
+
import { demoteSubmittedTellsForReplay, readProjectionEvents, } from "./projection-core.js";
|
|
6
|
+
import { createProjectionExecutionObserver, createReplayRunStartGate, markReplayCompleted, snapshotReplayPrompt, } from "./projection-execution-observer.js";
|
|
6
7
|
import { readProjectionIdentity } from "./projection-identity.js";
|
|
7
8
|
import { selectValidStoredAgentEvents } from "./stored-agent-event.js";
|
|
8
9
|
import { persistResponseHistory } from "./transcripts.js";
|
|
@@ -45,6 +46,7 @@ function parseLaunchInputs(launch) {
|
|
|
45
46
|
const title = optionalString(raw.title, "title");
|
|
46
47
|
const context = optionalString(raw.context, "context");
|
|
47
48
|
const resumePath = optionalString(raw.resumePath, "resumePath");
|
|
49
|
+
const sourceArtifactId = optionalString(raw.sourceArtifactId, "sourceArtifactId");
|
|
48
50
|
return {
|
|
49
51
|
prompt: requireString(raw.prompt, "prompt"),
|
|
50
52
|
cwd: requireString(raw.cwd, "cwd"),
|
|
@@ -58,6 +60,7 @@ function parseLaunchInputs(launch) {
|
|
|
58
60
|
persistProjectionResponse: raw.persistProjectionResponse,
|
|
59
61
|
...(raw.session ? { session: raw.session } : {}),
|
|
60
62
|
...(resumePath ? { resumePath } : {}),
|
|
63
|
+
...(sourceArtifactId ? { sourceArtifactId } : {}),
|
|
61
64
|
};
|
|
62
65
|
}
|
|
63
66
|
function persistenceError(error) {
|
|
@@ -81,8 +84,9 @@ function maximumValidEnvelopeTurn(projectionDirectory) {
|
|
|
81
84
|
return maximum;
|
|
82
85
|
}
|
|
83
86
|
async function completionFacts(projectionDirectory, executionId, inputs, outcome) {
|
|
87
|
+
const providerUnavailable = outcome.error?.code === "SUBAGENT_PROVIDER_UNAVAILABLE";
|
|
84
88
|
let persistence = {};
|
|
85
|
-
if (inputs.persistProjectionResponse) {
|
|
89
|
+
if (inputs.persistProjectionResponse && !providerUnavailable) {
|
|
86
90
|
try {
|
|
87
91
|
if (!inputs.evidenceCwd) {
|
|
88
92
|
throw new Error("projection response persistence is missing evidenceCwd");
|
|
@@ -120,29 +124,95 @@ async function completionFacts(projectionDirectory, executionId, inputs, outcome
|
|
|
120
124
|
launchSnapshot: inputs.launchSnapshot,
|
|
121
125
|
effectivePolicy: inputs.launchSnapshot.akuma.policy,
|
|
122
126
|
...(outcome.error ? { error: outcome.error } : {}),
|
|
127
|
+
...(providerUnavailable && inputs.sourceArtifactId
|
|
128
|
+
? { sourceArtifactId: inputs.sourceArtifactId }
|
|
129
|
+
: {}),
|
|
123
130
|
...persistence,
|
|
124
131
|
});
|
|
125
132
|
}
|
|
126
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Construct the public Projection once and expose a provider-neutral execution
|
|
135
|
+
* handle. Provider adapters and harness public types are unchanged.
|
|
136
|
+
*/
|
|
137
|
+
export function executeProjectionGeneration(projectionDirectory, launch) {
|
|
127
138
|
const inputs = parseLaunchInputs(launch);
|
|
128
139
|
initializeConfig(process.env, inputs.cwd);
|
|
129
|
-
const
|
|
140
|
+
const executionId = launch.executionId;
|
|
141
|
+
const tellFence = launch.facts.tellFence ?? [];
|
|
142
|
+
demoteSubmittedTellsForReplay(projectionDirectory, executionId);
|
|
143
|
+
const baseTerms = buildCallTerms(inputs.launchSnapshot, inputs.prompt, inputs.cwd, {
|
|
130
144
|
idleTimeoutMs: inputs.idleTimeoutMs,
|
|
131
|
-
projectionDir: projectionDirectory,
|
|
132
|
-
projectionExecutionId: launch.executionId,
|
|
133
|
-
projectionTellFence: launch.facts.tellFence ?? [],
|
|
134
145
|
initialTurn: maximumValidEnvelopeTurn(projectionDirectory),
|
|
135
146
|
});
|
|
136
|
-
const
|
|
137
|
-
?
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
const launchSnapshot = baseTerms.provider === "codex-sdk"
|
|
148
|
+
? snapshotReplayPrompt(projectionDirectory, baseTerms.prompt, tellFence, executionId, {
|
|
149
|
+
sessionContinuationPromptPrefix: inputs.session && inputs.resumePath
|
|
150
|
+
? baseTerms.sessionContinuationPromptPrefix
|
|
151
|
+
: undefined,
|
|
152
|
+
})
|
|
153
|
+
: undefined;
|
|
154
|
+
const terms = launchSnapshot
|
|
155
|
+
? baseTerms.provider === "codex-sdk" && launchSnapshot.effort
|
|
156
|
+
? {
|
|
157
|
+
...baseTerms,
|
|
158
|
+
prompt: launchSnapshot.prompt,
|
|
159
|
+
threadOptions: {
|
|
160
|
+
...baseTerms.threadOptions,
|
|
161
|
+
modelReasoningEffort: launchSnapshot.effort,
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
: { ...baseTerms, prompt: launchSnapshot.prompt }
|
|
165
|
+
: baseTerms;
|
|
166
|
+
// A constructed driver is not an SDK run acknowledgement. Tier-2 has no
|
|
167
|
+
// live steer surface, so the first provider event is the earliest harness
|
|
168
|
+
// observable start; a successful no-event completion is the only fallback.
|
|
169
|
+
const replayStartGate = launchSnapshot
|
|
170
|
+
? createReplayRunStartGate(projectionDirectory, executionId, launchSnapshot.tellIds)
|
|
171
|
+
: undefined;
|
|
172
|
+
const observerController = createProjectionExecutionObserver({
|
|
173
|
+
projectionDirectory,
|
|
174
|
+
executionId,
|
|
175
|
+
...(replayStartGate ? { replayStartGate } : {}),
|
|
176
|
+
});
|
|
177
|
+
let projection;
|
|
178
|
+
try {
|
|
179
|
+
projection = inputs.session && inputs.resumePath
|
|
180
|
+
? revive({ ...terms, session: inputs.session, resumePath: inputs.resumePath }, { observer: observerController.observer })
|
|
181
|
+
: call(terms, { observer: observerController.observer });
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
observerController.close();
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
const outcome = projection.outcome.then(async (result) => {
|
|
188
|
+
try {
|
|
189
|
+
if (result.status === "completed") {
|
|
190
|
+
// A provider may complete successfully without emitting any observable
|
|
191
|
+
// events. Its successful completion is still a real run start.
|
|
192
|
+
replayStartGate?.observeSuccessfulCompletion();
|
|
193
|
+
if (launchSnapshot) {
|
|
194
|
+
markReplayCompleted(projectionDirectory, executionId);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
verdict: result.status === "completed"
|
|
199
|
+
? "completed"
|
|
200
|
+
: result.status === "dismissed"
|
|
201
|
+
? "dismissed"
|
|
202
|
+
: "failed",
|
|
203
|
+
facts: await completionFacts(projectionDirectory, executionId, inputs, result),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
observerController.close();
|
|
208
|
+
}
|
|
209
|
+
}, (error) => {
|
|
210
|
+
observerController.close();
|
|
211
|
+
throw error;
|
|
212
|
+
});
|
|
140
213
|
return {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
? "dismissed"
|
|
145
|
-
: "failed",
|
|
146
|
-
facts: await completionFacts(projectionDirectory, launch.executionId, inputs, outcome),
|
|
214
|
+
events: projection.events,
|
|
215
|
+
outcome,
|
|
216
|
+
abort: (mode) => projection.abort(mode),
|
|
147
217
|
};
|
|
148
218
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
-
import { openProjectionGenerationStore } from "./projection
|
|
2
|
+
import { openProjectionGenerationStore } from "./projection/generation/store.js";
|
|
3
3
|
import { spawnProjectionGenerationRunner, } from "./projection-generation-process.js";
|
|
4
4
|
export const PROJECTION_ADOPTION_TIMEOUT_MS = 4_000;
|
|
5
5
|
export const PROJECTION_ADOPTION_POLL_MS = 20;
|