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
@@ -0,0 +1,39 @@
1
+ import type { OpenAiProviderCredentials } from '../ai/features/openai/create-chat-completion-stream.js';
2
+ export type CreateEmbeddingArgs = {
3
+ readonly providerId: string;
4
+ readonly model: string;
5
+ readonly texts: readonly string[];
6
+ readonly signal?: AbortSignal;
7
+ };
8
+ export type CreateEmbeddingResult = {
9
+ readonly dim: number;
10
+ readonly vectors: readonly Float32Array[];
11
+ };
12
+ export type CreateEmbedding = (args: CreateEmbeddingArgs) => Promise<CreateEmbeddingResult>;
13
+ export type EmbeddingsCreateBody = {
14
+ readonly model: string;
15
+ readonly input: readonly string[];
16
+ readonly encoding_format?: 'float' | 'base64';
17
+ };
18
+ export type EmbeddingsCreateOptions = {
19
+ readonly signal?: AbortSignal;
20
+ };
21
+ export type EmbeddingsClient = {
22
+ readonly embeddings: {
23
+ readonly create: (body: EmbeddingsCreateBody, options?: EmbeddingsCreateOptions) => Promise<{
24
+ readonly data: readonly {
25
+ readonly embedding: unknown;
26
+ readonly index?: number;
27
+ }[];
28
+ }>;
29
+ };
30
+ };
31
+ export type CreateEmbeddingDeps = {
32
+ readonly resolveProvider: (providerId: string) => Promise<OpenAiProviderCredentials>;
33
+ readonly createClient?: (credentials: OpenAiProviderCredentials) => EmbeddingsClient;
34
+ };
35
+ /**
36
+ * Unbound embeddings HTTP factory (`POST /v1/embeddings`).
37
+ * Forwards {@link CreateEmbeddingArgs.signal} so runner Stop can cancel.
38
+ */
39
+ export declare const createEmbedding: (deps: CreateEmbeddingDeps) => CreateEmbedding;
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Unbound OpenAI-compatible embeddings factory.
3
+ * Caller supplies credential resolve (server injects secrets).
4
+ * Does not rewrite texts for EmbedHandle `role` — packs/catalog do that.
5
+ *
6
+ * Always pass `encoding_format: 'float'`. openai-node otherwise defaults to
7
+ * `base64` and runs `toFloat32Array` on the body; local servers that return
8
+ * JSON `number[]` become a zero typed array. Chat completions have no such
9
+ * field — this is embeddings-only.
10
+ */
11
+ import OpenAI from 'openai';
12
+ const SECRET_SUBSTRINGS = ['sk-', 'apiKey', 'api_key', 'authorization'];
13
+ const requireNonEmpty = (value, label) => {
14
+ const trimmed = value.trim();
15
+ if (trimmed.length === 0) {
16
+ throw new Error(`${label} is required for OpenAI-compatible embeddings`);
17
+ }
18
+ return trimmed;
19
+ };
20
+ const toSafeErrorMessage = (message) => {
21
+ const lower = message.toLowerCase();
22
+ for (const needle of SECRET_SUBSTRINGS) {
23
+ if (lower.includes(needle.toLowerCase())) {
24
+ return 'Failed to create embeddings for provider';
25
+ }
26
+ }
27
+ return message;
28
+ };
29
+ const abortError = () => {
30
+ const error = new Error('The operation was aborted');
31
+ error.name = 'AbortError';
32
+ return error;
33
+ };
34
+ const defaultCreateClient = (credentials) => new OpenAI({
35
+ apiKey: credentials.apiKey ?? 'local-no-key',
36
+ ...(credentials.baseURL !== undefined
37
+ ? { baseURL: credentials.baseURL }
38
+ : {}),
39
+ });
40
+ const first8 = (value) => {
41
+ if (Array.isArray(value) || ArrayBuffer.isView(value)) {
42
+ const list = value;
43
+ const out = [];
44
+ const n = Math.min(8, list.length);
45
+ for (let i = 0; i < n; i += 1) {
46
+ out.push(list[i]);
47
+ }
48
+ return out;
49
+ }
50
+ return [];
51
+ };
52
+ const embeddingSnapshot = (embedding) => {
53
+ const embeddingLen = Array.isArray(embedding) || ArrayBuffer.isView(embedding)
54
+ ? embedding.length
55
+ : undefined;
56
+ return JSON.stringify({
57
+ embeddingIsArray: Array.isArray(embedding),
58
+ embeddingType: embedding === null ? 'null' : typeof embedding,
59
+ embeddingCtor: typeof embedding === 'object' && embedding !== null
60
+ ? embedding.constructor.name
61
+ : undefined,
62
+ embeddingLen,
63
+ embeddingFirst8: first8(embedding),
64
+ });
65
+ };
66
+ const missingNumericMessage = (embedding) => `Embedding item is missing a numeric embedding array (is a chat model loaded instead of an embedding model?). ${embeddingSnapshot(embedding)}`;
67
+ const asNumericVector = (embedding) => {
68
+ if (embedding instanceof Float32Array ||
69
+ embedding instanceof Float64Array) {
70
+ return embedding;
71
+ }
72
+ if (Array.isArray(embedding)) {
73
+ const numbers = embedding.filter((item) => typeof item === 'number' && Number.isFinite(item));
74
+ if (numbers.length !== embedding.length) {
75
+ throw new Error(missingNumericMessage(embedding));
76
+ }
77
+ return numbers;
78
+ }
79
+ throw new Error(missingNumericMessage(embedding));
80
+ };
81
+ const l2Norm = (values) => {
82
+ let sumSq = 0;
83
+ for (let i = 0; i < values.length; i += 1) {
84
+ const n = Number(values[i] ?? 0);
85
+ sumSq += n * n;
86
+ }
87
+ return Math.sqrt(sumSq);
88
+ };
89
+ const orderByIndex = (data, textCount) => {
90
+ const byIndex = new Map();
91
+ data.forEach((item, fallbackIndex) => {
92
+ const index = typeof item.index === 'number' ? item.index : fallbackIndex;
93
+ byIndex.set(index, item.embedding);
94
+ });
95
+ return Array.from({ length: textCount }, (_, index) => {
96
+ if (!byIndex.has(index)) {
97
+ throw new Error(`Embedding batch missing index ${String(index)}`);
98
+ }
99
+ return { embedding: byIndex.get(index) };
100
+ });
101
+ };
102
+ const toVectors = (data) => {
103
+ if (data.length === 0) {
104
+ throw new Error('Provider returned no embedding vectors');
105
+ }
106
+ const vectors = data.map((row) => Float32Array.from(asNumericVector(row.embedding)));
107
+ const dim = vectors[0]?.length ?? 0;
108
+ if (dim === 0) {
109
+ throw new Error('Provider returned an empty embedding vector');
110
+ }
111
+ for (const vector of vectors) {
112
+ if (vector.length !== dim) {
113
+ throw new Error(`Embedding batch dim mismatch: expected ${dim}, got ${vector.length}`);
114
+ }
115
+ if (l2Norm(vector) === 0) {
116
+ throw new Error('Provider returned a zero embedding vector (is a chat model loaded instead of an embedding model?).');
117
+ }
118
+ }
119
+ return { dim, vectors };
120
+ };
121
+ /**
122
+ * Unbound embeddings HTTP factory (`POST /v1/embeddings`).
123
+ * Forwards {@link CreateEmbeddingArgs.signal} so runner Stop can cancel.
124
+ */
125
+ export const createEmbedding = (deps) => {
126
+ const createClient = deps.createClient ?? defaultCreateClient;
127
+ return async (args) => {
128
+ if (args.signal?.aborted === true) {
129
+ throw abortError();
130
+ }
131
+ const providerId = requireNonEmpty(args.providerId, 'Provider');
132
+ const model = requireNonEmpty(args.model, 'Model');
133
+ if (args.texts.length === 0) {
134
+ throw new Error('Texts are required for OpenAI-compatible embeddings');
135
+ }
136
+ const credentials = await deps.resolveProvider(providerId);
137
+ const client = createClient(credentials);
138
+ try {
139
+ const response = await client.embeddings.create({
140
+ model,
141
+ input: [...args.texts],
142
+ encoding_format: 'float',
143
+ }, args.signal !== undefined ? { signal: args.signal } : {});
144
+ return toVectors(orderByIndex(response.data, args.texts.length));
145
+ }
146
+ catch (error) {
147
+ if (error instanceof Error && error.name === 'AbortError') {
148
+ throw error;
149
+ }
150
+ const raw = error instanceof Error ? error.message : String(error);
151
+ throw new Error(toSafeErrorMessage(raw));
152
+ }
153
+ };
154
+ };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * UC2: emits a live {@link EmbedHandle} on **embed** after a one-text probe
3
+ * fixes `dim`. Empty panel provider/model → Settings default.
4
+ */
5
+ export declare const embedProviderNode: {
6
+ readonly emitOncePerActivation: boolean;
7
+ readonly stopsRun: boolean;
8
+ readonly chatEntry: boolean;
9
+ readonly uiSchema: readonly [{
10
+ readonly field: "providerId";
11
+ readonly type: "select";
12
+ readonly label: "Provider";
13
+ readonly optionsSource: "langflower.providers";
14
+ }, {
15
+ readonly field: "model";
16
+ readonly type: "select";
17
+ readonly label: "Model";
18
+ readonly optionsSource: "langflower.models";
19
+ readonly dependsOn: "providerId";
20
+ }];
21
+ readonly bypassPorts: Record<string, import("@langflower/node-sdk").WireType>;
22
+ readonly inputsConfigs: readonly [import("@langflower/node-sdk").InputPortMeta<import("@langflower/node-sdk").ExecutionContext<readonly [{
23
+ readonly field: "providerId";
24
+ readonly type: "select";
25
+ readonly label: "Provider";
26
+ readonly optionsSource: "langflower.providers";
27
+ }, {
28
+ readonly field: "model";
29
+ readonly type: "select";
30
+ readonly label: "Model";
31
+ readonly optionsSource: "langflower.models";
32
+ readonly dependsOn: "providerId";
33
+ }], Record<string, never>>>, ...import("@langflower/node-sdk").InputPortMeta<unknown>[]];
34
+ readonly outputsConfigs: (import("@langflower/node-sdk").OutputParams & import("@langflower/node-sdk").PortMeta)[];
35
+ readonly getInstance: () => import("@langflower/node-sdk").ReactiveNodeInstance<readonly [{
36
+ readonly field: "providerId";
37
+ readonly type: "select";
38
+ readonly label: "Provider";
39
+ readonly optionsSource: "langflower.providers";
40
+ }, {
41
+ readonly field: "model";
42
+ readonly type: "select";
43
+ readonly label: "Model";
44
+ readonly optionsSource: "langflower.models";
45
+ readonly dependsOn: "providerId";
46
+ }], Record<string, never>>;
47
+ readonly paletteSecondary?: true;
48
+ readonly description?: string;
49
+ readonly type: string;
50
+ readonly displayName: string;
51
+ readonly category: string | undefined;
52
+ readonly icon: string | undefined;
53
+ };
@@ -0,0 +1,126 @@
1
+ import { defineReactiveNode, withLoading, EMBED_HANDLE_WIRE_TYPE, } from '@langflower/node-sdk';
2
+ import { distinctUntilChanged, map, switchMap } from 'rxjs';
3
+ import { getRunHostServices } from '../../ai/features/run-host-services.js';
4
+ import { fromEmbedding } from '../from-embedding.js';
5
+ import { resolveEmbeddingProviderModel } from '../resolve-embedding-provider-model.js';
6
+ const embedPanelUiSchema = [
7
+ {
8
+ field: 'providerId',
9
+ type: 'select',
10
+ label: 'Provider',
11
+ optionsSource: 'langflower.providers',
12
+ },
13
+ {
14
+ field: 'model',
15
+ type: 'select',
16
+ label: 'Model',
17
+ optionsSource: 'langflower.models',
18
+ dependsOn: 'providerId',
19
+ },
20
+ ];
21
+ const abortError = () => {
22
+ const error = new Error('The operation was aborted');
23
+ error.name = 'AbortError';
24
+ return error;
25
+ };
26
+ const prefixForRole = (text, role) => role === 'query' ? `query: ${text}` : `passage: ${text}`;
27
+ const linkAbortSignals = (runSignal, callSignal) => {
28
+ const controller = new AbortController();
29
+ const forward = (signal) => {
30
+ if (signal.aborted) {
31
+ controller.abort();
32
+ return;
33
+ }
34
+ signal.addEventListener('abort', () => controller.abort(), {
35
+ once: true,
36
+ });
37
+ };
38
+ forward(runSignal);
39
+ if (callSignal !== undefined) {
40
+ forward(callSignal);
41
+ }
42
+ return controller.signal;
43
+ };
44
+ const buildEmbedHandle = (options) => {
45
+ const { create, providerId, model, dim, runSignal } = options;
46
+ if (create === undefined) {
47
+ throw new Error('OpenAI-compatible embeddings are only available during server workflow runs');
48
+ }
49
+ return {
50
+ dim,
51
+ embedTexts: async (texts, options) => {
52
+ if (runSignal.aborted === true) {
53
+ throw abortError();
54
+ }
55
+ if (options?.signal?.aborted === true) {
56
+ throw abortError();
57
+ }
58
+ const role = options?.role ?? 'document';
59
+ const prefixed = texts.map((text) => prefixForRole(text, role));
60
+ const result = await create({
61
+ providerId,
62
+ model,
63
+ texts: prefixed,
64
+ signal: linkAbortSignals(runSignal, options?.signal),
65
+ });
66
+ if (result.dim !== dim) {
67
+ throw new Error(`Embedding dim mismatch: expected ${dim}, got ${result.dim}`);
68
+ }
69
+ return result.vectors;
70
+ },
71
+ };
72
+ };
73
+ /**
74
+ * UC2: emits a live {@link EmbedHandle} on **embed** after a one-text probe
75
+ * fixes `dim`. Empty panel provider/model → Settings default.
76
+ */
77
+ export const embedProviderNode = defineReactiveNode({
78
+ type: 'common-embed-provider',
79
+ displayName: 'Embed provider',
80
+ category: 'Embeddings',
81
+ description: `
82
+ Share an embedding model with custom nodes. Wire **embed** into a pack that needs batch vectors.
83
+
84
+ Uses the Settings default model, or pick one on this node.
85
+ `.trim(),
86
+ uiSchema: embedPanelUiSchema,
87
+ bind(ctx, { configureOutput, combineInputs }) {
88
+ const resolved$ = combineInputs([ctx], ([ec]) => ec).pipeValue(map((ec) => {
89
+ const host = getRunHostServices(ec);
90
+ const resolved = resolveEmbeddingProviderModel(ec.params, host);
91
+ return {
92
+ ec,
93
+ host,
94
+ key: `${resolved.providerId}/${resolved.model}`,
95
+ ...resolved,
96
+ };
97
+ }), distinctUntilChanged((left, right) => left.key === right.key));
98
+ const embed$ = resolved$.pipe(withLoading()).pipeValue(switchMap(({ host, providerId, model }) => fromEmbedding(async (runSignal) => {
99
+ const create = host?.createEmbedding;
100
+ if (create === undefined) {
101
+ throw new Error('OpenAI-compatible embeddings are only available during server workflow runs');
102
+ }
103
+ const probe = await create({
104
+ providerId,
105
+ model,
106
+ texts: [prefixForRole('x', 'document')],
107
+ signal: runSignal,
108
+ });
109
+ return buildEmbedHandle({
110
+ create,
111
+ providerId,
112
+ model,
113
+ dim: probe.dim,
114
+ runSignal,
115
+ });
116
+ })));
117
+ return {
118
+ inputs: [],
119
+ outputs: [
120
+ configureOutput('embed', embed$, {
121
+ wireType: EMBED_HANDLE_WIRE_TYPE,
122
+ }),
123
+ ],
124
+ };
125
+ },
126
+ });
@@ -0,0 +1,20 @@
1
+ /**
2
+ * UC1: L2-normalized dot (cosine) between two wired JSON vectors.
3
+ * Pure / offline — no HTTP, no provider panel.
4
+ */
5
+ export declare const embedSimilarityNode: {
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,81 @@
1
+ import { defineReactiveNode } from '@langflower/node-sdk';
2
+ const toNumberVector = (value, label) => {
3
+ if (!Array.isArray(value)) {
4
+ throw new Error(`${label} must be a JSON number array`);
5
+ }
6
+ return value.map((entry, index) => {
7
+ const n = Number(entry);
8
+ if (!Number.isFinite(n)) {
9
+ throw new Error(`${label}[${index}] must be a finite number`);
10
+ }
11
+ return n;
12
+ });
13
+ };
14
+ const l2Normalize = (values) => {
15
+ const out = new Float32Array(values.length);
16
+ let sumSq = 0;
17
+ for (let i = 0; i < values.length; i += 1) {
18
+ const n = values[i] ?? 0;
19
+ out[i] = n;
20
+ sumSq += n * n;
21
+ }
22
+ const norm = Math.sqrt(sumSq);
23
+ if (norm === 0) {
24
+ throw new Error('Cannot compute similarity for a zero-norm vector');
25
+ }
26
+ const scale = 1 / norm;
27
+ for (let i = 0; i < out.length; i += 1) {
28
+ out[i] = (out[i] ?? 0) * scale;
29
+ }
30
+ return out;
31
+ };
32
+ const cosineSimilarity = (left, right) => {
33
+ if (left.length !== right.length) {
34
+ throw new Error(`Vector dim mismatch: ${left.length} vs ${right.length}`);
35
+ }
36
+ const a = l2Normalize(left);
37
+ const b = l2Normalize(right);
38
+ let sum = 0;
39
+ for (let i = 0; i < a.length; i += 1) {
40
+ sum += (a[i] ?? 0) * (b[i] ?? 0);
41
+ }
42
+ return sum;
43
+ };
44
+ /**
45
+ * UC1: L2-normalized dot (cosine) between two wired JSON vectors.
46
+ * Pure / offline — no HTTP, no provider panel.
47
+ */
48
+ export const embedSimilarityNode = defineReactiveNode({
49
+ type: 'common-embed-similarity',
50
+ displayName: 'Embed similarity',
51
+ category: 'Embeddings',
52
+ description: `
53
+ Score how close two vectors are (cosine, typically 0–1).
54
+
55
+ Typical uses:
56
+ - Compare two Embed text outputs
57
+ - Rank which snippet matches a query
58
+ `.trim(),
59
+ uiSchema: [],
60
+ bind(_ctx, { makeInput, configureOutput, combineInputs }) {
61
+ const a = makeInput('a', {
62
+ name: 'a',
63
+ wireType: 'json',
64
+ required: true,
65
+ });
66
+ const b = makeInput('b', {
67
+ name: 'b',
68
+ wireType: 'json',
69
+ required: true,
70
+ });
71
+ const score$ = combineInputs([a, b], ([left, right]) => cosineSimilarity(toNumberVector(left, 'a'), toNumberVector(right, 'b')));
72
+ return {
73
+ inputs: [a, b],
74
+ outputs: [
75
+ configureOutput('score', score$, {
76
+ wireType: 'number',
77
+ }),
78
+ ],
79
+ };
80
+ },
81
+ });
@@ -0,0 +1,53 @@
1
+ /**
2
+ * UC1: embed a single string via the host embeddings factory (raw texts,
3
+ * no e5 role prefixes). Empty panel provider/model → Settings default.
4
+ */
5
+ export declare const embedTextNode: {
6
+ readonly emitOncePerActivation: boolean;
7
+ readonly stopsRun: boolean;
8
+ readonly chatEntry: boolean;
9
+ readonly uiSchema: readonly [{
10
+ readonly field: "providerId";
11
+ readonly type: "select";
12
+ readonly label: "Provider";
13
+ readonly optionsSource: "langflower.providers";
14
+ }, {
15
+ readonly field: "model";
16
+ readonly type: "select";
17
+ readonly label: "Model";
18
+ readonly optionsSource: "langflower.models";
19
+ readonly dependsOn: "providerId";
20
+ }];
21
+ readonly bypassPorts: Record<string, import("@langflower/node-sdk").WireType>;
22
+ readonly inputsConfigs: readonly [import("@langflower/node-sdk").InputPortMeta<import("@langflower/node-sdk").ExecutionContext<readonly [{
23
+ readonly field: "providerId";
24
+ readonly type: "select";
25
+ readonly label: "Provider";
26
+ readonly optionsSource: "langflower.providers";
27
+ }, {
28
+ readonly field: "model";
29
+ readonly type: "select";
30
+ readonly label: "Model";
31
+ readonly optionsSource: "langflower.models";
32
+ readonly dependsOn: "providerId";
33
+ }], Record<string, never>>>, ...import("@langflower/node-sdk").InputPortMeta<unknown>[]];
34
+ readonly outputsConfigs: (import("@langflower/node-sdk").OutputParams & import("@langflower/node-sdk").PortMeta)[];
35
+ readonly getInstance: () => import("@langflower/node-sdk").ReactiveNodeInstance<readonly [{
36
+ readonly field: "providerId";
37
+ readonly type: "select";
38
+ readonly label: "Provider";
39
+ readonly optionsSource: "langflower.providers";
40
+ }, {
41
+ readonly field: "model";
42
+ readonly type: "select";
43
+ readonly label: "Model";
44
+ readonly optionsSource: "langflower.models";
45
+ readonly dependsOn: "providerId";
46
+ }], Record<string, never>>;
47
+ readonly paletteSecondary?: true;
48
+ readonly description?: string;
49
+ readonly type: string;
50
+ readonly displayName: string;
51
+ readonly category: string | undefined;
52
+ readonly icon: string | undefined;
53
+ };
@@ -0,0 +1,91 @@
1
+ import { defineReactiveNode, withLoading } from '@langflower/node-sdk';
2
+ import { map, switchMap } from 'rxjs';
3
+ import { getRunHostServices } from '../../ai/features/run-host-services.js';
4
+ import { fromEmbedding } from '../from-embedding.js';
5
+ import { resolveEmbeddingProviderModel } from '../resolve-embedding-provider-model.js';
6
+ const PREVIEW_FLOATS = 8;
7
+ const embedPanelUiSchema = [
8
+ {
9
+ field: 'providerId',
10
+ type: 'select',
11
+ label: 'Provider',
12
+ optionsSource: 'langflower.providers',
13
+ },
14
+ {
15
+ field: 'model',
16
+ type: 'select',
17
+ label: 'Model',
18
+ optionsSource: 'langflower.models',
19
+ dependsOn: 'providerId',
20
+ },
21
+ ];
22
+ const formatEmbedPreview = (dim, vector) => {
23
+ const shown = vector.slice(0, PREVIEW_FLOATS).map((n) => {
24
+ const rounded = Math.round(n * 100) / 100;
25
+ return String(rounded);
26
+ });
27
+ const suffix = vector.length > PREVIEW_FLOATS ? ', …' : '';
28
+ return `dim=${dim} [${shown.join(', ')}${suffix}]`;
29
+ };
30
+ /**
31
+ * UC1: embed a single string via the host embeddings factory (raw texts,
32
+ * no e5 role prefixes). Empty panel provider/model → Settings default.
33
+ */
34
+ export const embedTextNode = defineReactiveNode({
35
+ type: 'common-embed-text',
36
+ displayName: 'Embed text',
37
+ category: 'Embeddings',
38
+ description: `
39
+ Turn wired text into an embedding vector. Uses the Settings default model, or pick one on the node.
40
+
41
+ Typical uses:
42
+ - String → Embed text → Preview
43
+ - Feed **vector** into Embed similarity
44
+ `.trim(),
45
+ uiSchema: embedPanelUiSchema,
46
+ bind(ctx, { makeInput, configureOutput, combineInputs }) {
47
+ const text = makeInput('text', {
48
+ name: 'text',
49
+ wireType: 'string',
50
+ inline: 'text',
51
+ required: true,
52
+ });
53
+ const session$ = combineInputs([text, ctx], ([rawText, ec]) => ({
54
+ rawText: String(rawText ?? ''),
55
+ ec,
56
+ }))
57
+ .pipe(withLoading())
58
+ .pipeValue(switchMap(({ rawText, ec }) => fromEmbedding(async (signal) => {
59
+ const host = getRunHostServices(ec);
60
+ const create = host?.createEmbedding;
61
+ if (create === undefined) {
62
+ throw new Error('OpenAI-compatible embeddings are only available during server workflow runs');
63
+ }
64
+ const { providerId, model } = resolveEmbeddingProviderModel(ec.params, host);
65
+ const result = await create({
66
+ providerId,
67
+ model,
68
+ texts: [rawText],
69
+ signal,
70
+ });
71
+ const first = result.vectors[0];
72
+ if (first === undefined) {
73
+ throw new Error('Provider returned no embedding vectors');
74
+ }
75
+ const vector = Array.from(first);
76
+ return {
77
+ vector,
78
+ dim: result.dim,
79
+ preview: formatEmbedPreview(result.dim, vector),
80
+ };
81
+ })));
82
+ return {
83
+ inputs: [text],
84
+ outputs: [
85
+ configureOutput('vector', session$.pipeValue(map((session) => session.vector)), { wireType: 'json' }),
86
+ configureOutput('dim', session$.pipeValue(map((session) => session.dim)), { wireType: 'number' }),
87
+ configureOutput('preview', session$.pipeValue(map((session) => session.preview)), { wireType: 'string' }),
88
+ ],
89
+ };
90
+ },
91
+ });
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Run an embeddings Promise on a teardown-owned AbortSignal.
3
+ * Stays open after the first value so unsubscribe (runner Stop) can still
4
+ * abort in-flight work — unlike `from(promise)`, which completes and would
5
+ * abort immediately after a successful probe.
6
+ */
7
+ import { Observable } from 'rxjs';
8
+ export declare const fromEmbedding: <T>(work: (signal: AbortSignal) => Promise<T>) => Observable<T>;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Run an embeddings Promise on a teardown-owned AbortSignal.
3
+ * Stays open after the first value so unsubscribe (runner Stop) can still
4
+ * abort in-flight work — unlike `from(promise)`, which completes and would
5
+ * abort immediately after a successful probe.
6
+ */
7
+ import { defer, Observable } from 'rxjs';
8
+ export const fromEmbedding = (work) => defer(() => {
9
+ const cancel = new AbortController();
10
+ return new Observable((subscriber) => {
11
+ void work(cancel.signal).then((value) => {
12
+ if (!subscriber.closed) {
13
+ subscriber.next(value);
14
+ }
15
+ }, (error) => {
16
+ if (!subscriber.closed) {
17
+ subscriber.error(error);
18
+ }
19
+ });
20
+ return () => {
21
+ cancel.abort();
22
+ };
23
+ });
24
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Resolve embedding provider/model from node params with optional host
3
+ * default (`LangflowerConfig.embedding` parsed into
4
+ * {@link RunHostServices.defaultEmbedding}).
5
+ */
6
+ import type { RunHostServices } from '../ai/features/run-host-services.js';
7
+ export type ResolvedEmbeddingProviderModel = {
8
+ readonly providerId: string;
9
+ readonly model: string;
10
+ };
11
+ export declare const resolveEmbeddingProviderModel: (params: Readonly<Record<string, unknown>>, host: RunHostServices | undefined) => ResolvedEmbeddingProviderModel;
@@ -0,0 +1,8 @@
1
+ export const resolveEmbeddingProviderModel = (params, host) => {
2
+ const fromParamsProvider = String(params['providerId'] ?? '').trim();
3
+ const fromParamsModel = String(params['model'] ?? '').trim();
4
+ return {
5
+ providerId: fromParamsProvider || host?.defaultEmbedding?.providerId || '',
6
+ model: fromParamsModel || host?.defaultEmbedding?.model || '',
7
+ };
8
+ };