langflower 0.0.9 → 0.1.0

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 (223) hide show
  1. package/README.md +96 -70
  2. package/docs/public/README.md +2 -2
  3. package/docs/public/configuration.md +4 -0
  4. package/docs/public/extending.md +18 -2
  5. package/docs/public/getting-started.md +7 -0
  6. package/docs/public/how-it-works.md +18 -11
  7. package/docs/public/product.md +35 -25
  8. package/package.json +2 -2
  9. package/ui-dist/chunk-QI4IYILJ.js +4 -0
  10. package/ui-dist/{chunk-7UMVYN3A.js → chunk-UG3GFV4Y.js} +1 -1
  11. package/ui-dist/index.html +2 -2
  12. package/ui-dist/main-ODIDCCNX.js +315 -0
  13. package/ui-dist/styles-2JMBAQC3.css +1 -0
  14. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-reducer.js +0 -12
  15. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.d.ts +2 -7
  16. package/vendor/common-nodes/dist/ai/features/llm-loop/llm-loop-types.js +1 -1
  17. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.d.ts +0 -3
  18. package/vendor/common-nodes/dist/ai/features/llm-loop/run-agent-loop.js +22 -36
  19. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.d.ts +1 -7
  20. package/vendor/common-nodes/dist/ai/features/llm-loop/run-llm-loop.js +12 -35
  21. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.d.ts +5 -12
  22. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.js +48 -21
  23. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.d.ts +11 -0
  24. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.js +2 -2
  25. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.d.ts +0 -3
  26. package/vendor/common-nodes/dist/ai/features/path-choice/run-reactive-path-choice-loop.js +2 -15
  27. package/vendor/common-nodes/dist/ai/features/run-host-services.d.ts +10 -0
  28. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.d.ts +1 -0
  29. package/vendor/common-nodes/dist/ai/features/sub-agent-protocol.js +1 -0
  30. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.d.ts +1 -1
  31. package/vendor/common-nodes/dist/ai/features/ui-schema/llm-recovery-ui-schema.js +1 -1
  32. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.d.ts +1 -0
  33. package/vendor/common-nodes/dist/ai/features/wait-for-subagent-result.js +1 -0
  34. package/vendor/common-nodes/dist/ai/nodes/critique/node.d.ts +3 -3
  35. package/vendor/common-nodes/dist/ai/nodes/critique/node.js +10 -19
  36. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.d.ts +3 -3
  37. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.js +10 -11
  38. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.d.ts +3 -3
  39. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.js +7 -10
  40. package/vendor/common-nodes/dist/ai/nodes/review/node.d.ts +3 -3
  41. package/vendor/common-nodes/dist/ai/nodes/review/node.js +12 -19
  42. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.d.ts +5 -5
  43. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.js +251 -96
  44. package/vendor/common-nodes/dist/catalog.js +12 -0
  45. package/vendor/common-nodes/dist/crawl/crawl/node.js +11 -3
  46. package/vendor/common-nodes/dist/crawl/crawl-tools/node.js +5 -1
  47. package/vendor/common-nodes/dist/crawl/extract-links/node.js +7 -1
  48. package/vendor/common-nodes/dist/crawl/fetch-url/node.js +13 -4
  49. package/vendor/common-nodes/dist/crawl/save-page/node.js +11 -3
  50. package/vendor/common-nodes/dist/embeddings/create-embedding.d.ts +39 -0
  51. package/vendor/common-nodes/dist/embeddings/create-embedding.js +154 -0
  52. package/vendor/common-nodes/dist/embeddings/embed-provider/node.d.ts +53 -0
  53. package/vendor/common-nodes/dist/embeddings/embed-provider/node.js +126 -0
  54. package/vendor/common-nodes/dist/embeddings/embed-similarity/node.d.ts +20 -0
  55. package/vendor/common-nodes/dist/embeddings/embed-similarity/node.js +81 -0
  56. package/vendor/common-nodes/dist/embeddings/embed-text/node.d.ts +53 -0
  57. package/vendor/common-nodes/dist/embeddings/embed-text/node.js +91 -0
  58. package/vendor/common-nodes/dist/embeddings/from-embedding.d.ts +8 -0
  59. package/vendor/common-nodes/dist/embeddings/from-embedding.js +24 -0
  60. package/vendor/common-nodes/dist/embeddings/resolve-embedding-provider-model.d.ts +11 -0
  61. package/vendor/common-nodes/dist/embeddings/resolve-embedding-provider-model.js +8 -0
  62. package/vendor/common-nodes/dist/flow/checkpoint/node.js +7 -3
  63. package/vendor/common-nodes/dist/flow/delay/node.d.ts +2 -6
  64. package/vendor/common-nodes/dist/flow/delay/node.js +13 -9
  65. package/vendor/common-nodes/dist/flow/loop/node.js +7 -1
  66. package/vendor/common-nodes/dist/flow/merge/node.js +7 -1
  67. package/vendor/common-nodes/dist/flow/repeat/node.js +5 -1
  68. package/vendor/common-nodes/dist/flow/router/node.js +7 -1
  69. package/vendor/common-nodes/dist/hitl/chat-input/node.d.ts +2 -2
  70. package/vendor/common-nodes/dist/hitl/chat-input/node.js +8 -4
  71. package/vendor/common-nodes/dist/hitl/review-gate/node.js +11 -5
  72. package/vendor/common-nodes/dist/langflower-tools/node.js +5 -1
  73. package/vendor/common-nodes/dist/logic/assert/node.js +7 -1
  74. package/vendor/common-nodes/dist/logic/compare/node.js +7 -1
  75. package/vendor/common-nodes/dist/logic/gate/node.js +7 -1
  76. package/vendor/common-nodes/dist/logic/if/node.js +7 -1
  77. package/vendor/common-nodes/dist/logic/switch/node.js +7 -1
  78. package/vendor/common-nodes/dist/mcp/mcp-http/node.d.ts +4 -4
  79. package/vendor/common-nodes/dist/mcp/mcp-http/node.js +61 -60
  80. package/vendor/common-nodes/dist/mcp/mcp-stdio/node.d.ts +4 -4
  81. package/vendor/common-nodes/dist/mcp/mcp-stdio/node.js +58 -57
  82. package/vendor/common-nodes/dist/memory/memory-tools/node.js +5 -1
  83. package/vendor/common-nodes/dist/output/finish/node.js +13 -1
  84. package/vendor/common-nodes/dist/output/preview/node.js +9 -2
  85. package/vendor/common-nodes/dist/primitives/boolean/node.js +7 -1
  86. package/vendor/common-nodes/dist/primitives/number/node.js +7 -1
  87. package/vendor/common-nodes/dist/primitives/string/node.js +7 -1
  88. package/vendor/common-nodes/dist/primitives/string-multiline/node.d.ts +17 -0
  89. package/vendor/common-nodes/dist/primitives/string-multiline/node.js +31 -0
  90. package/vendor/common-nodes/dist/text/append-file/node.js +11 -3
  91. package/vendor/common-nodes/dist/text/concat/node.js +5 -1
  92. package/vendor/common-nodes/dist/text/read-file/node.js +9 -3
  93. package/vendor/common-nodes/dist/text/split-paced/node.d.ts +21 -0
  94. package/vendor/common-nodes/dist/text/split-paced/node.js +93 -0
  95. package/vendor/common-nodes/dist/text/write-file/node.js +11 -3
  96. package/vendor/common-nodes/dist/tools/collect-agent-tool-handles.d.ts +4 -4
  97. package/vendor/common-nodes/dist/tools/collect-agent-tool-handles.js +3 -11
  98. package/vendor/common-nodes/dist/tools/inventory-tool-round.d.ts +0 -10
  99. package/vendor/common-nodes/dist/tools/inventory-tool-round.js +0 -84
  100. package/vendor/common-nodes/dist/tools/tool-collection/node.d.ts +20 -0
  101. package/vendor/common-nodes/dist/tools/tool-collection/node.js +45 -0
  102. package/vendor/common-nodes/package.json +5 -5
  103. package/vendor/compiler/package.json +1 -1
  104. package/vendor/node-sdk/dist/node-factory/define-embed/embed-handle.d.ts +25 -0
  105. package/vendor/node-sdk/dist/node-factory/define-embed/embed-handle.js +25 -0
  106. package/vendor/node-sdk/dist/node-factory/define-llm-node/default-llm-ports.d.ts +3 -7
  107. package/vendor/node-sdk/dist/node-factory/define-llm-node/default-llm-ports.js +4 -44
  108. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.d.ts +3 -5
  109. package/vendor/node-sdk/dist/node-factory/define-llm-node/define-llm-node.js +3 -5
  110. package/vendor/node-sdk/dist/node-factory/define-llm-node/llm-inventory-wire.d.ts +1 -0
  111. package/vendor/node-sdk/dist/node-factory/define-llm-node/llm-inventory-wire.js +1 -0
  112. package/vendor/node-sdk/dist/node-factory/define-mcp/mcp-handle.d.ts +4 -4
  113. package/vendor/node-sdk/dist/node-factory/define-mcp/mcp-handle.js +2 -1
  114. package/vendor/node-sdk/dist/node-factory/define-node/define-node.d.ts +2 -0
  115. package/vendor/node-sdk/dist/node-factory/define-node/define-node.js +4 -1
  116. package/vendor/node-sdk/dist/node-factory/define-reactive-node/define-reactive-node.d.ts +3 -1
  117. package/vendor/node-sdk/dist/node-factory/define-reactive-node/define-reactive-node.js +2 -1
  118. package/vendor/node-sdk/dist/node-factory/define-reactive-node/io-helpers.d.ts +15 -0
  119. package/vendor/node-sdk/dist/node-factory/define-reactive-node/io-helpers.js +17 -1
  120. package/vendor/node-sdk/dist/node-factory/define-reactive-node/port-meta.d.ts +17 -4
  121. package/vendor/node-sdk/dist/node-factory/define-reactive-node/test/samples/delay-node.js +4 -2
  122. package/vendor/node-sdk/dist/node-factory/define-reactive-node/types.d.ts +6 -7
  123. package/vendor/node-sdk/dist/node-factory/define-reactive-node/ui-schema-inference.d.ts +1 -1
  124. package/vendor/node-sdk/dist/testing/create-node-harness.d.ts +30 -0
  125. package/vendor/node-sdk/dist/testing/create-node-harness.js +68 -0
  126. package/vendor/node-sdk/package.json +5 -5
  127. package/vendor/runtime/dist/port-feed-override.d.ts +13 -0
  128. package/vendor/runtime/dist/port-feed-override.js +21 -0
  129. package/vendor/runtime/dist/port-signal-from-response.d.ts +15 -0
  130. package/vendor/runtime/dist/port-signal-from-response.js +48 -0
  131. package/vendor/runtime/dist/runtime-runner.d.ts +8 -3
  132. package/vendor/runtime/dist/runtime-runner.js +102 -81
  133. package/vendor/runtime/dist/runtime.d.ts +3 -2
  134. package/vendor/runtime/dist/runtime.js +1 -1
  135. package/vendor/runtime/dist/testing/workflows/workflow-events.d.ts +2 -0
  136. package/vendor/runtime/dist/testing/workflows/workflow-events.js +7 -5
  137. package/vendor/runtime/dist/types.d.ts +26 -9
  138. package/vendor/runtime/dist/types.js +3 -0
  139. package/vendor/runtime/package.json +1 -1
  140. package/vendor/server/dist/bootstrap/project-bootstrap.service.d.ts +1 -1
  141. package/vendor/server/dist/bootstrap/seed-skeleton.d.ts +2 -2
  142. package/vendor/server/dist/bootstrap/seed-skeleton.js +17 -2
  143. package/vendor/server/dist/bridge/bind-embed-context.d.ts +7 -0
  144. package/vendor/server/dist/bridge/bind-embed-context.js +16 -0
  145. package/vendor/server/dist/bridge/build-execution-context.d.ts +2 -2
  146. package/vendor/server/dist/bridge/build-execution-context.js +8 -4
  147. package/vendor/server/dist/bridge/emit-bootstrap.js +4 -1
  148. package/vendor/server/dist/bridge/get-live-wired-tools.d.ts +3 -2
  149. package/vendor/server/dist/bridge/get-live-wired-tools.js +8 -5
  150. package/vendor/server/dist/bridge/settings-draft-controller.js +7 -3
  151. package/vendor/server/dist/bridge/wire-config-handlers.js +2 -0
  152. package/vendor/server/dist/bridge/wire-editor-handlers.js +14 -0
  153. package/vendor/server/dist/bridge/wire-runner-handlers.js +2 -2
  154. package/vendor/server/dist/bridge/wire-workflow-handlers.js +23 -9
  155. package/vendor/server/dist/checkpoint/run-checkpoint-session.js +3 -3
  156. package/vendor/server/dist/config/langflower-config.service.d.ts +2 -0
  157. package/vendor/server/dist/config/langflower-config.service.js +30 -0
  158. package/vendor/server/dist/session/build-session-bootstrap.js +1 -0
  159. package/vendor/server/dist/session/langflower-session.d.ts +3 -1
  160. package/vendor/server/dist/session/langflower-session.js +3 -1
  161. package/vendor/server/dist/session/reset-session-execution-feed.d.ts +6 -0
  162. package/vendor/server/dist/session/reset-session-execution-feed.js +8 -0
  163. package/vendor/server/dist/workflow/apply-editor-mutation.js +6 -0
  164. package/vendor/server/dist/workflow/workflow-persisted-inputs.js +8 -6
  165. package/vendor/server/skeleton/instructions.md +15 -3
  166. package/vendor/server/skeleton/nodes/hello-embed/README.md +185 -0
  167. package/vendor/server/skeleton/nodes/hello-embed/hello-embed.nodes.test.ts +181 -0
  168. package/vendor/server/skeleton/nodes/hello-embed/ingest.ts +126 -0
  169. package/vendor/server/skeleton/nodes/hello-embed/lib/chunk-markdown.test.ts +40 -0
  170. package/vendor/server/skeleton/nodes/hello-embed/lib/chunk-markdown.ts +123 -0
  171. package/vendor/server/skeleton/nodes/hello-embed/lib/ingest-search.test.ts +180 -0
  172. package/vendor/server/skeleton/nodes/hello-embed/lib/ingest.ts +128 -0
  173. package/vendor/server/skeleton/nodes/hello-embed/lib/paths.test.ts +20 -0
  174. package/vendor/server/skeleton/nodes/hello-embed/lib/paths.ts +70 -0
  175. package/vendor/server/skeleton/nodes/hello-embed/lib/schema.ts +21 -0
  176. package/vendor/server/skeleton/nodes/hello-embed/lib/search.ts +254 -0
  177. package/vendor/server/skeleton/nodes/hello-embed/lib/text-embedder.ts +14 -0
  178. package/vendor/server/skeleton/nodes/hello-embed/lib/vectors.ts +126 -0
  179. package/vendor/server/skeleton/nodes/hello-embed/lib/walk-markdown.test.ts +62 -0
  180. package/vendor/server/skeleton/nodes/hello-embed/lib/walk-markdown.ts +67 -0
  181. package/vendor/server/skeleton/nodes/hello-embed/package.json +11 -0
  182. package/vendor/server/skeleton/nodes/hello-embed/search-handle.ts +119 -0
  183. package/vendor/server/skeleton/nodes/hello-embed/search.ts +98 -0
  184. package/vendor/server/skeleton/nodes/hello-embed/tsconfig.json +14 -0
  185. package/vendor/server/skeleton/nodes/my-nodes/README.md +13 -3
  186. package/vendor/server/skeleton/nodes/my-nodes/package.json +1 -1
  187. package/vendor/server/skeleton/schemas/langflower-config.schema.json +4 -0
  188. package/vendor/server/skeleton/skills/langflower-helper/SKILL.md +125 -38
  189. package/vendor/server/skeleton/skills/langflower-helper/architecture.md +17 -6
  190. package/vendor/server/skeleton/skills/langflower-helper/layout.md +24 -17
  191. package/vendor/server/skeleton/skills/langflower-node-writer/SKILL.md +8 -1
  192. package/vendor/server/skeleton/skills/langflower-workflow-writer/SKILL.md +12 -8
  193. package/vendor/server/skeleton/workflows/kb-create.json +15 -43
  194. package/vendor/server/skeleton/workflows/kb-ingest.json +88 -0
  195. package/vendor/server/skeleton/workflows/kb-manual-search.json +105 -0
  196. package/vendor/server/skeleton/workflows/kb-navigate.json +8 -22
  197. package/vendor/server/skeleton/workflows/kb-rag.json +192 -0
  198. package/vendor/server/skeleton/workflows/kb-tool.json +111 -0
  199. package/vendor/server/skeleton/workflows/simple-coder.json +18 -46
  200. package/vendor/server/skeleton/workflows/starter.json +8 -22
  201. package/vendor/shared/dist/execution/derive-run-settle-outcome.js +2 -2
  202. package/vendor/shared/dist/execution/derive-run-settle-outcome.test.js +11 -8
  203. package/vendor/shared/dist/langflower-bus-config.d.ts +22 -6
  204. package/vendor/shared/dist/langflower-bus-config.js +23 -7
  205. package/vendor/shared/dist/langflower-config/merge-langflower-config-layers.test.js +8 -0
  206. package/vendor/shared/dist/langflower-config/settings-draft.d.ts +5 -0
  207. package/vendor/shared/dist/langflower-config/settings-draft.js +15 -7
  208. package/vendor/shared/dist/langflower-ws-waits.d.ts +3 -1
  209. package/vendor/shared/dist/langflower-ws-waits.js +2 -2
  210. package/vendor/shared/dist/langflower.d.ts +1 -1
  211. package/vendor/shared/dist/langflower.js +1 -1
  212. package/vendor/shared/dist/types/langflower-bootstrap.d.ts +6 -0
  213. package/vendor/shared/dist/types/langflower-config.d.ts +17 -0
  214. package/vendor/shared/dist/types/langflower-palette.d.ts +2 -1
  215. package/vendor/tools/dist/harness-types.d.ts +1 -1
  216. package/vendor/tools/dist/mcp/build-mcp-handle.d.ts +3 -21
  217. package/vendor/tools/dist/mcp/build-mcp-handle.js +2 -11
  218. package/vendor/tools/dist/mcp/create-system-mcp-handles.d.ts +9 -6
  219. package/vendor/tools/dist/mcp/create-system-mcp-handles.js +21 -17
  220. package/vendor/tools/package.json +1 -0
  221. package/ui-dist/chunk-MDGXX73Z.js +0 -4
  222. package/ui-dist/main-2JJGCNTD.js +0 -313
  223. package/ui-dist/styles-EOXODOI7.css +0 -1
