langflower 0.0.8 → 0.0.10
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 +2 -2
- 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 +2 -2
- package/ui-dist/main-Z7CPFXFA.js +313 -0
- package/ui-dist/styles-2TMDAUD7.css +1 -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 +204 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.d.ts +120 -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 +29 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.js +44 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.d.ts +74 -0
- package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.js +658 -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 +141 -0
- package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.js +193 -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 +32 -0
- package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.js +93 -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 +40 -0
- package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.js +44 -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 +7 -0
- package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.js +31 -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 +227 -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 +201 -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 +84 -0
- package/vendor/common-nodes/dist/ai/nodes/review/node.d.ts +593 -0
- package/vendor/common-nodes/dist/ai/nodes/review/node.js +227 -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 +417 -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 +9 -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/mcp/mcp-http/node.d.ts +4 -4
- package/vendor/common-nodes/dist/mcp/mcp-http/node.js +9 -10
- package/vendor/common-nodes/dist/mcp/mcp-stdio/node.d.ts +4 -4
- package/vendor/common-nodes/dist/mcp/mcp-stdio/node.js +9 -10
- 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/collect-agent-tool-handles.d.ts +4 -4
- package/vendor/common-nodes/dist/tools/collect-agent-tool-handles.js +3 -11
- package/vendor/common-nodes/dist/tools/inventory-tool-round.d.ts +1 -11
- package/vendor/common-nodes/dist/tools/inventory-tool-round.js +0 -84
- package/vendor/common-nodes/dist/tools/tool-collection/node.d.ts +20 -0
- package/vendor/common-nodes/dist/tools/tool-collection/node.js +42 -0
- package/vendor/common-nodes/package.json +9 -13
- 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/compiler/package.json +1 -1
- package/vendor/node-sdk/dist/node-factory/define-llm-node/default-llm-ports.d.ts +3 -7
- package/vendor/node-sdk/dist/node-factory/define-llm-node/default-llm-ports.js +4 -44
- package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.d.ts +4 -6
- package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.js +4 -6
- package/vendor/node-sdk/dist/node-factory/define-llm-node/llm-inventory-wire.d.ts +1 -0
- package/vendor/node-sdk/dist/node-factory/define-llm-node/llm-inventory-wire.js +1 -0
- 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/node-sdk/dist/node-factory/define-mcp/mcp-handle.d.ts +3 -4
- package/vendor/node-sdk/dist/node-factory/define-mcp/mcp-handle.js +1 -1
- package/vendor/node-sdk/dist/node-factory/define-reactive-node/types.d.ts +2 -4
- package/vendor/node-sdk/dist/node-factory/define-reactive-node/ui-schema-inference.d.ts +1 -1
- package/vendor/node-sdk/package.json +1 -1
- package/vendor/runtime/dist/port-feed-override.d.ts +13 -0
- package/vendor/runtime/dist/port-feed-override.js +21 -0
- package/vendor/runtime/dist/port-signal-from-response.d.ts +15 -0
- package/vendor/runtime/dist/port-signal-from-response.js +48 -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.d.ts +8 -3
- package/vendor/runtime/dist/runtime-runner.js +108 -87
- package/vendor/runtime/dist/runtime.d.ts +3 -1
- package/vendor/runtime/dist/runtime.js +1 -0
- package/vendor/runtime/dist/testing/workflows/workflow-events.d.ts +10 -6
- package/vendor/runtime/dist/testing/workflows/workflow-events.js +21 -31
- package/vendor/runtime/dist/types.d.ts +52 -40
- package/vendor/runtime/dist/types.js +5 -1
- package/vendor/runtime/package.json +1 -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 +48 -8
- 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 +13 -0
- package/vendor/server/dist/bridge/get-live-wired-tools.js +83 -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/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 +17 -10
- package/vendor/server/dist/bridge/wire-workflow-handlers.js +23 -9
- 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/session/reset-session-execution-feed.d.ts +6 -0
- package/vendor/server/dist/session/reset-session-execution-feed.js +8 -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/nodes/my-nodes/package.json +1 -1
- package/vendor/server/skeleton/skills/langflower-helper/SKILL.md +82 -38
- package/vendor/server/skeleton/skills/langflower-helper/architecture.md +29 -10
- package/vendor/server/skeleton/skills/langflower-helper/layout.md +16 -15
- package/vendor/server/skeleton/skills/langflower-node-writer/SKILL.md +19 -9
- package/vendor/server/skeleton/skills/langflower-workflow-writer/SKILL.md +23 -15
- package/vendor/server/skeleton/workflows/kb-create.json +15 -43
- package/vendor/server/skeleton/workflows/kb-navigate.json +8 -22
- package/vendor/server/skeleton/workflows/simple-coder.json +18 -46
- package/vendor/server/skeleton/workflows/starter.json +35 -22
- 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 +18 -15
- 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 +9 -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-ECEWAM6V.js +0 -311
- package/ui-dist/styles-EOXODOI7.css +0 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ToolHandle } from '@langflower/node-sdk';
|
|
2
|
+
import type { LangflowerSession } from '../session/langflower-session.js';
|
|
3
|
+
/**
|
|
4
|
+
* Activate current editor `tools` / `subagent-registration` outputs
|
|
5
|
+
* (including post-swap instances) so a later inbound peek in
|
|
6
|
+
* {@link getLiveWiredTools} sees live handles.
|
|
7
|
+
*/
|
|
8
|
+
export declare const refreshLiveWiredToolPacks: (session: LangflowerSession) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Walk inbound `tools` edges on **current** editor instances (post-swap).
|
|
11
|
+
* Does not emit on the LLM tools port (ADR-016 session must not reset).
|
|
12
|
+
*/
|
|
13
|
+
export declare const getLiveWiredTools: (session: LangflowerSession, agentNodeId: string) => readonly ToolHandle[];
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
2
|
+
const isToolHandle = (value) => {
|
|
3
|
+
if (!isRecord(value)) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
return (typeof value.toolId === 'string' &&
|
|
7
|
+
typeof value.name === 'string' &&
|
|
8
|
+
typeof value.description === 'string' &&
|
|
9
|
+
typeof value.inputSchema === 'object' &&
|
|
10
|
+
value.inputSchema !== null &&
|
|
11
|
+
typeof value.invoke === 'function');
|
|
12
|
+
};
|
|
13
|
+
/** Flatten multi-wire values that may be single handles or arrays (packs). */
|
|
14
|
+
const flattenToolHandles = (wired) => wired.flatMap((item) => {
|
|
15
|
+
if (Array.isArray(item)) {
|
|
16
|
+
return item.filter(isToolHandle);
|
|
17
|
+
}
|
|
18
|
+
if (isToolHandle(item)) {
|
|
19
|
+
return [item];
|
|
20
|
+
}
|
|
21
|
+
return [];
|
|
22
|
+
});
|
|
23
|
+
const resolveToolsOutput = (outputs, portId) => {
|
|
24
|
+
const direct = outputs[portId];
|
|
25
|
+
if (direct !== undefined) {
|
|
26
|
+
return direct;
|
|
27
|
+
}
|
|
28
|
+
return Object.values(outputs).find((port) => port.meta.portId === portId);
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* One-shot subscribe to activate a freshly swapped instance without
|
|
32
|
+
* connecting into the LLM `tools` input.
|
|
33
|
+
*/
|
|
34
|
+
const peekPortValue = (port) => {
|
|
35
|
+
let peeked;
|
|
36
|
+
const sub = port.value$.subscribe((value) => {
|
|
37
|
+
peeked = value;
|
|
38
|
+
});
|
|
39
|
+
sub.unsubscribe();
|
|
40
|
+
return peeked;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Activate current editor `tools` / `subagent-registration` outputs
|
|
44
|
+
* (including post-swap instances) so a later inbound peek in
|
|
45
|
+
* {@link getLiveWiredTools} sees live handles.
|
|
46
|
+
*/
|
|
47
|
+
export const refreshLiveWiredToolPacks = (session) => {
|
|
48
|
+
for (const node of session.runtime.editor.getNodes()) {
|
|
49
|
+
for (const portId of ['tools', 'subagent-registration']) {
|
|
50
|
+
const port = resolveToolsOutput(node.outputs, portId);
|
|
51
|
+
if (port !== undefined) {
|
|
52
|
+
peekPortValue(port);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Walk inbound `tools` edges on **current** editor instances (post-swap).
|
|
59
|
+
* Does not emit on the LLM tools port (ADR-016 session must not reset).
|
|
60
|
+
*/
|
|
61
|
+
export const getLiveWiredTools = (session, agentNodeId) => {
|
|
62
|
+
const editor = session.runtime.editor;
|
|
63
|
+
const inbound = editor
|
|
64
|
+
.getEdges()
|
|
65
|
+
.filter((edge) => String(edge.toNodeId) === agentNodeId &&
|
|
66
|
+
edge.toPort[0] === 'tools');
|
|
67
|
+
const packs = [];
|
|
68
|
+
for (const edge of inbound) {
|
|
69
|
+
const source = editor.getNode(edge.fromNodeId);
|
|
70
|
+
if (source === false) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const port = resolveToolsOutput(source.outputs, edge.fromPort[0]);
|
|
74
|
+
if (port === undefined) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const peeked = peekPortValue(port);
|
|
78
|
+
if (peeked !== undefined) {
|
|
79
|
+
packs.push(peeked);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return flattenToolHandles(packs);
|
|
83
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LangflowerBusRequest } from '@langflower/common-nodes/ai/run-host-services';
|
|
2
|
+
import type { LangflowerBridge } from './langflower-bridge.types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Wait-then-emit RPC (MCP `emitAction` shape) over the **server** bridge.
|
|
5
|
+
* Does not import `@langflower/mcp`.
|
|
6
|
+
*/
|
|
7
|
+
export declare const createLangflowerToolsRpc: (bridge: LangflowerBridge) => LangflowerBusRequest;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { waitBusEvent } from '@langflower/shared/langflower-ws-waits';
|
|
2
|
+
/**
|
|
3
|
+
* In-process bus intents this pack may emit. Compile only for now.
|
|
4
|
+
* Later: `editor.addNode.requested`, `editor.removeNode.requested`,
|
|
5
|
+
* `editor.addEdge.requested`, `editor.removeEdge.requested`.
|
|
6
|
+
*/
|
|
7
|
+
const LANGFLOWER_TOOLS_INTENTS = ['customPalette.update.requested'];
|
|
8
|
+
const isAllowedIntent = (intent) => LANGFLOWER_TOOLS_INTENTS.includes(intent);
|
|
9
|
+
/**
|
|
10
|
+
* Wait-then-emit RPC (MCP `emitAction` shape) over the **server** bridge.
|
|
11
|
+
* Does not import `@langflower/mcp`.
|
|
12
|
+
*/
|
|
13
|
+
export const createLangflowerToolsRpc = (bridge) => {
|
|
14
|
+
return async (intent, payload) => {
|
|
15
|
+
if (!isAllowedIntent(intent)) {
|
|
16
|
+
throw new Error(`Langflower Tools does not allow intent: ${intent}`);
|
|
17
|
+
}
|
|
18
|
+
const resultPromise = waitBusEvent(bridge['customPalette.snapshot'], {
|
|
19
|
+
predicate: (snapshot) => snapshot.status !== 'compiling',
|
|
20
|
+
});
|
|
21
|
+
const body = payload !== null &&
|
|
22
|
+
typeof payload === 'object' &&
|
|
23
|
+
!Array.isArray(payload)
|
|
24
|
+
? payload
|
|
25
|
+
: {};
|
|
26
|
+
bridge.injectInbound(intent, body, 'langflower-tools');
|
|
27
|
+
return resultPromise;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Subscription } from 'rxjs';
|
|
2
2
|
import type { ServerContext } from '../server-context.js';
|
|
3
|
+
import type { LangflowerSession } from '../session/langflower-session.js';
|
|
3
4
|
import type { LangflowerBridge } from './langflower-bridge.types.js';
|
|
4
|
-
export declare const wireCustomPaletteHandlers: (bridge: LangflowerBridge, context: ServerContext) => Subscription;
|
|
5
|
+
export declare const wireCustomPaletteHandlers: (bridge: LangflowerBridge, context: ServerContext, session: LangflowerSession) => Subscription;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { compileAndHotSwapCustomNodes } from '../palette/compile-and-hot-swap-custom-nodes.js';
|
|
2
2
|
import { isInboundEvent } from './inbound-guards.js';
|
|
3
|
-
export const wireCustomPaletteHandlers = (bridge, context) => bridge['customPalette.update.requested'].subscribe(async (raw) => {
|
|
3
|
+
export const wireCustomPaletteHandlers = (bridge, context, session) => bridge['customPalette.update.requested'].subscribe(async (raw) => {
|
|
4
4
|
if (!isInboundEvent(raw)) {
|
|
5
5
|
return;
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
const snapshot = await context.customPaletteService.update(context.projectDir);
|
|
9
|
-
bridgeEmit(bridge, 'customPalette.snapshot', snapshot);
|
|
7
|
+
await compileAndHotSwapCustomNodes(session, context, bridge);
|
|
10
8
|
});
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { isPortTelemetry, isRuntimeDone, } from '@langflower/runtime';
|
|
1
2
|
import { buildWorkflowFingerprint, } from '@langflower/shared/langflower.js';
|
|
2
3
|
import { Subscription } from 'rxjs';
|
|
3
4
|
import { listResumableCheckpoints } from '../checkpoint/list-resumable-checkpoints.js';
|
|
4
5
|
import { resolveCheckpointBoundary } from '../checkpoint/resolve-checkpoint-boundary.js';
|
|
6
|
+
import { resetSessionExecutionFeed } from '../session/reset-session-execution-feed.js';
|
|
5
7
|
import { buildContextSeeds, applyObservableContextSeeds, } from './build-execution-context.js';
|
|
8
|
+
import { getLiveWiredTools } from './get-live-wired-tools.js';
|
|
9
|
+
import { createLangflowerToolsRpc } from './langflower-tools-rpc.js';
|
|
6
10
|
import { bridgeEmit, clientEmit } from './bridge-outbound.js';
|
|
7
11
|
import { findClientById } from './client-index.js';
|
|
8
12
|
import { isInboundEvent } from './inbound-guards.js';
|
|
@@ -35,11 +39,15 @@ export const wireRunnerHandlers = (bridge, context, session, checkpoints) => {
|
|
|
35
39
|
const emitPermissionAsk = (payload) => {
|
|
36
40
|
bridgeEmit(bridge, 'runner.permission.ask', payload);
|
|
37
41
|
};
|
|
42
|
+
const requestLangflowerBus = createLangflowerToolsRpc(bridge);
|
|
43
|
+
const liveWiredTools = (agentNodeId) => getLiveWiredTools(session, agentNodeId);
|
|
38
44
|
subscription.add(session.runtime.runner.events$.subscribe((event) => {
|
|
39
|
-
const
|
|
40
|
-
|
|
45
|
+
const [, nodeId, portId] = isPortTelemetry(event) ? event : [];
|
|
46
|
+
const boundary = isPortTelemetry(event) &&
|
|
47
|
+
event[0] === 'out' &&
|
|
48
|
+
typeof portId === 'string' &&
|
|
41
49
|
session.activeWorkflow !== null
|
|
42
|
-
? resolveCheckpointBoundary(session.activeWorkflow, String(
|
|
50
|
+
? resolveCheckpointBoundary(session.activeWorkflow, String(nodeId), portId)
|
|
43
51
|
: undefined;
|
|
44
52
|
const shouldPersist = checkpoints.observe(event, boundary === undefined
|
|
45
53
|
? undefined
|
|
@@ -57,7 +65,7 @@ export const wireRunnerHandlers = (bridge, context, session, checkpoints) => {
|
|
|
57
65
|
})
|
|
58
66
|
.catch(() => undefined);
|
|
59
67
|
}
|
|
60
|
-
if (event
|
|
68
|
+
if (isRuntimeDone(event)) {
|
|
61
69
|
void checkpoints
|
|
62
70
|
.markCompleted()
|
|
63
71
|
.then(async (summary) => {
|
|
@@ -83,7 +91,7 @@ export const wireRunnerHandlers = (bridge, context, session, checkpoints) => {
|
|
|
83
91
|
crypto.randomUUID());
|
|
84
92
|
// Lock before async seed build so workflow load cannot race in.
|
|
85
93
|
session.runnerStatus = 'running';
|
|
86
|
-
const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk));
|
|
94
|
+
const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk, requestLangflowerBus, liveWiredTools));
|
|
87
95
|
const initialPayload = mergeSeeds(contextSeeds, clientInitialPayload);
|
|
88
96
|
if (session.activeWorkflow !== null) {
|
|
89
97
|
checkpoints.beginRun(resolvedRunId, session.activeWorkflow);
|
|
@@ -111,7 +119,7 @@ export const wireRunnerHandlers = (bridge, context, session, checkpoints) => {
|
|
|
111
119
|
const resolvedRunId = (clientRunId ??
|
|
112
120
|
crypto.randomUUID());
|
|
113
121
|
session.runnerStatus = 'running';
|
|
114
|
-
const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk));
|
|
122
|
+
const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk, requestLangflowerBus, liveWiredTools));
|
|
115
123
|
const initialPayload = mergeSeeds(contextSeeds, clientInitialPayload);
|
|
116
124
|
if (session.activeWorkflow !== null) {
|
|
117
125
|
checkpoints.beginRun(resolvedRunId, session.activeWorkflow);
|
|
@@ -196,7 +204,7 @@ export const wireRunnerHandlers = (bridge, context, session, checkpoints) => {
|
|
|
196
204
|
return;
|
|
197
205
|
}
|
|
198
206
|
session.runnerStatus = 'running';
|
|
199
|
-
const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, checkpoint.runId, emitPermissionAsk));
|
|
207
|
+
const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, checkpoint.runId, emitPermissionAsk, requestLangflowerBus, liveWiredTools));
|
|
200
208
|
checkpoints.hydrateFromCheckpoint(checkpoint, workflow);
|
|
201
209
|
const resumeOptions = checkpoints.resumeOptionsFromCheckpoint(checkpoint);
|
|
202
210
|
const resumed = session.runtime.runner.resume({
|
|
@@ -249,7 +257,7 @@ export const wireRunnerHandlers = (bridge, context, session, checkpoints) => {
|
|
|
249
257
|
if (wasIdle) {
|
|
250
258
|
const resolvedRunId = crypto.randomUUID();
|
|
251
259
|
session.runnerStatus = 'running';
|
|
252
|
-
const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk));
|
|
260
|
+
const contextSeeds = applyObservableContextSeeds(session, await buildContextSeeds(session, context, resolvedRunId, emitPermissionAsk, requestLangflowerBus, liveWiredTools));
|
|
253
261
|
if (session.activeWorkflow !== null) {
|
|
254
262
|
checkpoints.beginRun(resolvedRunId, session.activeWorkflow);
|
|
255
263
|
}
|
|
@@ -286,8 +294,7 @@ export const wireRunnerHandlers = (bridge, context, session, checkpoints) => {
|
|
|
286
294
|
if (session.runnerStatus === 'running') {
|
|
287
295
|
return;
|
|
288
296
|
}
|
|
289
|
-
session
|
|
290
|
-
session.runId = undefined;
|
|
297
|
+
resetSessionExecutionFeed(session);
|
|
291
298
|
// Re-broadcast the (now empty) feed to every tab.
|
|
292
299
|
bridgeEmit(bridge, 'executionFeed.snapshot', session.buildExecutionFeed());
|
|
293
300
|
}));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Subscription } from 'rxjs';
|
|
2
2
|
import { listResumableCheckpoints } from '../checkpoint/list-resumable-checkpoints.js';
|
|
3
3
|
import { WorkflowCheckpointStore } from '../checkpoint/workflow-checkpoint-store.js';
|
|
4
|
+
import { resetSessionExecutionFeed } from '../session/reset-session-execution-feed.js';
|
|
4
5
|
import { buildSaveCurrentPayload } from '../workflow/build-save-current-payload.js';
|
|
5
6
|
import { copyWorkflowToSession } from '../workflow/copy-workflow-to-session.js';
|
|
6
7
|
import { createEmptyWorkflowInSession } from '../workflow/create-empty-workflow-in-session.js';
|
|
@@ -10,11 +11,17 @@ import { bridgeEmit, clientEmit } from './bridge-outbound.js';
|
|
|
10
11
|
import { findClientById } from './client-index.js';
|
|
11
12
|
import { isInboundEvent } from './inbound-guards.js';
|
|
12
13
|
/**
|
|
13
|
-
* Composer: clear selection → current snapshot →
|
|
14
|
-
* Sibling steps — handlers do not
|
|
14
|
+
* Composer: optional feed reset → clear selection → current snapshot →
|
|
15
|
+
* optional catalog sync. Sibling steps — handlers do not nest these.
|
|
15
16
|
*/
|
|
16
17
|
const syncAfterWorkflowMutation = async (bridge, context, session, client, options) => {
|
|
17
|
-
// 1.
|
|
18
|
+
// 1. Document switch: empty feed before the new catalog so the UI never
|
|
19
|
+
// paints the previous run under the next workflow's nodes.
|
|
20
|
+
if (options.resetFeed === true) {
|
|
21
|
+
resetSessionExecutionFeed(session);
|
|
22
|
+
bridgeEmit(bridge, 'executionFeed.snapshot', session.buildExecutionFeed());
|
|
23
|
+
}
|
|
24
|
+
// 2. Clear selection (and notify tabs if it was set)
|
|
18
25
|
if (options.clearSelection) {
|
|
19
26
|
const hadSelection = session.selectedNodeId !== null;
|
|
20
27
|
session.selectedNodeId = null;
|
|
@@ -22,19 +29,19 @@ const syncAfterWorkflowMutation = async (bridge, context, session, client, optio
|
|
|
22
29
|
bridgeEmit(bridge, 'editor.nodeSelected', { node: null });
|
|
23
30
|
}
|
|
24
31
|
}
|
|
25
|
-
//
|
|
32
|
+
// 3. Authoritative current-workflow slice (session-shared — fan out)
|
|
26
33
|
bridgeEmit(bridge, 'workflow.current.snapshot', {
|
|
27
34
|
activeWorkflow: session.activeWorkflow,
|
|
28
35
|
currentStatus: { status: session.currentStatus },
|
|
29
36
|
});
|
|
30
|
-
//
|
|
37
|
+
// 4. Resumable checkpoints for the active workflow (explicit boundaries)
|
|
31
38
|
const workflowId = session.activeWorkflowId ?? null;
|
|
32
39
|
const checkpoints = await listResumableCheckpoints(new WorkflowCheckpointStore(context.projectDir), workflowId, session.activeWorkflow);
|
|
33
40
|
bridgeEmit(bridge, 'runner.checkpoints.snapshot', {
|
|
34
41
|
workflowId,
|
|
35
42
|
checkpoints,
|
|
36
43
|
});
|
|
37
|
-
//
|
|
44
|
+
// 5. Catalog sync
|
|
38
45
|
if (options.catalog.kind === 'broadcast') {
|
|
39
46
|
const workflows = await context.workflowService.list();
|
|
40
47
|
bridgeEmit(bridge, 'workflow.list.snapshot', { workflows });
|
|
@@ -67,11 +74,13 @@ export const wireWorkflowHandlers = (bridge, context, session) => {
|
|
|
67
74
|
return;
|
|
68
75
|
}
|
|
69
76
|
let clearSelection = false;
|
|
77
|
+
let resetFeed = false;
|
|
70
78
|
if (!session.isGraphLocked()) {
|
|
71
79
|
// 1. Load document into session
|
|
72
80
|
const loaded = await loadWorkflowIntoSession(session, context.workflowService, context.projectDir, raw.payload.workflowId, context.resolveDefinition);
|
|
73
81
|
// 2. Persist current-workflow id when load succeeded
|
|
74
82
|
if (loaded.ok) {
|
|
83
|
+
resetFeed = true;
|
|
75
84
|
await context.langflowerConfigService.setCurrentWorkflowId(raw.payload.workflowId);
|
|
76
85
|
if (loaded.repaired) {
|
|
77
86
|
const nodeCount = loaded.droppedNodeIds.length;
|
|
@@ -101,7 +110,7 @@ export const wireWorkflowHandlers = (bridge, context, session) => {
|
|
|
101
110
|
});
|
|
102
111
|
}
|
|
103
112
|
// 3. Sync outbound
|
|
104
|
-
await syncAfterWorkflowMutation(bridge, context, session, connected, { clearSelection, catalog: { kind: 'none' } });
|
|
113
|
+
await syncAfterWorkflowMutation(bridge, context, session, connected, { clearSelection, catalog: { kind: 'none' }, resetFeed });
|
|
105
114
|
}));
|
|
106
115
|
subscription.add(bridge['workflow.saveCurrent.requested'].subscribe(async (raw) => {
|
|
107
116
|
if (!isInboundEvent(raw)) {
|
|
@@ -163,11 +172,13 @@ export const wireWorkflowHandlers = (bridge, context, session) => {
|
|
|
163
172
|
return;
|
|
164
173
|
}
|
|
165
174
|
let clearSelection = false;
|
|
175
|
+
let resetFeed = false;
|
|
166
176
|
if (!session.isGraphLocked()) {
|
|
167
|
-
await createEmptyWorkflowInSession(session, context.workflowService, context.projectDir, context.resolveDefinition);
|
|
177
|
+
const created = await createEmptyWorkflowInSession(session, context.workflowService, context.projectDir, context.resolveDefinition);
|
|
168
178
|
clearSelection = true;
|
|
179
|
+
resetFeed = created;
|
|
169
180
|
}
|
|
170
|
-
await syncAfterWorkflowMutation(bridge, context, session, connected, { clearSelection, catalog: { kind: 'none' } });
|
|
181
|
+
await syncAfterWorkflowMutation(bridge, context, session, connected, { clearSelection, catalog: { kind: 'none' }, resetFeed });
|
|
171
182
|
}));
|
|
172
183
|
subscription.add(bridge['workflow.copy.requested'].subscribe(async (raw) => {
|
|
173
184
|
if (!isInboundEvent(raw)) {
|
|
@@ -179,16 +190,19 @@ export const wireWorkflowHandlers = (bridge, context, session) => {
|
|
|
179
190
|
}
|
|
180
191
|
let catalogChanged = false;
|
|
181
192
|
let clearSelection = false;
|
|
193
|
+
let resetFeed = false;
|
|
182
194
|
if (!session.isGraphLocked()) {
|
|
183
195
|
const copied = await copyWorkflowToSession(session, context.workflowService, context.projectDir, raw.payload.workflowId, context.resolveDefinition);
|
|
184
196
|
if (copied && session.activeWorkflowId !== undefined) {
|
|
185
197
|
catalogChanged = true;
|
|
198
|
+
resetFeed = true;
|
|
186
199
|
await context.langflowerConfigService.setCurrentWorkflowId(session.activeWorkflowId);
|
|
187
200
|
}
|
|
188
201
|
clearSelection = true;
|
|
189
202
|
}
|
|
190
203
|
await syncAfterWorkflowMutation(bridge, context, session, connected, {
|
|
191
204
|
clearSelection,
|
|
205
|
+
resetFeed,
|
|
192
206
|
catalog: catalogChanged
|
|
193
207
|
? { kind: 'broadcast' }
|
|
194
208
|
: { kind: 'none' },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type NodeId, type RunId, type RuntimeRunnerEvent } from '@langflower/runtime';
|
|
2
2
|
import { type WorkflowCheckpoint, type WorkflowCheckpointSummary, type WorkflowLoadedPayload } from '@langflower/shared/langflower.js';
|
|
3
3
|
import { WorkflowCheckpointStore } from './workflow-checkpoint-store.js';
|
|
4
4
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isPortTelemetry, } from '@langflower/runtime';
|
|
1
2
|
import { buildWorkflowFingerprint, toCheckpointJsonValue, } from '@langflower/shared/langflower.js';
|
|
2
3
|
import { summarizeCheckpoint, WorkflowCheckpointStore, } from './workflow-checkpoint-store.js';
|
|
3
4
|
/**
|
|
@@ -56,27 +57,27 @@ export class RunCheckpointSession {
|
|
|
56
57
|
* that should trigger an immediate persist.
|
|
57
58
|
*/
|
|
58
59
|
observe(event, boundary) {
|
|
59
|
-
if (this.active === undefined ||
|
|
60
|
+
if (this.active === undefined ||
|
|
61
|
+
!isPortTelemetry(event) ||
|
|
62
|
+
event[0] !== 'out') {
|
|
60
63
|
return false;
|
|
61
64
|
}
|
|
62
|
-
|
|
65
|
+
const [, nodeIdRaw, portId, response] = event;
|
|
66
|
+
if (!('value' in response) || typeof portId !== 'string') {
|
|
63
67
|
return false;
|
|
64
68
|
}
|
|
65
|
-
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
const jsonValue = toCheckpointJsonValue(event.value);
|
|
69
|
+
const jsonValue = toCheckpointJsonValue(response.value);
|
|
69
70
|
if (jsonValue === undefined) {
|
|
70
|
-
this.unsupportedValue = `${
|
|
71
|
+
this.unsupportedValue = `${String(nodeIdRaw)}.${portId}`;
|
|
71
72
|
return false;
|
|
72
73
|
}
|
|
73
|
-
const nodeId = String(
|
|
74
|
+
const nodeId = String(nodeIdRaw);
|
|
74
75
|
let ports = this.active.outputSnapshots.get(nodeId);
|
|
75
76
|
if (ports === undefined) {
|
|
76
77
|
ports = new Map();
|
|
77
78
|
this.active.outputSnapshots.set(nodeId, ports);
|
|
78
79
|
}
|
|
79
|
-
ports.set(
|
|
80
|
+
ports.set(portId, {
|
|
80
81
|
state: 'value',
|
|
81
82
|
value: jsonValue,
|
|
82
83
|
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CustomPaletteSnapshotPayload } from '@langflower/shared/langflower.js';
|
|
2
|
+
import type { LangflowerBridge } from '../bridge/langflower-bridge.types.js';
|
|
3
|
+
import type { ServerContext } from '../server-context.js';
|
|
4
|
+
import type { LangflowerSession } from '../session/langflower-session.js';
|
|
5
|
+
/**
|
|
6
|
+
* One composer for Custom → Update and `compile_custom_nodes` (via bus
|
|
7
|
+
* intent `customPalette.update.requested`): compile, registry, live swap,
|
|
8
|
+
* then palette snapshot (and deleteEdges if ports vanished).
|
|
9
|
+
*/
|
|
10
|
+
export declare const compileAndHotSwapCustomNodes: (session: LangflowerSession, context: ServerContext, bridge: LangflowerBridge) => Promise<CustomPaletteSnapshotPayload>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { swapCustomNodesInEditor } from '../workflow/apply-editor-mutation.js';
|
|
2
|
+
import { refreshLiveWiredToolPacks } from '../bridge/get-live-wired-tools.js';
|
|
3
|
+
import { bridgeEmit } from '../bridge/bridge-outbound.js';
|
|
4
|
+
/**
|
|
5
|
+
* One composer for Custom → Update and `compile_custom_nodes` (via bus
|
|
6
|
+
* intent `customPalette.update.requested`): compile, registry, live swap,
|
|
7
|
+
* then palette snapshot (and deleteEdges if ports vanished).
|
|
8
|
+
*/
|
|
9
|
+
export const compileAndHotSwapCustomNodes = async (session, context, bridge) => {
|
|
10
|
+
bridgeEmit(bridge, 'customPalette.snapshot', context.customPaletteService.compilingSnapshot());
|
|
11
|
+
const snapshot = await context.customPaletteService.update(context.projectDir);
|
|
12
|
+
const customTypes = new Set(snapshot.nodes.map((node) => node.type));
|
|
13
|
+
const droppedEdges = swapCustomNodesInEditor(session, context.projectDir, context.resolveDefinition, customTypes);
|
|
14
|
+
refreshLiveWiredToolPacks(session);
|
|
15
|
+
if (droppedEdges.length > 0) {
|
|
16
|
+
bridgeEmit(bridge, 'editor.deleteEdges', droppedEdges);
|
|
17
|
+
bridgeEmit(bridge, 'workflow.currentStatus.snapshot', {
|
|
18
|
+
status: session.currentStatus,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
bridgeEmit(bridge, 'customPalette.snapshot', snapshot);
|
|
22
|
+
return snapshot;
|
|
23
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { LangflowerSession } from './langflower-session.js';
|
|
2
|
+
/**
|
|
3
|
+
* Drop the session run log so `buildExecutionFeed()` returns null.
|
|
4
|
+
* Call only when the runner is idle (document switch or user Clear).
|
|
5
|
+
*/
|
|
6
|
+
export declare const resetSessionExecutionFeed: (session: LangflowerSession) => void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drop the session run log so `buildExecutionFeed()` returns null.
|
|
3
|
+
* Call only when the runner is idle (document switch or user Clear).
|
|
4
|
+
*/
|
|
5
|
+
export const resetSessionExecutionFeed = (session) => {
|
|
6
|
+
session.runtime.runner.clearEventLog();
|
|
7
|
+
session.runId = undefined;
|
|
8
|
+
};
|
|
@@ -44,6 +44,11 @@ export declare const applyEditorRemoveEdge: (session: LangflowerSession, edgeId:
|
|
|
44
44
|
* Composer: snapshot → runtime remove → sync session topology from editor.
|
|
45
45
|
*/
|
|
46
46
|
export declare const applyEditorRemoveNode: (session: LangflowerSession, nodeId: NodeId) => WorkflowNodePersisted[];
|
|
47
|
+
/**
|
|
48
|
+
* Replace live editor instances whose persisted `type` is in `customTypes`.
|
|
49
|
+
* Types missing from the set keep the old instance. Allowed while locked.
|
|
50
|
+
*/
|
|
51
|
+
export declare const swapCustomNodesInEditor: (session: LangflowerSession, projectDir: string, resolveDefinition: ResolveNodeDefinition, customTypes: ReadonlySet<string>) => readonly RuntimeEdge[];
|
|
47
52
|
export type BindWorkflowResult = {
|
|
48
53
|
readonly ok: true;
|
|
49
54
|
readonly droppedNodeIds: readonly string[];
|
|
@@ -447,6 +447,38 @@ export const applyEditorRemoveNode = (session, nodeId) => {
|
|
|
447
447
|
syncActiveWorkflowTopologyFromEditor(session);
|
|
448
448
|
return nodeSnapshot !== undefined ? [nodeSnapshot] : [];
|
|
449
449
|
};
|
|
450
|
+
/**
|
|
451
|
+
* Replace live editor instances whose persisted `type` is in `customTypes`.
|
|
452
|
+
* Types missing from the set keep the old instance. Allowed while locked.
|
|
453
|
+
*/
|
|
454
|
+
export const swapCustomNodesInEditor = (session, projectDir, resolveDefinition, customTypes) => {
|
|
455
|
+
const active = session.activeWorkflow;
|
|
456
|
+
if (active === null) {
|
|
457
|
+
return [];
|
|
458
|
+
}
|
|
459
|
+
const persistedById = new Map(active.graph.nodes.map((node) => [node.id, node]));
|
|
460
|
+
const droppedEdges = [];
|
|
461
|
+
for (const runtimeNode of session.runtime.editor.getNodes()) {
|
|
462
|
+
const persisted = persistedById.get(runtimeNode.nodeId);
|
|
463
|
+
if (persisted === undefined || !customTypes.has(persisted.type)) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
const next = materializeRuntimeNode(projectDir, persisted, resolveDefinition);
|
|
467
|
+
if (next === undefined) {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
const { nodeId: _nodeId, ...rest } = next;
|
|
471
|
+
const swapped = session.runtime.editor.swapNode(runtimeNode.nodeId, rest);
|
|
472
|
+
if (swapped === false) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
droppedEdges.push(...swapped.droppedEdges);
|
|
476
|
+
}
|
|
477
|
+
if (droppedEdges.length > 0) {
|
|
478
|
+
syncActiveWorkflowTopologyFromEditor(session);
|
|
479
|
+
}
|
|
480
|
+
return droppedEdges;
|
|
481
|
+
};
|
|
450
482
|
/**
|
|
451
483
|
* Load path: document → editor (activate/rename/rebind).
|
|
452
484
|
* Unsupported nodes and invalid edges are skipped (graceful degradation);
|
|
@@ -27,11 +27,15 @@ contract.
|
|
|
27
27
|
|
|
28
28
|
## Load custom nodes
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
Call **`compile_custom_nodes`** (no args) — on starter, Helper and Writer
|
|
31
|
+
already have it because **Langflower Tools** is wired — or, in the editor
|
|
32
|
+
Custom section, click **Update** (or reconnect). Same composer: typecheck
|
|
33
|
+
each pack (`tsc --noEmit` when `tsconfig.json` is present), esbuild-bundle
|
|
34
|
+
entries that passed, hot-swap live custom instances, refresh **Custom**.
|
|
35
|
+
Stop is not required for already-placed custom types. Already-wired custom
|
|
36
|
+
tools can be invoked later in the **same run**. New types are not auto-placed
|
|
37
|
+
or auto-wired mid-run. Failures write `COMPILATION_ERRORS.md` in the pack
|
|
38
|
+
without dropping other successful custom nodes.
|
|
35
39
|
|
|
36
40
|
## Gaps
|
|
37
41
|
|
|
@@ -199,9 +199,10 @@ even though Langflower bundles with esbuild for load.
|
|
|
199
199
|
2. `export default defineNode({ … })`, `defineToolRegistrations({ … })` for an
|
|
200
200
|
LLM `tools` pack, **or** `defineReactiveNode({ … })` when exclusive `ok` /
|
|
201
201
|
`fail` (or other silent-branch) ports are required.
|
|
202
|
-
3. Run `npm install` in the pack if
|
|
203
|
-
4.
|
|
204
|
-
appears under **Custom**.
|
|
202
|
+
3. Run `npm install` in the pack if author deps changed.
|
|
203
|
+
4. Call **`compile_custom_nodes`** (starter Helper / Writer) or Custom →
|
|
204
|
+
**Update**. The type appears under **Custom**. Already-placed instances
|
|
205
|
+
hot-swap (no Stop). Place **new** types on the canvas yourself.
|
|
205
206
|
|
|
206
207
|
## Second shareable pack
|
|
207
208
|
|