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.
- package/package.json +1 -1
- package/ui-dist/{chunk-Y6VMBLSJ.js → chunk-7UMVYN3A.js} +1 -1
- package/ui-dist/{chunk-6DQ2XSRW.js → chunk-MDGXX73Z.js} +3 -3
- package/ui-dist/index.html +1 -1
- package/ui-dist/main-2JJGCNTD.js +313 -0
- package/vendor/common-nodes/dist/ai/chat-completion-stream.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/critique/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/critique/node.js +2 -2
- package/vendor/common-nodes/dist/ai/fake-llm/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/features/chat-completion-stream.d.ts +53 -0
- package/vendor/common-nodes/dist/ai/features/chat-completion-stream.js +1 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.d.ts +13 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.js +17 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.js +113 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.d.ts +28 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.js +194 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.d.ts +9 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.js +21 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.js +216 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.d.ts +125 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.js +39 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.js +59 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.d.ts +1 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.js +7 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.d.ts +43 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.js +96 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.d.ts +32 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.js +58 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.d.ts +80 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.js +681 -0
- package/vendor/common-nodes/dist/ai/features/llm-role-preset.d.ts +69 -0
- package/vendor/common-nodes/dist/ai/features/llm-role-preset.js +265 -0
- package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.d.ts +148 -0
- package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.js +198 -0
- package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.d.ts +21 -0
- package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.js +118 -0
- package/vendor/common-nodes/dist/ai/features/openai/context-length-error.d.ts +14 -0
- package/vendor/common-nodes/dist/ai/features/openai/context-length-error.js +63 -0
- package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.d.ts +19 -0
- package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.js +182 -0
- package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.d.ts +28 -0
- package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.js +52 -0
- package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.d.ts +31 -0
- package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.js +326 -0
- package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.d.ts +14 -0
- package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.js +21 -0
- package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.d.ts +30 -0
- package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.js +132 -0
- package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.d.ts +20 -0
- package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.js +70 -0
- package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.d.ts +35 -0
- package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.js +106 -0
- package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.d.ts +9 -0
- package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.js +21 -0
- package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.d.ts +13 -0
- package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.js +23 -0
- package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.d.ts +10 -0
- package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.js +8 -0
- package/vendor/common-nodes/dist/ai/features/run-host-services.d.ts +54 -0
- package/vendor/common-nodes/dist/ai/features/run-host-services.js +29 -0
- package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.d.ts +17 -0
- package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.js +61 -0
- package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.d.ts +39 -0
- package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.js +43 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.d.ts +14 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.js +18 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.d.ts +80 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.js +76 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.d.ts +113 -0
- package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.js +131 -0
- package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.d.ts +6 -0
- package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.js +30 -0
- package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.d.ts +13 -0
- package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.js +17 -0
- package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.d.ts +28 -0
- package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.js +194 -0
- package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-reducer.js +36 -0
- package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.d.ts +35 -0
- package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.js +19 -0
- package/vendor/common-nodes/dist/ai/llm-loop/normalize-llm-recovery-policy.js +52 -9
- package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.d.ts +8 -2
- package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.js +43 -13
- package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.d.ts +3 -5
- package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.js +116 -1
- package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.d.ts +82 -0
- package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.js +95 -0
- package/vendor/common-nodes/dist/ai/llm-session-shell.d.ts +4 -9
- package/vendor/common-nodes/dist/ai/llm-session-shell.js +2 -4
- package/vendor/common-nodes/dist/ai/nodes/critique/node.d.ts +588 -0
- package/vendor/common-nodes/dist/ai/nodes/critique/node.js +240 -0
- package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.d.ts +571 -0
- package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.js +208 -0
- package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.d.ts +587 -0
- package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.js +91 -0
- package/vendor/common-nodes/dist/ai/nodes/review/node.d.ts +593 -0
- package/vendor/common-nodes/dist/ai/nodes/review/node.js +240 -0
- package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.d.ts +630 -0
- package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.js +302 -0
- package/vendor/common-nodes/dist/ai/openai/create-chat-completion-stream.js +6 -0
- package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.d.ts +2 -0
- package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.js +18 -0
- package/vendor/common-nodes/dist/ai/openai-llm/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/review/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/review/node.js +2 -2
- package/vendor/common-nodes/dist/ai/sub-agent/node.d.ts +246 -0
- package/vendor/common-nodes/dist/ai/sub-agent/node.js +2 -2
- package/vendor/common-nodes/dist/catalog.js +7 -5
- package/vendor/common-nodes/dist/compile-custom-nodes/node.d.ts +21 -0
- package/vendor/common-nodes/dist/compile-custom-nodes/node.js +45 -0
- package/vendor/common-nodes/dist/crawl/crawl/node.js +1 -1
- package/vendor/common-nodes/dist/crawl/fetch-url/node.js +1 -1
- package/vendor/common-nodes/dist/flow/repeat/node.js +6 -1
- package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.d.ts +18 -0
- package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.js +29 -0
- package/vendor/common-nodes/dist/langflower-tools/node.d.ts +20 -0
- package/vendor/common-nodes/dist/langflower-tools/node.js +77 -0
- package/vendor/common-nodes/dist/text/append-file/node.js +1 -1
- package/vendor/common-nodes/dist/text/read-file/node.js +1 -1
- package/vendor/common-nodes/dist/text/write-file/node.js +1 -1
- package/vendor/common-nodes/dist/tools/inventory-tool-round.d.ts +2 -2
- package/vendor/common-nodes/package.json +10 -10
- package/vendor/compiler/dist/compile-project-nodes.d.ts +2 -1
- package/vendor/compiler/dist/compile-project-nodes.js +35 -6
- package/vendor/compiler/dist/resolve-host-types.d.ts +0 -5
- package/vendor/compiler/dist/resolve-host-types.js +0 -8
- package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.d.ts +1 -1
- package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.js +1 -1
- package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.d.ts +8 -0
- package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.js +14 -0
- package/vendor/runtime/dist/runtime-editor.d.ts +5 -1
- package/vendor/runtime/dist/runtime-editor.js +19 -0
- package/vendor/runtime/dist/runtime-runner.js +17 -17
- package/vendor/runtime/dist/runtime.d.ts +2 -1
- package/vendor/runtime/dist/runtime.js +1 -0
- package/vendor/runtime/dist/testing/workflows/workflow-events.d.ts +8 -6
- package/vendor/runtime/dist/testing/workflows/workflow-events.js +19 -31
- package/vendor/runtime/dist/types.d.ts +33 -38
- package/vendor/runtime/dist/types.js +2 -1
- package/vendor/server/dist/bridge/attach-langflower-bridge.js +3 -2
- package/vendor/server/dist/bridge/bridge-event-log.js +17 -102
- package/vendor/server/dist/bridge/build-execution-context.d.ts +5 -2
- package/vendor/server/dist/bridge/build-execution-context.js +45 -5
- package/vendor/server/dist/bridge/forward-runner-event.d.ts +1 -1
- package/vendor/server/dist/bridge/forward-runner-event.js +7 -12
- package/vendor/server/dist/bridge/get-live-wired-tools.d.ts +12 -0
- package/vendor/server/dist/bridge/get-live-wired-tools.js +80 -0
- package/vendor/server/dist/bridge/langflower-tools-rpc.d.ts +7 -0
- package/vendor/server/dist/bridge/langflower-tools-rpc.js +29 -0
- package/vendor/server/dist/bridge/settings-draft-controller.js +26 -3
- package/vendor/server/dist/bridge/wire-custom-palette-handlers.d.ts +2 -1
- package/vendor/server/dist/bridge/wire-custom-palette-handlers.js +3 -5
- package/vendor/server/dist/bridge/wire-runner-handlers.js +15 -8
- package/vendor/server/dist/checkpoint/run-checkpoint-session.d.ts +1 -1
- package/vendor/server/dist/checkpoint/run-checkpoint-session.js +10 -9
- package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.d.ts +10 -0
- package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.js +23 -0
- package/vendor/server/dist/workflow/apply-editor-mutation.d.ts +5 -0
- package/vendor/server/dist/workflow/apply-editor-mutation.js +32 -0
- package/vendor/server/skeleton/instructions.md +9 -5
- package/vendor/server/skeleton/nodes/my-nodes/README.md +4 -3
- package/vendor/server/skeleton/schemas/langflower-config.schema.json +11 -1
- package/vendor/server/skeleton/skills/langflower-helper/SKILL.md +49 -19
- package/vendor/server/skeleton/skills/langflower-helper/architecture.md +22 -9
- package/vendor/server/skeleton/skills/langflower-helper/layout.md +15 -15
- package/vendor/server/skeleton/skills/langflower-node-writer/SKILL.md +19 -9
- package/vendor/server/skeleton/skills/langflower-workflow-writer/SKILL.md +14 -10
- package/vendor/server/skeleton/workflows/starter.json +30 -3
- package/vendor/shared/dist/execution/derive-run-settle-outcome.d.ts +1 -1
- package/vendor/shared/dist/execution/derive-run-settle-outcome.js +4 -3
- package/vendor/shared/dist/execution/derive-run-settle-outcome.test.js +9 -9
- package/vendor/shared/dist/langflower-bus-config.d.ts +6 -14
- package/vendor/shared/dist/langflower-bus-config.js +4 -12
- package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.js +6 -0
- package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.test.js +30 -0
- package/vendor/shared/dist/langflower-ws-waits.d.ts +7 -14
- package/vendor/shared/dist/langflower-ws-waits.js +14 -14
- package/vendor/websocket-bridge/dist/bridge-codec.d.ts +1 -0
- package/vendor/websocket-bridge/dist/bridge-codec.js +11 -11
- package/vendor/websocket-bridge/dist/bridge-frame.js +1 -1
- package/vendor/websocket-bridge/dist/bridge-subjects.d.ts +1 -1
- package/vendor/websocket-bridge/dist/bridge-subjects.js +2 -2
- package/vendor/websocket-bridge/dist/bridge-types.d.ts +13 -1
- package/vendor/websocket-bridge/dist/create-client.js +3 -3
- package/vendor/websocket-bridge/dist/create-server.js +12 -6
- package/vendor/websocket-bridge/package.json +8 -0
- 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-
|
|
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
|
|
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
|
|
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(
|
|
16
|
-
const hasError = portEvents.some((event) => event
|
|
17
|
-
const hasValue = portEvents.some((event) => event
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
portId: 'out',
|
|
8
|
-
portIdx: 0,
|
|
9
|
-
edgeIds: [],
|
|
3
|
+
const output = (state) => [
|
|
4
|
+
'out',
|
|
5
|
+
'n1',
|
|
6
|
+
'out',
|
|
10
7
|
state,
|
|
11
|
-
|
|
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 {
|
|
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.
|
|
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
|
-
*
|
|
408
|
-
* `kind === 'output-emitted'`.
|
|
406
|
+
* Port signal — {@link PortTelemetry}; direction at `payload[0]` (`'in'` | `'out'`).
|
|
409
407
|
*/
|
|
410
|
-
readonly 'runner.
|
|
408
|
+
readonly 'runner.port': import("@langflower/websocket-bridge").WsBridgeMessageDefinition<PortTelemetry>;
|
|
411
409
|
/**
|
|
412
|
-
*
|
|
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<
|
|
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
|
-
*
|
|
246
|
-
* `kind === 'output-emitted'`.
|
|
245
|
+
* Port signal — {@link PortTelemetry}; direction at `payload[0]` (`'in'` | `'out'`).
|
|
247
246
|
*/
|
|
248
|
-
'runner.
|
|
247
|
+
'runner.port': message(),
|
|
249
248
|
/**
|
|
250
|
-
*
|
|
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.
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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<
|
|
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
|
|
89
|
-
const received$ = firstValueFrom(client['runner.
|
|
90
|
-
event
|
|
91
|
-
event
|
|
92
|
-
|
|
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.
|
|
97
|
-
event
|
|
98
|
-
event
|
|
99
|
-
event
|
|
100
|
-
|
|
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
|
|
104
|
-
export const waitForRunnerDone = async (client, runId) => firstValueFrom(client['runner.done'].pipe(filter((event) => event
|
|
105
|
-
(runId === undefined || event
|
|
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,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
|
|
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 (
|
|
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:
|
|
19
|
-
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
|
|
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": {
|