@osolmaz/pi-workflows 0.1.0 → 0.2.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 (62) hide show
  1. package/README.md +36 -21
  2. package/dist/extension/executor.d.ts +14 -1
  3. package/dist/extension/executor.js +11 -1
  4. package/dist/extension/executor.js.map +1 -1
  5. package/dist/extension/index.js +79 -7
  6. package/dist/extension/index.js.map +1 -1
  7. package/dist/extension/recorder.d.ts +85 -0
  8. package/dist/extension/recorder.js +525 -0
  9. package/dist/extension/recorder.js.map +1 -0
  10. package/dist/extension/session-events.d.ts +134 -0
  11. package/dist/extension/session-events.js +60 -0
  12. package/dist/extension/session-events.js.map +1 -0
  13. package/dist/extension/widget.js +25 -24
  14. package/dist/extension/widget.js.map +1 -1
  15. package/dist/render/canvas.d.ts +1 -1
  16. package/dist/render/canvas.js +5 -0
  17. package/dist/render/canvas.js.map +1 -1
  18. package/dist/render/graph-render.d.ts +5 -0
  19. package/dist/render/graph-render.js +211 -48
  20. package/dist/render/graph-render.js.map +1 -1
  21. package/dist/viewer/render.js +19 -3
  22. package/dist/viewer/render.js.map +1 -1
  23. package/dist/viewer/session-reducer.d.ts +45 -0
  24. package/dist/viewer/session-reducer.js +266 -0
  25. package/dist/viewer/session-reducer.js.map +1 -0
  26. package/dist/workflows/artifacts.d.ts +40 -0
  27. package/dist/workflows/artifacts.js +155 -0
  28. package/dist/workflows/artifacts.js.map +1 -0
  29. package/dist/workflows/engine.d.ts +2 -0
  30. package/dist/workflows/engine.js +38 -7
  31. package/dist/workflows/engine.js.map +1 -1
  32. package/dist/workflows/index.d.ts +3 -2
  33. package/dist/workflows/index.js +2 -1
  34. package/dist/workflows/index.js.map +1 -1
  35. package/dist/workflows/store.d.ts +53 -9
  36. package/dist/workflows/store.js +523 -43
  37. package/dist/workflows/store.js.map +1 -1
  38. package/dist/workflows/types.d.ts +126 -3
  39. package/docs/development.md +43 -19
  40. package/docs/live-replay-protocol.md +155 -0
  41. package/docs/plans/piw-viewer-experience-implementation-plan.md +674 -0
  42. package/docs/plans/replayable-run-bundles-implementation-plan.md +65 -0
  43. package/docs/plans/session-event-replay-implementation-plan.md +494 -0
  44. package/docs/plans/tui-viewer-implementation-plan.md +64 -0
  45. package/docs/run-bundles.md +320 -55
  46. package/docs/session-event-journal.md +470 -0
  47. package/docs/tui-viewer.md +218 -0
  48. package/package.json +2 -1
  49. package/src/extension/executor.ts +28 -1
  50. package/src/extension/index.ts +87 -7
  51. package/src/extension/recorder.ts +633 -0
  52. package/src/extension/session-events.ts +119 -0
  53. package/src/extension/widget.ts +26 -24
  54. package/src/render/canvas.ts +19 -1
  55. package/src/render/graph-render.ts +277 -44
  56. package/src/viewer/render.ts +21 -3
  57. package/src/viewer/session-reducer.ts +347 -0
  58. package/src/workflows/artifacts.ts +188 -0
  59. package/src/workflows/engine.ts +39 -7
  60. package/src/workflows/index.ts +15 -0
  61. package/src/workflows/store.ts +649 -49
  62. package/src/workflows/types.ts +141 -3
