langflower 0.0.7 → 0.0.9

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 (189) hide show
  1. package/package.json +1 -1
  2. package/ui-dist/{chunk-Y6VMBLSJ.js → chunk-7UMVYN3A.js} +1 -1
  3. package/ui-dist/{chunk-6DQ2XSRW.js → chunk-MDGXX73Z.js} +3 -3
  4. package/ui-dist/index.html +1 -1
  5. package/ui-dist/main-2JJGCNTD.js +313 -0
  6. package/vendor/common-nodes/dist/ai/chat-completion-stream.d.ts +2 -0
  7. package/vendor/common-nodes/dist/ai/critique/node.d.ts +246 -0
  8. package/vendor/common-nodes/dist/ai/critique/node.js +2 -2
  9. package/vendor/common-nodes/dist/ai/fake-llm/node.d.ts +246 -0
  10. package/vendor/common-nodes/dist/ai/features/chat-completion-stream.d.ts +53 -0
  11. package/vendor/common-nodes/dist/ai/features/chat-completion-stream.js +1 -0
  12. package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.d.ts +13 -0
  13. package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.js +17 -0
  14. package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.d.ts +2 -0
  15. package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.js +113 -0
  16. package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.d.ts +28 -0
  17. package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.js +194 -0
  18. package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.d.ts +9 -0
  19. package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.js +21 -0
  20. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.d.ts +2 -0
  21. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.js +216 -0
  22. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.d.ts +125 -0
  23. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.js +39 -0
  24. package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.d.ts +2 -0
  25. package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.js +59 -0
  26. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.d.ts +1 -0
  27. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.js +7 -0
  28. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.d.ts +43 -0
  29. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.js +96 -0
  30. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.d.ts +32 -0
  31. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.js +58 -0
  32. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.d.ts +80 -0
  33. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.js +681 -0
  34. package/vendor/common-nodes/dist/ai/features/llm-role-preset.d.ts +69 -0
  35. package/vendor/common-nodes/dist/ai/features/llm-role-preset.js +265 -0
  36. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.d.ts +148 -0
  37. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.js +198 -0
  38. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.d.ts +21 -0
  39. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.js +118 -0
  40. package/vendor/common-nodes/dist/ai/features/openai/context-length-error.d.ts +14 -0
  41. package/vendor/common-nodes/dist/ai/features/openai/context-length-error.js +63 -0
  42. package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.d.ts +19 -0
  43. package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.js +182 -0
  44. package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.d.ts +28 -0
  45. package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.js +52 -0
  46. package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.d.ts +31 -0
  47. package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.js +326 -0
  48. package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.d.ts +14 -0
  49. package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.js +21 -0
  50. package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.d.ts +30 -0
  51. package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.js +132 -0
  52. package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.d.ts +20 -0
  53. package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.js +70 -0
  54. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.d.ts +35 -0
  55. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.js +106 -0
  56. package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.d.ts +9 -0
  57. package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.js +21 -0
  58. package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.d.ts +13 -0
  59. package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.js +23 -0
  60. package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.d.ts +10 -0
  61. package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.js +8 -0
  62. package/vendor/common-nodes/dist/ai/features/run-host-services.d.ts +54 -0
  63. package/vendor/common-nodes/dist/ai/features/run-host-services.js +29 -0
  64. package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.d.ts +17 -0
  65. package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.js +61 -0
  66. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.d.ts +39 -0
  67. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.js +43 -0
  68. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.d.ts +14 -0
  69. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.js +18 -0
  70. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.d.ts +80 -0
  71. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.js +76 -0
  72. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.d.ts +113 -0
  73. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.js +131 -0
  74. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.d.ts +6 -0
  75. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.js +30 -0
  76. package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.d.ts +13 -0
  77. package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.js +17 -0
  78. package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.d.ts +28 -0
  79. package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.js +194 -0
  80. package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-reducer.js +36 -0
  81. package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.d.ts +35 -0
  82. package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.js +19 -0
  83. package/vendor/common-nodes/dist/ai/llm-loop/normalize-llm-recovery-policy.js +52 -9
  84. package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.d.ts +8 -2
  85. package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.js +43 -13
  86. package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.d.ts +3 -5
  87. package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.js +116 -1
  88. package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.d.ts +82 -0
  89. package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.js +95 -0
  90. package/vendor/common-nodes/dist/ai/llm-session-shell.d.ts +4 -9
  91. package/vendor/common-nodes/dist/ai/llm-session-shell.js +2 -4
  92. package/vendor/common-nodes/dist/ai/nodes/critique/node.d.ts +588 -0
  93. package/vendor/common-nodes/dist/ai/nodes/critique/node.js +240 -0
  94. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.d.ts +571 -0
  95. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.js +208 -0
  96. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.d.ts +587 -0
  97. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.js +91 -0
  98. package/vendor/common-nodes/dist/ai/nodes/review/node.d.ts +593 -0
  99. package/vendor/common-nodes/dist/ai/nodes/review/node.js +240 -0
  100. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.d.ts +630 -0
  101. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.js +302 -0
  102. package/vendor/common-nodes/dist/ai/openai/create-chat-completion-stream.js +6 -0
  103. package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.d.ts +2 -0
  104. package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.js +18 -0
  105. package/vendor/common-nodes/dist/ai/openai-llm/node.d.ts +246 -0
  106. package/vendor/common-nodes/dist/ai/review/node.d.ts +246 -0
  107. package/vendor/common-nodes/dist/ai/review/node.js +2 -2
  108. package/vendor/common-nodes/dist/ai/sub-agent/node.d.ts +246 -0
  109. package/vendor/common-nodes/dist/ai/sub-agent/node.js +2 -2
  110. package/vendor/common-nodes/dist/catalog.js +7 -5
  111. package/vendor/common-nodes/dist/compile-custom-nodes/node.d.ts +21 -0
  112. package/vendor/common-nodes/dist/compile-custom-nodes/node.js +45 -0
  113. package/vendor/common-nodes/dist/crawl/crawl/node.js +1 -1
  114. package/vendor/common-nodes/dist/crawl/fetch-url/node.js +1 -1
  115. package/vendor/common-nodes/dist/flow/repeat/node.js +6 -1
  116. package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.d.ts +18 -0
  117. package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.js +29 -0
  118. package/vendor/common-nodes/dist/langflower-tools/node.d.ts +20 -0
  119. package/vendor/common-nodes/dist/langflower-tools/node.js +77 -0
  120. package/vendor/common-nodes/dist/text/append-file/node.js +1 -1
  121. package/vendor/common-nodes/dist/text/read-file/node.js +1 -1
  122. package/vendor/common-nodes/dist/text/write-file/node.js +1 -1
  123. package/vendor/common-nodes/dist/tools/inventory-tool-round.d.ts +2 -2
  124. package/vendor/common-nodes/package.json +10 -10
  125. package/vendor/compiler/dist/compile-project-nodes.d.ts +2 -1
  126. package/vendor/compiler/dist/compile-project-nodes.js +35 -6
  127. package/vendor/compiler/dist/resolve-host-types.d.ts +0 -5
  128. package/vendor/compiler/dist/resolve-host-types.js +0 -8
  129. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.d.ts +1 -1
  130. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.js +1 -1
  131. package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.d.ts +8 -0
  132. package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.js +14 -0
  133. package/vendor/runtime/dist/runtime-editor.d.ts +5 -1
  134. package/vendor/runtime/dist/runtime-editor.js +19 -0
  135. package/vendor/runtime/dist/runtime-runner.js +17 -17
  136. package/vendor/runtime/dist/runtime.d.ts +2 -1
  137. package/vendor/runtime/dist/runtime.js +1 -0
  138. package/vendor/runtime/dist/testing/workflows/workflow-events.d.ts +8 -6
  139. package/vendor/runtime/dist/testing/workflows/workflow-events.js +19 -31
  140. package/vendor/runtime/dist/types.d.ts +33 -38
  141. package/vendor/runtime/dist/types.js +2 -1
  142. package/vendor/server/dist/bridge/attach-langflower-bridge.js +3 -2
  143. package/vendor/server/dist/bridge/bridge-event-log.js +17 -102
  144. package/vendor/server/dist/bridge/build-execution-context.d.ts +5 -2
  145. package/vendor/server/dist/bridge/build-execution-context.js +45 -5
  146. package/vendor/server/dist/bridge/forward-runner-event.d.ts +1 -1
  147. package/vendor/server/dist/bridge/forward-runner-event.js +7 -12
  148. package/vendor/server/dist/bridge/get-live-wired-tools.d.ts +12 -0
  149. package/vendor/server/dist/bridge/get-live-wired-tools.js +80 -0
  150. package/vendor/server/dist/bridge/langflower-tools-rpc.d.ts +7 -0
  151. package/vendor/server/dist/bridge/langflower-tools-rpc.js +29 -0
  152. package/vendor/server/dist/bridge/settings-draft-controller.js +26 -3
  153. package/vendor/server/dist/bridge/wire-custom-palette-handlers.d.ts +2 -1
  154. package/vendor/server/dist/bridge/wire-custom-palette-handlers.js +3 -5
  155. package/vendor/server/dist/bridge/wire-runner-handlers.js +15 -8
  156. package/vendor/server/dist/checkpoint/run-checkpoint-session.d.ts +1 -1
  157. package/vendor/server/dist/checkpoint/run-checkpoint-session.js +10 -9
  158. package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.d.ts +10 -0
  159. package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.js +23 -0
  160. package/vendor/server/dist/workflow/apply-editor-mutation.d.ts +5 -0
  161. package/vendor/server/dist/workflow/apply-editor-mutation.js +32 -0
  162. package/vendor/server/skeleton/instructions.md +9 -5
  163. package/vendor/server/skeleton/nodes/my-nodes/README.md +4 -3
  164. package/vendor/server/skeleton/schemas/langflower-config.schema.json +11 -1
  165. package/vendor/server/skeleton/skills/langflower-helper/SKILL.md +49 -19
  166. package/vendor/server/skeleton/skills/langflower-helper/architecture.md +22 -9
  167. package/vendor/server/skeleton/skills/langflower-helper/layout.md +15 -15
  168. package/vendor/server/skeleton/skills/langflower-node-writer/SKILL.md +19 -9
  169. package/vendor/server/skeleton/skills/langflower-workflow-writer/SKILL.md +14 -10
  170. package/vendor/server/skeleton/workflows/starter.json +30 -3
  171. package/vendor/shared/dist/execution/derive-run-settle-outcome.d.ts +1 -1
  172. package/vendor/shared/dist/execution/derive-run-settle-outcome.js +4 -3
  173. package/vendor/shared/dist/execution/derive-run-settle-outcome.test.js +9 -9
  174. package/vendor/shared/dist/langflower-bus-config.d.ts +6 -14
  175. package/vendor/shared/dist/langflower-bus-config.js +4 -12
  176. package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.js +6 -0
  177. package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.test.js +30 -0
  178. package/vendor/shared/dist/langflower-ws-waits.d.ts +7 -14
  179. package/vendor/shared/dist/langflower-ws-waits.js +14 -14
  180. package/vendor/websocket-bridge/dist/bridge-codec.d.ts +1 -0
  181. package/vendor/websocket-bridge/dist/bridge-codec.js +11 -11
  182. package/vendor/websocket-bridge/dist/bridge-frame.js +1 -1
  183. package/vendor/websocket-bridge/dist/bridge-subjects.d.ts +1 -1
  184. package/vendor/websocket-bridge/dist/bridge-subjects.js +2 -2
  185. package/vendor/websocket-bridge/dist/bridge-types.d.ts +13 -1
  186. package/vendor/websocket-bridge/dist/create-client.js +3 -3
  187. package/vendor/websocket-bridge/dist/create-server.js +12 -6
  188. package/vendor/websocket-bridge/package.json +8 -0
  189. package/ui-dist/main-SMO3L7U5.js +0 -311