@@ -4,11 +4,11 @@ export type SeedSkeletonResult = {
4
4
  };
5
5
  export type SeedSkeletonOptions = {
6
6
  readonly mode: SeedSkeletonMode;
7
- /** When false, leave `nodes/` empty (no skeleton `my-nodes`). Default true. */
7
+ /** When false, leave `nodes/` empty (no skeleton packs). Default true. */
8
8
  readonly seedCustomNodes?: boolean;
9
9
  };
10
10
  /**
11
- * Copy skeleton workflows, skills, my-nodes, and instructions into
11
+ * Copy skeleton workflows, skills, custom-node packs, and instructions into
12
12
  * `.langflower/`. Create mode skips existing paths; force overwrites
13
13
  * skeleton-owned files (extra project-only files stay).
14
14
  */
@@ -23,8 +23,21 @@ const listSkeletonSkillIds = async (skeletonRoot) => {
23
23
  return [];
24
24
  }
25
25
  };
26
+ const listSkeletonPackIds = async (skeletonRoot) => {
27
+ const nodesDir = path.join(skeletonRoot, 'nodes');
28
+ try {
29
+ const entries = await fs.readdir(nodesDir, { withFileTypes: true });
30
+ return entries
31
+ .filter((entry) => entry.isDirectory())
32
+ .map((entry) => entry.name)
33
+ .sort();
34
+ }
35
+ catch {
36
+ return [];
37
+ }
38
+ };
26
39
  /**
27
- * Copy skeleton workflows, skills, my-nodes, and instructions into
40
+ * Copy skeleton workflows, skills, custom-node packs, and instructions into
28
41
  * `.langflower/`. Create mode skips existing paths; force overwrites
29
42
  * skeleton-owned files (extra project-only files stay).
30
43
  */
