@earendil-works/pi-agent-core 0.85.0 → 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.
Files changed (198) hide show
  1. package/README.md +16 -6
  2. package/dist/agent-loop.d.ts.map +1 -1
  3. package/dist/agent-loop.js +64 -22
  4. package/dist/agent-loop.js.map +1 -1
  5. package/dist/agent.d.ts +5 -3
  6. package/dist/agent.d.ts.map +1 -1
  7. package/dist/agent.js +15 -6
  8. package/dist/agent.js.map +1 -1
  9. package/dist/harness/config.d.ts +1 -1
  10. package/dist/harness/config.d.ts.map +1 -1
  11. package/dist/harness/config.js +10 -2
  12. package/dist/harness/config.js.map +1 -1
  13. package/dist/harness/env/nodejs.d.ts +2 -1
  14. package/dist/harness/env/nodejs.d.ts.map +1 -1
  15. package/dist/harness/env/nodejs.js +98 -27
  16. package/dist/harness/env/nodejs.js.map +1 -1
  17. package/dist/harness/execution/tools.d.ts +1 -1
  18. package/dist/harness/execution/tools.d.ts.map +1 -1
  19. package/dist/harness/execution/tools.js +0 -2
  20. package/dist/harness/execution/tools.js.map +1 -1
  21. package/dist/harness/messages.d.ts.map +1 -1
  22. package/dist/harness/messages.js +1 -0
  23. package/dist/harness/messages.js.map +1 -1
  24. package/dist/harness/pico3/bash.d.ts +10 -0
  25. package/dist/harness/pico3/bash.d.ts.map +1 -0
  26. package/dist/harness/pico3/bash.js +25 -0
  27. package/dist/harness/pico3/bash.js.map +1 -0
  28. package/dist/harness/pico3/bounded.d.ts +21 -0
  29. package/dist/harness/pico3/bounded.d.ts.map +1 -0
  30. package/dist/harness/pico3/bounded.js +98 -0
  31. package/dist/harness/pico3/bounded.js.map +1 -0
  32. package/dist/harness/pico3/chord.d.ts +41 -0
  33. package/dist/harness/pico3/chord.d.ts.map +1 -0
  34. package/dist/harness/pico3/chord.js +130 -0
  35. package/dist/harness/pico3/chord.js.map +1 -0
  36. package/dist/harness/pico3/context.d.ts +16 -0
  37. package/dist/harness/pico3/context.d.ts.map +1 -0
  38. package/dist/harness/pico3/context.js +88 -0
  39. package/dist/harness/pico3/context.js.map +1 -0
  40. package/dist/harness/pico3/harness.d.ts +197 -0
  41. package/dist/harness/pico3/harness.d.ts.map +1 -0
  42. package/dist/harness/pico3/harness.js +654 -0
  43. package/dist/harness/pico3/harness.js.map +1 -0
  44. package/dist/harness/pico3/hooks.d.ts +10 -0
  45. package/dist/harness/pico3/hooks.d.ts.map +1 -0
  46. package/dist/harness/pico3/hooks.js +33 -0
  47. package/dist/harness/pico3/hooks.js.map +1 -0
  48. package/dist/harness/pico3/index.d.ts +19 -0
  49. package/dist/harness/pico3/index.d.ts.map +1 -0
  50. package/dist/harness/pico3/index.js +15 -0
  51. package/dist/harness/pico3/index.js.map +1 -0
  52. package/dist/harness/pico3/jsonl.d.ts +58 -0
  53. package/dist/harness/pico3/jsonl.d.ts.map +1 -0
  54. package/dist/harness/pico3/jsonl.js +325 -0
  55. package/dist/harness/pico3/jsonl.js.map +1 -0
  56. package/dist/harness/pico3/kinds/collapse.d.ts +49 -0
  57. package/dist/harness/pico3/kinds/collapse.d.ts.map +1 -0
  58. package/dist/harness/pico3/kinds/collapse.js +191 -0
  59. package/dist/harness/pico3/kinds/collapse.js.map +1 -0
  60. package/dist/harness/pico3/kinds/entries.d.ts +78 -0
  61. package/dist/harness/pico3/kinds/entries.d.ts.map +1 -0
  62. package/dist/harness/pico3/kinds/entries.js +13 -0
  63. package/dist/harness/pico3/kinds/entries.js.map +1 -0
  64. package/dist/harness/pico3/kinds/frames.d.ts +9 -0
  65. package/dist/harness/pico3/kinds/frames.d.ts.map +1 -0
  66. package/dist/harness/pico3/kinds/frames.js +75 -0
  67. package/dist/harness/pico3/kinds/frames.js.map +1 -0
  68. package/dist/harness/pico3/kinds/generation.d.ts +94 -0
  69. package/dist/harness/pico3/kinds/generation.d.ts.map +1 -0
  70. package/dist/harness/pico3/kinds/generation.js +504 -0
  71. package/dist/harness/pico3/kinds/generation.js.map +1 -0
  72. package/dist/harness/pico3/kinds/job.d.ts +44 -0
  73. package/dist/harness/pico3/kinds/job.d.ts.map +1 -0
  74. package/dist/harness/pico3/kinds/job.js +143 -0
  75. package/dist/harness/pico3/kinds/job.js.map +1 -0
  76. package/dist/harness/pico3/kinds/plugin.d.ts +15 -0
  77. package/dist/harness/pico3/kinds/plugin.d.ts.map +1 -0
  78. package/dist/harness/pico3/kinds/plugin.js +35 -0
  79. package/dist/harness/pico3/kinds/plugin.js.map +1 -0
  80. package/dist/harness/pico3/kinds/post-tools.d.ts +22 -0
  81. package/dist/harness/pico3/kinds/post-tools.d.ts.map +1 -0
  82. package/dist/harness/pico3/kinds/post-tools.js +145 -0
  83. package/dist/harness/pico3/kinds/post-tools.js.map +1 -0
  84. package/dist/harness/pico3/kinds/task-api.d.ts +3 -0
  85. package/dist/harness/pico3/kinds/task-api.d.ts.map +1 -0
  86. package/dist/harness/pico3/kinds/task-api.js +45 -0
  87. package/dist/harness/pico3/kinds/task-api.js.map +1 -0
  88. package/dist/harness/pico3/kinds/tool.d.ts +43 -0
  89. package/dist/harness/pico3/kinds/tool.d.ts.map +1 -0
  90. package/dist/harness/pico3/kinds/tool.js +373 -0
  91. package/dist/harness/pico3/kinds/tool.js.map +1 -0
  92. package/dist/harness/pico3/membrane.d.ts +23 -0
  93. package/dist/harness/pico3/membrane.d.ts.map +1 -0
  94. package/dist/harness/pico3/membrane.js +141 -0
  95. package/dist/harness/pico3/membrane.js.map +1 -0
  96. package/dist/harness/pico3/memory.d.ts +53 -0
  97. package/dist/harness/pico3/memory.d.ts.map +1 -0
  98. package/dist/harness/pico3/memory.js +264 -0
  99. package/dist/harness/pico3/memory.js.map +1 -0
  100. package/dist/harness/pico3/scheduler.d.ts +46 -0
  101. package/dist/harness/pico3/scheduler.d.ts.map +1 -0
  102. package/dist/harness/pico3/scheduler.js +438 -0
  103. package/dist/harness/pico3/scheduler.js.map +1 -0
  104. package/dist/harness/pico3/session.d.ts +263 -0
  105. package/dist/harness/pico3/session.d.ts.map +1 -0
  106. package/dist/harness/pico3/session.js +1347 -0
  107. package/dist/harness/pico3/session.js.map +1 -0
  108. package/dist/harness/pico3/system.d.ts +126 -0
  109. package/dist/harness/pico3/system.d.ts.map +1 -0
  110. package/dist/harness/pico3/system.js +244 -0
  111. package/dist/harness/pico3/system.js.map +1 -0
  112. package/dist/harness/pico3/types.d.ts +973 -0
  113. package/dist/harness/pico3/types.d.ts.map +1 -0
  114. package/dist/harness/pico3/types.js +96 -0
  115. package/dist/harness/pico3/types.js.map +1 -0
  116. package/dist/harness/pico3/view.d.ts +34 -0
  117. package/dist/harness/pico3/view.d.ts.map +1 -0
  118. package/dist/harness/pico3/view.js +417 -0
  119. package/dist/harness/pico3/view.js.map +1 -0
  120. package/dist/harness/runtime/drive/boundary.d.ts.map +1 -1
  121. package/dist/harness/runtime/drive/boundary.js +6 -3
  122. package/dist/harness/runtime/drive/boundary.js.map +1 -1
  123. package/dist/harness/runtime/drive/response.d.ts.map +1 -1
  124. package/dist/harness/runtime/drive/response.js +4 -4
  125. package/dist/harness/runtime/drive/response.js.map +1 -1
  126. package/dist/harness/runtime/drive/retry.d.ts +2 -2
  127. package/dist/harness/runtime/drive/retry.d.ts.map +1 -1
  128. package/dist/harness/runtime/drive/retry.js +3 -6
  129. package/dist/harness/runtime/drive/retry.js.map +1 -1
  130. package/dist/harness/runtime/drive/structural.d.ts.map +1 -1
  131. package/dist/harness/runtime/drive/structural.js +5 -5
  132. package/dist/harness/runtime/drive/structural.js.map +1 -1
  133. package/dist/harness/runtime/drive/tool-placement.d.ts.map +1 -1
  134. package/dist/harness/runtime/drive/tool-placement.js +2 -27
  135. package/dist/harness/runtime/drive/tool-placement.js.map +1 -1
  136. package/dist/harness/runtime/drive/tools.d.ts.map +1 -1
  137. package/dist/harness/runtime/drive/tools.js.map +1 -1
  138. package/dist/harness/session/fork-policy.d.ts +20 -12
  139. package/dist/harness/session/fork-policy.d.ts.map +1 -1
  140. package/dist/harness/session/fork-policy.js +45 -12
  141. package/dist/harness/session/fork-policy.js.map +1 -1
  142. package/dist/harness/session/fork.d.ts +0 -2
  143. package/dist/harness/session/fork.d.ts.map +1 -1
  144. package/dist/harness/session/fork.js +20 -68
  145. package/dist/harness/session/fork.js.map +1 -1
  146. package/dist/harness/session/in-memory-storage-state.d.ts +5 -5
  147. package/dist/harness/session/in-memory-storage-state.d.ts.map +1 -1
  148. package/dist/harness/session/in-memory-storage-state.js +99 -39
  149. package/dist/harness/session/in-memory-storage-state.js.map +1 -1
  150. package/dist/harness/session/index.d.ts +1 -1
  151. package/dist/harness/session/index.d.ts.map +1 -1
  152. package/dist/harness/session/index.js +1 -1
  153. package/dist/harness/session/index.js.map +1 -1
  154. package/dist/harness/session/jsonl/fork.d.ts +38 -0
  155. package/dist/harness/session/jsonl/fork.d.ts.map +1 -0
  156. package/dist/harness/session/jsonl/fork.js +264 -0
  157. package/dist/harness/session/jsonl/fork.js.map +1 -0
  158. package/dist/harness/session/jsonl/io.d.ts +14 -0
  159. package/dist/harness/session/jsonl/io.d.ts.map +1 -0
  160. package/dist/harness/session/jsonl/io.js +86 -0
  161. package/dist/harness/session/jsonl/io.js.map +1 -0
  162. package/dist/harness/session/jsonl/legacy-v3.d.ts +33 -8
  163. package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -1
  164. package/dist/harness/session/jsonl/legacy-v3.js +285 -206
  165. package/dist/harness/session/jsonl/legacy-v3.js.map +1 -1
  166. package/dist/harness/session/jsonl/repo.d.ts +2 -1
  167. package/dist/harness/session/jsonl/repo.d.ts.map +1 -1
  168. package/dist/harness/session/jsonl/repo.js +36 -20
  169. package/dist/harness/session/jsonl/repo.js.map +1 -1
  170. package/dist/harness/session/jsonl/storage.d.ts +4 -5
  171. package/dist/harness/session/jsonl/storage.d.ts.map +1 -1
  172. package/dist/harness/session/jsonl/storage.js +39 -113
  173. package/dist/harness/session/jsonl/storage.js.map +1 -1
  174. package/dist/harness/session/memory.d.ts +3 -5
  175. package/dist/harness/session/memory.d.ts.map +1 -1
  176. package/dist/harness/session/memory.js +9 -14
  177. package/dist/harness/session/memory.js.map +1 -1
  178. package/dist/harness/session/testing/conformance/session-repo.d.ts +2 -0
  179. package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -1
  180. package/dist/harness/session/testing/conformance/session-repo.js +220 -1
  181. package/dist/harness/session/testing/conformance/session-repo.js.map +1 -1
  182. package/dist/harness/session/testing/index.d.ts +1 -1
  183. package/dist/harness/session/testing/index.d.ts.map +1 -1
  184. package/dist/harness/session/testing/index.js +1 -1
  185. package/dist/harness/session/testing/index.js.map +1 -1
  186. package/dist/harness/session/types.d.ts +1 -0
  187. package/dist/harness/session/types.d.ts.map +1 -1
  188. package/dist/harness/session/types.js.map +1 -1
  189. package/dist/harness/types.d.ts +14 -0
  190. package/dist/harness/types.d.ts.map +1 -1
  191. package/dist/harness/types.js.map +1 -1
  192. package/dist/proxy.d.ts +2 -2
  193. package/dist/proxy.d.ts.map +1 -1
  194. package/dist/proxy.js.map +1 -1
  195. package/dist/types.d.ts +30 -14
  196. package/dist/types.d.ts.map +1 -1
  197. package/dist/types.js.map +1 -1
  198. package/package.json +10 -6
