langflower 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/package.json +1 -1
  2. package/ui-dist/{chunk-Y6VMBLSJ.js → chunk-7UMVYN3A.js} +1 -1
  3. package/ui-dist/{chunk-6DQ2XSRW.js → chunk-MDGXX73Z.js} +3 -3
  4. package/ui-dist/index.html +1 -1
  5. package/ui-dist/main-2JJGCNTD.js +313 -0
  6. package/vendor/common-nodes/dist/ai/chat-completion-stream.d.ts +2 -0
  7. package/vendor/common-nodes/dist/ai/critique/node.d.ts +246 -0
  8. package/vendor/common-nodes/dist/ai/critique/node.js +2 -2
  9. package/vendor/common-nodes/dist/ai/fake-llm/node.d.ts +246 -0
  10. package/vendor/common-nodes/dist/ai/features/chat-completion-stream.d.ts +53 -0
  11. package/vendor/common-nodes/dist/ai/features/chat-completion-stream.js +1 -0
  12. package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.d.ts +13 -0
  13. package/vendor/common-nodes/dist/ai/features/llm-loop/autokick-recovery.js +17 -0
  14. package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.d.ts +2 -0
  15. package/vendor/common-nodes/dist/ai/features/llm-loop/classify-llm-failure.js +113 -0
  16. package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.d.ts +28 -0
  17. package/vendor/common-nodes/dist/ai/features/llm-loop/dead-loop-detector.js +194 -0
  18. package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.d.ts +9 -0
  19. package/vendor/common-nodes/dist/ai/features/llm-loop/live-get-tools.js +21 -0
  20. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.d.ts +2 -0
  21. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.js +216 -0
  22. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.d.ts +125 -0
  23. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.js +39 -0
  24. package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.d.ts +2 -0
  25. package/vendor/common-nodes/dist/ai/features/llm-loop/normalize-llm-recovery-policy.js +59 -0
  26. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.d.ts +1 -0
  27. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/normalize-tool-result.js +7 -0
  28. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.d.ts +43 -0
  29. package/vendor/common-nodes/dist/ai/features/llm-loop/operators/observe-provider-stream.js +96 -0
  30. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.d.ts +32 -0
  31. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.js +58 -0
  32. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.d.ts +80 -0
  33. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.js +681 -0
  34. package/vendor/common-nodes/dist/ai/features/llm-role-preset.d.ts +69 -0
  35. package/vendor/common-nodes/dist/ai/features/llm-role-preset.js +265 -0
  36. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.d.ts +148 -0
  37. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.js +198 -0
  38. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.d.ts +21 -0
  39. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.js +118 -0
  40. package/vendor/common-nodes/dist/ai/features/openai/context-length-error.d.ts +14 -0
  41. package/vendor/common-nodes/dist/ai/features/openai/context-length-error.js +63 -0
  42. package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.d.ts +19 -0
  43. package/vendor/common-nodes/dist/ai/features/openai/create-chat-completion-stream.js +182 -0
  44. package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.d.ts +28 -0
  45. package/vendor/common-nodes/dist/ai/features/openai/list-provider-models.js +52 -0
  46. package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.d.ts +31 -0
  47. package/vendor/common-nodes/dist/ai/features/openai/llm-context-compaction.js +326 -0
  48. package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.d.ts +14 -0
  49. package/vendor/common-nodes/dist/ai/features/openai/normalize-compaction-params.js +21 -0
  50. package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.d.ts +30 -0
  51. package/vendor/common-nodes/dist/ai/features/openai/prepare-chat-completion.js +132 -0
  52. package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.d.ts +20 -0
  53. package/vendor/common-nodes/dist/ai/features/path-choice/control-tools.js +70 -0
  54. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.d.ts +35 -0
  55. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.js +106 -0
  56. package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.d.ts +9 -0
  57. package/vendor/common-nodes/dist/ai/features/prompt/build-effective-system-prompt.js +21 -0
  58. package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.d.ts +13 -0
  59. package/vendor/common-nodes/dist/ai/features/prompt/normalize-max-iterations.js +23 -0
  60. package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.d.ts +10 -0
  61. package/vendor/common-nodes/dist/ai/features/prompt/resolve-chat-provider-model.js +8 -0
  62. package/vendor/common-nodes/dist/ai/features/run-host-services.d.ts +54 -0
  63. package/vendor/common-nodes/dist/ai/features/run-host-services.js +29 -0
  64. package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.d.ts +17 -0
  65. package/vendor/common-nodes/dist/ai/features/scripted-chat-completion-stream.js +61 -0
  66. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.d.ts +39 -0
  67. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.js +43 -0
  68. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.d.ts +14 -0
  69. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-compaction-ui-schema.js +18 -0
  70. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.d.ts +80 -0
  71. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-panel-ui-schema.js +76 -0
  72. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.d.ts +113 -0
  73. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.js +131 -0
  74. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.d.ts +6 -0
  75. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.js +30 -0
  76. package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.d.ts +13 -0
  77. package/vendor/common-nodes/dist/ai/llm-loop/autokick-recovery.js +17 -0
  78. package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.d.ts +28 -0
  79. package/vendor/common-nodes/dist/ai/llm-loop/dead-loop-detector.js +194 -0
  80. package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-reducer.js +36 -0
  81. package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.d.ts +35 -0
  82. package/vendor/common-nodes/dist/ai/llm-loop/llm-loop-types.js +19 -0
  83. package/vendor/common-nodes/dist/ai/llm-loop/normalize-llm-recovery-policy.js +52 -9
  84. package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.d.ts +8 -2
  85. package/vendor/common-nodes/dist/ai/llm-loop/operators/observe-provider-stream.js +43 -13
  86. package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.d.ts +3 -5
  87. package/vendor/common-nodes/dist/ai/llm-loop/run-llm-loop.js +116 -1
  88. package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.d.ts +82 -0
  89. package/vendor/common-nodes/dist/ai/llm-recovery-ui-schema.js +95 -0
  90. package/vendor/common-nodes/dist/ai/llm-session-shell.d.ts +4 -9
  91. package/vendor/common-nodes/dist/ai/llm-session-shell.js +2 -4
  92. package/vendor/common-nodes/dist/ai/nodes/critique/node.d.ts +588 -0
  93. package/vendor/common-nodes/dist/ai/nodes/critique/node.js +240 -0
  94. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.d.ts +571 -0
  95. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.js +208 -0
  96. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.d.ts +587 -0
  97. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.js +91 -0
  98. package/vendor/common-nodes/dist/ai/nodes/review/node.d.ts +593 -0
  99. package/vendor/common-nodes/dist/ai/nodes/review/node.js +240 -0
  100. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.d.ts +630 -0
  101. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.js +302 -0
  102. package/vendor/common-nodes/dist/ai/openai/create-chat-completion-stream.js +6 -0
  103. package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.d.ts +2 -0
  104. package/vendor/common-nodes/dist/ai/openai/prepare-chat-completion.js +18 -0
  105. package/vendor/common-nodes/dist/ai/openai-llm/node.d.ts +246 -0
  106. package/vendor/common-nodes/dist/ai/review/node.d.ts +246 -0
  107. package/vendor/common-nodes/dist/ai/review/node.js +2 -2
  108. package/vendor/common-nodes/dist/ai/sub-agent/node.d.ts +246 -0
  109. package/vendor/common-nodes/dist/ai/sub-agent/node.js +2 -2
  110. package/vendor/common-nodes/dist/catalog.js +7 -5
  111. package/vendor/common-nodes/dist/compile-custom-nodes/node.d.ts +21 -0
  112. package/vendor/common-nodes/dist/compile-custom-nodes/node.js +45 -0
  113. package/vendor/common-nodes/dist/crawl/crawl/node.js +1 -1
  114. package/vendor/common-nodes/dist/crawl/fetch-url/node.js +1 -1
  115. package/vendor/common-nodes/dist/flow/repeat/node.js +6 -1
  116. package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.d.ts +18 -0
  117. package/vendor/common-nodes/dist/langflower-tools/emit-registration-tools.js +29 -0
  118. package/vendor/common-nodes/dist/langflower-tools/node.d.ts +20 -0
  119. package/vendor/common-nodes/dist/langflower-tools/node.js +77 -0
  120. package/vendor/common-nodes/dist/text/append-file/node.js +1 -1
  121. package/vendor/common-nodes/dist/text/read-file/node.js +1 -1
  122. package/vendor/common-nodes/dist/text/write-file/node.js +1 -1
  123. package/vendor/common-nodes/dist/tools/inventory-tool-round.d.ts +2 -2
  124. package/vendor/common-nodes/package.json +10 -10
  125. package/vendor/compiler/dist/compile-project-nodes.d.ts +2 -1
  126. package/vendor/compiler/dist/compile-project-nodes.js +35 -6
  127. package/vendor/compiler/dist/resolve-host-types.d.ts +0 -5
  128. package/vendor/compiler/dist/resolve-host-types.js +0 -8
  129. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.d.ts +1 -1
  130. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.js +1 -1
  131. package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.d.ts +8 -0
  132. package/vendor/node-sdk/dist/node-factory/define-llm-node/recovery-notice.js +14 -0
  133. package/vendor/runtime/dist/runtime-editor.d.ts +5 -1
  134. package/vendor/runtime/dist/runtime-editor.js +19 -0
  135. package/vendor/runtime/dist/runtime-runner.js +17 -17
  136. package/vendor/runtime/dist/runtime.d.ts +2 -1
  137. package/vendor/runtime/dist/runtime.js +1 -0
  138. package/vendor/runtime/dist/testing/workflows/workflow-events.d.ts +8 -6
  139. package/vendor/runtime/dist/testing/workflows/workflow-events.js +19 -31
  140. package/vendor/runtime/dist/types.d.ts +33 -38
  141. package/vendor/runtime/dist/types.js +2 -1
  142. package/vendor/server/dist/bridge/attach-langflower-bridge.js +3 -2
  143. package/vendor/server/dist/bridge/bridge-event-log.js +17 -102
  144. package/vendor/server/dist/bridge/build-execution-context.d.ts +5 -2
  145. package/vendor/server/dist/bridge/build-execution-context.js +45 -5
  146. package/vendor/server/dist/bridge/forward-runner-event.d.ts +1 -1
  147. package/vendor/server/dist/bridge/forward-runner-event.js +7 -12
  148. package/vendor/server/dist/bridge/get-live-wired-tools.d.ts +12 -0
  149. package/vendor/server/dist/bridge/get-live-wired-tools.js +80 -0
  150. package/vendor/server/dist/bridge/langflower-tools-rpc.d.ts +7 -0
  151. package/vendor/server/dist/bridge/langflower-tools-rpc.js +29 -0
  152. package/vendor/server/dist/bridge/settings-draft-controller.js +26 -3
  153. package/vendor/server/dist/bridge/wire-custom-palette-handlers.d.ts +2 -1
  154. package/vendor/server/dist/bridge/wire-custom-palette-handlers.js +3 -5
  155. package/vendor/server/dist/bridge/wire-runner-handlers.js +15 -8
  156. package/vendor/server/dist/checkpoint/run-checkpoint-session.d.ts +1 -1
  157. package/vendor/server/dist/checkpoint/run-checkpoint-session.js +10 -9
  158. package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.d.ts +10 -0
  159. package/vendor/server/dist/palette/compile-and-hot-swap-custom-nodes.js +23 -0
  160. package/vendor/server/dist/workflow/apply-editor-mutation.d.ts +5 -0
  161. package/vendor/server/dist/workflow/apply-editor-mutation.js +32 -0
  162. package/vendor/server/skeleton/instructions.md +9 -5
  163. package/vendor/server/skeleton/nodes/my-nodes/README.md +4 -3
  164. package/vendor/server/skeleton/schemas/langflower-config.schema.json +11 -1
  165. package/vendor/server/skeleton/skills/langflower-helper/SKILL.md +49 -19
  166. package/vendor/server/skeleton/skills/langflower-helper/architecture.md +22 -9
  167. package/vendor/server/skeleton/skills/langflower-helper/layout.md +15 -15
  168. package/vendor/server/skeleton/skills/langflower-node-writer/SKILL.md +19 -9
  169. package/vendor/server/skeleton/skills/langflower-workflow-writer/SKILL.md +14 -10
  170. package/vendor/server/skeleton/workflows/starter.json +30 -3
  171. package/vendor/shared/dist/execution/derive-run-settle-outcome.d.ts +1 -1
  172. package/vendor/shared/dist/execution/derive-run-settle-outcome.js +4 -3
  173. package/vendor/shared/dist/execution/derive-run-settle-outcome.test.js +9 -9
  174. package/vendor/shared/dist/langflower-bus-config.d.ts +6 -14
  175. package/vendor/shared/dist/langflower-bus-config.js +4 -12
  176. package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.js +6 -0
  177. package/vendor/shared/dist/langflower-config/resolve-wired-tool-options.test.js +30 -0
  178. package/vendor/shared/dist/langflower-ws-waits.d.ts +7 -14
  179. package/vendor/shared/dist/langflower-ws-waits.js +14 -14
  180. package/vendor/websocket-bridge/dist/bridge-codec.d.ts +1 -0
  181. package/vendor/websocket-bridge/dist/bridge-codec.js +11 -11
  182. package/vendor/websocket-bridge/dist/bridge-frame.js +1 -1
  183. package/vendor/websocket-bridge/dist/bridge-subjects.d.ts +1 -1
  184. package/vendor/websocket-bridge/dist/bridge-subjects.js +2 -2
  185. package/vendor/websocket-bridge/dist/bridge-types.d.ts +13 -1
  186. package/vendor/websocket-bridge/dist/create-client.js +3 -3
  187. package/vendor/websocket-bridge/dist/create-server.js +12 -6
  188. package/vendor/websocket-bridge/package.json +8 -0
  189. package/ui-dist/main-SMO3L7U5.js +0 -311