@@ -34,7 +47,9 @@ export const seedSkeletonContent = async (skeletonRoot, langflowerDir, options)
34
47
  const copyFile = mode === 'force' ? copyFileForce : copyFileIfMissing;
35
48
  const copyDir = mode === 'force' ? copyDirForce : copyDirIfMissing;
36
49
  if (seedCustomNodes) {
37
- await copyDir(path.join(skeletonRoot, 'nodes', 'my-nodes'), path.join(langflowerDir, 'nodes', 'my-nodes'));
50
+ for (const packId of await listSkeletonPackIds(skeletonRoot)) {
51
+ await copyDir(path.join(skeletonRoot, 'nodes', packId), path.join(langflowerDir, 'nodes', packId));
52
+ }
38
53
  }
39
54
  else {
40
55
  await fs.mkdir(path.join(langflowerDir, 'nodes'), { recursive: true });
@@ -0,0 +1,7 @@
1
+ import { type CreateEmbedding } from '@langflower/common-nodes/embeddings/create-embedding';
2
+ import type { LangflowerConfigService } from '../config/langflower-config.service.js';
3
+ /**
4
+ * Thin credential bind: secrets stay server-side; embeddings HTTP lives in
5
+ * common-nodes.
6
+ */
7
+ export declare const bindCreateEmbedding: (langflowerConfigService: LangflowerConfigService) => CreateEmbedding;
@@ -0,0 +1,16 @@
1
+ import { createEmbedding, } from '@langflower/common-nodes/embeddings/create-embedding';
2
+ import { resolveProviderCredentials } from '../config/resolve-provider-credentials.js';
3
+ /**
4
+ * Thin credential bind: secrets stay server-side; embeddings HTTP lives in
5
+ * common-nodes.
6
+ */
7
+ export const bindCreateEmbedding = (langflowerConfigService) => createEmbedding({
8
+ resolveProvider: async (providerId) => {
9
+ const config = await langflowerConfigService.read();
10
+ const resolved = resolveProviderCredentials(config, providerId);
11
+ if (!resolved.ok) {
12
+ throw new Error(resolved.message);
13
+ }
14
+ return resolved.credentials;
15
+ },
16
+ });
@@ -1,9 +1,9 @@
1
1
  import type { LangflowerBusRequest } from '@langflower/common-nodes/ai/run-host-services';
2
2
  import { type ExecutionContext, type ToolHandle } from '@langflower/node-sdk';
3
3
  import type { LlmExecutionCaps } from '@langflower/node-sdk/llm';
4
- import type { McpHandle } from '@langflower/node-sdk/mcp';
5
4
  import type { RuntimeSeedPortValue } from '@langflower/runtime';
6
5
  import { type LangflowerConfig, type RunnerPermissionAskPayload } from '@langflower/shared/langflower.js';
6
+ import { type SystemMcpServerTools } from '@langflower/tools/create-system-mcp-handles';
7
7
  import type { ServerContext } from '../server-context.js';
8
8
  import type { LangflowerSession } from '../session/langflower-session.js';
9
9
  type WorkflowGraphNode = {
@@ -20,7 +20,7 @@ type BuildHarnessHooks = {
20
20
  readonly requestLangflowerBus?: LangflowerBusRequest;
21
21
  readonly getLiveWiredTools?: (agentNodeId: string) => readonly ToolHandle[];
22
22
  };
23
- export declare const buildExecutionContext: (context: ExecutionContextDeps, runId: string, node: WorkflowGraphNode, hooks?: BuildHarnessHooks, preloadedConfig?: LangflowerConfig, runMcpHandles?: readonly McpHandle[]) => Promise<ExecutionContext<never, LlmExecutionCaps>>;
23
+ export declare const buildExecutionContext: (context: ExecutionContextDeps, runId: string, node: WorkflowGraphNode, hooks?: BuildHarnessHooks, preloadedConfig?: LangflowerConfig, runMcpHandles?: readonly SystemMcpServerTools[]) => Promise<ExecutionContext<never, LlmExecutionCaps>>;
24
24
  /**
25
25
  * Context seeds whose `value` is an Observable (e.g. `throwError` → CtxError)
26
26
  * must be `connect`ed directly. Runner `applySeeds` wraps with `of(value)`,
@@ -2,12 +2,13 @@ import { parseLlmRolePreset, resolveEffectiveSkillId, resolveEffectiveToolPermis
2
2
  import { attachRunHostServices } from '@langflower/common-nodes/ai/run-host-services';
3
3
  import { contextSymbol, } from '@langflower/node-sdk';
4
4
  import { parseDefaultChatModel, } from '@langflower/shared/langflower.js';
5
- import { collectEnabledMcpIdsFromNodes, createSystemMcpHandles, filterMcpFailuresForNode, filterMcpHandlesByIds, parseEnabledMcpIds, } from '@langflower/tools/create-system-mcp-handles';
5
+ import { collectEnabledMcpIdsFromNodes, createSystemMcpHandles, filterMcpFailuresForNode, filterSystemMcpToolsByServerIds, parseEnabledMcpIds, } from '@langflower/tools/create-system-mcp-handles';
6
6
  import { createProjectHarness, } from '@langflower/tools/create-project-harness';
7
7
  import { createWebFetch } from '@langflower/tools/create-web-fetch';
8
8
  import { mergeProjectAndNodePermissions, } from '@langflower/tools/permission';
9
9
  import { isObservable, throwError } from 'rxjs';
10
10
  import { bindCreateChatCompletionStream } from './bind-llm-context.js';
11
+ import { bindCreateEmbedding } from './bind-embed-context.js';
11
12
  import { wrapBuiltinToolHandles } from './wrap-builtin-tool-handles.js';
12
13
  import { readAgentsMarkdown } from '../skills/read-agents-markdown.js';
13
14
  import { readSkillMarkdown } from '../skills/read-skill-markdown.js';
@@ -73,8 +74,9 @@ export const buildExecutionContext = async (context, runId, node, hooks, preload
73
74
  webFetch,
74
75
  };
75
76
  const enabledToolIds = toolPermissionsToEnabledIds(toolPermissions);
76
- const toolHandles = wrapBuiltinToolHandles(harness, enabledToolIds, permission);
77
- const mcpHandles = filterMcpHandlesByIds(runMcpHandles ?? [], parseEnabledMcpIds(node.params.enabledMcpIds));
77
+ const builtinHandles = wrapBuiltinToolHandles(harness, enabledToolIds, permission);
78
+ const mcpTools = filterSystemMcpToolsByServerIds(runMcpHandles ?? [], parseEnabledMcpIds(node.params.enabledMcpIds)).flatMap((entry) => entry.tools);
79
+ const toolHandles = [...builtinHandles, ...mcpTools];
78
80
  const base = {
79
81
  projectDir: context.projectDir,
80
82
  runId,
@@ -85,16 +87,18 @@ export const buildExecutionContext = async (context, runId, node, hooks, preload
85
87
  params: node.params,
86
88
  })?.uiSchema ?? []),
87
89
  ...(toolHandles.length > 0 ? { toolHandles } : {}),
88
- ...(mcpHandles.length > 0 ? { mcpHandles } : {}),
89
90
  };
90
91
  const defaultChat = parseDefaultChatModel(config.model);
92
+ const defaultEmbedding = parseDefaultChatModel(config.embedding);
91
93
  return attachRunHostServices(base, {
92
94
  ...(node.type !== 'common-fake-llm'
93
95
  ? {
94
96
  createChatCompletionStream: bindCreateChatCompletionStream(context.langflowerConfigService),
95
97
  }
96
98
  : {}),
99
+ createEmbedding: bindCreateEmbedding(context.langflowerConfigService),
97
100
  ...(defaultChat !== null ? { defaultChat } : {}),
101
+ ...(defaultEmbedding !== null ? { defaultEmbedding } : {}),
98
102
  ...(skillMarkdown.length > 0 ? { skillMarkdown } : {}),
99
103
  ...(agentsMarkdown.length > 0 ? { agentsMarkdown } : {}),
100
104
  ...(toolHarness.authorize !== undefined
@@ -26,7 +26,10 @@ export const emitBootstrap = async (client, context, session, checkpoints, draft
26
26
  if (langflowerConfig.dividerPositions !== undefined) {
27
27
  session.dividerPositions = langflowerConfig.dividerPositions;
28
28
  }
29
- // Thin bootstrap — version + config + dividers + selected node only
29
+ if (langflowerConfig.paletteVisible !== undefined) {
30
+ session.paletteVisible = langflowerConfig.paletteVisible;
31
+ }
32
+ // Thin bootstrap — version + config + dividers + palette chrome + selected node only
30
33
  const bootstrap = await buildSessionBootstrap(session, context.langflowerConfigService, context.resolveDefinition, context.projectDir);
31
34
  clientEmit(client, 'session.state.snapshot', bootstrap);
32
35
  // Domain snapshots
@@ -1,8 +1,9 @@
1
1
  import type { ToolHandle } from '@langflower/node-sdk';
2
2
  import type { LangflowerSession } from '../session/langflower-session.js';
3
3
  /**
4
- * Activate current editor `tools` outputs (including post-swap instances)
5
- * so a later inbound peek in {@link getLiveWiredTools} sees live handles.
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.
6
7
  */
7
8
  export declare const refreshLiveWiredToolPacks: (session: LangflowerSession) => void;
8
9
  /**
@@ -40,14 +40,17 @@ const peekPortValue = (port) => {
40
40
  return peeked;
41
41
  };
42
42
  /**
43
- * Activate current editor `tools` outputs (including post-swap instances)
44
- * so a later inbound peek in {@link getLiveWiredTools} sees live handles.
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.
45
46
  */
46
47
  export const refreshLiveWiredToolPacks = (session) => {
47
48
  for (const node of session.runtime.editor.getNodes()) {
48
- const port = resolveToolsOutput(node.outputs, 'tools');
49
- if (port !== undefined) {
50
- peekPortValue(port);
49
+ for (const portId of ['tools', 'subagent-registration']) {
50
+ const port = resolveToolsOutput(node.outputs, portId);
51
+ if (port !== undefined) {
52
+ peekPortValue(port);
53
+ }
51
54
  }
52
55
  }
53
56
  };
@@ -154,12 +154,13 @@ export const createSettingsDraftController = (bridge, context, session) => {
154
154
  const commitSave = async (scope, fallback) => {
155
155
  await ensureSeeded(scope);
156
156
  const state = getState(scope);
157
- // Prefer an explicit Save payload (provider/model/serverLogs) so a
158
- // trailing draft.patch cannot race past commit. Otherwise persist the
159
- // session draft (`{ scope }` only).
157
+ // Prefer an explicit Save payload (provider/model/embedding/serverLogs)
158
+ // so a trailing draft.patch cannot race past commit. Otherwise persist
159
+ // the session draft (`{ scope }` only).
160
160
  const payload = fallback !== undefined &&
161
161
  (fallback.provider !== undefined ||
162
162
  fallback.model !== undefined ||
163
+ fallback.embedding !== undefined ||
163
164
  'serverLogs' in fallback)
164
165
  ? fallback
165
166
  : state !== undefined
@@ -172,6 +173,9 @@ export const createSettingsDraftController = (bridge, context, session) => {
172
173
  const layers = await context.langflowerConfigService.writeSettings({
173
174
  scope: payload.scope,
174
175
  ...(payload.model !== undefined ? { model: payload.model } : {}),
176
+ ...(payload.embedding !== undefined
177
+ ? { embedding: payload.embedding }
178
+ : {}),
175
179
  ...(payload.provider !== undefined
176
180
  ? { provider: payload.provider }
177
181
  : {}),
@@ -9,6 +9,8 @@ const isSettingsDraft = (value) => {
9
9
  const draft = value;
10
10
  return (typeof draft['defaultProviderId'] === 'string' &&
11
11
  typeof draft['defaultModelId'] === 'string' &&
12
+ typeof draft['defaultEmbeddingProviderId'] === 'string' &&
13
+ typeof draft['defaultEmbeddingModelId'] === 'string' &&
12
14
  Array.isArray(draft['providers']) &&
13
15
  (draft['serverLogs'] === 'off' ||
14
16
  draft['serverLogs'] === 'default' ||
@@ -182,6 +182,20 @@ export const wireEditorHandlers = (bridge, context, session, draftController) =>
182
182
  bridgeEmit(bridge, 'editor.dividers.snapshot', clamped);
183
183
  void context.langflowerConfigService.setDividerPositions(clamped);
184
184
  }));
185
+ subscription.add(bridge['editor.paletteVisible.requested'].subscribe((raw) => {
186
+ if (!isInboundEvent(raw)) {
187
+ return;
188
+ }
189
+ if (findClientById(bridge, raw.clientId) === undefined) {
190
+ return;
191
+ }
192
+ if (typeof raw.payload !== 'boolean') {
193
+ return;
194
+ }
195
+ session.paletteVisible = raw.payload;
196
+ bridgeEmit(bridge, 'editor.paletteVisible.snapshot', raw.payload);
197
+ void context.langflowerConfigService.setPaletteVisible(raw.payload);
198
+ }));
185
199
  subscription.add(bridge['editor.settings.requested'].subscribe((raw) => {
186
200
  if (!isInboundEvent(raw)) {
187
201
  return;
@@ -3,6 +3,7 @@ import { buildWorkflowFingerprint, } from '@langflower/shared/langflower.js';
3
3
  import { Subscription } from 'rxjs';
4
4
  import { listResumableCheckpoints } from '../checkpoint/list-resumable-checkpoints.js';
5
5
  import { resolveCheckpointBoundary } from '../checkpoint/resolve-checkpoint-boundary.js';
6
+ import { resetSessionExecutionFeed } from '../session/reset-session-execution-feed.js';
6
7
  import { buildContextSeeds, applyObservableContextSeeds, } from './build-execution-context.js';
7
8
  import { getLiveWiredTools } from './get-live-wired-tools.js';
8
9
  import { createLangflowerToolsRpc } from './langflower-tools-rpc.js';
@@ -293,8 +294,7 @@ export const wireRunnerHandlers = (bridge, context, session, checkpoints) => {
293
294
  if (session.runnerStatus === 'running') {
294
295
  return;
295
296
  }
296
- session.runtime.runner.clearEventLog();
297
- session.runId = undefined;
297
+ resetSessionExecutionFeed(session);
298
298
  // Re-broadcast the (now empty) feed to every tab.
299
299
  bridgeEmit(bridge, 'executionFeed.snapshot', session.buildExecutionFeed());
300
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 → optional catalog sync.
14
- * Sibling steps — handlers do not call these in nested order themselves.
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. Clear selection (and notify tabs if it was set)
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
- // 2. Authoritative current-workflow slice (session-shared — fan out)
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
- // 3. Resumable checkpoints for the active workflow (explicit boundaries)
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
- // 4. Catalog sync
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' },
@@ -62,11 +62,11 @@ export class RunCheckpointSession {
62
62
  event[0] !== 'out') {
63
63
  return false;
64
64
  }
65
- const [, nodeIdRaw, portId, state, value] = event;
66
- if (state !== 'value' || typeof portId !== 'string') {
65
+ const [, nodeIdRaw, portId, response] = event;
66
+ if (!('value' in response) || typeof portId !== 'string') {
67
67
  return false;
68
68
  }
69
- const jsonValue = toCheckpointJsonValue(value);
69
+ const jsonValue = toCheckpointJsonValue(response.value);
70
70
  if (jsonValue === undefined) {
71
71
  this.unsupportedValue = `${String(nodeIdRaw)}.${portId}`;
72
72
  return false;
@@ -6,6 +6,7 @@ export type LangflowerConfigLayers = {
6
6
  export type LangflowerConfigSettingsWrite = {
7
7
  readonly scope: LangflowerConfigScope;
8
8
  readonly model?: string;
9
+ readonly embedding?: string;
9
10
  readonly provider?: Readonly<Record<string, LangflowerProviderConfig>>;
10
11
  readonly providerApiKeys?: Readonly<Record<string, string>>;
11
12
  /** `null` clears the scope key (Settings Default). */
@@ -32,4 +33,5 @@ export declare class LangflowerConfigService {
32
33
  writeSettings(input: LangflowerConfigSettingsWrite): Promise<LangflowerConfigLayers>;
33
34
  setCurrentWorkflowId(workflowId: string | undefined): Promise<LangflowerConfig>;
34
35
  setDividerPositions(positions: DividerPositions): Promise<LangflowerConfig>;
36
+ setPaletteVisible(visible: boolean): Promise<LangflowerConfig>;
35
37
  }
@@ -147,6 +147,9 @@ function parseLangflowerConfig(raw) {
147
147
  ? { currentWorkflowId: raw.currentWorkflowId }
148
148
  : {}),
149
149
  ...(typeof raw.model === 'string' ? { model: raw.model } : {}),
150
+ ...(typeof raw.embedding === 'string'
151
+ ? { embedding: raw.embedding }
152
+ : {}),
150
153
  ...(typeof raw.serverLogs === 'boolean'
151
154
  ? { serverLogs: raw.serverLogs }
152
155
  : {}),
@@ -156,6 +159,9 @@ function parseLangflowerConfig(raw) {
156
159
  ...(harness !== undefined ? { harness } : {}),
157
160
  ...(mcp !== undefined ? { mcp } : {}),
158
161
  ...parseDividerPositions(raw.dividerPositions),
162
+ ...(typeof raw.paletteVisible === 'boolean'
163
+ ? { paletteVisible: raw.paletteVisible }
164
+ : {}),
159
165
  };
160
166
  }
161
167
  function parseDividerPositions(raw) {
@@ -205,6 +211,14 @@ function mergeLangflowerConfig(existing, patch) {
205
211
  merged.model = patch.model;
206
212
  }
207
213
  }
214
+ if (patch.embedding !== undefined) {
215
+ if (patch.embedding.trim().length === 0) {
216
+ delete merged.embedding;
217
+ }
218
+ else {
219
+ merged.embedding = patch.embedding;
220
+ }
221
+ }
208
222
  if ('serverLogs' in patch) {
209
223
  if (patch.serverLogs === undefined) {
210
224
  delete merged.serverLogs;
@@ -219,6 +233,9 @@ function mergeLangflowerConfig(existing, patch) {
219
233
  if (patch.dividerPositions !== undefined) {
220
234
  merged.dividerPositions = patch.dividerPositions;
221
235
  }
236
+ if (patch.paletteVisible !== undefined) {
237
+ merged.paletteVisible = patch.paletteVisible;
238
+ }
222
239
  return merged;
223
240
  }
224
241
  function serializeLangflowerConfig(merged) {
@@ -302,6 +319,9 @@ export class LangflowerConfigService {
302
319
  ? { currentWorkflowId: config.currentWorkflowId }
303
320
  : {}),
304
321
  ...(config.model !== undefined ? { model: config.model } : {}),
322
+ ...(config.embedding !== undefined
323
+ ? { embedding: config.embedding }
324
+ : {}),
305
325
  ...(config.provider !== undefined
306
326
  ? { provider: config.provider }
307
327
  : {}),
@@ -330,6 +350,9 @@ export class LangflowerConfigService {
330
350
  ]));
331
351
  const patch = {
332
352
  ...(input.model !== undefined ? { model: input.model } : {}),
353
+ ...(input.embedding !== undefined
354
+ ? { embedding: input.embedding }
355
+ : {}),
333
356
  ...(provider !== undefined ? { provider } : {}),
334
357
  ...('serverLogs' in input
335
358
  ? {
@@ -357,4 +380,11 @@ export class LangflowerConfigService {
357
380
  await this.writeRawAt(this.projectConfigPath(), merged);
358
381
  return parseLangflowerConfig(merged);
359
382
  }
383
+ async setPaletteVisible(visible) {
384
+ const merged = mergeLangflowerConfig(await this.readRawAt(this.projectConfigPath()), {
385
+ paletteVisible: visible,
386
+ });
387
+ await this.writeRawAt(this.projectConfigPath(), merged);
388
+ return parseLangflowerConfig(merged);
389
+ }
360
390
  }
@@ -16,6 +16,7 @@ export async function buildSessionBootstrap(session, langflowerConfigService, re
16
16
  version: LangflowerSession.snapshotVersion,
17
17
  langflowerConfig,
18
18
  dividerPositions: session.dividerPositions,
19
+ paletteVisible: session.paletteVisible,
19
20
  selectedNode: buildSelectedNodePayload(session, resolveDefinition).node,
20
21
  settings: session.settings,
21
22
  };
@@ -14,6 +14,8 @@ export declare class LangflowerSession {
14
14
  runnerStatus: RuntimeRunnerStatus;
15
15
  runId: RunId | undefined;
16
16
  dividerPositions: DividerPositions;
17
+ /** Left node palette shown. Hydrated from project jsonc; default visible. */
18
+ paletteVisible: boolean;
17
19
  /** In-memory canvas selection, shared across tabs. `null` = nothing selected. */
18
20
  selectedNodeId: string | null;
19
21
  /** Settings aside chrome — session memory only (not persisted to disk). */
@@ -32,5 +34,5 @@ export declare class LangflowerSession {
32
34
  markPristine(): void;
33
35
  buildExecutionFeed(): ExecutionFeedSnapshotPayload | null;
34
36
  static readonly sessionReadyVersion = 1;
35
- static readonly snapshotVersion = 6;
37
+ static readonly snapshotVersion = 7;
36
38
  }
@@ -4,7 +4,7 @@ import { Subscription } from 'rxjs';
4
4
  import { PendingPermissionAsks } from '../harness/pending-permission-asks.js';
5
5
  import { emptySettingsDraftStore, } from './settings-draft-session.js';
6
6
  const SESSION_READY_VERSION = 1;
7
- const SNAPSHOT_VERSION = 6;
7
+ const SNAPSHOT_VERSION = 7;
8
8
  export class LangflowerSession {
9
9
  runtime = new RuntimeFacade({ log: true });
10
10
  /** Feed permission.ask pause/resume for the internal tool loop. */
@@ -20,6 +20,8 @@ export class LangflowerSession {
20
20
  rightWidth: 360,
21
21
  composerHeight: 168,
22
22
  };
23
+ /** Left node palette shown. Hydrated from project jsonc; default visible. */
24
+ paletteVisible = true;
23
25
  /** In-memory canvas selection, shared across tabs. `null` = nothing selected. */
24
26
  selectedNodeId = null;
25
27
  /** Settings aside chrome — session memory only (not persisted to disk). */
@@ -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
+ };
@@ -149,6 +149,12 @@ const materializeRuntimeNode = (projectDir, node, resolveDefinition) => {
149
149
  if (input === undefined) {
150
150
  continue;
151
151
  }
152
+ // HITL ports stay inactive until `pushIntoInput` (composer Start /
153
+ // reply). Connecting a persisted Chat Input message here would
154
+ // double-emit when cold-start does startNode + pushIntoInput.
155
+ if (config.hitl !== undefined) {
156
+ continue;
157
+ }
152
158
  if (Object.hasOwn(node.inputs, config.portId)) {
153
159
  input.connect(of(node.inputs[config.portId]));
154
160
  continue;
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Persisted `node.inputs` hold visible UI overrides only (ADR-028).
3
- * Wire-only / hidden / preview ports and values equal to the current
4
- * definition `defaultValue` must not be written to disk.
3
+ * Wire-only / preview ports and values equal to the current definition
4
+ * `defaultValue` must not be written to disk. Hidden ports with an
5
+ * editable `inline` still persist (Chat Input `message`).
5
6
  */
6
7
  const valuesEqual = (left, right) => JSON.stringify(left) === JSON.stringify(right);
7
8
  const isPreviewInline = (inline) => {
@@ -18,10 +19,8 @@ const isPreviewInline = (inline) => {
18
19
  }
19
20
  return false;
20
21
  };
21
- /** Visible editable field on the canvas / inspector (not wire-only, not preview). */
22
- const hasVisibleUiInputField = (config) => config.hidden !== true &&
23
- config.inline !== undefined &&
24
- !isPreviewInline(config.inline);
22
+ /** Editable inline field (canvas / inspector), including hidden+inline. */
23
+ const hasVisibleUiInputField = (config) => config.inline !== undefined && !isPreviewInline(config.inline);
25
24
  /**
26
25
  * Keep only persistable overrides: visible UI field and value !== current
27
26
  * definition defaultValue.
@@ -36,6 +35,9 @@ export const prunePersistedInputs = (inputs, definition) => {
36
35
  if (!hasVisibleUiInputField(config)) {
37
36
  continue;
38
37
  }
38
+ if (typeof value === 'string' && value.trim() === '') {
39
+ continue;
40
+ }
39
41
  if (config.defaultValue !== undefined &&
40
42
  valuesEqual(value, config.defaultValue)) {
41
43
  continue;
@@ -1,7 +1,8 @@
1
1
  # Custom Nodes
2
2
 
3
- Author packs under `.langflower/nodes/<pack>/`. Default seed pack:
4
- **`my-nodes/`**.
3
+ Author packs under `.langflower/nodes/<pack>/`. Default seed packs:
4
+ **`my-nodes/`** (git-diff / review-gate) and **`hello-embed/`** (markdown
5
+ → local sqlite embeddings; copy as a starting point).
5
6
 
6
7
  Import **`defineNode`** (default), `defineToolRegistrations` (LLM tool packs),
7
8
  or `defineReactiveNode` from `@langflower/node-sdk` — not from a root
@@ -10,8 +11,19 @@ or `defineReactiveNode` from `@langflower/node-sdk` — not from a root
10
11
  Each `*.ts` file may `export default` a definition or an array. No required
11
12
  `index.ts`. Run `npm install` inside the pack when you add author dependencies;
12
13
  Langflower does **not** auto-install on start, bootstrap, or palette reload.
14
+ Startup **does** compile packs under `.langflower/nodes/`.
13
15
 
14
- See [`nodes/my-nodes/README.md`](nodes/my-nodes/README.md) for the full
16
+ If pack files `import` each other with a **`.ts` suffix**, set
17
+ `"allowImportingTsExtensions": true` next to `"noEmit": true` in the pack
18
+ `tsconfig.json` (hello-embed seed). Without it the pack does not compile.
19
+ `my-nodes` uses extensionless imports and does not need the flag.
20
+
21
+ - `hello-embed/` — sample embedding KB (`ingest` / `search` /
22
+ `search-handle`). See [`nodes/hello-embed/README.md`](nodes/hello-embed/README.md).
23
+ Workflows: `kb-ingest`, `kb-manual-search`, `kb-tool`, `kb-rag`.
24
+ Settings default embedding model required.
25
+
26
+ See [`nodes/my-nodes/README.md`](nodes/my-nodes/README.md) for the author
15
27
  contract.
16
28
 
17
29
  ## Seed demo