@osolmaz/pi-workflows 0.16.2 → 0.16.4

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 (315) hide show
  1. package/README.md +41 -41
  2. package/dist/builtins/monitor.workflow.d.ts +1 -1
  3. package/dist/builtins/monitor.workflow.js +8 -8
  4. package/dist/builtins/pi-agent-group.js +3 -3
  5. package/dist/builtins/pi-agent-group.js.map +1 -1
  6. package/dist/channels/adapter-entry.js +14 -14
  7. package/dist/channels/adapter-entry.js.map +1 -1
  8. package/dist/client/client.d.ts +6 -6
  9. package/dist/client/client.js +27 -27
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/protocol.d.ts +4 -1
  12. package/dist/client/protocol.js +17 -11
  13. package/dist/client/protocol.js.map +1 -1
  14. package/dist/client/resolver.d.ts +4 -4
  15. package/dist/client/view.d.ts +1 -1
  16. package/dist/extension/index.d.ts +1 -1
  17. package/dist/extension/index.js +32 -32
  18. package/dist/extension/index.js.map +1 -1
  19. package/dist/extension/recorder.d.ts +1 -1
  20. package/dist/extension/recorder.js +1 -1
  21. package/dist/extension/recorder.js.map +1 -1
  22. package/dist/extension/remote-recorder-store.d.ts +1 -1
  23. package/dist/extension/remote-recorder-store.js +2 -2
  24. package/dist/extension/remote-recorder-store.js.map +1 -1
  25. package/dist/extension/{controller-command.d.ts → resource-manager-command.d.ts} +6 -6
  26. package/dist/extension/{controller-command.js → resource-manager-command.js} +7 -7
  27. package/dist/extension/resource-manager-command.js.map +1 -0
  28. package/dist/extension/session-delivery.d.ts +1 -1
  29. package/dist/extension/session-delivery.js +2 -2
  30. package/dist/extension/session-delivery.js.map +1 -1
  31. package/dist/extension/session-view.d.ts +1 -1
  32. package/dist/extension/session-view.js +1 -1
  33. package/dist/extension/session-view.js.map +1 -1
  34. package/dist/extension/workflow-message-coordinator.d.ts +1 -1
  35. package/dist/extension/workflow-message-coordinator.js +6 -6
  36. package/dist/extension/workflow-message-coordinator.js.map +1 -1
  37. package/dist/resource-managers/conditions.d.ts +6 -0
  38. package/dist/{controllers → resource-managers}/conditions.js +3 -3
  39. package/dist/resource-managers/conditions.js.map +1 -0
  40. package/dist/resource-managers/definition.d.ts +6 -0
  41. package/dist/resource-managers/definition.js +45 -0
  42. package/dist/resource-managers/definition.js.map +1 -0
  43. package/dist/resource-managers/effects.d.ts +15 -0
  44. package/dist/{controllers → resource-managers}/effects.js +2 -2
  45. package/dist/resource-managers/effects.js.map +1 -0
  46. package/dist/resource-managers/errors.d.ts +12 -0
  47. package/dist/resource-managers/errors.js +25 -0
  48. package/dist/resource-managers/errors.js.map +1 -0
  49. package/dist/resource-managers/index.d.ts +12 -0
  50. package/dist/resource-managers/index.js +12 -0
  51. package/dist/resource-managers/index.js.map +1 -0
  52. package/dist/resource-managers/json.js.map +1 -0
  53. package/dist/resource-managers/loader.d.ts +23 -0
  54. package/dist/resource-managers/loader.js +75 -0
  55. package/dist/resource-managers/loader.js.map +1 -0
  56. package/dist/resource-managers/results.d.ts +5 -0
  57. package/dist/resource-managers/results.js.map +1 -0
  58. package/dist/resource-managers/runtime.d.ts +59 -0
  59. package/dist/{controllers/manager.js → resource-managers/runtime.js} +57 -57
  60. package/dist/resource-managers/runtime.js.map +1 -0
  61. package/dist/{controllers → resource-managers}/sqlite.d.ts +44 -44
  62. package/dist/{controllers → resource-managers}/sqlite.js +139 -130
  63. package/dist/resource-managers/sqlite.js.map +1 -0
  64. package/dist/{controllers → resource-managers}/store.d.ts +33 -33
  65. package/dist/{controllers → resource-managers}/store.js.map +1 -1
  66. package/dist/{controllers → resource-managers}/types.d.ts +41 -41
  67. package/dist/{controllers → resource-managers}/types.js.map +1 -1
  68. package/dist/resource-managers/workflows.d.ts +34 -0
  69. package/dist/{controllers → resource-managers}/workflows.js +15 -15
  70. package/dist/resource-managers/workflows.js.map +1 -0
  71. package/dist/server/channel-effects.js.map +1 -0
  72. package/dist/{host → server}/channel-supervisor.d.ts +6 -6
  73. package/dist/{host → server}/channel-supervisor.js +3 -3
  74. package/dist/server/channel-supervisor.js.map +1 -0
  75. package/dist/{host/child-worker-supervisor.d.ts → server/child-runner-supervisor.d.ts} +15 -13
  76. package/dist/{host/child-worker-supervisor.js → server/child-runner-supervisor.js} +6 -5
  77. package/dist/server/child-runner-supervisor.js.map +1 -0
  78. package/dist/{host → server}/processes.d.ts +3 -3
  79. package/dist/{host → server}/processes.js +3 -3
  80. package/dist/server/processes.js.map +1 -0
  81. package/dist/{host → server}/resolver-entry.d.ts +6 -6
  82. package/dist/{host → server}/resolver-entry.js +14 -14
  83. package/dist/server/resolver-entry.js.map +1 -0
  84. package/dist/server/resource-runner-entry.d.ts +2 -0
  85. package/dist/{host/controller-worker-entry.js → server/resource-runner-entry.js} +33 -33
  86. package/dist/server/resource-runner-entry.js.map +1 -0
  87. package/dist/server/resource-runner-protocol.d.ts +36 -0
  88. package/dist/server/resource-runner-protocol.js +49 -0
  89. package/dist/server/resource-runner-protocol.js.map +1 -0
  90. package/dist/server/resource-runner-supervisor.d.ts +21 -0
  91. package/dist/{host/worker-supervisor.js → server/resource-runner-supervisor.js} +17 -17
  92. package/dist/server/resource-runner-supervisor.js.map +1 -0
  93. package/dist/{host → server}/rpc-bridge.d.ts +3 -3
  94. package/dist/{host → server}/rpc-bridge.js +3 -3
  95. package/dist/server/rpc-bridge.js.map +1 -0
  96. package/dist/{host → server}/rpc-executor.d.ts +1 -1
  97. package/dist/{host → server}/rpc-executor.js +3 -3
  98. package/dist/server/rpc-executor.js.map +1 -0
  99. package/dist/{host/host-entry.js → server/server-entry.js} +6 -6
  100. package/dist/server/server-entry.js.map +1 -0
  101. package/dist/{host/runner.d.ts → server/server.d.ts} +39 -38
  102. package/dist/{host/runner.js → server/server.js} +408 -374
  103. package/dist/server/server.js.map +1 -0
  104. package/dist/{host → server}/state.d.ts +25 -25
  105. package/dist/{host → server}/state.js +49 -49
  106. package/dist/server/state.js.map +1 -0
  107. package/dist/{host → server}/view.d.ts +7 -7
  108. package/dist/{host → server}/view.js +13 -13
  109. package/dist/server/view.js.map +1 -0
  110. package/dist/server/workflow-runner-content.d.ts +6 -0
  111. package/dist/server/workflow-runner-content.js +96 -0
  112. package/dist/server/workflow-runner-content.js.map +1 -0
  113. package/dist/{host/worker-entry.d.ts → server/workflow-runner-entry.d.ts} +3 -3
  114. package/dist/{host/worker-entry.js → server/workflow-runner-entry.js} +68 -35
  115. package/dist/server/workflow-runner-entry.js.map +1 -0
  116. package/dist/server/workflow-runner-protocol.d.ts +69 -0
  117. package/dist/server/workflow-runner-protocol.js +176 -0
  118. package/dist/server/workflow-runner-protocol.js.map +1 -0
  119. package/dist/{host/worker-store.d.ts → server/workflow-runner-store.d.ts} +11 -11
  120. package/dist/{host/worker-store.js → server/workflow-runner-store.js} +8 -8
  121. package/dist/server/workflow-runner-store.js.map +1 -0
  122. package/dist/server/workflow-runner-supervisor.d.ts +22 -0
  123. package/dist/server/workflow-runner-supervisor.js +56 -0
  124. package/dist/server/workflow-runner-supervisor.js.map +1 -0
  125. package/dist/state/prune.d.ts +1 -1
  126. package/dist/state/prune.js +17 -10
  127. package/dist/state/prune.js.map +1 -1
  128. package/dist/state/schema.js +2 -2
  129. package/dist/state/workflow-messages.d.ts +1 -1
  130. package/dist/state/workflow-messages.js +1 -1
  131. package/dist/state/workflow-messages.js.map +1 -1
  132. package/dist/viewer/backup.js +1 -1
  133. package/dist/viewer/backup.js.map +1 -1
  134. package/dist/viewer/cli.d.ts +2 -2
  135. package/dist/viewer/cli.js +46 -32
  136. package/dist/viewer/cli.js.map +1 -1
  137. package/dist/viewer/tui.d.ts +1 -1
  138. package/dist/viewer/tui.js +1 -1
  139. package/dist/viewer/tui.js.map +1 -1
  140. package/dist/workflows/command-batch.js +2 -2
  141. package/dist/workflows/engine.js +14 -15
  142. package/dist/workflows/engine.js.map +1 -1
  143. package/dist/workflows/store.d.ts +12 -11
  144. package/dist/workflows/store.js +24 -18
  145. package/dist/workflows/store.js.map +1 -1
  146. package/dist/workflows/types.d.ts +2 -2
  147. package/docs/2026-08-20-durable-workflow-launch-plan.md +12 -12
  148. package/docs/2026-08-25-workflow-follow-ups.md +7 -7
  149. package/docs/2026-08-25-workflow-settings.md +3 -3
  150. package/docs/2026-08-30-out-of-process-workflow-host-plan.md +3 -3
  151. package/docs/2026-09-01-restore-session-delivery-controls-plan.md +5 -5
  152. package/docs/2026-09-01-unified-workflow-client-plan.md +6 -6
  153. package/docs/2026-09-02-installed-live-e2e-plan.md +3 -3
  154. package/docs/2026-09-02-unify-workflow-messages-plan.md +8 -8
  155. package/docs/2026-09-04-workflow-run-state-plan.md +6 -6
  156. package/docs/DEFERRED_TURNS.md +7 -7
  157. package/docs/DESIGN_PHILOSOPHY.md +1 -1
  158. package/docs/HUMAN_DECISIONS.md +11 -11
  159. package/docs/HUMAN_DECISION_PRESENTATIONS.md +4 -4
  160. package/docs/MONITOR.md +1 -1
  161. package/docs/RESOURCE_MANAGERS.md +221 -0
  162. package/docs/SQLITE_STATE.md +35 -33
  163. package/docs/WORKFLOW_COMPOSITION.md +1 -1
  164. package/docs/{WORKFLOW_HOST.md → WORKFLOW_SERVER.md} +125 -119
  165. package/docs/WORKFLOW_STEP_MESSAGES.md +18 -18
  166. package/docs/WORKFLOW_UPDATES.md +16 -16
  167. package/docs/development.md +15 -14
  168. package/docs/live-replay-protocol.md +20 -20
  169. package/docs/plans/2026-08-04-controller-runtime-plan.md +25 -25
  170. package/docs/plans/2026-08-05-always-on-workflows-plan.md +8 -8
  171. package/docs/plans/2026-08-10-agent-managed-monitor-workflows-plan.md +2 -2
  172. package/docs/plans/2026-08-13-session-addressed-workflow-notifications-plan.md +1 -1
  173. package/docs/plans/2026-08-16-workflow-updates-plan.md +5 -5
  174. package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
  175. package/docs/plans/2026-08-20-bounded-command-batches-plan.md +1 -1
  176. package/docs/plans/2026-08-21-deferred-turn-intents-plan.md +3 -3
  177. package/docs/plans/2026-08-21-sanity-check-plan.md +2 -2
  178. package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +5 -5
  179. package/docs/plans/2026-08-23-sqlite-state-plan.md +25 -25
  180. package/docs/plans/2026-08-25-live-workflow-settings-plan.md +4 -4
  181. package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +3 -3
  182. package/docs/plans/2026-09-04-workflow-runner-resume-state-plan.md +318 -0
  183. package/docs/plans/piw-viewer-experience-implementation-plan.md +1 -1
  184. package/docs/tui-viewer.md +9 -9
  185. package/docs/workflows.md +72 -66
  186. package/examples/{controllers/pull-request.controller.ts → resource-managers/pull-request.resource-manager.ts} +12 -12
  187. package/herdr-plugin.toml +1 -1
  188. package/package.json +12 -11
  189. package/protocol/client.v1.schema.json +7 -7
  190. package/protocol/fixtures/client-v1.json +1 -1
  191. package/src/builtins/monitor.workflow.ts +9 -9
  192. package/src/builtins/pi-agent-group.ts +3 -3
  193. package/src/channels/adapter-entry.ts +14 -14
  194. package/src/client/client.ts +33 -32
  195. package/src/client/protocol.ts +16 -11
  196. package/src/client/resolver.ts +4 -4
  197. package/src/client/view.ts +1 -1
  198. package/src/extension/index.ts +44 -34
  199. package/src/extension/recorder.ts +1 -1
  200. package/src/extension/remote-recorder-store.ts +2 -2
  201. package/src/extension/resource-manager-command.ts +45 -0
  202. package/src/extension/session-delivery.ts +2 -2
  203. package/src/extension/session-view.ts +1 -1
  204. package/src/extension/workflow-message-coordinator.ts +6 -6
  205. package/src/{controllers → resource-managers}/conditions.ts +23 -23
  206. package/src/resource-managers/definition.ts +71 -0
  207. package/src/{controllers → resource-managers}/effects.ts +9 -9
  208. package/src/resource-managers/errors.ts +27 -0
  209. package/src/resource-managers/index.ts +88 -0
  210. package/src/resource-managers/loader.ts +111 -0
  211. package/src/{controllers → resource-managers}/results.ts +4 -4
  212. package/src/{controllers/manager.ts → resource-managers/runtime.ts} +95 -92
  213. package/src/{controllers → resource-managers}/sqlite.ts +198 -186
  214. package/src/{controllers → resource-managers}/store.ts +46 -38
  215. package/src/{controllers → resource-managers}/types.ts +50 -41
  216. package/src/{controllers → resource-managers}/workflows.ts +43 -41
  217. package/src/{host → server}/channel-supervisor.ts +8 -8
  218. package/src/{host/child-worker-supervisor.ts → server/child-runner-supervisor.ts} +22 -18
  219. package/src/{host → server}/processes.ts +3 -3
  220. package/src/{host → server}/resolver-entry.ts +28 -25
  221. package/src/{host/controller-worker-entry.ts → server/resource-runner-entry.ts} +67 -65
  222. package/src/server/resource-runner-protocol.ts +103 -0
  223. package/src/server/resource-runner-supervisor.ts +76 -0
  224. package/src/{host → server}/rpc-bridge.ts +3 -3
  225. package/src/{host → server}/rpc-executor.ts +4 -4
  226. package/src/{host/host-entry.ts → server/server-entry.ts} +5 -5
  227. package/src/{host/runner.ts → server/server.ts} +526 -461
  228. package/src/{host → server}/state.ts +78 -67
  229. package/src/{host → server}/view.ts +15 -15
  230. package/src/server/workflow-runner-content.ts +119 -0
  231. package/src/{host/worker-entry.ts → server/workflow-runner-entry.ts} +98 -57
  232. package/src/server/workflow-runner-protocol.ts +241 -0
  233. package/src/{host/worker-store.ts → server/workflow-runner-store.ts} +18 -20
  234. package/src/server/workflow-runner-supervisor.ts +79 -0
  235. package/src/state/prune.ts +27 -9
  236. package/src/state/schema.ts +2 -2
  237. package/src/state/workflow-messages.ts +1 -1
  238. package/src/viewer/backup.ts +1 -1
  239. package/src/viewer/cli.ts +50 -36
  240. package/src/viewer/tui.ts +1 -1
  241. package/src/workflows/command-batch.ts +2 -2
  242. package/src/workflows/engine.ts +14 -15
  243. package/src/workflows/store.ts +31 -28
  244. package/src/workflows/types.ts +2 -2
  245. package/dist/controllers/conditions.d.ts +0 -6
  246. package/dist/controllers/conditions.js.map +0 -1
  247. package/dist/controllers/definition.d.ts +0 -6
  248. package/dist/controllers/definition.js +0 -45
  249. package/dist/controllers/definition.js.map +0 -1
  250. package/dist/controllers/effects.d.ts +0 -15
  251. package/dist/controllers/effects.js.map +0 -1
  252. package/dist/controllers/errors.d.ts +0 -12
  253. package/dist/controllers/errors.js +0 -25
  254. package/dist/controllers/errors.js.map +0 -1
  255. package/dist/controllers/index.d.ts +0 -12
  256. package/dist/controllers/index.js +0 -12
  257. package/dist/controllers/index.js.map +0 -1
  258. package/dist/controllers/json.js.map +0 -1
  259. package/dist/controllers/loader.d.ts +0 -23
  260. package/dist/controllers/loader.js +0 -74
  261. package/dist/controllers/loader.js.map +0 -1
  262. package/dist/controllers/manager.d.ts +0 -59
  263. package/dist/controllers/manager.js.map +0 -1
  264. package/dist/controllers/results.d.ts +0 -5
  265. package/dist/controllers/results.js.map +0 -1
  266. package/dist/controllers/sqlite.js.map +0 -1
  267. package/dist/controllers/workflows.d.ts +0 -34
  268. package/dist/controllers/workflows.js.map +0 -1
  269. package/dist/extension/controller-command.js.map +0 -1
  270. package/dist/host/channel-effects.js.map +0 -1
  271. package/dist/host/channel-supervisor.js.map +0 -1
  272. package/dist/host/child-worker-supervisor.js.map +0 -1
  273. package/dist/host/controller-worker-entry.d.ts +0 -2
  274. package/dist/host/controller-worker-entry.js.map +0 -1
  275. package/dist/host/controller-worker-protocol.d.ts +0 -36
  276. package/dist/host/controller-worker-protocol.js +0 -49
  277. package/dist/host/controller-worker-protocol.js.map +0 -1
  278. package/dist/host/controller-worker-supervisor.d.ts +0 -21
  279. package/dist/host/controller-worker-supervisor.js +0 -54
  280. package/dist/host/controller-worker-supervisor.js.map +0 -1
  281. package/dist/host/host-entry.js.map +0 -1
  282. package/dist/host/processes.js.map +0 -1
  283. package/dist/host/resolver-entry.js.map +0 -1
  284. package/dist/host/rpc-bridge.js.map +0 -1
  285. package/dist/host/rpc-executor.js.map +0 -1
  286. package/dist/host/runner.js.map +0 -1
  287. package/dist/host/state.js.map +0 -1
  288. package/dist/host/view.js.map +0 -1
  289. package/dist/host/worker-entry.js.map +0 -1
  290. package/dist/host/worker-protocol.d.ts +0 -46
  291. package/dist/host/worker-protocol.js +0 -122
  292. package/dist/host/worker-protocol.js.map +0 -1
  293. package/dist/host/worker-store.js.map +0 -1
  294. package/dist/host/worker-supervisor.d.ts +0 -22
  295. package/dist/host/worker-supervisor.js.map +0 -1
  296. package/docs/CONTROLLERS.md +0 -217
  297. package/src/controllers/definition.ts +0 -65
  298. package/src/controllers/errors.ts +0 -27
  299. package/src/controllers/index.ts +0 -88
  300. package/src/controllers/loader.ts +0 -104
  301. package/src/extension/controller-command.ts +0 -45
  302. package/src/host/controller-worker-protocol.ts +0 -104
  303. package/src/host/controller-worker-supervisor.ts +0 -79
  304. package/src/host/worker-protocol.ts +0 -176
  305. package/src/host/worker-supervisor.ts +0 -74
  306. /package/dist/{controllers → resource-managers}/json.d.ts +0 -0
  307. /package/dist/{controllers → resource-managers}/json.js +0 -0
  308. /package/dist/{controllers → resource-managers}/results.js +0 -0
  309. /package/dist/{controllers → resource-managers}/store.js +0 -0
  310. /package/dist/{controllers → resource-managers}/types.js +0 -0
  311. /package/dist/{host → server}/channel-effects.d.ts +0 -0
  312. /package/dist/{host → server}/channel-effects.js +0 -0
  313. /package/dist/{host/host-entry.d.ts → server/server-entry.d.ts} +0 -0
  314. /package/src/{controllers → resource-managers}/json.ts +0 -0
  315. /package/src/{host → server}/channel-effects.ts +0 -0