@@ -36,10 +36,11 @@ export const repeatNode = defineReactiveNode({
36
36
  return of({ kind: 'done' });
37
37
  }
38
38
  return trigger.value$.pipe(startWith(undefined), take(n + 1), observeOn(asapScheduler), map((_, index) => index < n
39
- ? { kind: 'value', value: v }
39
+ ? { kind: 'value', value: v, index }
40
40
  : { kind: 'done' }));
41
41
  }));
42
42
  const valueOut$ = session$.pipeValue(filter((e) => e.kind === 'value'), map((e) => e.value));
43
+ const indexOut$ = session$.pipeValue(filter((e) => e.kind === 'value'), map((e) => e.index));
43
44
  const doneOut$ = session$.pipeValue(filter((e) => e.kind === 'done'), map(() => true));
44
45
  return {
45
46
  inputs: [value, count, trigger],
@@ -47,8 +48,12 @@ export const repeatNode = defineReactiveNode({
47
48
  configureOutput('value', valueOut$, {
48
49
  inferTypeFrom: value,
49
50
  }),
51
+ configureOutput('index', indexOut$, {
52
+ wireType: 'number',
53
+ }),
50
54
  configureOutput('done', doneOut$, {
51
55
  wireType: 'boolean',
56
+ feed: { role: 'none' },
52
57
  }),
53
58
  ],
54
59
  };
@@ -0,0 +1,18 @@
1
+ import { type ToolHandle, type ToolHandler } from '@langflower/node-sdk';
2
+ import { type Observable } from 'rxjs';
3
+ type RegistrationTool = {
4
+ readonly toolId: string;
5
+ readonly name?: string;
6
+ readonly description: string;
7
+ readonly inputSchema: object;
8
+ readonly handler: ToolHandler;
9
+ };
10
+ /**
11
+ * Emit a `tools` pack, peeking **this** node's EC at invoke so bus RPC
12
+ * stays on the pack instance (not agent `toolCtx`). Local to this folder —
13
+ * not the author SDK factory.
14
+ */
15
+ export declare const emitRegistrationTools: (ctx: {
16
+ readonly value$: Observable<unknown>;
17
+ }, tools: readonly RegistrationTool[]) => import("@rx-evo/stateful-observable").StatefulObservable<ToolHandle[], unknown, undefined>;
18
+ export {};
@@ -0,0 +1,29 @@
1
+ import { statefulObservable } from '@rx-evo/stateful-observable';
2
+ import { of } from 'rxjs';
3
+ const peekNodeContext = (source) => {
4
+ let peeked;
5
+ const sub = source.value$.subscribe((value) => {
6
+ peeked = value;
7
+ });
8
+ sub.unsubscribe();
9
+ return typeof peeked === 'object' && peeked !== null
10
+ ? peeked
11
+ : undefined;
12
+ };
13
+ /**
14
+ * Emit a `tools` pack, peeking **this** node's EC at invoke so bus RPC
15
+ * stays on the pack instance (not agent `toolCtx`). Local to this folder —
16
+ * not the author SDK factory.
17
+ */
18
+ export const emitRegistrationTools = (ctx, tools) => statefulObservable({
19
+ loader: () => of(tools.map((tool) => ({
20
+ toolId: tool.toolId,
21
+ name: tool.name ?? tool.toolId,
22
+ description: tool.description,
23
+ inputSchema: tool.inputSchema,
24
+ invoke: (args, agentCtx) => {
25
+ const nodeCtx = peekNodeContext(ctx);
26
+ return tool.handler(args, nodeCtx ?? agentCtx);
27
+ },
28
+ }))),
29
+ });
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Emits Langflower bus tools for agent inventory. Recompile is unsafe:
3
+ * wire this node’s `tools` into the agent (starter Helper / Writer).
4
+ */
5
+ export declare const langflowerToolsNode: {
6
+ readonly emitOncePerActivation: boolean;
7
+ readonly stopsRun: boolean;
8
+ readonly chatEntry: boolean;
9
+ readonly uiSchema: readonly [];
10
+ readonly bypassPorts: Record<string, import("@langflower/node-sdk").WireType>;
11
+ readonly inputsConfigs: readonly [import("@langflower/node-sdk").InputPortMeta<import("@langflower/node-sdk").ExecutionContext<readonly [], Record<string, never>>>, ...import("@langflower/node-sdk").InputPortMeta<unknown>[]];
12
+ readonly outputsConfigs: (import("@langflower/node-sdk").OutputParams & import("@langflower/node-sdk").PortMeta)[];
13
+ readonly getInstance: () => import("@langflower/node-sdk").ReactiveNodeInstance<readonly [], Record<string, never>>;
14
+ readonly paletteSecondary?: true;
15
+ readonly description?: string;
16
+ readonly type: string;
17
+ readonly displayName: string;
18
+ readonly category: string | undefined;
19
+ readonly icon: string | undefined;
20
+ };
@@ -0,0 +1,77 @@
1
+ import { defineReactiveNode, TOOL_HANDLE_WIRE_TYPE, } from '@langflower/node-sdk';
2
+ import { getRunHostServices } from '../ai/features/run-host-services.js';
3
+ import { emitRegistrationTools } from './emit-registration-tools.js';
4
+ const MISSING_RPC_TEXT = '{ ok: false }\ncompile_custom_nodes unavailable (no bus RPC)';
5
+ const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
6
+ /** Format `customPalette.snapshot` (RPC wait skips `compiling`). */
7
+ const formatPaletteSnapshot = (value) => {
8
+ if (!isRecord(value)) {
9
+ return `{ ok: false }\nUnexpected compile result`;
10
+ }
11
+ const status = typeof value.status === 'string' ? value.status : 'error';
12
+ const lines = [`status: ${status}`];
13
+ const nodes = Array.isArray(value.nodes) ? value.nodes : [];
14
+ const nodeTypes = nodes.flatMap((node) => isRecord(node) && typeof node.type === 'string' ? [node.type] : []);
15
+ if (nodeTypes.length > 0) {
16
+ lines.push(`nodeTypes: ${nodeTypes.join(', ')}`);
17
+ }
18
+ const errors = Array.isArray(value.errors) ? value.errors : [];
19
+ if (errors.length > 0) {
20
+ lines.push('errors:');
21
+ for (const error of errors) {
22
+ if (!isRecord(error)) {
23
+ continue;
24
+ }
25
+ const pack = typeof error.packageName === 'string'
26
+ ? error.packageName
27
+ : 'unknown';
28
+ const message = typeof error.message === 'string' ? error.message : '';
29
+ lines.push(`- ${pack}: ${message}`);
30
+ }
31
+ }
32
+ return lines.join('\n');
33
+ };
34
+ const LANGFLOWER_BUS_TOOL_CONFIGS = [
35
+ {
36
+ toolId: 'compile_custom_nodes',
37
+ description: 'Recompile `.langflower/nodes/` packs, hot-swap live custom instances, and refresh the Custom palette (same intent as Custom → Update). No arguments. Pack failures also write COMPILATION_ERRORS.md.',
38
+ inputSchema: {
39
+ type: 'object',
40
+ properties: {},
41
+ additionalProperties: false,
42
+ },
43
+ handler: (async (_args, ctx) => {
44
+ const request = getRunHostServices(ctx)?.requestLangflowerBus;
45
+ if (request === undefined) {
46
+ return MISSING_RPC_TEXT;
47
+ }
48
+ try {
49
+ const snapshot = await request('customPalette.update.requested', {});
50
+ return formatPaletteSnapshot(snapshot);
51
+ }
52
+ catch (error) {
53
+ const message = error instanceof Error ? error.message : String(error);
54
+ return `{ ok: false }\n${message}`;
55
+ }
56
+ }),
57
+ },
58
+ ];
59
+ /**
60
+ * Emits Langflower bus tools for agent inventory. Recompile is unsafe:
61
+ * wire this node’s `tools` into the agent (starter Helper / Writer).
62
+ */
63
+ export const langflowerToolsNode = defineReactiveNode({
64
+ type: 'common-langflower-tools',
65
+ displayName: 'Langflower Tools',
66
+ category: 'Tools',
67
+ description: 'Emits compile_custom_nodes (Custom → Update over the bus). Wire tools to opt in; later bus actions may be added to this pack.',
68
+ uiSchema: [],
69
+ bind(ctx, { configureOutput }) {
70
+ return {
71
+ inputs: [],
72
+ outputs: [
73
+ configureOutput('tools', emitRegistrationTools(ctx, LANGFLOWER_BUS_TOOL_CONFIGS), { wireType: TOOL_HANDLE_WIRE_TYPE }),
74
+ ],
75
+ };
76
+ },
77
+ });
@@ -1,7 +1,7 @@
1
1
  import { defineReactiveNode } from '@langflower/node-sdk';
2
2
  import { createProjectFilesContext } from '@langflower/tools/create-project-files-context';
3
3
  import { from, map, mergeMap, throwError } from 'rxjs';
4
- import { getRunHostServices } from '../../ai/run-host-services.js';
4
+ import { getRunHostServices } from '../../ai/features/run-host-services.js';
5
5
  /**
6
6
  * Append to a project-relative text file via `createProjectFilesContext` (no permission ask).
7
7
  * Non-empty files get `delimiter` between existing text and `content`.
@@ -1,7 +1,7 @@
1
1
  import { defineReactiveNode } from '@langflower/node-sdk';
2
2
  import { createProjectFilesContext } from '@langflower/tools/create-project-files-context';
3
3
  import { from, mergeMap, throwError } from 'rxjs';
4
- import { getRunHostServices } from '../../ai/run-host-services.js';
4
+ import { getRunHostServices } from '../../ai/features/run-host-services.js';
5
5
  /**
6
6
  * Read a project-relative text file via `createProjectFilesContext` (no permission ask).
7
7
  * Wire `update` (dynamic) to re-read when the path is unchanged.
@@ -1,7 +1,7 @@
1
1
  import { defineReactiveNode } from '@langflower/node-sdk';
2
2
  import { createProjectFilesContext } from '@langflower/tools/create-project-files-context';
3
3
  import { from, map, mergeMap, throwError } from 'rxjs';
4
- import { getRunHostServices } from '../../ai/run-host-services.js';
4
+ import { getRunHostServices } from '../../ai/features/run-host-services.js';
5
5
  /**
6
6
  * Overwrite a project-relative text file via `createProjectFilesContext` (no permission ask).
7
7
  */
@@ -1,8 +1,8 @@
1
1
  import type { ToolHandle } from '@langflower/node-sdk';
2
2
  import { type Harness } from '@langflower/tools/create-project-harness';
3
3
  import type { ToolHandlerContext } from '@langflower/tools/domain-tool-configs';
4
- import type { ChatCompletionToolCall, ChatCompletionToolDefinition } from '../ai/chat-completion-stream.js';
5
- import type { SubAgentRegistration, SubAgentSpawnPayload } from '../ai/sub-agent-protocol.js';
4
+ import type { ChatCompletionToolCall, ChatCompletionToolDefinition } from '../ai/features/chat-completion-stream.js';
5
+ import type { SubAgentRegistration, SubAgentSpawnPayload } from '../ai/features/sub-agent-protocol.js';
6
6
  export declare const SPAWN_SUBAGENT_TOOL = "spawn_subagent";
7
7
  export declare const previewToolLogText: (text: string) => string;
8
8
  export declare const toChatToolDefinitions: (tools: readonly ToolHandle[]) => readonly ChatCompletionToolDefinition[];
@@ -14,24 +14,24 @@
14
14
  "import": "./dist/test-nodes/test-index.js"
15
15
  },