@@ -24,6 +24,9 @@ You help the user **author valid Langflower workflow JSON** under
24
24
  `write`, `create`, `delete`, `bash` — never `Bash(ls)`-style strings.
25
25
  - LLM `rolePreset` values are only: `custom` | `plan` | `coder` | `explorer`.
26
26
  Unknown values silently become `custom`.
27
+ - Recompile is opt-in: wire `common-langflower-tools` `tools` → agent
28
+ `tools`. Do **not** add that pack to every agent unless the user wants
29
+ `compile_custom_nodes`. Do not invent editor mutation tools on that pack.
27
30
 
28
31
  ## On-disk shape
29
32
 
@@ -49,16 +52,17 @@ Schema: `.langflower/schemas/workflow.schema.json`. Samples:
49
52
 
50
53
  ## Ports you must get right
51
54
 
52
- | Node type | Key ports |
53
- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
54
- | `common-chat-input` | out `message` (no wireable in) |
55
- | `common-openai-llm` / `common-fake-llm` | in `userPrompt`, `systemPrompt`, `feedback`, `subagentRegistration`, `subagentResult`; out `response`, `subagent`, … |
56
- | `common-hitl-review-gate` | in `result`; out `response`, `feedback` |
57
- | `common-merge` | in/out **`value`** only (not `step` / `output`) |
58
- | `common-review` | in `task`, `result`, `systemPrompt`; out `response`, `feedback` |
59
- | `common-sub-agent` | out `registration`, `result`; in `task`, `systemPrompt` |
60
- | `common-finish` | in `value` |
61
- | `common-string` | in/out `value` |
55
+ | Node type | Key ports |
56
+ | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
57
+ | `common-chat-input` | out `message` (no wireable in) |
58
+ | `common-openai-llm` / `common-fake-llm` | in `userPrompt`, `systemPrompt`, `feedback`, `subagentRegistration`, `subagentResult`; out `response`, `subagent`, … |
59
+ | `common-hitl-review-gate` | in `result`; out `response`, `feedback` |
60
+ | `common-merge` | in/out **`value`** only (not `step` / `output`) |
61
+ | `common-review` | in `task`, `result`, `systemPrompt`; out `response`, `feedback` |
62
+ | `common-sub-agent` | out `registration`, `result`; in `task`, `systemPrompt` |
63
+ | `common-finish` | in `value` |
64
+ | `common-string` | in/out `value` |
65
+ | `common-langflower-tools` | out **`tools`** only — wire into an agent `tools` port to opt in to **`compile_custom_nodes`** (unsafe; starter Helper / Writer already wired). Not ambient. Canvas add/remove node or edge tools are **not** shipped. |
62
66
 
