@osolmaz/pi-workflows 0.12.1 → 0.13.1

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 (233) hide show
  1. package/README.md +59 -33
  2. package/dist/builtins/autodoc.workflow.d.ts +194 -7
  3. package/dist/builtins/autodoc.workflow.js +156 -30
  4. package/dist/builtins/autodoc.workflow.js.map +1 -1
  5. package/dist/builtins/autoimplement-command-batches.d.ts +1 -0
  6. package/dist/builtins/autoimplement-command-batches.js +29 -31
  7. package/dist/builtins/autoimplement-command-batches.js.map +1 -1
  8. package/dist/builtins/autoimplement.workflow.d.ts +1619 -97
  9. package/dist/builtins/autoimplement.workflow.js +416 -153
  10. package/dist/builtins/autoimplement.workflow.js.map +1 -1
  11. package/dist/builtins/autoplan.workflow.d.ts +126 -13
  12. package/dist/builtins/autoplan.workflow.js +200 -29
  13. package/dist/builtins/autoplan.workflow.js.map +1 -1
  14. package/dist/builtins/catalog.js +7 -5
  15. package/dist/builtins/catalog.js.map +1 -1
  16. package/dist/builtins/change-verification.workflow.d.ts +110 -0
  17. package/dist/builtins/change-verification.workflow.js +860 -0
  18. package/dist/builtins/change-verification.workflow.js.map +1 -0
  19. package/dist/builtins/index.d.ts +2 -1
  20. package/dist/builtins/index.js +1 -0
  21. package/dist/builtins/index.js.map +1 -1
  22. package/dist/builtins/monitor.workflow.d.ts +56 -21
  23. package/dist/builtins/monitor.workflow.js +499 -217
  24. package/dist/builtins/monitor.workflow.js.map +1 -1
  25. package/dist/builtins/plain-summary.workflow.d.ts +32 -0
  26. package/dist/builtins/plain-summary.workflow.js +134 -0
  27. package/dist/builtins/plain-summary.workflow.js.map +1 -0
  28. package/dist/builtins/plan-change.workflow.d.ts +527 -26
  29. package/dist/builtins/plan-change.workflow.js +26 -0
  30. package/dist/builtins/plan-change.workflow.js.map +1 -1
  31. package/dist/builtins/sanity-check.workflow.d.ts +45 -3
  32. package/dist/builtins/sanity-check.workflow.js +45 -7
  33. package/dist/builtins/sanity-check.workflow.js.map +1 -1
  34. package/dist/builtins/workspace-preparation.workflow.d.ts +75 -0
  35. package/dist/builtins/workspace-preparation.workflow.js +498 -0
  36. package/dist/builtins/workspace-preparation.workflow.js.map +1 -0
  37. package/dist/controllers/effects.d.ts +3 -2
  38. package/dist/controllers/effects.js +8 -1
  39. package/dist/controllers/effects.js.map +1 -1
  40. package/dist/controllers/index.d.ts +1 -1
  41. package/dist/controllers/index.js +1 -1
  42. package/dist/controllers/index.js.map +1 -1
  43. package/dist/controllers/manager.d.ts +1 -0
  44. package/dist/controllers/manager.js +41 -17
  45. package/dist/controllers/manager.js.map +1 -1
  46. package/dist/controllers/sqlite.d.ts +107 -85
  47. package/dist/controllers/sqlite.js +1611 -1486
  48. package/dist/controllers/sqlite.js.map +1 -1
  49. package/dist/controllers/store.d.ts +9 -8
  50. package/dist/controllers/store.js +1 -31
  51. package/dist/controllers/store.js.map +1 -1
  52. package/dist/controllers/types.d.ts +3 -0
  53. package/dist/controllers/workflow-engine-scheduler.d.ts +1 -1
  54. package/dist/controllers/workflow-engine-scheduler.js +3 -5
  55. package/dist/controllers/workflow-engine-scheduler.js.map +1 -1
  56. package/dist/controllers/workflows.d.ts +2 -2
  57. package/dist/controllers/workflows.js +11 -10
  58. package/dist/controllers/workflows.js.map +1 -1
  59. package/dist/extension/controller-host.js +2 -2
  60. package/dist/extension/controller-host.js.map +1 -1
  61. package/dist/extension/decision-channels.d.ts +2 -0
  62. package/dist/extension/decision-channels.js +311 -118
  63. package/dist/extension/decision-channels.js.map +1 -1
  64. package/dist/extension/executor.d.ts +9 -2
  65. package/dist/extension/executor.js +90 -6
  66. package/dist/extension/executor.js.map +1 -1
  67. package/dist/extension/herdr-viewer.d.ts +0 -1
  68. package/dist/extension/herdr-viewer.js +0 -4
  69. package/dist/extension/herdr-viewer.js.map +1 -1
  70. package/dist/extension/index.js +156 -117
  71. package/dist/extension/index.js.map +1 -1
  72. package/dist/extension/recorder.d.ts +3 -10
  73. package/dist/extension/recorder.js +13 -22
  74. package/dist/extension/recorder.js.map +1 -1
  75. package/dist/extension/step-message.d.ts +7 -2
  76. package/dist/extension/step-message.js +94 -2
  77. package/dist/extension/step-message.js.map +1 -1
  78. package/dist/extension/widget.js +6 -0
  79. package/dist/extension/widget.js.map +1 -1
  80. package/dist/host/rpc-executor.d.ts +3 -0
  81. package/dist/host/rpc-executor.js +2 -0
  82. package/dist/host/rpc-executor.js.map +1 -1
  83. package/dist/host/runner.d.ts +3 -6
  84. package/dist/host/runner.js +83 -32
  85. package/dist/host/runner.js.map +1 -1
  86. package/dist/render/graph-render.js +14 -8
  87. package/dist/render/graph-render.js.map +1 -1
  88. package/dist/state/database.d.ts +35 -0
  89. package/dist/state/database.js +287 -0
  90. package/dist/state/database.js.map +1 -0
  91. package/dist/state/index.d.ts +4 -0
  92. package/dist/state/index.js +5 -0
  93. package/dist/state/index.js.map +1 -0
  94. package/dist/state/json.d.ts +6 -0
  95. package/dist/state/json.js +38 -0
  96. package/dist/state/json.js.map +1 -0
  97. package/dist/state/mutation.d.ts +57 -0
  98. package/dist/state/mutation.js +255 -0
  99. package/dist/state/mutation.js.map +1 -0
  100. package/dist/state/schema.d.ts +6 -0
  101. package/dist/state/schema.js +473 -0
  102. package/dist/state/schema.js.map +1 -0
  103. package/dist/viewer/cli.d.ts +2 -2
  104. package/dist/viewer/cli.js +142 -122
  105. package/dist/viewer/cli.js.map +1 -1
  106. package/dist/viewer/render.d.ts +4 -4
  107. package/dist/viewer/render.js +2 -17
  108. package/dist/viewer/render.js.map +1 -1
  109. package/dist/viewer/session-reducer.d.ts +1 -1
  110. package/dist/viewer/session-reducer.js +1 -1
  111. package/dist/viewer/tui.d.ts +3 -3
  112. package/dist/viewer/tui.js +15 -13
  113. package/dist/viewer/tui.js.map +1 -1
  114. package/dist/viewer/watch.d.ts +2 -5
  115. package/dist/viewer/watch.js +13 -13
  116. package/dist/viewer/watch.js.map +1 -1
  117. package/dist/workflows/composition.js +12 -2
  118. package/dist/workflows/composition.js.map +1 -1
  119. package/dist/workflows/definition.d.ts +6 -2
  120. package/dist/workflows/definition.js +17 -0
  121. package/dist/workflows/definition.js.map +1 -1
  122. package/dist/workflows/engine.d.ts +6 -6
  123. package/dist/workflows/engine.js +183 -103
  124. package/dist/workflows/engine.js.map +1 -1
  125. package/dist/workflows/errors.d.ts +3 -3
  126. package/dist/workflows/errors.js +3 -3
  127. package/dist/workflows/human-decision.d.ts +29 -4
  128. package/dist/workflows/human-decision.js +547 -283
  129. package/dist/workflows/human-decision.js.map +1 -1
  130. package/dist/workflows/index.d.ts +4 -5
  131. package/dist/workflows/index.js +3 -4
  132. package/dist/workflows/index.js.map +1 -1
  133. package/dist/workflows/schema.js +17 -1
  134. package/dist/workflows/schema.js.map +1 -1
  135. package/dist/workflows/store.d.ts +83 -103
  136. package/dist/workflows/store.js +902 -951
  137. package/dist/workflows/store.js.map +1 -1
  138. package/dist/workflows/types.d.ts +55 -81
  139. package/docs/CONTROLLERS.md +10 -8
  140. package/docs/DEFERRED_TURNS.md +2 -2
  141. package/docs/DESIGN_PHILOSOPHY.md +4 -2
  142. package/docs/HUMAN_DECISIONS.md +13 -14
  143. package/docs/MONITOR.md +179 -231
  144. package/docs/SQLITE_STATE.md +219 -0
  145. package/docs/WORKFLOW_COMPOSITION.md +27 -19
  146. package/docs/WORKFLOW_STEP_MESSAGES.md +20 -18
  147. package/docs/WORKFLOW_UPDATES.md +10 -9
  148. package/docs/development.md +9 -9
  149. package/docs/live-replay-protocol.md +28 -37
  150. package/docs/plans/2026-08-16-workflow-updates-plan.md +1 -1
  151. package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
  152. package/docs/plans/2026-08-21-autoimplement-timeout-fallback-plan.md +1 -1
  153. package/docs/plans/2026-08-21-plan-change-approval-policy-plan.md +1 -1
  154. package/docs/plans/2026-08-21-sanity-check-plan.md +30 -16
  155. package/docs/plans/2026-08-22-goal-finishing-monitor-plan.md +200 -0
  156. package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +701 -0
  157. package/docs/plans/2026-08-23-sqlite-state-plan.md +970 -0
  158. package/docs/plans/2026-08-24-change-scoped-verification-plan.md +419 -0
  159. package/docs/plans/replayable-run-bundles-implementation-plan.md +2 -2
  160. package/docs/plans/session-event-replay-implementation-plan.md +1 -1
  161. package/docs/plans/tui-viewer-implementation-plan.md +1 -1
  162. package/docs/session-event-journal.md +63 -434
  163. package/docs/tui-viewer.md +13 -15
  164. package/docs/workflows.md +111 -62
  165. package/examples/workflows/plain-summary.workflow.ts +1 -0
  166. package/herdr-plugin.toml +1 -1
  167. package/package.json +1 -1
  168. package/plugins/herdr/viewer.mjs +1 -11
  169. package/skills/autodoc/SKILL.md +7 -0
  170. package/skills/autoimplement/SKILL.md +4 -0
  171. package/skills/autoplan/SKILL.md +5 -4
  172. package/skills/monitor/SKILL.md +91 -163
  173. package/skills/pi-workflows/SKILL.md +7 -7
  174. package/skills/sanity-check/SKILL.md +1 -1
  175. package/src/builtins/autodoc.workflow.ts +184 -33
  176. package/src/builtins/autoimplement-command-batches.ts +39 -33
  177. package/src/builtins/autoimplement.workflow.ts +483 -175
  178. package/src/builtins/autoplan.workflow.ts +290 -40
  179. package/src/builtins/catalog.ts +7 -5
  180. package/src/builtins/change-verification.workflow.ts +1143 -0
  181. package/src/builtins/index.ts +7 -1
  182. package/src/builtins/monitor.workflow.ts +667 -250
  183. package/src/builtins/plain-summary.workflow.ts +185 -0
  184. package/src/builtins/plan-change.workflow.ts +35 -0
  185. package/src/builtins/sanity-check.workflow.ts +62 -7
  186. package/src/builtins/workspace-preparation.workflow.ts +668 -0
  187. package/src/controllers/effects.ts +7 -0
  188. package/src/controllers/index.ts +0 -6
  189. package/src/controllers/manager.ts +72 -32
  190. package/src/controllers/sqlite.ts +2420 -1948
  191. package/src/controllers/store.ts +17 -38
  192. package/src/controllers/types.ts +3 -0
  193. package/src/controllers/workflow-engine-scheduler.ts +4 -8
  194. package/src/controllers/workflows.ts +45 -21
  195. package/src/extension/controller-host.ts +1 -2
  196. package/src/extension/decision-channels.ts +427 -144
  197. package/src/extension/executor.ts +106 -6
  198. package/src/extension/herdr-viewer.ts +0 -5
  199. package/src/extension/index.ts +180 -132
  200. package/src/extension/recorder.ts +13 -22
  201. package/src/extension/step-message.ts +106 -4
  202. package/src/extension/widget.ts +8 -0
  203. package/src/host/rpc-executor.ts +4 -0
  204. package/src/host/runner.ts +93 -41
  205. package/src/render/graph-render.ts +11 -4
  206. package/src/state/database.ts +375 -0
  207. package/src/state/index.ts +29 -0
  208. package/src/state/json.ts +42 -0
  209. package/src/state/mutation.ts +435 -0
  210. package/src/state/schema.ts +475 -0
  211. package/src/viewer/cli.ts +151 -144
  212. package/src/viewer/render.ts +12 -24
  213. package/src/viewer/session-reducer.ts +1 -1
  214. package/src/viewer/tui.ts +18 -17
  215. package/src/viewer/watch.ts +13 -17
  216. package/src/workflows/composition.ts +12 -3
  217. package/src/workflows/definition.ts +36 -3
  218. package/src/workflows/engine.ts +212 -116
  219. package/src/workflows/errors.ts +3 -3
  220. package/src/workflows/human-decision.ts +795 -340
  221. package/src/workflows/index.ts +15 -19
  222. package/src/workflows/schema.ts +19 -1
  223. package/src/workflows/store.ts +1295 -1163
  224. package/src/workflows/types.ts +61 -81
  225. package/dist/workflows/artifacts.d.ts +0 -40
  226. package/dist/workflows/artifacts.js +0 -155
  227. package/dist/workflows/artifacts.js.map +0 -1
  228. package/dist/workflows/migrate-sources.d.ts +0 -42
  229. package/dist/workflows/migrate-sources.js +0 -133
  230. package/dist/workflows/migrate-sources.js.map +0 -1
  231. package/docs/run-bundles.md +0 -481
  232. package/src/workflows/artifacts.ts +0 -188
  233. package/src/workflows/migrate-sources.ts +0 -178