16
16
  "./ai/llm-role-preset": {
17
- "types": "./dist/ai/llm-role-preset.d.ts",
18
- "import": "./dist/ai/llm-role-preset.js"
17
+ "types": "./dist/ai/features/llm-role-preset.d.ts",
18
+ "import": "./dist/ai/features/llm-role-preset.js"
19
19
  },
20
20
  "./ai/sub-agent-protocol": {
21
- "types": "./dist/ai/sub-agent-protocol.d.ts",
22
- "import": "./dist/ai/sub-agent-protocol.js"
21
+ "types": "./dist/ai/features/sub-agent-protocol.d.ts",
22
+ "import": "./dist/ai/features/sub-agent-protocol.js"
23
23
  },
24
24
  "./ai/run-host-services": {
25
- "types": "./dist/ai/run-host-services.d.ts",
26
- "import": "./dist/ai/run-host-services.js"
25
+ "types": "./dist/ai/features/run-host-services.d.ts",
26
+ "import": "./dist/ai/features/run-host-services.js"
27
27
  },
28
28
  "./ai/openai/create-chat-completion-stream": {
29
- "types": "./dist/ai/openai/create-chat-completion-stream.d.ts",
30
- "import": "./dist/ai/openai/create-chat-completion-stream.js"
29
+ "types": "./dist/ai/features/openai/create-chat-completion-stream.d.ts",
30
+ "import": "./dist/ai/features/openai/create-chat-completion-stream.js"
31
31
  },
