langflower 0.0.10 → 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 (159) 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 +1 -1
  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-session/llm-session-shell.d.ts +2 -2
  15. package/vendor/common-nodes/dist/ai/features/llm-session/llm-session-shell.js +39 -7
  16. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.d.ts +11 -0
  17. package/vendor/common-nodes/dist/ai/features/llm-session/run-session-machine.js +2 -2
  18. package/vendor/common-nodes/dist/ai/features/run-host-services.d.ts +10 -0
  19. package/vendor/common-nodes/dist/ai/nodes/critique/node.js +5 -1
  20. package/vendor/common-nodes/dist/ai/nodes/fake-llm/node.js +7 -1
  21. package/vendor/common-nodes/dist/ai/nodes/openai-llm/node.js +5 -1
  22. package/vendor/common-nodes/dist/ai/nodes/review/node.js +7 -1
  23. package/vendor/common-nodes/dist/ai/nodes/sub-agent/node.js +62 -22
  24. package/vendor/common-nodes/dist/catalog.js +10 -0
  25. package/vendor/common-nodes/dist/crawl/crawl/node.js +11 -3
  26. package/vendor/common-nodes/dist/crawl/crawl-tools/node.js +5 -1
  27. package/vendor/common-nodes/dist/crawl/extract-links/node.js +7 -1
  28. package/vendor/common-nodes/dist/crawl/fetch-url/node.js +13 -4
  29. package/vendor/common-nodes/dist/crawl/save-page/node.js +11 -3
  30. package/vendor/common-nodes/dist/embeddings/create-embedding.d.ts +39 -0
  31. package/vendor/common-nodes/dist/embeddings/create-embedding.js +154 -0
  32. package/vendor/common-nodes/dist/embeddings/embed-provider/node.d.ts +53 -0
  33. package/vendor/common-nodes/dist/embeddings/embed-provider/node.js +126 -0
  34. package/vendor/common-nodes/dist/embeddings/embed-similarity/node.d.ts +20 -0
  35. package/vendor/common-nodes/dist/embeddings/embed-similarity/node.js +81 -0
  36. package/vendor/common-nodes/dist/embeddings/embed-text/node.d.ts +53 -0
  37. package/vendor/common-nodes/dist/embeddings/embed-text/node.js +91 -0
  38. package/vendor/common-nodes/dist/embeddings/from-embedding.d.ts +8 -0
  39. package/vendor/common-nodes/dist/embeddings/from-embedding.js +24 -0
  40. package/vendor/common-nodes/dist/embeddings/resolve-embedding-provider-model.d.ts +11 -0
  41. package/vendor/common-nodes/dist/embeddings/resolve-embedding-provider-model.js +8 -0
  42. package/vendor/common-nodes/dist/flow/checkpoint/node.js +7 -3
  43. package/vendor/common-nodes/dist/flow/delay/node.d.ts +2 -6
  44. package/vendor/common-nodes/dist/flow/delay/node.js +13 -9
  45. package/vendor/common-nodes/dist/flow/loop/node.js +7 -1
  46. package/vendor/common-nodes/dist/flow/merge/node.js +7 -1
  47. package/vendor/common-nodes/dist/flow/repeat/node.js +5 -1
  48. package/vendor/common-nodes/dist/flow/router/node.js +7 -1
  49. package/vendor/common-nodes/dist/hitl/chat-input/node.d.ts +2 -2
  50. package/vendor/common-nodes/dist/hitl/chat-input/node.js +8 -4
  51. package/vendor/common-nodes/dist/hitl/review-gate/node.js +11 -5
  52. package/vendor/common-nodes/dist/langflower-tools/node.js +5 -1
  53. package/vendor/common-nodes/dist/logic/assert/node.js +7 -1
  54. package/vendor/common-nodes/dist/logic/compare/node.js +7 -1
  55. package/vendor/common-nodes/dist/logic/gate/node.js +7 -1
  56. package/vendor/common-nodes/dist/logic/if/node.js +7 -1
  57. package/vendor/common-nodes/dist/logic/switch/node.js +7 -1
  58. package/vendor/common-nodes/dist/mcp/mcp-http/node.js +55 -53
  59. package/vendor/common-nodes/dist/mcp/mcp-stdio/node.js +52 -50
  60. package/vendor/common-nodes/dist/memory/memory-tools/node.js +5 -1
  61. package/vendor/common-nodes/dist/output/finish/node.js +13 -1
  62. package/vendor/common-nodes/dist/output/preview/node.js +9 -2
  63. package/vendor/common-nodes/dist/primitives/boolean/node.js +7 -1
  64. package/vendor/common-nodes/dist/primitives/number/node.js +7 -1
  65. package/vendor/common-nodes/dist/primitives/string/node.js +7 -1
  66. package/vendor/common-nodes/dist/primitives/string-multiline/node.d.ts +17 -0
  67. package/vendor/common-nodes/dist/primitives/string-multiline/node.js +31 -0
  68. package/vendor/common-nodes/dist/text/append-file/node.js +11 -3
  69. package/vendor/common-nodes/dist/text/concat/node.js +5 -1
  70. package/vendor/common-nodes/dist/text/read-file/node.js +9 -3
  71. package/vendor/common-nodes/dist/text/split-paced/node.d.ts +21 -0
  72. package/vendor/common-nodes/dist/text/split-paced/node.js +93 -0
  73. package/vendor/common-nodes/dist/text/write-file/node.js +11 -3
  74. package/vendor/common-nodes/dist/tools/tool-collection/node.js +5 -2
  75. package/vendor/common-nodes/package.json +4 -0
  76. package/vendor/node-sdk/dist/node-factory/define-embed/embed-handle.d.ts +25 -0
  77. package/vendor/node-sdk/dist/node-factory/define-embed/embed-handle.js +25 -0
  78. package/vendor/node-sdk/dist/node-factory/define-mcp/mcp-handle.d.ts +1 -0
  79. package/vendor/node-sdk/dist/node-factory/define-mcp/mcp-handle.js +1 -0
  80. package/vendor/node-sdk/dist/node-factory/define-node/define-node.d.ts +2 -0
  81. package/vendor/node-sdk/dist/node-factory/define-node/define-node.js +4 -1
  82. package/vendor/node-sdk/dist/node-factory/define-reactive-node/define-reactive-node.d.ts +3 -1
  83. package/vendor/node-sdk/dist/node-factory/define-reactive-node/define-reactive-node.js +2 -1
  84. package/vendor/node-sdk/dist/node-factory/define-reactive-node/io-helpers.d.ts +15 -0
  85. package/vendor/node-sdk/dist/node-factory/define-reactive-node/io-helpers.js +17 -1
  86. package/vendor/node-sdk/dist/node-factory/define-reactive-node/port-meta.d.ts +17 -4
  87. package/vendor/node-sdk/dist/node-factory/define-reactive-node/test/samples/delay-node.js +4 -2
  88. package/vendor/node-sdk/dist/node-factory/define-reactive-node/types.d.ts +4 -3
  89. package/vendor/node-sdk/dist/testing/create-node-harness.d.ts +30 -0
  90. package/vendor/node-sdk/dist/testing/create-node-harness.js +68 -0
  91. package/vendor/node-sdk/package.json +4 -4
  92. package/vendor/runtime/dist/types.d.ts +1 -1
  93. package/vendor/server/dist/bootstrap/project-bootstrap.service.d.ts +1 -1
  94. package/vendor/server/dist/bootstrap/seed-skeleton.d.ts +2 -2
  95. package/vendor/server/dist/bootstrap/seed-skeleton.js +17 -2
  96. package/vendor/server/dist/bridge/bind-embed-context.d.ts +7 -0
  97. package/vendor/server/dist/bridge/bind-embed-context.js +16 -0
  98. package/vendor/server/dist/bridge/build-execution-context.d.ts +2 -2
  99. package/vendor/server/dist/bridge/build-execution-context.js +6 -2
  100. package/vendor/server/dist/bridge/emit-bootstrap.js +4 -1
  101. package/vendor/server/dist/bridge/settings-draft-controller.js +7 -3
  102. package/vendor/server/dist/bridge/wire-config-handlers.js +2 -0
  103. package/vendor/server/dist/bridge/wire-editor-handlers.js +14 -0
  104. package/vendor/server/dist/config/langflower-config.service.d.ts +2 -0
  105. package/vendor/server/dist/config/langflower-config.service.js +30 -0
  106. package/vendor/server/dist/session/build-session-bootstrap.js +1 -0
  107. package/vendor/server/dist/session/langflower-session.d.ts +3 -1
  108. package/vendor/server/dist/session/langflower-session.js +3 -1
  109. package/vendor/server/dist/workflow/apply-editor-mutation.js +6 -0
  110. package/vendor/server/dist/workflow/workflow-persisted-inputs.js +8 -6
  111. package/vendor/server/skeleton/instructions.md +15 -3
  112. package/vendor/server/skeleton/nodes/hello-embed/README.md +185 -0
  113. package/vendor/server/skeleton/nodes/hello-embed/hello-embed.nodes.test.ts +181 -0
  114. package/vendor/server/skeleton/nodes/hello-embed/ingest.ts +126 -0
  115. package/vendor/server/skeleton/nodes/hello-embed/lib/chunk-markdown.test.ts +40 -0
  116. package/vendor/server/skeleton/nodes/hello-embed/lib/chunk-markdown.ts +123 -0
  117. package/vendor/server/skeleton/nodes/hello-embed/lib/ingest-search.test.ts +180 -0
  118. package/vendor/server/skeleton/nodes/hello-embed/lib/ingest.ts +128 -0
  119. package/vendor/server/skeleton/nodes/hello-embed/lib/paths.test.ts +20 -0
  120. package/vendor/server/skeleton/nodes/hello-embed/lib/paths.ts +70 -0
  121. package/vendor/server/skeleton/nodes/hello-embed/lib/schema.ts +21 -0
  122. package/vendor/server/skeleton/nodes/hello-embed/lib/search.ts +254 -0
  123. package/vendor/server/skeleton/nodes/hello-embed/lib/text-embedder.ts +14 -0
  124. package/vendor/server/skeleton/nodes/hello-embed/lib/vectors.ts +126 -0
  125. package/vendor/server/skeleton/nodes/hello-embed/lib/walk-markdown.test.ts +62 -0
  126. package/vendor/server/skeleton/nodes/hello-embed/lib/walk-markdown.ts +67 -0
  127. package/vendor/server/skeleton/nodes/hello-embed/package.json +11 -0
  128. package/vendor/server/skeleton/nodes/hello-embed/search-handle.ts +119 -0
  129. package/vendor/server/skeleton/nodes/hello-embed/search.ts +98 -0
  130. package/vendor/server/skeleton/nodes/hello-embed/tsconfig.json +14 -0
  131. package/vendor/server/skeleton/nodes/my-nodes/README.md +13 -3
  132. package/vendor/server/skeleton/schemas/langflower-config.schema.json +4 -0
  133. package/vendor/server/skeleton/skills/langflower-helper/SKILL.md +99 -26
  134. package/vendor/server/skeleton/skills/langflower-helper/architecture.md +11 -6
  135. package/vendor/server/skeleton/skills/langflower-helper/layout.md +24 -18
  136. package/vendor/server/skeleton/skills/langflower-node-writer/SKILL.md +8 -1
  137. package/vendor/server/skeleton/workflows/kb-ingest.json +88 -0
  138. package/vendor/server/skeleton/workflows/kb-manual-search.json +105 -0
  139. package/vendor/server/skeleton/workflows/kb-rag.json +192 -0
  140. package/vendor/server/skeleton/workflows/kb-tool.json +111 -0
  141. package/vendor/shared/dist/langflower-bus-config.d.ts +22 -6
  142. package/vendor/shared/dist/langflower-bus-config.js +23 -7
  143. package/vendor/shared/dist/langflower-config/merge-langflower-config-layers.test.js +8 -0
  144. package/vendor/shared/dist/langflower-config/settings-draft.d.ts +5 -0
  145. package/vendor/shared/dist/langflower-config/settings-draft.js +15 -7
  146. package/vendor/shared/dist/langflower.d.ts +1 -1
  147. package/vendor/shared/dist/langflower.js +1 -1
  148. package/vendor/shared/dist/types/langflower-bootstrap.d.ts +6 -0
  149. package/vendor/shared/dist/types/langflower-config.d.ts +17 -0
  150. package/vendor/shared/dist/types/langflower-palette.d.ts +2 -1
  151. package/vendor/tools/dist/harness-types.d.ts +1 -1
  152. package/vendor/tools/dist/mcp/build-mcp-handle.d.ts +3 -21
  153. package/vendor/tools/dist/mcp/build-mcp-handle.js +2 -11
  154. package/vendor/tools/dist/mcp/create-system-mcp-handles.d.ts +9 -6
  155. package/vendor/tools/dist/mcp/create-system-mcp-handles.js +21 -17
  156. package/vendor/tools/package.json +1 -0
  157. package/ui-dist/chunk-MDGXX73Z.js +0 -4
  158. package/ui-dist/main-Z7CPFXFA.js +0 -313
  159. package/ui-dist/styles-2TMDAUD7.css +0 -1
