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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { filter, firstValueFrom } from 'rxjs';
|
|
2
|
+
import { isPortTelemetry, isRuntimeDone, } from '../../types.js';
|
|
2
3
|
import { RuntimeEditor } from '../../runtime-editor.js';
|
|
3
4
|
import { RuntimeRunner } from '../../runtime-runner.js';
|
|
4
5
|
export function createRuntimeHarness(options) {
|
|
@@ -17,27 +18,23 @@ export function wireEdge(editor, edge) {
|
|
|
17
18
|
throw new Error(`Failed to wire ${edge.fromNodeId}.${edge.fromPort[0]} → ${edge.toNodeId}.${edge.toPort[0]}`);
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
export function outputValues(events, nodeId, portId, runId) {
|
|
21
|
+
const isOutputValue = (event) => isPortTelemetry(event) && event[0] === 'out' && event[3] === 'value';
|
|
22
|
+
export function outputValues(events, nodeId, portId, _runId) {
|
|
24
23
|
return events
|
|
25
|
-
.filter((event) =>
|
|
26
|
-
event
|
|
27
|
-
event
|
|
28
|
-
(
|
|
29
|
-
.map((event) => event.value);
|
|
24
|
+
.filter((event) => isOutputValue(event) &&
|
|
25
|
+
event[1] === nodeId &&
|
|
26
|
+
event[2] === portId)
|
|
27
|
+
.map((event) => event[4]);
|
|
30
28
|
}
|
|
31
|
-
export async function waitForOutput(runtime, nodeId, portId,
|
|
32
|
-
return waitForOutputMatching(runtime, nodeId, portId, () => true,
|
|
29
|
+
export async function waitForOutput(runtime, nodeId, portId, _runId) {
|
|
30
|
+
return waitForOutputMatching(runtime, nodeId, portId, () => true, _runId);
|
|
33
31
|
}
|
|
34
|
-
async function waitForOutputMatching(runtime, nodeId, portId, predicate,
|
|
32
|
+
async function waitForOutputMatching(runtime, nodeId, portId, predicate, _runId) {
|
|
35
33
|
const runner = resolveRunner(runtime);
|
|
36
|
-
return firstValueFrom(runner.events$.pipe(filter((event) =>
|
|
37
|
-
event
|
|
38
|
-
event
|
|
39
|
-
(
|
|
40
|
-
predicate(event.value))));
|
|
34
|
+
return firstValueFrom(runner.events$.pipe(filter((event) => isOutputValue(event) &&
|
|
35
|
+
event[1] === nodeId &&
|
|
36
|
+
event[2] === portId &&
|
|
37
|
+
predicate(event[4]))));
|
|
41
38
|
}
|
|
42
39
|
export async function runAndCollectEvents(runtime, startRun, settleMs = 50) {
|
|
43
40
|
const events = [];
|
|
@@ -52,26 +49,17 @@ export async function runAndCollectEvents(runtime, startRun, settleMs = 50) {
|
|
|
52
49
|
subscription.unsubscribe();
|
|
53
50
|
return { runId, events };
|
|
54
51
|
}
|
|
55
|
-
async function collectEventsForMs(runtime, ms) {
|
|
56
|
-
const events = [];
|
|
57
|
-
const runner = resolveRunner(runtime);
|
|
58
|
-
const subscription = runner.events$.subscribe((event) => {
|
|
59
|
-
events.push(event);
|
|
60
|
-
});
|
|
61
|
-
await new Promise((resolve) => {
|
|
62
|
-
setTimeout(resolve, ms);
|
|
63
|
-
});
|
|
64
|
-
subscription.unsubscribe();
|
|
65
|
-
return events;
|
|
66
|
-
}
|
|
67
52
|
export async function noDoneWithin(runtime, ms, runId) {
|
|
68
53
|
const runner = resolveRunner(runtime);
|
|
69
54
|
const result = await Promise.race([
|
|
70
|
-
firstValueFrom(runner.events$.pipe(filter((event) => event
|
|
71
|
-
|
|
55
|
+
firstValueFrom(runner.events$.pipe(filter((event) => isRuntimeDone(event) &&
|
|
56
|
+
event.length === 2 &&
|
|
57
|
+
(runId === undefined || event[1] === runId)))).then(() => 'done'),
|
|
72
58
|
new Promise((resolve) => {
|
|
73
59
|
setTimeout(() => resolve('timeout'), ms);
|
|
74
60
|
}),
|
|
75
61
|
]);
|
|
76
62
|
return result === 'timeout';
|
|
77
63
|
}
|
|
64
|
+
export const edgeIdsFromPortEvent = (event) => event[6];
|
|
65
|
+
export const portDirLabel = (event) => event[0] === 'out' ? 'output-emitted' : 'input-received';
|
|
@@ -119,44 +119,26 @@ export type MetaFromStatefulObservable<T extends StatefulObservable<unknown, unk
|
|
|
119
119
|
*/
|
|
120
120
|
export type RuntimeRunnerStatus = 'idle' | 'running' | 'stopped';
|
|
121
121
|
export type RuntimePortSignalState = 'pending' | 'value' | 'error';
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
readonly value: unknown;
|
|
143
|
-
/** Resolved author feed contract carried with the runtime fact. */
|
|
144
|
-
readonly feed?: RuntimeFeedPortMeta;
|
|
145
|
-
};
|
|
146
|
-
export type RuntimeRunnerEvent = RuntimeOutputEmittedEvent | RuntimeInputReceivedEvent | {
|
|
147
|
-
/**
|
|
148
|
-
* Run ended naturally — sets {@link RuntimeRunnerStatus} to `'idle'`.
|
|
149
|
-
*
|
|
150
|
-
* Emitted when:
|
|
151
|
-
* - the graph is **empty** on {@link RuntimeRunner.start}, or
|
|
152
|
-
* - a node with {@link RuntimeNode.stopsRun} emits on a watched output.
|
|
153
|
-
*
|
|
154
|
-
* Otherwise the run stays `'running'` until
|
|
155
|
-
* {@link RuntimeRunner.interrupt}.
|
|
156
|
-
*/
|
|
157
|
-
readonly kind: 'done';
|
|
158
|
-
readonly runId: RunId;
|
|
159
|
-
};
|
|
122
|
+
/**
|
|
123
|
+
* Port signal tuple — `portDir` `'out'` = output emitted, `'in'` = input received.
|
|
124
|
+
* No per-frame `runId`; session snapshots own run correlation.
|
|
125
|
+
*/
|
|
126
|
+
export type PortTelemetry = readonly [
|
|
127
|
+
portDir: 'in' | 'out',
|
|
128
|
+
nodeId: NodeId,
|
|
129
|
+
portId: string,
|
|
130
|
+
state: RuntimePortSignalState,
|
|
131
|
+
value: unknown,
|
|
132
|
+
portIdx: number,
|
|
133
|
+
edgeIds: readonly EdgeId[],
|
|
134
|
+
/** Absent feed meta — use `null` (never `undefined`; JSON arrays drop undefined). */
|
|
135
|
+
feed: RuntimeFeedPortMeta | null
|
|
136
|
+
];
|
|
137
|
+
/** Run ended — `runId` at index 1 when replay needs explicit correlation. */
|
|
138
|
+
export type RuntimeDoneTelemetry = readonly ['done'] | readonly ['done', RunId];
|
|
139
|
+
export type RuntimeRunnerEvent = PortTelemetry | RuntimeDoneTelemetry;
|
|
140
|
+
export declare const isPortTelemetry: (event: RuntimeRunnerEvent) => event is PortTelemetry;
|
|
141
|
+
export declare const isRuntimeDone: (event: RuntimeRunnerEvent) => event is RuntimeDoneTelemetry;
|
|
160
142
|
/** Seed value pushed into an input port slot on {@link RuntimeRunner.start}. */
|
|
161
143
|
export type RuntimeSeedPortValue = {
|
|
162
144
|
readonly portId: string | symbol;
|
|
@@ -255,6 +237,10 @@ export type RuntimeOptions = {
|
|
|
255
237
|
*/
|
|
256
238
|
readonly log?: boolean;
|
|
257
239
|
};
|
|
240
|
+
export type SwapNodeResult = {
|
|
241
|
+
readonly node: RuntimeNode;
|
|
242
|
+
readonly droppedEdges: readonly RuntimeEdge[];
|
|
243
|
+
};
|
|
258
244
|
export type RuntimeEditorApi = {
|
|
259
245
|
/**
|
|
260
246
|
* Register a node and its port observables (handler already bound).
|
|
@@ -288,6 +274,15 @@ export type RuntimeEditorApi = {
|
|
|
288
274
|
* graph is locked. Does not cascade-remove other edges.
|
|
289
275
|
*/
|
|
290
276
|
replaceEdge(edge: Omit<RuntimeEdge, 'edgeId'>): RuntimeEdge | false;
|
|
277
|
+
/**
|
|
278
|
+
* Replace the live instance at `nodeId` with `next`. Keeps `nodeId`.
|
|
279
|
+
* Drops incident edges whose ports vanished or whose wire types are no
|
|
280
|
+
* longer compatible (same rules as {@link addEdge}).
|
|
281
|
+
*
|
|
282
|
+
* Allowed while the graph is locked. Does not call {@link addNode} /
|
|
283
|
+
* {@link removeNode}. Returns `false` when disposed or `nodeId` is missing.
|
|
284
|
+
*/
|
|
285
|
+
swapNode(nodeId: NodeId, next: Omit<RuntimeNode, 'nodeId'>): SwapNodeResult | false;
|
|
291
286
|
/** Must fail while runner status is `'running'`.
|
|
292
287
|
*
|
|
293
288
|
* return false while running or node not found
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const isPortTelemetry = (event) => Array.isArray(event) && (event[0] === 'in' || event[0] === 'out');
|
|
2
|
+
export const isRuntimeDone = (event) => Array.isArray(event) && event[0] === 'done';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRuntimeDone } from '@langflower/runtime';
|
|
1
2
|
import { deriveExecutionProgressStatus, terminalExecutionProgressStatus, } from '@langflower/shared/langflower.js';
|
|
2
3
|
import { Subscription } from 'rxjs';
|
|
3
4
|
import { RunCheckpointSession } from '../checkpoint/run-checkpoint-session.js';
|
|
@@ -36,7 +37,7 @@ export const attachLangflowerBridge = (bridge, context, options = {}) => {
|
|
|
36
37
|
// miss them (`events$` is a non-replaying Subject). Late clients get the
|
|
37
38
|
// backlog via `executionFeed.snapshot`. See FOUND_BUGS pending race.
|
|
38
39
|
rootSubscription.add(session.runtime.runner.events$.subscribe((event) => {
|
|
39
|
-
if (event
|
|
40
|
+
if (isRuntimeDone(event) && onRunSettled !== undefined) {
|
|
40
41
|
const progress = deriveExecutionProgressStatus('idle', session.runtime.runner.eventLog);
|
|
41
42
|
const status = terminalExecutionProgressStatus(progress);
|
|
42
43
|
if (status !== null) {
|
|
@@ -59,7 +60,7 @@ export const attachLangflowerBridge = (bridge, context, options = {}) => {
|
|
|
59
60
|
// 3. Intent handlers (bus namespaces)
|
|
60
61
|
rootSubscription.add(wireWorkflowHandlers(bridge, context, session));
|
|
61
62
|
rootSubscription.add(wirePaletteHandlers(bridge, context));
|
|
62
|
-
rootSubscription.add(wireCustomPaletteHandlers(bridge, context));
|
|
63
|
+
rootSubscription.add(wireCustomPaletteHandlers(bridge, context, session));
|
|
63
64
|
rootSubscription.add(wireConfigHandlers(bridge, context, session, draftController, {
|
|
64
65
|
onEffectiveConfig: (config) => {
|
|
65
66
|
applyServerLogsGate(diagnosticLog.setEnabled, config);
|
|
@@ -2,67 +2,22 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { promises as fs } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { langflowerWsConfig } from '@langflower/shared/langflower.js';
|
|
5
|
+
import { encodeBridgeFrame } from '@langflower/websocket-bridge/bridge-codec';
|
|
5
6
|
import { Subscription } from 'rxjs';
|
|
6
|
-
const REDACTED = '[REDACTED]';
|
|
7
|
-
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
8
|
-
const isSecretKey = (key) => {
|
|
9
|
-
const normalized = key.toLowerCase();
|
|
10
|
-
return (normalized.includes('apikey') ||
|
|
11
|
-
normalized.includes('authorization') ||
|
|
12
|
-
normalized.includes('cookie') ||
|
|
13
|
-
normalized.includes('token') ||
|
|
14
|
-
normalized.includes('password') ||
|
|
15
|
-
normalized.includes('secret') ||
|
|
16
|
-
normalized.includes('credential'));
|
|
17
|
-
};
|
|
18
|
-
const sanitize = (value, seen = new WeakSet()) => {
|
|
19
|
-
if (value === null ||
|
|
20
|
-
typeof value === 'string' ||
|
|
21
|
-
typeof value === 'number' ||
|
|
22
|
-
typeof value === 'boolean') {
|
|
23
|
-
return value;
|
|
24
|
-
}
|
|
25
|
-
if (typeof value === 'bigint') {
|
|
26
|
-
return `${value}n`;
|
|
27
|
-
}
|
|
28
|
-
if (typeof value === 'undefined') {
|
|
29
|
-
return '[undefined]';
|
|
30
|
-
}
|
|
31
|
-
if (typeof value === 'symbol' || typeof value === 'function') {
|
|
32
|
-
return `[${typeof value}]`;
|
|
33
|
-
}
|
|
34
|
-
if (value instanceof Error) {
|
|
35
|
-
return {
|
|
36
|
-
name: value.name,
|
|
37
|
-
message: value.message,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
if (value instanceof Date) {
|
|
41
|
-
return value.toISOString();
|
|
42
|
-
}
|
|
43
|
-
if (typeof value === 'object') {
|
|
44
|
-
if (seen.has(value)) {
|
|
45
|
-
return '[circular]';
|
|
46
|
-
}
|
|
47
|
-
seen.add(value);
|
|
48
|
-
}
|
|
49
|
-
if (Array.isArray(value)) {
|
|
50
|
-
return value.map((entry) => sanitize(entry, seen));
|
|
51
|
-
}
|
|
52
|
-
if (isRecord(value)) {
|
|
53
|
-
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
54
|
-
key,
|
|
55
|
-
isSecretKey(key) ? REDACTED : sanitize(entry, seen),
|
|
56
|
-
]));
|
|
57
|
-
}
|
|
58
|
-
return String(value);
|
|
59
|
-
};
|
|
60
7
|
const toSafeTimestamp = (date) => date.toISOString().replaceAll(':', '-').replaceAll('.', '-');
|
|
61
|
-
const asObservable = (value) =>
|
|
8
|
+
const asObservable = (value) => typeof value === 'object' &&
|
|
9
|
+
value !== null &&
|
|
10
|
+
typeof value.subscribe === 'function'
|
|
62
11
|
? value
|
|
63
12
|
: undefined;
|
|
64
|
-
const asInboundEvent = (value) =>
|
|
65
|
-
|
|
13
|
+
const asInboundEvent = (value) => typeof value === 'object' &&
|
|
14
|
+
value !== null &&
|
|
15
|
+
typeof value.clientId === 'string' &&
|
|
16
|
+
'payload' in value
|
|
17
|
+
? {
|
|
18
|
+
clientId: value.clientId,
|
|
19
|
+
payload: value.payload,
|
|
20
|
+
}
|
|
66
21
|
: undefined;
|
|
67
22
|
const logPath = (projectDir) => path.join(projectDir, '.langflower', 'logs', `${toSafeTimestamp(new Date())}-${process.pid}-${randomUUID()}.log`);
|
|
68
23
|
export const attachBridgeEventLog = (bridge, projectDir, subscriptions, options = {}) => {
|
|
@@ -81,15 +36,11 @@ export const attachBridgeEventLog = (bridge, projectDir, subscriptions, options
|
|
|
81
36
|
const message = error instanceof Error ? error.message : String(error);
|
|
82
37
|
process.stderr.write(`Langflower diagnostic logging disabled: ${message}\n`);
|
|
83
38
|
};
|
|
84
|
-
const
|
|
39
|
+
const writeFrame = (transportDir, busType, payload) => {
|
|
85
40
|
if (!enabled || !acceptingWrites || closed) {
|
|
86
41
|
return;
|
|
87
42
|
}
|
|
88
|
-
const line = `${
|
|
89
|
-
schemaVersion: 1,
|
|
90
|
-
timestamp: new Date().toISOString(),
|
|
91
|
-
...record,
|
|
92
|
-
}))}\n`;
|
|
43
|
+
const line = `${encodeBridgeFrame(transportDir, busType, payload)}\n`;
|
|
93
44
|
writeQueue = writeQueue.then(async () => {
|
|
94
45
|
if (!enabled || !acceptingWrites) {
|
|
95
46
|
return;
|
|
@@ -118,13 +69,7 @@ export const attachBridgeEventLog = (bridge, projectDir, subscriptions, options
|
|
|
118
69
|
subscriptions.add(channel.subscribe((value) => {
|
|
119
70
|
const event = asInboundEvent(value);
|
|
120
71
|
if (event !== undefined) {
|
|
121
|
-
|
|
122
|
-
kind: 'frame',
|
|
123
|
-
direction: 'inbound',
|
|
124
|
-
clientId: event.clientId,
|
|
125
|
-
type,
|
|
126
|
-
payload: event.payload,
|
|
127
|
-
});
|
|
72
|
+
writeFrame('in', type, event.payload);
|
|
128
73
|
}
|
|
129
74
|
}));
|
|
130
75
|
}
|
|
@@ -134,30 +79,10 @@ export const attachBridgeEventLog = (bridge, projectDir, subscriptions, options
|
|
|
134
79
|
continue;
|
|
135
80
|
}
|
|
136
81
|
subscriptions.add(channel.subscribe((payload) => {
|
|
137
|
-
|
|
138
|
-
kind: 'frame',
|
|
139
|
-
direction: 'outbound',
|
|
140
|
-
scope: 'broadcast',
|
|
141
|
-
type,
|
|
142
|
-
payload,
|
|
143
|
-
});
|
|
82
|
+
writeFrame('out', type, payload);
|
|
144
83
|
}));
|
|
145
84
|
}
|
|
146
|
-
subscriptions.add(bridge.status$.subscribe((status) => {
|
|
147
|
-
write({ kind: 'status', status });
|
|
148
|
-
}));
|
|
149
|
-
subscriptions.add(bridge.errors$.subscribe((error) => {
|
|
150
|
-
write({
|
|
151
|
-
kind: 'error',
|
|
152
|
-
error: {
|
|
153
|
-
code: error.code,
|
|
154
|
-
message: error.message,
|
|
155
|
-
...('cause' in error ? { cause: error.cause } : {}),
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
}));
|
|
159
85
|
subscriptions.add(bridge.connections$.subscribe((client) => {
|
|
160
|
-
write({ kind: 'connection', clientId: client.id });
|
|
161
86
|
const clientSubscriptions = new Subscription();
|
|
162
87
|
subscriptions.add(clientSubscriptions);
|
|
163
88
|
const clientChannels = client;
|
|
@@ -167,29 +92,19 @@ export const attachBridgeEventLog = (bridge, projectDir, subscriptions, options
|
|
|
167
92
|
continue;
|
|
168
93
|
}
|
|
169
94
|
clientSubscriptions.add(channel.subscribe((payload) => {
|
|
170
|
-
|
|
171
|
-
kind: 'frame',
|
|
172
|
-
direction: 'outbound',
|
|
173
|
-
scope: 'client',
|
|
174
|
-
clientId: client.id,
|
|
175
|
-
type,
|
|
176
|
-
payload,
|
|
177
|
-
});
|
|
95
|
+
writeFrame('out', type, payload);
|
|
178
96
|
}));
|
|
179
97
|
}
|
|
180
98
|
clientSubscriptions.add(client.disconnected$.subscribe(() => {
|
|
181
|
-
write({ kind: 'disconnection', clientId: client.id });
|
|
182
99
|
clientSubscriptions.unsubscribe();
|
|
183
100
|
}));
|
|
184
101
|
}));
|
|
185
|
-
write({ kind: 'server-started' });
|
|
186
102
|
return {
|
|
187
103
|
filePath,
|
|
188
104
|
setEnabled: (nextEnabled) => {
|
|
189
105
|
enabled = nextEnabled;
|
|
190
106
|
},
|
|
191
107
|
writeServerClosing: () => {
|
|
192
|
-
write({ kind: 'server-closing' });
|
|
193
108
|
closed = true;
|
|
194
109
|
},
|
|
195
110
|
flush: async () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { LangflowerBusRequest } from '@langflower/common-nodes/ai/run-host-services';
|
|
2
|
+
import { type ExecutionContext, type ToolHandle } from '@langflower/node-sdk';
|
|
2
3
|
import type { LlmExecutionCaps } from '@langflower/node-sdk/llm';
|
|
3
4
|
import type { McpHandle } from '@langflower/node-sdk/mcp';
|
|
4
5
|
import type { RuntimeSeedPortValue } from '@langflower/runtime';
|
|
@@ -16,6 +17,8 @@ type BuildHarnessHooks = {
|
|
|
16
17
|
readonly nodeId: string;
|
|
17
18
|
readonly requestPermission: LangflowerSession['permissionAsks']['requestPermission'];
|
|
18
19
|
readonly emitPermissionAsk: (payload: RunnerPermissionAskPayload) => void;
|
|
20
|
+
readonly requestLangflowerBus?: LangflowerBusRequest;
|
|
21
|
+
readonly getLiveWiredTools?: (agentNodeId: string) => readonly ToolHandle[];
|
|
19
22
|
};
|
|
20
23
|
export declare const buildExecutionContext: (context: ExecutionContextDeps, runId: string, node: WorkflowGraphNode, hooks?: BuildHarnessHooks, preloadedConfig?: LangflowerConfig, runMcpHandles?: readonly McpHandle[]) => Promise<ExecutionContext<never, LlmExecutionCaps>>;
|
|
21
24
|
/**
|
|
@@ -24,5 +27,5 @@ export declare const buildExecutionContext: (context: ExecutionContextDeps, runI
|
|
|
24
27
|
* which would put the Observable in value$ instead of error$.
|
|
25
28
|
*/
|
|
26
29
|
export declare const applyObservableContextSeeds: (session: LangflowerSession, seeds: Readonly<Record<string, ReadonlyArray<RuntimeSeedPortValue>>>) => Record<string, ReadonlyArray<RuntimeSeedPortValue>>;
|
|
27
|
-
export declare const buildContextSeeds: (session: LangflowerSession, context: ExecutionContextDeps, runId: string, emitPermissionAsk: (payload: RunnerPermissionAskPayload) => void) => Promise<Record<string, ReadonlyArray<RuntimeSeedPortValue>>>;
|
|
30
|
+
export declare const buildContextSeeds: (session: LangflowerSession, context: ExecutionContextDeps, runId: string, emitPermissionAsk: (payload: RunnerPermissionAskPayload) => void, requestLangflowerBus?: LangflowerBusRequest, getLiveWiredTools?: (agentNodeId: string) => readonly ToolHandle[]) => Promise<Record<string, ReadonlyArray<RuntimeSeedPortValue>>>;
|
|
28
31
|
export {};
|
|
@@ -28,6 +28,13 @@ const createToolHarness = (options) => {
|
|
|
28
28
|
: {}),
|
|
29
29
|
});
|
|
30
30
|
};
|
|
31
|
+
const LIVE_WIRED_TOOLS_NODE_TYPES = new Set([
|
|
32
|
+
'common-openai-llm',
|
|
33
|
+
'common-fake-llm',
|
|
34
|
+
'common-review',
|
|
35
|
+
'common-critique',
|
|
36
|
+
'common-sub-agent',
|
|
37
|
+
]);
|
|
31
38
|
export const buildExecutionContext = async (context, runId, node, hooks, preloadedConfig, runMcpHandles) => {
|
|
32
39
|
const rolePreset = parseLlmRolePreset(node.params.rolePreset);
|
|
33
40
|
const skillId = resolveEffectiveSkillId(rolePreset, node.params.skillId);
|
|
@@ -104,8 +111,28 @@ export const buildExecutionContext = async (context, runId, node, hooks, preload
|
|
|
104
111
|
...(config.harness?.allowedHosts !== undefined
|
|
105
112
|
? { allowedHosts: config.harness.allowedHosts }
|
|
106
113
|
: {}),
|
|
114
|
+
...(hooks?.requestLangflowerBus !== undefined &&
|
|
115
|
+
node.type === 'common-langflower-tools'
|
|
116
|
+
? { requestLangflowerBus: hooks.requestLangflowerBus }
|
|
117
|
+
: {}),
|
|
118
|
+
...(hooks?.getLiveWiredTools !== undefined &&
|
|
119
|
+
LIVE_WIRED_TOOLS_NODE_TYPES.has(node.type)
|
|
120
|
+
? { getLiveWiredTools: hooks.getLiveWiredTools }
|
|
121
|
+
: {}),
|
|
107
122
|
});
|
|
108
123
|
};
|
|
124
|
+
/** Host `contextSymbol` vs compiled-pack duplicate (`file://` / Vitest alias). */
|
|
125
|
+
const contextPortLabel = String(contextSymbol);
|
|
126
|
+
const resolveLiveContextPortId = (session, nodeId) => {
|
|
127
|
+
const node = session.runtime.editor.getNode(nodeId);
|
|
128
|
+
if (node === false || node.inputs[contextSymbol] !== undefined) {
|
|
129
|
+
return contextSymbol;
|
|
130
|
+
}
|
|
131
|
+
const match = Object.getOwnPropertySymbols(node.inputs).find((portId) => String(portId) === contextPortLabel);
|
|
132
|
+
return match ?? contextSymbol;
|
|
133
|
+
};
|
|
134
|
+
const isContextSeedPort = (portId) => portId === contextSymbol ||
|
|
135
|
+
(typeof portId === 'symbol' && String(portId) === contextPortLabel);
|
|
109
136
|
const ctxErrorFromFailures = (failures) => ({
|
|
110
137
|
message: failures.map((failure) => failure.message).join('\n'),
|
|
111
138
|
});
|
|
@@ -119,9 +146,10 @@ export const applyObservableContextSeeds = (session, seeds) => {
|
|
|
119
146
|
for (const [nodeId, list] of Object.entries(seeds)) {
|
|
120
147
|
const kept = [];
|
|
121
148
|
for (const seed of list) {
|
|
122
|
-
if (seed.portId
|
|
149
|
+
if (isContextSeedPort(seed.portId) && isObservable(seed.value)) {
|
|
123
150
|
const node = session.runtime.editor.getNode(nodeId);
|
|
124
|
-
const
|
|
151
|
+
const portId = resolveLiveContextPortId(session, nodeId);
|
|
152
|
+
const connection = node === false ? undefined : node.inputs[portId];
|
|
125
153
|
if (connection !== undefined) {
|
|
126
154
|
connection.connect(seed.value);
|
|
127
155
|
}
|
|
@@ -135,7 +163,7 @@ export const applyObservableContextSeeds = (session, seeds) => {
|
|
|
135
163
|
}
|
|
136
164
|
return valueSeeds;
|
|
137
165
|
};
|
|
138
|
-
export const buildContextSeeds = async (session, context, runId, emitPermissionAsk) => {
|
|
166
|
+
export const buildContextSeeds = async (session, context, runId, emitPermissionAsk, requestLangflowerBus, getLiveWiredTools) => {
|
|
139
167
|
const workflow = session.activeWorkflow;
|
|
140
168
|
if (workflow === null) {
|
|
141
169
|
return {};
|
|
@@ -160,7 +188,7 @@ export const buildContextSeeds = async (session, context, runId, emitPermissionA
|
|
|
160
188
|
const error = ctxErrorFromFailures(nodeFailures);
|
|
161
189
|
seeds[node.id] = [
|
|
162
190
|
{
|
|
163
|
-
portId:
|
|
191
|
+
portId: resolveLiveContextPortId(session, node.id),
|
|
164
192
|
slotIndex: 0,
|
|
165
193
|
value: throwError(() => error),
|
|
166
194
|
},
|
|
@@ -172,8 +200,20 @@ export const buildContextSeeds = async (session, context, runId, emitPermissionA
|
|
|
172
200
|
nodeId: node.id,
|
|
173
201
|
requestPermission: session.permissionAsks.requestPermission,
|
|
174
202
|
emitPermissionAsk,
|
|
203
|
+
...(requestLangflowerBus !== undefined
|
|
204
|
+
? { requestLangflowerBus }
|
|
205
|
+
: {}),
|
|
206
|
+
...(getLiveWiredTools !== undefined
|
|
207
|
+
? { getLiveWiredTools }
|
|
208
|
+
: {}),
|
|
175
209
|
}, config, runMcp?.handles);
|
|
176
|
-
seeds[node.id] = [
|
|
210
|
+
seeds[node.id] = [
|
|
211
|
+
{
|
|
212
|
+
portId: resolveLiveContextPortId(session, node.id),
|
|
213
|
+
slotIndex: 0,
|
|
214
|
+
value: ctx,
|
|
215
|
+
},
|
|
216
|
+
];
|
|
177
217
|
}
|
|
178
218
|
return seeds;
|
|
179
219
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type RuntimeRunnerEvent } from '@langflower/runtime';
|
|
2
2
|
import type { LangflowerBridge } from './langflower-bridge.types.js';
|
|
3
3
|
/** Fan-out runner telemetry to every connected tab (session-shared). */
|
|
4
4
|
export declare const forwardRunnerEvent: (bridge: LangflowerBridge, event: RuntimeRunnerEvent) => void;
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
+
import { isPortTelemetry, isRuntimeDone, } from '@langflower/runtime';
|
|
1
2
|
import { bridgeEmit } from './bridge-outbound.js';
|
|
2
3
|
/** Fan-out runner telemetry to every connected tab (session-shared). */
|
|
3
4
|
export const forwardRunnerEvent = (bridge, event) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
break;
|
|
11
|
-
case 'done':
|
|
12
|
-
bridgeEmit(bridge, 'runner.done', event);
|
|
13
|
-
break;
|
|
14
|
-
default:
|
|
15
|
-
break;
|
|
5
|
+
if (isPortTelemetry(event)) {
|
|
6
|
+
bridgeEmit(bridge, 'runner.port', event);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (isRuntimeDone(event)) {
|
|
10
|
+
bridgeEmit(bridge, 'runner.done', event);
|
|
16
11
|
}
|
|
17
12
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ToolHandle } from '@langflower/node-sdk';
|
|
2
|
+
import type { LangflowerSession } from '../session/langflower-session.js';
|
|
3
|
+
/**
|
|
4
|
+
* Activate current editor `tools` outputs (including post-swap instances)
|
|
5
|
+
* so a later inbound peek in {@link getLiveWiredTools} sees live handles.
|
|
6
|
+
*/
|
|
7
|
+
export declare const refreshLiveWiredToolPacks: (session: LangflowerSession) => void;
|
|
8
|
+
/**
|
|
9
|
+
* Walk inbound `tools` edges on **current** editor instances (post-swap).
|
|
10
|
+
* Does not emit on the LLM tools port (ADR-016 session must not reset).
|
|
11
|
+
*/
|
|
12
|
+
export declare const getLiveWiredTools: (session: LangflowerSession, agentNodeId: string) => readonly ToolHandle[];
|
|
@@ -0,0 +1,80 @@
|
|
|
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` outputs (including post-swap instances)
|
|
44
|
+
* so a later inbound peek in {@link getLiveWiredTools} sees live handles.
|
|
45
|
+
*/
|
|
46
|
+
export const refreshLiveWiredToolPacks = (session) => {
|
|
47
|
+
for (const node of session.runtime.editor.getNodes()) {
|
|
48
|
+
const port = resolveToolsOutput(node.outputs, 'tools');
|
|
49
|
+
if (port !== undefined) {
|
|
50
|
+
peekPortValue(port);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Walk inbound `tools` edges on **current** editor instances (post-swap).
|
|
56
|
+
* Does not emit on the LLM tools port (ADR-016 session must not reset).
|
|
57
|
+
*/
|
|
58
|
+
export const getLiveWiredTools = (session, agentNodeId) => {
|
|
59
|
+
const editor = session.runtime.editor;
|
|
60
|
+
const inbound = editor
|
|
61
|
+
.getEdges()
|
|
62
|
+
.filter((edge) => String(edge.toNodeId) === agentNodeId &&
|
|
63
|
+
edge.toPort[0] === 'tools');
|
|
64
|
+
const packs = [];
|
|
65
|
+
for (const edge of inbound) {
|
|
66
|
+
const source = editor.getNode(edge.fromNodeId);
|
|
67
|
+
if (source === false) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const port = resolveToolsOutput(source.outputs, edge.fromPort[0]);
|
|
71
|
+
if (port === undefined) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const peeked = peekPortValue(port);
|
|
75
|
+
if (peeked !== undefined) {
|
|
76
|
+
packs.push(peeked);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return flattenToolHandles(packs);
|
|
80
|
+
};
|
|
@@ -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
|
+
};
|