32
32
  "./ai/openai/list-provider-models": {
33
- "types": "./dist/ai/openai/list-provider-models.d.ts",
34
- "import": "./dist/ai/openai/list-provider-models.js"
33
+ "types": "./dist/ai/features/openai/list-provider-models.d.ts",
34
+ "import": "./dist/ai/features/openai/list-provider-models.js"
35
35
  }
36
36
  },
37
37
  "dependencies": {
@@ -7,7 +7,8 @@ export declare const hasCustomNodePacks: (projectDir: string) => Promise<boolean
7
7
  * Scan `.langflower/nodes/`. Each pack runs independently; within a pack each
8
8
  * `export default` entry is typechecked then esbuilt only if clean.
9
9
  * Returns all successful definitions plus all failures (partial success OK).
10
- * Empty / missing `nodes/` is a no-op (no cache dir).
10
+ * Always deletes `.langflower/.cache/nodes/` first. Empty / missing `nodes/`
11
+ * does not recreate the cache dir.
11
12
  */
12
13
  export declare const compileProjectNodes: (projectDir: string) => Promise<CompileProjectNodesResult>;
13
14
  export type { CompileDiagnostic, CompilePackError, CompileProjectNodesResult, } from './compile-types.js';
@@ -1,17 +1,39 @@
1
1
  import fs from 'node:fs/promises';
2
+ import os from 'node:os';
2
3
  import path from 'node:path';
3
4
  import { pathToFileURL } from 'node:url';
4
5
  import { bundleEntry } from './bundle-pack.js';
5
- import { computePackCacheKey } from './cache-key.js';
6
6
  import { discoverPacks } from './discover-packs.js';
7
7
  import { diagnosticsForEntry, typecheckPack } from './typecheck-pack.js';
8
8
  import { formatCompilePackError } from './format-compilation-errors.js';
9
9
  import { parseDefaultExport } from './validate-default-export.js';
10
10
  import { deleteCompilationErrorsFile, writeCompilationErrorsFile, } from './write-compilation-errors.js';
11
11
  const cacheRoot = (projectDir) => path.join(projectDir, '.langflower', '.cache', 'nodes');
12
+ const wipeCacheRoot = async (projectDir) => {
13
+ try {
14
+ await fs.rm(cacheRoot(projectDir), { recursive: true, force: true });
15
+ return { ok: true };
16
+ }
17
+ catch (error) {
18
+ const message = error instanceof Error ? error.message : String(error);
19
+ return {
20
+ ok: false,
21
+ error: formatCompilePackError('.cache/nodes', [
22
+ {
23
+ message: `Failed to delete custom-node cache: ${message}`,
24
+ },
25
+ ], projectDir),
26
+ };
27
+ }
28
+ };
12
29
  const loadBundledDefault = async (outfile, entryPath, packageName, projectDir) => {
13
- const href = `${pathToFileURL(outfile).href}?t=${Date.now()}`;
30
+ const loadFile = path.join(os.tmpdir(), `lf-node-load-${process.hrtime.bigint()}.mjs`);
14
31
  try {
32
+ // Stable outfile stays at `<pack>/<entry>.mjs` for git diff. Import a
33
+ // unique temp copy so Node / Vitest ESM cache cannot reuse the previous
34
+ // module for that path (query strings are not enough under Vitest).
35
+ await fs.copyFile(outfile, loadFile);
36
+ const href = `${pathToFileURL(loadFile).href}?t=${Date.now()}`;
15
37
  const mod = await import(href);
16
38
  const defaultExport = typeof mod === 'object' && mod !== null && 'default' in mod
17
39
  ? mod.default
@@ -40,9 +62,11 @@ const loadBundledDefault = async (outfile, entryPath, packageName, projectDir) =
40
62
  };
41
63
  const relativeEntry = (packDir, entryPath) => path.relative(packDir, entryPath).split(path.sep).join('/');
42
64
  const compileEntry = async (projectDir, pack, entryPath) => {
43
- const cacheKey = await computePackCacheKey(pack.packDir, [entryPath]);
44
- const relative = relativeEntry(pack.packDir, entryPath).replace(/[\\/]/g, '__');
45
- const outfile = path.join(cacheRoot(projectDir), pack.packageName.replace(/[^\w.-]+/g, '_'), cacheKey, `${relative}.mjs`);
65
+ const relative = relativeEntry(pack.packDir, entryPath)
66
+ .replace(/[\\/]/g, '__')
67
+ .replace(/\.tsx$/u, '')
68
+ .replace(/\.ts$/u, '');
69
+ const outfile = path.join(cacheRoot(projectDir), pack.packageName.replace(/[^\w.-]+/g, '_'), `${relative}.mjs`);
46
70
  const bundled = await bundleEntry({
47
71
  entryPath,
48
72
  packDir: pack.packDir,
@@ -95,10 +119,15 @@ export const hasCustomNodePacks = async (projectDir) => {
95
119
  * Scan `.langflower/nodes/`. Each pack runs independently; within a pack each
96
120
  * `export default` entry is typechecked then esbuilt only if clean.
97
121
  * Returns all successful definitions plus all failures (partial success OK).
98
- * Empty / missing `nodes/` is a no-op (no cache dir).
122
+ * Always deletes `.langflower/.cache/nodes/` first. Empty / missing `nodes/`
123
+ * does not recreate the cache dir.
99
124
  */
100
125
  export const compileProjectNodes = async (projectDir) => {
101
126
  const packs = await discoverPacks(projectDir);
127
+ const wiped = await wipeCacheRoot(projectDir);
128
+ if (!wiped.ok) {
129
+ return { nodes: [], errors: [wiped.error] };
130
+ }
102
131
  if (packs.length === 0) {
103
132
  return { nodes: [], errors: [] };
104
133
  }
@@ -8,11 +8,6 @@ export declare const isHostPeerSpecifier: (id: string) => boolean;
8
8
  * compiler's install tree. Works with `npm i -g` and an empty project.
9
9
  */
10
10
  export declare const resolveHostPackageEntry: (specifier: string) => string | undefined;
11
- /**
12
- * Stable stamp of resolved host peer roots for cache invalidation when the
13
- * Langflower install tree moves or upgrades.
14
- */
15
- export declare const hostRuntimeEntryStamp: () => string;
16
11
  /**
17
12
  * Resolve declaration entry for a host package installed next to the
18
13
  * compiler (global Langflower tree), using package.json `types` /
@@ -64,14 +64,6 @@ export const isHostPeerSpecifier = (id) => {
64
64
  * compiler's install tree. Works with `npm i -g` and an empty project.
65
65
  */
66
66
  export const resolveHostPackageEntry = (specifier) => resolvePackageEntry(specifier);
67
- /**
68
- * Stable stamp of resolved host peer roots for cache invalidation when the
69
- * Langflower install tree moves or upgrades.
70
- */
71
- export const hostRuntimeEntryStamp = () => HOST_PEER_PACKAGES.map((name) => {
72
- const entry = resolveHostPackageEntry(name);
73
- return `${name}=${entry === undefined ? '' : toPosix(entry)}`;
74
- }).join('\n');
75
67
  /**
76
68
  * Prefer `exports` types conditions (import → require → default), then
77
69
  * top-level `types` / `typings`.
@@ -43,4 +43,4 @@ export declare const defineLlmNode: <UI extends readonly UISchemaConstItem[]>(co
43
43
  export { LLM_INVENTORY_INPUT_PORT_IDS, LLM_INVENTORY_OUTPUT_PORT_IDS, type LlmInventoryInputs, type LlmInventoryOutputStreams, } from './default-llm-ports.js';
44
44
  export { SUBAGENT_REGISTRATION_WIRE_TYPE, SUBAGENT_RESULT_WIRE_TYPE, SUBAGENT_SPAWN_WIRE_TYPE, } from './llm-inventory-wire.js';
45
45
  export { STEER_CONTROL_PORT_ID, isSteerControlContinue, isSteerControlPause, isSteerControlPayload, type SteerControlPayload, type SteerControlPause, type SteerControlResume, type SteerControlSteer, } from './steer-control.js';
46
- export { RECOVERY_PORT_ID, isLlmRecoveryNotice, isLlmRecoverySuspended, recoveryNoticeText, type LlmRecoveryNotice, type LlmRecoveryNoticeCode, } from './recovery-notice.js';
46
+ export { RECOVERY_PORT_ID, isLlmRecoveryNotice, isLlmRecoverySuspended, recoveryNoticeText, toLlmRecoveryPortValue, type LlmRecoveryNotice, type LlmRecoveryNoticeCode, type LlmRecoveryRetryReason, } from './recovery-notice.js';
@@ -48,4 +48,4 @@ export const defineLlmNode = (config) => {
48
48
  export { LLM_INVENTORY_INPUT_PORT_IDS, LLM_INVENTORY_OUTPUT_PORT_IDS, } from './default-llm-ports.js';
49
49
  export { SUBAGENT_REGISTRATION_WIRE_TYPE, SUBAGENT_RESULT_WIRE_TYPE, SUBAGENT_SPAWN_WIRE_TYPE, } from './llm-inventory-wire.js';
50
50
  export { STEER_CONTROL_PORT_ID, isSteerControlContinue, isSteerControlPause, isSteerControlPayload, } from './steer-control.js';
51
- export { RECOVERY_PORT_ID, isLlmRecoveryNotice, isLlmRecoverySuspended, recoveryNoticeText, } from './recovery-notice.js';
51
+ export { RECOVERY_PORT_ID, isLlmRecoveryNotice, isLlmRecoverySuspended, recoveryNoticeText, toLlmRecoveryPortValue, } from './recovery-notice.js';
@@ -5,10 +5,18 @@
5
5
  */
6
6
  export declare const RECOVERY_PORT_ID: "recovery";
7
7
  export type LlmRecoveryNoticeCode = 'retry' | 'suspended';
8
+ export type LlmRecoveryRetryReason = 'idle' | 'dead-loop' | 'rate-limit' | 'provider-unavailable' | 'network';
8
9
  export type LlmRecoveryNotice = {
9
10
  readonly code: LlmRecoveryNoticeCode;
10
11
  readonly text: string;
12
+ readonly attempt?: number;
13
+ readonly reason?: LlmRecoveryRetryReason;
14
+ readonly lastAttemptAt?: number;
15
+ readonly nextAttemptAt?: number;
16
+ readonly backoffMs?: number;
11
17
  };
12
18
  export declare const isLlmRecoveryNotice: (value: unknown) => value is LlmRecoveryNotice;
13
19
  export declare const isLlmRecoverySuspended: (value: unknown) => boolean;
14
20
  export declare const recoveryNoticeText: (value: unknown) => string;
21
+ /** Port payload: `code` + `text` plus any additive timing fields. */
22
+ export declare const toLlmRecoveryPortValue: (notice: LlmRecoveryNotice) => LlmRecoveryNotice;
@@ -22,3 +22,17 @@ export const recoveryNoticeText = (value) => {
22
22
  }
23
23
  return '';
24
24
  };
25
+ /** Port payload: `code` + `text` plus any additive timing fields. */
26
+ export const toLlmRecoveryPortValue = (notice) => ({
27
+ code: notice.code,
28
+ text: notice.text,
29
+ ...(notice.attempt !== undefined ? { attempt: notice.attempt } : {}),
30
+ ...(notice.reason !== undefined ? { reason: notice.reason } : {}),
31
+ ...(notice.lastAttemptAt !== undefined
32
+ ? { lastAttemptAt: notice.lastAttemptAt }
33
+ : {}),
34
+ ...(notice.nextAttemptAt !== undefined
35
+ ? { nextAttemptAt: notice.nextAttemptAt }
36
+ : {}),
37
+ ...(notice.backoffMs !== undefined ? { backoffMs: notice.backoffMs } : {}),
38
+ });
@@ -1,5 +1,5 @@
1
1
  import { GraphCluster } from './runtime-helpers.js';
2
- import { RuntimeEdge, RuntimeEditorApi, RuntimeNode, type EdgeId, type NodeId } from './types.js';
2
+ import { RuntimeEdge, RuntimeEditorApi, RuntimeNode, type EdgeId, type NodeId, type SwapNodeResult } from './types.js';
3
3
  export declare class RuntimeEditor implements RuntimeEditorApi {
4
4
  /** Node ID -> node definition. */
5
5
  private readonly nodes;
@@ -20,6 +20,10 @@ export declare class RuntimeEditor implements RuntimeEditorApi {
20
20
  * Composer: find occupying → prepare → swap → cleanup/rollback → refresh.
21
21
  */
22
22
  replaceEdge(edgeInput: Omit<RuntimeEdge, 'edgeId'>): RuntimeEdge | false;
23
+ /**
24
+ * Replace the live instance at `nodeId` with `next`. Allowed while locked.
25
+ */
26
+ swapNode(nodeId: NodeId, next: Omit<RuntimeNode, 'nodeId'>): SwapNodeResult | false;
23
27
  removeNode(nodeId: NodeId): RuntimeNode | false;
24
28
  removeEdge(edgeId: EdgeId): RuntimeNode[];
25
29
  getNode(nodeId: NodeId): RuntimeNode | false;
@@ -108,6 +108,25 @@ export class RuntimeEditor {
108
108
  this.refreshClusters();
109
109
  return occupying;
110
110
  }
111
+ /**
112
+ * Replace the live instance at `nodeId` with `next`. Allowed while locked.
113
+ */
114
+ swapNode(nodeId, next) {
115
+ if (this.disposed) {
116
+ return false;
117
+ }
118
+ if (!this.nodes.has(nodeId)) {
119
+ return false;
120
+ }
121
+ const runtimeNode = materializeBypassNodeOnAdd({
122
+ ...next,
123
+ nodeId,
124
+ });
125
+ this.nodes.set(nodeId, runtimeNode);
126
+ const droppedEdges = this.cleanupInvalidEdges();
127
+ this.refreshClusters();
128
+ return { node: runtimeNode, droppedEdges };
129
+ }
111
130
  removeNode(nodeId) {
112
131
  if (this.disposed) {
113
132
  return false;
@@ -239,18 +239,18 @@ export class RuntimeRunner {
239
239
  }
240
240
  this.eventsSubject.next(event);
241
241
  }
242
- emitPortEvent(runId, kind, nodeId, portId, portIdx, state, value, edgeIds, feed) {
243
- this.emitRunnerEvent({
244
- kind,
245
- runId,
242
+ emitPortEvent(_runId, portDir, nodeId, portId, portIdx, state, value, edgeIds, feed) {
243
+ const portIdStr = typeof portId === 'string' ? portId : String(portId);
244
+ this.emitRunnerEvent([
245
+ portDir,
246
246
  nodeId,
247
- portId,
248
- portIdx,
249
- edgeIds,
247
+ portIdStr,
250
248
  state,
251
249
  value,
252
- ...(feed !== undefined ? { feed } : {}),
253
- });
250
+ portIdx,
251
+ edgeIds,
252
+ feed ?? null,
253
+ ]);
254
254
  }
255
255
  canPreparePushedInput(node, portId) {
256
256
  const connection = node.inputs[portId];
@@ -281,7 +281,7 @@ export class RuntimeRunner {
281
281
  if (existing !== undefined) {
282
282
  // Telemetry before deliver so HITL input-received precedes cascade
283
283
  // (output-emitted / downstream input-received) in the event log.
284
- this.emitPortEvent(run.runId, 'input-received', cfg.nodeId, cfg.portId, 0, 'value', cfg.payload, []);
284
+ this.emitPortEvent(run.runId, 'in', cfg.nodeId, cfg.portId, 0, 'value', cfg.payload, []);
285
285
  existing.source.next(cfg.payload);
286
286
  return run.runId;
287
287
  }
@@ -300,7 +300,7 @@ export class RuntimeRunner {
300
300
  connection,
301
301
  });
302
302
  run.pushedInputSources.set(key, { source });
303
- this.emitPortEvent(run.runId, 'input-received', cfg.nodeId, cfg.portId, 0, 'value', cfg.payload, []);
303
+ this.emitPortEvent(run.runId, 'in', cfg.nodeId, cfg.portId, 0, 'value', cfg.payload, []);
304
304
  source.next(cfg.payload);
305
305
  return run.runId;
306
306
  }
@@ -326,7 +326,7 @@ export class RuntimeRunner {
326
326
  if (resolved === null) {
327
327
  return;
328
328
  }
329
- this.emitPortEvent(run.runId, 'output-emitted', nodeId, portId, 0, resolved.state, resolved.value, edgeIds, output.meta.feed);
329
+ this.emitPortEvent(run.runId, 'out', nodeId, portId, 0, resolved.state, resolved.value, edgeIds, output.meta.feed);
330
330
  if (resolved.state === 'value' &&
331
331
  node !== false &&
332
332
  node.stopsRun === true) {
@@ -357,7 +357,7 @@ export class RuntimeRunner {
357
357
  if (resolved === null) {
358
358
  return;
359
359
  }
360
- this.emitPortEvent(run.runId, 'input-received', nodeId, portId, slotIndex, resolved.state, resolved.value, edgeIds);
360
+ this.emitPortEvent(run.runId, 'in', nodeId, portId, slotIndex, resolved.state, resolved.value, edgeIds);
361
361
  },
362
362
  }))
363
363
  .with({ meta: source.meta });
@@ -369,7 +369,7 @@ export class RuntimeRunner {
369
369
  if (this.activeRun !== undefined && this.activeRun.runId !== runId) {
370
370
  return;
371
371
  }
372
- this.emitRunnerEvent({ kind: 'done', runId });
372
+ this.emitRunnerEvent(['done', runId]);
373
373
  this.setStatus('idle');
374
374
  this.teardownRun();
375
375
  }
@@ -429,7 +429,7 @@ export class RuntimeRunner {
429
429
  connection.connect(of(seed.value).pipe(tap({
430
430
  next: (value) => {
431
431
  if (typeof seed.portId !== 'symbol') {
432
- this.emitPortEvent(runId, 'input-received', nodeId, seed.portId, seed.slotIndex, 'value', value, []);
432
+ this.emitPortEvent(runId, 'in', nodeId, seed.portId, seed.slotIndex, 'value', value, []);
433
433
  }
434
434
  },
435
435
  })));
@@ -467,7 +467,7 @@ export class RuntimeRunner {
467
467
  }
468
468
  connection.connect(of(defaultValue).pipe(tap({
469
469
  next: (value) => {
470
- this.emitPortEvent(runId, 'input-received', nodeId, portId, 0, 'value', value, []);
470
+ this.emitPortEvent(runId, 'in', nodeId, portId, 0, 'value', value, []);
471
471
  },
472
472
  })));
473
473
  wiredSlotKeys.add(key);
@@ -705,7 +705,7 @@ export class RuntimeRunner {
705
705
  if (resolved === null) {
706
706
  return;
707
707
  }
708
- this.emitPortEvent(run.runId, 'input-received', group.nodeId, group.portId, 0, resolved.state, resolved.value, group.edges.map((entry) => entry.edge.edgeId));
708
+ this.emitPortEvent(run.runId, 'in', group.nodeId, group.portId, 0, resolved.state, resolved.value, group.edges.map((entry) => entry.edge.edgeId));
709
709
  },
710
710
  })));
711
711
  wiredSlots.push({
@@ -6,7 +6,8 @@ export { RuntimeEditor } from './runtime-editor.js';
6
6
  export { graphHasCycle } from './runtime-helpers.js';
7
7
  export type { GraphCluster } from './runtime-helpers.js';
8
8
  export { RuntimeRunner } from './runtime-runner.js';
9
- export type { MetaFromStatefulObservable, NodeId, EdgeId, RunId, PortMeta, RuntimeEdge, RuntimeEditorApi, RuntimeFeedPortMeta, RuntimeFeedRole, RuntimeInputReceivedEvent, RuntimeNode, RuntimeOutputEmittedEvent, RuntimePortSignalState, RuntimeResumeOptions, RuntimeRunnerApi, RuntimeRunnerEvent, RuntimeRunnerStatus, RuntimeSeedPortValue, RuntimeWireType, } from './types.js';
9
+ export type { MetaFromStatefulObservable, NodeId, EdgeId, RunId, PortMeta, RuntimeEdge, RuntimeEditorApi, RuntimeFeedPortMeta, RuntimeFeedRole, PortTelemetry, RuntimeDoneTelemetry, RuntimeNode, RuntimePortSignalState, RuntimeResumeOptions, RuntimeRunnerApi, RuntimeRunnerEvent, RuntimeRunnerStatus, RuntimeSeedPortValue, RuntimeWireType, SwapNodeResult, } from './types.js';
10
+ export { isPortTelemetry, isRuntimeDone } from './types.js';
10
11
  export type { RuntimeOptions };
11
12
  export declare class RuntimeFacade {
12
13
  readonly editor: RuntimeEditor;
@@ -4,6 +4,7 @@ export { bypassOutputPortId, parseBypassOutputPortId } from './bypass-ports.js';
4
4
  export { RuntimeEditor } from './runtime-editor.js';
5
5
  export { graphHasCycle } from './runtime-helpers.js';
6
6
  export { RuntimeRunner } from './runtime-runner.js';
7
+ export { isPortTelemetry, isRuntimeDone } from './types.js';
7
8
  export class RuntimeFacade {
8
9
  editor;
9
10
  runner;
@@ -1,20 +1,22 @@
1
+ import { type EdgeId, type PortTelemetry, type RunId, type RuntimeEdge, type RuntimeRunnerEvent } from '../../types.js';
1
2
  import { RuntimeEditor } from '../../runtime-editor.js';
2
3
  import { RuntimeRunner } from '../../runtime-runner.js';
3
4
  import { type RuntimeOptions } from '../../runtime.js';
4
- import type { RunId, RuntimeEdge, RuntimeRunnerEvent } from '../../types.js';
5
5
  export type RuntimeHarness = {
6
6
  readonly editor: RuntimeEditor;
7
7
  readonly runner: RuntimeRunner;
8
8
  };
9
9
  export declare function createRuntimeHarness(options?: RuntimeOptions): RuntimeHarness;
10
10
  export declare function wireEdge(editor: RuntimeEditor, edge: Omit<RuntimeEdge, 'edgeId'>): void;
11
- export type OutputEmittedEvent = Extract<RuntimeRunnerEvent, {
12
- kind: 'output-emitted';
13
- }>;
14
- export declare function outputValues(events: readonly RuntimeRunnerEvent[], nodeId: string, portId: string, runId?: string): unknown[];
15
- export declare function waitForOutput(runtime: RuntimeRunner | RuntimeHarness, nodeId: string, portId: string, runId?: string): Promise<OutputEmittedEvent>;
11
+ export type OutputEmittedEvent = PortTelemetry & {
12
+ readonly 0: 'out';
13
+ };
14
+ export declare function outputValues(events: readonly RuntimeRunnerEvent[], nodeId: string, portId: string, _runId?: string): unknown[];
15
+ export declare function waitForOutput(runtime: RuntimeRunner | RuntimeHarness, nodeId: string, portId: string, _runId?: string): Promise<OutputEmittedEvent>;
16
16
  export declare function runAndCollectEvents(runtime: RuntimeRunner | RuntimeHarness, startRun: () => string, settleMs?: number): Promise<{
17
17
  readonly runId: string;
18
18
  readonly events: readonly RuntimeRunnerEvent[];
19
19
  }>;
20
20
  export declare function noDoneWithin(runtime: RuntimeRunner | RuntimeHarness, ms: number, runId?: RunId): Promise<boolean>;
21
+ export declare const edgeIdsFromPortEvent: (event: PortTelemetry) => readonly EdgeId[];
22
+ export declare const portDirLabel: (event: PortTelemetry) => "input-received" | "output-emitted";