@@ -153,6 +153,34 @@ export type WorkflowDefinition = {
153
153
 
154
154
  export type WorkflowNodeOutcome = "ok" | "timed_out" | "failed" | "cancelled";
155
155
 
156
+ /**
157
+ * Reference to a content-addressed file under the bundle's `artifacts/`
158
+ * directory. Large string leaves inside persisted values are replaced by
159
+ * `{ "$artifact": ArtifactRef }` at write time (see `docs/run-bundles.md`).
160
+ */
161
+ export type ArtifactRef = {
162
+ /** Bundle-relative path, `artifacts/sha256-<64 hex>.txt`. */
163
+ path: string;
164
+ mediaType: string;
165
+ bytes: number;
166
+ /** Hex digest of the artifact bytes. */
167
+ sha256: string;
168
+ };
169
+
170
+ /** The sentinel wrapper that replaces an externalized value. */
171
+ export type ArtifactValue = { $artifact: ArtifactRef };
172
+
173
+ /**
174
+ * Explicit linkage from a workflow attempt to the Pi conversation slice it
175
+ * produced. Ids address entries in `session/entries.ndjson` by Pi entry id.
176
+ */
177
+ export type ConversationRange = {
178
+ /** First Pi session entry id of the attempt. */
179
+ firstEntryId: string;
180
+ /** Last Pi session entry id of the attempt, inclusive. */
181
+ lastEntryId: string;
182
+ };
183
+
156
184
  export type WorkflowNodeResult = {
157
185
  attemptId: string;
158
186
  nodeId: string;
@@ -182,10 +210,16 @@ export type WorkflowStepRecord = {
182
210
  outcome: WorkflowNodeOutcome;
183
211
  startedAt: string;
184
212
  finishedAt: string;
185
- promptText: string | null;
213
+ /**
214
+ * Full prompt text for agent steps, `null` for other node types. In a
215
+ * persisted bundle a large prompt may be an `ArtifactValue`.
216
+ */
217
+ prompt: string | ArtifactValue | null;
186
218
  output: unknown;
187
219
  error?: string;
188
220
  action?: WorkflowActionReceipt;
221
+ /** For agent steps recorded inside a Pi conversation. */
222
+ conversation?: ConversationRange;
189
223
  };
190
224
 
191
225
  export type WorkflowRunStatus =
@@ -197,6 +231,13 @@ export type WorkflowRunStatus =
197
231
  | "cancelled";
198
232
 
199
233
  export type WorkflowRunState = {
234
+ schema: "pi-workflows.run-state.v1";
235
+ /**
236
+ * `seq` of the trace event this projection reflects. `trace.ndjson` is the
237
+ * source of truth; a state whose `traceSeq` is older than the trace tail is
238
+ * a stale projection.
239
+ */
240
+ traceSeq: number;
200
241
  runId: string;
201
242
  workflowName: string;
202
243
  runTitle?: string;
@@ -211,7 +252,6 @@ export type WorkflowRunState = {
211
252
  steps: WorkflowStepRecord[];
212
253
  currentNode?: string;
213
254
  currentAttemptId?: string;
214
- currentNodeType?: WorkflowNodeDefinition["nodeType"];
215
255
  currentNodeStartedAt?: string;
216
256
  statusDetail?: string;
217
257
  /** True while the run is held at a step boundary by a pause request. */
@@ -241,7 +281,7 @@ export type WorkflowDefinitionSnapshot = {
241
281
  export type WorkflowTraceEvent = {
242
282
  seq: number;
243
283
  at: string;
244
- scope: "run" | "node" | "agent" | "action";
284
+ scope: "run" | "node" | "agent" | "action" | "session";
245
285
  type: string;
246
286
  runId: string;
247
287
  nodeId?: string;
@@ -249,6 +289,77 @@ export type WorkflowTraceEvent = {
249
289
  payload: Record<string, unknown>;
250
290
  };
251
291
 
292
+ /** `session/binding.json`: written once when a run binds to a conversation. */
293
+ export type WorkflowSessionBinding = {
294
+ schema: "pi-workflows.session-binding.v1";
295
+ runId: string;
296
+ /** Pi session UUID. */
297
+ piSessionId: string;
298
+ /**
299
+ * Absolute path of the Pi session file; provenance only, never read back.
300
+ * Absent for in-memory sessions.
301
+ */
302
+ piSessionFile?: string;
303
+ /** Working directory of the conversation. */
304
+ cwd: string;
305
+ boundAt: string;
306
+ };
307
+
308
+ /**
309
+ * One line of `session/entries.ndjson`: a verbatim Pi session entry recorded
310
+ * while the run was active. The inner entry shape is owned by Pi.
311
+ */
312
+ export type WorkflowSessionEntryRecord = {
313
+ /** Starts at 1, increases by exactly 1 within the file. */
314
+ seq: number;
315
+ /** When the entry was recorded into the bundle. */
316
+ at: string;
317
+ /** Verbatim Pi session entry (has its own id/parentId/timestamp). */
318
+ entry: Record<string, unknown>;
319
+ };
320
+
321
+ export type WorkflowSessionEventType =
322
+ | "turn_started"
323
+ | "turn_finished"
324
+ | "message_started"
325
+ | "assistant_event"
326
+ | "message_finished"
327
+ | "tool_execution_started"
328
+ | "tool_execution_updated"
329
+ | "tool_execution_finished";
330
+
331
+ /** One normalized temporal Pi event in `session/events.ndjson`. */
332
+ export type WorkflowSessionEventRecord = {
333
+ /** Starts at 1 and increases by exactly 1 within the file. */
334
+ seq: number;
335
+ /** Time when the extension received the public Pi event. */
336
+ at: string;
337
+ nodeId: string;
338
+ attemptId: string;
339
+ turnId?: string;
340
+ messageId?: string;
341
+ toolCallId?: string;
342
+ type: WorkflowSessionEventType;
343
+ payload: Record<string, unknown>;
344
+ };
345
+
346
+ export type WorkflowSessionCaptureFailure = {
347
+ failedAt: string;
348
+ code: string;
349
+ message: string;
350
+ };
351
+
352
+ /** Atomic integrity projection for the temporal session journal. */
353
+ export type WorkflowSessionCapture = {
354
+ schema: "pi-workflows.session-capture.v1";
355
+ eventSchema: "pi-workflows.session-event.v1";
356
+ status: "recording" | "complete" | "failed";
357
+ eventCount: number;
358
+ entryCount: number;
359
+ lastEventSeq: number;
360
+ failure?: WorkflowSessionCaptureFailure;
361
+ };
362
+
252
363
  export type WorkflowTraceEventDraft = Omit<WorkflowTraceEvent, "seq" | "at" | "runId">;
253
364
 
254
365
  export type WorkflowRunManifest = {
@@ -265,6 +376,10 @@ export type WorkflowRunManifest = {
265
376
  workflow: string;
266
377
  state: string;
267
378
  trace: string;
379
+ /** Bundle-relative session directory, present once a session is bound. */
380
+ session?: string;
381
+ /** Bundle-relative artifacts directory, present once a value was externalized. */
382
+ artifacts?: string;
268
383
  };
269
384
  };
270
385
 
@@ -294,6 +409,11 @@ export type AgentStepRequest = {
294
409
 
295
410
  export type AgentStepSubmission = {
296
411
  output: unknown;
412
+ /**
413
+ * The Pi conversation slice this step produced, when the executor records
414
+ * one. Persisted verbatim into the step record and terminal node event.
415
+ */
416
+ conversation?: ConversationRange;
297
417
  };
298
418
 
299
419
  /**
@@ -309,6 +429,24 @@ export type WorkflowEngineOptions = {
309
429
  executor: AgentStepExecutor;
310
430
  /** Root directory for run bundles. Defaults to `~/.pi/agent/workflows/runs`. */
311
431
  outputRoot?: string;
432
+ /**
433
+ * Shared run store. Pass the same instance used by a session recorder so
434
+ * trace sequence numbers stay single-writer. Defaults to a new store on
435
+ * `outputRoot`.
436
+ */
437
+ store?: import("./store.js").WorkflowRunStore;
438
+ /**
439
+ * Awaited after `run_started` is persisted, before any node executes. This
440
+ * is where a session recorder binds, so `session_bound` lands at the start
441
+ * of the trace and can never trail the terminal event.
442
+ */
443
+ onRunStarted?: (runDir: string, state: WorkflowRunState) => MaybePromise<void>;
444
+ /**
445
+ * Awaited before the terminal snapshot is persisted. This is where a
446
+ * session recorder stops and drains, so the bundle is immutable the moment
447
+ * the terminal event exists. Errors are swallowed: finishing the run wins.
448
+ */
449
+ onRunFinishing?: (runDir: string, state: WorkflowRunState) => MaybePromise<void>;
312
450
  /** Default per-node timeout. Defaults to 15 minutes. */
313
451
  defaultNodeTimeoutMs?: number;
314
452
  /** Guard against unbounded graph loops. Defaults to 100 executed steps. */