@@ -25,21 +25,28 @@ import type {
25
25
  WorkflowSource,
26
26
  } from "../workflows/types.js";
27
27
  import { RpcStepExecutor } from "./rpc-executor.js";
28
- import type { WorkerLaunchEnvelope } from "./state.js";
28
+ import type { WorkflowRunnerLaunchEnvelope } from "./state.js";
29
+ import { materializeRunnerContent } from "./workflow-runner-content.js";
29
30
  import {
30
- encodeWorkerLine,
31
- parseWorkerResponse,
32
- type WorkerMessage,
33
- type WorkerResponse,
34
- type WorkerRunCommand,
35
- } from "./worker-protocol.js";
36
- import { HostBackedWorkflowStore, type WorkerStoreTransport } from "./worker-store.js";
31
+ MAX_WORKFLOW_RUNNER_PROTOCOL_MESSAGE_BYTES,
32
+ encodeRunnerLine,
33
+ isRunnerContentChunk,
34
+ isRunnerContentReference,
35
+ parseRunnerResponse,
36
+ type WorkflowRunnerMessage,
37
+ type WorkflowRunnerResponse,
38
+ type WorkflowRunnerCommand,
39
+ } from "./workflow-runner-protocol.js";
40
+ import {
41
+ ServerBackedWorkflowStore,
42
+ type WorkflowRunnerStoreTransport,
43
+ } from "./workflow-runner-store.js";
37
44
 