@@ -1,3 +1,5 @@
1
+ import { createHash } from "node:crypto";
2
+ import type { AssistantMessage } from "@earendil-works/pi-ai";
1
3
  import type {
2
4
  AgentStepExecutor,
3
5
  AgentStepRequest,
@@ -27,6 +29,7 @@ export type PromptDelivery = {
27
29
  */
28
30
  export type ConversationHooks = {
29
31
  beginAttempt?: (contract: AgentStepRequest["contract"]) => void;
32
+ recoverAssistant?: (contract: AgentStepRequest["contract"]) => AgentStepSubmission | undefined;
30
33
  mark: () => number;
31
34
  rangeSince: (mark: number) => ConversationRange | undefined;
32
35
  };
@@ -49,6 +52,8 @@ type PendingStep = {
49
52
  nudgesSent: number;
50
53
  /** Conversation mark taken when the prompt was first delivered. */
51
54
  mark: number | null;
55
+ /** Latest finalized assistant message observed for this attempt. */
56
+ assistantMessage?: AssistantMessage;
52
57
  cleanup: () => void;
53
58
  /** Resolves when this step stops being the pending step. */
54
59
  cleared: Promise<void>;
@@ -65,6 +70,7 @@ const DEFAULT_MAX_NUDGES = 2;
65
70
  * bounded number of times before failing the step.
66
71
  */
67
72
  export class ConversationStepExecutor implements AgentStepExecutor {
73
+ readonly assistantMessageMode = "visible" as const;
68
74
  private readonly sendPrompt: (delivery: PromptDelivery) => void;
69
75
  private readonly maxNudges: number;
70
76
  private readonly conversation: ConversationHooks | undefined;
@@ -89,6 +95,10 @@ export class ConversationStepExecutor implements AgentStepExecutor {
89
95
  return this.pending?.request.contract.nodeId ?? null;
90
96
  }
91
97
 
98
+ get pendingCompletion(): "submit" | "assistant" | null {
99
+ return this.pending === null ? null : completionKind(this.pending.request);
100
+ }
101
+
92
102
  /**
93
103
  * Hold the pending step for the user: no nudges are sent while held, so an
94
104
  * escape-interrupted conversation stays quiet until the user resumes.
@@ -127,6 +137,12 @@ export class ConversationStepExecutor implements AgentStepExecutor {
127
137
  if (this.pending) {
128
138
  throw new Error("Another workflow step is already awaiting output");
129
139
  }
140
+ if (completionKind(request) === "assistant") {
141
+ const recovered = this.conversation?.recoverAssistant?.(request.contract);
142
+ if (recovered !== undefined) {
143
+ return recovered;
144
+ }
145
+ }
130
146
  return await new Promise<AgentStepSubmission>((resolve, reject) => {
131
147
  const onAbort = () => {
132
148
  const reason: unknown = signal.reason ?? new Error("Workflow step aborted");
@@ -199,6 +215,13 @@ export class ConversationStepExecutor implements AgentStepExecutor {
199
215
  )}; the pending attempt is ${JSON.stringify(expectedAttempt)}. Use the attempt id from the latest step contract.`,
200
216
  };
201
217
  }
218
+ if (completionKind(pending.request) === "assistant") {
219
+ return {
220
+ accepted: false,
221
+ message:
222
+ "This step completes with a normal assistant response. Do not submit workflow output.",
223
+ };
224
+ }
202
225
  // Race validation against the step being cleared: a hung `validate`
203
226
  // callback must not leave this tool call (and therefore pi) blocked after
204
227
  // a timeout or cancel already resolved the run.
@@ -230,17 +253,26 @@ export class ConversationStepExecutor implements AgentStepExecutor {
230
253
  });
231
254
  return {
232
255
  accepted: true,
233
- message: [
234
- `Output accepted for step ${JSON.stringify(stepId)}.`,
235
- "If the workflow continues, the next step arrives as a new workflow message. End your turn now.",
236
- ].join(" "),
256
+ message: `Output accepted for step ${JSON.stringify(stepId)}.`,
237
257
  };
238
258
  }
239
259
 
260
+ /** Keep the latest finalized assistant message for an assistant-output step. */
261
+ handleMessageEnd(message: unknown): void {
262
+ const pending = this.pending;
263
+ if (pending === null || completionKind(pending.request) !== "assistant") {
264
+ return;
265
+ }
266
+ const assistant = assistantMessageLike(message);
267
+ if (assistant !== undefined) {
268
+ pending.assistantMessage = assistant as AssistantMessage;
269
+ }
270
+ }
271
+
240
272
  /**
241
273
  * Called when the agent settles. Returns true when a nudge was sent, false
242
- * when there was nothing to do. Fails the pending step once the nudge
243
- * budget is exhausted.
274
+ * when there was nothing to do. Submitted steps use bounded nudges;
275
+ * assistant-output steps accept or fail the one visible response.
244
276
  */
245
277
  handleAgentSettled(): boolean {
246
278
  const pending = this.pending;
@@ -252,6 +284,33 @@ export class ConversationStepExecutor implements AgentStepExecutor {
252
284
  // steal the conversation back. The step waits for an explicit resume.
253
285
  return false;
254
286
  }
287
+ if (completionKind(pending.request) === "assistant") {
288
+ try {
289
+ const output = visibleAssistantText(
290
+ pending.assistantMessage,
291
+ pending.request.contract.maxOutputChars,
292
+ );
293
+ const conversation =
294
+ pending.mark !== null ? this.conversation?.rangeSince(pending.mark) : undefined;
295
+ const assistantMessage = {
296
+ sha256: createHash("sha256").update(output).digest("hex"),
297
+ ...(conversation?.lastEntryId !== undefined ? { entryId: conversation.lastEntryId } : {}),
298
+ ...(pending.request.contract.maxOutputChars !== undefined
299
+ ? { maxChars: pending.request.contract.maxOutputChars }
300
+ : {}),
301
+ };
302
+ this.clearPending();
303
+ pending.resolve({
304
+ output,
305
+ assistantMessage,
306
+ ...(conversation !== undefined ? { conversation } : {}),
307
+ });
308
+ } catch (error) {
309
+ this.clearPending();
310
+ pending.reject(error);
311
+ }
312
+ return false;
313
+ }
255
314
  if (pending.nudgesSent >= this.maxNudges) {
256
315
  this.clearPending();
257
316
  pending.reject(
@@ -309,3 +368,44 @@ export class ConversationStepExecutor implements AgentStepExecutor {
309
368
  this.pending = null;
310
369
  }
311
370
  }
371
+
372
+ function completionKind(request: AgentStepRequest): "submit" | "assistant" {
373
+ return request.contract.completion;
374
+ }
375
+
376
+ function assistantMessageLike(
377
+ message: unknown,
378
+ ): Pick<AssistantMessage, "role" | "content" | "stopReason" | "errorMessage"> | undefined {
379
+ if (message === null || typeof message !== "object") return undefined;
380
+ const candidate = message as Partial<AssistantMessage>;
381
+ if (candidate.role !== "assistant" || !Array.isArray(candidate.content)) return undefined;
382
+ if (typeof candidate.stopReason !== "string") return undefined;
383
+ return candidate as Pick<AssistantMessage, "role" | "content" | "stopReason" | "errorMessage">;
384
+ }
385
+
386
+ /** Extract the exact visible text blocks from one finalized assistant message. */
387
+ export function visibleAssistantText(message: unknown, maxChars?: number): string {
388
+ const assistant = assistantMessageLike(message);
389
+ if (assistant === undefined) {
390
+ throw new Error("Assistant step settled without a final assistant message");
391
+ }
392
+ if (assistant.stopReason !== "stop" && assistant.stopReason !== "length") {
393
+ throw new Error(
394
+ assistant.errorMessage?.trim() ||
395
+ `Assistant step stopped with ${JSON.stringify(assistant.stopReason)} before a final response`,
396
+ );
397
+ }
398
+ const text = assistant.content
399
+ .filter((part) => part.type === "text")
400
+ .map((part) => part.text)
401
+ .join("\n");
402
+ if (text.trim().length === 0) {
403
+ throw new Error("Assistant step returned no visible text");
404
+ }
405
+ if (maxChars !== undefined && text.length > maxChars) {
406
+ throw new Error(
407
+ `Assistant response has ${text.length} characters, above the configured limit of ${maxChars}`,
408
+ );
409
+ }
410
+ return text;
411
+ }
@@ -14,7 +14,6 @@ export type ViewerPlacement = (typeof VIEWER_PLACEMENTS)[number];
14
14
  export type WorkflowViewTarget = {
15
15
  runId: string;
16
16
  workflowName: string;
17
- runDir: string;
18
17
  };
19
18
 
20
19
  export type HerdrCapability = { available: true } | { available: false; reason: string };
@@ -178,8 +177,6 @@ export class HerdrWorkflowViewer {
178
177
  HERDR_PLUGIN_ENTRYPOINT,
179
178
  "--env",
180
179
  `PI_WORKFLOWS_RUN_ID=${target.runId}`,
181
- "--env",
182
- `PI_WORKFLOWS_RUN_DIR=${target.runDir}`,
183
180
  "--focus",
184
181
  ];
185
182
  if (placement === "tab") {
@@ -229,8 +226,6 @@ export class HerdrWorkflowViewer {
229
226
  created.workspaceId,
230
227
  "--env",
231
228
  `PI_WORKFLOWS_RUN_ID=${target.runId}`,
232
- "--env",
233
- `PI_WORKFLOWS_RUN_DIR=${target.runDir}`,
234
229
  "--focus",
235
230
  ]),
236
231
  );