@osolmaz/pi-workflows 0.16.0 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +18 -2
  2. package/dist/channels/adapter-entry.d.ts +3 -0
  3. package/dist/channels/adapter-entry.js +203 -0
  4. package/dist/channels/adapter-entry.js.map +1 -0
  5. package/dist/channels/config.d.ts +43 -0
  6. package/dist/channels/config.js +234 -0
  7. package/dist/channels/config.js.map +1 -0
  8. package/dist/channels/protocol.d.ts +94 -0
  9. package/dist/channels/protocol.js +219 -0
  10. package/dist/channels/protocol.js.map +1 -0
  11. package/dist/channels/telegram.d.ts +46 -0
  12. package/dist/channels/telegram.js +285 -0
  13. package/dist/channels/telegram.js.map +1 -0
  14. package/dist/client/client.d.ts +1 -0
  15. package/dist/client/client.js +5 -1
  16. package/dist/client/client.js.map +1 -1
  17. package/dist/client/index.d.ts +1 -1
  18. package/dist/client/protocol.d.ts +1 -1
  19. package/dist/client/protocol.js +11 -5
  20. package/dist/client/protocol.js.map +1 -1
  21. package/dist/client/view.d.ts +48 -16
  22. package/dist/client/view.js +1 -0
  23. package/dist/client/view.js.map +1 -1
  24. package/dist/controllers/index.d.ts +1 -1
  25. package/dist/controllers/index.js.map +1 -1
  26. package/dist/controllers/sqlite.d.ts +20 -165
  27. package/dist/controllers/sqlite.js +178 -436
  28. package/dist/controllers/sqlite.js.map +1 -1
  29. package/dist/extension/index.d.ts +23 -2
  30. package/dist/extension/index.js +637 -534
  31. package/dist/extension/index.js.map +1 -1
  32. package/dist/extension/recorder.d.ts +95 -0
  33. package/dist/extension/recorder.js +530 -0
  34. package/dist/extension/recorder.js.map +1 -0
  35. package/dist/extension/remote-recorder-store.d.ts +25 -0
  36. package/dist/extension/remote-recorder-store.js +81 -0
  37. package/dist/extension/remote-recorder-store.js.map +1 -0
  38. package/dist/extension/session-events.d.ts +134 -0
  39. package/dist/extension/session-events.js +60 -0
  40. package/dist/extension/session-events.js.map +1 -0
  41. package/dist/extension/session-view.d.ts +2 -0
  42. package/dist/extension/session-view.js +60 -2
  43. package/dist/extension/session-view.js.map +1 -1
  44. package/dist/extension/step-message.d.ts +6 -4
  45. package/dist/extension/step-message.js +12 -6
  46. package/dist/extension/step-message.js.map +1 -1
  47. package/dist/extension/widget.d.ts +2 -2
  48. package/dist/extension/widget.js +28 -18
  49. package/dist/extension/widget.js.map +1 -1
  50. package/dist/extension/workflow-message-coordinator.d.ts +28 -0
  51. package/dist/extension/workflow-message-coordinator.js +346 -0
  52. package/dist/extension/workflow-message-coordinator.js.map +1 -0
  53. package/dist/host/channel-effects.d.ts +72 -0
  54. package/dist/host/channel-effects.js +271 -0
  55. package/dist/host/channel-effects.js.map +1 -0
  56. package/dist/host/channel-supervisor.d.ts +21 -0
  57. package/dist/host/channel-supervisor.js +54 -0
  58. package/dist/host/channel-supervisor.js.map +1 -0
  59. package/dist/host/runner.d.ts +50 -8
  60. package/dist/host/runner.js +1632 -341
  61. package/dist/host/runner.js.map +1 -1
  62. package/dist/host/state.d.ts +19 -16
  63. package/dist/host/state.js +251 -63
  64. package/dist/host/state.js.map +1 -1
  65. package/dist/host/view.d.ts +19 -9
  66. package/dist/host/view.js +227 -119
  67. package/dist/host/view.js.map +1 -1
  68. package/dist/host/worker-entry.d.ts +4 -1
  69. package/dist/host/worker-entry.js +23 -24
  70. package/dist/host/worker-entry.js.map +1 -1
  71. package/dist/host/worker-protocol.d.ts +15 -0
  72. package/dist/host/worker-protocol.js.map +1 -1
  73. package/dist/state/prune.js +3 -25
  74. package/dist/state/prune.js.map +1 -1
  75. package/dist/state/schema.js +76 -97
  76. package/dist/state/schema.js.map +1 -1
  77. package/dist/state/workflow-messages.d.ts +98 -0
  78. package/dist/state/workflow-messages.js +366 -0
  79. package/dist/state/workflow-messages.js.map +1 -0
  80. package/dist/viewer/render.js +1 -1
  81. package/dist/viewer/render.js.map +1 -1
  82. package/dist/viewer/tui.d.ts +1 -1
  83. package/dist/viewer/tui.js +65 -8
  84. package/dist/viewer/tui.js.map +1 -1
  85. package/dist/workflows/composition.js +0 -4
  86. package/dist/workflows/composition.js.map +1 -1
  87. package/dist/workflows/definition.js +0 -8
  88. package/dist/workflows/definition.js.map +1 -1
  89. package/dist/workflows/engine.js +4 -5
  90. package/dist/workflows/engine.js.map +1 -1
  91. package/dist/workflows/human-decision.d.ts +2 -0
  92. package/dist/workflows/human-decision.js +8 -2
  93. package/dist/workflows/human-decision.js.map +1 -1
  94. package/dist/workflows/index.d.ts +1 -1
  95. package/dist/workflows/index.js.map +1 -1
  96. package/dist/workflows/schema.js +0 -4
  97. package/dist/workflows/schema.js.map +1 -1
  98. package/dist/workflows/settings.d.ts +1 -8
  99. package/dist/workflows/settings.js.map +1 -1
  100. package/dist/workflows/store.d.ts +20 -19
  101. package/dist/workflows/store.js +163 -354
  102. package/dist/workflows/store.js.map +1 -1
  103. package/dist/workflows/tool-input.d.ts +21 -0
  104. package/dist/workflows/tool-input.js +23 -1
  105. package/dist/workflows/tool-input.js.map +1 -1
  106. package/dist/workflows/types.d.ts +6 -8
  107. package/dist/workflows/workflow-message-content.d.ts +38 -0
  108. package/dist/workflows/workflow-message-content.js +157 -0
  109. package/dist/workflows/workflow-message-content.js.map +1 -0
  110. package/docs/2026-08-18-herdr-piw-plan.md +2 -1
  111. package/docs/2026-08-20-durable-workflow-launch-plan.md +1 -1
  112. package/docs/2026-08-25-workflow-follow-ups.md +26 -50
  113. package/docs/2026-08-30-out-of-process-workflow-host-plan.md +3 -3
  114. package/docs/2026-09-01-restore-session-delivery-controls-plan.md +4 -0
  115. package/docs/2026-09-01-unified-workflow-client-plan.md +5 -1
  116. package/docs/2026-09-02-installed-live-e2e-plan.md +15 -1
  117. package/docs/2026-09-02-unify-workflow-messages-plan.md +562 -0
  118. package/docs/2026-09-04-workflow-run-state-plan.md +363 -0
  119. package/docs/DEFERRED_TURNS.md +66 -294
  120. package/docs/HUMAN_DECISIONS.md +29 -30
  121. package/docs/HUMAN_DECISION_PRESENTATIONS.md +4 -11
  122. package/docs/SQLITE_STATE.md +25 -17
  123. package/docs/WORKFLOW_HOST.md +105 -31
  124. package/docs/WORKFLOW_STEP_MESSAGES.md +166 -75
  125. package/docs/live-replay-protocol.md +8 -4
  126. package/docs/tui-viewer.md +3 -1
  127. package/docs/workflows.md +44 -28
  128. package/herdr-plugin.toml +1 -1
  129. package/package.json +1 -1
  130. package/plugins/herdr/viewer.mjs +14 -5
  131. package/src/channels/adapter-entry.ts +220 -0
  132. package/src/channels/config.ts +296 -0
  133. package/src/channels/protocol.ts +333 -0
  134. package/src/channels/telegram.ts +335 -0
  135. package/src/client/client.ts +6 -2
  136. package/src/client/index.ts +2 -1
  137. package/src/client/protocol.ts +11 -5
  138. package/src/client/view.ts +51 -18
  139. package/src/controllers/index.ts +0 -1
  140. package/src/controllers/sqlite.ts +247 -845
  141. package/src/extension/index.ts +712 -647
  142. package/src/extension/recorder.ts +687 -0
  143. package/src/extension/remote-recorder-store.ts +126 -0
  144. package/src/extension/session-events.ts +119 -0
  145. package/src/extension/session-view.ts +86 -3
  146. package/src/extension/step-message.ts +19 -9
  147. package/src/extension/widget.ts +37 -17
  148. package/src/extension/workflow-message-coordinator.ts +398 -0
  149. package/src/host/channel-effects.ts +465 -0
  150. package/src/host/channel-supervisor.ts +73 -0
  151. package/src/host/runner.ts +2163 -525
  152. package/src/host/state.ts +333 -94
  153. package/src/host/view.ts +254 -122
  154. package/src/host/worker-entry.ts +38 -30
  155. package/src/host/worker-protocol.ts +11 -0
  156. package/src/state/prune.ts +3 -31
  157. package/src/state/schema.ts +76 -97
  158. package/src/state/workflow-messages.ts +599 -0
  159. package/src/viewer/render.ts +1 -5
  160. package/src/viewer/tui.ts +71 -6
  161. package/src/workflows/composition.ts +0 -5
  162. package/src/workflows/definition.ts +0 -8
  163. package/src/workflows/engine.ts +4 -6
  164. package/src/workflows/human-decision.ts +18 -2
  165. package/src/workflows/index.ts +0 -1
  166. package/src/workflows/schema.ts +0 -6
  167. package/src/workflows/settings.ts +1 -20
  168. package/src/workflows/store.ts +237 -489
  169. package/src/workflows/tool-input.ts +36 -1
  170. package/src/workflows/types.ts +6 -8
  171. package/src/workflows/workflow-message-content.ts +197 -0
  172. package/dist/extension/decision-channels.d.ts +0 -134
  173. package/dist/extension/decision-channels.js +0 -1307
  174. package/dist/extension/decision-channels.js.map +0 -1
  175. package/src/extension/decision-channels.ts +0 -1826
