@astrosheep/keiyaku 4.6.8 → 4.6.10
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 +40 -14
- package/build/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/build/plugins/claude/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/claude/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/claude/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/build/plugins/codex/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/codex/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/codex/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/opencode/index.js +1 -1
- package/build/plugins/opencode/skills/keiyaku/SKILL.md +5 -6
- package/build/plugins/opencode/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/plugins/opencode/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/skills/keiyaku/SKILL.md +5 -6
- package/build/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/skills/keiyaku-akuma/references/automation.md +8 -8
- package/build/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/skills/keiyaku-bind/SKILL.md +9 -9
- package/build/skills/keiyaku-debt/SKILL.md +91 -0
- package/build/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/src/akuma/akuma-instance.d.ts +2 -0
- package/build/src/akuma/akuma-instance.js +10 -0
- package/build/src/akuma/akuma-observe.d.ts +33 -8
- package/build/src/akuma/akuma-observe.js +88 -64
- package/build/src/akuma/akuma-owner.d.ts +11 -2
- package/build/src/akuma/akuma-owner.js +45 -35
- package/build/src/akuma/akuma-selection-execution.js +9 -1
- package/build/src/akuma/akuma-stream.d.ts +22 -0
- package/build/src/akuma/akuma-stream.js +116 -0
- package/build/src/akuma/akuma-wait.d.ts +1 -40
- package/build/src/akuma/akuma-wait.js +23 -84
- package/build/src/akuma/akuma.d.ts +17 -11
- package/build/src/akuma/akuma.js +2 -0
- package/build/src/akuma/allowed.d.ts +7 -12
- package/build/src/akuma/allowed.js +13 -4
- package/build/src/akuma/body-supervisor.d.ts +5 -5
- package/build/src/akuma/body-supervisor.js +22 -20
- package/build/src/akuma/body.js +28 -1
- package/build/src/akuma/call-request.d.ts +12 -22
- package/build/src/akuma/heart/activity-schema.d.ts +12 -0
- package/build/src/akuma/heart/activity-schema.js +6 -0
- package/build/src/akuma/heart/index.d.ts +59 -2
- package/build/src/akuma/heart/index.js +87 -8
- package/build/src/akuma/heart/rows.js +5 -3
- package/build/src/akuma/heart/soul.d.ts +9 -0
- package/build/src/akuma/heart/soul.js +29 -0
- package/build/src/akuma/heart/storage.d.ts +15 -0
- package/build/src/akuma/heart/storage.js +55 -0
- package/build/src/akuma/heart/timeline.d.ts +7 -0
- package/build/src/akuma/heart/timeline.js +10 -0
- package/build/src/akuma/index.d.ts +1 -0
- package/build/src/akuma/projection.d.ts +25 -0
- package/build/src/akuma/projection.js +24 -7
- package/build/src/akuma/provider-recipe.d.ts +11 -0
- package/build/src/akuma/provider-recipe.js +23 -0
- package/build/src/akuma/provider.d.ts +25 -0
- package/build/src/akuma/provider.js +99 -7
- package/build/src/akuma/providers/acp/events.js +25 -2
- package/build/src/akuma/providers/claude/events.js +76 -10
- package/build/src/akuma/providers/claude/index.js +2 -5
- package/build/src/akuma/providers/codex-app-server/events.js +17 -2
- package/build/src/akuma/providers/codex-app-server/index.js +15 -9
- package/build/src/akuma/providers/decode.d.ts +8 -0
- package/build/src/akuma/providers/decode.js +21 -0
- package/build/src/akuma/providers/grok-build/index.js +10 -26
- package/build/src/akuma/providers/opencode-sdk/event-stream.d.ts +3 -3
- package/build/src/akuma/providers/opencode-sdk/event-stream.js +2 -25
- package/build/src/akuma/providers/opencode-sdk/events.d.ts +7 -43
- package/build/src/akuma/providers/opencode-sdk/events.js +147 -284
- package/build/src/akuma/providers/opencode-sdk/index.js +267 -421
- package/build/src/akuma/providers/opencode-sdk/native-http.d.ts +9 -0
- package/build/src/akuma/providers/opencode-sdk/native-http.js +69 -0
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +42 -36
- package/build/src/akuma/providers/opencode-sdk/session.js +75 -82
- package/build/src/akuma/providers/paseo/events.d.ts +8 -0
- package/build/src/akuma/providers/paseo/events.js +58 -11
- package/build/src/akuma/providers/paseo/index.js +11 -7
- package/build/src/akuma/providers/pi/events.d.ts +2 -0
- package/build/src/akuma/providers/pi/events.js +32 -24
- package/build/src/akuma/providers/pi/index.js +21 -35
- package/build/src/akuma/request-lifecycle.d.ts +1 -2
- package/build/src/akuma/request-lifecycle.js +2 -8
- package/build/src/akuma/request-rendezvous.js +38 -55
- package/build/src/akuma/request-serve.d.ts +1 -1
- package/build/src/akuma/request-serve.js +77 -113
- package/build/src/akuma/selection-observation.d.ts +57 -51
- package/build/src/akuma/selection-observation.js +3 -3
- package/build/src/akuma/turn-drive.d.ts +3 -0
- package/build/src/akuma/turn-drive.js +26 -5
- package/build/src/akuma-body.js +12 -22
- package/build/src/cli/akuma-caller.js +10 -0
- package/build/src/cli/commands/akuma-grammar.js +3 -4
- package/build/src/cli/commands/akuma.js +13 -51
- package/build/src/cli/commands/contract-grammar.d.ts +7 -6
- package/build/src/cli/commands/contract-grammar.js +27 -32
- package/build/src/cli/commands/contract-help.d.ts +16 -7
- package/build/src/cli/commands/contract-help.js +20 -11
- package/build/src/cli/commands/contract.js +11 -11
- package/build/src/cli/commands/debt-grammar.d.ts +19 -0
- package/build/src/cli/commands/debt-grammar.js +323 -0
- package/build/src/cli/commands/debt-query.d.ts +5 -0
- package/build/src/cli/commands/{task-query.js → debt-query.js} +9 -9
- package/build/src/cli/commands/{task.d.ts → debt.d.ts} +2 -2
- package/build/src/cli/commands/{task.js → debt.js} +83 -143
- package/build/src/cli/coordinates.d.ts +1 -1
- package/build/src/cli/coordinates.js +1 -1
- package/build/src/cli/parse.d.ts +4 -4
- package/build/src/cli/parse.js +17 -16
- package/build/src/cli/render/akuma-activity.d.ts +11 -83
- package/build/src/cli/render/akuma-activity.js +20 -382
- package/build/src/cli/render/catalog.d.ts +2 -2
- package/build/src/cli/render/catalog.js +5 -5
- package/build/src/cli/render/contract.js +2 -2
- package/build/src/cli/render/debt.d.ts +28 -0
- package/build/src/cli/render/{task.js → debt.js} +51 -112
- package/build/src/cli/render/kanshi.js +28 -28
- package/build/src/cli/render/marks.d.ts +5 -5
- package/build/src/cli/render/marks.js +4 -10
- package/build/src/cli/render/nuke.js +1 -1
- package/build/src/cli/runtime.js +3 -3
- package/build/src/cli/scan.d.ts +1 -1
- package/build/src/cli/usage.d.ts +1 -1
- package/build/src/cli/usage.js +4 -4
- package/build/src/contract-worktree.js +3 -3
- package/build/src/debt/board.d.ts +160 -0
- package/build/src/{task → debt}/board.js +89 -89
- package/build/src/debt/catalog.d.ts +11 -0
- package/build/src/debt/catalog.js +59 -0
- package/build/src/{task → debt}/context.d.ts +1 -1
- package/build/src/{task → debt}/context.js +1 -1
- package/build/src/{task → debt}/created-observation.d.ts +6 -10
- package/build/src/{task → debt}/created-observation.js +7 -7
- package/build/src/debt/document.d.ts +37 -0
- package/build/src/{task → debt}/document.js +37 -37
- package/build/src/debt/identity.d.ts +21 -0
- package/build/src/{task → debt}/identity.js +35 -35
- package/build/src/debt/index.d.ts +111 -0
- package/build/src/debt/index.js +203 -0
- package/build/src/{task → debt}/input.d.ts +8 -8
- package/build/src/{task → debt}/input.js +21 -21
- package/build/src/debt/lifecycle-operations.d.ts +6 -0
- package/build/src/{task → debt}/lifecycle-operations.js +27 -31
- package/build/src/debt/mutation-result.d.ts +981 -0
- package/build/src/debt/mutation-result.js +109 -0
- package/build/src/debt/mutation.d.ts +424 -0
- package/build/src/debt/mutation.js +223 -0
- package/build/src/debt/operation-types.d.ts +71 -0
- package/build/src/debt/operations.d.ts +28 -0
- package/build/src/{task → debt}/operations.js +59 -60
- package/build/src/debt/query.d.ts +76 -0
- package/build/src/{task → debt}/query.js +55 -55
- package/build/src/{task → debt}/store.d.ts +13 -13
- package/build/src/{task → debt}/store.js +58 -49
- package/build/src/debt/view.d.ts +4 -0
- package/build/src/debt/view.js +7 -0
- package/build/src/identity/coordinates.d.ts +1 -1
- package/build/src/index.d.ts +13 -13
- package/build/src/index.js +9 -9
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +33 -33
- package/build/src/kanshi/report.d.ts +7 -7
- package/build/src/kanshi/select.js +4 -4
- package/build/src/library/akumas.d.ts +2 -3
- package/build/src/library/bind.d.ts +3 -3
- package/build/src/library/bind.js +5 -5
- package/build/src/library/contract-creation.js +5 -5
- package/build/src/library/contract-execution.js +4 -4
- package/build/src/library/contract-types.d.ts +2 -2
- package/build/src/library/input.d.ts +2 -2
- package/build/src/library/input.js +5 -5
- package/build/src/library/invocation.js +2 -2
- package/build/src/library/nuke.js +3 -3
- package/build/src/library/outcome.d.ts +126 -126
- package/build/src/library/outcome.js +3 -3
- package/build/src/library/selection.d.ts +1 -4
- package/build/src/library/selection.js +11 -62
- package/build/src/plugin/public.d.ts +5 -0
- package/build/src/plugin/runtime.js +3 -1
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/fence.d.ts +3 -3
- package/build/src/settlement/fence.js +4 -4
- package/build/src/settlement/holder.d.ts +16 -16
- package/build/src/settlement/holder.js +69 -63
- package/build/src/settlement/settle.d.ts +5 -5
- package/build/src/settlement/settle.js +53 -53
- package/package.json +12 -6
- package/plugins/paseo/plugin/index.server.ts +17 -0
- package/plugins/paseo/plugin/paseo-plugin.json +4 -0
- package/plugins/paseo/plugin/server/attach.ts +52 -0
- package/plugins/paseo/plugin/server/keiyaku.ts +44 -0
- package/plugins/paseo/plugin/server/message.ts +60 -0
- package/plugins/paseo/plugin/server/mirror.ts +193 -0
- package/plugins/paseo/plugin/server/model.ts +14 -0
- package/plugins/paseo/plugin/server/provider.ts +276 -0
- package/plugins/paseo/plugin/server/sdk-worker.ts +237 -0
- package/plugins/paseo/plugin/server/sdk.ts +289 -0
- package/plugins/paseo/plugin/server/stop.ts +26 -0
- package/plugins/paseo/plugin/server/transport.ts +35 -0
- package/plugins/paseo/plugin/shared/attach-rpc.ts +10 -0
- package/plugins/paseo/plugin/shared/refresh-rpc.ts +6 -0
- package/plugins/paseo/plugin/tsconfig.json +6 -0
- package/skills/keiyaku/SKILL.md +5 -6
- package/skills/keiyaku-akuma/SKILL.md +1 -1
- package/skills/keiyaku-akuma/references/automation.md +8 -8
- package/skills/keiyaku-babysit/SKILL.md +1 -1
- package/skills/keiyaku-bind/SKILL.md +9 -9
- package/skills/keiyaku-debt/SKILL.md +91 -0
- package/skills/keiyaku-workflow/SKILL.md +2 -2
- package/build/plugins/claude/skills/keiyaku-task/SKILL.md +0 -104
- package/build/plugins/codex/skills/keiyaku-task/SKILL.md +0 -104
- package/build/plugins/opencode/skills/keiyaku-task/SKILL.md +0 -104
- package/build/skills/keiyaku-task/SKILL.md +0 -104
- package/build/src/cli/commands/task-grammar.d.ts +0 -19
- package/build/src/cli/commands/task-grammar.js +0 -384
- package/build/src/cli/commands/task-query.d.ts +0 -5
- package/build/src/cli/render/task.d.ts +0 -39
- package/build/src/task/board.d.ts +0 -168
- package/build/src/task/catalog.d.ts +0 -11
- package/build/src/task/catalog.js +0 -59
- package/build/src/task/compose-language.d.ts +0 -57
- package/build/src/task/compose-language.js +0 -364
- package/build/src/task/compose-parser.d.ts +0 -32
- package/build/src/task/compose-parser.js +0 -180
- package/build/src/task/compose.d.ts +0 -16
- package/build/src/task/compose.js +0 -189
- package/build/src/task/document.d.ts +0 -39
- package/build/src/task/identity.d.ts +0 -21
- package/build/src/task/index.d.ts +0 -138
- package/build/src/task/index.js +0 -269
- package/build/src/task/lifecycle-operations.d.ts +0 -6
- package/build/src/task/mutation-result.d.ts +0 -1726
- package/build/src/task/mutation-result.js +0 -198
- package/build/src/task/mutation.d.ts +0 -590
- package/build/src/task/mutation.js +0 -262
- package/build/src/task/operation-types.d.ts +0 -71
- package/build/src/task/operations.d.ts +0 -28
- package/build/src/task/query.d.ts +0 -76
- package/build/src/task/view.d.ts +0 -4
- package/build/src/task/view.js +0 -7
- package/skills/keiyaku-task/SKILL.md +0 -104
- /package/build/src/{task → debt}/operation-types.js +0 -0
package/build/src/akuma/body.js
CHANGED
|
@@ -313,6 +313,29 @@ async function recoverBodyRequests(input) {
|
|
|
313
313
|
}
|
|
314
314
|
return false;
|
|
315
315
|
}
|
|
316
|
+
function turnStartedEmitter(launch, soul, world) {
|
|
317
|
+
const reportDiagnostic = (message) => {
|
|
318
|
+
void recordPluginDiagnostic(launch.paths, "turn started", message);
|
|
319
|
+
};
|
|
320
|
+
return {
|
|
321
|
+
async emit(turnSequence) {
|
|
322
|
+
try {
|
|
323
|
+
const turn = await readTurn(launch.paths, turnSequence);
|
|
324
|
+
if (turn === null)
|
|
325
|
+
throw new Error(`Committed Turn ${turnSequence} is missing from Heart`);
|
|
326
|
+
await emitPluginSignal({ world, reportDiagnostic }, {
|
|
327
|
+
kind: "akuma.turn-started",
|
|
328
|
+
akumaId: soul.id,
|
|
329
|
+
turnSequence,
|
|
330
|
+
...(turn.initiator === undefined ? {} : { initiator: turn.initiator }),
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
await recordPluginDiagnostic(launch.paths, "turn started", error);
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
}
|
|
316
339
|
function turnOutcomeEmitter(launch, soul, world) {
|
|
317
340
|
const reportDiagnostic = (message) => {
|
|
318
341
|
void recordPluginDiagnostic(launch.paths, "turn outcome", message);
|
|
@@ -383,7 +406,7 @@ async function admitInitialCallTell(runtime, input) {
|
|
|
383
406
|
});
|
|
384
407
|
}
|
|
385
408
|
async function runBodyTurns(input) {
|
|
386
|
-
const { launch, soul, adapter, bodySequence, supervisor, runtime, turnOutcome } = input;
|
|
409
|
+
const { launch, soul, adapter, bodySequence, supervisor, runtime, turnStarted, turnOutcome } = input;
|
|
387
410
|
let initial = launch.initialBody;
|
|
388
411
|
for (;;) {
|
|
389
412
|
const launchTells = drainPendingTells(supervisor.current().pending, await readOpenBoundTurns(launch.paths, bodySequence));
|
|
@@ -418,6 +441,7 @@ async function runBodyTurns(input) {
|
|
|
418
441
|
world: runtime.world,
|
|
419
442
|
externalCommands: runtime.externalCommands,
|
|
420
443
|
now: runtime.now,
|
|
444
|
+
turnStarted,
|
|
421
445
|
});
|
|
422
446
|
if (result.kind === "hung") {
|
|
423
447
|
await failOpenBoundTurnsIfPresent(launch.paths, bodySequence, "Body hung with open bound Turns", runtime.now());
|
|
@@ -566,12 +590,14 @@ export async function driveAkumaBody(launch, adapter, runtimeInput = {}) {
|
|
|
566
590
|
let pendingTellDisposition = undefined;
|
|
567
591
|
let bodySequence;
|
|
568
592
|
let emitBodyEnd;
|
|
593
|
+
let emitTurnStarted;
|
|
569
594
|
let emitTurnOutcome;
|
|
570
595
|
try {
|
|
571
596
|
const prepared = await prepareBodyExecution(launch, leash, runtime, adapter);
|
|
572
597
|
if (prepared === null)
|
|
573
598
|
return;
|
|
574
599
|
emitBodyEnd = bodyEndEmitter(launch, prepared.soul, world);
|
|
600
|
+
emitTurnStarted = turnStartedEmitter(launch, prepared.soul, world);
|
|
575
601
|
emitTurnOutcome = turnOutcomeEmitter(launch, prepared.soul, world);
|
|
576
602
|
const body = await leash.recordBody(launch.paths, { leashTakenAt: runtime.now() });
|
|
577
603
|
bodySequence = body.sequence;
|
|
@@ -598,6 +624,7 @@ export async function driveAkumaBody(launch, adapter, runtimeInput = {}) {
|
|
|
598
624
|
bodySequence: body.sequence,
|
|
599
625
|
supervisor,
|
|
600
626
|
runtime,
|
|
627
|
+
turnStarted: emitTurnStarted,
|
|
601
628
|
turnOutcome: emitTurnOutcome,
|
|
602
629
|
});
|
|
603
630
|
}
|
|
@@ -8,23 +8,18 @@ import type { WorldRoot } from "../world.js";
|
|
|
8
8
|
declare const akumaCallRecipeSchema: z.ZodObject<{
|
|
9
9
|
description: z.ZodOptional<z.ZodString>;
|
|
10
10
|
allowed: z.ZodPipe<z.ZodArray<z.ZodEnum<{
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"task.hold": "task.hold";
|
|
17
|
-
"task.resume": "task.resume";
|
|
18
|
-
"task.start": "task.start";
|
|
19
|
-
"task.stop": "task.stop";
|
|
20
|
-
"task.update": "task.update";
|
|
11
|
+
"debt.add": "debt.add";
|
|
12
|
+
"debt.addDocument": "debt.addDocument";
|
|
13
|
+
"debt.done": "debt.done";
|
|
14
|
+
"debt.drop": "debt.drop";
|
|
15
|
+
"debt.update": "debt.update";
|
|
21
16
|
"akuma.call": "akuma.call";
|
|
22
17
|
"akuma.kill": "akuma.kill";
|
|
23
18
|
"akuma.tell": "akuma.tell";
|
|
24
19
|
"contract.audit": "contract.audit";
|
|
25
20
|
"contract.deliver": "contract.deliver";
|
|
26
21
|
"contract.review": "contract.review";
|
|
27
|
-
}>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("
|
|
22
|
+
}>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("debt.add" | "debt.addDocument" | "debt.done" | "debt.drop" | "debt.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
|
|
28
23
|
provider: z.ZodPipe<z.ZodObject<{
|
|
29
24
|
name: z.ZodString;
|
|
30
25
|
kind: z.ZodEnum<{
|
|
@@ -93,23 +88,18 @@ declare const akumaCallPayloadSchema: z.ZodObject<{
|
|
|
93
88
|
recipe: z.ZodObject<{
|
|
94
89
|
description: z.ZodOptional<z.ZodString>;
|
|
95
90
|
allowed: z.ZodPipe<z.ZodArray<z.ZodEnum<{
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"task.hold": "task.hold";
|
|
102
|
-
"task.resume": "task.resume";
|
|
103
|
-
"task.start": "task.start";
|
|
104
|
-
"task.stop": "task.stop";
|
|
105
|
-
"task.update": "task.update";
|
|
91
|
+
"debt.add": "debt.add";
|
|
92
|
+
"debt.addDocument": "debt.addDocument";
|
|
93
|
+
"debt.done": "debt.done";
|
|
94
|
+
"debt.drop": "debt.drop";
|
|
95
|
+
"debt.update": "debt.update";
|
|
106
96
|
"akuma.call": "akuma.call";
|
|
107
97
|
"akuma.kill": "akuma.kill";
|
|
108
98
|
"akuma.tell": "akuma.tell";
|
|
109
99
|
"contract.audit": "contract.audit";
|
|
110
100
|
"contract.deliver": "contract.deliver";
|
|
111
101
|
"contract.review": "contract.review";
|
|
112
|
-
}>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("
|
|
102
|
+
}>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("debt.add" | "debt.addDocument" | "debt.done" | "debt.drop" | "debt.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
|
|
113
103
|
provider: z.ZodPipe<z.ZodObject<{
|
|
114
104
|
name: z.ZodString;
|
|
115
105
|
kind: z.ZodEnum<{
|
|
@@ -24,6 +24,7 @@ export declare const fileChangeSchema: z.ZodObject<{
|
|
|
24
24
|
added: z.ZodNumber;
|
|
25
25
|
removed: z.ZodNumber;
|
|
26
26
|
}, z.core.$strip>>;
|
|
27
|
+
patch: z.ZodOptional<z.ZodString>;
|
|
27
28
|
}, z.core.$strip>;
|
|
28
29
|
export declare const toolCallSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
29
30
|
kind: z.ZodLiteral<"run">;
|
|
@@ -57,6 +58,7 @@ export declare const toolCallSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
57
58
|
added: z.ZodNumber;
|
|
58
59
|
removed: z.ZodNumber;
|
|
59
60
|
}, z.core.$strip>>;
|
|
61
|
+
patch: z.ZodOptional<z.ZodString>;
|
|
60
62
|
}, z.core.$strip>>>;
|
|
61
63
|
}, z.core.$strip>, z.ZodObject<{
|
|
62
64
|
kind: z.ZodLiteral<"other">;
|
|
@@ -72,6 +74,7 @@ export declare const toolResultSchema: z.ZodObject<{
|
|
|
72
74
|
ok: "ok";
|
|
73
75
|
}>;
|
|
74
76
|
message: z.ZodOptional<z.ZodString>;
|
|
77
|
+
output: z.ZodOptional<z.ZodString>;
|
|
75
78
|
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
76
79
|
}, z.core.$strip>;
|
|
77
80
|
declare const toolEventSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
@@ -112,6 +115,7 @@ declare const toolEventSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
112
115
|
added: z.ZodNumber;
|
|
113
116
|
removed: z.ZodNumber;
|
|
114
117
|
}, z.core.$strip>>;
|
|
118
|
+
patch: z.ZodOptional<z.ZodString>;
|
|
115
119
|
}, z.core.$strip>>>;
|
|
116
120
|
}, z.core.$strip>, z.ZodObject<{
|
|
117
121
|
kind: z.ZodLiteral<"other">;
|
|
@@ -130,6 +134,7 @@ declare const toolEventSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
130
134
|
ok: "ok";
|
|
131
135
|
}>;
|
|
132
136
|
message: z.ZodOptional<z.ZodString>;
|
|
137
|
+
output: z.ZodOptional<z.ZodString>;
|
|
133
138
|
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
134
139
|
}, z.core.$strip>;
|
|
135
140
|
type: z.ZodLiteral<"tool">;
|
|
@@ -167,6 +172,7 @@ declare const toolEventSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
167
172
|
added: z.ZodNumber;
|
|
168
173
|
removed: z.ZodNumber;
|
|
169
174
|
}, z.core.$strip>>;
|
|
175
|
+
patch: z.ZodOptional<z.ZodString>;
|
|
170
176
|
}, z.core.$strip>>>;
|
|
171
177
|
}, z.core.$strip>, z.ZodObject<{
|
|
172
178
|
kind: z.ZodLiteral<"other">;
|
|
@@ -195,6 +201,9 @@ export declare const agentEventSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
195
201
|
}>>, z.ZodObject<{
|
|
196
202
|
sessionId: z.ZodString;
|
|
197
203
|
}, z.core.$strict>]>;
|
|
204
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
205
|
+
type: z.ZodLiteral<"model">;
|
|
206
|
+
model: z.ZodOptional<z.ZodString>;
|
|
198
207
|
}, z.core.$strip>, z.ZodObject<{
|
|
199
208
|
type: z.ZodLiteral<"assistant">;
|
|
200
209
|
text: z.ZodString;
|
|
@@ -241,6 +250,7 @@ export declare const agentEventSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
241
250
|
added: z.ZodNumber;
|
|
242
251
|
removed: z.ZodNumber;
|
|
243
252
|
}, z.core.$strip>>;
|
|
253
|
+
patch: z.ZodOptional<z.ZodString>;
|
|
244
254
|
}, z.core.$strip>>>;
|
|
245
255
|
}, z.core.$strip>, z.ZodObject<{
|
|
246
256
|
kind: z.ZodLiteral<"other">;
|
|
@@ -259,6 +269,7 @@ export declare const agentEventSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
259
269
|
ok: "ok";
|
|
260
270
|
}>;
|
|
261
271
|
message: z.ZodOptional<z.ZodString>;
|
|
272
|
+
output: z.ZodOptional<z.ZodString>;
|
|
262
273
|
exitCode: z.ZodOptional<z.ZodNumber>;
|
|
263
274
|
}, z.core.$strip>;
|
|
264
275
|
type: z.ZodLiteral<"tool">;
|
|
@@ -296,6 +307,7 @@ export declare const agentEventSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
296
307
|
added: z.ZodNumber;
|
|
297
308
|
removed: z.ZodNumber;
|
|
298
309
|
}, z.core.$strip>>;
|
|
310
|
+
patch: z.ZodOptional<z.ZodString>;
|
|
299
311
|
}, z.core.$strip>>>;
|
|
300
312
|
}, z.core.$strip>, z.ZodObject<{
|
|
301
313
|
kind: z.ZodLiteral<"other">;
|
|
@@ -11,6 +11,7 @@ export const fileChangeSchema = z.object({
|
|
|
11
11
|
op: z.enum(["add", "update", "delete", "unspecified"]),
|
|
12
12
|
path: text,
|
|
13
13
|
diffstat: diffstatSchema.optional(),
|
|
14
|
+
patch: text.optional(),
|
|
14
15
|
});
|
|
15
16
|
export const toolCallSchema = z.union([
|
|
16
17
|
z.object({ kind: z.literal("run"), command: text }),
|
|
@@ -33,6 +34,7 @@ export const toolCallSchema = z.union([
|
|
|
33
34
|
export const toolResultSchema = z.object({
|
|
34
35
|
status: z.enum(["ok", "error"]),
|
|
35
36
|
message: text.optional(),
|
|
37
|
+
output: text.optional(),
|
|
36
38
|
exitCode: z.number().int().safe().optional(),
|
|
37
39
|
});
|
|
38
40
|
const toolFields = { type: z.literal("tool"), id: text, name: text, call: toolCallSchema, truncated };
|
|
@@ -42,6 +44,10 @@ const toolEventSchema = z.union([
|
|
|
42
44
|
]);
|
|
43
45
|
export const agentEventSchema = z.union([
|
|
44
46
|
z.object({ type: z.literal("session"), coordinate: resumeCoordinateSchema }),
|
|
47
|
+
// One provider-neutral runtime-model observation in the shared agent-event
|
|
48
|
+
// vocabulary. Body admits it into the Soul's single current model; it is
|
|
49
|
+
// never appended to activity, so compaction cannot lose or resurrect it.
|
|
50
|
+
z.object({ type: z.literal("model"), model: text.optional() }),
|
|
45
51
|
z.object({ type: z.literal("assistant"), text, truncated }),
|
|
46
52
|
z.object({ type: z.literal("thought"), text, truncated }),
|
|
47
53
|
toolEventSchema,
|
|
@@ -2,6 +2,7 @@ import type { AkumaPaths } from "../identity.js";
|
|
|
2
2
|
import type { BodyEnd, BodyFact, ForkPoint, HeartSnapshot, KillFact, SealFact, SessionFact, Soul, TellDeliveryInput, TellFact, TellReceiptInput, TurnEndFact, TurnFact, TurnOutcome, TurnStartFact } from "./facts.js";
|
|
3
3
|
import type { AgentEvent } from "./activity-schema.js";
|
|
4
4
|
import { type StatusFactInput, type ActivityFactSlice } from "./timeline.js";
|
|
5
|
+
import { type HeartRead } from "./storage.js";
|
|
5
6
|
export { HeartAbsentError, HeldAkumaLeash, classifyHeartSchema, initializeHeart, isHeartAbsent, probeLeash, } from "./storage.js";
|
|
6
7
|
export { admitRequest, beginRequest, isRequestInputConflict, readNonterminalRequests, readRequest, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, unproveRequest, voidRequest, } from "./request-authority.js";
|
|
7
8
|
export { AkumaBusyError, life, lifeAt, projectTell } from "./facts.js";
|
|
@@ -19,10 +20,61 @@ export declare function appendActivity(paths: AkumaPaths, input: Readonly<{
|
|
|
19
20
|
}>): Promise<number>;
|
|
20
21
|
type ActivitySlice = ActivityFactSlice;
|
|
21
22
|
export type { TimelineFact } from "./timeline.js";
|
|
23
|
+
export type CurrentModelUpdate = "recorded" | "unchanged" | "not-current-body";
|
|
24
|
+
/**
|
|
25
|
+
* Admit one runtime-model observation from the Body that is actually running.
|
|
26
|
+
* The model is the one mutable member of an otherwise frozen recipe, so only
|
|
27
|
+
* the exact latest Running Body may move it: evidence that arrives after that
|
|
28
|
+
* Body settled, or from a superseded Body, is refused rather than applied.
|
|
29
|
+
*/
|
|
30
|
+
export declare function recordCurrentModel(paths: AkumaPaths, input: Readonly<{
|
|
31
|
+
bodySequence: number;
|
|
32
|
+
model: string | undefined;
|
|
33
|
+
}>): Promise<CurrentModelUpdate>;
|
|
22
34
|
export declare function activitySlice(paths: AkumaPaths): Promise<ActivitySlice>;
|
|
23
35
|
export declare function readStatusFacts(paths: AkumaPaths, input: StatusFactInput, signal?: AbortSignal): Promise<ActivitySlice["rows"]>;
|
|
24
|
-
/** One live observation's
|
|
36
|
+
/** One live observation's current retained timeline, or a no-change witness. */
|
|
37
|
+
export type TimelineRead = Readonly<{
|
|
38
|
+
changed: false;
|
|
39
|
+
}> | Readonly<{
|
|
40
|
+
changed: true;
|
|
41
|
+
born: boolean;
|
|
42
|
+
slice: ActivityFactSlice;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* One operation-owned reader of the retained timeline. It keeps its read
|
|
46
|
+
* custody between observations, skips decoding when the same connection's
|
|
47
|
+
* change counter still names the observed snapshot, and renews that gate
|
|
48
|
+
* whenever a replaced Heart gives it a new connection.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createTimelineReader(paths: AkumaPaths): Readonly<{
|
|
51
|
+
read(signal?: AbortSignal): Promise<TimelineRead>;
|
|
52
|
+
clear(): void;
|
|
53
|
+
}>;
|
|
54
|
+
/** One observer owns its connection and successful decoded frontier. */
|
|
25
55
|
export declare function createStatusFactReader(paths: AkumaPaths): {
|
|
56
|
+
life: (signal?: AbortSignal) => Promise<LifeSnapshot>;
|
|
57
|
+
tellOutcome: (id: string, signal?: AbortSignal) => Promise<{
|
|
58
|
+
tell: Readonly<{
|
|
59
|
+
kind: "tell";
|
|
60
|
+
sequence: number;
|
|
61
|
+
id: string;
|
|
62
|
+
body: string;
|
|
63
|
+
initiator?: string;
|
|
64
|
+
schemaJson?: string;
|
|
65
|
+
recordedAt: string;
|
|
66
|
+
state: "pending" | "told";
|
|
67
|
+
deliveries: readonly import("./facts.js").TellDelivery[];
|
|
68
|
+
binding?: import("./facts.js").TellBinding;
|
|
69
|
+
}> | null;
|
|
70
|
+
end: Readonly<{
|
|
71
|
+
kind: "turn-end";
|
|
72
|
+
sequence: number;
|
|
73
|
+
turnSequence: number;
|
|
74
|
+
outcome: TurnOutcome;
|
|
75
|
+
completedAt: string;
|
|
76
|
+
}> | undefined;
|
|
77
|
+
}>;
|
|
26
78
|
clear(): void;
|
|
27
79
|
read(input: StatusFactInput, signal?: AbortSignal): Promise<ActivitySlice["rows"]>;
|
|
28
80
|
};
|
|
@@ -30,7 +82,7 @@ type LifeSnapshot = Pick<HeartSnapshot, "soul" | "latestBody" | "latestSession"
|
|
|
30
82
|
hasPendingTell: boolean;
|
|
31
83
|
}>;
|
|
32
84
|
/** Lifecycle probes do not load narration, Tell bodies, or delivery histories. */
|
|
33
|
-
export declare function readLifeSnapshot(paths: AkumaPaths, signal?: AbortSignal): Promise<LifeSnapshot>;
|
|
85
|
+
export declare function readLifeSnapshot(paths: AkumaPaths, signal?: AbortSignal, read?: HeartRead): Promise<LifeSnapshot>;
|
|
34
86
|
export declare function recordTell(paths: AkumaPaths, tell: Omit<TellFact, "sequence" | "state" | "deliveries" | "binding">, options?: Readonly<{
|
|
35
87
|
interrupt?: boolean;
|
|
36
88
|
}>): Promise<Readonly<{
|
|
@@ -111,6 +163,11 @@ export declare function finishBodyIfIdle(paths: AkumaPaths, input: Readonly<{
|
|
|
111
163
|
kind: "pending";
|
|
112
164
|
tells: readonly string[];
|
|
113
165
|
}>>;
|
|
166
|
+
export type BodyControlSnapshot = Pick<HeartSnapshot, "soul" | "pending" | "stop" | "pause">;
|
|
167
|
+
export declare function createBodyHeartReader(paths: AkumaPaths): {
|
|
168
|
+
clear: () => void;
|
|
169
|
+
read(): Promise<BodyControlSnapshot>;
|
|
170
|
+
};
|
|
114
171
|
export declare function readHeart(paths: AkumaPaths): Promise<HeartSnapshot>;
|
|
115
172
|
export declare function readLastAnsweredTurn(paths: AkumaPaths): Promise<TurnFact | null>;
|
|
116
173
|
export declare function readForkPoint(paths: AkumaPaths, historyId: string): Promise<ForkPoint | null>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { parsePublicHistoryId } from "../identity.js";
|
|
2
|
+
import { decodeRuntimeModel, withoutModel } from "../provider-recipe.js";
|
|
2
3
|
import { answeredTurnFact, endBodyFact, finishBodyFact, deleteStopControl, insertActivityFact, insertTurnEndFact, insertTurnStartFact, insertPauseControl, insertKillFact, insertSessionFact, insertStopControl, killFactForBody, latestBodyFact, latestKillFact, latestSessionFact, latestTurnFactForBody, lastAnsweredTurnFact, pauseFact, sessionFactForCoordinate, stopFact, turnFact, } from "./rows.js";
|
|
3
4
|
import { insertTellDeliveryFact, dispositionSnapshotProven, insertTellBindingFact, insertTellDispositionSnapshot, insertTellReceiptFact, insertUndeliveredTellReceipts, latestOpenTellDisposition, openBoundTurns, openTellDispositionIds, pendingTellFacts, hasPendingTell, resolveTellDispositionSnapshot, tellDispositionResolved, tellFact, tellIdsForFence, turnParticipants, } from "./tells.js";
|
|
4
|
-
import { activityFactSlice, statusFacts, readStatusBatch, decodeTimelineBatch, lastActivityAt as readLastActivityAt, pruneActivityFacts, } from "./timeline.js";
|
|
5
|
-
import { isHeartAbsent, readSealFromLeash, recordPendingTell, withHeartTransaction, withReadOnlyHeart, } from "./storage.js";
|
|
6
|
-
import { soulFact } from "./soul.js";
|
|
5
|
+
import { activityFactSlice, statusFacts, readStatusBatch, decodeTimelineBatch, timelineDataVersion, lastActivityAt as readLastActivityAt, pruneActivityFacts, } from "./timeline.js";
|
|
6
|
+
import { createHeartReader, isHeartAbsent, readSealFromLeash, recordPendingTell, withHeartTransaction, withReadOnlyHeart, } from "./storage.js";
|
|
7
|
+
import { setSoulModel, soulFact } from "./soul.js";
|
|
7
8
|
import { AkumaBusyError, HeartAuthorityCorruptionError } from "./facts.js";
|
|
8
9
|
export { HeartAbsentError, HeldAkumaLeash, classifyHeartSchema, initializeHeart, isHeartAbsent, probeLeash, } from "./storage.js";
|
|
9
10
|
export { admitRequest, beginRequest, isRequestInputConflict, readNonterminalRequests, readRequest, refuseRequest, reserveRequest, serveRequest, serveUpstreamRequest, unproveRequest, voidRequest, } from "./request-authority.js";
|
|
@@ -50,12 +51,57 @@ export async function appendActivity(paths, input) {
|
|
|
50
51
|
return sequence;
|
|
51
52
|
});
|
|
52
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Admit one runtime-model observation from the Body that is actually running.
|
|
56
|
+
* The model is the one mutable member of an otherwise frozen recipe, so only
|
|
57
|
+
* the exact latest Running Body may move it: evidence that arrives after that
|
|
58
|
+
* Body settled, or from a superseded Body, is refused rather than applied.
|
|
59
|
+
*/
|
|
60
|
+
export async function recordCurrentModel(paths, input) {
|
|
61
|
+
const model = decodeRuntimeModel(input.model);
|
|
62
|
+
return await withHeartTransaction(paths, (heart) => {
|
|
63
|
+
const body = latestBodyFact(heart);
|
|
64
|
+
if (body === null || body.sequence !== input.bodySequence || body.end !== undefined || body.hung !== undefined) {
|
|
65
|
+
return "not-current-body";
|
|
66
|
+
}
|
|
67
|
+
return setSoulModel(heart, model) ? "recorded" : "unchanged";
|
|
68
|
+
});
|
|
69
|
+
}
|
|
53
70
|
export async function activitySlice(paths) {
|
|
54
71
|
return await withReadOnlyHeart(paths, (heart) => activityFactSlice(heart));
|
|
55
72
|
}
|
|
56
73
|
export async function readStatusFacts(paths, input, signal) {
|
|
57
74
|
return await withReadOnlyHeart(paths, (heart) => statusFacts(heart, input), signal);
|
|
58
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* One operation-owned reader of the retained timeline. It keeps its read
|
|
78
|
+
* custody between observations, skips decoding when the same connection's
|
|
79
|
+
* change counter still names the observed snapshot, and renews that gate
|
|
80
|
+
* whenever a replaced Heart gives it a new connection.
|
|
81
|
+
*/
|
|
82
|
+
export function createTimelineReader(paths) {
|
|
83
|
+
const reader = createHeartReader(paths);
|
|
84
|
+
let generation = -1;
|
|
85
|
+
let version;
|
|
86
|
+
return {
|
|
87
|
+
clear: reader.clear,
|
|
88
|
+
async read(signal) {
|
|
89
|
+
// Publication follows COMMIT, so a failed read never leaves a memo behind.
|
|
90
|
+
return await reader.read((heart) => {
|
|
91
|
+
const current = reader.generation();
|
|
92
|
+
if (current !== generation) {
|
|
93
|
+
generation = current;
|
|
94
|
+
version = undefined;
|
|
95
|
+
}
|
|
96
|
+
const observed = timelineDataVersion(heart);
|
|
97
|
+
if (version !== undefined && observed === version)
|
|
98
|
+
return { changed: false };
|
|
99
|
+
version = observed;
|
|
100
|
+
return { changed: true, born: soulFact(heart) !== null, slice: activityFactSlice(heart) };
|
|
101
|
+
}, signal);
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
59
105
|
// Each query returns a fixed set of scalar columns; compare JSON columns as text.
|
|
60
106
|
function sameRawRows(left, right) {
|
|
61
107
|
if (left.length !== right.length)
|
|
@@ -75,16 +121,24 @@ function sameStatusBatch(left, right) {
|
|
|
75
121
|
sameRawRows(left.tells.deliveries, right.tells.deliveries) &&
|
|
76
122
|
sameRawRows(left.tells.bindings, right.tells.bindings));
|
|
77
123
|
}
|
|
78
|
-
/** One
|
|
124
|
+
/** One observer owns its connection and successful decoded frontier. */
|
|
79
125
|
export function createStatusFactReader(paths) {
|
|
126
|
+
const reader = createHeartReader(paths);
|
|
80
127
|
let memo;
|
|
81
128
|
return {
|
|
129
|
+
life: (signal) => readLifeSnapshot(paths, signal, reader.read),
|
|
130
|
+
tellOutcome: (id, signal) => reader.read((heart) => {
|
|
131
|
+
const tell = tellFact(heart, id);
|
|
132
|
+
const end = tell?.binding === undefined ? undefined : turnFact(heart, tell.binding.turnSequence)?.end;
|
|
133
|
+
return { tell, end };
|
|
134
|
+
}, signal),
|
|
82
135
|
clear() {
|
|
136
|
+
reader.clear();
|
|
83
137
|
memo = undefined;
|
|
84
138
|
},
|
|
85
139
|
async read(input, signal) {
|
|
86
140
|
try {
|
|
87
|
-
const next = await
|
|
141
|
+
const next = await reader.read((heart) => {
|
|
88
142
|
const batch = readStatusBatch(heart, input);
|
|
89
143
|
if (memo !== undefined && sameStatusBatch(batch, memo.batch))
|
|
90
144
|
return memo;
|
|
@@ -95,6 +149,7 @@ export function createStatusFactReader(paths) {
|
|
|
95
149
|
return next.facts;
|
|
96
150
|
}
|
|
97
151
|
catch (error) {
|
|
152
|
+
reader.clear();
|
|
98
153
|
memo = undefined;
|
|
99
154
|
throw error;
|
|
100
155
|
}
|
|
@@ -102,9 +157,9 @@ export function createStatusFactReader(paths) {
|
|
|
102
157
|
};
|
|
103
158
|
}
|
|
104
159
|
/** Lifecycle probes do not load narration, Tell bodies, or delivery histories. */
|
|
105
|
-
export async function readLifeSnapshot(paths, signal) {
|
|
160
|
+
export async function readLifeSnapshot(paths, signal, read = (body, signal) => withReadOnlyHeart(paths, body, signal)) {
|
|
106
161
|
try {
|
|
107
|
-
return await
|
|
162
|
+
return await read((heart) => ({
|
|
108
163
|
soul: soulFact(heart),
|
|
109
164
|
latestBody: latestBodyFact(heart),
|
|
110
165
|
latestSession: latestSessionFact(heart),
|
|
@@ -321,6 +376,27 @@ export async function finishBodyIfIdle(paths, input) {
|
|
|
321
376
|
return { kind: "finished" };
|
|
322
377
|
});
|
|
323
378
|
}
|
|
379
|
+
export function createBodyHeartReader(paths) {
|
|
380
|
+
const reader = createHeartReader(paths);
|
|
381
|
+
return {
|
|
382
|
+
clear: reader.clear,
|
|
383
|
+
async read() {
|
|
384
|
+
try {
|
|
385
|
+
return await reader.read((heart) => ({
|
|
386
|
+
soul: soulFact(heart),
|
|
387
|
+
pending: pendingTellFacts(heart),
|
|
388
|
+
stop: stopFact(heart),
|
|
389
|
+
pause: pauseFact(heart),
|
|
390
|
+
}));
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
if (isHeartAbsent(error))
|
|
394
|
+
return { soul: null, pending: [], stop: null, pause: null };
|
|
395
|
+
throw error;
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
}
|
|
324
400
|
export async function readHeart(paths) {
|
|
325
401
|
try {
|
|
326
402
|
return await withReadOnlyHeart(paths, (heart) => ({
|
|
@@ -366,12 +442,15 @@ export async function readForkPoint(paths, historyId) {
|
|
|
366
442
|
const recipe = sessionFactForCoordinate(heart, outcome.session);
|
|
367
443
|
if (recipe === null)
|
|
368
444
|
throw new Error(`Akuma fork point ${historyId} has no session recipe`);
|
|
445
|
+
// The source's current model is the admitted child selection. The session
|
|
446
|
+
// row's obsolete copy is dropped, and an absent current model stays absent.
|
|
447
|
+
const current = soulFact(heart)?.options.model;
|
|
369
448
|
return {
|
|
370
449
|
historyId: outcome.historyId,
|
|
371
450
|
session: outcome.session,
|
|
372
451
|
provider: recipe.provider,
|
|
373
452
|
cwd: recipe.cwd,
|
|
374
|
-
options: recipe.options,
|
|
453
|
+
options: { ...withoutModel(recipe.options), ...(current === undefined ? {} : { model: current }) },
|
|
375
454
|
};
|
|
376
455
|
});
|
|
377
456
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { providerOptionsSchema } from "../provider-recipe.js";
|
|
2
|
+
import { providerOptionsSchema, withoutModel } from "../provider-recipe.js";
|
|
3
3
|
import { resumeCoordinateSchema } from "../coordinate.js";
|
|
4
4
|
import { decodeResumeCoordinate, encodeResumeCoordinate as encodeCoordinate } from "../coordinate.js";
|
|
5
5
|
import { agentEventSchema } from "./activity-schema.js";
|
|
@@ -32,7 +32,7 @@ export function encodeSessionRow(session) {
|
|
|
32
32
|
session.provider,
|
|
33
33
|
encodeResumeCoordinate(session.coordinate),
|
|
34
34
|
session.cwd,
|
|
35
|
-
json(session.options),
|
|
35
|
+
json(withoutModel(session.options)),
|
|
36
36
|
session.admittedAt,
|
|
37
37
|
];
|
|
38
38
|
}
|
|
@@ -45,7 +45,9 @@ export function decodeSessionRow(row) {
|
|
|
45
45
|
provider: row.provider,
|
|
46
46
|
coordinate: resumeCoordinate(parsed(row.coordinate_json)),
|
|
47
47
|
cwd: row.cwd,
|
|
48
|
-
|
|
48
|
+
// A session's own model copy is obsolete: the Soul owns the one current
|
|
49
|
+
// model, so an old row never re-admits the model it happened to start with.
|
|
50
|
+
options: withoutModel(parsed(row.options_json)),
|
|
49
51
|
admittedAt: row.admitted_at,
|
|
50
52
|
};
|
|
51
53
|
}
|
|
@@ -7,3 +7,12 @@ export declare function encodeSoulRow(soul: Soul): readonly [string];
|
|
|
7
7
|
export declare function decodeSoulRow(row: SoulRow): Soul;
|
|
8
8
|
export declare function soulFact(database: DatabaseSync): Soul | null;
|
|
9
9
|
export declare function insertSoulFact(database: DatabaseSync, soul: Soul): void;
|
|
10
|
+
/**
|
|
11
|
+
* Replace only the current-model member of the singleton Soul and report
|
|
12
|
+
* whether the stored value actually moved. Every other raw member is carried
|
|
13
|
+
* through byte-identically: the codec normalizes recipe options, origin and
|
|
14
|
+
* allowed, so decoding and re-encoding a whole Soul here would silently
|
|
15
|
+
* rewrite fields this update never touched. A Soul this build cannot read is
|
|
16
|
+
* refused rather than mutated.
|
|
17
|
+
*/
|
|
18
|
+
export declare function setSoulModel(database: DatabaseSync, model: string | undefined): boolean;
|
|
@@ -78,3 +78,32 @@ export function soulFact(database) {
|
|
|
78
78
|
export function insertSoulFact(database, soul) {
|
|
79
79
|
database.prepare("INSERT INTO soul(singleton, soul_json) VALUES (1, ?)").run(...encodeSoulRow(soul));
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Replace only the current-model member of the singleton Soul and report
|
|
83
|
+
* whether the stored value actually moved. Every other raw member is carried
|
|
84
|
+
* through byte-identically: the codec normalizes recipe options, origin and
|
|
85
|
+
* allowed, so decoding and re-encoding a whole Soul here would silently
|
|
86
|
+
* rewrite fields this update never touched. A Soul this build cannot read is
|
|
87
|
+
* refused rather than mutated.
|
|
88
|
+
*/
|
|
89
|
+
export function setSoulModel(database, model) {
|
|
90
|
+
const row = database.prepare("SELECT soul_json FROM soul WHERE singleton = 1").get();
|
|
91
|
+
if (row === undefined)
|
|
92
|
+
throw new Error("Akuma soul is absent");
|
|
93
|
+
const raw = JSON.parse(row.soul_json);
|
|
94
|
+
decodeSoul(raw);
|
|
95
|
+
const soul = record(raw);
|
|
96
|
+
const options = record(soul.options);
|
|
97
|
+
if (options === null)
|
|
98
|
+
throw new Error("Akuma soul options must be an object");
|
|
99
|
+
const current = options.model;
|
|
100
|
+
if (model === undefined ? current === undefined : current === model)
|
|
101
|
+
return false;
|
|
102
|
+
const next = { ...options };
|
|
103
|
+
if (model === undefined)
|
|
104
|
+
delete next.model;
|
|
105
|
+
else
|
|
106
|
+
next.model = model;
|
|
107
|
+
database.prepare("UPDATE soul SET soul_json = ? WHERE singleton = 1").run(JSON.stringify({ ...soul, options: next }));
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
@@ -9,6 +9,21 @@ export declare class HeartAbsentError extends Error {
|
|
|
9
9
|
export declare function isHeartAbsent(error: unknown): error is HeartAbsentError;
|
|
10
10
|
export declare function classifyHeartSchema(paths: AkumaPaths): Promise<"current" | "unsupported">;
|
|
11
11
|
export declare function withReadOnlyHeart<T>(paths: AkumaPaths, body: (database: DatabaseSync) => T, signal?: AbortSignal): Promise<T>;
|
|
12
|
+
export type HeartRead = <T>(body: (database: DatabaseSync) => T, signal?: AbortSignal) => Promise<T>;
|
|
13
|
+
export type HeartReader = Readonly<{
|
|
14
|
+
read: HeartRead;
|
|
15
|
+
clear(): void;
|
|
16
|
+
/** Counts opened connections, so a caller's own reuse cannot survive a replaced Heart. */
|
|
17
|
+
generation(): number;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* A bounded observer owns its connection between observations, never a
|
|
21
|
+
* transaction: each read settles the transaction it began, and a removed or
|
|
22
|
+
* replaced Heart invalidates the retained custody through file identity.
|
|
23
|
+
* Release never interrupts an executing read; it settles after the current
|
|
24
|
+
* observation, so a caller may release while a pull is still in flight.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createHeartReader(paths: AkumaPaths): HeartReader;
|
|
12
27
|
export declare function withHeartTransaction<T>(paths: AkumaPaths, body: (database: DatabaseSync) => T, signal?: AbortSignal): Promise<T>;
|
|
13
28
|
/** Insert one already-admitted pending Tell into an already-open Heart transaction. */
|
|
14
29
|
export declare function recordPendingTell(heart: DatabaseSync, tell: Omit<TellFact, "sequence" | "state" | "deliveries" | "binding">): Readonly<{
|
|
@@ -112,6 +112,61 @@ export async function withReadOnlyHeart(paths, body, signal) {
|
|
|
112
112
|
database.close();
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* A bounded observer owns its connection between observations, never a
|
|
117
|
+
* transaction: each read settles the transaction it began, and a removed or
|
|
118
|
+
* replaced Heart invalidates the retained custody through file identity.
|
|
119
|
+
* Release never interrupts an executing read; it settles after the current
|
|
120
|
+
* observation, so a caller may release while a pull is still in flight.
|
|
121
|
+
*/
|
|
122
|
+
export function createHeartReader(paths) {
|
|
123
|
+
let database;
|
|
124
|
+
let identity;
|
|
125
|
+
let tail = Promise.resolve();
|
|
126
|
+
let opened = 0;
|
|
127
|
+
const release = () => {
|
|
128
|
+
const retained = database;
|
|
129
|
+
database = undefined;
|
|
130
|
+
identity = undefined;
|
|
131
|
+
try {
|
|
132
|
+
retained?.close();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// A connection already released by its own failed read stays released.
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const clear = () => {
|
|
139
|
+
tail = tail.then(release, release);
|
|
140
|
+
};
|
|
141
|
+
const read = (body, signal) => {
|
|
142
|
+
const pending = tail.then(async () => {
|
|
143
|
+
try {
|
|
144
|
+
signal?.throwIfAborted();
|
|
145
|
+
const current = await lstat(paths.heart).catch((error) => {
|
|
146
|
+
if (error.code === "ENOENT")
|
|
147
|
+
throw new HeartAbsentError(paths.heart, { cause: error });
|
|
148
|
+
throw error;
|
|
149
|
+
});
|
|
150
|
+
if (identity?.dev !== current.dev || identity?.ino !== current.ino)
|
|
151
|
+
release();
|
|
152
|
+
if (database === undefined) {
|
|
153
|
+
database = await openHeart(paths.heart, "ro");
|
|
154
|
+
identity = current;
|
|
155
|
+
opened += 1;
|
|
156
|
+
}
|
|
157
|
+
await beginTransaction(database, "read", signal);
|
|
158
|
+
return finishTransaction(database, body);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
release();
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
tail = pending.catch(() => undefined);
|
|
166
|
+
return pending;
|
|
167
|
+
};
|
|
168
|
+
return { read, clear, generation: () => opened };
|
|
169
|
+
}
|
|
115
170
|
export async function withHeartTransaction(paths, body, signal) {
|
|
116
171
|
signal?.throwIfAborted();
|
|
117
172
|
const database = await openHeart(paths.heart, "rw");
|