38
- const STARTUP_ENV = "PI_WORKFLOWS_WORKER_LAUNCH";
45
+ const STARTUP_ENV = "PI_WORKFLOWS_WORKFLOW_RUNNER_LAUNCH";
39
46
  const PRESENTATION_TIMEOUT_MS = 30_000;
40
47
 
41
- type WorkerBootstrap = {
42
- command: WorkerRunCommand;
48
+ type WorkflowRunnerBootstrap = {
49
+ command: WorkflowRunnerCommand;
43
50
  originSessionId: string | null;
44
51
  stateDirectory: string;
45
52
  piArgs?: string[];
@@ -52,21 +59,21 @@ type WorkerBootstrap = {
52
59
  };
53
60
  };
54
61
 
55
- class StdioWorkerTransport implements WorkerStoreTransport {
62
+ class StdioRunnerTransport implements WorkflowRunnerStoreTransport {
56
63
  private readonly pending = new Map<
57
64
  string,
58
- { resolve: (response: WorkerResponse) => void; reject: (error: Error) => void }
65
+ { resolve: (response: WorkflowRunnerResponse) => void; reject: (error: Error) => void }
59
66
  >();
60
67
  private buffered = Buffer.alloc(0);
61
68
 
62
- constructor(private readonly launch: WorkerLaunchEnvelope) {
69
+ constructor(private readonly launch: WorkflowRunnerLaunchEnvelope) {
63
70
  process.stdin.on("data", (chunk: Buffer) => this.onData(chunk));
64
71
  process.stdin.on("error", (error) => this.failAll(error));
65
72
  process.stdin.resume();
66
73
  }
67
74
 
68
- async request(options: Parameters<WorkerStoreTransport["request"]>[0]) {
69
- const message: WorkerMessage = {
75
+ async request(options: Parameters<WorkflowRunnerStoreTransport["request"]>[0]) {
76
+ const message: WorkflowRunnerMessage = {
70
77
  schema: "pi-workflows.worker-message.v1",
71
78
  launchSchema: this.launch.schema,
72
79
  messageId: options.messageId,
@@ -74,17 +81,17 @@ class StdioWorkerTransport implements WorkerStoreTransport {
74
81
  operation: options.operation,
75
82
  runId: this.launch.runId,
76
83
  generation: this.launch.generation,
77
- workerEpoch: this.launch.workerEpoch,
84
+ runnerEpoch: this.launch.runnerEpoch,
78
85
  expectedRevision: options.expectedRevision,
79
86
  ...(options.attemptId === undefined ? {} : { attemptId: options.attemptId }),
80
87
  payload: options.payload,
81
88
  };
82
- const response = await this.send(message);
89
+ const response = await this.sendResolved(message);
83
90
  if (response.outcome === "claimLost") {
84
91
  throw new ClaimLostError(this.launch.runId, "ownerChanged");
85
92
  }
86
93
  if (response.outcome === "rejected") {
87
- throw new Error(response.error ?? "Workflow worker message was rejected");
94
+ throw new Error(response.error ?? "Workflow runner message was rejected");
88
95
  }
89
96
  return {
90
97
  ...(response.result === undefined ? {} : { result: response.result }),
@@ -93,10 +100,10 @@ class StdioWorkerTransport implements WorkerStoreTransport {
93
100
  }
94
101
 
95
102
  async control(
96
- operation: "worker.ready" | "worker.exiting",
103
+ operation: "runner.ready" | "runner.exiting",
97
104
  payload: JsonValue,
98
- ): Promise<WorkerResponse> {
99
- return await this.send({
105
+ ): Promise<WorkflowRunnerResponse> {
106
+ return await this.sendResolved({
100
107
  schema: "pi-workflows.worker-message.v1",
101
108
  launchSchema: this.launch.schema,
102
109
  messageId: randomUUID(),
@@ -104,7 +111,7 @@ class StdioWorkerTransport implements WorkerStoreTransport {
104
111
  operation,
105
112
  runId: this.launch.runId,
106
113
  generation: this.launch.generation,
107
- workerEpoch: this.launch.workerEpoch,
114
+ runnerEpoch: this.launch.runnerEpoch,
108
115
  expectedRevision: 0,
109
116
  payload,
110
117
  });
@@ -114,21 +121,55 @@ class StdioWorkerTransport implements WorkerStoreTransport {
114
121
  process.stdin.pause();
115
122
  process.stdin.removeAllListeners("data");
116
123
  process.stdin.removeAllListeners("error");
117
- this.failAll(new Error("Workflow worker transport closed"));
124
+ this.failAll(new Error("Workflow runner transport closed"));
118
125
  }
119
126
 
120
- private async send(message: WorkerMessage): Promise<WorkerResponse> {
121
- const response = new Promise<WorkerResponse>((resolve, reject) => {
127
+ private async sendResolved(message: WorkflowRunnerMessage): Promise<WorkflowRunnerResponse> {
128
+ const response = await this.send(message);
129
+ if (!isRunnerContentReference(response.result)) return response;
130
+ const reference = response.result;
131
+ const expectedRevision = response.revision ?? message.expectedRevision;
132
+ return {
133
+ ...response,
134
+ result: await materializeRunnerContent(reference, async (offset) => {
135
+ const chunkResponse = await this.send({
136
+ schema: "pi-workflows.worker-message.v1",
137
+ launchSchema: this.launch.schema,
138
+ messageId: randomUUID(),
139
+ kind: "runner.progress",
140
+ operation: "content.read",
141
+ runId: this.launch.runId,
142
+ generation: this.launch.generation,
143
+ runnerEpoch: this.launch.runnerEpoch,
144
+ expectedRevision,
145
+ payload: { sha256: reference.sha256, offset },
146
+ });
147
+ if (chunkResponse.outcome === "claimLost") {
148
+ throw new ClaimLostError(this.launch.runId, "ownerChanged");
149
+ }
150
+ if (chunkResponse.outcome !== "accepted" || !isRunnerContentChunk(chunkResponse.result)) {
151
+ throw new Error(chunkResponse.error ?? "Workflow runner content read was rejected");
152
+ }
153
+ return chunkResponse.result;
154
+ }),
155
+ };
156
+ }
157
+
158
+ private async send(message: WorkflowRunnerMessage): Promise<WorkflowRunnerResponse> {
159
+ const response = new Promise<WorkflowRunnerResponse>((resolve, reject) => {
122
160
  this.pending.set(message.messageId, { resolve, reject });
123
161
  });
124
- if (!process.stdout.write(encodeWorkerLine(message))) await once(process.stdout, "drain");
162
+ if (!process.stdout.write(encodeRunnerLine(message))) await once(process.stdout, "drain");
125
163
  return await response;
126
164
  }
127
165
 
128
166
  private onData(chunk: Buffer): void {
129
167
  this.buffered = Buffer.concat([this.buffered, chunk]);
130
- if (this.buffered.byteLength > 1024 * 1024 && !this.buffered.includes(0x0a)) {
131
- this.failAll(new Error("Worker response exceeds 1 MiB"));
168
+ if (
169
+ this.buffered.byteLength > MAX_WORKFLOW_RUNNER_PROTOCOL_MESSAGE_BYTES &&
170
+ !this.buffered.includes(0x0a)
171
+ ) {
172
+ this.failAll(new Error("Runner response exceeds 1 MiB"));
132
173
  return;
133
174
  }
134
175
  for (;;) {
@@ -138,9 +179,9 @@ class StdioWorkerTransport implements WorkerStoreTransport {
138
179
  this.buffered = this.buffered.subarray(newline + 1);
139
180
  if (frame.byteLength === 0) continue;
140
181
  try {
141
- const response = parseWorkerResponse(frame);
182
+ const response = parseRunnerResponse(frame);
142
183
  const pending = this.pending.get(response.messageId);
143
- if (pending === undefined) throw new Error("Worker response has no pending request");
184
+ if (pending === undefined) throw new Error("Runner response has no pending request");
144
185
  this.pending.delete(response.messageId);
145
186
  pending.resolve(response);
146
187
  } catch (error) {
@@ -160,7 +201,7 @@ class InteractiveExecutor implements AgentStepExecutor {
160
201
  readonly preservesDeadlineWhileParked = true;
161
202
 
162
203
  constructor(
163
- private readonly store: HostBackedWorkflowStore,
204
+ private readonly store: ServerBackedWorkflowStore,
164
205
  private readonly candidate:
165
206
  | {
166
207
  requestId: string;
@@ -275,12 +316,12 @@ export function validateAcceptedAssistantSubmission(
275
316
  };
276
317
  }
277
318
 
278
- export async function executeWorkerRunCommand(
319
+ export async function executeRunnerRunCommand(
279
320
  engine: Pick<WorkflowEngine, "run" | "resumeRun" | "continueRun">,
280
321
  workflow: WorkflowDefinition,
281
322
  runId: string,
282
323
  workflowSource: WorkflowSource,
283
- command: WorkerRunCommand,
324
+ command: WorkflowRunnerCommand,
284
325
  ) {
285
326
  switch (command.kind) {
286
327
  case "start":
@@ -304,30 +345,30 @@ export async function executeWorkerRunCommand(
304
345
  }
305
346
  }
306
347
 
307
- export async function runWorkflowWorker(): Promise<number> {
348
+ export async function runWorkflowRunner(): Promise<number> {
308
349
  const launch = readLaunchEnvelope();
309
- const transport = new StdioWorkerTransport(launch);
350
+ const transport = new StdioRunnerTransport(launch);
310
351
  try {
311
- const ready = await transport.control("worker.ready", {});
352
+ const ready = await transport.control("runner.ready", {});
312
353
  if (ready.outcome !== "accepted" || ready.result === undefined) {
313
- throw new Error(ready.error ?? "Workflow host rejected worker startup");
354
+ throw new Error(ready.error ?? "Workflow server rejected runner startup");
314
355
  }
315
- const bootstrap = ready.result as unknown as WorkerBootstrap;
316
- const workflowSource = parseWorkerWorkflowSources(launch.workflowSource);
356
+ const bootstrap = ready.result as unknown as WorkflowRunnerBootstrap;
357
+ const workflowSource = parseRunnerWorkflowSources(launch.workflowSource);
317
358
  let workflow: WorkflowDefinition;
318
359
  try {
319
360
  workflow = await resolveVerifiedWorkflow(launch.runId, workflowSource);
320
361
  } catch (error) {
321
- const response = await transport.control("worker.exiting", {
362
+ const response = await transport.control("runner.exiting", {
322
363
  status: "workflowLoadFailed",
323
364
  error: errorMessage(error),
324
365
  });
325
366
  if (response.outcome !== "accepted") {
326
- throw new Error(response.error ?? "Workflow host rejected the load-failure report");
367
+ throw new Error(response.error ?? "Workflow server rejected the load-failure report");
327
368
  }
328
369
  return 1;
329
370
  }
330
- const store = new HostBackedWorkflowStore(launch.runId, transport, ready.revision ?? 0);
371
+ const store = new ServerBackedWorkflowStore(launch.runId, transport, ready.revision ?? 0);
331
372
  let executor: AgentStepExecutor;
332
373
  let closeExecutor: (() => Promise<void>) | undefined;
333
374
  if (bootstrap.originSessionId !== null) {
@@ -342,7 +383,7 @@ export async function runWorkflowWorker(): Promise<number> {
342
383
  await transport.request({
343
384
  messageId: randomUUID(),
344
385
  operation: "process.register",
345
- kind: "worker.progress",
386
+ kind: "runner.progress",
346
387
  expectedRevision: 0,
347
388
  payload: { pid },
348
389
  });
@@ -351,7 +392,7 @@ export async function runWorkflowWorker(): Promise<number> {
351
392
  await transport.request({
352
393
  messageId: randomUUID(),
353
394
  operation: "process.unregister",
354
- kind: "worker.progress",
395
+ kind: "runner.progress",
355
396
  expectedRevision: 0,
356
397
  payload: { pid },
357
398
  });
@@ -387,14 +428,14 @@ export async function runWorkflowWorker(): Promise<number> {
387
428
  },
388
429
  });
389
430
  try {
390
- const result = await executeWorkerRunCommand(
431
+ const result = await executeRunnerRunCommand(
391
432
  engine,
392
433
  workflow,
393
434
  launch.runId,
394
435
  workflowSource.root,
395
436
  bootstrap.command,
396
437
  );
397
- await transport.control("worker.exiting", {
438
+ await transport.control("runner.exiting", {
398
439
  status: result.state.status,
399
440
  traceSeq: result.state.traceSeq,
400
441
  });
@@ -444,25 +485,25 @@ async function resolvePresentationInstructions(
444
485
  }
445
486
  }
446
487
 
447
- type WorkerWorkflowSources = {
488
+ type WorkflowRunnerSources = {
448
489
  root: WorkflowSource;
449
490
  mounted: WorkflowMountedSource[];
450
491
  };
451
492
 
452
- function parseWorkerWorkflowSources(value: JsonValue): WorkerWorkflowSources {
493
+ function parseRunnerWorkflowSources(value: JsonValue): WorkflowRunnerSources {
453
494
  if (!isRecord(value) || !isWorkflowSource(value.root) || !Array.isArray(value.mounted)) {
454
- throw new Error("Workflow worker source identity is invalid");
495
+ throw new Error("Workflow runner source identity is invalid");
455
496
  }
456
497
  const mounted = value.mounted;
457
498
  if (!mounted.every(isMountedWorkflowSource)) {
458
- throw new Error("Workflow worker mounted source identity is invalid");
499
+ throw new Error("Workflow runner mounted source identity is invalid");
459
500
  }
460
501
  return { root: value.root, mounted };
461
502
  }
462
503
 
463
504
  async function resolveVerifiedWorkflow(
464
505
  runId: string,
465
- sources: WorkerWorkflowSources,
506
+ sources: WorkflowRunnerSources,
466
507
  ): Promise<WorkflowDefinition> {
467
508
  for (const source of [sources.root, ...sources.mounted.map((mounted) => mounted.source)]) {
468
509
  if (source.kind === "file") {
@@ -514,9 +555,9 @@ function isRecord(value: unknown): value is Record<string, unknown> {
514
555
  return typeof value === "object" && value !== null && !Array.isArray(value);
515
556
  }
516
557
 
517
- function readLaunchEnvelope(): WorkerLaunchEnvelope {
558
+ function readLaunchEnvelope(): WorkflowRunnerLaunchEnvelope {
518
559
  const encoded = process.env[STARTUP_ENV];
519
- if (encoded === undefined) throw new Error("Workflow worker launch envelope is missing");
560
+ if (encoded === undefined) throw new Error("Workflow runner launch envelope is missing");
520
561
  const value = parseJson(Buffer.from(encoded, "base64url").toString("utf8"));
521
562
  if (
522
563
  typeof value !== "object" ||
@@ -524,14 +565,14 @@ function readLaunchEnvelope(): WorkerLaunchEnvelope {
524
565
  Array.isArray(value) ||
525
566
  (value as { schema?: unknown }).schema !== "pi-workflows.worker-launch.v1"
526
567
  ) {
527
- throw new Error("Workflow worker launch envelope is invalid");
568
+ throw new Error("Workflow runner launch envelope is invalid");
528
569
  }
529
- return value as unknown as WorkerLaunchEnvelope;
570
+ return value as unknown as WorkflowRunnerLaunchEnvelope;
530
571
  }
531
572
 
532
573
  async function main(): Promise<void> {
533
574
  try {
534
- process.exitCode = await runWorkflowWorker();
575
+ process.exitCode = await runWorkflowRunner();
535
576
  } catch (error) {
536
577
  process.stderr.write(`${errorMessage(error)}\n`);
537
578
  process.exitCode = 1;
@@ -0,0 +1,241 @@
1
+ import { canonicalJson, parseJson, type JsonValue } from "../state/json.js";
2
+
3
+ export const MAX_WORKFLOW_RUNNER_PROTOCOL_MESSAGE_BYTES = 1024 * 1024;
4
+ export const WORKFLOW_RUNNER_CONTENT_CHUNK_BYTES = 512 * 1024;
5
+ export const WORKFLOW_RUNNER_MESSAGE_SCHEMA = "pi-workflows.worker-message.v1" as const;
6
+ export const WORKFLOW_RUNNER_RESPONSE_SCHEMA = "pi-workflows.worker-response.v1" as const;
7
+ export const WORKFLOW_RUNNER_CONTENT_REFERENCE_SCHEMA =
8
+ "pi-workflows.worker-content-reference.v1" as const;
9
+ export const WORKFLOW_RUNNER_CONTENT_CHUNK_SCHEMA = "pi-workflows.worker-content-chunk.v1" as const;
10
+
11
+ export type WorkflowRunnerCommand =
12
+ | { kind: "start"; input: JsonValue }
13
+ | { kind: "resume"; resumeInteractionAttemptId?: string }
14
+ | {
15
+ kind: "continue";
16
+ parentRunId: string;
17
+ input: JsonValue;
18
+ humanDecision?: JsonValue;
19
+ }
20
+ | { kind: "restart"; input: JsonValue };
21
+
22
+ export const WORKFLOW_RUNNER_MESSAGE_KINDS = [
23
+ "runner.ready",
24
+ "node.started",
25
+ "node.update",
26
+ "node.finished",
27
+ "node.failed",
28
+ "run.parked",
29
+ "run.finished",
30
+ "interaction.requested",
31
+ "interaction.accepted",
32
+ "interaction.rejected",
33
+ "notification.requested",
34
+ "presentation.requested",
35
+ "effect.reserve",
36
+ "effect.settle",
37
+ "runner.progress",
38
+ "runner.exiting",
39
+ ] as const;
40
+
41
+ export type WorkflowRunnerMessageKind = (typeof WORKFLOW_RUNNER_MESSAGE_KINDS)[number];
42
+ export const WORKFLOW_RUNNER_STORE_OPERATIONS = [
43
+ "store.initializeRun",
44
+ "store.prepareRunResume",
45
+ "store.readRunState",
46
+ "store.writeSnapshot",
47
+ "store.publishUpdate",
48
+ "store.findSettingsScope",
49
+ "store.ensureSettingsScope",
50
+ "store.getSettingsScopeAtChange",
51
+ "store.createHumanDecisionRequest",
52
+ "store.readResolvedHumanDecision",
53
+ "store.reserveEffect",
54
+ "store.settleEffect",
55
+ "content.read",
56
+ "process.register",
57
+ "process.unregister",
58
+ "interaction.request",
59
+ "interaction.accept",
60
+ "interaction.reject",
61
+ "notification.request",
62
+ "presentation.request",
63
+ ] as const;
64
+ export type WorkflowRunnerStoreOperation = (typeof WORKFLOW_RUNNER_STORE_OPERATIONS)[number];
65
+ const WORKFLOW_RUNNER_CONTROL_OPERATIONS = ["runner.ready", "runner.exiting"] as const;
66
+
67
+ export type WorkflowRunnerMessage = {
68
+ schema: typeof WORKFLOW_RUNNER_MESSAGE_SCHEMA;
69
+ launchSchema: "pi-workflows.worker-launch.v1";
70
+ messageId: string;
71
+ kind: WorkflowRunnerMessageKind;
72
+ operation: WorkflowRunnerStoreOperation | "runner.ready" | "runner.exiting";
73
+ runId: string;
74
+ generation: number;
75
+ runnerEpoch: string;
76
+ expectedRevision: number;
77
+ attemptId?: string;
78
+ payload: JsonValue;
79
+ };
80
+
81
+ export type WorkflowRunnerResponse = {
82
+ schema: typeof WORKFLOW_RUNNER_RESPONSE_SCHEMA;
83
+ messageId: string;
84
+ outcome: "accepted" | "adopted" | "rejected" | "claimLost";
85
+ revision?: number;
86
+ result?: JsonValue;
87
+ error?: string;
88
+ };
89
+
90
+ export type WorkflowRunnerContentReference = {
91
+ schema: typeof WORKFLOW_RUNNER_CONTENT_REFERENCE_SCHEMA;
92
+ sha256: string;
93
+ mediaType: "application/json";
94
+ bytes: number;
95
+ };
96
+
97
+ export type WorkflowRunnerContentChunk = {
98
+ schema: typeof WORKFLOW_RUNNER_CONTENT_CHUNK_SCHEMA;
99
+ sha256: string;
100
+ mediaType: "application/json";
101
+ bytes: number;
102
+ offset: number;
103
+ nextOffset: number;
104
+ complete: boolean;
105
+ data: string;
106
+ };
107
+
108
+ export function isRunnerContentReference(value: unknown): value is WorkflowRunnerContentReference {
109
+ return (
110
+ isRecord(value) &&
111
+ value.schema === WORKFLOW_RUNNER_CONTENT_REFERENCE_SCHEMA &&
112
+ typeof value.sha256 === "string" &&
113
+ /^[0-9a-f]{64}$/u.test(value.sha256) &&
114
+ value.mediaType === "application/json" &&
115
+ Number.isSafeInteger(value.bytes) &&
116
+ (value.bytes as number) >= 0
117
+ );
118
+ }
119
+
120
+ export function isRunnerContentChunk(value: unknown): value is WorkflowRunnerContentChunk {
121
+ return (
122
+ isRecord(value) &&
123
+ value.schema === WORKFLOW_RUNNER_CONTENT_CHUNK_SCHEMA &&
124
+ typeof value.sha256 === "string" &&
125
+ /^[0-9a-f]{64}$/u.test(value.sha256) &&
126
+ value.mediaType === "application/json" &&
127
+ Number.isSafeInteger(value.bytes) &&
128
+ (value.bytes as number) >= 0 &&
129
+ Number.isSafeInteger(value.offset) &&
130
+ (value.offset as number) >= 0 &&
131
+ Number.isSafeInteger(value.nextOffset) &&
132
+ (value.nextOffset as number) >= (value.offset as number) &&
133
+ typeof value.complete === "boolean" &&
134
+ typeof value.data === "string"
135
+ );
136
+ }
137
+
138
+ export function runnerKindForOperation(
139
+ operation: WorkflowRunnerStoreOperation,
140
+ payload: Record<string, unknown>,
141
+ ): WorkflowRunnerMessageKind {
142
+ if (operation === "store.publishUpdate") return "node.update";
143
+ if (operation === "store.reserveEffect") return "effect.reserve";
144
+ if (operation === "store.settleEffect") return "effect.settle";
145
+ if (operation === "store.createHumanDecisionRequest" || operation === "interaction.request") {
146
+ return "interaction.requested";
147
+ }
148
+ if (operation === "interaction.accept") return "interaction.accepted";
149
+ if (operation === "interaction.reject") return "interaction.rejected";
150
+ if (operation === "notification.request") return "notification.requested";
151
+ if (operation === "presentation.request") return "presentation.requested";
152
+ if (operation === "store.writeSnapshot") {
153
+ const event = payload.event;
154
+ const eventType = isRecord(event) && typeof event.type === "string" ? event.type : "";
155
+ if (eventType === "node_started") return "node.started";
156
+ if (eventType === "node_finished") return "node.finished";
157
+ if (eventType === "node_failed" || eventType === "node_timed_out") return "node.failed";
158
+ if (eventType === "run_waiting" || eventType.includes("park")) return "run.parked";
159
+ if (eventType.startsWith("run_") && eventType !== "run_started") return "run.finished";
160
+ }
161
+ return "runner.progress";
162
+ }
163
+
164
+ export function encodeRunnerLine(message: WorkflowRunnerMessage | WorkflowRunnerResponse): Buffer {
165
+ const encoded = Buffer.from(`${canonicalJson(message)}\n`, "utf8");
166
+ if (encoded.byteLength > MAX_WORKFLOW_RUNNER_PROTOCOL_MESSAGE_BYTES) {
167
+ throw new Error("Runner protocol message exceeds 1 MiB");
168
+ }
169
+ return encoded;
170
+ }
171
+
172
+ export function parseRunnerMessage(line: Buffer | string): WorkflowRunnerMessage {
173
+ const value = parseRunnerValue(line);
174
+ if (
175
+ value.schema !== WORKFLOW_RUNNER_MESSAGE_SCHEMA ||
176
+ value.launchSchema !== "pi-workflows.worker-launch.v1"
177
+ ) {
178
+ throw new Error("Invalid workflow runner message schema");
179
+ }
180
+ requireText(value.messageId, "messageId");
181
+ requireText(value.runId, "runId");
182
+ requireText(value.runnerEpoch, "runnerEpoch");
183
+ if (!WORKFLOW_RUNNER_MESSAGE_KINDS.includes(value.kind as WorkflowRunnerMessageKind)) {
184
+ throw new Error("Invalid workflow runner message kind");
185
+ }
186
+ if (!Number.isSafeInteger(value.generation) || (value.generation as number) <= 0) {
187
+ throw new Error("Runner generation must be positive");
188
+ }
189
+ if (!Number.isSafeInteger(value.expectedRevision) || (value.expectedRevision as number) < 0) {
190
+ throw new Error("Runner expectedRevision must be non-negative");
191
+ }
192
+ requireText(value.operation, "operation");
193
+ if (
194
+ !WORKFLOW_RUNNER_STORE_OPERATIONS.includes(value.operation as WorkflowRunnerStoreOperation) &&
195
+ !WORKFLOW_RUNNER_CONTROL_OPERATIONS.includes(
196
+ value.operation as (typeof WORKFLOW_RUNNER_CONTROL_OPERATIONS)[number],
197
+ )
198
+ ) {
199
+ throw new Error("Invalid workflow runner operation");
200
+ }
201
+ if (value.attemptId !== undefined) requireText(value.attemptId, "attemptId");
202
+ if (!Object.hasOwn(value, "payload")) throw new Error("Runner payload is required");
203
+ return value as WorkflowRunnerMessage;
204
+ }
205
+
206
+ export function parseRunnerResponse(line: Buffer | string): WorkflowRunnerResponse {
207
+ const value = parseRunnerValue(line);
208
+ if (value.schema !== WORKFLOW_RUNNER_RESPONSE_SCHEMA)
209
+ throw new Error("Invalid workflow runner response schema");
210
+ requireText(value.messageId, "messageId");
211
+ if (!["accepted", "adopted", "rejected", "claimLost"].includes(value.outcome as string)) {
212
+ throw new Error("Invalid workflow runner response outcome");
213
+ }
214
+ if (value.error !== undefined && typeof value.error !== "string") {
215
+ throw new Error("Runner response error must be text");
216
+ }
217
+ return value as WorkflowRunnerResponse;
218
+ }
219
+
220
+ function parseRunnerValue(line: Buffer | string): Record<string, unknown> {
221
+ const buffer = Buffer.isBuffer(line) ? line : Buffer.from(line, "utf8");
222
+ if (buffer.byteLength + 1 > MAX_WORKFLOW_RUNNER_PROTOCOL_MESSAGE_BYTES) {
223
+ throw new Error("Runner protocol message exceeds 1 MiB");
224
+ }
225
+ const text = buffer.toString("utf8");
226
+ const value = parseJson(text);
227
+ if (!isRecord(value) || canonicalJson(value) !== text) {
228
+ throw new Error("Runner protocol message must be a canonical JSON object");
229
+ }
230
+ return value;
231
+ }
232
+
233
+ function requireText(value: unknown, field: string): asserts value is string {
234
+ if (typeof value !== "string" || value.length === 0 || value.length > 256) {
235
+ throw new Error(`Runner ${field} must be nonempty bounded text`);
236
+ }
237
+ }
238
+
239
+ function isRecord(value: unknown): value is Record<string, unknown> {
240
+ return typeof value === "object" && value !== null && !Array.isArray(value);
241
+ }
@@ -4,8 +4,6 @@ import type { WorkflowSettingsScopeRecord } from "../workflows/settings.js";
4
4
  import {
5
5
  createDefinitionSnapshot,
6
6
  type InitializeWorkflowRunOptions,
7
- type LoadedWorkflowRun,
8
- type ReadWorkflowRunOptions,
9
7
  type WorkflowExecutionStore,
10
8
  } from "../workflows/store.js";
11
9
  import type {
@@ -22,28 +20,31 @@ import type {
22
20
  WorkflowUpdateInput,
23
21
  WorkflowUpdateRecord,
24
22
  } from "../workflows/types.js";
25
- import type { WorkerMessageKind, WorkerStoreOperation } from "./worker-protocol.js";
26
- import { workerKindForOperation } from "./worker-protocol.js";
23
+ import type {
24
+ WorkflowRunnerMessageKind,
25
+ WorkflowRunnerStoreOperation,
26
+ } from "./workflow-runner-protocol.js";
27
+ import { runnerKindForOperation } from "./workflow-runner-protocol.js";
27
28
 
28
- export interface WorkerStoreTransport {
29
+ export interface WorkflowRunnerStoreTransport {
29
30
  request(options: {
30
31
  messageId: string;
31
- operation: WorkerStoreOperation;
32
- kind: WorkerMessageKind;
32
+ operation: WorkflowRunnerStoreOperation;
33
+ kind: WorkflowRunnerMessageKind;
33
34
  expectedRevision: number;
34
35
  attemptId?: string;
35
36
  payload: JsonValue;
36
37
  }): Promise<{ result?: JsonValue; revision?: number }>;
37
38
  }
38
39
 
39
- /** A worker-side store that can only propose state changes to its host. */
40
- export class HostBackedWorkflowStore implements WorkflowExecutionStore {
41
- readonly databasePath = "host://pi-workflows-state";
40
+ /** A runner-side store that can only propose state changes to its server. */
41
+ export class ServerBackedWorkflowStore implements WorkflowExecutionStore {
42
+ readonly databasePath = "server://pi-workflows-state";
42
43
  private revision: number;
43
44
 
44
45
  constructor(
45
46
  private readonly runId: string,
46
- private readonly transport: WorkerStoreTransport,
47
+ private readonly transport: WorkflowRunnerStoreTransport,
47
48
  initialRevision = 0,
48
49
  ) {
49
50
  this.revision = initialRevision;
@@ -62,15 +63,12 @@ export class HostBackedWorkflowStore implements WorkflowExecutionStore {
62
63
  });
63
64
  }
64
65
 
65
- async prepareRunResume(runId: string): Promise<LoadedWorkflowRun> {
66
- return await this.call<LoadedWorkflowRun>("store.prepareRunResume", { runId });
66
+ async prepareRunResume(runId: string): Promise<WorkflowRunState> {
67
+ return await this.call<WorkflowRunState>("store.prepareRunResume", { runId });
67
68
  }
68
69
 
69
- async readRun(
70
- runId: string,
71
- options: ReadWorkflowRunOptions = {},
72
- ): Promise<LoadedWorkflowRun | null> {
73
- return await this.call<LoadedWorkflowRun | null>("store.readRun", { runId, options });
70
+ async readRunState(runId: string): Promise<WorkflowRunState | null> {
71
+ return await this.call<WorkflowRunState | null>("store.readRunState", { runId });
74
72
  }
75
73
 
76
74
  async writeSnapshot(
@@ -211,14 +209,14 @@ export class HostBackedWorkflowStore implements WorkflowExecutionStore {
211
209
  }
212
210
 
213
211
  private async call<T>(
214
- operation: WorkerStoreOperation,
212
+ operation: WorkflowRunnerStoreOperation,
215
213
  payload: Record<string, unknown>,
216
214
  attemptId?: string,
217
215
  ): Promise<T> {
218
216
  const response = await this.transport.request({
219
217
  messageId: randomUUID(),
220
218
  operation,
221
- kind: workerKindForOperation(operation, payload),
219
+ kind: runnerKindForOperation(operation, payload),
222
220
  expectedRevision: this.revision,
223
221
  ...(attemptId === undefined ? {} : { attemptId }),
224
222
  payload: payload as JsonValue,