@@ -0,0 +1,417 @@
1
+ import { applyImmutable, track } from "@earendil-works/chord/delta";
2
+ export const WATCH_CAPACITY = 256;
3
+ export function applyEnvelope(view, envelope) {
4
+ return applyImmutable(view, envelope.ops);
5
+ }
6
+ export class ViewManager {
7
+ records = new Map();
8
+ deliveries = [];
9
+ session;
10
+ onReport;
11
+ constructor(session, onReport) {
12
+ this.session = session;
13
+ this.onReport = onReport;
14
+ }
15
+ watch(conversation, entries) {
16
+ let record = this.records.get(conversation.id);
17
+ if (record === undefined) {
18
+ const tracker = track(this.build(conversation, entries));
19
+ tracker.flush();
20
+ record = { conversationId: conversation.id, tracker, watchers: new Set(), revision: 0 };
21
+ this.records.set(conversation.id, record);
22
+ }
23
+ const watcher = new WatchImpl(structuredClone(record.tracker.target), record.revision, this.onReport, () => {
24
+ record.watchers.delete(watcher);
25
+ if (record.watchers.size === 0 && this.records.get(conversation.id) === record)
26
+ this.records.delete(conversation.id);
27
+ });
28
+ record.watchers.add(watcher);
29
+ return watcher;
30
+ }
31
+ /** Runs on the Session line after persistence and in-memory indexes update. */
32
+ update(result) {
33
+ for (const record of [...this.records.values()]) {
34
+ const conversation = this.session.conversationRecords.get(record.conversationId);
35
+ if (conversation === undefined)
36
+ continue;
37
+ try {
38
+ const changes = result.changes;
39
+ const appended = changes.entries.filter((entry) => entry.conversationId === record.conversationId);
40
+ const documentChanges = changes.docs.filter((change) => change.ref.doc === "session" || change.ref.conversationId === record.conversationId);
41
+ const taskChanged = changes.tasks.some((task) => task.conversationId === record.conversationId);
42
+ const events = changes.events
43
+ .filter((scoped) => scoped.conversationId === record.conversationId)
44
+ .map((scoped) => scoped.event);
45
+ if (appended.length === 0 && documentChanges.length === 0 && !taskChanged && events.length === 0)
46
+ continue;
47
+ const entryOps = applyEntries(record.tracker, appended);
48
+ const state = record.tracker.state;
49
+ const rewindableChanged = documentChanges.some((change) => change.ref.doc === "rewindable" && change.ref.conversationId === record.conversationId);
50
+ const stickyChanged = documentChanges.some((change) => change.ref.doc === "sticky" && change.ref.conversationId === record.conversationId);
51
+ const configChanged = events.some((event) => event.type === "config.changed");
52
+ const pluginChanged = documentChanges.some((change) => touchesKey(change.ops, "plugins"));
53
+ const rewindable = rewindableChanged || configChanged || pluginChanged
54
+ ? this.document({ doc: "rewindable", conversationId: record.conversationId })
55
+ : undefined;
56
+ const sticky = stickyChanged || taskChanged || configChanged || pluginChanged
57
+ ? this.document({ doc: "sticky", conversationId: record.conversationId })
58
+ : undefined;
59
+ if (configChanged)
60
+ syncRecord(state.config, this.config(rewindable, sticky));
61
+ if (stickyChanged)
62
+ syncArray(state.inbox, structuredClone(sticky.inbox));
63
+ if (stickyChanged || taskChanged) {
64
+ syncOptional(state, "turn", this.turn(record.conversationId, sticky).turn);
65
+ syncOptional(state, "compaction", this.compaction(record.conversationId).compaction);
66
+ syncRecord(state.tasks, this.tasks(record.conversationId, sticky));
67
+ }
68
+ if (pluginChanged) {
69
+ const session = this.document({ doc: "session" });
70
+ syncRecord(state.plugins, this.plugins(rewindable, sticky, session));
71
+ }
72
+ const ops = [...entryOps, ...record.tracker.flush()];
73
+ if (ops.length === 0 && events.length === 0)
74
+ continue;
75
+ const envelope = Object.freeze({
76
+ revision: ++record.revision,
77
+ ops: Object.freeze(ops),
78
+ events: Object.freeze(events),
79
+ });
80
+ this.deliveries.push({ envelope, watchers: [...record.watchers] });
81
+ }
82
+ catch (error) {
83
+ this.records.delete(record.conversationId);
84
+ for (const watcher of [...record.watchers])
85
+ watcher.fail(error);
86
+ }
87
+ }
88
+ }
89
+ /** Runs after the Session line; listeners are synchronous and ordered. */
90
+ deliver() {
91
+ for (const delivery of this.deliveries.splice(0)) {
92
+ for (const watcher of delivery.watchers)
93
+ watcher.accept(delivery.envelope);
94
+ }
95
+ }
96
+ close() {
97
+ const records = [...this.records.values()];
98
+ this.records.clear();
99
+ this.deliveries.length = 0;
100
+ for (const record of records)
101
+ for (const watcher of [...record.watchers])
102
+ watcher.stop();
103
+ }
104
+ build(conversation, entries) {
105
+ const rewindable = this.document({ doc: "rewindable", conversationId: conversation.id });
106
+ const sticky = this.document({ doc: "sticky", conversationId: conversation.id });
107
+ const session = this.document({ doc: "session" });
108
+ const { sections: _sections, ...publicConversation } = conversation;
109
+ return {
110
+ conversation: structuredClone(publicConversation),
111
+ entries: structuredClone(entries),
112
+ config: this.config(rewindable, sticky),
113
+ inbox: structuredClone(sticky.inbox),
114
+ ...this.turn(conversation.id, sticky),
115
+ ...this.compaction(conversation.id),
116
+ tasks: this.tasks(conversation.id, sticky),
117
+ plugins: this.plugins(rewindable, sticky, session),
118
+ };
119
+ }
120
+ document(ref) {
121
+ const value = this.session.loadedDocument(ref);
122
+ if (value === undefined)
123
+ throw new Error(`view document ${ref.doc} is not loaded`);
124
+ return value;
125
+ }
126
+ config(rewindable, sticky) {
127
+ const out = {};
128
+ for (const [key, doc] of this.session.defaults.route) {
129
+ const source = doc === "rewindable" ? rewindable : sticky;
130
+ const value = key in source ? source[key] : this.session.defaults[doc][key];
131
+ if (value !== undefined)
132
+ out[key] = structuredClone(value);
133
+ }
134
+ return out;
135
+ }
136
+ turn(conversationId, sticky) {
137
+ const live = [...this.session.liveTasks.values()].filter((task) => task.conversationId === conversationId);
138
+ const turnTasks = live.filter((task) => this.session.kinds.get(task.kind)?.turn === true);
139
+ if (turnTasks.length === 0)
140
+ return {};
141
+ const generation = turnTasks.find((task) => task.kind === "pi.generation");
142
+ const postTools = turnTasks.find((task) => task.kind === "pi.post_tools");
143
+ const inputTask = generation ?? postTools;
144
+ const inputs = inputTask === undefined ? [] : inputIds(inputTask);
145
+ const turn = {
146
+ inputs,
147
+ ...(generation === undefined
148
+ ? {}
149
+ : { generation: generationStatus(generation, sticky.turn.message !== undefined) }),
150
+ ...(sticky.turn.message === undefined ? {} : { message: structuredClone(sticky.turn.message) }),
151
+ tools: sticky.turn.tools.map(stripPrivateToolState),
152
+ };
153
+ return { turn };
154
+ }
155
+ compaction(conversationId) {
156
+ const task = [...this.session.liveTasks.values()].find((candidate) => candidate.conversationId === conversationId && candidate.kind === "pi.collapse");
157
+ if (task === undefined)
158
+ return {};
159
+ const input = task.input;
160
+ const checkpoint = task.checkpoint;
161
+ return {
162
+ compaction: {
163
+ taskId: task.id,
164
+ reason: input.reason,
165
+ stage: checkpoint?.phase === "retrying" ? "retrying" : "summarizing",
166
+ attempt: checkpoint?.attempt ?? 1,
167
+ ...(checkpoint?.phase === "retrying" && checkpoint.untilMs !== undefined
168
+ ? { retryAt: checkpoint.untilMs }
169
+ : {}),
170
+ },
171
+ };
172
+ }
173
+ tasks(conversationId, sticky) {
174
+ const out = {};
175
+ for (const task of this.session.liveTasks.values()) {
176
+ const kind = this.session.kinds.get(task.kind);
177
+ if (task.conversationId !== conversationId ||
178
+ kind === undefined ||
179
+ kind.turn === true ||
180
+ task.kind === "pi.collapse")
181
+ continue;
182
+ const slot = sticky.tasks[task.id];
183
+ out[task.id] = {
184
+ kind: task.kind,
185
+ ...(task.background ? { background: true } : {}),
186
+ ...(task.abort ? { marked: true } : {}),
187
+ status: describe(kind, task, slot),
188
+ };
189
+ }
190
+ return out;
191
+ }
192
+ plugins(rewindable, sticky, session) {
193
+ const out = {};
194
+ const sessionPlugins = (session.plugins ?? {});
195
+ for (const [id, registration] of this.session.namespaces) {
196
+ if (registration.project === undefined)
197
+ continue;
198
+ const merged = {
199
+ ...registration.defaults.rewindable,
200
+ ...registration.defaults.sticky,
201
+ ...registration.defaults.session,
202
+ ...(rewindable.plugins[id] ?? {}),
203
+ ...(sticky.plugins[id] ?? {}),
204
+ ...(sessionPlugins[id] ?? {}),
205
+ };
206
+ out[id] = strictJson(registration.project(structuredClone(merged)), `namespace ${id} view`);
207
+ }
208
+ return out;
209
+ }
210
+ }
211
+ class WatchImpl {
212
+ view;
213
+ initialRevision;
214
+ onReport;
215
+ onStop;
216
+ listener;
217
+ buffer = [];
218
+ stopped = false;
219
+ constructor(view, revision, onReport, onStop) {
220
+ this.view = view;
221
+ this.initialRevision = revision;
222
+ this.onReport = onReport;
223
+ this.onStop = onStop;
224
+ }
225
+ get revision() {
226
+ return this.initialRevision;
227
+ }
228
+ get closed() {
229
+ return this.stopped;
230
+ }
231
+ start(listener) {
232
+ if (this.listener !== undefined || this.stopped)
233
+ return;
234
+ this.listener = listener;
235
+ for (const envelope of this.buffer.splice(0)) {
236
+ if (this.stopped)
237
+ break;
238
+ this.deliver(envelope);
239
+ }
240
+ }
241
+ stop() {
242
+ if (this.stopped)
243
+ return;
244
+ this.stopped = true;
245
+ this.buffer.length = 0;
246
+ this.onStop();
247
+ }
248
+ accept(envelope) {
249
+ if (this.stopped)
250
+ return;
251
+ if (this.listener === undefined) {
252
+ if (this.buffer.length >= WATCH_CAPACITY) {
253
+ this.stop();
254
+ this.report(new Error(`watch capacity ${WATCH_CAPACITY} exceeded before start()`));
255
+ return;
256
+ }
257
+ this.buffer.push(envelope);
258
+ return;
259
+ }
260
+ this.deliver(envelope);
261
+ }
262
+ deliver(envelope) {
263
+ try {
264
+ this.listener(envelope);
265
+ }
266
+ catch (error) {
267
+ this.fail(error);
268
+ }
269
+ }
270
+ fail(error) {
271
+ this.stop();
272
+ this.report(error);
273
+ }
274
+ report(error) {
275
+ try {
276
+ this.onReport(error);
277
+ }
278
+ catch { }
279
+ }
280
+ }
281
+ function applyEntries(tracker, appended) {
282
+ const ops = [];
283
+ const entries = tracker.state.entries;
284
+ for (const entry of appended) {
285
+ if (entry.head !== undefined) {
286
+ const retained = entries.findIndex((candidate) => candidate.id >= entry.head);
287
+ const remove = retained < 0 ? entries.length : retained;
288
+ if (remove > 0) {
289
+ ops.push(...tracker.flush());
290
+ entries.splice(0, remove);
291
+ tracker.flush();
292
+ ops.push(["p", ["entries"], 0, remove, []]);
293
+ }
294
+ }
295
+ entries.push(structuredClone(entry));
296
+ }
297
+ return ops;
298
+ }
299
+ function inputIds(task) {
300
+ const inputs = task.input.inputs;
301
+ return Array.isArray(inputs) ? inputs.filter((value) => typeof value === "number") : [];
302
+ }
303
+ function generationStatus(task, streaming) {
304
+ if (task.status === "pending" && task.after.length > 0)
305
+ return { stage: "waiting", on: "compaction" };
306
+ const checkpoint = task.checkpoint;
307
+ if (checkpoint?.phase === "requesting")
308
+ return { stage: streaming ? "streaming" : "requesting", attempt: checkpoint.attempt ?? 1 };
309
+ if (checkpoint?.phase === "retrying")
310
+ return {
311
+ stage: "retrying",
312
+ attempt: checkpoint.attempt ?? 1,
313
+ retryAt: checkpoint.untilMs ?? 0,
314
+ lastError: checkpoint.lastError ?? "",
315
+ };
316
+ if (checkpoint?.phase === "deferred")
317
+ return { stage: "deferred", attempt: checkpoint.attempt ?? 1, pollAt: checkpoint.pollAt ?? 0 };
318
+ return { stage: "preparing" };
319
+ }
320
+ function stripPrivateToolState(slot) {
321
+ const { memos: _memos, ...view } = structuredClone(slot);
322
+ return view;
323
+ }
324
+ function describe(kind, task, slot) {
325
+ if (typeof kind.describe !== "function")
326
+ return { phase: task.checkpoint?.phase ?? (task.status === "pending" ? "pending" : "running") };
327
+ const publicSlot = slot === undefined ? undefined : structuredClone(slot);
328
+ if (publicSlot !== undefined)
329
+ delete publicSlot.memos;
330
+ const value = kind.describe({
331
+ ...task,
332
+ ...(publicSlot === undefined ? {} : { slot: publicSlot }),
333
+ });
334
+ return strictJson(value, `task kind ${task.kind} describe`);
335
+ }
336
+ function strictJson(value, what) {
337
+ const encoded = JSON.stringify(value);
338
+ if (encoded === undefined)
339
+ throw new Error(`${what} returned a non-JSON value`);
340
+ return JSON.parse(encoded);
341
+ }
342
+ function touchesKey(ops, key) {
343
+ return ops.some((op) => op[0] === "r" || op[1][0] === key);
344
+ }
345
+ function syncOptional(target, key, next) {
346
+ const record = target;
347
+ if (next === undefined) {
348
+ delete record[key];
349
+ return;
350
+ }
351
+ const current = record[key];
352
+ if (same(current, next))
353
+ return;
354
+ if (isRecord(current) && isRecord(next))
355
+ syncRecord(current, next);
356
+ else
357
+ record[key] = structuredClone(next);
358
+ }
359
+ function syncRecord(target, next) {
360
+ for (const key of Object.keys(target))
361
+ if (!(key in next))
362
+ delete target[key];
363
+ for (const [key, value] of Object.entries(next)) {
364
+ const current = target[key];
365
+ if (same(current, value))
366
+ continue;
367
+ if (Array.isArray(current) && Array.isArray(value)) {
368
+ syncArray(current, value);
369
+ continue;
370
+ }
371
+ if (isRecord(current) && isRecord(value)) {
372
+ syncRecord(current, value);
373
+ continue;
374
+ }
375
+ target[key] = structuredClone(value);
376
+ }
377
+ }
378
+ function syncArray(target, next) {
379
+ let prefix = 0;
380
+ while (prefix < target.length && prefix < next.length) {
381
+ if (same(target[prefix], next[prefix])) {
382
+ prefix++;
383
+ continue;
384
+ }
385
+ const current = target[prefix];
386
+ const replacement = next[prefix];
387
+ if (!isRecord(current) || !isRecord(replacement) || !sameArrayItem(current, replacement))
388
+ break;
389
+ syncRecord(current, replacement);
390
+ prefix++;
391
+ }
392
+ if (prefix === target.length && prefix === next.length)
393
+ return;
394
+ if (prefix === target.length) {
395
+ target.push(...structuredClone(next.slice(prefix)));
396
+ return;
397
+ }
398
+ target.splice(prefix, target.length - prefix, ...structuredClone(next.slice(prefix)));
399
+ }
400
+ function sameArrayItem(current, next) {
401
+ if (typeof current.id === "number" || typeof next.id === "number")
402
+ return current.id === next.id;
403
+ if (typeof current.callId === "string" || typeof next.callId === "string")
404
+ return current.callId === next.callId;
405
+ if (typeof current.type === "string" || typeof next.type === "string")
406
+ return current.type === next.type;
407
+ return false;
408
+ }
409
+ function isRecord(value) {
410
+ return typeof value === "object" && value !== null && !Array.isArray(value);
411
+ }
412
+ function same(a, b) {
413
+ if (Object.is(a, b))
414
+ return true;
415
+ return JSON.stringify(a) === JSON.stringify(b);
416
+ }
417
+ //# sourceMappingURL=view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../../../src/harness/pico3/view.ts"],"names":[],"mappings":"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","sourcesContent":["import { applyImmutable, type Op, type Tracker, track } from \"@earendil-works/chord/delta\";\nimport type { CommitResult, Session } from \"./session.ts\";\nimport type {\n\tAnyKind,\n\tConversation,\n\tConversationView,\n\tDocRef,\n\tEnvelope,\n\tGenerationStatus,\n\tId,\n\tJsonObject,\n\tJsonValue,\n\tRewindableState,\n\tStickyState,\n\tTask,\n\tToolSlot,\n\tTurnView,\n\tViewEvent,\n} from \"./types.ts\";\n\nexport const WATCH_CAPACITY = 256;\n\nexport interface Watch {\n\treadonly view: ConversationView;\n\treadonly revision: number;\n\treadonly closed: boolean;\n\tstart(listener: (envelope: Envelope) => void): void;\n\tstop(): void;\n}\n\nexport function applyEnvelope(view: ConversationView, envelope: Envelope): ConversationView {\n\treturn applyImmutable(view, envelope.ops) as ConversationView;\n}\n\ntype Listener = (envelope: Envelope) => void;\ntype ViewRecord = {\n\treadonly conversationId: Id;\n\treadonly tracker: Tracker<ConversationView>;\n\treadonly watchers: Set<WatchImpl>;\n\trevision: number;\n};\ntype Delivery = { envelope: Envelope; watchers: WatchImpl[] };\n\nexport class ViewManager {\n\tprivate readonly records = new Map<Id, ViewRecord>();\n\tprivate readonly deliveries: Delivery[] = [];\n\tprivate readonly session: Session;\n\tprivate readonly onReport: (error: unknown) => void;\n\n\tconstructor(session: Session, onReport: (error: unknown) => void) {\n\t\tthis.session = session;\n\t\tthis.onReport = onReport;\n\t}\n\n\twatch(conversation: Conversation, entries: EntryList): Watch {\n\t\tlet record = this.records.get(conversation.id);\n\t\tif (record === undefined) {\n\t\t\tconst tracker = track(this.build(conversation, entries));\n\t\t\ttracker.flush();\n\t\t\trecord = { conversationId: conversation.id, tracker, watchers: new Set(), revision: 0 };\n\t\t\tthis.records.set(conversation.id, record);\n\t\t}\n\t\tconst watcher = new WatchImpl(structuredClone(record.tracker.target), record.revision, this.onReport, () => {\n\t\t\trecord!.watchers.delete(watcher);\n\t\t\tif (record!.watchers.size === 0 && this.records.get(conversation.id) === record)\n\t\t\t\tthis.records.delete(conversation.id);\n\t\t});\n\t\trecord.watchers.add(watcher);\n\t\treturn watcher;\n\t}\n\n\t/** Runs on the Session line after persistence and in-memory indexes update. */\n\tupdate(result: CommitResult<unknown>): void {\n\t\tfor (const record of [...this.records.values()]) {\n\t\t\tconst conversation = this.session.conversationRecords.get(record.conversationId);\n\t\t\tif (conversation === undefined) continue;\n\t\t\ttry {\n\t\t\t\tconst changes = result.changes;\n\t\t\t\tconst appended = changes.entries.filter((entry) => entry.conversationId === record.conversationId);\n\t\t\t\tconst documentChanges = changes.docs.filter(\n\t\t\t\t\t(change) => change.ref.doc === \"session\" || change.ref.conversationId === record.conversationId,\n\t\t\t\t);\n\t\t\t\tconst taskChanged = changes.tasks.some((task) => task.conversationId === record.conversationId);\n\t\t\t\tconst events = changes.events\n\t\t\t\t\t.filter((scoped) => scoped.conversationId === record.conversationId)\n\t\t\t\t\t.map((scoped) => scoped.event);\n\t\t\t\tif (appended.length === 0 && documentChanges.length === 0 && !taskChanged && events.length === 0) continue;\n\n\t\t\t\tconst entryOps = applyEntries(record.tracker, appended);\n\t\t\t\tconst state = record.tracker.state;\n\t\t\t\tconst rewindableChanged = documentChanges.some(\n\t\t\t\t\t(change) => change.ref.doc === \"rewindable\" && change.ref.conversationId === record.conversationId,\n\t\t\t\t);\n\t\t\t\tconst stickyChanged = documentChanges.some(\n\t\t\t\t\t(change) => change.ref.doc === \"sticky\" && change.ref.conversationId === record.conversationId,\n\t\t\t\t);\n\t\t\t\tconst configChanged = events.some((event) => event.type === \"config.changed\");\n\t\t\t\tconst pluginChanged = documentChanges.some((change) => touchesKey(change.ops, \"plugins\"));\n\t\t\t\tconst rewindable =\n\t\t\t\t\trewindableChanged || configChanged || pluginChanged\n\t\t\t\t\t\t? this.document<RewindableState>({ doc: \"rewindable\", conversationId: record.conversationId })\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst sticky =\n\t\t\t\t\tstickyChanged || taskChanged || configChanged || pluginChanged\n\t\t\t\t\t\t? this.document<StickyState>({ doc: \"sticky\", conversationId: record.conversationId })\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\tif (configChanged) syncRecord(state.config, this.config(rewindable!, sticky!));\n\t\t\t\tif (stickyChanged) syncArray(state.inbox, structuredClone(sticky!.inbox));\n\t\t\t\tif (stickyChanged || taskChanged) {\n\t\t\t\t\tsyncOptional(state, \"turn\", this.turn(record.conversationId, sticky!).turn);\n\t\t\t\t\tsyncOptional(state, \"compaction\", this.compaction(record.conversationId).compaction);\n\t\t\t\t\tsyncRecord(state.tasks, this.tasks(record.conversationId, sticky!));\n\t\t\t\t}\n\t\t\t\tif (pluginChanged) {\n\t\t\t\t\tconst session = this.document<JsonObject>({ doc: \"session\" });\n\t\t\t\t\tsyncRecord(state.plugins, this.plugins(rewindable!, sticky!, session));\n\t\t\t\t}\n\n\t\t\t\tconst ops = [...entryOps, ...record.tracker.flush()];\n\t\t\t\tif (ops.length === 0 && events.length === 0) continue;\n\t\t\t\tconst envelope = Object.freeze({\n\t\t\t\t\trevision: ++record.revision,\n\t\t\t\t\tops: Object.freeze(ops) as unknown as Op[],\n\t\t\t\t\tevents: Object.freeze(events) as unknown as ViewEvent[],\n\t\t\t\t}) satisfies Envelope;\n\t\t\t\tthis.deliveries.push({ envelope, watchers: [...record.watchers] });\n\t\t\t} catch (error) {\n\t\t\t\tthis.records.delete(record.conversationId);\n\t\t\t\tfor (const watcher of [...record.watchers]) watcher.fail(error);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Runs after the Session line; listeners are synchronous and ordered. */\n\tdeliver(): void {\n\t\tfor (const delivery of this.deliveries.splice(0)) {\n\t\t\tfor (const watcher of delivery.watchers) watcher.accept(delivery.envelope);\n\t\t}\n\t}\n\n\tclose(): void {\n\t\tconst records = [...this.records.values()];\n\t\tthis.records.clear();\n\t\tthis.deliveries.length = 0;\n\t\tfor (const record of records) for (const watcher of [...record.watchers]) watcher.stop();\n\t}\n\n\tprivate build(conversation: Conversation, entries: EntryList): ConversationView {\n\t\tconst rewindable = this.document<RewindableState>({ doc: \"rewindable\", conversationId: conversation.id });\n\t\tconst sticky = this.document<StickyState>({ doc: \"sticky\", conversationId: conversation.id });\n\t\tconst session = this.document<JsonObject>({ doc: \"session\" });\n\t\tconst { sections: _sections, ...publicConversation } = conversation;\n\t\treturn {\n\t\t\tconversation: structuredClone(publicConversation),\n\t\t\tentries: structuredClone(entries),\n\t\t\tconfig: this.config(rewindable, sticky),\n\t\t\tinbox: structuredClone(sticky.inbox),\n\t\t\t...this.turn(conversation.id, sticky),\n\t\t\t...this.compaction(conversation.id),\n\t\t\ttasks: this.tasks(conversation.id, sticky),\n\t\t\tplugins: this.plugins(rewindable, sticky, session),\n\t\t};\n\t}\n\n\tprivate document<T>(ref: DocRef): T {\n\t\tconst value = this.session.loadedDocument(ref);\n\t\tif (value === undefined) throw new Error(`view document ${ref.doc} is not loaded`);\n\t\treturn value as T;\n\t}\n\n\tprivate config(rewindable: RewindableState, sticky: StickyState): ConversationView[\"config\"] {\n\t\tconst out: ConversationView[\"config\"] = {};\n\t\tfor (const [key, doc] of this.session.defaults.route) {\n\t\t\tconst source = doc === \"rewindable\" ? rewindable : sticky;\n\t\t\tconst value = key in source ? source[key] : this.session.defaults[doc][key];\n\t\t\tif (value !== undefined) out[key] = structuredClone(value);\n\t\t}\n\t\treturn out;\n\t}\n\n\tprivate turn(conversationId: Id, sticky: StickyState): { turn?: TurnView } {\n\t\tconst live = [...this.session.liveTasks.values()].filter((task) => task.conversationId === conversationId);\n\t\tconst turnTasks = live.filter((task) => this.session.kinds.get(task.kind)?.turn === true);\n\t\tif (turnTasks.length === 0) return {};\n\t\tconst generation = turnTasks.find((task) => task.kind === \"pi.generation\");\n\t\tconst postTools = turnTasks.find((task) => task.kind === \"pi.post_tools\");\n\t\tconst inputTask = generation ?? postTools;\n\t\tconst inputs = inputTask === undefined ? [] : inputIds(inputTask);\n\t\tconst turn: TurnView = {\n\t\t\tinputs,\n\t\t\t...(generation === undefined\n\t\t\t\t? {}\n\t\t\t\t: { generation: generationStatus(generation, sticky.turn.message !== undefined) }),\n\t\t\t...(sticky.turn.message === undefined ? {} : { message: structuredClone(sticky.turn.message) }),\n\t\t\ttools: sticky.turn.tools.map(stripPrivateToolState),\n\t\t};\n\t\treturn { turn };\n\t}\n\n\tprivate compaction(conversationId: Id): { compaction?: ConversationView[\"compaction\"] } {\n\t\tconst task = [...this.session.liveTasks.values()].find(\n\t\t\t(candidate) => candidate.conversationId === conversationId && candidate.kind === \"pi.collapse\",\n\t\t);\n\t\tif (task === undefined) return {};\n\t\tconst input = task.input as { reason: \"threshold\" | \"manual\" | \"overflow\" };\n\t\tconst checkpoint = task.checkpoint as { phase?: string; attempt?: number; untilMs?: number } | undefined;\n\t\treturn {\n\t\t\tcompaction: {\n\t\t\t\ttaskId: task.id,\n\t\t\t\treason: input.reason,\n\t\t\t\tstage: checkpoint?.phase === \"retrying\" ? \"retrying\" : \"summarizing\",\n\t\t\t\tattempt: checkpoint?.attempt ?? 1,\n\t\t\t\t...(checkpoint?.phase === \"retrying\" && checkpoint.untilMs !== undefined\n\t\t\t\t\t? { retryAt: checkpoint.untilMs }\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate tasks(conversationId: Id, sticky: StickyState): ConversationView[\"tasks\"] {\n\t\tconst out: ConversationView[\"tasks\"] = {};\n\t\tfor (const task of this.session.liveTasks.values()) {\n\t\t\tconst kind = this.session.kinds.get(task.kind);\n\t\t\tif (\n\t\t\t\ttask.conversationId !== conversationId ||\n\t\t\t\tkind === undefined ||\n\t\t\t\tkind.turn === true ||\n\t\t\t\ttask.kind === \"pi.collapse\"\n\t\t\t)\n\t\t\t\tcontinue;\n\t\t\tconst slot = sticky.tasks[task.id];\n\t\t\tout[task.id] = {\n\t\t\t\tkind: task.kind,\n\t\t\t\t...(task.background ? { background: true as const } : {}),\n\t\t\t\t...(task.abort ? { marked: true as const } : {}),\n\t\t\t\tstatus: describe(kind, task, slot),\n\t\t\t};\n\t\t}\n\t\treturn out;\n\t}\n\n\tprivate plugins(rewindable: RewindableState, sticky: StickyState, session: JsonObject): ConversationView[\"plugins\"] {\n\t\tconst out: ConversationView[\"plugins\"] = {};\n\t\tconst sessionPlugins = (session.plugins ?? {}) as { [key: string]: JsonObject };\n\t\tfor (const [id, registration] of this.session.namespaces) {\n\t\t\tif (registration.project === undefined) continue;\n\t\t\tconst merged: JsonObject = {\n\t\t\t\t...registration.defaults.rewindable,\n\t\t\t\t...registration.defaults.sticky,\n\t\t\t\t...registration.defaults.session,\n\t\t\t\t...(rewindable.plugins[id] ?? {}),\n\t\t\t\t...(sticky.plugins[id] ?? {}),\n\t\t\t\t...(sessionPlugins[id] ?? {}),\n\t\t\t};\n\t\t\tout[id] = strictJson(registration.project(structuredClone(merged)), `namespace ${id} view`);\n\t\t}\n\t\treturn out;\n\t}\n}\n\ntype EntryList = ConversationView[\"entries\"];\n\nclass WatchImpl implements Watch {\n\treadonly view: ConversationView;\n\tprivate readonly initialRevision: number;\n\tprivate readonly onReport: (error: unknown) => void;\n\tprivate readonly onStop: () => void;\n\tprivate listener: Listener | undefined;\n\tprivate readonly buffer: Envelope[] = [];\n\tprivate stopped = false;\n\n\tconstructor(view: ConversationView, revision: number, onReport: (error: unknown) => void, onStop: () => void) {\n\t\tthis.view = view;\n\t\tthis.initialRevision = revision;\n\t\tthis.onReport = onReport;\n\t\tthis.onStop = onStop;\n\t}\n\n\tget revision(): number {\n\t\treturn this.initialRevision;\n\t}\n\tget closed(): boolean {\n\t\treturn this.stopped;\n\t}\n\n\tstart(listener: Listener): void {\n\t\tif (this.listener !== undefined || this.stopped) return;\n\t\tthis.listener = listener;\n\t\tfor (const envelope of this.buffer.splice(0)) {\n\t\t\tif (this.stopped) break;\n\t\t\tthis.deliver(envelope);\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tif (this.stopped) return;\n\t\tthis.stopped = true;\n\t\tthis.buffer.length = 0;\n\t\tthis.onStop();\n\t}\n\n\taccept(envelope: Envelope): void {\n\t\tif (this.stopped) return;\n\t\tif (this.listener === undefined) {\n\t\t\tif (this.buffer.length >= WATCH_CAPACITY) {\n\t\t\t\tthis.stop();\n\t\t\t\tthis.report(new Error(`watch capacity ${WATCH_CAPACITY} exceeded before start()`));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.buffer.push(envelope);\n\t\t\treturn;\n\t\t}\n\t\tthis.deliver(envelope);\n\t}\n\n\tprivate deliver(envelope: Envelope): void {\n\t\ttry {\n\t\t\tthis.listener!(envelope);\n\t\t} catch (error) {\n\t\t\tthis.fail(error);\n\t\t}\n\t}\n\n\tfail(error: unknown): void {\n\t\tthis.stop();\n\t\tthis.report(error);\n\t}\n\n\tprivate report(error: unknown): void {\n\t\ttry {\n\t\t\tthis.onReport(error);\n\t\t} catch {}\n\t}\n}\n\nfunction applyEntries(tracker: Tracker<ConversationView>, appended: EntryList): Op[] {\n\tconst ops: Op[] = [];\n\tconst entries = tracker.state.entries;\n\tfor (const entry of appended) {\n\t\tif (entry.head !== undefined) {\n\t\t\tconst retained = entries.findIndex((candidate) => candidate.id >= entry.head!);\n\t\t\tconst remove = retained < 0 ? entries.length : retained;\n\t\t\tif (remove > 0) {\n\t\t\t\tops.push(...tracker.flush());\n\t\t\t\tentries.splice(0, remove);\n\t\t\t\ttracker.flush();\n\t\t\t\tops.push([\"p\", [\"entries\"], 0, remove, []]);\n\t\t\t}\n\t\t}\n\t\tentries.push(structuredClone(entry));\n\t}\n\treturn ops;\n}\n\nfunction inputIds(task: Task): Id[] {\n\tconst inputs = (task.input as { inputs?: JsonValue }).inputs;\n\treturn Array.isArray(inputs) ? inputs.filter((value): value is Id => typeof value === \"number\") : [];\n}\n\nfunction generationStatus(task: Task, streaming: boolean): GenerationStatus {\n\tif (task.status === \"pending\" && task.after.length > 0) return { stage: \"waiting\", on: \"compaction\" };\n\tconst checkpoint = task.checkpoint as\n\t\t| {\n\t\t\t\tphase?: string;\n\t\t\t\tattempt?: number;\n\t\t\t\tuntilMs?: number;\n\t\t\t\tlastError?: string;\n\t\t\t\tpollAt?: number;\n\t\t }\n\t\t| undefined;\n\tif (checkpoint?.phase === \"requesting\")\n\t\treturn { stage: streaming ? \"streaming\" : \"requesting\", attempt: checkpoint.attempt ?? 1 };\n\tif (checkpoint?.phase === \"retrying\")\n\t\treturn {\n\t\t\tstage: \"retrying\",\n\t\t\tattempt: checkpoint.attempt ?? 1,\n\t\t\tretryAt: checkpoint.untilMs ?? 0,\n\t\t\tlastError: checkpoint.lastError ?? \"\",\n\t\t};\n\tif (checkpoint?.phase === \"deferred\")\n\t\treturn { stage: \"deferred\", attempt: checkpoint.attempt ?? 1, pollAt: checkpoint.pollAt ?? 0 };\n\treturn { stage: \"preparing\" };\n}\n\nfunction stripPrivateToolState(slot: ToolSlot): Omit<ToolSlot, \"memos\"> {\n\tconst { memos: _memos, ...view } = structuredClone(slot);\n\treturn view;\n}\n\nfunction describe(kind: AnyKind, task: Task, slot: JsonObject | undefined): JsonValue {\n\tif (typeof kind.describe !== \"function\")\n\t\treturn { phase: task.checkpoint?.phase ?? (task.status === \"pending\" ? \"pending\" : \"running\") };\n\tconst publicSlot = slot === undefined ? undefined : structuredClone(slot);\n\tif (publicSlot !== undefined) delete publicSlot.memos;\n\tconst value = (kind.describe as (task: Task & { readonly slot?: Readonly<JsonObject> }) => JsonValue)({\n\t\t...task,\n\t\t...(publicSlot === undefined ? {} : { slot: publicSlot }),\n\t});\n\treturn strictJson(value, `task kind ${task.kind} describe`);\n}\n\nfunction strictJson(value: JsonValue, what: string): JsonValue {\n\tconst encoded = JSON.stringify(value);\n\tif (encoded === undefined) throw new Error(`${what} returned a non-JSON value`);\n\treturn JSON.parse(encoded) as JsonValue;\n}\n\nfunction touchesKey(ops: readonly Op[], key: string): boolean {\n\treturn ops.some((op) => op[0] === \"r\" || op[1][0] === key);\n}\n\nfunction syncOptional(target: object, key: string, next: unknown): void {\n\tconst record = target as Record<string, unknown>;\n\tif (next === undefined) {\n\t\tdelete record[key];\n\t\treturn;\n\t}\n\tconst current = record[key];\n\tif (same(current, next)) return;\n\tif (isRecord(current) && isRecord(next)) syncRecord(current, next);\n\telse record[key] = structuredClone(next);\n}\n\nfunction syncRecord(target: Record<string, unknown>, next: Record<string, unknown>): void {\n\tfor (const key of Object.keys(target)) if (!(key in next)) delete target[key];\n\tfor (const [key, value] of Object.entries(next)) {\n\t\tconst current = target[key];\n\t\tif (same(current, value)) continue;\n\t\tif (Array.isArray(current) && Array.isArray(value)) {\n\t\t\tsyncArray(current, value);\n\t\t\tcontinue;\n\t\t}\n\t\tif (isRecord(current) && isRecord(value)) {\n\t\t\tsyncRecord(current, value);\n\t\t\tcontinue;\n\t\t}\n\t\ttarget[key] = structuredClone(value);\n\t}\n}\n\nfunction syncArray(target: unknown[], next: unknown[]): void {\n\tlet prefix = 0;\n\twhile (prefix < target.length && prefix < next.length) {\n\t\tif (same(target[prefix], next[prefix])) {\n\t\t\tprefix++;\n\t\t\tcontinue;\n\t\t}\n\t\tconst current = target[prefix];\n\t\tconst replacement = next[prefix];\n\t\tif (!isRecord(current) || !isRecord(replacement) || !sameArrayItem(current, replacement)) break;\n\t\tsyncRecord(current, replacement);\n\t\tprefix++;\n\t}\n\tif (prefix === target.length && prefix === next.length) return;\n\tif (prefix === target.length) {\n\t\ttarget.push(...structuredClone(next.slice(prefix)));\n\t\treturn;\n\t}\n\ttarget.splice(prefix, target.length - prefix, ...structuredClone(next.slice(prefix)));\n}\n\nfunction sameArrayItem(current: Record<string, unknown>, next: Record<string, unknown>): boolean {\n\tif (typeof current.id === \"number\" || typeof next.id === \"number\") return current.id === next.id;\n\tif (typeof current.callId === \"string\" || typeof next.callId === \"string\") return current.callId === next.callId;\n\tif (typeof current.type === \"string\" || typeof next.type === \"string\") return current.type === next.type;\n\treturn false;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction same(a: unknown, b: unknown): boolean {\n\tif (Object.is(a, b)) return true;\n\treturn JSON.stringify(a) === JSON.stringify(b);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../../../src/harness/runtime/drive/boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG3E,OAAO,KAAK,EACX,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACZ,QAAQ,EACR,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,EACrB,KAAK,EACL,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGrE,MAAM,WAAW,qBAAqB;IACrC,IAAI,EAAE,gBAAgB,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,KAAK,uBAAuB,GACzB,mBAAmB,GACnB,wBAAwB,GACxB,qBAAqB,GACrB,6BAA6B,CAAC;AAEjC,wBAAgB,qBAAqB,CAAC,QAAQ,SAAS,MAAM,GAAG,SAAS,EACxE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,GAClB,qBAAqB,CAKvB;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,SAAS,MAAM,GAAG,SAAS,EAC3E,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,EACpB,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,MAAM,EACtB,oBAAoB,EAAE,OAAO,GAC3B,uBAAuB,CAezB;AAED,oFAAoF;AACpF,wBAAsB,iBAAiB,CAAC,QAAQ,SAAS,MAAM,GAAG,SAAS,EAC1E,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,EACpB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,qBAAqB,EAAE,OAAO,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CA6D5B;AAED,wBAAgB,uBAAuB,CACtC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,YAAY,EACpB,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACX,YAAY,EAAE,CAKhB;AAED,6FAA6F;AAC7F,wBAAsB,iBAAiB,CAAC,QAAQ,SAAS,MAAM,GAAG,SAAS,EAAE,MAAM,SAAS,uBAAuB,EAClH,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,EACpB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,OAAO,CAAC,mBAAmB,CAAC,cAAc,CAAC,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,EAClF,eAAe,EAAE,SAAS,MAAM,EAAE,EAClC,aAAa,GAAE,YAAY,EAAO,GAChC,OAAO,CAAC,eAAe,CAAC,CA2F1B","sourcesContent":["import type { HarnessEvent, LaneQueuedItem } from \"../../agent-harness.ts\";\nimport { insertEntry } from \"../../session/commit.ts\";\nimport { SessionInvariantError } from \"../../session/session.ts\";\nimport type {\n\tAssistantReadyOperation,\n\tCheckpointOperation,\n\tCommitResult,\n\tNewEntry,\n\tNormalizedRetryPolicy,\n\tOperationScope,\n\tSessionReader,\n\tSummaryDecidingOperation,\n\tSummaryEffectPendingOperation,\n\tSummaryReadyOperation,\n\tWrite,\n} from \"../../session/types.ts\";\nimport { branchTip, deleteValue, pendingEntry, setValue } from \"../../session/values.ts\";\nimport type { Lane } from \"../lane.ts\";\nimport { committedEntryEvents, entryLifecycleEvents, readBoundedContext, readLaneQueues } from \"../transcript.ts\";\nimport type { Drive, LaneState, ProcedureResult } from \"../types.ts\";\nimport { operationCleanupWrites, operationResultRecord } from \"./terminal.ts\";\n\nexport interface BoundaryFinishPending {\n\tkind: \"finish_pending\";\n\tentryIds: string[];\n}\n\nexport interface BoundaryPlacement {\n\tentries: NewEntry[];\n\twrites: Write[];\n\ttipId: string | null;\n\tinbox: LaneState[\"inbox\"];\n\ttriggerEntryId?: string;\n\tqueues?: LaneQueuedItem[];\n}\n\ntype FinishBoundaryOperation =\n\t| CheckpointOperation\n\t| SummaryDecidingOperation\n\t| SummaryReadyOperation\n\t| SummaryEffectPendingOperation;\n\nexport function normalizedRetryPolicy<TContext extends object | undefined>(\n\tlane: Lane<TContext>,\n): NormalizedRetryPolicy {\n\tconst retry = lane.readConfig().retryPolicy;\n\treturn retry.enabled\n\t\t? { maxAttempts: retry.maxRetries + 1, baseDelayMs: retry.baseDelayMs }\n\t\t: { maxAttempts: 1, baseDelayMs: retry.baseDelayMs };\n}\n\nexport function assistantReadyAtBoundary<TContext extends object | undefined>(\n\tlane: Lane<TContext>,\n\tstate: LaneState,\n\tscope: OperationScope,\n\ttriggerEntryId: string,\n\toverflowRecoveryUsed: boolean,\n): AssistantReadyOperation {\n\tconst config = lane.readConfig();\n\treturn {\n\t\t...scope,\n\t\tat: \"assistant.ready\",\n\t\tgenerationContext: {\n\t\t\tstepId: lane.session.idGenerator.next(),\n\t\t\ttriggerEntryId,\n\t\t\tconfiguration: state.configuration,\n\t\t\tstreamOptions: config.streamOptions,\n\t\t\tretryPolicy: normalizedRetryPolicy(lane),\n\t\t\toverflowRecoveryUsed,\n\t\t},\n\t\tnextAttempt: 1,\n\t};\n}\n\n/** Select and materialize one boundary's lane-owned input without committing it. */\nexport async function planBoundaryInbox<TContext extends object | undefined>(\n\tlane: Lane<TContext>,\n\tdrive: Drive,\n\tstate: LaneState,\n\tscope: OperationScope,\n\treader: SessionReader,\n\ttipId: string | null,\n\tfollowUpWhenNoTrigger: boolean,\n): Promise<BoundaryPlacement> {\n\tconst steer = state.inbox.filter((item) => item.kind === \"steer\");\n\tconst selectedSteer = scope.settings.steeringMode === \"all\" ? steer : steer.slice(0, 1);\n\tlet selected = state.inbox.filter(\n\t\t(item) => item.kind === \"write\" || selectedSteer.some((candidate) => candidate.entryId === item.entryId),\n\t);\n\tconst load = (items: typeof selected) =>\n\t\tPromise.all(\n\t\t\titems.map(async (item) => {\n\t\t\t\tconst stored = await reader.getValue(pendingEntry(item.entryId), drive.context);\n\t\t\t\tif (stored === undefined) {\n\t\t\t\t\tthrow new SessionInvariantError(`Pending ${item.kind} entry ${item.entryId} is missing its payload`);\n\t\t\t\t}\n\t\t\t\tif (item.kind !== \"write\" && stored.value.type !== \"message\") {\n\t\t\t\t\tthrow new SessionInvariantError(`Queued ${item.kind} entry ${item.entryId} is not a message`);\n\t\t\t\t}\n\t\t\t\treturn { item, pending: stored.value };\n\t\t\t}),\n\t\t);\n\tlet pending = await load(selected);\n\tconst projects = (value: (typeof pending)[number][\"pending\"]): boolean =>\n\t\tvalue.type === \"message\" || lane.readConfig().entryProjectors[value.customType] !== undefined;\n\tif (followUpWhenNoTrigger && !pending.some(({ pending: value }) => projects(value))) {\n\t\tconst followUp = state.inbox.filter((item) => item.kind === \"followUp\");\n\t\tconst selectedFollowUp = scope.settings.followUpMode === \"all\" ? followUp : followUp.slice(0, 1);\n\t\tselected = [...selected, ...selectedFollowUp].sort((a, b) => state.inbox.indexOf(a) - state.inbox.indexOf(b));\n\t\tpending = await load(selected);\n\t}\n\n\tlet parentId = tipId;\n\tlet triggerEntryId: string | undefined;\n\tconst entries: NewEntry[] = pending.map(({ item, pending: value }) => {\n\t\tconst entry: NewEntry =\n\t\t\tvalue.type === \"message\"\n\t\t\t\t? { id: item.entryId, parentId, type: \"message\", message: value.payload }\n\t\t\t\t: {\n\t\t\t\t\t\tid: item.entryId,\n\t\t\t\t\t\tparentId,\n\t\t\t\t\t\ttype: \"custom\",\n\t\t\t\t\t\tcustomType: value.customType,\n\t\t\t\t\t\t...(value.payload === undefined ? {} : { data: value.payload }),\n\t\t\t\t\t};\n\t\tparentId = item.entryId;\n\t\tif (projects(value)) triggerEntryId = item.entryId;\n\t\treturn entry;\n\t});\n\tconst selectedIds = new Set(selected.map((item) => item.entryId));\n\tconst inbox = state.inbox.filter((item) => !selectedIds.has(item.entryId));\n\tconst queues = selected.length === 0 ? undefined : await readLaneQueues(reader, inbox, drive.context);\n\treturn {\n\t\tentries,\n\t\twrites: [\n\t\t\t...entries.map((entry) => insertEntry(entry)),\n\t\t\t...selected.map((item) => deleteValue(pendingEntry(item.entryId))),\n\t\t\t...(entries.length === 0 ? [] : [setValue(branchTip(lane.name), parentId)]),\n\t\t],\n\t\ttipId: parentId,\n\t\tinbox,\n\t\t...(triggerEntryId === undefined ? {} : { triggerEntryId }),\n\t\t...(queues === undefined ? {} : { queues }),\n\t};\n}\n\nexport function boundaryPlacementEvents(\n\tplacement: BoundaryPlacement,\n\tcommit: CommitResult,\n\tfirstWriteIndex: number,\n\tlane: string,\n\trunId: string,\n): HarnessEvent[] {\n\treturn [\n\t\t...committedEntryEvents(placement.entries, commit, lane, runId, firstWriteIndex),\n\t\t...(placement.queues === undefined ? [] : [{ type: \"queue_update\" as const, lane, queues: placement.queues }]),\n\t];\n}\n\n/** Replan after before_run_end and commit either renewed work or the terminal run result. */\nexport async function finishRunBoundary<TContext extends object | undefined, TState extends FinishBoundaryOperation>(\n\tlane: Lane<TContext>,\n\tdrive: Drive,\n\tcapability: TState,\n\tcontinuation: Extract<CheckpointOperation[\"continuation\"], { kind: \"may_finish\" }>,\n\tplannedEntryIds: readonly string[],\n\tpendingEvents: HarnessEvent[] = [],\n): Promise<ProcedureResult> {\n\tconst context = await readBoundedContext(lane, drive, capability);\n\tif (context.kind === \"cancel_requested\") return { kind: \"continue\" };\n\tconst hook = await lane.hooks.runWithGate(\n\t\t\"before_run_end\",\n\t\t{ lane: lane.name, runId: drive.operationId, messages: context.value },\n\t\tdrive.gate,\n\t\tdrive.context,\n\t);\n\tconst followUp =\n\t\thook?.followUp === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tid: lane.session.idGenerator.next(),\n\t\t\t\t\tmessage: { role: \"user\" as const, content: hook.followUp, timestamp: Date.now() },\n\t\t\t\t};\n\tconst result = await lane.continueOperation<TState, ProcedureResult>(\n\t\tcapability,\n\t\tasync (state, current, meta, reader) => {\n\t\t\tconst placement = await planBoundaryInbox(lane, drive, state, current, reader, state.tipId, true);\n\t\t\tif (placement.triggerEntryId !== undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"commit\",\n\t\t\t\t\twrites: placement.writes,\n\t\t\t\t\toperationState: assistantReadyAtBoundary(lane, state, current, placement.triggerEntryId, false),\n\t\t\t\t\tlane: { tipId: placement.tipId, inbox: placement.inbox },\n\t\t\t\t\tmaterialize: () => ({ kind: \"continue\" }) as const,\n\t\t\t\t\tevents: (commit) => [\n\t\t\t\t\t\t...pendingEvents,\n\t\t\t\t\t\t...boundaryPlacementEvents(placement, commit, 0, lane.name, drive.operationId),\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst hookPlanIsCurrent =\n\t\t\t\tplacement.entries.length === plannedEntryIds.length &&\n\t\t\t\tplacement.entries.every((entry, index) => entry.id === plannedEntryIds[index]);\n\t\t\tif (hookPlanIsCurrent && followUp !== undefined) {\n\t\t\t\tconst entry: NewEntry = {\n\t\t\t\t\tid: followUp.id,\n\t\t\t\t\tparentId: placement.tipId,\n\t\t\t\t\ttype: \"message\",\n\t\t\t\t\tmessage: followUp.message,\n\t\t\t\t};\n\t\t\t\tconst entryWriteIndex = placement.writes.length;\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"commit\",\n\t\t\t\t\twrites: [...placement.writes, insertEntry(entry), setValue(branchTip(lane.name), followUp.id)],\n\t\t\t\t\toperationState: assistantReadyAtBoundary(lane, state, current, followUp.id, false),\n\t\t\t\t\tlane: { tipId: followUp.id, inbox: placement.inbox },\n\t\t\t\t\tmaterialize: () => ({ kind: \"continue\" }) as const,\n\t\t\t\t\tevents: (commit) => [\n\t\t\t\t\t\t...pendingEvents,\n\t\t\t\t\t\t...boundaryPlacementEvents(placement, commit, 0, lane.name, drive.operationId),\n\t\t\t\t\t\t...entryLifecycleEvents(\n\t\t\t\t\t\t\t{ ...entry, seq: commit.seqs[entryWriteIndex]!, timestamp: commit.timestamp },\n\t\t\t\t\t\t\tlane.name,\n\t\t\t\t\t\t\tdrive.operationId,\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (placement.tipId === null) throw new SessionInvariantError(\"Completed run has no tip\");\n\t\t\tif (continuation.includeFinalAssistant && current.latestAssistantEntryId === null) {\n\t\t\t\tthrow new SessionInvariantError(\"Completed run is missing its final assistant\");\n\t\t\t}\n\t\t\tconst record = operationResultRecord(meta, \"completed\", placement.tipId);\n\t\t\tconst cleanup = await operationCleanupWrites(reader, drive.operationId, current, drive.context);\n\t\t\treturn {\n\t\t\t\tkind: \"finish\",\n\t\t\t\twrites: [...placement.writes, ...cleanup],\n\t\t\t\trecord,\n\t\t\t\tlane: { tipId: placement.tipId, inbox: placement.inbox },\n\t\t\t\tmaterialize: () => ({ kind: \"settled\", outcome: record }) as const,\n\t\t\t\tevents: (commit) => [\n\t\t\t\t\t...pendingEvents,\n\t\t\t\t\t...boundaryPlacementEvents(placement, commit, 0, lane.name, drive.operationId),\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"run_end\",\n\t\t\t\t\t\tlane: lane.name,\n\t\t\t\t\t\trunId: drive.operationId,\n\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\tfromTipId: meta.sourceTipId,\n\t\t\t\t\t\ttipId: placement.tipId,\n\t\t\t\t\t\tendedAt: record.endedAt,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t\tdrive.context,\n\t);\n\treturn result.kind === \"cancel_requested\" ? { kind: \"continue\" } : result.value;\n}\n"]}
1
+ {"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../../../../src/harness/runtime/drive/boundary.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG3E,OAAO,KAAK,EACX,uBAAuB,EACvB,mBAAmB,EACnB,YAAY,EACZ,QAAQ,EACR,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,EACrB,KAAK,EACL,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGrE,MAAM,WAAW,qBAAqB;IACrC,IAAI,EAAE,gBAAgB,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,KAAK,uBAAuB,GACzB,mBAAmB,GACnB,wBAAwB,GACxB,qBAAqB,GACrB,6BAA6B,CAAC;AAEjC,wBAAgB,qBAAqB,CAAC,QAAQ,SAAS,MAAM,GAAG,SAAS,EACxE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,GAClB,qBAAqB,CAOvB;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,SAAS,MAAM,GAAG,SAAS,EAC3E,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,EACpB,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,cAAc,EACrB,cAAc,EAAE,MAAM,EACtB,oBAAoB,EAAE,OAAO,GAC3B,uBAAuB,CAezB;AAED,oFAAoF;AACpF,wBAAsB,iBAAiB,CAAC,QAAQ,SAAS,MAAM,GAAG,SAAS,EAC1E,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,EACpB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,qBAAqB,EAAE,OAAO,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CA6D5B;AAED,wBAAgB,uBAAuB,CACtC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,YAAY,EACpB,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACX,YAAY,EAAE,CAKhB;AAED,6FAA6F;AAC7F,wBAAsB,iBAAiB,CAAC,QAAQ,SAAS,MAAM,GAAG,SAAS,EAAE,MAAM,SAAS,uBAAuB,EAClH,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,EACpB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,OAAO,CAAC,mBAAmB,CAAC,cAAc,CAAC,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,EAClF,eAAe,EAAE,SAAS,MAAM,EAAE,EAClC,aAAa,GAAE,YAAY,EAAO,GAChC,OAAO,CAAC,eAAe,CAAC,CA2F1B","sourcesContent":["import { DEFAULT_MAX_AGENT_RETRY_DELAY_MS } from \"@earendil-works/pi-ai\";\nimport type { HarnessEvent, LaneQueuedItem } from \"../../agent-harness.ts\";\nimport { insertEntry } from \"../../session/commit.ts\";\nimport { SessionInvariantError } from \"../../session/session.ts\";\nimport type {\n\tAssistantReadyOperation,\n\tCheckpointOperation,\n\tCommitResult,\n\tNewEntry,\n\tNormalizedRetryPolicy,\n\tOperationScope,\n\tSessionReader,\n\tSummaryDecidingOperation,\n\tSummaryEffectPendingOperation,\n\tSummaryReadyOperation,\n\tWrite,\n} from \"../../session/types.ts\";\nimport { branchTip, deleteValue, pendingEntry, setValue } from \"../../session/values.ts\";\nimport type { Lane } from \"../lane.ts\";\nimport { committedEntryEvents, entryLifecycleEvents, readBoundedContext, readLaneQueues } from \"../transcript.ts\";\nimport type { Drive, LaneState, ProcedureResult } from \"../types.ts\";\nimport { operationCleanupWrites, operationResultRecord } from \"./terminal.ts\";\n\nexport interface BoundaryFinishPending {\n\tkind: \"finish_pending\";\n\tentryIds: string[];\n}\n\nexport interface BoundaryPlacement {\n\tentries: NewEntry[];\n\twrites: Write[];\n\ttipId: string | null;\n\tinbox: LaneState[\"inbox\"];\n\ttriggerEntryId?: string;\n\tqueues?: LaneQueuedItem[];\n}\n\ntype FinishBoundaryOperation =\n\t| CheckpointOperation\n\t| SummaryDecidingOperation\n\t| SummaryReadyOperation\n\t| SummaryEffectPendingOperation;\n\nexport function normalizedRetryPolicy<TContext extends object | undefined>(\n\tlane: Lane<TContext>,\n): NormalizedRetryPolicy {\n\tconst retry = lane.readConfig().retryPolicy;\n\treturn {\n\t\tmaxAttempts: retry.enabled ? retry.maxRetries + 1 : 1,\n\t\tbaseDelayMs: retry.baseDelayMs,\n\t\tmaxAgentDelayMs: retry.maxAgentDelayMs ?? DEFAULT_MAX_AGENT_RETRY_DELAY_MS,\n\t};\n}\n\nexport function assistantReadyAtBoundary<TContext extends object | undefined>(\n\tlane: Lane<TContext>,\n\tstate: LaneState,\n\tscope: OperationScope,\n\ttriggerEntryId: string,\n\toverflowRecoveryUsed: boolean,\n): AssistantReadyOperation {\n\tconst config = lane.readConfig();\n\treturn {\n\t\t...scope,\n\t\tat: \"assistant.ready\",\n\t\tgenerationContext: {\n\t\t\tstepId: lane.session.idGenerator.next(),\n\t\t\ttriggerEntryId,\n\t\t\tconfiguration: state.configuration,\n\t\t\tstreamOptions: config.streamOptions,\n\t\t\tretryPolicy: normalizedRetryPolicy(lane),\n\t\t\toverflowRecoveryUsed,\n\t\t},\n\t\tnextAttempt: 1,\n\t};\n}\n\n/** Select and materialize one boundary's lane-owned input without committing it. */\nexport async function planBoundaryInbox<TContext extends object | undefined>(\n\tlane: Lane<TContext>,\n\tdrive: Drive,\n\tstate: LaneState,\n\tscope: OperationScope,\n\treader: SessionReader,\n\ttipId: string | null,\n\tfollowUpWhenNoTrigger: boolean,\n): Promise<BoundaryPlacement> {\n\tconst steer = state.inbox.filter((item) => item.kind === \"steer\");\n\tconst selectedSteer = scope.settings.steeringMode === \"all\" ? steer : steer.slice(0, 1);\n\tlet selected = state.inbox.filter(\n\t\t(item) => item.kind === \"write\" || selectedSteer.some((candidate) => candidate.entryId === item.entryId),\n\t);\n\tconst load = (items: typeof selected) =>\n\t\tPromise.all(\n\t\t\titems.map(async (item) => {\n\t\t\t\tconst stored = await reader.getValue(pendingEntry(item.entryId), drive.context);\n\t\t\t\tif (stored === undefined) {\n\t\t\t\t\tthrow new SessionInvariantError(`Pending ${item.kind} entry ${item.entryId} is missing its payload`);\n\t\t\t\t}\n\t\t\t\tif (item.kind !== \"write\" && stored.value.type !== \"message\") {\n\t\t\t\t\tthrow new SessionInvariantError(`Queued ${item.kind} entry ${item.entryId} is not a message`);\n\t\t\t\t}\n\t\t\t\treturn { item, pending: stored.value };\n\t\t\t}),\n\t\t);\n\tlet pending = await load(selected);\n\tconst projects = (value: (typeof pending)[number][\"pending\"]): boolean =>\n\t\tvalue.type === \"message\" || lane.readConfig().entryProjectors[value.customType] !== undefined;\n\tif (followUpWhenNoTrigger && !pending.some(({ pending: value }) => projects(value))) {\n\t\tconst followUp = state.inbox.filter((item) => item.kind === \"followUp\");\n\t\tconst selectedFollowUp = scope.settings.followUpMode === \"all\" ? followUp : followUp.slice(0, 1);\n\t\tselected = [...selected, ...selectedFollowUp].sort((a, b) => state.inbox.indexOf(a) - state.inbox.indexOf(b));\n\t\tpending = await load(selected);\n\t}\n\n\tlet parentId = tipId;\n\tlet triggerEntryId: string | undefined;\n\tconst entries: NewEntry[] = pending.map(({ item, pending: value }) => {\n\t\tconst entry: NewEntry =\n\t\t\tvalue.type === \"message\"\n\t\t\t\t? { id: item.entryId, parentId, type: \"message\", message: value.payload }\n\t\t\t\t: {\n\t\t\t\t\t\tid: item.entryId,\n\t\t\t\t\t\tparentId,\n\t\t\t\t\t\ttype: \"custom\",\n\t\t\t\t\t\tcustomType: value.customType,\n\t\t\t\t\t\t...(value.payload === undefined ? {} : { data: value.payload }),\n\t\t\t\t\t};\n\t\tparentId = item.entryId;\n\t\tif (projects(value)) triggerEntryId = item.entryId;\n\t\treturn entry;\n\t});\n\tconst selectedIds = new Set(selected.map((item) => item.entryId));\n\tconst inbox = state.inbox.filter((item) => !selectedIds.has(item.entryId));\n\tconst queues = selected.length === 0 ? undefined : await readLaneQueues(reader, inbox, drive.context);\n\treturn {\n\t\tentries,\n\t\twrites: [\n\t\t\t...entries.map((entry) => insertEntry(entry)),\n\t\t\t...selected.map((item) => deleteValue(pendingEntry(item.entryId))),\n\t\t\t...(entries.length === 0 ? [] : [setValue(branchTip(lane.name), parentId)]),\n\t\t],\n\t\ttipId: parentId,\n\t\tinbox,\n\t\t...(triggerEntryId === undefined ? {} : { triggerEntryId }),\n\t\t...(queues === undefined ? {} : { queues }),\n\t};\n}\n\nexport function boundaryPlacementEvents(\n\tplacement: BoundaryPlacement,\n\tcommit: CommitResult,\n\tfirstWriteIndex: number,\n\tlane: string,\n\trunId: string,\n): HarnessEvent[] {\n\treturn [\n\t\t...committedEntryEvents(placement.entries, commit, lane, runId, firstWriteIndex),\n\t\t...(placement.queues === undefined ? [] : [{ type: \"queue_update\" as const, lane, queues: placement.queues }]),\n\t];\n}\n\n/** Replan after before_run_end and commit either renewed work or the terminal run result. */\nexport async function finishRunBoundary<TContext extends object | undefined, TState extends FinishBoundaryOperation>(\n\tlane: Lane<TContext>,\n\tdrive: Drive,\n\tcapability: TState,\n\tcontinuation: Extract<CheckpointOperation[\"continuation\"], { kind: \"may_finish\" }>,\n\tplannedEntryIds: readonly string[],\n\tpendingEvents: HarnessEvent[] = [],\n): Promise<ProcedureResult> {\n\tconst context = await readBoundedContext(lane, drive, capability);\n\tif (context.kind === \"cancel_requested\") return { kind: \"continue\" };\n\tconst hook = await lane.hooks.runWithGate(\n\t\t\"before_run_end\",\n\t\t{ lane: lane.name, runId: drive.operationId, messages: context.value },\n\t\tdrive.gate,\n\t\tdrive.context,\n\t);\n\tconst followUp =\n\t\thook?.followUp === undefined\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tid: lane.session.idGenerator.next(),\n\t\t\t\t\tmessage: { role: \"user\" as const, content: hook.followUp, timestamp: Date.now() },\n\t\t\t\t};\n\tconst result = await lane.continueOperation<TState, ProcedureResult>(\n\t\tcapability,\n\t\tasync (state, current, meta, reader) => {\n\t\t\tconst placement = await planBoundaryInbox(lane, drive, state, current, reader, state.tipId, true);\n\t\t\tif (placement.triggerEntryId !== undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"commit\",\n\t\t\t\t\twrites: placement.writes,\n\t\t\t\t\toperationState: assistantReadyAtBoundary(lane, state, current, placement.triggerEntryId, false),\n\t\t\t\t\tlane: { tipId: placement.tipId, inbox: placement.inbox },\n\t\t\t\t\tmaterialize: () => ({ kind: \"continue\" }) as const,\n\t\t\t\t\tevents: (commit) => [\n\t\t\t\t\t\t...pendingEvents,\n\t\t\t\t\t\t...boundaryPlacementEvents(placement, commit, 0, lane.name, drive.operationId),\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst hookPlanIsCurrent =\n\t\t\t\tplacement.entries.length === plannedEntryIds.length &&\n\t\t\t\tplacement.entries.every((entry, index) => entry.id === plannedEntryIds[index]);\n\t\t\tif (hookPlanIsCurrent && followUp !== undefined) {\n\t\t\t\tconst entry: NewEntry = {\n\t\t\t\t\tid: followUp.id,\n\t\t\t\t\tparentId: placement.tipId,\n\t\t\t\t\ttype: \"message\",\n\t\t\t\t\tmessage: followUp.message,\n\t\t\t\t};\n\t\t\t\tconst entryWriteIndex = placement.writes.length;\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"commit\",\n\t\t\t\t\twrites: [...placement.writes, insertEntry(entry), setValue(branchTip(lane.name), followUp.id)],\n\t\t\t\t\toperationState: assistantReadyAtBoundary(lane, state, current, followUp.id, false),\n\t\t\t\t\tlane: { tipId: followUp.id, inbox: placement.inbox },\n\t\t\t\t\tmaterialize: () => ({ kind: \"continue\" }) as const,\n\t\t\t\t\tevents: (commit) => [\n\t\t\t\t\t\t...pendingEvents,\n\t\t\t\t\t\t...boundaryPlacementEvents(placement, commit, 0, lane.name, drive.operationId),\n\t\t\t\t\t\t...entryLifecycleEvents(\n\t\t\t\t\t\t\t{ ...entry, seq: commit.seqs[entryWriteIndex]!, timestamp: commit.timestamp },\n\t\t\t\t\t\t\tlane.name,\n\t\t\t\t\t\t\tdrive.operationId,\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (placement.tipId === null) throw new SessionInvariantError(\"Completed run has no tip\");\n\t\t\tif (continuation.includeFinalAssistant && current.latestAssistantEntryId === null) {\n\t\t\t\tthrow new SessionInvariantError(\"Completed run is missing its final assistant\");\n\t\t\t}\n\t\t\tconst record = operationResultRecord(meta, \"completed\", placement.tipId);\n\t\t\tconst cleanup = await operationCleanupWrites(reader, drive.operationId, current, drive.context);\n\t\t\treturn {\n\t\t\t\tkind: \"finish\",\n\t\t\t\twrites: [...placement.writes, ...cleanup],\n\t\t\t\trecord,\n\t\t\t\tlane: { tipId: placement.tipId, inbox: placement.inbox },\n\t\t\t\tmaterialize: () => ({ kind: \"settled\", outcome: record }) as const,\n\t\t\t\tevents: (commit) => [\n\t\t\t\t\t...pendingEvents,\n\t\t\t\t\t...boundaryPlacementEvents(placement, commit, 0, lane.name, drive.operationId),\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"run_end\",\n\t\t\t\t\t\tlane: lane.name,\n\t\t\t\t\t\trunId: drive.operationId,\n\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\tfromTipId: meta.sourceTipId,\n\t\t\t\t\t\ttipId: placement.tipId,\n\t\t\t\t\t\tendedAt: record.endedAt,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t},\n\t\tdrive.context,\n\t);\n\treturn result.kind === \"cancel_requested\" ? { kind: \"continue\" } : result.value;\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { DEFAULT_MAX_AGENT_RETRY_DELAY_MS } from "@earendil-works/pi-ai";
1
2
  import { insertEntry } from "../../session/commit.js";
2
3
  import { SessionInvariantError } from "../../session/session.js";
3
4
  import { branchTip, deleteValue, pendingEntry, setValue } from "../../session/values.js";
@@ -5,9 +6,11 @@ import { committedEntryEvents, entryLifecycleEvents, readBoundedContext, readLan
5
6
  import { operationCleanupWrites, operationResultRecord } from "./terminal.js";
6
7
  export function normalizedRetryPolicy(lane) {
7
8
  const retry = lane.readConfig().retryPolicy;
8
- return retry.enabled
9
- ? { maxAttempts: retry.maxRetries + 1, baseDelayMs: retry.baseDelayMs }
10
- : { maxAttempts: 1, baseDelayMs: retry.baseDelayMs };
9
+ return {
10
+ maxAttempts: retry.enabled ? retry.maxRetries + 1 : 1,
11
+ baseDelayMs: retry.baseDelayMs,
12
+ maxAgentDelayMs: retry.maxAgentDelayMs ?? DEFAULT_MAX_AGENT_RETRY_DELAY_MS,
13
+ };
11
14
  }
12
15
  export function assistantReadyAtBoundary(lane, state, scope, triggerEntryId, overflowRecoveryUsed) {
13
16
  const config = lane.readConfig();