@nodetool-ai/execution 0.8.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 (231) hide show
  1. package/README.md +129 -0
  2. package/dist/.nodetool-build-stamp +1 -0
  3. package/dist/app-debug/app-spec.d.ts +94 -0
  4. package/dist/app-debug/app-spec.d.ts.map +1 -0
  5. package/dist/app-debug/app-spec.js +710 -0
  6. package/dist/app-debug/app-spec.js.map +1 -0
  7. package/dist/app-debug/application-target.d.ts +53 -0
  8. package/dist/app-debug/application-target.d.ts.map +1 -0
  9. package/dist/app-debug/application-target.js +126 -0
  10. package/dist/app-debug/application-target.js.map +1 -0
  11. package/dist/app-debug/bundle-target.d.ts +21 -0
  12. package/dist/app-debug/bundle-target.d.ts.map +1 -0
  13. package/dist/app-debug/bundle-target.js +51 -0
  14. package/dist/app-debug/bundle-target.js.map +1 -0
  15. package/dist/app-debug/graph-shape.d.ts +14 -0
  16. package/dist/app-debug/graph-shape.d.ts.map +1 -0
  17. package/dist/app-debug/graph-shape.js +23 -0
  18. package/dist/app-debug/graph-shape.js.map +1 -0
  19. package/dist/app-debug/index.d.ts +26 -0
  20. package/dist/app-debug/index.d.ts.map +1 -0
  21. package/dist/app-debug/index.js +19 -0
  22. package/dist/app-debug/index.js.map +1 -0
  23. package/dist/app-debug/markdown.d.ts +6 -0
  24. package/dist/app-debug/markdown.d.ts.map +1 -0
  25. package/dist/app-debug/markdown.js +133 -0
  26. package/dist/app-debug/markdown.js.map +1 -0
  27. package/dist/app-debug/runtime.d.ts +267 -0
  28. package/dist/app-debug/runtime.d.ts.map +1 -0
  29. package/dist/app-debug/runtime.js +633 -0
  30. package/dist/app-debug/runtime.js.map +1 -0
  31. package/dist/app-debug/script-operation.d.ts +58 -0
  32. package/dist/app-debug/script-operation.d.ts.map +1 -0
  33. package/dist/app-debug/script-operation.js +44 -0
  34. package/dist/app-debug/script-operation.js.map +1 -0
  35. package/dist/app-debug/simulate.d.ts +85 -0
  36. package/dist/app-debug/simulate.d.ts.map +1 -0
  37. package/dist/app-debug/simulate.js +991 -0
  38. package/dist/app-debug/simulate.js.map +1 -0
  39. package/dist/app-debug/summarize.d.ts +64 -0
  40. package/dist/app-debug/summarize.d.ts.map +1 -0
  41. package/dist/app-debug/summarize.js +65 -0
  42. package/dist/app-debug/summarize.js.map +1 -0
  43. package/dist/app-debug/types.d.ts +343 -0
  44. package/dist/app-debug/types.d.ts.map +1 -0
  45. package/dist/app-debug/types.js +2 -0
  46. package/dist/app-debug/types.js.map +1 -0
  47. package/dist/cost-ledger.d.ts +147 -0
  48. package/dist/cost-ledger.d.ts.map +1 -0
  49. package/dist/cost-ledger.js +288 -0
  50. package/dist/cost-ledger.js.map +1 -0
  51. package/dist/debug/collector.d.ts +28 -0
  52. package/dist/debug/collector.d.ts.map +1 -0
  53. package/dist/debug/collector.js +284 -0
  54. package/dist/debug/collector.js.map +1 -0
  55. package/dist/debug/index.d.ts +15 -0
  56. package/dist/debug/index.d.ts.map +1 -0
  57. package/dist/debug/index.js +16 -0
  58. package/dist/debug/index.js.map +1 -0
  59. package/dist/debug/types.d.ts +179 -0
  60. package/dist/debug/types.d.ts.map +1 -0
  61. package/dist/debug/types.js +11 -0
  62. package/dist/debug/types.js.map +1 -0
  63. package/dist/debug/verdict.d.ts +27 -0
  64. package/dist/debug/verdict.d.ts.map +1 -0
  65. package/dist/debug/verdict.js +51 -0
  66. package/dist/debug/verdict.js.map +1 -0
  67. package/dist/executor-resolver.d.ts +13 -0
  68. package/dist/executor-resolver.d.ts.map +1 -0
  69. package/dist/executor-resolver.js +13 -0
  70. package/dist/executor-resolver.js.map +1 -0
  71. package/dist/fal-output-decoder.d.ts +36 -0
  72. package/dist/fal-output-decoder.d.ts.map +1 -0
  73. package/dist/fal-output-decoder.js +129 -0
  74. package/dist/fal-output-decoder.js.map +1 -0
  75. package/dist/generation-lifecycle.d.ts +54 -0
  76. package/dist/generation-lifecycle.d.ts.map +1 -0
  77. package/dist/generation-lifecycle.js +431 -0
  78. package/dist/generation-lifecycle.js.map +1 -0
  79. package/dist/generation-recovery-worker.d.ts +100 -0
  80. package/dist/generation-recovery-worker.d.ts.map +1 -0
  81. package/dist/generation-recovery-worker.js +995 -0
  82. package/dist/generation-recovery-worker.js.map +1 -0
  83. package/dist/generation-tracker.d.ts +83 -0
  84. package/dist/generation-tracker.d.ts.map +1 -0
  85. package/dist/generation-tracker.js +436 -0
  86. package/dist/generation-tracker.js.map +1 -0
  87. package/dist/index.d.ts +28 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +21 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/js-script-debug/index.d.ts +13 -0
  92. package/dist/js-script-debug/index.d.ts.map +1 -0
  93. package/dist/js-script-debug/index.js +12 -0
  94. package/dist/js-script-debug/index.js.map +1 -0
  95. package/dist/js-script-debug/markdown.d.ts +6 -0
  96. package/dist/js-script-debug/markdown.d.ts.map +1 -0
  97. package/dist/js-script-debug/markdown.js +62 -0
  98. package/dist/js-script-debug/markdown.js.map +1 -0
  99. package/dist/js-script-debug/outputs.d.ts +20 -0
  100. package/dist/js-script-debug/outputs.d.ts.map +1 -0
  101. package/dist/js-script-debug/outputs.js +30 -0
  102. package/dist/js-script-debug/outputs.js.map +1 -0
  103. package/dist/js-script-debug/report.d.ts +15 -0
  104. package/dist/js-script-debug/report.d.ts.map +1 -0
  105. package/dist/js-script-debug/report.js +90 -0
  106. package/dist/js-script-debug/report.js.map +1 -0
  107. package/dist/js-script-debug/types.d.ts +63 -0
  108. package/dist/js-script-debug/types.d.ts.map +1 -0
  109. package/dist/js-script-debug/types.js +10 -0
  110. package/dist/js-script-debug/types.js.map +1 -0
  111. package/dist/js-script-debug/validate.d.ts +38 -0
  112. package/dist/js-script-debug/validate.d.ts.map +1 -0
  113. package/dist/js-script-debug/validate.js +137 -0
  114. package/dist/js-script-debug/validate.js.map +1 -0
  115. package/dist/message-stream.d.ts +33 -0
  116. package/dist/message-stream.d.ts.map +1 -0
  117. package/dist/message-stream.js +58 -0
  118. package/dist/message-stream.js.map +1 -0
  119. package/dist/normalize-graph.d.ts +13 -0
  120. package/dist/normalize-graph.d.ts.map +1 -0
  121. package/dist/normalize-graph.js +63 -0
  122. package/dist/normalize-graph.js.map +1 -0
  123. package/dist/output-names.d.ts +13 -0
  124. package/dist/output-names.d.ts.map +1 -0
  125. package/dist/output-names.js +13 -0
  126. package/dist/output-names.js.map +1 -0
  127. package/dist/predicates.d.ts +6 -0
  128. package/dist/predicates.d.ts.map +1 -0
  129. package/dist/predicates.js +6 -0
  130. package/dist/predicates.js.map +1 -0
  131. package/dist/preflight.d.ts +87 -0
  132. package/dist/preflight.d.ts.map +1 -0
  133. package/dist/preflight.js +139 -0
  134. package/dist/preflight.js.map +1 -0
  135. package/dist/provider-secret-key.d.ts +3 -0
  136. package/dist/provider-secret-key.d.ts.map +1 -0
  137. package/dist/provider-secret-key.js +7 -0
  138. package/dist/provider-secret-key.js.map +1 -0
  139. package/dist/service/app-debug-service.d.ts +78 -0
  140. package/dist/service/app-debug-service.d.ts.map +1 -0
  141. package/dist/service/app-debug-service.js +201 -0
  142. package/dist/service/app-debug-service.js.map +1 -0
  143. package/dist/service/app-run-server.d.ts +28 -0
  144. package/dist/service/app-run-server.d.ts.map +1 -0
  145. package/dist/service/app-run-server.js +104 -0
  146. package/dist/service/app-run-server.js.map +1 -0
  147. package/dist/service/debug-sessions.d.ts +158 -0
  148. package/dist/service/debug-sessions.d.ts.map +1 -0
  149. package/dist/service/debug-sessions.js +358 -0
  150. package/dist/service/debug-sessions.js.map +1 -0
  151. package/dist/service/index.d.ts +22 -0
  152. package/dist/service/index.d.ts.map +1 -0
  153. package/dist/service/index.js +17 -0
  154. package/dist/service/index.js.map +1 -0
  155. package/dist/service/job-progress.d.ts +40 -0
  156. package/dist/service/job-progress.d.ts.map +1 -0
  157. package/dist/service/job-progress.js +53 -0
  158. package/dist/service/job-progress.js.map +1 -0
  159. package/dist/service/workflow-run.d.ts +279 -0
  160. package/dist/service/workflow-run.d.ts.map +1 -0
  161. package/dist/service/workflow-run.js +598 -0
  162. package/dist/service/workflow-run.js.map +1 -0
  163. package/dist/service/workflow-workspace.d.ts +89 -0
  164. package/dist/service/workflow-workspace.d.ts.map +1 -0
  165. package/dist/service/workflow-workspace.js +160 -0
  166. package/dist/service/workflow-workspace.js.map +1 -0
  167. package/dist/session.d.ts +62 -0
  168. package/dist/session.d.ts.map +1 -0
  169. package/dist/session.js +353 -0
  170. package/dist/session.js.map +1 -0
  171. package/dist/sketch-debug/index.d.ts +11 -0
  172. package/dist/sketch-debug/index.d.ts.map +1 -0
  173. package/dist/sketch-debug/index.js +10 -0
  174. package/dist/sketch-debug/index.js.map +1 -0
  175. package/dist/sketch-debug/markdown.d.ts +6 -0
  176. package/dist/sketch-debug/markdown.d.ts.map +1 -0
  177. package/dist/sketch-debug/markdown.js +93 -0
  178. package/dist/sketch-debug/markdown.js.map +1 -0
  179. package/dist/sketch-debug/report.d.ts +15 -0
  180. package/dist/sketch-debug/report.d.ts.map +1 -0
  181. package/dist/sketch-debug/report.js +98 -0
  182. package/dist/sketch-debug/report.js.map +1 -0
  183. package/dist/sketch-debug/types.d.ts +62 -0
  184. package/dist/sketch-debug/types.d.ts.map +1 -0
  185. package/dist/sketch-debug/types.js +10 -0
  186. package/dist/sketch-debug/types.js.map +1 -0
  187. package/dist/sketch-debug/validate.d.ts +14 -0
  188. package/dist/sketch-debug/validate.d.ts.map +1 -0
  189. package/dist/sketch-debug/validate.js +478 -0
  190. package/dist/sketch-debug/validate.js.map +1 -0
  191. package/dist/supervisor.d.ts +45 -0
  192. package/dist/supervisor.d.ts.map +1 -0
  193. package/dist/supervisor.js +97 -0
  194. package/dist/supervisor.js.map +1 -0
  195. package/dist/timeline-debug/index.d.ts +11 -0
  196. package/dist/timeline-debug/index.d.ts.map +1 -0
  197. package/dist/timeline-debug/index.js +10 -0
  198. package/dist/timeline-debug/index.js.map +1 -0
  199. package/dist/timeline-debug/legibility.d.ts +23 -0
  200. package/dist/timeline-debug/legibility.d.ts.map +1 -0
  201. package/dist/timeline-debug/legibility.js +240 -0
  202. package/dist/timeline-debug/legibility.js.map +1 -0
  203. package/dist/timeline-debug/markdown.d.ts +6 -0
  204. package/dist/timeline-debug/markdown.d.ts.map +1 -0
  205. package/dist/timeline-debug/markdown.js +103 -0
  206. package/dist/timeline-debug/markdown.js.map +1 -0
  207. package/dist/timeline-debug/motion.d.ts +20 -0
  208. package/dist/timeline-debug/motion.d.ts.map +1 -0
  209. package/dist/timeline-debug/motion.js +362 -0
  210. package/dist/timeline-debug/motion.js.map +1 -0
  211. package/dist/timeline-debug/report.d.ts +16 -0
  212. package/dist/timeline-debug/report.d.ts.map +1 -0
  213. package/dist/timeline-debug/report.js +100 -0
  214. package/dist/timeline-debug/report.js.map +1 -0
  215. package/dist/timeline-debug/showcase.d.ts +7 -0
  216. package/dist/timeline-debug/showcase.d.ts.map +1 -0
  217. package/dist/timeline-debug/showcase.js +347 -0
  218. package/dist/timeline-debug/showcase.js.map +1 -0
  219. package/dist/timeline-debug/types.d.ts +64 -0
  220. package/dist/timeline-debug/types.d.ts.map +1 -0
  221. package/dist/timeline-debug/types.js +10 -0
  222. package/dist/timeline-debug/types.js.map +1 -0
  223. package/dist/timeline-debug/validate.d.ts +24 -0
  224. package/dist/timeline-debug/validate.d.ts.map +1 -0
  225. package/dist/timeline-debug/validate.js +1432 -0
  226. package/dist/timeline-debug/validate.js.map +1 -0
  227. package/dist/types.d.ts +211 -0
  228. package/dist/types.d.ts.map +1 -0
  229. package/dist/types.js +2 -0
  230. package/dist/types.js.map +1 -0
  231. package/package.json +103 -0
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # @nodetool-ai/execution
2
+
3
+ `ExecutionSession` — the one place that constructs `WorkflowRunner`. Sits
4
+ between `@nodetool-ai/kernel` and its consumers (CLI, debug harness, headless
5
+ job runner, HTTP API, MCP server, the WebSocket runner). Task A3 migrated the CLI, debug
6
+ harness, and headless job runner onto this facade; A5 migrated the WS runner
7
+ (then `unified-websocket-runner.ts`, since renamed to
8
+ `packages/websocket/src/websocket-client-session.ts`) last, once the reliability
9
+ harness could watch it for drift. The wiring-inventory table below is a
10
+ historical snapshot from before those migrations, and still uses the old file
11
+ name and its line numbers — each migrated row is annotated with what actually
12
+ changed; unmigrated sites (HTTP API, MCP server, the DSL, the agent runner,
13
+ `RunInnerGraph`, the browser workflow runner) are unchanged and still
14
+ construct `WorkflowRunner` directly, per `scripts/check-execution-boundary.mjs`'s
15
+ allowlist.
16
+
17
+ ## Wiring inventory (Task A1)
18
+
19
+ Every non-test `new WorkflowRunner(...)` site in the repo, and what each one
20
+ does around `runner.run()`. "Decision" says where that behavior now lives:
21
+ **facade-owned** (moved into `ExecutionSession`, available to every surface
22
+ that migrates onto it), **adapter-owned** (stays specific to one surface —
23
+ transport/queueing/UI concerns the facade should not generalize), or
24
+ **out of scope** (a nested/child-runner construction, not a top-level
25
+ execution surface — not part of this facade's contract).
26
+
27
+ | Site | Graph hydration | Executor resolution | Param/stream seeding | Cancellation | Timeout | Persistence | Output-name rewriting | Decision |
28
+ |---|---|---|---|---|---|---|---|---|
29
+ | `packages/cli/src/nodetool.ts:751` (`workflows run`) | `hydrateGraphNodeFlags` (registry) | 3-branch: registry → `resolvePythonNodeExecutor` → throw (copy-pasted) | params only | none (`process.exit` on completion) | none | none (stdout only) | none | **facade-owned** (hydration, executor resolution); timeout/cancel are new capabilities A3 can adopt |
30
+ | `packages/cli/src/debug/server-runner.ts:101` (`nodetool debug`) | `hydrateGraphNodeFlags` (registry) | 3-branch (copy-pasted, identical to above) | params only | **none** — `withTimeout` races the promise and *abandons* the still-running kernel on timeout (a real leak) | `withTimeout` wraps the whole run in a `setTimeout`/`Promise.race`, synthesizing a `failed` result; kernel run keeps executing | none | none | **facade-owned**: hydration, executor resolution, and — critically — the timeout becomes `session.cancel("timeout")` instead of abandonment (A3's stated fix) |
31
+ | `packages/websocket/src/headless-job-runner.ts:225` (`startHeadlessJob`) | `hydrateGraphNodeFlags` (registry), preceded by its own `normalizeRunnableGraph` (editor-only pruning, `data`→`properties`, edge_type normalization) | 3-branch (copy-pasted, identical) | params + optional `trigger_event` | none exposed (no cancel handle returned to caller) | none | `Job` row created before run, terminal status persisted after (`persistTerminalStatus`, DB-cancel-aware) | none | **facade-owned**: hydration + the `normalizeRunnableGraph` pre-step (folded into this package's `normalizeGraph`), executor resolution, trigger_event passthrough. Persistence stays **adapter-owned** (Job-model specifics) but is expressible via `JobPersistenceHook` |
32
+ | `packages/websocket/src/unified-websocket-runner.ts:2797` (`startJobInner`, `run_job`) | `this.hydrateGraph` — `Graph.loadFromDict({resolver: this.resolveNodeType})` when a node-type resolver is configured, else `withExplicitNodeFlags` (a *different* hydration path than `hydrateGraphNodeFlags`, richer: supports async Python-metadata-backed resolution) | `resolveExecutor` **injected at construction** (`UnifiedWebSocketRunnerOptions.resolveExecutor`) — not the copy-pasted 3-branch; the WS server wires it once at bootstrap | params, **plus** live `stream_input`/`end_input_stream` commands mapped straight onto `runner.pushInputValue`/`finishInputStream` (the *only* surface with streaming seeding before this package) | `cancelJob`: `runner.cancel()` + immediate DB `markCancelled()` + `job_update` (ahead of the runner's own `.finally()` persistence, to avoid a UI race) | none built in (host process only) | `Job.create` before run, queueing (`MAX_CONCURRENT_JOBS`, per-workflow caps), slot accounting (`startingJobs`→`activeJobs`) | **yes** — `unified-websocket-runner.ts:2733`: when `require_terminal_result`, every `nodetool.output.*` node's kernel-facing `name` is rewritten to `properties.name` before the run, so `output_update` and the terminal snapshot address the same key | **Migrated (A5).** `startJobInner` now calls `ExecutionSession.create(...)` instead of `new WorkflowRunner(...)` + a later `runner.run(...)`; `active.runner: WorkflowRunner` is `active.session: ExecutionSession`. What moved and what didn't: **hydration** stays exactly as it was — `this.hydrateGraph(rawGraph)` (unchanged, including the output-name rewrite right after it) still runs first, so `ExecutionSession` receives an *already-hydrated* graph; it re-hydrates internally via `withExplicitNodeFlags` (no `registry` passed — this class has never held a `NodeRegistry` instance, only the bootstrap-injected `resolveExecutor`/`resolveNodeType` closures), which is a no-op on fields already resolved (`...node` passes `propertyTypes`, flags, and the rewritten output name straight through). **Executor resolution** is the bootstrap-injected `this.resolveExecutor` passed via the facade's new `resolveExecutor` override (added in A5 specifically for this: it bypasses `ExecutionSession`'s own registry+bridge construction, since this class has no registry to hand it) — not rebuilt, not duplicated. **`pushInputValue`/`finishInputStream`** passthrough is now `session.pushInput`/`session.finishInputStream`; the new `session.updateNodeProperties` passthrough (added in A5) covers the `update_node_properties` command, which the pre-migration inventory above didn't list. **Still adapter-owned, unchanged**: queueing, slot accounting, per-client concurrency caps, the DB-ahead-of-runner cancel ordering, the `Job.create`/existing-row persistence block, output-name rewriting (still the manual pre-existing rewrite loop, not the facade's `requireTerminalResult` option — no reason to swap a working adapter-owned rewrite for a facade one mid-migration). One real (accepted) behavior shift: `ExecutionSession.create()` couples "construct" and "start the kernel run" into one call, where the pre-migration code constructed the runner (registering it in `activeJobs`, cancellable) *before* the `Job.create` persistence block and only called `runner.run()` *after* it — the migrated code creates the session (which starts the run) at the former construction point, so the run can begin a few milliseconds before its DB row exists. The reliability harness's differential suite (C2/C4) shows this produces no observable wire-protocol difference. |
33
+ | `packages/websocket/src/unified-websocket-runner.ts:4147` (`handleChatMessage`) | same `this.hydrateGraph` | injected `resolveExecutor` (same pattern) | params built from chat history/legacy fields | none exposed here directly (goes through the same `activeJobs`/`cancelJob` machinery) | none | `Job.create` (best-effort) | n/a | **out of scope for A2**: this is chat-turn orchestration built on the same runner-construction pattern as the row above, not a distinct wiring divergence |
34
+ | `packages/websocket/src/unified-websocket-runner.ts:6283` (single-node tool-call harness) | `this.hydrateGraph` on a synthetic one-node graph | injected `resolveExecutor` | `params: {}`, values fed via `data` on the synthetic node | none | none | none | n/a | **out of scope for A2**: an internal single-node execution helper (tool call → node run), not a top-level surface |
35
+ | `packages/websocket/src/http-api.ts:771` (async HTTP run) | — | — | params only | — | — | — | — | **Migrated.** The route calls `runWorkflow` from `@nodetool-ai/execution/service`, so hydration, executor resolution, cancellation, timeout and `Job` persistence are all the facade's now. The one thing it still owns is the environment: `environment: () => getWorkflowRuntimeEnvironment(options)`, passed lazily so a nonexistent workflow 404s before the runtime bootstraps. That bootstrap stays **out of scope** (it also builds the registry and connects the Python bridge — infra construction, not execution semantics) |
36
+ | `packages/websocket/src/mcp-server.ts` (MCP tool: run workflow) | — | — | — | — | — | — | — | **Gone.** The mount no longer runs workflows; `registerAgentMcpTools` exposes the agents package's capability tools instead, and the file imports nothing from `@nodetool-ai/kernel` |
37
+ | `packages/core-nodes/src/nodes/run-inner-graph.ts:131` (`RunInnerGraph` / `WorkflowNode`) | `Graph.loadFromDict` via `context.resolveNodeType` when set, else `withExplicitNodeFlags` | injected `resolveExecutor` from the *parent* run's `context.resolveExecutor` | params from node properties | none (bounded by the parent run's lifetime) | none | none (child of an already-persisted parent run) | maps runner output keys back to the sub-graph's declared output names (`outputKeyMap`) | **out of scope**: a node's own implementation spawning a *child* runner inside an already-running parent node — not a top-level surface entry point. Revisit only if a future task generalizes nested execution |
38
+ | `packages/agents/src/execute-agent-graph.ts:122` (`executeAgentGraph`) | — | — | — | — | — | — | — | **Gone.** The retired `Agent` graph branch was its only caller, so it was deleted with it; `applyRunPolicy`, a graph transform rather than execution wiring, survives in `packages/agents/src/run-policy.ts` for the `graph-e2e` eval |
39
+ | `packages/dsl/src/core.ts:399` (`run()`, the TS DSL entry point) | none — DSL nodes carry flags from generated metadata; wrapped in `withExplicitNodeFlags` directly | 4-branch: `opts.registry` → `NodeRegistry.global` → `builtinRegistry` → Python bridge → throw (a superset of the 3-branch pattern — DSL graphs can mix three TS registries) | params only | none | none | none | none | **out of scope for A2, revisit for A3+**: the DSL's multi-registry resolver is a genuinely different shape (3 TS registries, not 1) that this package's single-`registry` option doesn't yet cover. Noted as a gap, not silently generalized |
40
+ | `packages/workflow-runner/src/run.ts:118` (`runWorkflow`, browser + `nodetool run` shared core) | `hydrateGraphNodeFlags` | `opts.registry.resolve(node)` only (no Python-bridge branch — this path targets the browser, which has no Python bridge) | params only, **but** already an `AsyncGenerator<ProcessingMessage, RunResult>` with `AbortSignal`-based `cancelRun()` — this file is the closest existing prior art to `ExecutionSession`'s streaming/cancel shape | `AbortSignal` → `runner.cancel()`, mirrors this package's `cancel()` | none built in (caller's `AbortSignal` can carry one) | none (caller's concern) | none | **not migrated in A2** — its generator-based public API predates this package and has its own consumers (browser workflow runner, `nodetool run`). Cataloged here as the pattern this package's `messages`/`cancel()` API generalizes; a follow-up task can make it a thin wrapper over `ExecutionSession` |
41
+ | `packages/workflow-runner/e2e/src/browser-entry.ts:151` | same pattern as `run.ts` (it's the e2e harness's copy of the browser runner) | `opts.registry.resolve` | params only | `AbortSignal` | none | none | none | **out of scope**: test harness, not a product surface |
42
+
43
+ ### Notes on what didn't make the table
44
+
45
+ - **The third executor-resolution copy is down to one caller.** `http-api.ts`
46
+ and `mcp-server.ts` used to share a `getRuntimeEnvironment`/
47
+ `getWorkflowRuntimeEnvironment` helper wrapping registry + Python-bridge
48
+ bootstrap — a third copy of "registry → Python bridge → throw", independent
49
+ of the one duplicated verbatim in `cli/nodetool.ts`, `debug/server-runner.ts`,
50
+ and `headless-job-runner.ts`. `mcp-server.ts` no longer runs workflows, and
51
+ `http-api.ts` now hands that helper to `runWorkflow` as an `environment`
52
+ callback rather than driving a runner with it. Folding what remains onto this
53
+ package's `createExecutorResolver` (`src/executor-resolver.ts`) is still open.
54
+ - **Output-name rewriting** existed at exactly one site
55
+ (`unified-websocket-runner.ts:2733`, `require_terminal_result`). It is now
56
+ `ExecutionSession`'s `requireTerminalResult` option
57
+ (`src/output-names.ts`), available to every surface without being
58
+ reinvented per-site.
59
+ - **`bufferLimit`** is a `WorkflowRunnerOptions` field, not a `run()`-time
60
+ argument; no existing call site sets it (all rely on the kernel default).
61
+ `ExecutionSession`'s `limits.bufferLimit` forwards it 1:1.
62
+ - **`nodeTimeoutMs`** has no kernel-side hook today (only the run-level `AbortSignal` that
63
+ `cancel()` aborts). `ExecutionSession.create()` throws if it's set, rather
64
+ than accepting and silently ignoring it — inventing a no-op timeout would
65
+ be worse than refusing it.
66
+
67
+ ## API
68
+
69
+ ```ts
70
+ import { ExecutionSession } from "@nodetool-ai/execution";
71
+
72
+ const session = await ExecutionSession.create({
73
+ graph, // raw saved JSON — hydration happens HERE, once
74
+ registry, // NodeRegistry from @nodetool-ai/node-sdk
75
+ bridgeFactory, // optional; defaults to connectPythonBridgeForGraph
76
+ params, // and/or pushInput/finishInputStream below
77
+ persistence: { onAccepted, onTerminal } | null,
78
+ limits: { runTimeoutMs, bufferLimit }, // nodeTimeoutMs: not yet supported, see above
79
+ requireTerminalResult: true, // optional — output-name rewriting
80
+ captureMessages: true, // optional — required to read `messages` below
81
+ catalogs, providerConfiguration, // optional — preflight, see below
82
+ });
83
+
84
+ // Only with `captureMessages: true`, and only if you actually drain it:
85
+ // capture queues each message until a consumer pulls it, so a host that just
86
+ // awaits `result` would hold the whole run's messages (audio chunks included)
87
+ // for nothing. Reading `messages` without the flag throws; a consumer that
88
+ // falls behind `limits.messageBufferLimit` makes the iterator throw.
89
+ for await (const message of session.messages) { /* ProcessingMessage */ }
90
+
91
+ await session.pushInput("input_name", value);
92
+ session.finishInputStream("input_name");
93
+
94
+ session.cancel("reason"); // the ONLY cancel; limits.runTimeoutMs = cancel("timeout")
95
+
96
+ const result = await session.result; // RunResult — never rejects
97
+ ```
98
+
99
+ `create()` refuses before it spends anything. After normalization — and ahead
100
+ of the Python bridge, `persistence.onAccepted`, and the kernel — it checks the
101
+ graph's model selections against the provider catalogs and each selected
102
+ provider's credentials against `context.getSecret`, and throws
103
+ `ExecutionPreflightError` (`.issues` is the machine-readable list, `.message`
104
+ the text a host prints). Without it a missing key failed at the node that
105
+ needed it, after the upstream half of the graph had already run and billed.
106
+ `catalogs` and `providerConfiguration` default to the process-wide provider
107
+ registry; a host whose providers are not in that registry must pass both.
108
+
109
+ Inside the facade: `hydrateGraphNodeFlags` (plus the graph normalization
110
+ `headless-job-runner.ts` used to do inline — editor-only pruning, `data` →
111
+ `properties`, `edge_type` defaulting), the three-branch executor resolver,
112
+ param/stream seeding via the kernel's own `pushInputValue`/
113
+ `finishInputStream`, cancellation, and run-timeout-as-cancel.
114
+
115
+ ## Subpaths
116
+
117
+ - `@nodetool-ai/execution/debug` — the execution-summary reducer, the run
118
+ verdict, and the target/run-report types every surface reports a run with.
119
+ - `@nodetool-ai/execution/app-debug` — the headless mini-app simulator:
120
+ `simulateApp` takes a resolved app target and an injected workflow runner and
121
+ returns an `AppDebugReport`. It reads no database and writes no files, so the
122
+ CLI (`nodetool app debug`), the agent build loop, and the server all simulate
123
+ an app the same way. Target resolution and bundle writing belong to the host.
124
+
125
+ ## What this package does not do
126
+
127
+ - **Does not validate the message stream against a schema.** `messages` is a
128
+ live `AsyncIterable<ProcessingMessage>`; runtime protocol validation is
129
+ Track B (`packages/protocol`'s Zod-first `messages.ts`).
@@ -0,0 +1 @@
1
+ 2026-09-28T09:19:14.123Z
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Pure app-spec layer: parse a workflow's app document into a flat widget
3
+ * list, extract the graph's bindable surface, and statically validate the
4
+ * wiring between the two.
5
+ *
6
+ * The semantics — widget catalog, document parsing, binding resolution — come
7
+ * from `@nodetool-ai/app-runtime`, so this harness checks the same rules the
8
+ * web runtime enforces instead of a copy that drifts away from it.
9
+ */
10
+ import { type ApplicationDocument, type BindingScope, type OperationBinding, type VariableDeclaration } from "@nodetool-ai/app-runtime";
11
+ import type { DebugGraph } from "../debug/types.js";
12
+ import type { AppIO, AppOperationSpec, AppSpec, AppValidation, AppWidgetSpec } from "./types.js";
13
+ /**
14
+ * The app's operations resolved against real graphs, plus the declared
15
+ * variables and resources. Built by the harness (resolving an operation's
16
+ * workflow may need a database read) and handed to the pure layer here.
17
+ */
18
+ export interface AppContext {
19
+ defaultOperationId: string;
20
+ operations: AppOperationSpec[];
21
+ variables: VariableDeclaration[];
22
+ resources: Array<{
23
+ id: string;
24
+ name: string;
25
+ kind: string;
26
+ }>;
27
+ }
28
+ /**
29
+ * The binding scope an app resolves against: every declared operation with the
30
+ * surface of the workflow it runs, plus the declared variables. Without a
31
+ * context this is the single-operation shape a legacy `app_doc` has.
32
+ */
33
+ export declare function bindingScopeFor(io: AppIO, context?: AppContext): BindingScope;
34
+ /**
35
+ * The operations a parsed document declares, as report specs. A document with
36
+ * none gets the implicit single operation a legacy `app_doc` runs.
37
+ */
38
+ export declare function documentOperations(document: ApplicationDocument): OperationBinding[];
39
+ /** Parse an app document (object or JSON string), or explain why it will not. */
40
+ export declare function parseAppDocument(appDoc: unknown): {
41
+ document: null;
42
+ issue: string;
43
+ } | {
44
+ document: ApplicationDocument;
45
+ issue: null;
46
+ };
47
+ /**
48
+ * Parse an app document (object or JSON string) into an {@link AppSpec},
49
+ * resolving every widget binding to a node-ID reference against the live
50
+ * graph. Slot children are discovered from the widget catalog, falling back to
51
+ * a structural scan so a new layout widget keeps working before the catalog
52
+ * knows about it.
53
+ */
54
+ export declare function parseAppSpec(appDoc: unknown, io: AppIO, context?: AppContext,
55
+ /**
56
+ * The document the target loader already parsed. Passed in so an application
57
+ * or bundle target is not re-parsed as if it were a `workflow.app_doc` —
58
+ * `appDoc` stays the raw stored value, which is what the persist-downgrade
59
+ * check needs to see.
60
+ */
61
+ preparsed?: {
62
+ document: ApplicationDocument | null;
63
+ issue: string | null;
64
+ }): {
65
+ spec: null;
66
+ issues: string[];
67
+ warnings: never[];
68
+ } | {
69
+ spec: {
70
+ version: number;
71
+ title: string | null;
72
+ widgets: AppWidgetSpec[];
73
+ operations: AppOperationSpec[];
74
+ variables: VariableDeclaration[];
75
+ resources: {
76
+ id: string;
77
+ name: string;
78
+ kind: import("@nodetool-ai/app-runtime").ResourceKind;
79
+ }[];
80
+ };
81
+ issues: string[];
82
+ warnings: string[];
83
+ };
84
+ /** An operation binding plus the surface it resolved against, for the report. */
85
+ export declare function operationSpec(binding: OperationBinding, io: AppIO | null, unavailable: string | null): AppOperationSpec;
86
+ /**
87
+ * Extract the app-bindable surface from a kernel-shape graph: input nodes,
88
+ * output/Preview nodes, and SetVariable channel names — the same surface the
89
+ * web builder offers in its binding pickers.
90
+ */
91
+ export declare function extractAppIO(graph: DebugGraph): AppIO;
92
+ /** Statically check the app's wiring against the workflow's bindable surface. */
93
+ export declare function validateApp(spec: AppSpec, io: AppIO, context?: AppContext): AppValidation;
94
+ //# sourceMappingURL=app-spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-spec.d.ts","sourceRoot":"","sources":["../../src/app-debug/app-spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAYL,KAAK,mBAAmB,EAGxB,KAAK,YAAY,EAEjB,KAAK,gBAAgB,EAErB,KAAK,mBAAmB,EACzB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAGV,KAAK,EACL,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,aAAa,EACd,MAAM,YAAY,CAAC;AAwBpB;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,SAAS,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9D;AA2CD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,YAAY,CAoB7E;AA+DD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,mBAAmB,GAC5B,gBAAgB,EAAE,CAYpB;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO;;;;;;EAyB/C;AAmCD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,OAAO,EACf,EAAE,EAAE,KAAK,EACT,OAAO,CAAC,EAAE,UAAU;AACpB;;;;;GAKG;AACH,SAAS,CAAC,EAAE;IAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;;;;;;;;;;;;;;;;;;;EAsH3E;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAC3B,OAAO,EAAE,gBAAgB,EACzB,EAAE,EAAE,KAAK,GAAG,IAAI,EAChB,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,gBAAgB,CAalB;AAeD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,KAAK,CAwBrD;AAsBD,iFAAiF;AACjF,wBAAgB,WAAW,CACzB,IAAI,EAAE,OAAO,EACb,EAAE,EAAE,KAAK,EACT,OAAO,CAAC,EAAE,UAAU,GACnB,aAAa,CAyTf"}