@@ -0,0 +1 @@
1
+ @charset "UTF-8";@layer properties;:root{--ngd-colors-gray-100: #ffffff;--ngd-colors-gray-200: #f7f7f7;--ngd-colors-gray-300: #edeff3;--ngd-colors-gray-400: #d5d8e0;--ngd-colors-gray-450: #c2c0c0;--ngd-colors-gray-500: #6f7480;--ngd-colors-gray-600: #4d5059;--ngd-colors-gray-650: #383a40;--ngd-colors-gray-700: #27282b;--ngd-colors-gray-800: #151516;--ngd-colors-gray-900-5: rgba(7, 7, 8, .05);--ngd-colors-gray-900-20: rgba(7, 7, 8, .2);--ngd-colors-gray-900-50: rgba(7, 7, 8, .5);--ngd-colors-acc1-400: #a977ff;--ngd-colors-acc1-500: #9140ff;--ngd-colors-acc1-500-40: rgba(145, 64, 255, .4);--ngd-colors-acc1-500-50: rgba(145, 64, 255, .5);--ngd-colors-acc1-600: #891aff;--ngd-colors-acc4-500: #1096e7}:root{--ngd-shadow: var(--ngd-colors-gray-900-20);--ngd-txt-primary-default: var(--ngd-colors-gray-800);--ngd-nav-button-primary-default: var(--ngd-colors-gray-600);--ngd-nav-button-primary-pressed: var(--ngd-colors-acc1-600);--ngd-nav-button-primary-hover: var(--ngd-colors-gray-900-5);--ngd-nav-button-primary-disabled: var(--ngd-colors-gray-450);--ngd-diagram-background-color: var(--ngd-colors-gray-200);--ngd-ui-bg-primary-default: var(--ngd-colors-gray-100);--ngd-ui-bg-tertiary-default: var(--ngd-colors-gray-200);--ngd-ui-stroke-primary-focus: var(--ngd-colors-gray-500);--ngd-pt-stroke-primary-default: var(--ngd-colors-gray-600);--ngd-node-bg-primary-default: var(--ngd-colors-gray-100);--ngd-node-stroke-primary-default: var(--ngd-colors-gray-400);--ngd-node-stroke-primary-hover: var(--ngd-colors-acc1-500);--ngd-node-port-fill-default: var(--ngd-colors-gray-100);--ngd-node-port-fill-active: var(--ngd-colors-acc1-500);--ngd-node-port-stroke-default: var(--ngd-colors-gray-500);--ngd-node-port-stroke-active: var(--ngd-colors-gray-100);--ngd-transform-box: var(--ngd-colors-acc4-500);--ngd-focus-ring-node-active: var(--ngd-colors-acc1-500-40);--ngd-button-gray-bg-default: var(--ngd-colors-gray-500);--ngd-button-gray-bg-hover: var(--ngd-colors-gray-600);--ngd-button-gray-bg-active: var(--ngd-colors-gray-650);--ngd-default-edge-label-bg-primary-default: var(--ngd-colors-gray-100);--ngd-background-line-minor-color: var(--ngd-colors-gray-450);--ngd-background-line-major-color: var(--ngd-colors-gray-500);--ngd-ui-border-color: var(--ngd-colors-gray-300);--ngd-minimap-bg-primary-default: var(--ngd-colors-gray-100);--ngd-minimap-stroke-primary-default: var(--ngd-colors-gray-400)}html[data-theme=dark]{--ngd-shadow: var(--ngd-colors-gray-900-50);--ngd-txt-primary-default: var(--ngd-colors-gray-100);--ngd-nav-button-primary-default: var(--ngd-colors-gray-400);--ngd-nav-button-primary-pressed: var(--ngd-colors-acc1-500);--ngd-nav-button-primary-hover: var(--ngd-colors-gray-900-5);--ngd-nav-button-primary-disabled: var(--ngd-colors-gray-600);--ngd-diagram-background-color: var(--ngd-colors-gray-800);--ngd-ui-bg-primary-default: var(--ngd-colors-gray-700);--ngd-ui-bg-tertiary-default: var(--ngd-colors-gray-800);--ngd-ui-stroke-primary-focus: var(--ngd-colors-gray-500);--ngd-pt-stroke-primary-default: var(--ngd-colors-gray-200);--ngd-node-bg-primary-default: var(--ngd-colors-gray-700);--ngd-node-stroke-primary-default: var(--ngd-colors-gray-600);--ngd-node-stroke-primary-hover: var(--ngd-colors-acc1-400);--ngd-node-port-fill-default: var(--ngd-colors-gray-100);--ngd-node-port-fill-active: var(--ngd-colors-acc1-500);--ngd-node-port-stroke-default: var(--ngd-colors-gray-500);--ngd-node-port-stroke-active: var(--ngd-colors-gray-100);--ngd-transform-box: var(--ngd-colors-acc4-500);--ngd-focus-ring-node-active: var(--ngd-colors-acc1-500-40);--ngd-button-gray-bg-default: var(--ngd-colors-gray-650);--ngd-button-gray-bg-hover: var(--ngd-colors-gray-600);--ngd-button-gray-bg-active: var(--ngd-colors-gray-500);--ngd-default-edge-label-bg-primary-default: var(--ngd-colors-gray-700);--ngd-background-line-minor-color: var(--ngd-colors-gray-700);--ngd-background-line-major-color: var(--ngd-colors-gray-600);--ngd-ui-border-color: var(--ngd-colors-gray-700);--ngd-minimap-bg-primary-default: var(--ngd-colors-gray-700);--ngd-minimap-stroke-primary-default: var(--ngd-colors-gray-600)}:root{--ngd-node-background-color: var(--ngd-node-bg-primary-default);--ngd-node-border-color: var(--ngd-node-stroke-primary-default);--ngd-node-border-color-hover: var(--ngd-node-stroke-primary-hover);--ngd-node-border-radius: .75rem;--ngd-node-border-size: .0625rem;--ngd-group-border-color: var(--ngd-ui-stroke-primary-focus);--ngd-group-border-color-hover: var(--ngd-pt-stroke-primary-default);--ngd-group-border-color-highlight: var(--ngd-colors-acc1-500);--ngd-group-box-shadow-color-highlight: var(--ngd-colors-acc1-500-50);--ngd-group-background-color-highlight: var(--ngd-colors-gray-400);--ngd-group-border-radius: .75rem;--ngd-group-highlight-size: 1.25rem;--ngd-selected-node-box-shadow: 0 0 0 .25rem var(--ngd-focus-ring-node-active);--ngd-rotate-handle-size: 2rem;--ngd-rotate-handle-distance: 2rem;--ngd-rotate-handle-background-color: var(--ngd-button-gray-bg-default);--ngd-rotate-handle-background-color-hover: var(--ngd-button-gray-bg-hover);--ngd-rotate-handle-background-color-active: var(--ngd-button-gray-bg-active);--ngd-rotate-handle-xy: calc(-.7071 * var(--ngd-rotate-handle-distance));--ngd-rotate-handle-top: var(--ngd-rotate-handle-xy);--ngd-rotate-handle-right: var(--ngd-rotate-handle-xy);--ngd-resize-line-border-width: .0625rem;--ngd-resize-line-border-style: solid;--ngd-resize-line-border-color: var(--ngd-transform-box);--ngd-resize-handle-size: .375rem;--ngd-resize-handle-background-color: var(--ngd-ui-bg-primary-default);--ngd-resize-handle-border-size: .0625rem;--ngd-resize-handle-border-style: solid;--ngd-resize-handle-border-color: var(--ngd-transform-box);--ngd-resize-handle-border-radius: 0;--ngd-port-size: .25rem;--ngd-port-background-color: var(--ngd-node-port-fill-default);--ngd-port-border-color: var(--ngd-node-port-stroke-default);--ngd-port-border-size: .125rem;--ngd-port-border-radius: 50%;--ngd-port-background-color-hover: var(--ngd-node-port-fill-active);--ngd-port-border-color-hover: var(--ngd-node-port-stroke-active);--ngd-port-border-size-hover: .25rem;--ngd-default-edge-stroke: var(--ngd-colors-gray-500);--ngd-default-edge-stroke-hover: var(--ngd-colors-gray-700);--ngd-default-edge-stroke-selected: var(--ngd-colors-acc1-500);--ngd-box-selection-border-color: #961ce7;--ngd-box-selection-border-size: 1px;--ngd-box-selection-background: rgba(43, 91, 213, .12);--ngd-default-edge-label-background-color: var(--ngd-default-edge-label-bg-primary-default);--ngd-default-edge-label-color: var(--ngd-txt-primary-default);--ngd-default-edge-label-border-color: var(--ngd-colors-gray-500);--ngd-background-dot-color: var(--ngd-colors-gray-500);--ngd-background-line-minor-width: .5;--ngd-background-line-major-width: 1;--ngd-background-line-minor-opacity: .5;--ngd-background-line-major-opacity: .6;--ngd-minimap-background: var(--ngd-minimap-bg-primary-default);--ngd-minimap-border-color: var(--ngd-minimap-stroke-primary-default);--ngd-minimap-shadow-color: var(--ngd-shadow);--ngd-minimap-border-radius: 1rem;--ngd-minimap-padding: .5rem;--ngd-minimap-margin: 1rem;--ngd-minimap-node-color: var(--ngd-colors-gray-400);--ngd-minimap-node-opacity: .8;--ngd-minimap-diagram-bounds-opacity: .3;--ngd-minimap-diagram-bounds-color: var(--ngd-colors-gray-400);--ngd-minimap-viewport-stroke-color: var(--ngd-colors-gray-400);--ngd-minimap-viewport-stroke-width: 1;--ngd-nav-button-color: var(--ngd-nav-button-primary-default);--ngd-nav-button-size: 1.25rem;--ngd-nav-button-border-radius: .5rem;--ngd-nav-button-padding: .6875rem;--ngd-nav-button-background-color-hover: var(--ngd-nav-button-primary-hover);--ngd-nav-button-color-active: var(--ngd-nav-button-primary-pressed);--ngd-nav-button-color-disabled: var(--ngd-nav-button-primary-disabled);--ngd-zoom-controls-font-size: .8125rem;--ngd-zoom-controls-font-weight: 500;--ngd-zoom-controls-color: var(--ngd-nav-button-primary-default)}.ng-diagram-port-hoverable .ng-diagram-port:hover,.ng-diagram-port-hoverable .ng-diagram-port.custom-content:hover .content-projection,.ng-diagram-port-hoverable-over-node:hover:not(:has(.ng-diagram-rotate-handle:hover)):not(:has([data-rotating])) .ng-diagram-port.custom-content .content-projection,.ng-diagram-port-hoverable-over-node:hover:not(:has(.ng-diagram-rotate-handle:hover)):not(:has([data-rotating])) .ng-diagram-port{background-color:var(--ngd-port-background-color-hover);border-color:var(--ngd-port-background-color-hover);outline:calc(1px + var(--ngd-port-border-size)) solid var(--ngd-port-background-color-hover);outline-offset:-1px;box-shadow:0 0 0 var(--ngd-port-border-size-hover) var(--ngd-port-border-color-hover)}.ng-diagram-node-wrapper:not(.ng-diagram-node-selected){transition:box-shadow .1s ease-in-out}.ng-diagram-node-wrapper.ng-diagram-group-highlight,.ng-diagram-node-wrapper.ng-diagram-group.ng-diagram-group-highlight{border-color:var(--ngd-group-border-color-highlight);box-shadow:0 0 var(--ngd-group-highlight-size) 0 var(--ngd-group-box-shadow-color-highlight) inset}.ng-diagram-node-wrapper.ng-diagram-node-selected{box-shadow:var(--ngd-selected-node-box-shadow)}ng-diagram *,ng-diagram *:before,ng-diagram *:after{box-sizing:border-box}@layer theme,base,components,utilities;@layer theme{:root,:host{--font-sans: Inter, ui-sans-serif, system-ui, sans-serif;--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;--color-red-300: oklch(80.8% .114 19.571);--color-red-700: oklch(50.5% .213 27.518);--color-amber-50: oklch(98.7% .022 95.277);--color-amber-100: oklch(96.2% .059 95.617);--color-amber-300: oklch(87.9% .169 91.605);--color-amber-400: oklch(82.8% .189 84.429);--color-amber-500: oklch(76.9% .188 70.08);--color-amber-600: oklch(66.6% .179 58.318);--color-amber-700: oklch(55.5% .163 48.998);--color-amber-800: oklch(47.3% .137 46.201);--color-amber-900: oklch(41.4% .112 45.904);--color-amber-950: oklch(27.9% .077 45.635);--color-emerald-50: oklch(97.9% .021 166.113);--color-emerald-100: oklch(95% .052 163.051);--color-emerald-300: oklch(84.5% .143 164.978);--color-emerald-400: oklch(76.5% .177 163.223);--color-emerald-500: oklch(69.6% .17 162.48);--color-emerald-600: oklch(59.6% .145 163.225);--color-emerald-700: oklch(50.8% .118 165.612);--color-emerald-950: oklch(26.2% .051 172.552);--color-sky-50: oklch(97.7% .013 236.62);--color-sky-100: oklch(95.1% .026 236.824);--color-sky-300: oklch(82.8% .111 230.318);--color-sky-400: oklch(74.6% .16 232.661);--color-sky-500: oklch(68.5% .169 237.323);--color-sky-700: oklch(50% .134 242.749);--color-sky-950: oklch(29.3% .066 243.157);--color-violet-400: oklch(70.2% .183 293.541);--color-rose-50: oklch(96.9% .015 12.422);--color-rose-100: oklch(94.1% .03 12.58);--color-rose-300: oklch(81% .117 11.638);--color-rose-400: oklch(71.2% .194 13.428);--color-rose-500: oklch(64.5% .246 16.439);--color-rose-600: oklch(58.6% .253 17.585);--color-rose-700: oklch(51.4% .222 16.935);--color-rose-800: oklch(45.5% .188 13.697);--color-rose-950: oklch(27.1% .105 12.094);--color-zinc-50: oklch(98.5% 0 0);--color-zinc-100: oklch(96.7% .001 286.375);--color-zinc-200: oklch(92% .004 286.32);--color-zinc-300: oklch(87.1% .006 286.286);--color-zinc-400: oklch(70.5% .015 286.067);--color-zinc-500: oklch(55.2% .016 285.938);--color-zinc-600: oklch(44.2% .017 285.786);--color-zinc-700: oklch(37% .013 285.805);--color-zinc-800: oklch(27.4% .006 286.033);--color-zinc-900: oklch(21% .006 285.885);--color-zinc-950: oklch(14.1% .005 285.823);--color-white: #fff;--spacing: .25rem;--container-md: 28rem;--text-xs: .75rem;--text-xs--line-height: calc(1 / .75);--text-sm: .875rem;--text-sm--line-height: calc(1.25 / .875);--text-base: 1rem;--text-base--line-height: 1.5 ;--text-lg: 1.125rem;--text-lg--line-height: calc(1.75 / 1.125);--font-weight-medium: 500;--font-weight-semibold: 600;--tracking-tight: -.025em;--tracking-normal: 0em;--tracking-wide: .025em;--radius-md: .375rem;--radius-lg: .5rem;--radius-xl: .75rem;--radius-2xl: 1rem;--default-transition-duration: .15s;--default-transition-timing-function: cubic-bezier(.4, 0, .2, 1);--default-font-family: var(--font-sans);--default-mono-font-family: var(--font-mono)}}@layer base{*,:after,:before,::backdrop,::file-selector-button{box-sizing:border-box;margin:0;padding:0;border:0 solid}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings, normal);font-variation-settings:var(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings, normal);font-variation-settings:var(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea,::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;border-radius:0;background-color:transparent;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px){::placeholder{color:currentcolor}@supports (color: color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]),::file-selector-button{appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:0}.inset-x-0{inset-inline:0}.top-0{top:0}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-full{top:100%}.right-0{right:0}.right-3{right:calc(var(--spacing) * 3)}.right-full{right:100%}.bottom-0{bottom:0}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-full{bottom:100%}.left-0{left:0}.left-1\/2{left:50%}.left-2{left:calc(var(--spacing) * 2)}.left-full{left:100%}.z-0{z-index:0}.z-20{z-index:20}.z-50{z-index:50}.z-\[1\]{z-index:1}.z-\[3\]{z-index:3}.container{width:100%}@media(width>=40rem){.container{max-width:40rem}}@media(width>=48rem){.container{max-width:48rem}}@media(width>=64rem){.container{max-width:64rem}}@media(width>=80rem){.container{max-width:80rem}}@media(width>=96rem){.container{max-width:96rem}}.mx-1{margin-inline:var(--spacing)}.my-1{margin-block:var(--spacing)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-auto{margin-right:auto}.mb-1{margin-bottom:var(--spacing)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.ml-1{margin-left:var(--spacing)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-1{height:var(--spacing)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-12{height:calc(var(--spacing) * 12)}.h-\[2lh\]{height:2lh}.h-full{height:100%}.h-screen{height:100vh}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-72{max-height:calc(var(--spacing) * 72)}.min-h-0{min-height:0}.min-h-12{min-height:calc(var(--spacing) * 12)}.min-h-\[calc\(var\(--lf-control-h\)\+1\.1rem\)\]{min-height:calc(var(--lf-control-h) + 1.1rem)}.w-1{width:var(--spacing)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-72{width:calc(var(--spacing) * 72)}.w-80{width:calc(var(--spacing) * 80)}.w-96{width:calc(var(--spacing) * 96)}.w-full{width:100%}.w-max{width:max-content}.max-w-48{max-width:calc(var(--spacing) * 48)}.max-w-\[92\%\]{max-width:92%}.max-w-\[min\(24rem\,calc\(100vw-2rem\)\)\]{max-width:min(24rem,calc(100vw - 2rem))}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.max-w-none{max-width:none}.min-w-0{min-width:0}.min-w-40{min-width:calc(var(--spacing) * 40)}.min-w-48{min-width:calc(var(--spacing) * 48)}.min-w-\[120px\]{min-width:120px}.flex-1{flex:1}.flex-shrink,.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-collapse{border-collapse:collapse}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-col-resize{cursor:col-resize}.cursor-grab{cursor:grab}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.resize{resize:both}.resize-none{resize:none}.list-none{list-style-type:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse: 0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}.self-center{align-self:center}.self-start{align-self:flex-start}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:calc(infinity * 1px)}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-tl-md{border-top-left-radius:var(--radius-md)}.rounded-tr-md{border-top-right-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-amber-300{border-color:var(--color-amber-300)}.border-amber-300\/80{border-color:color-mix(in srgb,oklch(87.9% .169 91.605) 80%,transparent)}@supports (color: color-mix(in lab,red,red)){.border-amber-300\/80{border-color:color-mix(in oklab,var(--color-amber-300) 80%,transparent)}}.border-amber-400{border-color:var(--color-amber-400)}.border-emerald-400{border-color:var(--color-emerald-400)}.border-rose-300{border-color:var(--color-rose-300)}.border-rose-400{border-color:var(--color-rose-400)}.border-sky-400{border-color:var(--color-sky-400)}.border-zinc-200{border-color:var(--color-zinc-200)}.border-zinc-300{border-color:var(--color-zinc-300)}.border-zinc-400{border-color:var(--color-zinc-400)}.border-zinc-900{border-color:var(--color-zinc-900)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-400{background-color:var(--color-amber-400)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-emerald-400{background-color:var(--color-emerald-400)}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-rose-50{background-color:var(--color-rose-50)}.bg-rose-400{background-color:var(--color-rose-400)}.bg-rose-500{background-color:var(--color-rose-500)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-transparent{background-color:transparent}.bg-white{background-color:var(--color-white)}.bg-zinc-50{background-color:var(--color-zinc-50)}.bg-zinc-50\/90{background-color:color-mix(in srgb,oklch(98.5% 0 0) 90%,transparent)}@supports (color: color-mix(in lab,red,red)){.bg-zinc-50\/90{background-color:color-mix(in oklab,var(--color-zinc-50) 90%,transparent)}}.bg-zinc-100{background-color:var(--color-zinc-100)}.bg-zinc-200{background-color:var(--color-zinc-200)}.bg-zinc-400{background-color:var(--color-zinc-400)}.bg-zinc-900{background-color:var(--color-zinc-900)}.bg-gradient-to-b{--tw-gradient-position: to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-t{--tw-gradient-position: to top in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-white{--tw-gradient-from: var(--color-white);--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-40\%{--tw-gradient-from-position: 40%}.from-45\%{--tw-gradient-from-position: 45%}.to-transparent{--tw-gradient-to: transparent;--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.pt-1{padding-top:var(--spacing)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-11{padding-top:calc(var(--spacing) * 11)}.pr-1{padding-right:var(--spacing)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pb-14{padding-bottom:calc(var(--spacing) * 14)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading, var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading, var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading, var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading, var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.leading-4{--tw-leading: calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-5{--tw-leading: calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-6{--tw-leading: calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.font-medium{--tw-font-weight: var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight: var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-normal{--tw-tracking: var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking: var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking: var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-600{color:var(--color-amber-600)}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-amber-900{color:var(--color-amber-900)}.text-amber-950{color:var(--color-amber-950)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-red-700{color:var(--color-red-700)}.text-rose-600{color:var(--color-rose-600)}.text-rose-700{color:var(--color-rose-700)}.text-rose-800{color:var(--color-rose-800)}.text-sky-700{color:var(--color-sky-700)}.text-white{color:var(--color-white)}.text-zinc-400{color:var(--color-zinc-400)}.text-zinc-500{color:var(--color-zinc-500)}.text-zinc-600{color:var(--color-zinc-600)}.text-zinc-700{color:var(--color-zinc-700)}.text-zinc-800{color:var(--color-zinc-800)}.text-zinc-900{color:var(--color-zinc-900)}.text-zinc-950{color:var(--color-zinc-950)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.opacity-50{opacity:50%}.opacity-60{opacity:60%}.opacity-70{opacity:70%}.shadow-lg{--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / .1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / .1));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-2{--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-violet-400{--tw-ring-color: var(--color-violet-400)}.ring-zinc-400\/20{--tw-ring-color: color-mix(in srgb, oklch(70.5% .015 286.067) 20%, transparent)}@supports (color: color-mix(in lab,red,red)){.ring-zinc-400\/20{--tw-ring-color: color-mix(in oklab, var(--color-zinc-400) 20%, transparent)}}.blur{--tw-blur: blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease, var(--default-transition-timing-function));transition-duration:var(--tw-duration, var(--default-transition-duration))}.outline-none{--tw-outline-style: none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.group-focus-within\:block:is(:where(.group):focus-within *){display:block}@media(hover:hover){.group-hover\:block:is(:where(.group):hover *){display:block}}.placeholder\:text-zinc-400::placeholder{color:var(--color-zinc-400)}@media(hover:hover){.hover\:border-zinc-400:hover{border-color:var(--color-zinc-400)}}@media(hover:hover){.hover\:bg-amber-100:hover{background-color:var(--color-amber-100)}}@media(hover:hover){.hover\:bg-emerald-100:hover{background-color:var(--color-emerald-100)}}@media(hover:hover){.hover\:bg-rose-50:hover{background-color:var(--color-rose-50)}}@media(hover:hover){.hover\:bg-rose-100:hover{background-color:var(--color-rose-100)}}@media(hover:hover){.hover\:bg-sky-100:hover{background-color:var(--color-sky-100)}}@media(hover:hover){.hover\:bg-zinc-50:hover{background-color:var(--color-zinc-50)}}@media(hover:hover){.hover\:bg-zinc-100:hover{background-color:var(--color-zinc-100)}}@media(hover:hover){.hover\:bg-zinc-400:hover{background-color:var(--color-zinc-400)}}@media(hover:hover){.hover\:bg-zinc-800:hover{background-color:var(--color-zinc-800)}}@media(hover:hover){.hover\:text-zinc-700:hover{color:var(--color-zinc-700)}}@media(hover:hover){.hover\:underline:hover{text-decoration-line:underline}}.focus\:border-zinc-400:focus{border-color:var(--color-zinc-400)}.focus\:ring-2:focus{--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:outline-none:focus{--tw-outline-style: none;outline-style:none}.active\:cursor-grabbing:active{cursor:grabbing}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:50%}.dark\:border-amber-500:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-amber-500)}.dark\:border-amber-700:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-amber-700)}.dark\:border-amber-700\/60:where([data-theme=dark],[data-theme=dark] *){border-color:color-mix(in srgb,oklch(55.5% .163 48.998) 60%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:border-amber-700\/60:where([data-theme=dark],[data-theme=dark] *){border-color:color-mix(in oklab,var(--color-amber-700) 60%,transparent)}}.dark\:border-amber-800:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-amber-800)}.dark\:border-emerald-500:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-emerald-500)}.dark\:border-rose-500:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-rose-500)}.dark\:border-rose-700:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-rose-700)}.dark\:border-rose-800:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-rose-800)}.dark\:border-sky-500:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-sky-500)}.dark\:border-zinc-100:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-zinc-100)}.dark\:border-zinc-500:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-zinc-500)}.dark\:border-zinc-600:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-zinc-600)}.dark\:border-zinc-700:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-zinc-700)}.dark\:border-zinc-800:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-zinc-800)}.dark\:bg-amber-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in srgb,oklch(27.9% .077 45.635) 40%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:bg-amber-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab,var(--color-amber-950) 40%,transparent)}}.dark\:bg-emerald-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in srgb,oklch(26.2% .051 172.552) 40%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:bg-emerald-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab,var(--color-emerald-950) 40%,transparent)}}.dark\:bg-rose-950\/30:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in srgb,oklch(27.1% .105 12.094) 30%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:bg-rose-950\/30:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab,var(--color-rose-950) 30%,transparent)}}.dark\:bg-rose-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in srgb,oklch(27.1% .105 12.094) 40%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:bg-rose-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab,var(--color-rose-950) 40%,transparent)}}.dark\:bg-sky-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in srgb,oklch(29.3% .066 243.157) 40%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:bg-sky-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab,var(--color-sky-950) 40%,transparent)}}.dark\:bg-zinc-100:where([data-theme=dark],[data-theme=dark] *){background-color:var(--color-zinc-100)}.dark\:bg-zinc-800:where([data-theme=dark],[data-theme=dark] *){background-color:var(--color-zinc-800)}.dark\:bg-zinc-900:where([data-theme=dark],[data-theme=dark] *){background-color:var(--color-zinc-900)}.dark\:bg-zinc-950:where([data-theme=dark],[data-theme=dark] *){background-color:var(--color-zinc-950)}.dark\:bg-zinc-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in srgb,oklch(14.1% .005 285.823) 40%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:bg-zinc-950\/40:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab,var(--color-zinc-950) 40%,transparent)}}.dark\:bg-zinc-950\/60:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in srgb,oklch(14.1% .005 285.823) 60%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:bg-zinc-950\/60:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab,var(--color-zinc-950) 60%,transparent)}}.dark\:bg-zinc-950\/90:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in srgb,oklch(14.1% .005 285.823) 90%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:bg-zinc-950\/90:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab,var(--color-zinc-950) 90%,transparent)}}.dark\:from-zinc-900:where([data-theme=dark],[data-theme=dark] *){--tw-gradient-from: var(--color-zinc-900);--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.dark\:text-amber-100:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-100)}.dark\:text-amber-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-300)}.dark\:text-amber-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-400)}.dark\:text-emerald-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-300)}.dark\:text-emerald-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-400)}.dark\:text-red-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-red-300)}.dark\:text-rose-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-300)}.dark\:text-rose-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-400)}.dark\:text-sky-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-sky-300)}.dark\:text-zinc-100:where([data-theme=dark],[data-theme=dark] *){color:var(--color-zinc-100)}.dark\:text-zinc-200:where([data-theme=dark],[data-theme=dark] *){color:var(--color-zinc-200)}.dark\:text-zinc-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-zinc-300)}.dark\:text-zinc-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-zinc-400)}.dark\:text-zinc-500:where([data-theme=dark],[data-theme=dark] *){color:var(--color-zinc-500)}.dark\:text-zinc-900:where([data-theme=dark],[data-theme=dark] *){color:var(--color-zinc-900)}.dark\:placeholder\:text-zinc-500:where([data-theme=dark],[data-theme=dark] *)::placeholder{color:var(--color-zinc-500)}@media(hover:hover){.dark\:hover\:border-zinc-500:where([data-theme=dark],[data-theme=dark] *):hover{border-color:var(--color-zinc-500)}}@media(hover:hover){.dark\:hover\:bg-amber-900\/50:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in srgb,oklch(41.4% .112 45.904) 50%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:hover\:bg-amber-900\/50:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in oklab,var(--color-amber-900) 50%,transparent)}}}@media(hover:hover){.dark\:hover\:bg-amber-950\/60:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in srgb,oklch(27.9% .077 45.635) 60%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:hover\:bg-amber-950\/60:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in oklab,var(--color-amber-950) 60%,transparent)}}}@media(hover:hover){.dark\:hover\:bg-emerald-950\/60:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in srgb,oklch(26.2% .051 172.552) 60%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:hover\:bg-emerald-950\/60:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in oklab,var(--color-emerald-950) 60%,transparent)}}}@media(hover:hover){.dark\:hover\:bg-rose-950\/30:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in srgb,oklch(27.1% .105 12.094) 30%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:hover\:bg-rose-950\/30:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in oklab,var(--color-rose-950) 30%,transparent)}}}@media(hover:hover){.dark\:hover\:bg-rose-950\/40:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in srgb,oklch(27.1% .105 12.094) 40%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:hover\:bg-rose-950\/40:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in oklab,var(--color-rose-950) 40%,transparent)}}}@media(hover:hover){.dark\:hover\:bg-rose-950\/60:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in srgb,oklch(27.1% .105 12.094) 60%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:hover\:bg-rose-950\/60:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in oklab,var(--color-rose-950) 60%,transparent)}}}@media(hover:hover){.dark\:hover\:bg-sky-950\/60:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in srgb,oklch(29.3% .066 243.157) 60%,transparent)}@supports (color: color-mix(in lab,red,red)){.dark\:hover\:bg-sky-950\/60:where([data-theme=dark],[data-theme=dark] *):hover{background-color:color-mix(in oklab,var(--color-sky-950) 60%,transparent)}}}@media(hover:hover){.dark\:hover\:bg-white:where([data-theme=dark],[data-theme=dark] *):hover{background-color:var(--color-white)}}@media(hover:hover){.dark\:hover\:bg-zinc-200:where([data-theme=dark],[data-theme=dark] *):hover{background-color:var(--color-zinc-200)}}@media(hover:hover){.dark\:hover\:bg-zinc-500:where([data-theme=dark],[data-theme=dark] *):hover{background-color:var(--color-zinc-500)}}@media(hover:hover){.dark\:hover\:bg-zinc-700:where([data-theme=dark],[data-theme=dark] *):hover{background-color:var(--color-zinc-700)}}@media(hover:hover){.dark\:hover\:bg-zinc-800:where([data-theme=dark],[data-theme=dark] *):hover{background-color:var(--color-zinc-800)}}@media(hover:hover){.dark\:hover\:text-zinc-200:where([data-theme=dark],[data-theme=dark] *):hover{color:var(--color-zinc-200)}}.dark\:focus\:border-zinc-500:where([data-theme=dark],[data-theme=dark] *):focus{border-color:var(--color-zinc-500)}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}}:root{--lf-control-h: 2rem;--lf-btn-pad: calc(var(--lf-control-h) / 2)}@layer components{.lf-composer-pill{display:inline-flex;align-items:center;justify-content:center;height:var(--lf-control-h);padding:0 var(--lf-btn-pad);border-radius:9999px;font-size:.75rem;line-height:1;font-weight:500;transition-property:color,background-color,border-color,opacity;transition-duration:.15s}.lf-composer-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--lf-control-h);height:var(--lf-control-h);padding:0;border-radius:9999px;transition-property:color,background-color,border-color,opacity;transition-duration:.15s}}html,body{height:100%;margin:0}body{background-color:var(--color-zinc-50);font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--tw-leading, var(--text-sm--line-height));color:var(--color-zinc-950);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body:where([data-theme=dark],[data-theme=dark] *){background-color:var(--color-zinc-950)}body:where([data-theme=dark],[data-theme=dark] *){color:var(--color-zinc-100)}button,textarea{font:inherit}@layer base{button:not(:disabled):not([aria-disabled=true]){cursor:pointer}button:disabled,button[aria-disabled=true]{cursor:not-allowed}}.lf-feed-row--hovered{border-radius:.5rem;background-color:#8b5cf61a}html[data-theme=dark] .lf-feed-row--hovered{background-color:#a78bfa1f}lf-edge:hover:not(.lf-edge--selected){--edge-stroke: rgb(74 108 182)}html[data-theme=dark] lf-edge:hover:not(.lf-edge--selected){--edge-stroke: rgb(120 160 220)}lf-edge.lf-edge--pulse ng-diagram-base-edge path{animation:lf-edge-pulse .3s ease-out}@keyframes lf-edge-pulse{0%{stroke:#10b981;stroke-width:3;filter:drop-shadow(0 0 6px rgba(16,185,129,.9))}to{stroke:var(--edge-stroke, var(--ngd-default-edge-stroke));stroke-width:2;filter:none}}.lf-port-anchor.lf-port-anchor--pulse{--ngd-port-border-color: rgb(16 185 129);--ngd-port-background-color: rgb(167 243 208);--ngd-port-size: .45rem;animation:lf-port-pulse .45s ease-in-out infinite}html[data-theme=dark] .lf-port-anchor.lf-port-anchor--pulse{--ngd-port-border-color: rgb(52 211 153);--ngd-port-background-color: rgb(6 78 59);animation-name:lf-port-pulse-dark}@keyframes lf-port-pulse{0%,to{box-shadow:0 0 #10b98100}50%{box-shadow:0 0 0 4px #10b981b3}}@keyframes lf-port-pulse-dark{0%,to{box-shadow:0 0 #34d39900}50%{box-shadow:0 0 0 4px #34d399b3}}lf-edge.lf-edge--pending ng-diagram-base-edge path{stroke:#ca8a04;stroke-width:3}lf-edge.lf-edge--error ng-diagram-base-edge path{stroke:#f43f5e;stroke-width:3}lf-edge.lf-edge--value ng-diagram-base-edge path{stroke:#10b981;stroke-width:3}html[data-theme=dark] lf-edge.lf-edge--value ng-diagram-base-edge path{stroke:#34d399}html[data-theme=dark] lf-edge.lf-edge--pending ng-diagram-base-edge path{stroke:#facc15}html[data-theme=dark] lf-edge.lf-edge--error ng-diagram-base-edge path{stroke:#fb7185}.lf-scroll{scrollbar-width:thin;scrollbar-color:rgb(212,212,216) transparent}.lf-scroll::-webkit-scrollbar{width:8px;height:8px}.lf-scroll::-webkit-scrollbar-button{display:none;width:0;height:0}.lf-scroll::-webkit-scrollbar-track{background:transparent}.lf-scroll::-webkit-scrollbar-thumb{background-color:#d4d4d8;border-radius:9999px;border:2px solid transparent;background-clip:content-box}.lf-scroll::-webkit-scrollbar-thumb:hover{background-color:#a1a1aa}.lf-scroll::-webkit-scrollbar-corner{background:transparent}html[data-theme=dark] .lf-scroll{scrollbar-color:rgb(63,63,70) transparent}html[data-theme=dark] .lf-scroll::-webkit-scrollbar-thumb{background-color:#3f3f46}html[data-theme=dark] .lf-scroll::-webkit-scrollbar-thumb:hover{background-color:#52525b}@property --tw-translate-x{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-y{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-translate-z{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-rotate-x{syntax: "*"; inherits: false;}@property --tw-rotate-y{syntax: "*"; inherits: false;}@property --tw-rotate-z{syntax: "*"; inherits: false;}@property --tw-skew-x{syntax: "*"; inherits: false;}@property --tw-skew-y{syntax: "*"; inherits: false;}@property --tw-space-y-reverse{syntax: "*"; inherits: false; initial-value: 0;}@property --tw-border-style{syntax: "*"; inherits: false; initial-value: solid;}@property --tw-gradient-position{syntax: "*"; inherits: false;}@property --tw-gradient-from{syntax: "<color>"; inherits: false; initial-value: #0000;}@property --tw-gradient-via{syntax: "<color>"; inherits: false; initial-value: #0000;}@property --tw-gradient-to{syntax: "<color>"; inherits: false; initial-value: #0000;}@property --tw-gradient-stops{syntax: "*"; inherits: false;}@property --tw-gradient-via-stops{syntax: "*"; inherits: false;}@property --tw-gradient-from-position{syntax: "<length-percentage>"; inherits: false; initial-value: 0%;}@property --tw-gradient-via-position{syntax: "<length-percentage>"; inherits: false; initial-value: 50%;}@property --tw-gradient-to-position{syntax: "<length-percentage>"; inherits: false; initial-value: 100%;}@property --tw-leading{syntax: "*"; inherits: false;}@property --tw-font-weight{syntax: "*"; inherits: false;}@property --tw-tracking{syntax: "*"; inherits: false;}@property --tw-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@property --tw-shadow-color{syntax: "*"; inherits: false;}@property --tw-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@property --tw-inset-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-shadow-color{syntax: "*"; inherits: false;}@property --tw-inset-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@property --tw-ring-color{syntax: "*"; inherits: false;}@property --tw-ring-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@property --tw-inset-ring-color{syntax: "*"; inherits: false;}@property --tw-inset-ring-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@property --tw-ring-inset{syntax: "*"; inherits: false;}@property --tw-ring-offset-width{syntax: "<length>"; inherits: false; initial-value: 0px;}@property --tw-ring-offset-color{syntax: "*"; inherits: false; initial-value: #fff;}@property --tw-ring-offset-shadow{syntax: "*"; inherits: false; initial-value: 0 0 #0000;}@property --tw-blur{syntax: "*"; inherits: false;}@property --tw-brightness{syntax: "*"; inherits: false;}@property --tw-contrast{syntax: "*"; inherits: false;}@property --tw-grayscale{syntax: "*"; inherits: false;}@property --tw-hue-rotate{syntax: "*"; inherits: false;}@property --tw-invert{syntax: "*"; inherits: false;}@property --tw-opacity{syntax: "*"; inherits: false;}@property --tw-saturate{syntax: "*"; inherits: false;}@property --tw-sepia{syntax: "*"; inherits: false;}@property --tw-drop-shadow{syntax: "*"; inherits: false;}@property --tw-drop-shadow-color{syntax: "*"; inherits: false;}@property --tw-drop-shadow-alpha{syntax: "<percentage>"; inherits: false; initial-value: 100%;}@property --tw-drop-shadow-size{syntax: "*"; inherits: false;}@layer properties{@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x: 0;--tw-translate-y: 0;--tw-translate-z: 0;--tw-rotate-x: initial;--tw-rotate-y: initial;--tw-rotate-z: initial;--tw-skew-x: initial;--tw-skew-y: initial;--tw-space-y-reverse: 0;--tw-border-style: solid;--tw-gradient-position: initial;--tw-gradient-from: #0000;--tw-gradient-via: #0000;--tw-gradient-to: #0000;--tw-gradient-stops: initial;--tw-gradient-via-stops: initial;--tw-gradient-from-position: 0%;--tw-gradient-via-position: 50%;--tw-gradient-to-position: 100%;--tw-leading: initial;--tw-font-weight: initial;--tw-tracking: initial;--tw-shadow: 0 0 #0000;--tw-shadow-color: initial;--tw-shadow-alpha: 100%;--tw-inset-shadow: 0 0 #0000;--tw-inset-shadow-color: initial;--tw-inset-shadow-alpha: 100%;--tw-ring-color: initial;--tw-ring-shadow: 0 0 #0000;--tw-inset-ring-color: initial;--tw-inset-ring-shadow: 0 0 #0000;--tw-ring-inset: initial;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-offset-shadow: 0 0 #0000;--tw-blur: initial;--tw-brightness: initial;--tw-contrast: initial;--tw-grayscale: initial;--tw-hue-rotate: initial;--tw-invert: initial;--tw-opacity: initial;--tw-saturate: initial;--tw-sepia: initial;--tw-drop-shadow: initial;--tw-drop-shadow-color: initial;--tw-drop-shadow-alpha: 100%;--tw-drop-shadow-size: initial}}}
@@ -1,10 +1,10 @@
1
- import type { ToolHandle, configureOutput, makeInput } from '@langflower/node-sdk';
1
+ import { type ToolHandle, type configureOutput, type makeInput } from '@langflower/node-sdk';
2
2
  import type { ToolHandlerContext } from '@langflower/tools/domain-tool-configs';
3
3
  import type { PermissionAskRequest } from '@langflower/tools/permission';
4
4
  import type { ChatCompletionMessage } from '../chat-completion-stream.js';
5
5
  import { type LlmInventoryInputs, type LlmRecoveryNotice, type SteerControlPayload } from '@langflower/node-sdk/llm';
6
6
  import type { PortMeta } from '@langflower/node-sdk';
7
- import type { combineStatefulObservables, StatefulObservable } from '@rx-evo/stateful-observable';
7
+ import { type combineStatefulObservables, type StatefulObservable } from '@rx-evo/stateful-observable';
8
8
  import { type Observable, type OperatorFunction } from 'rxjs';
9
9
  import { type LlmRolePreset } from '../llm-role-preset.js';
10
10
  import type { LlmCompactionConfig } from '../openai/normalize-compaction-params.js';
@@ -1,5 +1,6 @@
1
1
  import { toLlmRecoveryPortValue, } from '@langflower/node-sdk/llm';
2
- import { filter, map, pipe, shareReplay, switchMap, } from 'rxjs';
2
+ import { statefulObservable, } from '@rx-evo/stateful-observable';
3
+ import { concatMap, filter, map, pipe, shareReplay, startWith, switchMap, } from 'rxjs';
3
4
  import { buildEffectiveSystemPrompt } from '../prompt/build-effective-system-prompt.js';
4
5
  import { collectAgentToolHandles } from '../../../tools/collect-agent-tool-handles.js';
5
6
  import { parseLlmRolePreset, resolveEffectiveSkillId, } from '../llm-role-preset.js';
@@ -8,7 +9,7 @@ import { resolveChatProviderModel } from '../prompt/resolve-chat-provider-model.
8
9
  import { buildAgentToolCtx, getRunHostServices } from '../run-host-services.js';
9
10
  import { AGENT_MAX_ITERATIONS_CAP, DEFAULT_AGENT_MAX_ITERATIONS, normalizeMaxIterations as normalizeMaxIterationsParam, } from '../prompt/normalize-max-iterations.js';
10
11
  import { normalizeLlmRecoveryPolicy } from '../llm-loop/normalize-llm-recovery-policy.js';
11
- import { runLlmSessionMachine } from './run-session-machine.js';
12
+ import { isBlankTurn, runTurnFromState, } from './run-session-machine.js';
12
13
  const asPortList = (value) => {
13
14
  if (value === undefined || value === null) {
14
15
  return [];
@@ -118,12 +119,43 @@ const demuxLlmAgentPorts = (cycle$) => ({
118
119
  */
119
120
  export const createLlmSessionCycle$ = (context$, turn$, prepareSession, runTurn, options) => {
120
121
  const primeTurn0 = options?.primeTurn0 ?? true;
121
- return context$
122
- .pipeValue(switchMap((context) => {
122
+ const ticks$ = context$.pipeValue(switchMap((context) => {
123
123
  const prep = prepareSession(context);
124
- return runLlmSessionMachine(context, turn$, prep, runTurn, primeTurn0);
125
- }))
126
- .pipe(shareReplay({ bufferSize: 1, refCount: true }));
124
+ const turns$ = primeTurn0 ? turn$.pipe(startWith('')) : turn$;
125
+ return turns$.pipe(map((raw) => ({ context, prep, raw })));
126
+ }));
127
+ let state;
128
+ const isSkippableTick = (tick) => {
129
+ const prepChanged = state === undefined || state.preparation !== tick.prep;
130
+ if (prepChanged || !state?.turn0Done) {
131
+ return !primeTurn0 && isBlankTurn(tick.raw);
132
+ }
133
+ return isBlankTurn(tick.raw);
134
+ };
135
+ const workTicks$ = ticks$.pipeValue(filter((tick) => !isSkippableTick(tick)));
136
+ // pipeValue uses switchMap and would cancel an in-flight turn when the
137
+ // next tick arrives (startWith + a blank BehaviorSubject, or feedback
138
+ // during a stream). Queue turns with concatMap so pending comes from
139
+ // the loader, matching withLoading() + sequential I/O.
140
+ return statefulObservable({
141
+ input: workTicks$.value$,
142
+ mapOperator: concatMap,
143
+ loader: (tick) => {
144
+ const { context, prep, raw } = tick;
145
+ if (state === undefined || state.preparation !== prep) {
146
+ state = {
147
+ history: [...prep.history],
148
+ turn0Done: false,
149
+ feedbackTurns: 0,
150
+ preparation: prep,
151
+ };
152
+ }
153
+ return runTurnFromState(context, state, raw, primeTurn0, runTurn).pipe(map((next) => {
154
+ state = next;
155
+ return next;
156
+ }), filter((next) => next.emitted !== undefined), map((next) => next.emitted));
157
+ },
158
+ }).pipe(shareReplay({ bufferSize: 1, refCount: true }));
127
159
  };
128
160
  /**
129
161
  * Composer entry for OpenAI / Fake agent binds.
@@ -11,6 +11,17 @@ type LlmSessionContext = {
11
11
  readonly maxFeedbackTurns: number;
12
12
  readonly requestPermission?: (request: PermissionAskRequest) => Promise<'allow' | 'deny'>;
13
13
  };
14
+ export type LlmSessionState<Session, Chunk> = {
15
+ readonly history: readonly ChatCompletionMessage[];
16
+ readonly turn0Done: boolean;
17
+ readonly feedbackTurns: number;
18
+ readonly preparation: LlmSessionPreparation<Session>;
19
+ readonly emitted?: Chunk | undefined;
20
+ };
21
+ export declare const isBlankTurn: (raw: unknown) => boolean;
22
+ export declare const runTurnFromState: <Context extends LlmSessionContext, Session, Chunk extends {
23
+ readonly kind: string;
24
+ }>(context: Context, state: LlmSessionState<Session, Chunk>, raw: unknown, primeTurn0: boolean, runTurn: (context: Context, turnPayload: unknown, history: readonly ChatCompletionMessage[], session: Session) => Observable<Chunk>) => Observable<LlmSessionState<Session, Chunk>>;
14
25
  /**
15
26
  * Sequential session fold. Each turn is an inner Observable reduced into the
16
27
  * accumulator; concurrency 1 queues feedback while a turn is streaming.
@@ -1,5 +1,5 @@
1
1
  import { EMPTY, concat, filter, from, map, mergeScan, of, scan, startWith, switchMap, throwError, } from 'rxjs';
2
- const isBlankTurn = (raw) => raw === null ||
2
+ export const isBlankTurn = (raw) => raw === null ||
3
3
  raw === undefined ||
4
4
  (typeof raw === 'string' && raw.trim().length === 0);
5
5
  const readHistorySync = (chunk) => {
@@ -63,7 +63,7 @@ const denyMaxFeedbackTurns = (state, maxFeedbackTurns) => {
63
63
  },
64
64
  }), throwError(() => message));
65
65
  };
66
- const runTurnFromState = (context, state, raw, primeTurn0, runTurn) => {
66
+ export const runTurnFromState = (context, state, raw, primeTurn0, runTurn) => {
67
67
  if (!state.turn0Done) {
68
68
  if (!primeTurn0 && isBlankTurn(raw)) {
69
69
  return EMPTY;
@@ -8,10 +8,12 @@ import type { ToolInvokeCall } from '@langflower/tools/create-project-harness';
8
8
  import type { ToolHandlerContext } from '@langflower/tools/domain-tool-configs';
9
9
  import type { PermissionAskRequest } from '@langflower/tools/permission';
10
10
  import type { CreateChatCompletionStream } from './chat-completion-stream.js';
11
+ import type { CreateEmbedding } from '../../embeddings/create-embedding.js';
11
12
  export declare const runHostServicesSymbol: unique symbol;
12
13
  export type LangflowerBusRequest = (intent: string, payload: unknown) => Promise<unknown>;
13
14
  export type RunHostServices = {
14
15
  readonly createChatCompletionStream?: CreateChatCompletionStream;
16
+ readonly createEmbedding?: CreateEmbedding;
15
17
  readonly skillMarkdown?: string;
16
18
  readonly agentsMarkdown?: string;
17
19
  /**
@@ -22,6 +24,14 @@ export type RunHostServices = {
22
24
  readonly providerId: string;
23
25
  readonly model: string;
24
26
  };
27
+ /**
28
+ * Parsed effective `LangflowerConfig.embedding` (`providerId/modelId`).
29
+ * Empty embed-node `providerId` / `model` params fall back to these.
30
+ */
31
+ readonly defaultEmbedding?: {
32
+ readonly providerId: string;
33
+ readonly model: string;
34
+ };
25
35
  readonly authorize?: (call: ToolInvokeCall) => Promise<'allow' | 'deny'>;
26
36
  /**
27
37
  * Direct HITL ask (tool gates + agent limit continue). Bypasses permission
@@ -101,7 +101,11 @@ export const critiqueNode = defineLlmNode({
101
101
  type: 'common-critique',
102
102
  displayName: 'Critique',
103
103
  category: 'AI',
104
- description: 'Adversarial Critique: first input is the original assignment/topic; second is the packet to attack. Finish with accept (agreed enough) or feedback (findings). Requires native tool / function calling. Optional wired tools / MCP / Sub-Agents may run via harness first.',
104
+ description: `
105
+ Attack the work against the original assignment. **Accept** when it is good enough, or send **feedback** with findings.
106
+
107
+ Wire the assignment on the first input and the packet to critique on the second. Needs a model that can call tools.
108
+ `.trim(),
105
109
  uiSchema: [
106
110
  ...llmPanelUiSchema.filter((item) => item.field !== 'maxIterations'),
107
111
  llmMaxIterationsUiField(DEFAULT_PATH_CHOICE_MAX_ITERATIONS, PATH_CHOICE_MAX_ITERATIONS_CAP),
@@ -144,7 +144,13 @@ export const fakeLlmNode = defineLlmNode({
144
144
  type: 'common-fake-llm',
145
145
  displayName: 'Fake LLM',
146
146
  category: 'AI',
147
- description: 'Imitates an LLM for demos: streams **reasoning** and **draftResponse**, then **response**. Optional scripted tool loop invokes `ctx.harness`.',
147
+ description: `
148
+ Demo stand-in for a real model. Streams reasoning, then a reply — no API key needed.
149
+
150
+ Typical uses:
151
+ - Smoke-test a graph
152
+ - Scripted tool calls in CI
153
+ `.trim(),
148
154
  uiSchema: [
149
155
  ...llmPanelUiSchema,
150
156
  ...llmRecoveryUiSchema,
@@ -54,7 +54,11 @@ export const openAiLlmNode = defineLlmNode({
54
54
  type: 'common-openai-llm',
55
55
  displayName: 'OpenAI-compatible LLM',
56
56
  category: 'AI',
57
- description: 'Streams chat completions from an OpenAI-compatible API. Invokes allowlisted builtins and mapped MCP tools via an internal tool loop (`ctx.toolHandles`).',
57
+ description: `
58
+ Talk to an OpenAI-compatible model. Pick provider, model, and role in the inspector.
59
+
60
+ Wire tools and skills so the model can search, edit files, or call specialists. The reply streams in the work log.
61
+ `.trim(),
58
62
  uiSchema: [
59
63
  ...llmPanelUiSchema,
60
64
  ...llmCompactionUiSchema,
@@ -104,7 +104,13 @@ export const reviewNode = defineLlmNode({
104
104
  type: 'common-review',
105
105
  displayName: 'Review',
106
106
  category: 'AI',
107
- description: 'Forced-tool Review: finish with accept or feedback (requires a model with native tool / function calling — prose or markdown tool_code will not route). Optional wired tools / MCP / Sub-Agents may run via harness first.',
107
+ description: `
108
+ A reviewer that must **accept** the work or send **feedback**. Needs a model that can call tools.
109
+
110
+ Typical uses:
111
+ - Gate a draft before the next stage
112
+ - Optional extra tools or Sub-Agents for the reviewer to use first
113
+ `.trim(),
108
114
  uiSchema: [
109
115
  ...llmPanelUiSchema.filter((item) => item.field !== 'maxIterations'),
110
116
  llmMaxIterationsUiField(DEFAULT_PATH_CHOICE_MAX_ITERATIONS, PATH_CHOICE_MAX_ITERATIONS_CAP),
@@ -1,7 +1,8 @@
1
1
  import { defineLlmNode, isSteerControlPayload, toLlmRecoveryPortValue, } from '@langflower/node-sdk/llm';
2
2
  import { TOOL_HANDLE_WIRE_TYPE, } from '@langflower/node-sdk';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { catchError, concat, filter, firstValueFrom, map, mergeMap, of, Subject, switchMap, take, tap, timeout, TimeoutError, } from 'rxjs';
4
+ import { catchError, concat, concatMap, filter, firstValueFrom, map, mergeMap, Observable, of, Subject, take, tap, TimeoutError, } from 'rxjs';
5
+ import { statefulObservable } from '@rx-evo/stateful-observable';
5
6
  import { llmPanelUiSchema } from '../../features/ui-schema/llm-panel-ui-schema.js';
6
7
  import { llmCompactionUiSchema } from '../../features/ui-schema/llm-compaction-ui-schema.js';
7
8
  import { llmRecoveryUiSchema } from '../../features/ui-schema/llm-recovery-ui-schema.js';
@@ -201,6 +202,30 @@ const runSubAgentTurn = (context, turn, history) => {
201
202
  return fail(text);
202
203
  })));
203
204
  };
205
+ /** Wall-clock until the inner completes — not `timeout({ first })`, which
206
+ * is satisfied by `historySync` and would never abort a hung generator. */
207
+ const withInvokeDeadline = (source, timeoutMs) => new Observable((subscriber) => {
208
+ const handle = setTimeout(() => {
209
+ subscriber.error(new TimeoutError());
210
+ }, timeoutMs);
211
+ const inner = source.subscribe({
212
+ next: (value) => {
213
+ subscriber.next(value);
214
+ },
215
+ error: (err) => {
216
+ clearTimeout(handle);
217
+ subscriber.error(err);
218
+ },
219
+ complete: () => {
220
+ clearTimeout(handle);
221
+ subscriber.complete();
222
+ },
223
+ });
224
+ return () => {
225
+ clearTimeout(handle);
226
+ inner.unsubscribe();
227
+ };
228
+ });
204
229
  const parseInvokeTurn = (raw, skillIds) => {
205
230
  if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
206
231
  return {
@@ -237,7 +262,11 @@ export const subAgentNode = defineLlmNode({
237
262
  type: 'common-sub-agent',
238
263
  displayName: 'Sub-Agent',
239
264
  category: 'AI',
240
- description: 'OpenAI-compatible specialist agent. Wire `tools` into a parent agent; invoke runs this node in-graph.',
265
+ description: `
266
+ A specialist agent on the canvas. Wire it into a parent agent's **tools** so the parent can delegate a task.
267
+
268
+ The specialist streams in its own work-log card. Set name, role, and skills on this node.
269
+ `.trim(),
241
270
  uiSchema: [
242
271
  {
243
272
  field: 'name',
@@ -269,7 +298,7 @@ export const subAgentNode = defineLlmNode({
269
298
  inline: 'text-multiline',
270
299
  defaultValue: '',
271
300
  });
272
- const chunks$ = new Subject();
301
+ const invoke$ = new Subject();
273
302
  let latestContext;
274
303
  let history = [];
275
304
  let invokeTail = Promise.resolve();
@@ -332,9 +361,32 @@ export const subAgentNode = defineLlmNode({
332
361
  skillIds: normalizeSkillIds(ec.params.skillIds),
333
362
  };
334
363
  });
335
- // Inner chunks stay values. `statefulObservable({ input: chunks$ })`
336
- // re-emits loading on every token; pipeValue fans it to all demux ports.
337
- const cycle$ = context$.pipeValue(switchMap(() => chunks$));
364
+ // Loader input is invoke start, not the chunk Subject: wrapping
365
+ // chunks$ would re-pending on every token (demux fans loading).
366
+ const cycle$ = statefulObservable({
367
+ input: invoke$,
368
+ mapOperator: concatMap,
369
+ loader: ({ context, turn }) => {
370
+ history = seedInvokeHistory(history, context);
371
+ const timeoutMs = context.recovery.subagentTimeoutMs;
372
+ const failTimedOut = (text) => of({ kind: 'response', text }, {
373
+ kind: 'invokeDone',
374
+ requestId: turn.requestId,
375
+ text,
376
+ });
377
+ const inner$ = runSubAgentTurn(context, turn, history).pipe(tap((chunk) => {
378
+ history = reduceInvokeHistory(history, chunk);
379
+ }));
380
+ if (timeoutMs <= 0) {
381
+ return inner$;
382
+ }
383
+ return withInvokeDeadline(inner$, timeoutMs).pipe(catchError((error) => failTimedOut(error instanceof TimeoutError
384
+ ? `Error: Sub-Agent timed out after ${timeoutMs}ms.`
385
+ : error instanceof Error
386
+ ? `Error: ${error.message}`
387
+ : 'Error: Sub-Agent turn failed.')));
388
+ },
389
+ });
338
390
  const enqueueInvoke = (announced, args, _toolCtx) => {
339
391
  const context = latestContext ?? announced;
340
392
  const parsed = parseInvokeTurn({ ...args, requestId: randomUUID() }, announced.skillIds);
@@ -342,22 +394,10 @@ export const subAgentNode = defineLlmNode({
342
394
  return Promise.resolve(parsed.text);
343
395
  }
344
396
  const run = () => {
345
- history = seedInvokeHistory(history, context);
346
- const timeoutMs = context.recovery.subagentTimeoutMs;
347
- let done$ = runSubAgentTurn(context, parsed.turn, history).pipe(tap((chunk) => {
348
- history = reduceInvokeHistory(history, chunk);
349
- chunks$.next(chunk);
350
- }), filter((chunk) => chunk.kind === 'invokeDone'), map((chunk) => chunk.text), take(1));
351
- if (timeoutMs > 0) {
352
- done$ = done$.pipe(timeout({ first: timeoutMs }), catchError((error) => of(error instanceof TimeoutError
353
- ? `Error: Sub-Agent timed out after ${timeoutMs}ms.`
354
- : error instanceof Error
355
- ? `Error: ${error.message}`
356
- : 'Error: Sub-Agent turn failed.')));
357
- }
358
- return firstValueFrom(done$, {
359
- defaultValue: EMPTY_INVOKE_RESULT,
360
- });
397
+ const result = firstValueFrom(cycle$.value$.pipe(filter((chunk) => chunk.kind === 'invokeDone' &&
398
+ chunk.requestId === parsed.turn.requestId), map((chunk) => chunk.text), take(1)), { defaultValue: EMPTY_INVOKE_RESULT });
399
+ invoke$.next({ context, turn: parsed.turn });
400
+ return result;
361
401
  };
362
402
  const next = invokeTail.then(run, run);
363
403
  invokeTail = next.then(() => undefined, () => undefined);
@@ -23,9 +23,11 @@ import { previewNode } from './output/preview/node.js';
23
23
  import { booleanNode } from './primitives/boolean/node.js';
24
24
  import { numberNode } from './primitives/number/node.js';
25
25
  import { stringNode } from './primitives/string/node.js';
26
+ import { stringMultilineNode } from './primitives/string-multiline/node.js';
26
27
  import { appendFileNode } from './text/append-file/node.js';
27
28
  import { concatNode } from './text/concat/node.js';
28
29
  import { readFileNode } from './text/read-file/node.js';
30
+ import { splitPacedNode } from './text/split-paced/node.js';
29
31
  import { writeFileNode } from './text/write-file/node.js';
30
32
  import { crawlNode } from './crawl/crawl/node.js';
31
33
  import { crawlToolsNode } from './crawl/crawl-tools/node.js';
@@ -35,10 +37,14 @@ import { savePageNode } from './crawl/save-page/node.js';
35
37
  import { memoryToolsNode } from './memory/memory-tools/node.js';
36
38
  import { langflowerToolsNode } from './langflower-tools/node.js';
37
39
  import { toolCollectionNode } from './tools/tool-collection/node.js';
40
+ import { embedTextNode } from './embeddings/embed-text/node.js';
41
+ import { embedSimilarityNode } from './embeddings/embed-similarity/node.js';
42
+ import { embedProviderNode } from './embeddings/embed-provider/node.js';
38
43
  const COMMON_REACTIVE_NODES = [
39
44
  booleanNode,
40
45
  numberNode,
41
46
  stringNode,
47
+ stringMultilineNode,
42
48
  mergeNode,
43
49
  delayNode,
44
50
  checkpointNode,
@@ -48,6 +54,7 @@ const COMMON_REACTIVE_NODES = [
48
54
  previewNode,
49
55
  finishNode,
50
56
  concatNode,
57
+ splitPacedNode,
51
58
  readFileNode,
52
59
  writeFileNode,
53
60
  appendFileNode,
@@ -73,6 +80,9 @@ const COMMON_REACTIVE_NODES = [
73
80
  savePageNode,
74
81
  crawlNode,
75
82
  crawlToolsNode,
83
+ embedTextNode,
84
+ embedSimilarityNode,
85
+ embedProviderNode,
76
86
  ];
77
87
  const COMMON_REACTIVE_NODE_CATALOG = Object.fromEntries(COMMON_REACTIVE_NODES.map((node) => [node.type, node]));
78
88
  export function getCommonReactiveNodeCatalog() {
@@ -1,4 +1,4 @@
1
- import { defineReactiveNode } from '@langflower/node-sdk';
1
+ import { defineReactiveNode, withLoading } from '@langflower/node-sdk';
2
2
  import { createCrawlContext } from '@langflower/tools/create-crawl-context';
3
3
  import { createWebFetch } from '@langflower/tools/create-web-fetch';
4
4
  import { runBfsCrawl } from '@langflower/tools/run-bfs-crawl';
@@ -24,7 +24,13 @@ export const crawlNode = defineReactiveNode({
24
24
  displayName: 'Crawl',
25
25
  category: 'Crawl',
26
26
  paletteSecondary: true,
27
- description: 'BFS crawl from a seed URL with depth/page limits; saves pages into the crawl run.',
27
+ description: `
28
+ Start from a URL and follow links up to a depth and page cap. Pages are saved as they are visited.
29
+
30
+ Typical uses:
31
+ - Research a site without clicking by hand
32
+ - Collect a small corpus for an LLM
33
+ `.trim(),
28
34
  uiSchema: [
29
35
  {
30
36
  field: 'maxDepth',
@@ -67,7 +73,9 @@ export const crawlNode = defineReactiveNode({
67
73
  const pages$ = combineInputs([startUrl, ctx], ([rawUrl, ec]) => ({
68
74
  startUrl: String(rawUrl ?? '').trim(),
69
75
  ec,
70
- })).pipeValue(mergeMap(({ startUrl: seed, ec }) => {
76
+ }))
77
+ .pipe(withLoading())
78
+ .pipeValue(mergeMap(({ startUrl: seed, ec }) => {
71
79
  if (seed.length === 0) {
72
80
  return throwError(() => new Error('Crawl requires a non-empty startUrl.'));
73
81
  }
@@ -8,6 +8,10 @@ export const crawlToolsNode = defineToolRegistrations({
8
8
  type: 'common-crawl-tools',
9
9
  displayName: 'Crawl Tools',
10
10
  category: 'Tools',
11
- description: 'Emits crawl_fetch / crawl_extract_links / crawl_save_page / crawl_bfs with imported handlers for agent inventory.',
11
+ description: `
12
+ Give an agent fetch, extract-links, save-page, and crawl tools.
13
+
14
+ Wire **tools** into an LLM so it can research the web from chat.
15
+ `.trim(),
12
16
  tools: CRAWL_TOOL_CONFIGS,
13
17
  });
@@ -11,7 +11,13 @@ export const extractLinksNode = defineReactiveNode({
11
11
  displayName: 'Extract Links',
12
12
  category: 'Crawl',
13
13
  paletteSecondary: true,
14
- description: 'Resolves `href` values from HTML into an absolute URL list.',
14
+ description: `
15
+ Pull absolute URLs from HTML.
16
+
17
+ Typical uses:
18
+ - List outbound links after Fetch URL
19
+ - Feed those URLs into Crawl or another fetch
20
+ `.trim(),
15
21
  uiSchema: [],
16
22
  bind(_ctx, { makeInput, configureOutput, combineInputs }) {
17
23
  const html = makeInput('html', {
@@ -1,4 +1,4 @@
1
- import { defineReactiveNode } from '@langflower/node-sdk';
1
+ import { defineReactiveNode, withLoading } from '@langflower/node-sdk';
2
2
  import { createWebFetch } from '@langflower/tools/create-web-fetch';
3
3
  import { from, map, mergeMap, throwError } from 'rxjs';
4
4
  import { htmlToText } from '@langflower/tools/html';
@@ -18,7 +18,13 @@ export const fetchUrlNode = defineReactiveNode({
18
18
  displayName: 'Fetch URL',
19
19
  category: 'Crawl',
20
20
  paletteSecondary: true,
21
- description: 'Fetches a URL through the SSRF-guarded harness and emits HTML + plain text.',
21
+ description: `
22
+ Download a page and get HTML plus readable text.
23
+
24
+ Typical uses:
25
+ - Pull an article before Extract Links or an LLM
26
+ - Seed a Crawl
27
+ `.trim(),
22
28
  uiSchema: [
23
29
  {
24
30
  field: 'timeoutMs',
@@ -43,7 +49,9 @@ export const fetchUrlNode = defineReactiveNode({
43
49
  const fetched$ = combineInputs([url, ctx], ([rawUrl, ec]) => ({
44
50
  rawUrl: String(rawUrl ?? '').trim(),
45
51
  ec,
46
- })).pipeValue(mergeMap(({ rawUrl, ec }) => {
52
+ }))
53
+ .pipe(withLoading())
54
+ .pipeValue(mergeMap(({ rawUrl, ec }) => {
47
55
  if (rawUrl.length === 0) {
48
56
  return throwError(() => new Error('Fetch URL requires a non-empty url.'));
49
57
  }
@@ -59,7 +67,8 @@ export const fetchUrlNode = defineReactiveNode({
59
67
  maxBytes,
60
68
  })).pipe(map((result) => {
61
69
  if (!result.ok && result.body.length === 0) {
62
- throw new Error(result.error ?? `Fetch failed for ${rawUrl}`);
70
+ throw new Error(result.error ??
71
+ `Fetch failed for ${rawUrl}`);
63
72
  }
64
73
  return {
65
74
  html: result.body,
@@ -1,4 +1,4 @@
1
- import { defineReactiveNode } from '@langflower/node-sdk';
1
+ import { defineReactiveNode, withLoading } from '@langflower/node-sdk';
2
2
  import { createCrawlContext } from '@langflower/tools/create-crawl-context';
3
3
  import { from, mergeMap, throwError } from 'rxjs';
4
4
  import { extractHtmlTitle } from '@langflower/tools/html';
@@ -12,7 +12,13 @@ export const savePageNode = defineReactiveNode({
12
12
  displayName: 'Save Page',
13
13
  category: 'Crawl',
14
14
  paletteSecondary: true,
15
- description: 'Saves url/html/text into the run crawl directory and emits saved metadata.',
15
+ description: `
16
+ Store a fetched page in this run's crawl folder and emit where it was saved.
17
+
18
+ Typical uses:
19
+ - Keep HTML/text for later review
20
+ - Persist a page before the next crawl hop
21
+ `.trim(),
16
22
  uiSchema: [],
17
23
  bind(ctx, { makeInput, configureOutput, combineInputs }) {
18
24
  const url = makeInput('url', {
@@ -38,7 +44,9 @@ export const savePageNode = defineReactiveNode({
38
44
  html: String(rawHtml ?? ''),
39
45
  text: String(rawText ?? ''),
40
46
  ec,
41
- })).pipeValue(mergeMap(({ url: pageUrl, html: pageHtml, text: pageText, ec }) => {
47
+ }))
48
+ .pipe(withLoading())
49
+ .pipeValue(mergeMap(({ url: pageUrl, html: pageHtml, text: pageText, ec }) => {
42
50
  if (pageUrl.length === 0) {
43
51
  return throwError(() => new Error('Save Page requires a non-empty url.'));
44
52
  }