63
67
  ## Soft↔Hard loops
64
68
 
@@ -4,7 +4,7 @@
4
4
  "name": "Starter",
5
5
  "description": "Chat loop with an onboarding agent (skill langflower-helper) plus a Writer Sub-Agent (workflow-writer + node-writer). After bootstrap — product capabilities, workflows, editor chrome, and custom nodes.",
6
6
  "createdAt": "2026-07-24T00:00:00.000Z",
7
- "updatedAt": "2026-08-05T16:18:12.801Z"
7
+ "updatedAt": "2026-08-15T00:00:00.000Z"
8
8
  },
9
9
  "graph": {
10
10
  "viewport": {
@@ -15,6 +15,19 @@
15
15
  "height": 1005.328125
16
16
  },
17
17
  "nodes": [
18
+ {
19
+ "id": "compile",
20
+ "type": "common-langflower-tools",
21
+ "params": {},
22
+ "inputs": {},
23
+ "ui": {
24
+ "position": {
25
+ "x": 40,
26
+ "y": 40
27
+ },
28
+ "label": "Langflower Tools"
29
+ }
30
+ },
18
31
  {
19
32
  "id": "chat",
20
33
  "type": "common-chat-input",
@@ -50,7 +63,7 @@
50
63
  }
51
64
  },
52
65
  "inputs": {
53
- "systemPrompt": "You are the Langflower onboarding assistant. Use the langflower-helper skill. The user already started Langflower and configured a provider — do not lead with CLI start or provider setup. Help with what Langflower can do, workflows, editor chrome, and custom nodes. Keep answers short and actionable.\n\nWhen the user asks to draft or edit a workflow JSON or a custom node pack, spawn_subagent the Writer specialist (skills langflower-workflow-writer and langflower-node-writer) with a clear task; then summarize the Writer result for the user."
66
+ "systemPrompt": "You are the Langflower onboarding assistant. Use the langflower-helper skill. The user already started Langflower and configured a provider — do not lead with CLI start or provider setup. Help with what Langflower can do, workflows, editor chrome, and custom nodes. Keep answers short and actionable.\n\nLangflower Tools is wired: after custom-node file changes (yours or Writer's), call compile_custom_nodes (no args). Do not send the user to Custom → Update as the only path. You cannot place a new type on the canvas mid-run; already-placed custom types hot-swap, and already-wired custom tools can be invoked later in this run.\n\nWhen the user asks to draft or edit a workflow JSON or a custom node pack, spawn_subagent the Writer specialist (skills langflower-workflow-writer and langflower-node-writer) with a clear task; then compile if nodes changed, and summarize for the user."
54
67
  },
55
68
  "ui": {
56
69
  "position": {
@@ -88,7 +101,7 @@
88
101
  }
89
102
  },
90
103
  "inputs": {
91
- "systemPrompt": "You are Writer. Follow langflower-workflow-writer and/or langflower-node-writer for the task. Prefer editing files under .langflower/workflows/ and .langflower/nodes/. Use only catalog node types and real ports. Return a short summary of files changed and any open risks."
104
+ "systemPrompt": "You are Writer. Follow langflower-workflow-writer and/or langflower-node-writer for the task. Prefer editing files under .langflower/workflows/ and .langflower/nodes/. Use only catalog node types and real ports. After writing or editing .langflower/nodes/ files, call compile_custom_nodes (no args) and report status / COMPILATION_ERRORS.md — do not only remind the user to click Update. Wire common-langflower-tools into an agent only when they should be allowed to recompile. Return a short summary of files changed and any open risks."
92
105
  },
93
106
  "ui": {
94
107
  "position": {
@@ -113,6 +126,20 @@
113
126
  }
114
127
  ],
115
128
  "edges": [
129
+ {
130
+ "edgeId": "e-compile-helper",
131
+ "fromNodeId": "compile",
132
+ "fromPort": ["tools", 0],
133
+ "toNodeId": "helper",
134
+ "toPort": ["tools", 0]
135
+ },
136
+ {
137
+ "edgeId": "e-compile-writer",
138
+ "fromNodeId": "compile",
139
+ "fromPort": ["tools", 0],
140
+ "toNodeId": "writer",
141
+ "toPort": ["tools", 0]
142
+ },
116
143
  {
117
144
  "edgeId": "e-chat-helper",
118
145
  "fromNodeId": "chat",
@@ -1,4 +1,4 @@
1
- import type { RuntimeRunnerEvent, RuntimeRunnerStatus } from '@langflower/runtime';
1
+ import { type RuntimeRunnerEvent, type RuntimeRunnerStatus } from '@langflower/runtime';
2
2
  import type { ExecutionProgressStatus } from '../types/langflower-server.js';
3
3
  /** Terminal settle values of {@link ExecutionProgressStatus}. */
4
4
  export type TerminalExecutionProgressStatus = Extract<ExecutionProgressStatus, 'completed' | 'failed' | 'completed_with_errors'>;
@@ -1,3 +1,4 @@
1
+ import { isPortTelemetry, } from '@langflower/runtime';
1
2
  /**
2
3
  * Derive coarse execution progress from runner status + the recorded feed.
3
4
  *
@@ -12,9 +13,9 @@ export const deriveExecutionProgressStatus = (runnerStatus, events) => {
12
13
  if (runnerStatus === 'stopped') {
13
14
  return 'stopped';
14
15
  }
15
- const portEvents = events.filter((event) => event.kind === 'output-emitted' || event.kind === 'input-received');
16
- const hasError = portEvents.some((event) => event.state === 'error');
17
- const hasValue = portEvents.some((event) => event.state === 'value');
16
+ const portEvents = events.filter(isPortTelemetry);
17
+ const hasError = portEvents.some((event) => event[3] === 'error');
18
+ const hasValue = portEvents.some((event) => event[3] === 'value');
18
19
  if (hasError && hasValue) {
19
20
  return 'completed_with_errors';
20
21
  }
@@ -1,15 +1,15 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { deriveExecutionProgressStatus, formatRunSettleLine, terminalExecutionProgressStatus, } from './derive-run-settle-outcome.js';
3
- const output = (state) => ({
4
- kind: 'output-emitted',
5
- runId: 'run-1',
6
- nodeId: 'n1',
7
- portId: 'out',
8
- portIdx: 0,
9
- edgeIds: [],
3
+ const output = (state) => [
4
+ 'out',
5
+ 'n1',
6
+ 'out',
10
7
  state,
11
- value: state === 'error' ? new Error('boom') : 'ok',
12
- });
8
+ state === 'error' ? new Error('boom') : 'ok',
9
+ 0,
10
+ [],
11
+ null,
12
+ ];
13
13
  describe('deriveExecutionProgressStatus', () => {
14
14
  it('passes through running and stopped', () => {
15
15
  expect(deriveExecutionProgressStatus('running', [])).toBe('running');
@@ -1,4 +1,4 @@
1
- import type { RuntimeEdge, RuntimeRunnerEvent } from '@langflower/runtime';
1
+ import type { PortTelemetry, RuntimeDoneTelemetry, RuntimeEdge } from '@langflower/runtime';
2
2
  import type { DividerPositions, ExecutionFeedSnapshotPayload, RunnerSnapshotPayload, SessionStateSnapshotPayload, ToolConfigSnapshotPayload } from './types/langflower-bootstrap.js';
3
3
  import type { LangflowerConfigDraftDiscardRequestedPayload, LangflowerConfigDraftPatchRequestedPayload, LangflowerConfigDraftSnapshotPayload, LangflowerConfigSaveRequestedPayload, LangflowerConfigSnapshotPayload, LangflowerModelsCatalogSnapshotPayload, RunnerPermissionAskPayload, RunnerPermissionReplyPayload } from './types/langflower-config.js';
4
4
  import type { RunnerCheckpointDiscardRequestedPayload, RunnerCheckpointsSnapshotPayload, RunnerResumeFailedPayload, RunnerResumeRequestedPayload, WorkflowCheckpointSummary } from './types/workflow-checkpoint.js';
@@ -53,8 +53,7 @@ import type { CanvasViewport, WorkflowCurrentSnapshotPayload, WorkflowCurrentSta
53
53
  * broadcast `workflow.*.snapshot`.
54
54
  *
55
55
  * **Runtime after reconnect:** hydrate the log / port state from
56
- * `executionFeed.snapshot`, then append live `runner.output-emitted`,
57
- * `runner.input-received`, `runner.done`, … — no replay of the full runner
56
+ * `executionFeed.snapshot`, then append live `runner.port`, `runner.done`, … — no replay of the full runner
58
57
  * history on every mutation, only the dedicated feed snapshot plus new frames.
59
58
  *
60
59
  * Partials: {@link editorConfig} | {@link runnerConfig} |
@@ -404,21 +403,14 @@ export declare const langflowerWsConfig: {
404
403
  */
405
404
  readonly 'runner.interrupted': import("@langflower/websocket-bridge").WsBridgeMessageDefinition<"cancel">;
406
405
  /**
407
- * Output port signal — {@link RuntimeRunnerEvent} with
408
- * `kind === 'output-emitted'`.
406
+ * Port signal — {@link PortTelemetry}; direction at `payload[0]` (`'in'` | `'out'`).
409
407
  */
410
- readonly 'runner.output-emitted': import("@langflower/websocket-bridge").WsBridgeMessageDefinition<RuntimeRunnerEvent>;
408
+ readonly 'runner.port': import("@langflower/websocket-bridge").WsBridgeMessageDefinition<PortTelemetry>;
411
409
  /**
412
- * Input port signal — {@link RuntimeRunnerEvent} with
413
- * `kind === 'input-received'` (wires, seeds).
414
- */
415
- readonly 'runner.input-received': import("@langflower/websocket-bridge").WsBridgeMessageDefinition<RuntimeRunnerEvent>;
416
- /**
417
- * Natural run end — {@link RuntimeRunnerEvent} with `kind === 'done'`
418
- * (empty graph, {@link RuntimeNode.stopsRun}, or forced complete).
410
+ * Natural run end — {@link RuntimeDoneTelemetry}.
419
411
  * Runner status becomes `'idle'`.
420
412
  */
421
- readonly 'runner.done': import("@langflower/websocket-bridge").WsBridgeMessageDefinition<RuntimeRunnerEvent>;
413
+ readonly 'runner.done': import("@langflower/websocket-bridge").WsBridgeMessageDefinition<RuntimeDoneTelemetry>;
422
414
  /**
423
415
  * Runtime permission ask for a gated harness tool call (feed + composer).
424
416
  * Stays inside the internal tool loop — not a graph HITL edge.
@@ -242,18 +242,11 @@ const runnerConfig = {
242
242
  */
243
243
  'runner.interrupted': message(),
244
244
  /**
245
- * Output port signal — {@link RuntimeRunnerEvent} with
246
- * `kind === 'output-emitted'`.
245
+ * Port signal — {@link PortTelemetry}; direction at `payload[0]` (`'in'` | `'out'`).
247
246
  */
248
- 'runner.output-emitted': message(),
247
+ 'runner.port': message(),
249
248
  /**
250
- * Input port signal — {@link RuntimeRunnerEvent} with
251
- * `kind === 'input-received'` (wires, seeds).
252
- */
253
- 'runner.input-received': message(),
254
- /**
255
- * Natural run end — {@link RuntimeRunnerEvent} with `kind === 'done'`
256
- * (empty graph, {@link RuntimeNode.stopsRun}, or forced complete).
249
+ * Natural run end — {@link RuntimeDoneTelemetry}.
257
250
  * Runner status becomes `'idle'`.
258
251
  */
259
252
  'runner.done': message(),
@@ -595,8 +588,7 @@ const workflowManagerConfig = {
595
588
  * broadcast `workflow.*.snapshot`.
596
589
  *
597
590
  * **Runtime after reconnect:** hydrate the log / port state from
598
- * `executionFeed.snapshot`, then append live `runner.output-emitted`,
599
- * `runner.input-received`, `runner.done`, … — no replay of the full runner
591
+ * `executionFeed.snapshot`, then append live `runner.port`, `runner.done`, … — no replay of the full runner
600
592
  * history on every mutation, only the dedicated feed snapshot plus new frames.
601
593
  *
602
594
  * Partials: {@link editorConfig} | {@link runnerConfig} |
@@ -35,6 +35,12 @@ export const DOMAIN_PACK_TOOL_OPTIONS = {
35
35
  { value: 'update_memory_section', title: 'update_memory_section' },
36
36
  { value: 'create_memory_file', title: 'create_memory_file' },
37
37
  ],
38
+ 'common-langflower-tools': [
39
+ {
40
+ value: 'compile_custom_nodes',
41
+ title: 'compile_custom_nodes',
42
+ },
43
+ ],
38
44
  };
39
45
  const readToolMetaFromNode = (node) => {
40
46
  const toolId = String(node.inputs.toolId ?? '').trim();
@@ -38,6 +38,36 @@ describe('resolveWiredToolOptions', () => {
38
38
  'update_memory_section',
39
39
  ].sort());
40
40
  });
41
+ it('expands langflower tools pack into compile_custom_nodes', () => {
42
+ const options = resolveWiredToolOptions({
43
+ nodes: [
44
+ {
45
+ id: 'compile',
46
+ type: 'common-langflower-tools',
47
+ params: {},
48
+ inputs: {},
49
+ ui: { position: { x: 0, y: 0 } },
50
+ },
51
+ {
52
+ id: 'llm',
53
+ type: 'common-fake-llm',
54
+ params: {},
55
+ inputs: {},
56
+ ui: { position: { x: 0, y: 0 } },
57
+ },
58
+ ],
59
+ edges: [
60
+ {
61
+ edgeId: 'e1',
62
+ fromNodeId: 'compile',
63
+ fromPort: ['tools', 0],
64
+ toNodeId: 'llm',
65
+ toPort: ['tools', 0],
66
+ },
67
+ ],
68
+ }, 'llm');
69
+ expect(options.map((o) => o.value)).toEqual(['compile_custom_nodes']);
70
+ });
41
71
  it('maps wired tool-registration edges to select options with description', () => {
42
72
  const options = resolveWiredToolOptions({
43
73
  nodes: [
@@ -2,7 +2,7 @@
2
2
  * Wait / request helpers over {@link langflowerWsConfig} client subjects.
3
3
  * Shared by integration tests and `@langflower/mcp` (no filesystem I/O).
4
4
  */
5
- import type { NodeId, RunId, RuntimeRunnerEvent } from '@langflower/runtime';
5
+ import type { NodeId, PortTelemetry, RunId, RuntimeRunnerEvent } from '@langflower/runtime';
6
6
  import type { WsBridgeClientApi } from '@langflower/websocket-bridge';
7
7
  import { type Observable } from 'rxjs';
8
8
  import { langflowerWsConfig } from './langflower-bus-config.js';
@@ -35,23 +35,16 @@ export declare const requestWorkflowDeleteSnapshot: (client: LangflowerWsClient,
35
35
  export declare const startRunner: (client: LangflowerWsClient) => Promise<RunId>;
36
36
  export declare const startRunnerFromNode: (client: LangflowerWsClient, nodeId: NodeId) => Promise<RunId>;
37
37
  export declare const interruptRunner: (client: LangflowerWsClient) => Promise<void>;
38
- type InputReceivedEvent = Extract<RuntimeRunnerEvent, {
39
- kind: 'input-received';
40
- }>;
41
- export declare const sendHitlInput: (client: LangflowerWsClient, payload: Parameters<LangflowerWsClient["runner.hitl.event"]["next"]>[0], runId?: string) => Promise<InputReceivedEvent>;
42
- type OutputEmittedEvent = Extract<RuntimeRunnerEvent, {
43
- kind: 'output-emitted';
44
- state: 'value';
45
- }>;
38
+ export declare const sendHitlInput: (client: LangflowerWsClient, payload: Parameters<LangflowerWsClient["runner.hitl.event"]["next"]>[0]) => Promise<PortTelemetry>;
39
+ type OutputPortTelemetry = PortTelemetry & {
40
+ readonly 3: 'value';
41
+ };
46
42
  export declare const waitForRunnerOutput: (client: LangflowerWsClient, match: {
47
43
  readonly nodeId: string;
48
44
  readonly portId: string;
49
- readonly runId?: string;
50
45
  readonly predicate?: (value: unknown) => boolean;
51
- }) => Promise<OutputEmittedEvent>;
52
- export declare const waitForRunnerDone: (client: LangflowerWsClient, runId?: string) => Promise<Extract<RuntimeRunnerEvent, {
53
- kind: "done";
54
- }>>;
46
+ }) => Promise<OutputPortTelemetry>;
47
+ export declare const waitForRunnerDone: (client: LangflowerWsClient, runId?: string) => Promise<Extract<RuntimeRunnerEvent, readonly ["done"] | readonly ["done", RunId]>>;
55
48
  export declare const waitExecutionFeedSnapshot: (client: LangflowerWsClient, predicate?: (snap: ExecutionFeedSnapshotPayload | null) => boolean) => Promise<ExecutionFeedSnapshotPayload | null>;
56
49
  /**
57
50
  * Await the next value on a typed inbound bus stream (with optional timeout).
@@ -2,6 +2,7 @@
2
2
  * Wait / request helpers over {@link langflowerWsConfig} client subjects.
3
3
  * Shared by integration tests and `@langflower/mcp` (no filesystem I/O).
4
4
  */
5
+ import { isPortTelemetry, isRuntimeDone } from '@langflower/runtime';
5
6
  import { filter, firstValueFrom, take, timeout } from 'rxjs';
6
7
  const asRunId = (value) => {
7
8
  if (value === false) {
@@ -85,24 +86,23 @@ export const interruptRunner = async (client) => {
85
86
  client['runner.interrupt.requested'].next('cancel');
86
87
  await interrupted$;
87
88
  };
88
- export const sendHitlInput = async (client, payload, runId) => {
89
- const received$ = firstValueFrom(client['runner.input-received'].pipe(filter((event) => event.kind === 'input-received' &&
90
- event.nodeId === payload.nodeId &&
91
- event.portId === payload.portId &&
92
- (runId === undefined || event.runId === runId)), take(1)));
89
+ export const sendHitlInput = async (client, payload) => {
90
+ const received$ = firstValueFrom(client['runner.port'].pipe(filter((event) => isPortTelemetry(event) &&
91
+ event[0] === 'in' &&
92
+ event[1] === payload.nodeId &&
93
+ event[2] === payload.portId), take(1)));
93
94
  client['runner.hitl.event'].next(payload);
94
95
  return received$;
95
96
  };
96
- export const waitForRunnerOutput = async (client, match) => firstValueFrom(client['runner.output-emitted'].pipe(filter((event) => event.kind === 'output-emitted' &&
97
- event.state === 'value' &&
98
- event.nodeId === match.nodeId &&
99
- event.portId === match.portId &&
100
- (match.runId === undefined ||
101
- event.runId === match.runId) &&
97
+ export const waitForRunnerOutput = async (client, match) => firstValueFrom(client['runner.port'].pipe(filter((event) => isPortTelemetry(event) &&
98
+ event[0] === 'out' &&
99
+ event[3] === 'value' &&
100
+ event[1] === match.nodeId &&
101
+ event[2] === match.portId &&
102
102
  (match.predicate === undefined ||
103
- match.predicate(event.value))), take(1)));
104
- export const waitForRunnerDone = async (client, runId) => firstValueFrom(client['runner.done'].pipe(filter((event) => event.kind === 'done' &&
105
- (runId === undefined || event.runId === runId)), take(1)));
103
+ match.predicate(event[4]))), take(1)));
104
+ export const waitForRunnerDone = async (client, runId) => firstValueFrom(client['runner.done'].pipe(filter((event) => isRuntimeDone(event) &&
105
+ (runId === undefined || event[1] === runId)), take(1)));
106
106
  export const waitExecutionFeedSnapshot = async (client, predicate = () => true) => firstValueFrom(client['executionFeed.snapshot'].pipe(filter(predicate), take(1)));
107
107
  /**
108
108
  * Await the next value on a typed inbound bus stream (with optional timeout).
@@ -1,2 +1,3 @@
1
1
  import type { WsBridgeCodec } from './bridge-types.js';
2
+ export declare const encodeBridgeFrame: (transportDir: "in" | "out", busType: string, payload: unknown, ts?: string) => string;
2
3
  export declare const defaultWsBridgeCodec: WsBridgeCodec;
@@ -1,22 +1,22 @@
1
+ const isBridgeFrame = (value) => Array.isArray(value) &&
2
+ value.length === 4 &&
3
+ typeof value[0] === 'string' &&
4
+ (value[1] === 'in' || value[1] === 'out') &&
5
+ typeof value[2] === 'string';
6
+ export const encodeBridgeFrame = (transportDir, busType, payload, ts = new Date().toISOString()) => JSON.stringify([ts, transportDir, busType, payload]);
1
7
  export const defaultWsBridgeCodec = {
2
- encode(event) {
3
- return JSON.stringify(event);
8
+ encode(event, transportDir) {
9
+ return encodeBridgeFrame(transportDir, event.type, event.payload);
4
10
  },
5
11
  decode(raw) {
6
12
  try {
7
13
  const parsed = JSON.parse(raw);
8
- if (typeof parsed !== 'object' ||
9
- parsed === null ||
10
- Array.isArray(parsed)) {
11
- return null;
12
- }
13
- const record = parsed;
14
- if (typeof record['type'] !== 'string' || !('payload' in record)) {
14
+ if (!isBridgeFrame(parsed)) {
15
15
  return null;
16
16
  }
17
17
  return {
18
- type: record['type'],
19
- payload: record['payload'],
18
+ type: parsed[2],
19
+ payload: parsed[3],
20
20
  };
21
21
  }
22
22
  catch {
@@ -19,6 +19,6 @@ export function decodeInboundFrame(config, codec, raw, section) {
19
19
  };
20
20
  }
21
21
  return {
22
- error: createWsBridgeError('INVALID_ENVELOPE', 'Frame must be a { type, payload } object'),
22
+ error: createWsBridgeError('INVALID_ENVELOPE', 'Frame must be a bridge tuple [ts, transportDir, busType, payload]'),
23
23
  };
24
24
  }
@@ -5,6 +5,6 @@ export type WsBridgeMessageSection = keyof Pick<WsBridgeConfig, 'fromClientToSer
5
5
  export declare function readMessageKeys(config: WsBridgeConfig, section: WsBridgeMessageSection): readonly string[];
6
6
  export declare function createSubjectMap(keys: readonly string[]): Record<string, Subject<unknown>>;
7
7
  export declare function toObservables(subjects: Record<string, Subject<unknown>>): Record<string, Observable<unknown>>;
8
- export declare function wireOutgoingSubjects(subjects: Record<string, Subject<unknown>>, send: (event: WsBridgeEvent) => void): Subscription[];
8
+ export declare function wireOutgoingSubjects(subjects: Record<string, Subject<unknown>>, send: (event: WsBridgeEvent, transportDir: 'in' | 'out') => void, transportDir: 'in' | 'out'): Subscription[];
9
9
  export declare function routeInboundEvent(event: WsBridgeEvent, subjects: Record<string, Subject<unknown>>, clientId?: string): boolean;
10
10
  export declare function completeSubjects(subjects: Record<string, Subject<unknown>>): void;
@@ -16,9 +16,9 @@ export function toObservables(subjects) {
16
16
  }
17
17
  return observables;
18
18
  }
19
- export function wireOutgoingSubjects(subjects, send) {
19
+ export function wireOutgoingSubjects(subjects, send, transportDir) {
20
20
  return Object.entries(subjects).map(([type, subject]) => subject.subscribe((payload) => {
21
- send({ type, payload });
21
+ send({ type, payload }, transportDir);
22
22
  }));
23
23
  }
24
24
  export function routeInboundEvent(event, subjects, clientId) {
@@ -12,8 +12,15 @@ export type WsBridgeEvent<Payload = unknown> = {
12
12
  readonly type: string;
13
13
  readonly payload: Payload;
14
14
  };
15
+ /** Wire + log line: `[ts, transportDir, busType, payload]`. */
16
+ export type BridgeFrame = readonly [
17
+ ts: string,
18
+ transportDir: 'in' | 'out',
19
+ busType: string,
20
+ payload: unknown
21
+ ];
15
22
  export type WsBridgeCodec = {
16
- encode(event: WsBridgeEvent): string;
23
+ encode(event: WsBridgeEvent, transportDir: 'in' | 'out'): string;
17
24
  decode(raw: string): WsBridgeEvent | null;
18
25
  };
19
26
  export type WsBridgeConfig<ClientToServer extends WsBridgeMessageConfig = WsBridgeMessageConfig, ServerToClient extends WsBridgeMessageConfig = WsBridgeMessageConfig> = {
@@ -84,6 +91,11 @@ export type WsBridgeServer<C extends WsBridgeConfig> = {
84
91
  readonly errors$: Observable<WsBridgeError>;
85
92
  readonly status$: Observable<WsBridgeStatus>;
86
93
  close(): void;
94
+ /**
95
+ * Push a client-to-server event as if a socket sent it (in-process
96
+ * hosts). Inbound channels stay Observables — not Subjects.
97
+ */
98
+ injectInbound<K extends WsBridgeServerInboundKey<C>>(type: K, payload: WsBridgeServerInboundPayload<C, K>, clientId?: string): void;
87
99
  };
88
100
  export type WsBridgeServerApi<C extends WsBridgeConfig> = WsBridgeServer<C> & WsBridgeServerIncoming<C> & WsBridgeServerOutgoing<C>;
89
101
  /** Type carrier for config entries — no casts in consumer config. */
@@ -89,7 +89,7 @@ export function createClient(config, options = {}) {
89
89
  const errorsSubject = new Subject();
90
90
  const statusSubject = new BehaviorSubject('connecting');
91
91
  const socket = connectSocket(url);
92
- const sendEvent = (event) => {
92
+ const sendEvent = (event, transportDir) => {
93
93
  if (socket.readyState !== OPEN) {
94
94
  errorsSubject.next({
95
95
  code: 'TRANSPORT_NOT_OPEN',
@@ -97,11 +97,11 @@ export function createClient(config, options = {}) {
97
97
  });
98
98
  return;
99
99
  }
100
- socket.send(codec.encode(event));
100
+ socket.send(codec.encode(event, transportDir));
101
101
  };
102
102
  // Wire at construction so early `.next` is not silently dropped; sendEvent
103
103
  // still rejects until the socket is OPEN.
104
- const wireSubscriptions = wireOutgoingSubjects(outgoingSubjects, sendEvent);
104
+ const wireSubscriptions = wireOutgoingSubjects(outgoingSubjects, sendEvent, 'in');
105
105
  socket.onOpen(() => {
106
106
  statusSubject.next('connected');
107
107
  });
@@ -18,14 +18,14 @@ export function createServer(config, options = {}) {
18
18
  const errorsSubject = new Subject();
19
19
  const statusSubject = new BehaviorSubject('connecting');
20
20
  const clients = new Set();
21
- const wireSubscriptions = wireOutgoingSubjects(broadcastSubjects, (event) => {
22
- const raw = codec.encode(event);
21
+ const wireSubscriptions = wireOutgoingSubjects(broadcastSubjects, (event, transportDir) => {
22
+ const raw = codec.encode(event, transportDir);
23
23
  for (const client of clients) {
24
24
  if (client.ws.readyState === client.ws.OPEN) {
25
25
  client.ws.send(raw);
26
26
  }
27
27
  }
28
- });
28
+ }, 'out');
29
29
  const wss = options.httpServer !== undefined
30
30
  ? new WebSocketServer({ server: options.httpServer, path })
31
31
  : new WebSocketServer({ host, port, path });
@@ -57,12 +57,12 @@ export function createServer(config, options = {}) {
57
57
  const outgoingSubjects = createSubjectMap(serverToClientKeys);
58
58
  const disconnectedSubject = new Subject();
59
59
  const connectedSubject = new BehaviorSubject(true);
60
- const subscriptions = wireOutgoingSubjects(outgoingSubjects, (event) => {
60
+ const subscriptions = wireOutgoingSubjects(outgoingSubjects, (event, transportDir) => {
61
61
  if (ws.readyState !== ws.OPEN) {
62
62
  return;
63
63
  }
64
- ws.send(codec.encode(event));
65
- });
64
+ ws.send(codec.encode(event, transportDir));
65
+ }, 'out');
66
66
  const closeClient = () => {
67
67
  if (ws.readyState === ws.OPEN || ws.readyState === ws.CONNECTING) {
68
68
  ws.close();
@@ -108,6 +108,12 @@ export function createServer(config, options = {}) {
108
108
  connections$: connectionsSubject.asObservable(),
109
109
  errors$: errorsSubject.asObservable(),
110
110
  status$: statusSubject.asObservable(),
111
+ injectInbound(type, payload, clientId = 'in-process') {
112
+ const routed = routeInboundEvent({ type, payload }, inboundSubjects, clientId);
113
+ if (!routed) {
114
+ throw new Error(`Unknown inbound event: ${String(type)}`);
115
+ }
116
+ },
111
117
  close() {
112
118
  statusSubject.next('disconnected');
113
119
  for (const client of [...clients]) {
@@ -14,6 +14,14 @@
14
14
  "./create-server": {
15
15
  "types": "./dist/create-server.d.ts",
16
16
  "import": "./dist/create-server.js"
17
+ },
18
+ "./bridge-codec": {
19
+ "types": "./dist/bridge-codec.d.ts",
20
+ "import": "./dist/bridge-codec.js"
21
+ },
22
+ "./bridge-codec.js": {
23
+ "types": "./dist/bridge-codec.d.ts",
24
+ "import": "./dist/bridge-codec.js"
17
25
  }
18
26
  },
19
27
  "dependencies": {