@@ -0,0 +1,530 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { SESSION_BINDING_SCHEMA, SESSION_CAPTURE_SCHEMA, SESSION_EVENT_MAX_BYTES, SESSION_EVENT_SCHEMA, } from "../workflows/store.js";
3
+ import { messageRole, normalizeAssistantEvent, toolCallIdFromAssistantEvent, toolFinishedPayload, toolStartedPayload, turnFinishedPayload, } from "./session-events.js";
4
+ const FLUSH_INTERVAL_MS = 25;
5
+ const FINISH_TURN_TIMEOUT_MS = 30_000;
6
+ const FLUSH_MAX_RECORDS = 256;
7
+ const FLUSH_MAX_BYTES = 256 * 1024;
8
+ const QUEUE_MAX_RECORDS = 8_192;
9
+ const QUEUE_MAX_BYTES = 16 * 1024 * 1024;
10
+ function objectKey(value) {
11
+ return typeof value === "object" && value !== null ? value : null;
12
+ }
13
+ function stableMessageKey(value) {
14
+ if (typeof value !== "object" || value === null) {
15
+ return null;
16
+ }
17
+ const message = value;
18
+ if (typeof message.id === "string" && message.id.length > 0) {
19
+ return `id:${message.id}`;
20
+ }
21
+ if ((typeof message.timestamp === "number" || typeof message.timestamp === "string") &&
22
+ typeof message.role === "string") {
23
+ return `timestamp:${message.role}:${message.timestamp}`;
24
+ }
25
+ return null;
26
+ }
27
+ function entryRole(entry) {
28
+ const message = entry.message;
29
+ return messageRole(message);
30
+ }
31
+ function failureMessage(error) {
32
+ return error instanceof Error ? error.message : String(error);
33
+ }
34
+ /** Records settled Pi entries and normalized temporal events through the workflow host. */
35
+ export class SessionRecorder {
36
+ store;
37
+ runId;
38
+ /** Capture segment for this recorder after an ownership handoff. */
39
+ segmentId;
40
+ cursor = null;
41
+ recorded = [];
42
+ unclaimedEntries = [];
43
+ bound = false;
44
+ acceptingEntries = true;
45
+ acceptingEvents = true;
46
+ entryChain = Promise.resolve();
47
+ stopPromise = null;
48
+ nextEventSeq = 1;
49
+ nextTurnId = 1;
50
+ nextMessageId = 1;
51
+ currentAttempt = null;
52
+ currentTurn = null;
53
+ currentMessage = null;
54
+ lastFinishedAttempt = null;
55
+ finishPromise = null;
56
+ resolveFinish = null;
57
+ finishTimer = null;
58
+ messageOwners = new WeakMap();
59
+ stableMessageOwners = new Map();
60
+ toolOwners = new Map();
61
+ turnToolCallIds = new Map();
62
+ eventQueue = [];
63
+ pendingMessageEnds = [];
64
+ outstandingRecords = 0;
65
+ outstandingBytes = 0;
66
+ flushTimer = null;
67
+ flushPromise = null;
68
+ captureFailure = null;
69
+ constructor(store, runId) {
70
+ this.store = store;
71
+ this.runId = runId;
72
+ }
73
+ async bind(ctx) {
74
+ if (this.bound) {
75
+ return;
76
+ }
77
+ this.bound = true;
78
+ this.cursor = ctx.sessionManager.getLeafId();
79
+ const sessionFile = ctx.sessionManager.getSessionFile();
80
+ // An existing binding belongs to an earlier capture segment.
81
+ if (await this.store.hasSessionBinding(this.runId)) {
82
+ this.segmentId = randomUUID();
83
+ }
84
+ await this.store.writeSessionBinding(this.runId, {
85
+ schema: SESSION_BINDING_SCHEMA,
86
+ runId: this.runId,
87
+ piSessionId: ctx.sessionManager.getSessionId(),
88
+ ...(sessionFile !== undefined ? { piSessionFile: sessionFile } : {}),
89
+ cwd: ctx.cwd,
90
+ boundAt: new Date().toISOString(),
91
+ }, this.segmentId);
92
+ await this.store.writeSessionCapture(this.runId, {
93
+ schema: SESSION_CAPTURE_SCHEMA,
94
+ eventSchema: SESSION_EVENT_SCHEMA,
95
+ status: "recording",
96
+ eventCount: 0,
97
+ entryCount: 0,
98
+ lastEventSeq: 0,
99
+ }, this.segmentId);
100
+ }
101
+ /** Fix the owner before the executor delivers an agent-step prompt. */
102
+ beginAttempt(contract) {
103
+ this.currentAttempt = { nodeId: contract.nodeId, attemptId: contract.attemptId };
104
+ }
105
+ /** Record a workflow-owned turn that is not tied to one engine node attempt. */
106
+ beginWorkflowMessage(workflowMessageId, kind) {
107
+ this.currentAttempt = { nodeId: kind, attemptId: workflowMessageId };
108
+ }
109
+ /** Release ownership of the turn that Pi has fully settled. */
110
+ settleAttempt() {
111
+ const finished = this.lastFinishedAttempt;
112
+ this.lastFinishedAttempt = null;
113
+ if (this.currentTurn === null &&
114
+ (finished === null ||
115
+ (this.currentAttempt?.nodeId === finished.nodeId &&
116
+ this.currentAttempt.attemptId === finished.attemptId))) {
117
+ this.currentAttempt = null;
118
+ }
119
+ }
120
+ handleTurnStart(event) {
121
+ const owner = this.currentAttempt;
122
+ if (!owner) {
123
+ return;
124
+ }
125
+ const turn = {
126
+ ...owner,
127
+ turnId: `t${this.nextTurnId}`,
128
+ turnIndex: event.turnIndex,
129
+ };
130
+ this.nextTurnId += 1;
131
+ this.currentTurn = turn;
132
+ this.turnToolCallIds.set(turn.turnId, []);
133
+ this.enqueue(turn, "turn_started", { turnIndex: event.turnIndex });
134
+ }
135
+ async handleTurnEnd(event, ctx) {
136
+ const turn = this.currentTurn;
137
+ if (!turn) {
138
+ return;
139
+ }
140
+ const message = this.ownerForMessage(event.message);
141
+ try {
142
+ await this.synchronize(ctx);
143
+ this.enqueue(turn, "turn_finished", turnFinishedPayload(event, message?.messageId, this.turnToolCallIds.get(turn.turnId) ?? []));
144
+ }
145
+ catch (error) {
146
+ this.failCapture("entry_write_failed", failureMessage(error));
147
+ }
148
+ this.currentTurn = null;
149
+ this.currentMessage = null;
150
+ this.lastFinishedAttempt = { nodeId: turn.nodeId, attemptId: turn.attemptId };
151
+ if (this.finishPromise) {
152
+ await this.stop();
153
+ }
154
+ }
155
+ async handleMessageStart(event, ctx) {
156
+ const turn = this.currentTurn;
157
+ if (!turn) {
158
+ return;
159
+ }
160
+ await this.synchronize(ctx);
161
+ const owner = {
162
+ ...turn,
163
+ messageId: `m${this.nextMessageId}`,
164
+ role: messageRole(event.message),
165
+ };
166
+ this.nextMessageId += 1;
167
+ const key = objectKey(event.message);
168
+ if (key) {
169
+ this.messageOwners.set(key, owner);
170
+ }
171
+ const stableKey = stableMessageKey(event.message);
172
+ if (stableKey) {
173
+ this.stableMessageOwners.set(stableKey, owner);
174
+ }
175
+ this.currentMessage = owner;
176
+ this.enqueue(owner, "message_started", { role: owner.role });
177
+ }
178
+ handleMessageUpdate(event) {
179
+ const owner = this.ownerForMessage(event.message);
180
+ if (!owner) {
181
+ return;
182
+ }
183
+ const normalized = normalizeAssistantEvent(event.assistantMessageEvent);
184
+ if (normalized.type === "text_delta" ||
185
+ normalized.type === "thinking_delta" ||
186
+ normalized.type === "toolcall_delta") {
187
+ return;
188
+ }
189
+ const toolCallId = toolCallIdFromAssistantEvent(normalized);
190
+ if (toolCallId) {
191
+ this.toolOwners.set(toolCallId, owner);
192
+ const ids = this.turnToolCallIds.get(owner.turnId) ?? [];
193
+ if (!ids.includes(toolCallId)) {
194
+ ids.push(toolCallId);
195
+ this.turnToolCallIds.set(owner.turnId, ids);
196
+ }
197
+ }
198
+ this.enqueue(owner, "assistant_event", normalized);
199
+ }
200
+ handleMessageEnd(event) {
201
+ const owner = this.ownerForMessage(event.message);
202
+ if (!owner) {
203
+ return;
204
+ }
205
+ // Pi appends the final session entry after message_end handlers return.
206
+ // Keep this record and every later event queued until a documented hook
207
+ // with synchronized session state can attach the exact entry id.
208
+ this.clearFlushTimer();
209
+ const queued = this.enqueue(owner, "message_finished", { role: owner.role, settled: false }, undefined, {}, true);
210
+ if (queued) {
211
+ this.pendingMessageEnds.push({ queued, role: owner.role, message: event.message });
212
+ this.clearFlushTimer();
213
+ }
214
+ if (this.currentMessage?.messageId === owner.messageId) {
215
+ this.currentMessage = null;
216
+ }
217
+ }
218
+ handleToolStart(event) {
219
+ const owner = this.toolOwners.get(event.toolCallId) ?? this.currentMessage;
220
+ if (!owner) {
221
+ return;
222
+ }
223
+ this.toolOwners.set(event.toolCallId, owner);
224
+ this.enqueue(owner, "tool_execution_started", toolStartedPayload(event), undefined, {
225
+ toolCallId: event.toolCallId,
226
+ });
227
+ }
228
+ handleToolUpdate(_event) {
229
+ // Incremental tool progress is transient. The recorder stores the settled
230
+ // tool result and the surrounding lifecycle facts.
231
+ }
232
+ handleToolEnd(event) {
233
+ const owner = this.toolOwners.get(event.toolCallId);
234
+ if (!owner) {
235
+ return;
236
+ }
237
+ this.enqueue(owner, "tool_execution_finished", toolFinishedPayload(event), undefined, {
238
+ toolCallId: event.toolCallId,
239
+ });
240
+ }
241
+ /** Flush new entries on the current branch into the bundle. */
242
+ record(ctx) {
243
+ if (!this.bound || !this.acceptingEntries) {
244
+ return Promise.resolve([]);
245
+ }
246
+ const task = this.entryChain.then(async () => {
247
+ const branch = ctx.sessionManager.getBranch();
248
+ let startIndex = 0;
249
+ if (this.cursor !== null) {
250
+ const cursorIndex = branch.findIndex((entry) => entry.id === this.cursor);
251
+ if (cursorIndex === -1) {
252
+ this.cursor = branch.at(-1)?.id ?? this.cursor;
253
+ return [];
254
+ }
255
+ startIndex = cursorIndex + 1;
256
+ }
257
+ const appended = [];
258
+ for (const entry of branch.slice(startIndex)) {
259
+ await this.store.appendSessionEntry(this.runId, entry, this.segmentId);
260
+ const recorded = { id: entry.id, entry, claimed: false };
261
+ appended.push(recorded);
262
+ this.unclaimedEntries.push(recorded);
263
+ this.recorded.push(entry.id);
264
+ this.cursor = entry.id;
265
+ }
266
+ return appended;
267
+ });
268
+ this.entryChain = task.catch((error) => {
269
+ this.failCapture("entry_write_failed", failureMessage(error));
270
+ });
271
+ return task;
272
+ }
273
+ /** Record durable entries, then release deferred message-end events in order. */
274
+ async synchronize(ctx) {
275
+ if (this.pendingMessageEnds.length === 0) {
276
+ return;
277
+ }
278
+ await this.record(ctx);
279
+ for (const pending of this.pendingMessageEnds.splice(0)) {
280
+ const entryId = this.claimEntry(pending.role, pending.message);
281
+ pending.queued.record.payload = entryId
282
+ ? { role: pending.role, settled: true, entryId }
283
+ : { role: pending.role, settled: false };
284
+ const bytes = Buffer.byteLength(JSON.stringify(pending.queued.record), "utf8") + 1;
285
+ this.outstandingBytes += bytes - pending.queued.bytes;
286
+ pending.queued.bytes = bytes;
287
+ }
288
+ if (this.eventQueue.length >= FLUSH_MAX_RECORDS || this.queuedBytes() >= FLUSH_MAX_BYTES) {
289
+ this.startFlush();
290
+ }
291
+ else {
292
+ this.scheduleFlush();
293
+ }
294
+ }
295
+ /**
296
+ * Finalize immediately when no Pi turn is active. Otherwise wait for
297
+ * `turn_end`, which is the last documented lifecycle boundary needed to
298
+ * include the workflow tool result and any following assistant output.
299
+ */
300
+ async finish() {
301
+ if (this.stopPromise || this.currentTurn === null) {
302
+ return await this.stop();
303
+ }
304
+ if (!this.finishPromise) {
305
+ this.finishPromise = new Promise((resolve) => {
306
+ this.resolveFinish = resolve;
307
+ });
308
+ this.finishTimer = setTimeout(() => {
309
+ this.failCapture("turn_settle_timeout", `active Pi turn did not finish within ${FINISH_TURN_TIMEOUT_MS}ms`);
310
+ void this.stop();
311
+ }, FINISH_TURN_TIMEOUT_MS);
312
+ this.finishTimer.unref?.();
313
+ }
314
+ return await this.finishPromise;
315
+ }
316
+ async stop() {
317
+ if (this.stopPromise) {
318
+ return await this.stopPromise;
319
+ }
320
+ if (this.currentTurn !== null) {
321
+ this.failCapture("turn_interrupted", "session capture stopped before the active Pi turn finished");
322
+ }
323
+ this.acceptingEntries = false;
324
+ this.acceptingEvents = false;
325
+ // If Pi closes before another synchronized hook, preserve the message-end
326
+ // receipts as explicitly unsettled rather than hanging finalization.
327
+ this.pendingMessageEnds.splice(0);
328
+ this.clearFlushTimer();
329
+ this.stopPromise = (async () => {
330
+ try {
331
+ await this.flushAllEvents();
332
+ await this.entryChain;
333
+ const counts = await this.store.sessionCounts(this.runId, this.segmentId);
334
+ await this.store.writeSessionCapture(this.runId, {
335
+ schema: SESSION_CAPTURE_SCHEMA,
336
+ eventSchema: SESSION_EVENT_SCHEMA,
337
+ status: this.captureFailure ? "failed" : "complete",
338
+ ...counts,
339
+ ...(this.captureFailure ? { failure: this.captureFailure } : {}),
340
+ }, this.segmentId);
341
+ }
342
+ catch (error) {
343
+ // Capture is observational. A finalization failure must never reject
344
+ // the workflow's terminal persistence hook.
345
+ this.failCapture("capture_finalize_failed", failureMessage(error));
346
+ try {
347
+ const counts = await this.store.sessionCounts(this.runId, this.segmentId);
348
+ await this.store.writeSessionCapture(this.runId, {
349
+ schema: SESSION_CAPTURE_SCHEMA,
350
+ eventSchema: SESSION_EVENT_SCHEMA,
351
+ status: "failed",
352
+ ...counts,
353
+ failure: this.captureFailure ?? {
354
+ failedAt: new Date().toISOString(),
355
+ code: "capture_finalize_failed",
356
+ message: failureMessage(error),
357
+ },
358
+ }, this.segmentId);
359
+ }
360
+ catch {
361
+ // The viewer will report the missing/invalid capture file.
362
+ }
363
+ }
364
+ finally {
365
+ if (this.finishTimer) {
366
+ clearTimeout(this.finishTimer);
367
+ this.finishTimer = null;
368
+ }
369
+ this.resolveFinish?.();
370
+ this.resolveFinish = null;
371
+ }
372
+ })();
373
+ return await this.stopPromise;
374
+ }
375
+ mark() {
376
+ return this.recorded.length;
377
+ }
378
+ rangeSince(mark) {
379
+ if (this.recorded.length <= mark) {
380
+ return undefined;
381
+ }
382
+ return {
383
+ firstEntryId: this.recorded[mark],
384
+ lastEntryId: this.recorded.at(-1),
385
+ };
386
+ }
387
+ ownerForMessage(message) {
388
+ const key = objectKey(message);
389
+ const stableKey = stableMessageKey(message);
390
+ return ((key ? this.messageOwners.get(key) : undefined) ??
391
+ (stableKey ? this.stableMessageOwners.get(stableKey) : undefined) ??
392
+ this.currentMessage);
393
+ }
394
+ claimEntry(role, message) {
395
+ const messageKey = stableMessageKey(message);
396
+ const entry = this.unclaimedEntries.find((candidate) => {
397
+ if (candidate.claimed || entryRole(candidate.entry) !== role) {
398
+ return false;
399
+ }
400
+ return messageKey === null || stableMessageKey(candidate.entry.message) === messageKey;
401
+ });
402
+ if (!entry) {
403
+ return undefined;
404
+ }
405
+ entry.claimed = true;
406
+ return entry.id;
407
+ }
408
+ enqueue(owner, type, payload, at = new Date().toISOString(), extra = {}, deferFlush = false) {
409
+ if (!this.bound || !this.acceptingEvents || this.captureFailure) {
410
+ return null;
411
+ }
412
+ const messageId = "messageId" in owner ? owner.messageId : undefined;
413
+ const record = {
414
+ seq: this.nextEventSeq,
415
+ at,
416
+ nodeId: owner.nodeId,
417
+ attemptId: owner.attemptId,
418
+ turnId: owner.turnId,
419
+ ...(messageId === undefined ? {} : { messageId }),
420
+ ...(extra.toolCallId === undefined ? {} : { toolCallId: extra.toolCallId }),
421
+ type,
422
+ payload,
423
+ };
424
+ const bytes = Buffer.byteLength(JSON.stringify(record), "utf8") + 1;
425
+ const externalizable = type === "tool_execution_started" ||
426
+ type === "tool_execution_finished" ||
427
+ (type === "assistant_event" && payload.type === "toolcall_end");
428
+ if (bytes > SESSION_EVENT_MAX_BYTES && !externalizable) {
429
+ this.failCapture("event_too_large", `session event exceeded ${SESSION_EVENT_MAX_BYTES} bytes`);
430
+ return null;
431
+ }
432
+ if (this.outstandingRecords + 1 > QUEUE_MAX_RECORDS ||
433
+ this.outstandingBytes + bytes > QUEUE_MAX_BYTES) {
434
+ this.failCapture("event_queue_overflow", "session event queue limit exceeded");
435
+ return null;
436
+ }
437
+ this.nextEventSeq += 1;
438
+ const queued = { record, bytes };
439
+ this.eventQueue.push(queued);
440
+ this.outstandingRecords += 1;
441
+ this.outstandingBytes += bytes;
442
+ if (!deferFlush) {
443
+ if (this.eventQueue.length >= FLUSH_MAX_RECORDS || this.queuedBytes() >= FLUSH_MAX_BYTES) {
444
+ this.startFlush();
445
+ }
446
+ else {
447
+ this.scheduleFlush();
448
+ }
449
+ }
450
+ return queued;
451
+ }
452
+ queuedBytes() {
453
+ return this.eventQueue.reduce((sum, queued) => sum + queued.bytes, 0);
454
+ }
455
+ scheduleFlush() {
456
+ if (this.pendingMessageEnds.length > 0 || this.flushTimer || this.flushPromise) {
457
+ return;
458
+ }
459
+ this.flushTimer = setTimeout(() => {
460
+ this.flushTimer = null;
461
+ this.startFlush();
462
+ }, FLUSH_INTERVAL_MS);
463
+ this.flushTimer.unref?.();
464
+ }
465
+ startFlush() {
466
+ if (this.pendingMessageEnds.length > 0 || this.flushPromise || this.eventQueue.length === 0) {
467
+ return;
468
+ }
469
+ this.clearFlushTimer();
470
+ const batch = [];
471
+ let bytes = 0;
472
+ while (this.eventQueue.length > 0 && batch.length < FLUSH_MAX_RECORDS) {
473
+ const next = this.eventQueue[0];
474
+ if (batch.length > 0 && bytes + next.bytes > FLUSH_MAX_BYTES) {
475
+ break;
476
+ }
477
+ batch.push(this.eventQueue.shift());
478
+ bytes += next.bytes;
479
+ }
480
+ this.flushPromise = this.store
481
+ .appendSessionEventBatch(this.runId, batch.map((queued) => queued.record), this.segmentId)
482
+ .catch((error) => {
483
+ const message = failureMessage(error);
484
+ this.failCapture(message.includes(`exceeded ${SESSION_EVENT_MAX_BYTES} bytes`)
485
+ ? "event_too_large"
486
+ : "event_write_failed", message);
487
+ for (const queued of this.eventQueue.splice(0)) {
488
+ this.outstandingRecords -= 1;
489
+ this.outstandingBytes -= queued.bytes;
490
+ }
491
+ })
492
+ .finally(() => {
493
+ for (const queued of batch) {
494
+ this.outstandingRecords -= 1;
495
+ this.outstandingBytes -= queued.bytes;
496
+ }
497
+ this.flushPromise = null;
498
+ if (this.eventQueue.length > 0 && this.captureFailure?.code !== "event_write_failed") {
499
+ this.startFlush();
500
+ }
501
+ });
502
+ }
503
+ async flushAllEvents() {
504
+ this.clearFlushTimer();
505
+ while (this.eventQueue.length > 0 || this.flushPromise) {
506
+ if (!this.flushPromise) {
507
+ this.startFlush();
508
+ }
509
+ await this.flushPromise;
510
+ }
511
+ }
512
+ clearFlushTimer() {
513
+ if (this.flushTimer) {
514
+ clearTimeout(this.flushTimer);
515
+ this.flushTimer = null;
516
+ }
517
+ }
518
+ failCapture(code, message) {
519
+ if (this.captureFailure) {
520
+ return;
521
+ }
522
+ this.captureFailure = {
523
+ failedAt: new Date().toISOString(),
524
+ code,
525
+ message,
526
+ };
527
+ this.acceptingEvents = false;
528
+ }
529
+ }
530
+ //# sourceMappingURL=recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/extension/recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { WorkflowClient } from "../client/client.js";
2
+ import type { WorkflowSessionBinding, WorkflowSessionCapture, WorkflowSessionEventRecord } from "../workflows/types.js";
3
+ import type { SessionRecordingStore } from "./recorder.js";
4
+ type SessionCommandContext = {
5
+ targetSessionId: string;
6
+ coordinatorEpoch: string;
7
+ };
8
+ /** Sends bounded session recording batches to the single workflow host writer. */
9
+ export declare class RemoteSessionRecordingStore implements SessionRecordingStore {
10
+ private readonly client;
11
+ private readonly context;
12
+ constructor(client: WorkflowClient, context: () => SessionCommandContext);
13
+ hasSessionBinding(runId: string): Promise<boolean>;
14
+ writeSessionBinding(runId: string, binding: WorkflowSessionBinding, attemptId?: string): Promise<void>;
15
+ writeSessionCapture(runId: string, capture: WorkflowSessionCapture, attemptId?: string): Promise<void>;
16
+ appendSessionEntry(runId: string, entry: Record<string, unknown>, attemptId?: string): Promise<number>;
17
+ appendSessionEventBatch(runId: string, events: WorkflowSessionEventRecord[], attemptId?: string): Promise<void>;
18
+ sessionCounts(runId: string, attemptId?: string): Promise<{
19
+ eventCount: number;
20
+ entryCount: number;
21
+ lastEventSeq: number;
22
+ }>;
23
+ private request;
24
+ }
25
+ export {};
@@ -0,0 +1,81 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { canonicalJson } from "../state/json.js";
3
+ /** Sends bounded session recording batches to the single workflow host writer. */
4
+ export class RemoteSessionRecordingStore {
5
+ client;
6
+ context;
7
+ constructor(client, context) {
8
+ this.client = client;
9
+ this.context = context;
10
+ }
11
+ async hasSessionBinding(runId) {
12
+ const receipt = await this.request(runId, "status");
13
+ if (typeof receipt.bound !== "boolean")
14
+ throw new Error("Session recording status is invalid");
15
+ return receipt.bound;
16
+ }
17
+ async writeSessionBinding(runId, binding, attemptId) {
18
+ await this.request(runId, "bind", {
19
+ binding: toJson(binding),
20
+ ...(attemptId === undefined ? {} : { attemptId }),
21
+ });
22
+ }
23
+ async writeSessionCapture(runId, capture, attemptId) {
24
+ await this.request(runId, "capture", {
25
+ capture: toJson(capture),
26
+ ...(attemptId === undefined ? {} : { attemptId }),
27
+ });
28
+ }
29
+ async appendSessionEntry(runId, entry, attemptId) {
30
+ const receipt = await this.request(runId, "entries", {
31
+ entries: [toJson(entry)],
32
+ ...(attemptId === undefined ? {} : { attemptId }),
33
+ });
34
+ if (!Number.isSafeInteger(receipt.entrySequence) || receipt.entrySequence <= 0) {
35
+ throw new Error("Session recording entry receipt is invalid");
36
+ }
37
+ return receipt.entrySequence;
38
+ }
39
+ async appendSessionEventBatch(runId, events, attemptId) {
40
+ await this.request(runId, "events", {
41
+ events: toJson(events),
42
+ ...(attemptId === undefined ? {} : { attemptId }),
43
+ });
44
+ }
45
+ async sessionCounts(runId, attemptId) {
46
+ const receipt = await this.request(runId, "status", attemptId === undefined ? {} : { attemptId });
47
+ const eventCount = positiveOrZero(receipt.eventCount, "eventCount");
48
+ const entryCount = positiveOrZero(receipt.entryCount, "entryCount");
49
+ const lastEventSeq = positiveOrZero(receipt.lastEventSeq, "lastEventSeq");
50
+ return { eventCount, entryCount, lastEventSeq };
51
+ }
52
+ async request(runId, action, extra = {}) {
53
+ const idempotencyKey = `session-record-${randomUUID()}`;
54
+ const response = await this.client.requestDurable({
55
+ operation: "session.record",
56
+ requestId: idempotencyKey,
57
+ idempotencyKey,
58
+ runId,
59
+ payload: { ...this.context(), action, ...extra },
60
+ });
61
+ if (response.outcome !== "accepted" && response.outcome !== "adopted") {
62
+ throw new Error(response.error ?? "Workflow host rejected the session recording batch");
63
+ }
64
+ if (!isRecord(response.receipt))
65
+ throw new Error("Session recording receipt is invalid");
66
+ return response.receipt;
67
+ }
68
+ }
69
+ function toJson(value) {
70
+ return JSON.parse(canonicalJson(value));
71
+ }
72
+ function positiveOrZero(value, name) {
73
+ if (!Number.isSafeInteger(value) || value < 0) {
74
+ throw new Error(`Session recording ${name} is invalid`);
75
+ }
76
+ return value;
77
+ }
78
+ function isRecord(value) {
79
+ return typeof value === "object" && value !== null && !Array.isArray(value);
80
+ }
81
+ //# sourceMappingURL=remote-recorder-store.js.map