@earendil-works/pi-agent-core 0.85.1 → 0.86.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 +16 -6
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +64 -22
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent.d.ts +5 -3
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +15 -6
- package/dist/agent.js.map +1 -1
- package/dist/harness/config.d.ts +1 -1
- package/dist/harness/config.d.ts.map +1 -1
- package/dist/harness/config.js +10 -2
- package/dist/harness/config.js.map +1 -1
- package/dist/harness/env/nodejs.d.ts +2 -1
- package/dist/harness/env/nodejs.d.ts.map +1 -1
- package/dist/harness/env/nodejs.js +98 -27
- package/dist/harness/env/nodejs.js.map +1 -1
- package/dist/harness/execution/tools.d.ts +1 -1
- package/dist/harness/execution/tools.d.ts.map +1 -1
- package/dist/harness/execution/tools.js +0 -2
- package/dist/harness/execution/tools.js.map +1 -1
- package/dist/harness/messages.d.ts.map +1 -1
- package/dist/harness/messages.js +1 -0
- package/dist/harness/messages.js.map +1 -1
- package/dist/harness/pico3/bash.d.ts +10 -0
- package/dist/harness/pico3/bash.d.ts.map +1 -0
- package/dist/harness/pico3/bash.js +25 -0
- package/dist/harness/pico3/bash.js.map +1 -0
- package/dist/harness/pico3/bounded.d.ts +21 -0
- package/dist/harness/pico3/bounded.d.ts.map +1 -0
- package/dist/harness/pico3/bounded.js +98 -0
- package/dist/harness/pico3/bounded.js.map +1 -0
- package/dist/harness/pico3/chord.d.ts +41 -0
- package/dist/harness/pico3/chord.d.ts.map +1 -0
- package/dist/harness/pico3/chord.js +130 -0
- package/dist/harness/pico3/chord.js.map +1 -0
- package/dist/harness/pico3/context.d.ts +16 -0
- package/dist/harness/pico3/context.d.ts.map +1 -0
- package/dist/harness/pico3/context.js +88 -0
- package/dist/harness/pico3/context.js.map +1 -0
- package/dist/harness/pico3/harness.d.ts +197 -0
- package/dist/harness/pico3/harness.d.ts.map +1 -0
- package/dist/harness/pico3/harness.js +654 -0
- package/dist/harness/pico3/harness.js.map +1 -0
- package/dist/harness/pico3/hooks.d.ts +10 -0
- package/dist/harness/pico3/hooks.d.ts.map +1 -0
- package/dist/harness/pico3/hooks.js +33 -0
- package/dist/harness/pico3/hooks.js.map +1 -0
- package/dist/harness/pico3/index.d.ts +19 -0
- package/dist/harness/pico3/index.d.ts.map +1 -0
- package/dist/harness/pico3/index.js +15 -0
- package/dist/harness/pico3/index.js.map +1 -0
- package/dist/harness/pico3/jsonl.d.ts +58 -0
- package/dist/harness/pico3/jsonl.d.ts.map +1 -0
- package/dist/harness/pico3/jsonl.js +325 -0
- package/dist/harness/pico3/jsonl.js.map +1 -0
- package/dist/harness/pico3/kinds/collapse.d.ts +49 -0
- package/dist/harness/pico3/kinds/collapse.d.ts.map +1 -0
- package/dist/harness/pico3/kinds/collapse.js +191 -0
- package/dist/harness/pico3/kinds/collapse.js.map +1 -0
- package/dist/harness/pico3/kinds/entries.d.ts +78 -0
- package/dist/harness/pico3/kinds/entries.d.ts.map +1 -0
- package/dist/harness/pico3/kinds/entries.js +13 -0
- package/dist/harness/pico3/kinds/entries.js.map +1 -0
- package/dist/harness/pico3/kinds/frames.d.ts +9 -0
- package/dist/harness/pico3/kinds/frames.d.ts.map +1 -0
- package/dist/harness/pico3/kinds/frames.js +75 -0
- package/dist/harness/pico3/kinds/frames.js.map +1 -0
- package/dist/harness/pico3/kinds/generation.d.ts +94 -0
- package/dist/harness/pico3/kinds/generation.d.ts.map +1 -0
- package/dist/harness/pico3/kinds/generation.js +504 -0
- package/dist/harness/pico3/kinds/generation.js.map +1 -0
- package/dist/harness/pico3/kinds/job.d.ts +44 -0
- package/dist/harness/pico3/kinds/job.d.ts.map +1 -0
- package/dist/harness/pico3/kinds/job.js +143 -0
- package/dist/harness/pico3/kinds/job.js.map +1 -0
- package/dist/harness/pico3/kinds/plugin.d.ts +15 -0
- package/dist/harness/pico3/kinds/plugin.d.ts.map +1 -0
- package/dist/harness/pico3/kinds/plugin.js +35 -0
- package/dist/harness/pico3/kinds/plugin.js.map +1 -0
- package/dist/harness/pico3/kinds/post-tools.d.ts +22 -0
- package/dist/harness/pico3/kinds/post-tools.d.ts.map +1 -0
- package/dist/harness/pico3/kinds/post-tools.js +145 -0
- package/dist/harness/pico3/kinds/post-tools.js.map +1 -0
- package/dist/harness/pico3/kinds/task-api.d.ts +3 -0
- package/dist/harness/pico3/kinds/task-api.d.ts.map +1 -0
- package/dist/harness/pico3/kinds/task-api.js +45 -0
- package/dist/harness/pico3/kinds/task-api.js.map +1 -0
- package/dist/harness/pico3/kinds/tool.d.ts +43 -0
- package/dist/harness/pico3/kinds/tool.d.ts.map +1 -0
- package/dist/harness/pico3/kinds/tool.js +373 -0
- package/dist/harness/pico3/kinds/tool.js.map +1 -0
- package/dist/harness/pico3/membrane.d.ts +23 -0
- package/dist/harness/pico3/membrane.d.ts.map +1 -0
- package/dist/harness/pico3/membrane.js +141 -0
- package/dist/harness/pico3/membrane.js.map +1 -0
- package/dist/harness/pico3/memory.d.ts +53 -0
- package/dist/harness/pico3/memory.d.ts.map +1 -0
- package/dist/harness/pico3/memory.js +264 -0
- package/dist/harness/pico3/memory.js.map +1 -0
- package/dist/harness/pico3/scheduler.d.ts +46 -0
- package/dist/harness/pico3/scheduler.d.ts.map +1 -0
- package/dist/harness/pico3/scheduler.js +438 -0
- package/dist/harness/pico3/scheduler.js.map +1 -0
- package/dist/harness/pico3/session.d.ts +263 -0
- package/dist/harness/pico3/session.d.ts.map +1 -0
- package/dist/harness/pico3/session.js +1347 -0
- package/dist/harness/pico3/session.js.map +1 -0
- package/dist/harness/pico3/system.d.ts +126 -0
- package/dist/harness/pico3/system.d.ts.map +1 -0
- package/dist/harness/pico3/system.js +244 -0
- package/dist/harness/pico3/system.js.map +1 -0
- package/dist/harness/pico3/types.d.ts +973 -0
- package/dist/harness/pico3/types.d.ts.map +1 -0
- package/dist/harness/pico3/types.js +96 -0
- package/dist/harness/pico3/types.js.map +1 -0
- package/dist/harness/pico3/view.d.ts +34 -0
- package/dist/harness/pico3/view.d.ts.map +1 -0
- package/dist/harness/pico3/view.js +417 -0
- package/dist/harness/pico3/view.js.map +1 -0
- package/dist/harness/runtime/drive/boundary.d.ts.map +1 -1
- package/dist/harness/runtime/drive/boundary.js +6 -3
- package/dist/harness/runtime/drive/boundary.js.map +1 -1
- package/dist/harness/runtime/drive/response.d.ts.map +1 -1
- package/dist/harness/runtime/drive/response.js +4 -4
- package/dist/harness/runtime/drive/response.js.map +1 -1
- package/dist/harness/runtime/drive/retry.d.ts +2 -2
- package/dist/harness/runtime/drive/retry.d.ts.map +1 -1
- package/dist/harness/runtime/drive/retry.js +3 -6
- package/dist/harness/runtime/drive/retry.js.map +1 -1
- package/dist/harness/runtime/drive/structural.d.ts.map +1 -1
- package/dist/harness/runtime/drive/structural.js +5 -5
- package/dist/harness/runtime/drive/structural.js.map +1 -1
- package/dist/harness/runtime/drive/tool-placement.d.ts.map +1 -1
- package/dist/harness/runtime/drive/tool-placement.js +2 -27
- package/dist/harness/runtime/drive/tool-placement.js.map +1 -1
- package/dist/harness/runtime/drive/tools.d.ts.map +1 -1
- package/dist/harness/runtime/drive/tools.js.map +1 -1
- package/dist/harness/session/fork-policy.d.ts +20 -12
- package/dist/harness/session/fork-policy.d.ts.map +1 -1
- package/dist/harness/session/fork-policy.js +45 -12
- package/dist/harness/session/fork-policy.js.map +1 -1
- package/dist/harness/session/fork.d.ts +0 -2
- package/dist/harness/session/fork.d.ts.map +1 -1
- package/dist/harness/session/fork.js +20 -68
- package/dist/harness/session/fork.js.map +1 -1
- package/dist/harness/session/in-memory-storage-state.d.ts +5 -5
- package/dist/harness/session/in-memory-storage-state.d.ts.map +1 -1
- package/dist/harness/session/in-memory-storage-state.js +99 -39
- package/dist/harness/session/in-memory-storage-state.js.map +1 -1
- package/dist/harness/session/index.d.ts +1 -1
- package/dist/harness/session/index.d.ts.map +1 -1
- package/dist/harness/session/index.js +1 -1
- package/dist/harness/session/index.js.map +1 -1
- package/dist/harness/session/jsonl/fork.d.ts +38 -0
- package/dist/harness/session/jsonl/fork.d.ts.map +1 -0
- package/dist/harness/session/jsonl/fork.js +264 -0
- package/dist/harness/session/jsonl/fork.js.map +1 -0
- package/dist/harness/session/jsonl/io.d.ts +14 -0
- package/dist/harness/session/jsonl/io.d.ts.map +1 -0
- package/dist/harness/session/jsonl/io.js +86 -0
- package/dist/harness/session/jsonl/io.js.map +1 -0
- package/dist/harness/session/jsonl/legacy-v3.d.ts +33 -8
- package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -1
- package/dist/harness/session/jsonl/legacy-v3.js +285 -206
- package/dist/harness/session/jsonl/legacy-v3.js.map +1 -1
- package/dist/harness/session/jsonl/repo.d.ts +2 -1
- package/dist/harness/session/jsonl/repo.d.ts.map +1 -1
- package/dist/harness/session/jsonl/repo.js +36 -20
- package/dist/harness/session/jsonl/repo.js.map +1 -1
- package/dist/harness/session/jsonl/storage.d.ts +4 -5
- package/dist/harness/session/jsonl/storage.d.ts.map +1 -1
- package/dist/harness/session/jsonl/storage.js +39 -113
- package/dist/harness/session/jsonl/storage.js.map +1 -1
- package/dist/harness/session/memory.d.ts +3 -5
- package/dist/harness/session/memory.d.ts.map +1 -1
- package/dist/harness/session/memory.js +9 -14
- package/dist/harness/session/memory.js.map +1 -1
- package/dist/harness/session/testing/conformance/session-repo.d.ts +2 -0
- package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -1
- package/dist/harness/session/testing/conformance/session-repo.js +220 -1
- package/dist/harness/session/testing/conformance/session-repo.js.map +1 -1
- package/dist/harness/session/testing/index.d.ts +1 -1
- package/dist/harness/session/testing/index.d.ts.map +1 -1
- package/dist/harness/session/testing/index.js +1 -1
- package/dist/harness/session/testing/index.js.map +1 -1
- package/dist/harness/session/types.d.ts +1 -0
- package/dist/harness/session/types.d.ts.map +1 -1
- package/dist/harness/session/types.js.map +1 -1
- package/dist/harness/types.d.ts +14 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/proxy.d.ts +2 -2
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js.map +1 -1
- package/dist/types.d.ts +30 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -6
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
import { AssistantMessageFrameEncoder, isRetryableAssistantError } from "@earendil-works/pi-ai";
|
|
2
|
+
import { estimateContextTokens } from "@earendil-works/pi-ai/utils/estimate";
|
|
3
|
+
import { planManagedEntry, prepareDraft, sameSnapshot, takeSnapshot } from "../system.js";
|
|
4
|
+
import { toStored, } from "../types.js";
|
|
5
|
+
import { chooseThrough } from "./collapse.js";
|
|
6
|
+
import { applyFrame } from "./frames.js";
|
|
7
|
+
/** Configuration this kind reads, with defaults. `model` has none: absent → failed/no_model. */
|
|
8
|
+
export const generationConfig = {
|
|
9
|
+
rewindable: {
|
|
10
|
+
model: undefined,
|
|
11
|
+
thinkingLevel: "off",
|
|
12
|
+
selectedTools: [],
|
|
13
|
+
profile: "default",
|
|
14
|
+
},
|
|
15
|
+
sticky: { retry: { enabled: true, maxRetries: 3, baseDelayMs: 2000, maxAgentDelayMs: 60_000 } },
|
|
16
|
+
};
|
|
17
|
+
const fail = (reason, detail, assistant) => ({
|
|
18
|
+
status: "failed",
|
|
19
|
+
failure: { reason, detail, ...(assistant === undefined ? {} : { assistant }) },
|
|
20
|
+
});
|
|
21
|
+
/** Every terminal generation failure settles its group and admits queued triggers at the final boundary. */
|
|
22
|
+
const failStep = (task, reason, detail) => ({
|
|
23
|
+
done: async (tx, current) => {
|
|
24
|
+
const head = await tx.newestEntry(current.conversationId, { withHead: true });
|
|
25
|
+
tx.emit({ type: "generation.failed", taskId: current.id, reason, detail });
|
|
26
|
+
await settleFailedTurn(tx, current, task.input.inputs, detail, head?.id);
|
|
27
|
+
return fail(reason, detail);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
/** pi-ai drops system messages and aborted/error assistant messages before sending; estimate what is sent. */
|
|
31
|
+
const estimate = (messages) => estimateContextTokens(messages.filter((m) => m.role !== "system" &&
|
|
32
|
+
!(m.role === "assistant" && (m.stopReason === "aborted" || m.stopReason === "error")))).tokens;
|
|
33
|
+
const emptyUsage = () => ({
|
|
34
|
+
input: 0,
|
|
35
|
+
output: 0,
|
|
36
|
+
cacheRead: 0,
|
|
37
|
+
cacheWrite: 0,
|
|
38
|
+
totalTokens: 0,
|
|
39
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
40
|
+
});
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// The kind
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
export const generation = {
|
|
45
|
+
name: "pi.generation",
|
|
46
|
+
turn: true,
|
|
47
|
+
config: generationConfig,
|
|
48
|
+
inflight: ["requesting"],
|
|
49
|
+
// Step 1 (§12.5): snapshot S on the line; systemInstructions off the line; then in one
|
|
50
|
+
// commit re-take S′, retry if it moved, else append the managed entry and checkpoint
|
|
51
|
+
// `prepared` with the cutoff. Runs once per generation; never on recovery.
|
|
52
|
+
async initial(task, rt, ctx) {
|
|
53
|
+
const { snapshot, canonical, seed } = await rt.commit((tx, current) => takeSnapshot(tx, current.conversationId, rt.registries.sections, rt.registries.tools), ctx);
|
|
54
|
+
if (snapshot.settings.model === undefined)
|
|
55
|
+
return failStep(task, "no_model", "no model configured");
|
|
56
|
+
const retry = (await rt.sticky(task.conversationId, ctx)).retry;
|
|
57
|
+
const warnings = [];
|
|
58
|
+
const { desired, tools } = await prepareDraft(rt, rt.registries.sections, canonical, seed, snapshot.settings, (message) => warnings.push(message), ctx);
|
|
59
|
+
const model = snapshot.settings.model;
|
|
60
|
+
const thinkingLevel = snapshot.settings.thinkingLevel;
|
|
61
|
+
return {
|
|
62
|
+
next: async (tx, current) => {
|
|
63
|
+
const c = current.conversationId;
|
|
64
|
+
const again = await takeSnapshot(tx, c, rt.registries.sections, rt.registries.tools);
|
|
65
|
+
if (!sameSnapshot(again.snapshot, snapshot))
|
|
66
|
+
return "retry";
|
|
67
|
+
const plan = await planManagedEntry(tx, c, snapshot, canonical, desired, tools, rt.now());
|
|
68
|
+
for (const message of warnings)
|
|
69
|
+
tx.emit({ type: "warning", source: "generation", message });
|
|
70
|
+
const system = plan === undefined ? null : tx.appendEntry(c, { kind: "pi.system", ...plan });
|
|
71
|
+
const cutoff = system ?? (await tx.newestEntry(c)).id;
|
|
72
|
+
tx.sticky(c).turn = { tools: [] }; // a new generation starts a fresh turn view
|
|
73
|
+
return {
|
|
74
|
+
phase: "prepared",
|
|
75
|
+
cutoff,
|
|
76
|
+
system,
|
|
77
|
+
model,
|
|
78
|
+
thinkingLevel,
|
|
79
|
+
tools: tools.map((t) => t.name),
|
|
80
|
+
retry,
|
|
81
|
+
attempt: 0,
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
phases: {
|
|
87
|
+
// Step 2: derive the request from the cutoff (hooks rerun), overflow check, write the
|
|
88
|
+
// in-flight checkpoint, call the provider. Reached fresh from `initial`/`retrying`,
|
|
89
|
+
// and again on recovery of `prepared` (step 1 never reruns).
|
|
90
|
+
async prepared(task, rt, ctx) {
|
|
91
|
+
const cp = task.checkpoint;
|
|
92
|
+
const model = rt.models.resolve(cp.model);
|
|
93
|
+
if (model === undefined)
|
|
94
|
+
return failStep(task, "no_model", `model ${cp.model.provider}/${cp.model.modelId} unavailable`);
|
|
95
|
+
const derived = await derive(task, cp, rt, ctx);
|
|
96
|
+
if (estimate(derived.messages) > model.contextWindow - model.maxTokens)
|
|
97
|
+
return overflow(task, rt);
|
|
98
|
+
const attempt = cp.attempt + 1;
|
|
99
|
+
await rt.commit((tx) => {
|
|
100
|
+
tx.checkpoint({ ...cp, phase: "requesting", attempt });
|
|
101
|
+
tx.emit({ type: "generation.started", taskId: task.id, attempt });
|
|
102
|
+
}, ctx); // before the effect
|
|
103
|
+
const { terminal, deferred } = await stream(cp, model, derived.messages, rt, ctx);
|
|
104
|
+
if (deferred !== undefined) {
|
|
105
|
+
const pollAt = rt.now() + (deferred.pollAfterMs ?? 5000);
|
|
106
|
+
return {
|
|
107
|
+
next: (tx) => {
|
|
108
|
+
tx.emit({ type: "generation.deferred", taskId: task.id, pollAt });
|
|
109
|
+
return { ...cp, phase: "deferred", attempt, handle: toStored(deferred), pollAt };
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return classify(task, { ...cp, attempt }, terminal, rt, ctx);
|
|
114
|
+
},
|
|
115
|
+
// Only reached by the scheduler after a crash: the call may have happened and there
|
|
116
|
+
// is no result lookup. Count it as a failed attempt and retry per policy.
|
|
117
|
+
async requesting(task, rt) {
|
|
118
|
+
const cp = task.checkpoint;
|
|
119
|
+
const decision = retryDecision(cp, null, rt.now());
|
|
120
|
+
if (decision.kind === "fail")
|
|
121
|
+
return failStep(task, decision.reason, "interrupted");
|
|
122
|
+
return {
|
|
123
|
+
next: (tx, current) => {
|
|
124
|
+
tx.appendEntry(current.conversationId, {
|
|
125
|
+
kind: "pi.usage",
|
|
126
|
+
data: { attempt: cp.attempt, error: "interrupted" },
|
|
127
|
+
});
|
|
128
|
+
tx.emit({
|
|
129
|
+
type: "generation.retrying",
|
|
130
|
+
taskId: current.id,
|
|
131
|
+
attempt: cp.attempt,
|
|
132
|
+
retryAt: decision.untilMs,
|
|
133
|
+
error: "interrupted",
|
|
134
|
+
});
|
|
135
|
+
return { ...cp, phase: "retrying", untilMs: decision.untilMs, lastError: "interrupted" };
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
// Durable backoff, then back to step 2. Resets the streaming view.
|
|
140
|
+
async retrying(task, rt, ctx) {
|
|
141
|
+
const cp = task.checkpoint;
|
|
142
|
+
await rt.sleep(cp.untilMs, ctx);
|
|
143
|
+
const { untilMs: _u, lastError: _e, ...prep } = cp;
|
|
144
|
+
return {
|
|
145
|
+
next: (tx, current) => {
|
|
146
|
+
tx.sticky(current.conversationId).turn.message = undefined;
|
|
147
|
+
return { ...prep, phase: "prepared" };
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
// Provider-side async. Poll; not the retry backoff. Same after a crash: the handle is durable.
|
|
152
|
+
async deferred(task, rt, ctx) {
|
|
153
|
+
const cp = task.checkpoint;
|
|
154
|
+
const model = rt.models.resolve(cp.model);
|
|
155
|
+
if (model === undefined)
|
|
156
|
+
return failStep(task, "no_model", "model disappeared");
|
|
157
|
+
await rt.sleep(cp.pollAt, ctx);
|
|
158
|
+
const result = await rt.models.fetchDeferred(model, cp.handle, ctx);
|
|
159
|
+
if ("deferred" in result && result.deferred !== undefined) {
|
|
160
|
+
const pollAt = rt.now() + (result.deferred.pollAfterMs ?? 5000);
|
|
161
|
+
return {
|
|
162
|
+
next: (tx) => {
|
|
163
|
+
tx.emit({ type: "generation.deferred", taskId: task.id, pollAt });
|
|
164
|
+
return { ...cp, handle: toStored(result.deferred), pollAt };
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
const message = result;
|
|
169
|
+
await rt.commit((tx, current) => {
|
|
170
|
+
tx.sticky(current.conversationId).turn.message = toStored(message);
|
|
171
|
+
}, ctx);
|
|
172
|
+
const { handle: _handle, pollAt: _pollAt, ...prep } = cp;
|
|
173
|
+
return classify(task, prep, message, rt, ctx);
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
async abort(task, rt, ctx) {
|
|
177
|
+
const cp = task.checkpoint;
|
|
178
|
+
if (cp?.phase === "deferred") {
|
|
179
|
+
const model = rt.models.resolve(cp.model);
|
|
180
|
+
if (model)
|
|
181
|
+
await rt.models.cancelDeferred(model, cp.handle, ctx).catch(() => { });
|
|
182
|
+
}
|
|
183
|
+
return async (tx, current) => {
|
|
184
|
+
const partial = tx.sticky(current.conversationId).turn.message;
|
|
185
|
+
let assistant;
|
|
186
|
+
// Display-only: the partial goes in `data`, never in `model`, so it cannot enter a request.
|
|
187
|
+
if (partial && partial.content.length > 0)
|
|
188
|
+
assistant = tx.appendEntry(current.conversationId, {
|
|
189
|
+
kind: "pi.assistant",
|
|
190
|
+
data: {
|
|
191
|
+
attempt: cp?.attempt ?? 0,
|
|
192
|
+
display: { ...toStored(partial), stopReason: "aborted" },
|
|
193
|
+
reason: "aborted",
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
tx.sticky(current.conversationId).turn = { tools: [] };
|
|
197
|
+
await tx.resolveInputs(task.input.inputs, { status: "unanswered", reason: "aborted" });
|
|
198
|
+
tx.emit({ type: "turn.ended", inputs: task.input.inputs, status: "unanswered", reason: "aborted" });
|
|
199
|
+
return assistant === undefined ? {} : { assistant };
|
|
200
|
+
};
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
// Request derivation and streaming
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
async function derive(task, cp, rt, ctx) {
|
|
207
|
+
const { messages } = await rt.context(task.conversationId, cp.cutoff, ctx);
|
|
208
|
+
let request = { messages };
|
|
209
|
+
await rt.hooks.each(ctx, (h, api) => h.beforeRequest?.(request, { ...api, cutoff: cp.cutoff }, ctx), (value) => {
|
|
210
|
+
if (value !== undefined)
|
|
211
|
+
request = value;
|
|
212
|
+
});
|
|
213
|
+
return request;
|
|
214
|
+
}
|
|
215
|
+
/** Stream, coalescing frames into the turn view. Flush on size or time. */
|
|
216
|
+
async function stream(cp, model, messages, rt, ctx) {
|
|
217
|
+
const encoder = new AssistantMessageFrameEncoder();
|
|
218
|
+
let pending = [];
|
|
219
|
+
let pendingBytes = 0;
|
|
220
|
+
let lastFlush = rt.now();
|
|
221
|
+
let terminal;
|
|
222
|
+
let deferred;
|
|
223
|
+
let flushedContent = false;
|
|
224
|
+
const flush = async () => {
|
|
225
|
+
const batch = pending;
|
|
226
|
+
if (batch.length === 0)
|
|
227
|
+
return;
|
|
228
|
+
pending = [];
|
|
229
|
+
pendingBytes = 0;
|
|
230
|
+
lastFlush = rt.now();
|
|
231
|
+
if (batch.some((frame) => "delta" in frame))
|
|
232
|
+
flushedContent = true;
|
|
233
|
+
await rt.commit((tx, current) => {
|
|
234
|
+
const turn = tx.sticky(current.conversationId).turn;
|
|
235
|
+
for (const f of batch)
|
|
236
|
+
applyFrame(turn, f);
|
|
237
|
+
}, ctx);
|
|
238
|
+
};
|
|
239
|
+
try {
|
|
240
|
+
const iterator = rt.models
|
|
241
|
+
.stream(model, { messages, thinkingLevel: cp.thinkingLevel }, ctx)[Symbol.asyncIterator]();
|
|
242
|
+
let pull = iterator.next();
|
|
243
|
+
for (;;) {
|
|
244
|
+
const selected = pending.length === 0
|
|
245
|
+
? { kind: "event", result: await pull }
|
|
246
|
+
: await Promise.race([
|
|
247
|
+
pull.then((result) => ({ kind: "event", result })),
|
|
248
|
+
rt.sleep(lastFlush + 100, ctx).then(() => ({ kind: "flush" })),
|
|
249
|
+
]);
|
|
250
|
+
if (selected.kind === "flush") {
|
|
251
|
+
await flush();
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (selected.result.done)
|
|
255
|
+
break;
|
|
256
|
+
const event = selected.result.value;
|
|
257
|
+
if (event.type === "done") {
|
|
258
|
+
encoder.encode(event);
|
|
259
|
+
if (event.reason === "deferred" && event.message.deferred !== undefined)
|
|
260
|
+
deferred = event.message.deferred;
|
|
261
|
+
else
|
|
262
|
+
terminal = event.message;
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
if (event.type === "error") {
|
|
266
|
+
encoder.encode(event);
|
|
267
|
+
terminal = event.error;
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
const frame = encoder.encode(event);
|
|
271
|
+
pull = iterator.next();
|
|
272
|
+
if (frame === undefined)
|
|
273
|
+
continue;
|
|
274
|
+
pending.push(frame);
|
|
275
|
+
pendingBytes += "delta" in frame ? frame.delta.length : 64;
|
|
276
|
+
if (pendingBytes >= 256 || (!flushedContent && "delta" in frame))
|
|
277
|
+
await flush();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
if (ctx.abortSignal?.aborted)
|
|
282
|
+
throw error;
|
|
283
|
+
terminal = {
|
|
284
|
+
role: "assistant",
|
|
285
|
+
content: [],
|
|
286
|
+
api: model.api,
|
|
287
|
+
provider: model.provider,
|
|
288
|
+
model: model.id,
|
|
289
|
+
usage: emptyUsage(),
|
|
290
|
+
stopReason: "error",
|
|
291
|
+
errorMessage: String(error),
|
|
292
|
+
timestamp: rt.now(),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
if (pending.length > 0)
|
|
296
|
+
await flush();
|
|
297
|
+
if (terminal === undefined && deferred === undefined)
|
|
298
|
+
throw new Error("stream ended without a terminal message");
|
|
299
|
+
return { terminal, deferred };
|
|
300
|
+
}
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
// Steps 3–5: classify the terminal message.
|
|
303
|
+
// ---------------------------------------------------------------------------
|
|
304
|
+
async function classify(task, cp, message, rt, ctx) {
|
|
305
|
+
await rt.hooks.each(ctx, (h, api) => h.afterResponse?.(message, { ...api, attempt: cp.attempt }, ctx));
|
|
306
|
+
if (message.stopReason === "error") {
|
|
307
|
+
const decision = retryDecision(cp, message, rt.now());
|
|
308
|
+
if (decision.kind === "retry") {
|
|
309
|
+
return {
|
|
310
|
+
next: (tx, current) => {
|
|
311
|
+
tx.appendEntry(current.conversationId, {
|
|
312
|
+
kind: "pi.usage",
|
|
313
|
+
data: {
|
|
314
|
+
attempt: cp.attempt,
|
|
315
|
+
usage: toStored(message.usage),
|
|
316
|
+
error: message.errorMessage ?? "provider error",
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
tx.emit({
|
|
320
|
+
type: "generation.retrying",
|
|
321
|
+
taskId: current.id,
|
|
322
|
+
attempt: cp.attempt,
|
|
323
|
+
retryAt: decision.untilMs,
|
|
324
|
+
error: message.errorMessage ?? "provider error",
|
|
325
|
+
});
|
|
326
|
+
return {
|
|
327
|
+
...cp,
|
|
328
|
+
phase: "retrying",
|
|
329
|
+
untilMs: decision.untilMs,
|
|
330
|
+
lastError: message.errorMessage ?? "provider error",
|
|
331
|
+
};
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
return { done: terminalError(task, cp, message, decision.reason) };
|
|
336
|
+
}
|
|
337
|
+
if (message.stopReason === "aborted")
|
|
338
|
+
return { done: terminalError(task, cp, message, "provider") };
|
|
339
|
+
const calls = message.content.filter((c) => c.type === "toolCall");
|
|
340
|
+
const stored = toStored(message);
|
|
341
|
+
if (calls.length > 0) {
|
|
342
|
+
return {
|
|
343
|
+
done: async (tx, current) => {
|
|
344
|
+
const c = current.conversationId;
|
|
345
|
+
const collapseThrough = await thresholdCollapseThrough(tx, c, message); // read BEFORE the append
|
|
346
|
+
const assistant = tx.appendEntry(c, {
|
|
347
|
+
kind: "pi.assistant",
|
|
348
|
+
model: [stored],
|
|
349
|
+
data: { attempt: cp.attempt },
|
|
350
|
+
});
|
|
351
|
+
const turn = tx.sticky(c).turn;
|
|
352
|
+
turn.message = undefined;
|
|
353
|
+
turn.tools = calls.map((call) => ({
|
|
354
|
+
callId: call.id,
|
|
355
|
+
name: call.name,
|
|
356
|
+
args: toStored(call.arguments),
|
|
357
|
+
status: "pending",
|
|
358
|
+
}));
|
|
359
|
+
const tools = calls.map((call, index) => tx.createTask({ kind: "pi.tool", input: { assistant, call: toStored(call), offered: cp.tools, index } }));
|
|
360
|
+
const postTools = tx.createTask({
|
|
361
|
+
kind: "pi.post_tools",
|
|
362
|
+
after: tools,
|
|
363
|
+
input: { inputs: task.input.inputs, assistant, tools },
|
|
364
|
+
});
|
|
365
|
+
if (collapseThrough !== undefined)
|
|
366
|
+
tx.createTask({ kind: "pi.collapse", input: { reason: "threshold", through: collapseThrough } });
|
|
367
|
+
tx.emit({ type: "generation.completed", taskId: current.id, entry: assistant, toolCalls: calls.length });
|
|
368
|
+
return { status: "completed", result: { assistant, tools, postTools } };
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
let continueText;
|
|
373
|
+
await rt.hooks.each(ctx, (h, api) => h.onYield?.(message, api, ctx), (value) => {
|
|
374
|
+
if (value === undefined)
|
|
375
|
+
return;
|
|
376
|
+
continueText = value.continue;
|
|
377
|
+
return true;
|
|
378
|
+
});
|
|
379
|
+
return {
|
|
380
|
+
done: async (tx, current) => {
|
|
381
|
+
const c = current.conversationId;
|
|
382
|
+
const collapseThrough = await thresholdCollapseThrough(tx, c, message); // read BEFORE the append
|
|
383
|
+
const head = await tx.newestEntry(c, { withHead: true });
|
|
384
|
+
const assistant = tx.appendEntry(c, { kind: "pi.assistant", model: [stored], data: { attempt: cp.attempt } });
|
|
385
|
+
tx.emit({ type: "generation.completed", taskId: current.id, entry: assistant, toolCalls: 0 });
|
|
386
|
+
tx.sticky(c).turn = { tools: [] };
|
|
387
|
+
if (collapseThrough !== undefined)
|
|
388
|
+
tx.createTask({ kind: "pi.collapse", input: { reason: "threshold", through: collapseThrough } });
|
|
389
|
+
const { triggers, terminated } = await tx.boundary(c, "final", head?.id);
|
|
390
|
+
if (continueText !== undefined && triggers.length === 0 && !terminated) {
|
|
391
|
+
tx.appendEntry(c, {
|
|
392
|
+
kind: "pi.user",
|
|
393
|
+
model: [{ role: "user", content: continueText, timestamp: rt.now() }],
|
|
394
|
+
data: { continuation: true, from: assistant },
|
|
395
|
+
});
|
|
396
|
+
const successor = tx.createTask({ kind: "pi.generation", input: { inputs: task.input.inputs } });
|
|
397
|
+
return { status: "completed", result: { assistant, tools: [], successor } };
|
|
398
|
+
}
|
|
399
|
+
await tx.resolveInputs(task.input.inputs, { status: "done", answer: assistant });
|
|
400
|
+
tx.emit({ type: "turn.ended", inputs: task.input.inputs, status: "done", answer: assistant });
|
|
401
|
+
if (triggers.length > 0) {
|
|
402
|
+
const successor = tx.createTask({ kind: "pi.generation", input: { inputs: triggers } });
|
|
403
|
+
tx.emit({ type: "turn.started", inputs: triggers });
|
|
404
|
+
return { status: "completed", result: { assistant, tools: [], successor } };
|
|
405
|
+
}
|
|
406
|
+
return { status: "completed", result: { assistant, tools: [] } };
|
|
407
|
+
},
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
/** Provider error / aborted stop: a display-only assistant entry (no `model`), inputs unanswered. */
|
|
411
|
+
function terminalError(task, cp, message, reason) {
|
|
412
|
+
return async (tx, current) => {
|
|
413
|
+
const head = await tx.newestEntry(current.conversationId, { withHead: true });
|
|
414
|
+
const assistant = tx.appendEntry(current.conversationId, {
|
|
415
|
+
kind: "pi.assistant",
|
|
416
|
+
data: {
|
|
417
|
+
attempt: cp.attempt,
|
|
418
|
+
display: toStored(message),
|
|
419
|
+
reason: message.stopReason === "aborted" ? "aborted" : "error",
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
tx.emit({
|
|
423
|
+
type: "generation.failed",
|
|
424
|
+
taskId: current.id,
|
|
425
|
+
reason,
|
|
426
|
+
detail: message.errorMessage ?? "provider error",
|
|
427
|
+
entry: assistant,
|
|
428
|
+
});
|
|
429
|
+
await settleFailedTurn(tx, current, task.input.inputs, message.errorMessage ?? "provider error", head?.id);
|
|
430
|
+
return fail(reason, message.errorMessage ?? "provider error", assistant);
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
async function settleFailedTurn(tx, current, inputs, detail, headBoundary) {
|
|
434
|
+
tx.sticky(current.conversationId).turn = { tools: [] };
|
|
435
|
+
await tx.resolveInputs(inputs, { status: "unanswered", reason: "failed", detail });
|
|
436
|
+
tx.emit({ type: "turn.ended", inputs: [...inputs], status: "unanswered", reason: "failed", detail });
|
|
437
|
+
const { triggers } = await tx.boundary(current.conversationId, "final", headBoundary);
|
|
438
|
+
if (triggers.length > 0) {
|
|
439
|
+
tx.createTask({ kind: "pi.generation", conversationId: current.conversationId, input: { inputs: triggers } });
|
|
440
|
+
tx.emit({ type: "turn.started", inputs: triggers });
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
export function retryDecision(cp, message, now) {
|
|
444
|
+
if (message !== null && !isRetryableAssistantError(message))
|
|
445
|
+
return { kind: "fail", reason: "provider" };
|
|
446
|
+
if (!cp.retry.enabled)
|
|
447
|
+
return { kind: "fail", reason: "provider" };
|
|
448
|
+
if (cp.attempt > cp.retry.maxRetries)
|
|
449
|
+
return { kind: "fail", reason: "retries_exhausted" };
|
|
450
|
+
const delay = cp.retry.baseDelayMs * 2 ** Math.max(0, cp.attempt - 1);
|
|
451
|
+
const safeDelay = Number.isSafeInteger(delay) ? delay : Number.MAX_SAFE_INTEGER;
|
|
452
|
+
return { kind: "retry", untilMs: now + Math.min(safeDelay, cp.retry.maxAgentDelayMs ?? 60_000) };
|
|
453
|
+
}
|
|
454
|
+
// ---------------------------------------------------------------------------
|
|
455
|
+
// Collapse triggers
|
|
456
|
+
// ---------------------------------------------------------------------------
|
|
457
|
+
/** Read-side of threshold collapse: computed before the assistant is appended, applied after. */
|
|
458
|
+
async function thresholdCollapseThrough(tx, conversationId, message) {
|
|
459
|
+
if ((await tx.tasks({ conversationId, kind: "pi.collapse", status: ["pending", "running"] })).length > 0)
|
|
460
|
+
return undefined;
|
|
461
|
+
const state = tx.rewindable(conversationId);
|
|
462
|
+
if (state.threshold <= 0)
|
|
463
|
+
return undefined;
|
|
464
|
+
const { entries, messages } = await tx.context(conversationId);
|
|
465
|
+
const used = Math.max((message.usage?.input ?? 0) + (message.usage?.output ?? 0), estimate([...messages, toStored(message)]));
|
|
466
|
+
if (used <= state.threshold)
|
|
467
|
+
return undefined;
|
|
468
|
+
return chooseThrough(entries, state.keepRecent);
|
|
469
|
+
}
|
|
470
|
+
function overflow(task, rt) {
|
|
471
|
+
return {
|
|
472
|
+
done: async (tx, current) => {
|
|
473
|
+
const c = current.conversationId;
|
|
474
|
+
const state = tx.rewindable(c);
|
|
475
|
+
const { entries, head } = await tx.context(c);
|
|
476
|
+
const through = chooseThrough(entries, state.keepRecent);
|
|
477
|
+
tx.sticky(c).turn = { tools: [] };
|
|
478
|
+
if (through === undefined) {
|
|
479
|
+
await tx.write(c, {
|
|
480
|
+
kind: "pi.notice",
|
|
481
|
+
model: [{ role: "user", content: "Context too large; nothing to compact.", timestamp: rt.now() }],
|
|
482
|
+
});
|
|
483
|
+
tx.emit({
|
|
484
|
+
type: "generation.failed",
|
|
485
|
+
taskId: current.id,
|
|
486
|
+
reason: "overflow",
|
|
487
|
+
detail: "request exceeds context window and nothing is collapsible",
|
|
488
|
+
});
|
|
489
|
+
await settleFailedTurn(tx, current, task.input.inputs, "overflow", head?.id);
|
|
490
|
+
return fail("overflow", "request exceeds context window and nothing is collapsible");
|
|
491
|
+
}
|
|
492
|
+
const collapse = tx.createTask({ kind: "pi.collapse", input: { reason: "overflow", through } });
|
|
493
|
+
tx.createTask({ kind: "pi.generation", after: [collapse], input: { inputs: task.input.inputs } });
|
|
494
|
+
tx.emit({
|
|
495
|
+
type: "generation.failed",
|
|
496
|
+
taskId: current.id,
|
|
497
|
+
reason: "overflow",
|
|
498
|
+
detail: `collapsing through ${through}`,
|
|
499
|
+
});
|
|
500
|
+
return fail("overflow", `collapsing through ${through}`);
|
|
501
|
+
},
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
//# sourceMappingURL=generation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generation.js","sourceRoot":"","sources":["../../../../src/harness/pico3/kinds/generation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@earendil-works/chord\";\nimport type {\n\tAssistantMessage,\n\tAssistantMessageEvent,\n\tAssistantMessageFrame,\n\tDeferredHandle,\n\tToolCall,\n} from \"@earendil-works/pi-ai\";\nimport { AssistantMessageFrameEncoder, isRetryableAssistantError } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport { planManagedEntry, prepareDraft, type SystemInstructionsHooks, sameSnapshot, takeSnapshot } from \"../system.ts\";\nimport {\n\ttype Closure,\n\ttype Completion,\n\ttype CoreKind,\n\ttype CoreTx,\n\ttype HookInfo,\n\ttype HookResult,\n\ttype Id,\n\ttype ModelRef,\n\ttype RequestMessage,\n\ttype RetryPolicy,\n\ttype Runtime,\n\ttype Step,\n\ttype Stored,\n\ttype Task,\n\ttype ThinkingLevel,\n\ttoStored,\n} from \"../types.ts\";\nimport { chooseThrough } from \"./collapse.ts\";\nimport { applyFrame } from \"./frames.ts\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type GenerationInput = { inputs: Id[] };\n/** Captured once at `prepared`; carried unchanged except `attempt`. */\ntype Prep = {\n\tcutoff: Id;\n\tsystem: Id | null;\n\tmodel: ModelRef;\n\tthinkingLevel: ThinkingLevel;\n\ttools: string[];\n\tretry: RetryPolicy;\n\tattempt: number;\n};\nexport type GenerationCheckpoint =\n\t| ({ phase: \"prepared\" } & Prep)\n\t| ({ phase: \"requesting\" } & Prep)\n\t| ({ phase: \"retrying\"; untilMs: number; lastError: string } & Prep)\n\t| ({ phase: \"deferred\"; handle: Stored<DeferredHandle>; pollAt: number } & Prep);\nexport type GenerationResult = { assistant: Id; tools: Id[]; postTools?: Id; successor?: Id };\nexport type GenerationFailure = {\n\treason: \"provider\" | \"overflow\" | \"retries_exhausted\" | \"no_model\";\n\tdetail: string;\n\tassistant?: Id;\n};\n\n/** Display-only assistant entries (provider error, aborted partial) carry the message here, never in `model`. */\nexport type DisplayAssistantData = { attempt: number; display: Stored<AssistantMessage>; reason: \"error\" | \"aborted\" };\n\n/** Hook points this kind calls. Register with `h.hooks(namespace, kinds.generation, { … })`. */\nexport interface GenerationHooks extends SystemInstructionsHooks {\n\t/** Before every request (also on retry and recovery). Chain. */\n\tbeforeRequest(\n\t\trequest: { messages: RequestMessage[] },\n\t\tinfo: HookInfo & { cutoff: Id },\n\t\tctx: Context,\n\t): HookResult<{ messages: RequestMessage[] }>;\n\t/** Every terminal provider message, before classification. Observer. */\n\tafterResponse(message: AssistantMessage, info: HookInfo & { attempt: number }, ctx: Context): void | Promise<void>;\n\t/** On a final answer with nothing queued. First `{ continue }` wins and starts a continuation. */\n\tonYield(answer: AssistantMessage, info: HookInfo, ctx: Context): HookResult<{ continue: string }>;\n}\n\n/** Configuration this kind reads, with defaults. `model` has none: absent → failed/no_model. */\nexport const generationConfig = {\n\trewindable: {\n\t\tmodel: undefined as ModelRef | undefined,\n\t\tthinkingLevel: \"off\" as ThinkingLevel,\n\t\tselectedTools: [] as string[],\n\t\tprofile: \"default\" as string,\n\t},\n\tsticky: { retry: { enabled: true, maxRetries: 3, baseDelayMs: 2000, maxAgentDelayMs: 60_000 } as RetryPolicy },\n} as const;\n\ntype G = Task<GenerationInput, GenerationCheckpoint>;\ntype Rt = Runtime<GenerationHooks, CoreTx>;\ntype S = Step<GenerationCheckpoint, GenerationResult, GenerationFailure, CoreTx>;\ntype Out = Closure<GenerationResult, GenerationFailure, CoreTx>;\n\nconst fail = (\n\treason: GenerationFailure[\"reason\"],\n\tdetail: string,\n\tassistant?: Id,\n): Completion<GenerationResult, GenerationFailure> => ({\n\tstatus: \"failed\",\n\tfailure: { reason, detail, ...(assistant === undefined ? {} : { assistant }) },\n});\n/** Every terminal generation failure settles its group and admits queued triggers at the final boundary. */\nconst failStep = (task: G, reason: GenerationFailure[\"reason\"], detail: string): S => ({\n\tdone: async (tx, current) => {\n\t\tconst head = await tx.newestEntry(current.conversationId, { withHead: true });\n\t\ttx.emit({ type: \"generation.failed\", taskId: current.id, reason, detail });\n\t\tawait settleFailedTurn(tx, current, task.input.inputs, detail, head?.id);\n\t\treturn fail(reason, detail);\n\t},\n});\n/** pi-ai drops system messages and aborted/error assistant messages before sending; estimate what is sent. */\nconst estimate = (messages: RequestMessage[]) =>\n\testimateContextTokens(\n\t\tmessages.filter(\n\t\t\t(m) =>\n\t\t\t\tm.role !== \"system\" &&\n\t\t\t\t!(m.role === \"assistant\" && (m.stopReason === \"aborted\" || m.stopReason === \"error\")),\n\t\t) as never,\n\t).tokens;\nconst emptyUsage = (): AssistantMessage[\"usage\"] => ({\n\tinput: 0,\n\toutput: 0,\n\tcacheRead: 0,\n\tcacheWrite: 0,\n\ttotalTokens: 0,\n\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n});\n\n// ---------------------------------------------------------------------------\n// The kind\n// ---------------------------------------------------------------------------\n\nexport const generation: CoreKind<\n\tGenerationInput,\n\tGenerationCheckpoint,\n\tGenerationResult,\n\tGenerationFailure,\n\t{ assistant?: Id },\n\tGenerationHooks,\n\ttypeof generationConfig\n> = {\n\tname: \"pi.generation\",\n\tturn: true,\n\tconfig: generationConfig,\n\tinflight: [\"requesting\"],\n\n\t// Step 1 (§12.5): snapshot S on the line; systemInstructions off the line; then in one\n\t// commit re-take S′, retry if it moved, else append the managed entry and checkpoint\n\t// `prepared` with the cutoff. Runs once per generation; never on recovery.\n\tasync initial(task, rt, ctx) {\n\t\tconst { snapshot, canonical, seed } = await rt.commit(\n\t\t\t(tx, current) => takeSnapshot(tx, current.conversationId, rt.registries.sections, rt.registries.tools),\n\t\t\tctx,\n\t\t);\n\t\tif (snapshot.settings.model === undefined) return failStep(task, \"no_model\", \"no model configured\");\n\t\tconst retry = (await rt.sticky(task.conversationId, ctx)).retry;\n\n\t\tconst warnings: string[] = [];\n\t\tconst { desired, tools } = await prepareDraft(\n\t\t\trt,\n\t\t\trt.registries.sections,\n\t\t\tcanonical,\n\t\t\tseed,\n\t\t\tsnapshot.settings,\n\t\t\t(message) => warnings.push(message),\n\t\t\tctx,\n\t\t);\n\t\tconst model = snapshot.settings.model as unknown as ModelRef;\n\t\tconst thinkingLevel = snapshot.settings.thinkingLevel as ThinkingLevel;\n\n\t\treturn {\n\t\t\tnext: async (tx, current) => {\n\t\t\t\tconst c = current.conversationId;\n\t\t\t\tconst again = await takeSnapshot(tx, c, rt.registries.sections, rt.registries.tools);\n\t\t\t\tif (!sameSnapshot(again.snapshot, snapshot)) return \"retry\";\n\t\t\t\tconst plan = await planManagedEntry(tx, c, snapshot, canonical, desired, tools, rt.now());\n\t\t\t\tfor (const message of warnings) tx.emit({ type: \"warning\", source: \"generation\", message });\n\t\t\t\tconst system = plan === undefined ? null : tx.appendEntry(c, { kind: \"pi.system\", ...plan });\n\t\t\t\tconst cutoff = system ?? (await tx.newestEntry(c))!.id;\n\t\t\t\ttx.sticky(c).turn = { tools: [] }; // a new generation starts a fresh turn view\n\t\t\t\treturn {\n\t\t\t\t\tphase: \"prepared\",\n\t\t\t\t\tcutoff,\n\t\t\t\t\tsystem,\n\t\t\t\t\tmodel,\n\t\t\t\t\tthinkingLevel,\n\t\t\t\t\ttools: tools.map((t) => t.name),\n\t\t\t\t\tretry,\n\t\t\t\t\tattempt: 0,\n\t\t\t\t};\n\t\t\t},\n\t\t};\n\t},\n\n\tphases: {\n\t\t// Step 2: derive the request from the cutoff (hooks rerun), overflow check, write the\n\t\t// in-flight checkpoint, call the provider. Reached fresh from `initial`/`retrying`,\n\t\t// and again on recovery of `prepared` (step 1 never reruns).\n\t\tasync prepared(task, rt, ctx) {\n\t\t\tconst cp = task.checkpoint;\n\t\t\tconst model = rt.models.resolve(cp.model);\n\t\t\tif (model === undefined)\n\t\t\t\treturn failStep(task, \"no_model\", `model ${cp.model.provider}/${cp.model.modelId} unavailable`);\n\t\t\tconst derived = await derive(task, cp, rt, ctx);\n\t\t\tif (estimate(derived.messages) > model.contextWindow - model.maxTokens) return overflow(task, rt);\n\t\t\tconst attempt = cp.attempt + 1;\n\t\t\tawait rt.commit((tx) => {\n\t\t\t\ttx.checkpoint({ ...cp, phase: \"requesting\", attempt });\n\t\t\t\ttx.emit({ type: \"generation.started\", taskId: task.id, attempt });\n\t\t\t}, ctx); // before the effect\n\t\t\tconst { terminal, deferred } = await stream(cp, model, derived.messages, rt, ctx);\n\t\t\tif (deferred !== undefined) {\n\t\t\t\tconst pollAt = rt.now() + (deferred.pollAfterMs ?? 5000);\n\t\t\t\treturn {\n\t\t\t\t\tnext: (tx) => {\n\t\t\t\t\t\ttx.emit({ type: \"generation.deferred\", taskId: task.id, pollAt });\n\t\t\t\t\t\treturn { ...cp, phase: \"deferred\", attempt, handle: toStored(deferred), pollAt };\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn classify(task, { ...cp, attempt }, terminal!, rt, ctx);\n\t\t},\n\n\t\t// Only reached by the scheduler after a crash: the call may have happened and there\n\t\t// is no result lookup. Count it as a failed attempt and retry per policy.\n\t\tasync requesting(task, rt) {\n\t\t\tconst cp = task.checkpoint;\n\t\t\tconst decision = retryDecision(cp, null, rt.now());\n\t\t\tif (decision.kind === \"fail\") return failStep(task, decision.reason, \"interrupted\");\n\t\t\treturn {\n\t\t\t\tnext: (tx, current) => {\n\t\t\t\t\ttx.appendEntry(current.conversationId, {\n\t\t\t\t\t\tkind: \"pi.usage\",\n\t\t\t\t\t\tdata: { attempt: cp.attempt, error: \"interrupted\" },\n\t\t\t\t\t});\n\t\t\t\t\ttx.emit({\n\t\t\t\t\t\ttype: \"generation.retrying\",\n\t\t\t\t\t\ttaskId: current.id,\n\t\t\t\t\t\tattempt: cp.attempt,\n\t\t\t\t\t\tretryAt: decision.untilMs,\n\t\t\t\t\t\terror: \"interrupted\",\n\t\t\t\t\t});\n\t\t\t\t\treturn { ...cp, phase: \"retrying\", untilMs: decision.untilMs, lastError: \"interrupted\" };\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\n\t\t// Durable backoff, then back to step 2. Resets the streaming view.\n\t\tasync retrying(task, rt, ctx) {\n\t\t\tconst cp = task.checkpoint;\n\t\t\tawait rt.sleep(cp.untilMs, ctx);\n\t\t\tconst { untilMs: _u, lastError: _e, ...prep } = cp;\n\t\t\treturn {\n\t\t\t\tnext: (tx, current) => {\n\t\t\t\t\ttx.sticky(current.conversationId).turn.message = undefined;\n\t\t\t\t\treturn { ...prep, phase: \"prepared\" };\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\n\t\t// Provider-side async. Poll; not the retry backoff. Same after a crash: the handle is durable.\n\t\tasync deferred(task, rt, ctx) {\n\t\t\tconst cp = task.checkpoint;\n\t\t\tconst model = rt.models.resolve(cp.model);\n\t\t\tif (model === undefined) return failStep(task, \"no_model\", \"model disappeared\");\n\t\t\tawait rt.sleep(cp.pollAt, ctx);\n\t\t\tconst result = await rt.models.fetchDeferred(model, cp.handle, ctx);\n\t\t\tif (\"deferred\" in result && result.deferred !== undefined) {\n\t\t\t\tconst pollAt = rt.now() + (result.deferred.pollAfterMs ?? 5000);\n\t\t\t\treturn {\n\t\t\t\t\tnext: (tx) => {\n\t\t\t\t\t\ttx.emit({ type: \"generation.deferred\", taskId: task.id, pollAt });\n\t\t\t\t\t\treturn { ...cp, handle: toStored(result.deferred), pollAt };\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst message = result as AssistantMessage;\n\t\t\tawait rt.commit((tx, current) => {\n\t\t\t\ttx.sticky(current.conversationId).turn.message = toStored(message);\n\t\t\t}, ctx);\n\t\t\tconst { handle: _handle, pollAt: _pollAt, ...prep } = cp;\n\t\t\treturn classify(task, prep, message, rt, ctx);\n\t\t},\n\t},\n\n\tasync abort(task, rt, ctx) {\n\t\tconst cp = task.checkpoint;\n\t\tif (cp?.phase === \"deferred\") {\n\t\t\tconst model = rt.models.resolve(cp.model);\n\t\t\tif (model) await rt.models.cancelDeferred(model, cp.handle as DeferredHandle, ctx).catch(() => {});\n\t\t}\n\t\treturn async (tx, current) => {\n\t\t\tconst partial = tx.sticky(current.conversationId).turn.message;\n\t\t\tlet assistant: Id | undefined;\n\t\t\t// Display-only: the partial goes in `data`, never in `model`, so it cannot enter a request.\n\t\t\tif (partial && partial.content.length > 0)\n\t\t\t\tassistant = tx.appendEntry(current.conversationId, {\n\t\t\t\t\tkind: \"pi.assistant\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tattempt: cp?.attempt ?? 0,\n\t\t\t\t\t\tdisplay: { ...toStored(partial), stopReason: \"aborted\" },\n\t\t\t\t\t\treason: \"aborted\",\n\t\t\t\t\t} satisfies DisplayAssistantData,\n\t\t\t\t});\n\t\t\ttx.sticky(current.conversationId).turn = { tools: [] };\n\t\t\tawait tx.resolveInputs(task.input.inputs, { status: \"unanswered\", reason: \"aborted\" });\n\t\t\ttx.emit({ type: \"turn.ended\", inputs: task.input.inputs, status: \"unanswered\", reason: \"aborted\" });\n\t\t\treturn assistant === undefined ? {} : { assistant };\n\t\t};\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// Request derivation and streaming\n// ---------------------------------------------------------------------------\n\nasync function derive(task: G, cp: Prep, rt: Rt, ctx: Context): Promise<{ messages: RequestMessage[] }> {\n\tconst { messages } = await rt.context(task.conversationId, cp.cutoff, ctx);\n\tlet request = { messages };\n\tawait rt.hooks.each(\n\t\tctx,\n\t\t(h, api) => h.beforeRequest?.(request, { ...api, cutoff: cp.cutoff }, ctx),\n\t\t(value) => {\n\t\t\tif (value !== undefined) request = value;\n\t\t},\n\t);\n\treturn request;\n}\n\n/** Stream, coalescing frames into the turn view. Flush on size or time. */\nasync function stream(\n\tcp: Prep,\n\tmodel: NonNullable<ReturnType<Rt[\"models\"][\"resolve\"]>>,\n\tmessages: RequestMessage[],\n\trt: Rt,\n\tctx: Context,\n): Promise<{ terminal?: AssistantMessage; deferred?: DeferredHandle }> {\n\tconst encoder = new AssistantMessageFrameEncoder();\n\tlet pending: AssistantMessageFrame[] = [];\n\tlet pendingBytes = 0;\n\tlet lastFlush = rt.now();\n\tlet terminal: AssistantMessage | undefined;\n\tlet deferred: DeferredHandle | undefined;\n\tlet flushedContent = false;\n\tconst flush = async () => {\n\t\tconst batch = pending;\n\t\tif (batch.length === 0) return;\n\t\tpending = [];\n\t\tpendingBytes = 0;\n\t\tlastFlush = rt.now();\n\t\tif (batch.some((frame) => \"delta\" in frame)) flushedContent = true;\n\t\tawait rt.commit((tx, current) => {\n\t\t\tconst turn = tx.sticky(current.conversationId).turn;\n\t\t\tfor (const f of batch) applyFrame(turn as { message?: AssistantMessage }, f);\n\t\t}, ctx);\n\t};\n\ttry {\n\t\tconst iterator = rt.models\n\t\t\t.stream(model, { messages, thinkingLevel: cp.thinkingLevel }, ctx)\n\t\t\t[Symbol.asyncIterator]();\n\t\tlet pull = iterator.next();\n\t\tfor (;;) {\n\t\t\tconst selected: { kind: \"event\"; result: IteratorResult<AssistantMessageEvent> } | { kind: \"flush\" } =\n\t\t\t\tpending.length === 0\n\t\t\t\t\t? { kind: \"event\", result: await pull }\n\t\t\t\t\t: await Promise.race([\n\t\t\t\t\t\t\tpull.then((result) => ({ kind: \"event\" as const, result })),\n\t\t\t\t\t\t\trt.sleep(lastFlush + 100, ctx).then(() => ({ kind: \"flush\" as const })),\n\t\t\t\t\t\t]);\n\t\t\tif (selected.kind === \"flush\") {\n\t\t\t\tawait flush();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (selected.result.done) break;\n\t\t\tconst event = selected.result.value;\n\t\t\tif (event.type === \"done\") {\n\t\t\t\tencoder.encode(event);\n\t\t\t\tif (event.reason === \"deferred\" && event.message.deferred !== undefined) deferred = event.message.deferred;\n\t\t\t\telse terminal = event.message;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (event.type === \"error\") {\n\t\t\t\tencoder.encode(event);\n\t\t\t\tterminal = event.error;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst frame = encoder.encode(event);\n\t\t\tpull = iterator.next();\n\t\t\tif (frame === undefined) continue;\n\t\t\tpending.push(frame);\n\t\t\tpendingBytes += \"delta\" in frame ? frame.delta.length : 64;\n\t\t\tif (pendingBytes >= 256 || (!flushedContent && \"delta\" in frame)) await flush();\n\t\t}\n\t} catch (error) {\n\t\tif (ctx.abortSignal?.aborted) throw error;\n\t\tterminal = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: emptyUsage(),\n\t\t\tstopReason: \"error\",\n\t\t\terrorMessage: String(error),\n\t\t\ttimestamp: rt.now(),\n\t\t};\n\t}\n\tif (pending.length > 0) await flush();\n\tif (terminal === undefined && deferred === undefined) throw new Error(\"stream ended without a terminal message\");\n\treturn { terminal, deferred };\n}\n\n// ---------------------------------------------------------------------------\n// Steps 3–5: classify the terminal message.\n// ---------------------------------------------------------------------------\n\nasync function classify(task: G, cp: Prep, message: AssistantMessage, rt: Rt, ctx: Context): Promise<S> {\n\tawait rt.hooks.each(ctx, (h, api) => h.afterResponse?.(message, { ...api, attempt: cp.attempt }, ctx));\n\n\tif (message.stopReason === \"error\") {\n\t\tconst decision = retryDecision(cp, message, rt.now());\n\t\tif (decision.kind === \"retry\") {\n\t\t\treturn {\n\t\t\t\tnext: (tx, current) => {\n\t\t\t\t\ttx.appendEntry(current.conversationId, {\n\t\t\t\t\t\tkind: \"pi.usage\",\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tattempt: cp.attempt,\n\t\t\t\t\t\t\tusage: toStored(message.usage),\n\t\t\t\t\t\t\terror: message.errorMessage ?? \"provider error\",\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\ttx.emit({\n\t\t\t\t\t\ttype: \"generation.retrying\",\n\t\t\t\t\t\ttaskId: current.id,\n\t\t\t\t\t\tattempt: cp.attempt,\n\t\t\t\t\t\tretryAt: decision.untilMs,\n\t\t\t\t\t\terror: message.errorMessage ?? \"provider error\",\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...cp,\n\t\t\t\t\t\tphase: \"retrying\",\n\t\t\t\t\t\tuntilMs: decision.untilMs,\n\t\t\t\t\t\tlastError: message.errorMessage ?? \"provider error\",\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn { done: terminalError(task, cp, message, decision.reason) };\n\t}\n\tif (message.stopReason === \"aborted\") return { done: terminalError(task, cp, message, \"provider\") };\n\n\tconst calls = message.content.filter((c): c is ToolCall => c.type === \"toolCall\");\n\tconst stored = toStored(message);\n\tif (calls.length > 0) {\n\t\treturn {\n\t\t\tdone: async (tx, current) => {\n\t\t\t\tconst c = current.conversationId;\n\t\t\t\tconst collapseThrough = await thresholdCollapseThrough(tx, c, message); // read BEFORE the append\n\t\t\t\tconst assistant = tx.appendEntry(c, {\n\t\t\t\t\tkind: \"pi.assistant\",\n\t\t\t\t\tmodel: [stored],\n\t\t\t\t\tdata: { attempt: cp.attempt },\n\t\t\t\t});\n\t\t\t\tconst turn = tx.sticky(c).turn;\n\t\t\t\tturn.message = undefined;\n\t\t\t\tturn.tools = calls.map((call) => ({\n\t\t\t\t\tcallId: call.id,\n\t\t\t\t\tname: call.name,\n\t\t\t\t\targs: toStored(call.arguments),\n\t\t\t\t\tstatus: \"pending\",\n\t\t\t\t}));\n\t\t\t\tconst tools = calls.map((call, index) =>\n\t\t\t\t\ttx.createTask({ kind: \"pi.tool\", input: { assistant, call: toStored(call), offered: cp.tools, index } }),\n\t\t\t\t);\n\t\t\t\tconst postTools = tx.createTask({\n\t\t\t\t\tkind: \"pi.post_tools\",\n\t\t\t\t\tafter: tools,\n\t\t\t\t\tinput: { inputs: task.input.inputs, assistant, tools },\n\t\t\t\t});\n\t\t\t\tif (collapseThrough !== undefined)\n\t\t\t\t\ttx.createTask({ kind: \"pi.collapse\", input: { reason: \"threshold\", through: collapseThrough } });\n\t\t\t\ttx.emit({ type: \"generation.completed\", taskId: current.id, entry: assistant, toolCalls: calls.length });\n\t\t\t\treturn { status: \"completed\", result: { assistant, tools, postTools } };\n\t\t\t},\n\t\t};\n\t}\n\n\tlet continueText: string | undefined;\n\tawait rt.hooks.each(\n\t\tctx,\n\t\t(h, api) => h.onYield?.(message, api, ctx),\n\t\t(value) => {\n\t\t\tif (value === undefined) return;\n\t\t\tcontinueText = value.continue;\n\t\t\treturn true;\n\t\t},\n\t);\n\treturn {\n\t\tdone: async (tx, current) => {\n\t\t\tconst c = current.conversationId;\n\t\t\tconst collapseThrough = await thresholdCollapseThrough(tx, c, message); // read BEFORE the append\n\t\t\tconst head = await tx.newestEntry(c, { withHead: true });\n\t\t\tconst assistant = tx.appendEntry(c, { kind: \"pi.assistant\", model: [stored], data: { attempt: cp.attempt } });\n\t\t\ttx.emit({ type: \"generation.completed\", taskId: current.id, entry: assistant, toolCalls: 0 });\n\t\t\ttx.sticky(c).turn = { tools: [] };\n\t\t\tif (collapseThrough !== undefined)\n\t\t\t\ttx.createTask({ kind: \"pi.collapse\", input: { reason: \"threshold\", through: collapseThrough } });\n\t\t\tconst { triggers, terminated } = await tx.boundary(c, \"final\", head?.id);\n\t\t\tif (continueText !== undefined && triggers.length === 0 && !terminated) {\n\t\t\t\ttx.appendEntry(c, {\n\t\t\t\t\tkind: \"pi.user\",\n\t\t\t\t\tmodel: [{ role: \"user\", content: continueText, timestamp: rt.now() }],\n\t\t\t\t\tdata: { continuation: true, from: assistant },\n\t\t\t\t});\n\t\t\t\tconst successor = tx.createTask({ kind: \"pi.generation\", input: { inputs: task.input.inputs } });\n\t\t\t\treturn { status: \"completed\", result: { assistant, tools: [], successor } };\n\t\t\t}\n\t\t\tawait tx.resolveInputs(task.input.inputs, { status: \"done\", answer: assistant });\n\t\t\ttx.emit({ type: \"turn.ended\", inputs: task.input.inputs, status: \"done\", answer: assistant });\n\t\t\tif (triggers.length > 0) {\n\t\t\t\tconst successor = tx.createTask({ kind: \"pi.generation\", input: { inputs: triggers } });\n\t\t\t\ttx.emit({ type: \"turn.started\", inputs: triggers });\n\t\t\t\treturn { status: \"completed\", result: { assistant, tools: [], successor } };\n\t\t\t}\n\t\t\treturn { status: \"completed\", result: { assistant, tools: [] } };\n\t\t},\n\t};\n}\n\n/** Provider error / aborted stop: a display-only assistant entry (no `model`), inputs unanswered. */\nfunction terminalError(task: G, cp: Prep, message: AssistantMessage, reason: \"provider\" | \"retries_exhausted\"): Out {\n\treturn async (tx, current) => {\n\t\tconst head = await tx.newestEntry(current.conversationId, { withHead: true });\n\t\tconst assistant = tx.appendEntry(current.conversationId, {\n\t\t\tkind: \"pi.assistant\",\n\t\t\tdata: {\n\t\t\t\tattempt: cp.attempt,\n\t\t\t\tdisplay: toStored(message),\n\t\t\t\treason: message.stopReason === \"aborted\" ? \"aborted\" : \"error\",\n\t\t\t} satisfies DisplayAssistantData,\n\t\t});\n\t\ttx.emit({\n\t\t\ttype: \"generation.failed\",\n\t\t\ttaskId: current.id,\n\t\t\treason,\n\t\t\tdetail: message.errorMessage ?? \"provider error\",\n\t\t\tentry: assistant,\n\t\t});\n\t\tawait settleFailedTurn(tx, current, task.input.inputs, message.errorMessage ?? \"provider error\", head?.id);\n\t\treturn fail(reason, message.errorMessage ?? \"provider error\", assistant);\n\t};\n}\n\nasync function settleFailedTurn(\n\ttx: CoreTx,\n\tcurrent: Task,\n\tinputs: readonly Id[],\n\tdetail: string,\n\theadBoundary: Id | undefined,\n): Promise<void> {\n\ttx.sticky(current.conversationId).turn = { tools: [] };\n\tawait tx.resolveInputs(inputs, { status: \"unanswered\", reason: \"failed\", detail });\n\ttx.emit({ type: \"turn.ended\", inputs: [...inputs], status: \"unanswered\", reason: \"failed\", detail });\n\tconst { triggers } = await tx.boundary(current.conversationId, \"final\", headBoundary);\n\tif (triggers.length > 0) {\n\t\ttx.createTask({ kind: \"pi.generation\", conversationId: current.conversationId, input: { inputs: triggers } });\n\t\ttx.emit({ type: \"turn.started\", inputs: triggers });\n\t}\n}\n\ntype RetryDecision = { kind: \"retry\"; untilMs: number } | { kind: \"fail\"; reason: \"provider\" | \"retries_exhausted\" };\nexport function retryDecision(\n\tcp: { retry: RetryPolicy; attempt: number },\n\tmessage: AssistantMessage | null,\n\tnow: number,\n): RetryDecision {\n\tif (message !== null && !isRetryableAssistantError(message)) return { kind: \"fail\", reason: \"provider\" };\n\tif (!cp.retry.enabled) return { kind: \"fail\", reason: \"provider\" };\n\tif (cp.attempt > cp.retry.maxRetries) return { kind: \"fail\", reason: \"retries_exhausted\" };\n\tconst delay = cp.retry.baseDelayMs * 2 ** Math.max(0, cp.attempt - 1);\n\tconst safeDelay = Number.isSafeInteger(delay) ? delay : Number.MAX_SAFE_INTEGER;\n\treturn { kind: \"retry\", untilMs: now + Math.min(safeDelay, cp.retry.maxAgentDelayMs ?? 60_000) };\n}\n\n// ---------------------------------------------------------------------------\n// Collapse triggers\n// ---------------------------------------------------------------------------\n\n/** Read-side of threshold collapse: computed before the assistant is appended, applied after. */\nasync function thresholdCollapseThrough(\n\ttx: CoreTx,\n\tconversationId: Id,\n\tmessage: AssistantMessage,\n): Promise<Id | undefined> {\n\tif ((await tx.tasks({ conversationId, kind: \"pi.collapse\", status: [\"pending\", \"running\"] })).length > 0)\n\t\treturn undefined;\n\tconst state = tx.rewindable(conversationId);\n\tif (state.threshold <= 0) return undefined;\n\tconst { entries, messages } = await tx.context(conversationId);\n\tconst used = Math.max(\n\t\t(message.usage?.input ?? 0) + (message.usage?.output ?? 0),\n\t\testimate([...messages, toStored(message)]),\n\t);\n\tif (used <= state.threshold) return undefined;\n\treturn chooseThrough(entries, state.keepRecent);\n}\n\nfunction overflow(task: G, rt: Rt): S {\n\treturn {\n\t\tdone: async (tx, current) => {\n\t\t\tconst c = current.conversationId;\n\t\t\tconst state = tx.rewindable(c);\n\t\t\tconst { entries, head } = await tx.context(c);\n\t\t\tconst through = chooseThrough(entries, state.keepRecent);\n\t\t\ttx.sticky(c).turn = { tools: [] };\n\t\t\tif (through === undefined) {\n\t\t\t\tawait tx.write(c, {\n\t\t\t\t\tkind: \"pi.notice\",\n\t\t\t\t\tmodel: [{ role: \"user\", content: \"Context too large; nothing to compact.\", timestamp: rt.now() }],\n\t\t\t\t});\n\t\t\t\ttx.emit({\n\t\t\t\t\ttype: \"generation.failed\",\n\t\t\t\t\ttaskId: current.id,\n\t\t\t\t\treason: \"overflow\",\n\t\t\t\t\tdetail: \"request exceeds context window and nothing is collapsible\",\n\t\t\t\t});\n\t\t\t\tawait settleFailedTurn(tx, current, task.input.inputs, \"overflow\", head?.id);\n\t\t\t\treturn fail(\"overflow\", \"request exceeds context window and nothing is collapsible\");\n\t\t\t}\n\t\t\tconst collapse = tx.createTask({ kind: \"pi.collapse\", input: { reason: \"overflow\", through } });\n\t\t\ttx.createTask({ kind: \"pi.generation\", after: [collapse], input: { inputs: task.input.inputs } });\n\t\t\ttx.emit({\n\t\t\t\ttype: \"generation.failed\",\n\t\t\t\ttaskId: current.id,\n\t\t\t\treason: \"overflow\",\n\t\t\t\tdetail: `collapsing through ${through}`,\n\t\t\t});\n\t\t\treturn fail(\"overflow\", `collapsing through ${through}`);\n\t\t},\n\t};\n}\n"]}
|