flock-core 0.5.0b28__py3-none-any.whl → 0.5.0b51__py3-none-any.whl

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.

Potentially problematic release.


This version of flock-core might be problematic. Click here for more details.

Files changed (469) hide show
  1. flock/__init__.py +12 -217
  2. flock/agent.py +678 -0
  3. flock/api/themes.py +71 -0
  4. flock/artifacts.py +79 -0
  5. flock/cli.py +75 -0
  6. flock/components.py +173 -0
  7. flock/dashboard/__init__.py +28 -0
  8. flock/dashboard/collector.py +283 -0
  9. flock/dashboard/events.py +182 -0
  10. flock/dashboard/launcher.py +230 -0
  11. flock/dashboard/service.py +537 -0
  12. flock/dashboard/websocket.py +235 -0
  13. flock/engines/__init__.py +6 -0
  14. flock/engines/dspy_engine.py +856 -0
  15. flock/examples.py +128 -0
  16. flock/frontend/README.md +678 -0
  17. flock/frontend/docs/DESIGN_SYSTEM.md +1980 -0
  18. flock/frontend/index.html +12 -0
  19. flock/frontend/package-lock.json +4347 -0
  20. flock/frontend/package.json +48 -0
  21. flock/frontend/src/App.tsx +79 -0
  22. flock/frontend/src/__tests__/e2e/critical-scenarios.test.tsx +587 -0
  23. flock/frontend/src/__tests__/integration/filtering-e2e.test.tsx +387 -0
  24. flock/frontend/src/__tests__/integration/graph-rendering.test.tsx +640 -0
  25. flock/frontend/src/__tests__/integration/indexeddb-persistence.test.tsx +699 -0
  26. flock/frontend/src/components/common/BuildInfo.tsx +39 -0
  27. flock/frontend/src/components/common/EmptyState.module.css +115 -0
  28. flock/frontend/src/components/common/EmptyState.tsx +128 -0
  29. flock/frontend/src/components/common/ErrorBoundary.module.css +169 -0
  30. flock/frontend/src/components/common/ErrorBoundary.tsx +118 -0
  31. flock/frontend/src/components/common/KeyboardShortcutsDialog.css +251 -0
  32. flock/frontend/src/components/common/KeyboardShortcutsDialog.tsx +151 -0
  33. flock/frontend/src/components/common/LoadingSpinner.module.css +97 -0
  34. flock/frontend/src/components/common/LoadingSpinner.tsx +29 -0
  35. flock/frontend/src/components/controls/PublishControl.css +547 -0
  36. flock/frontend/src/components/controls/PublishControl.test.tsx +543 -0
  37. flock/frontend/src/components/controls/PublishControl.tsx +432 -0
  38. flock/frontend/src/components/details/DetailWindowContainer.tsx +62 -0
  39. flock/frontend/src/components/details/LiveOutputTab.test.tsx +792 -0
  40. flock/frontend/src/components/details/LiveOutputTab.tsx +220 -0
  41. flock/frontend/src/components/details/MessageHistoryTab.tsx +299 -0
  42. flock/frontend/src/components/details/NodeDetailWindow.test.tsx +501 -0
  43. flock/frontend/src/components/details/NodeDetailWindow.tsx +218 -0
  44. flock/frontend/src/components/details/RunStatusTab.tsx +307 -0
  45. flock/frontend/src/components/details/tabs.test.tsx +1015 -0
  46. flock/frontend/src/components/filters/CorrelationIDFilter.module.css +102 -0
  47. flock/frontend/src/components/filters/CorrelationIDFilter.test.tsx +197 -0
  48. flock/frontend/src/components/filters/CorrelationIDFilter.tsx +121 -0
  49. flock/frontend/src/components/filters/FilterBar.module.css +29 -0
  50. flock/frontend/src/components/filters/FilterBar.test.tsx +133 -0
  51. flock/frontend/src/components/filters/FilterBar.tsx +33 -0
  52. flock/frontend/src/components/filters/FilterPills.module.css +79 -0
  53. flock/frontend/src/components/filters/FilterPills.test.tsx +173 -0
  54. flock/frontend/src/components/filters/FilterPills.tsx +67 -0
  55. flock/frontend/src/components/filters/TimeRangeFilter.module.css +91 -0
  56. flock/frontend/src/components/filters/TimeRangeFilter.test.tsx +154 -0
  57. flock/frontend/src/components/filters/TimeRangeFilter.tsx +105 -0
  58. flock/frontend/src/components/graph/AgentNode.test.tsx +75 -0
  59. flock/frontend/src/components/graph/AgentNode.tsx +322 -0
  60. flock/frontend/src/components/graph/GraphCanvas.tsx +406 -0
  61. flock/frontend/src/components/graph/MessageFlowEdge.tsx +128 -0
  62. flock/frontend/src/components/graph/MessageNode.test.tsx +62 -0
  63. flock/frontend/src/components/graph/MessageNode.tsx +116 -0
  64. flock/frontend/src/components/graph/MiniMap.tsx +47 -0
  65. flock/frontend/src/components/graph/TransformEdge.tsx +123 -0
  66. flock/frontend/src/components/layout/DashboardLayout.css +407 -0
  67. flock/frontend/src/components/layout/DashboardLayout.tsx +300 -0
  68. flock/frontend/src/components/layout/Header.module.css +88 -0
  69. flock/frontend/src/components/layout/Header.tsx +52 -0
  70. flock/frontend/src/components/modules/EventLogModule.test.tsx +401 -0
  71. flock/frontend/src/components/modules/EventLogModule.tsx +396 -0
  72. flock/frontend/src/components/modules/EventLogModuleWrapper.tsx +17 -0
  73. flock/frontend/src/components/modules/ModuleRegistry.test.ts +333 -0
  74. flock/frontend/src/components/modules/ModuleRegistry.ts +85 -0
  75. flock/frontend/src/components/modules/ModuleWindow.tsx +155 -0
  76. flock/frontend/src/components/modules/registerModules.ts +20 -0
  77. flock/frontend/src/components/settings/AdvancedSettings.tsx +175 -0
  78. flock/frontend/src/components/settings/AppearanceSettings.tsx +185 -0
  79. flock/frontend/src/components/settings/GraphSettings.tsx +110 -0
  80. flock/frontend/src/components/settings/SettingsPanel.css +327 -0
  81. flock/frontend/src/components/settings/SettingsPanel.tsx +131 -0
  82. flock/frontend/src/components/settings/ThemeSelector.tsx +298 -0
  83. flock/frontend/src/hooks/useKeyboardShortcuts.ts +148 -0
  84. flock/frontend/src/hooks/useModulePersistence.test.ts +442 -0
  85. flock/frontend/src/hooks/useModulePersistence.ts +154 -0
  86. flock/frontend/src/hooks/useModules.ts +139 -0
  87. flock/frontend/src/hooks/usePersistence.ts +139 -0
  88. flock/frontend/src/main.tsx +13 -0
  89. flock/frontend/src/services/api.ts +213 -0
  90. flock/frontend/src/services/indexeddb.test.ts +793 -0
  91. flock/frontend/src/services/indexeddb.ts +794 -0
  92. flock/frontend/src/services/layout.test.ts +437 -0
  93. flock/frontend/src/services/layout.ts +146 -0
  94. flock/frontend/src/services/themeApplicator.ts +140 -0
  95. flock/frontend/src/services/themeService.ts +77 -0
  96. flock/frontend/src/services/websocket.test.ts +595 -0
  97. flock/frontend/src/services/websocket.ts +685 -0
  98. flock/frontend/src/store/filterStore.test.ts +242 -0
  99. flock/frontend/src/store/filterStore.ts +103 -0
  100. flock/frontend/src/store/graphStore.test.ts +186 -0
  101. flock/frontend/src/store/graphStore.ts +414 -0
  102. flock/frontend/src/store/moduleStore.test.ts +253 -0
  103. flock/frontend/src/store/moduleStore.ts +57 -0
  104. flock/frontend/src/store/settingsStore.ts +188 -0
  105. flock/frontend/src/store/streamStore.ts +68 -0
  106. flock/frontend/src/store/uiStore.test.ts +54 -0
  107. flock/frontend/src/store/uiStore.ts +110 -0
  108. flock/frontend/src/store/wsStore.ts +34 -0
  109. flock/frontend/src/styles/index.css +15 -0
  110. flock/frontend/src/styles/scrollbar.css +47 -0
  111. flock/frontend/src/styles/variables.css +488 -0
  112. flock/frontend/src/test/setup.ts +1 -0
  113. flock/frontend/src/types/filters.ts +14 -0
  114. flock/frontend/src/types/graph.ts +55 -0
  115. flock/frontend/src/types/modules.ts +7 -0
  116. flock/frontend/src/types/theme.ts +55 -0
  117. flock/frontend/src/utils/mockData.ts +85 -0
  118. flock/frontend/src/utils/performance.ts +16 -0
  119. flock/frontend/src/utils/transforms.test.ts +860 -0
  120. flock/frontend/src/utils/transforms.ts +323 -0
  121. flock/frontend/src/vite-env.d.ts +17 -0
  122. flock/frontend/tsconfig.json +27 -0
  123. flock/frontend/tsconfig.node.json +11 -0
  124. flock/frontend/vite.config.ts +25 -0
  125. flock/frontend/vitest.config.ts +11 -0
  126. flock/{core/util → helper}/cli_helper.py +4 -3
  127. flock/{core/logging → logging}/__init__.py +2 -3
  128. flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
  129. flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
  130. flock/{core/logging → logging}/formatters/themed_formatter.py +69 -115
  131. flock/{core/logging → logging}/logging.py +77 -61
  132. flock/{core/logging → logging}/telemetry.py +20 -26
  133. flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
  134. flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +6 -9
  135. flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
  136. flock/{core/logging → logging}/trace_and_logged.py +20 -24
  137. flock/mcp/__init__.py +91 -0
  138. flock/{core/mcp/mcp_client.py → mcp/client.py} +103 -154
  139. flock/{core/mcp/mcp_config.py → mcp/config.py} +62 -117
  140. flock/mcp/manager.py +255 -0
  141. flock/mcp/servers/sse/__init__.py +1 -1
  142. flock/mcp/servers/sse/flock_sse_server.py +11 -53
  143. flock/mcp/servers/stdio/__init__.py +1 -1
  144. flock/mcp/servers/stdio/flock_stdio_server.py +8 -48
  145. flock/mcp/servers/streamable_http/flock_streamable_http_server.py +17 -62
  146. flock/mcp/servers/websockets/flock_websocket_server.py +7 -40
  147. flock/{core/mcp/flock_mcp_tool.py → mcp/tool.py} +16 -26
  148. flock/mcp/types/__init__.py +42 -0
  149. flock/{core/mcp → mcp}/types/callbacks.py +9 -15
  150. flock/{core/mcp → mcp}/types/factories.py +7 -6
  151. flock/{core/mcp → mcp}/types/handlers.py +13 -18
  152. flock/{core/mcp → mcp}/types/types.py +70 -74
  153. flock/{core/mcp → mcp}/util/helpers.py +1 -1
  154. flock/orchestrator.py +645 -0
  155. flock/registry.py +148 -0
  156. flock/runtime.py +262 -0
  157. flock/service.py +140 -0
  158. flock/store.py +69 -0
  159. flock/subscription.py +111 -0
  160. flock/themes/andromeda.toml +1 -1
  161. flock/themes/apple-system-colors.toml +1 -1
  162. flock/themes/arcoiris.toml +1 -1
  163. flock/themes/atomonelight.toml +1 -1
  164. flock/themes/ayu copy.toml +1 -1
  165. flock/themes/ayu-light.toml +1 -1
  166. flock/themes/belafonte-day.toml +1 -1
  167. flock/themes/belafonte-night.toml +1 -1
  168. flock/themes/blulocodark.toml +1 -1
  169. flock/themes/breeze.toml +1 -1
  170. flock/themes/broadcast.toml +1 -1
  171. flock/themes/brogrammer.toml +1 -1
  172. flock/themes/builtin-dark.toml +1 -1
  173. flock/themes/builtin-pastel-dark.toml +1 -1
  174. flock/themes/catppuccin-latte.toml +1 -1
  175. flock/themes/catppuccin-macchiato.toml +1 -1
  176. flock/themes/catppuccin-mocha.toml +1 -1
  177. flock/themes/cga.toml +1 -1
  178. flock/themes/chalk.toml +1 -1
  179. flock/themes/ciapre.toml +1 -1
  180. flock/themes/coffee-theme.toml +1 -1
  181. flock/themes/cyberpunkscarletprotocol.toml +1 -1
  182. flock/themes/dark+.toml +1 -1
  183. flock/themes/darkermatrix.toml +1 -1
  184. flock/themes/darkside.toml +1 -1
  185. flock/themes/desert.toml +1 -1
  186. flock/themes/django.toml +1 -1
  187. flock/themes/djangosmooth.toml +1 -1
  188. flock/themes/doomone.toml +1 -1
  189. flock/themes/dotgov.toml +1 -1
  190. flock/themes/dracula+.toml +1 -1
  191. flock/themes/duckbones.toml +1 -1
  192. flock/themes/encom.toml +1 -1
  193. flock/themes/espresso.toml +1 -1
  194. flock/themes/everblush.toml +1 -1
  195. flock/themes/fairyfloss.toml +1 -1
  196. flock/themes/fideloper.toml +1 -1
  197. flock/themes/fishtank.toml +1 -1
  198. flock/themes/flexoki-light.toml +1 -1
  199. flock/themes/floraverse.toml +1 -1
  200. flock/themes/framer.toml +1 -1
  201. flock/themes/galizur.toml +1 -1
  202. flock/themes/github.toml +1 -1
  203. flock/themes/grass.toml +1 -1
  204. flock/themes/grey-green.toml +1 -1
  205. flock/themes/gruvboxlight.toml +1 -1
  206. flock/themes/guezwhoz.toml +1 -1
  207. flock/themes/harper.toml +1 -1
  208. flock/themes/hax0r-blue.toml +1 -1
  209. flock/themes/hopscotch.256.toml +1 -1
  210. flock/themes/ic-green-ppl.toml +1 -1
  211. flock/themes/iceberg-dark.toml +1 -1
  212. flock/themes/japanesque.toml +1 -1
  213. flock/themes/jubi.toml +1 -1
  214. flock/themes/kibble.toml +1 -1
  215. flock/themes/kolorit.toml +1 -1
  216. flock/themes/kurokula.toml +1 -1
  217. flock/themes/materialdesigncolors.toml +1 -1
  218. flock/themes/matrix.toml +1 -1
  219. flock/themes/mellifluous.toml +1 -1
  220. flock/themes/midnight-in-mojave.toml +1 -1
  221. flock/themes/monokai-remastered.toml +1 -1
  222. flock/themes/monokai-soda.toml +1 -1
  223. flock/themes/neon.toml +1 -1
  224. flock/themes/neopolitan.toml +1 -1
  225. flock/themes/nord-light.toml +1 -1
  226. flock/themes/ocean.toml +1 -1
  227. flock/themes/onehalfdark.toml +1 -1
  228. flock/themes/onehalflight.toml +1 -1
  229. flock/themes/palenighthc.toml +1 -1
  230. flock/themes/paulmillr.toml +1 -1
  231. flock/themes/pencildark.toml +1 -1
  232. flock/themes/pnevma.toml +1 -1
  233. flock/themes/purple-rain.toml +1 -1
  234. flock/themes/purplepeter.toml +1 -1
  235. flock/themes/raycast-dark.toml +1 -1
  236. flock/themes/red-sands.toml +1 -1
  237. flock/themes/relaxed.toml +1 -1
  238. flock/themes/retro.toml +1 -1
  239. flock/themes/rose-pine.toml +1 -1
  240. flock/themes/royal.toml +1 -1
  241. flock/themes/ryuuko.toml +1 -1
  242. flock/themes/sakura.toml +1 -1
  243. flock/themes/scarlet-protocol.toml +1 -1
  244. flock/themes/seoulbones-dark.toml +1 -1
  245. flock/themes/shades-of-purple.toml +1 -1
  246. flock/themes/smyck.toml +1 -1
  247. flock/themes/softserver.toml +1 -1
  248. flock/themes/solarized-darcula.toml +1 -1
  249. flock/themes/square.toml +1 -1
  250. flock/themes/sugarplum.toml +1 -1
  251. flock/themes/thayer-bright.toml +1 -1
  252. flock/themes/tokyonight.toml +1 -1
  253. flock/themes/tomorrow.toml +1 -1
  254. flock/themes/ubuntu.toml +1 -1
  255. flock/themes/ultradark.toml +1 -1
  256. flock/themes/ultraviolent.toml +1 -1
  257. flock/themes/unikitty.toml +1 -1
  258. flock/themes/urple.toml +1 -1
  259. flock/themes/vesper.toml +1 -1
  260. flock/themes/vimbones.toml +1 -1
  261. flock/themes/wildcherry.toml +1 -1
  262. flock/themes/wilmersdorf.toml +1 -1
  263. flock/themes/wryan.toml +1 -1
  264. flock/themes/xcodedarkhc.toml +1 -1
  265. flock/themes/xcodelight.toml +1 -1
  266. flock/themes/zenbones-light.toml +1 -1
  267. flock/themes/zenwritten-dark.toml +1 -1
  268. flock/utilities.py +301 -0
  269. flock/{components/utility → utility}/output_utility_component.py +68 -53
  270. flock/visibility.py +107 -0
  271. flock_core-0.5.0b51.dist-info/METADATA +747 -0
  272. flock_core-0.5.0b51.dist-info/RECORD +508 -0
  273. flock_core-0.5.0b51.dist-info/entry_points.txt +2 -0
  274. {flock_core-0.5.0b28.dist-info → flock_core-0.5.0b51.dist-info}/licenses/LICENSE +1 -1
  275. flock/adapter/__init__.py +0 -14
  276. flock/adapter/azure_adapter.py +0 -68
  277. flock/adapter/chroma_adapter.py +0 -73
  278. flock/adapter/faiss_adapter.py +0 -97
  279. flock/adapter/pinecone_adapter.py +0 -51
  280. flock/adapter/vector_base.py +0 -47
  281. flock/cli/assets/release_notes.md +0 -140
  282. flock/cli/config.py +0 -8
  283. flock/cli/constants.py +0 -36
  284. flock/cli/create_agent.py +0 -1
  285. flock/cli/create_flock.py +0 -280
  286. flock/cli/execute_flock.py +0 -620
  287. flock/cli/load_agent.py +0 -1
  288. flock/cli/load_examples.py +0 -1
  289. flock/cli/load_flock.py +0 -192
  290. flock/cli/load_release_notes.py +0 -20
  291. flock/cli/loaded_flock_cli.py +0 -254
  292. flock/cli/manage_agents.py +0 -459
  293. flock/cli/registry_management.py +0 -889
  294. flock/cli/runner.py +0 -41
  295. flock/cli/settings.py +0 -857
  296. flock/cli/utils.py +0 -135
  297. flock/cli/view_results.py +0 -29
  298. flock/cli/yaml_editor.py +0 -396
  299. flock/components/__init__.py +0 -30
  300. flock/components/evaluation/__init__.py +0 -9
  301. flock/components/evaluation/declarative_evaluation_component.py +0 -606
  302. flock/components/routing/__init__.py +0 -15
  303. flock/components/routing/conditional_routing_component.py +0 -494
  304. flock/components/routing/default_routing_component.py +0 -103
  305. flock/components/routing/llm_routing_component.py +0 -206
  306. flock/components/utility/__init__.py +0 -22
  307. flock/components/utility/example_utility_component.py +0 -250
  308. flock/components/utility/feedback_utility_component.py +0 -206
  309. flock/components/utility/memory_utility_component.py +0 -550
  310. flock/components/utility/metrics_utility_component.py +0 -700
  311. flock/config.py +0 -61
  312. flock/core/__init__.py +0 -110
  313. flock/core/agent/__init__.py +0 -16
  314. flock/core/agent/default_agent.py +0 -216
  315. flock/core/agent/flock_agent_components.py +0 -104
  316. flock/core/agent/flock_agent_execution.py +0 -101
  317. flock/core/agent/flock_agent_integration.py +0 -260
  318. flock/core/agent/flock_agent_lifecycle.py +0 -186
  319. flock/core/agent/flock_agent_serialization.py +0 -381
  320. flock/core/api/__init__.py +0 -10
  321. flock/core/api/custom_endpoint.py +0 -45
  322. flock/core/api/endpoints.py +0 -254
  323. flock/core/api/main.py +0 -162
  324. flock/core/api/models.py +0 -97
  325. flock/core/api/run_store.py +0 -224
  326. flock/core/api/runner.py +0 -44
  327. flock/core/api/service.py +0 -214
  328. flock/core/component/__init__.py +0 -15
  329. flock/core/component/agent_component_base.py +0 -309
  330. flock/core/component/evaluation_component.py +0 -62
  331. flock/core/component/routing_component.py +0 -74
  332. flock/core/component/utility_component.py +0 -69
  333. flock/core/config/flock_agent_config.py +0 -58
  334. flock/core/config/scheduled_agent_config.py +0 -40
  335. flock/core/context/context.py +0 -213
  336. flock/core/context/context_manager.py +0 -37
  337. flock/core/context/context_vars.py +0 -10
  338. flock/core/evaluation/utils.py +0 -396
  339. flock/core/execution/batch_executor.py +0 -369
  340. flock/core/execution/evaluation_executor.py +0 -438
  341. flock/core/execution/local_executor.py +0 -31
  342. flock/core/execution/opik_executor.py +0 -103
  343. flock/core/execution/temporal_executor.py +0 -164
  344. flock/core/flock.py +0 -634
  345. flock/core/flock_agent.py +0 -336
  346. flock/core/flock_factory.py +0 -613
  347. flock/core/flock_scheduler.py +0 -166
  348. flock/core/flock_server_manager.py +0 -136
  349. flock/core/interpreter/python_interpreter.py +0 -689
  350. flock/core/mcp/__init__.py +0 -1
  351. flock/core/mcp/flock_mcp_server.py +0 -680
  352. flock/core/mcp/mcp_client_manager.py +0 -201
  353. flock/core/mcp/types/__init__.py +0 -1
  354. flock/core/mixin/dspy_integration.py +0 -403
  355. flock/core/mixin/prompt_parser.py +0 -125
  356. flock/core/orchestration/__init__.py +0 -15
  357. flock/core/orchestration/flock_batch_processor.py +0 -94
  358. flock/core/orchestration/flock_evaluator.py +0 -113
  359. flock/core/orchestration/flock_execution.py +0 -295
  360. flock/core/orchestration/flock_initialization.py +0 -149
  361. flock/core/orchestration/flock_server_manager.py +0 -67
  362. flock/core/orchestration/flock_web_server.py +0 -117
  363. flock/core/registry/__init__.py +0 -45
  364. flock/core/registry/agent_registry.py +0 -69
  365. flock/core/registry/callable_registry.py +0 -139
  366. flock/core/registry/component_discovery.py +0 -142
  367. flock/core/registry/component_registry.py +0 -64
  368. flock/core/registry/config_mapping.py +0 -64
  369. flock/core/registry/decorators.py +0 -137
  370. flock/core/registry/registry_hub.py +0 -205
  371. flock/core/registry/server_registry.py +0 -57
  372. flock/core/registry/type_registry.py +0 -86
  373. flock/core/serialization/__init__.py +0 -13
  374. flock/core/serialization/callable_registry.py +0 -52
  375. flock/core/serialization/flock_serializer.py +0 -832
  376. flock/core/serialization/json_encoder.py +0 -41
  377. flock/core/serialization/secure_serializer.py +0 -175
  378. flock/core/serialization/serializable.py +0 -342
  379. flock/core/serialization/serialization_utils.py +0 -412
  380. flock/core/util/file_path_utils.py +0 -223
  381. flock/core/util/hydrator.py +0 -309
  382. flock/core/util/input_resolver.py +0 -164
  383. flock/core/util/loader.py +0 -59
  384. flock/core/util/splitter.py +0 -219
  385. flock/di.py +0 -27
  386. flock/platform/docker_tools.py +0 -49
  387. flock/platform/jaeger_install.py +0 -86
  388. flock/webapp/__init__.py +0 -1
  389. flock/webapp/app/__init__.py +0 -0
  390. flock/webapp/app/api/__init__.py +0 -0
  391. flock/webapp/app/api/agent_management.py +0 -241
  392. flock/webapp/app/api/execution.py +0 -709
  393. flock/webapp/app/api/flock_management.py +0 -129
  394. flock/webapp/app/api/registry_viewer.py +0 -30
  395. flock/webapp/app/chat.py +0 -665
  396. flock/webapp/app/config.py +0 -104
  397. flock/webapp/app/dependencies.py +0 -117
  398. flock/webapp/app/main.py +0 -1070
  399. flock/webapp/app/middleware.py +0 -113
  400. flock/webapp/app/models_ui.py +0 -7
  401. flock/webapp/app/services/__init__.py +0 -0
  402. flock/webapp/app/services/feedback_file_service.py +0 -363
  403. flock/webapp/app/services/flock_service.py +0 -337
  404. flock/webapp/app/services/sharing_models.py +0 -81
  405. flock/webapp/app/services/sharing_store.py +0 -762
  406. flock/webapp/app/templates/theme_mapper.html +0 -326
  407. flock/webapp/app/theme_mapper.py +0 -812
  408. flock/webapp/app/utils.py +0 -85
  409. flock/webapp/run.py +0 -215
  410. flock/webapp/static/css/chat.css +0 -301
  411. flock/webapp/static/css/components.css +0 -167
  412. flock/webapp/static/css/header.css +0 -39
  413. flock/webapp/static/css/layout.css +0 -46
  414. flock/webapp/static/css/sidebar.css +0 -127
  415. flock/webapp/static/css/two-pane.css +0 -48
  416. flock/webapp/templates/base.html +0 -200
  417. flock/webapp/templates/chat.html +0 -152
  418. flock/webapp/templates/chat_settings.html +0 -19
  419. flock/webapp/templates/flock_editor.html +0 -16
  420. flock/webapp/templates/index.html +0 -12
  421. flock/webapp/templates/partials/_agent_detail_form.html +0 -93
  422. flock/webapp/templates/partials/_agent_list.html +0 -18
  423. flock/webapp/templates/partials/_agent_manager_view.html +0 -51
  424. flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
  425. flock/webapp/templates/partials/_chat_container.html +0 -15
  426. flock/webapp/templates/partials/_chat_messages.html +0 -57
  427. flock/webapp/templates/partials/_chat_settings_form.html +0 -85
  428. flock/webapp/templates/partials/_create_flock_form.html +0 -50
  429. flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
  430. flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
  431. flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
  432. flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
  433. flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
  434. flock/webapp/templates/partials/_env_vars_table.html +0 -23
  435. flock/webapp/templates/partials/_execution_form.html +0 -118
  436. flock/webapp/templates/partials/_execution_view_container.html +0 -28
  437. flock/webapp/templates/partials/_flock_file_list.html +0 -23
  438. flock/webapp/templates/partials/_flock_properties_form.html +0 -52
  439. flock/webapp/templates/partials/_flock_upload_form.html +0 -16
  440. flock/webapp/templates/partials/_header_flock_status.html +0 -5
  441. flock/webapp/templates/partials/_load_manager_view.html +0 -49
  442. flock/webapp/templates/partials/_registry_table.html +0 -25
  443. flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
  444. flock/webapp/templates/partials/_results_display.html +0 -78
  445. flock/webapp/templates/partials/_settings_env_content.html +0 -9
  446. flock/webapp/templates/partials/_settings_theme_content.html +0 -14
  447. flock/webapp/templates/partials/_settings_view.html +0 -36
  448. flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
  449. flock/webapp/templates/partials/_share_link_snippet.html +0 -35
  450. flock/webapp/templates/partials/_sidebar.html +0 -74
  451. flock/webapp/templates/partials/_streaming_results_container.html +0 -195
  452. flock/webapp/templates/partials/_structured_data_view.html +0 -40
  453. flock/webapp/templates/partials/_theme_preview.html +0 -36
  454. flock/webapp/templates/registry_viewer.html +0 -84
  455. flock/webapp/templates/shared_run_page.html +0 -140
  456. flock/workflow/__init__.py +0 -0
  457. flock/workflow/activities.py +0 -196
  458. flock/workflow/agent_activities.py +0 -24
  459. flock/workflow/agent_execution_activity.py +0 -202
  460. flock/workflow/flock_workflow.py +0 -214
  461. flock/workflow/temporal_config.py +0 -96
  462. flock/workflow/temporal_setup.py +0 -68
  463. flock_core-0.5.0b28.dist-info/METADATA +0 -274
  464. flock_core-0.5.0b28.dist-info/RECORD +0 -561
  465. flock_core-0.5.0b28.dist-info/entry_points.txt +0 -2
  466. /flock/{core/logging → logging}/formatters/themes.py +0 -0
  467. /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
  468. /flock/{core/mcp → mcp}/util/__init__.py +0 -0
  469. {flock_core-0.5.0b28.dist-info → flock_core-0.5.0b51.dist-info}/WHEEL +0 -0
@@ -0,0 +1,406 @@
1
+ import { useCallback, useMemo, useEffect, useState } from 'react';
2
+ import {
3
+ ReactFlow,
4
+ Background,
5
+ Controls,
6
+ NodeChange,
7
+ EdgeChange,
8
+ applyNodeChanges,
9
+ applyEdgeChanges,
10
+ useReactFlow,
11
+ type Node,
12
+ } from '@xyflow/react';
13
+ import '@xyflow/react/dist/style.css';
14
+ import AgentNode from './AgentNode';
15
+ import MessageNode from './MessageNode';
16
+ import MessageFlowEdge from './MessageFlowEdge';
17
+ import TransformEdge from './TransformEdge';
18
+ import MiniMap from './MiniMap';
19
+ import { useGraphStore } from '../../store/graphStore';
20
+ import { useUIStore } from '../../store/uiStore';
21
+ import { useModuleStore } from '../../store/moduleStore';
22
+ import { useSettingsStore } from '../../store/settingsStore';
23
+ import { moduleRegistry } from '../modules/ModuleRegistry';
24
+ import { applyDagreLayout } from '../../services/layout';
25
+ import { usePersistence } from '../../hooks/usePersistence';
26
+ import { v4 as uuidv4 } from 'uuid';
27
+
28
+ const GraphCanvas: React.FC = () => {
29
+ const { fitView, getIntersectingNodes } = useReactFlow();
30
+
31
+ const mode = useUIStore((state) => state.mode);
32
+ const openDetailWindow = useUIStore((state) => state.openDetailWindow);
33
+ const layoutDirection = useSettingsStore((state) => state.advanced.layoutDirection);
34
+ const nodes = useGraphStore((state) => state.nodes);
35
+ const edges = useGraphStore((state) => state.edges);
36
+ const agents = useGraphStore((state) => state.agents);
37
+ const messages = useGraphStore((state) => state.messages);
38
+ const runs = useGraphStore((state) => state.runs);
39
+ const generateAgentViewGraph = useGraphStore((state) => state.generateAgentViewGraph);
40
+ const generateBlackboardViewGraph = useGraphStore((state) => state.generateBlackboardViewGraph);
41
+ const updateNodePosition = useGraphStore((state) => state.updateNodePosition);
42
+ const addModule = useModuleStore((state) => state.addModule);
43
+
44
+ // Graph settings from settings store
45
+ const edgeType = useSettingsStore((state) => state.graph.edgeType);
46
+ const edgeStrokeWidth = useSettingsStore((state) => state.graph.edgeStrokeWidth);
47
+ const edgeAnimation = useSettingsStore((state) => state.graph.edgeAnimation);
48
+
49
+ const [contextMenu, setContextMenu] = useState<{ x: number; y: number } | null>(null);
50
+ const [showModuleSubmenu, setShowModuleSubmenu] = useState(false);
51
+
52
+ // Persistence hook - loads positions on mount and handles saves
53
+ const { saveNodePosition } = usePersistence();
54
+
55
+ // Memoize node types to prevent re-creation
56
+ const nodeTypes = useMemo(
57
+ () => ({
58
+ agent: AgentNode,
59
+ message: MessageNode,
60
+ }),
61
+ []
62
+ );
63
+
64
+ // Memoize edge types to prevent re-creation
65
+ const edgeTypes = useMemo(
66
+ () => ({
67
+ message_flow: MessageFlowEdge,
68
+ transformation: TransformEdge,
69
+ }),
70
+ []
71
+ );
72
+
73
+ // Generate graph when mode changes OR when agents/messages/runs change
74
+ useEffect(() => {
75
+ if (mode === 'agent') {
76
+ generateAgentViewGraph();
77
+ } else {
78
+ generateBlackboardViewGraph();
79
+ }
80
+ }, [mode, agents, messages, runs, generateAgentViewGraph, generateBlackboardViewGraph]);
81
+
82
+ // Regenerate graph when edge settings change to apply new edge styles
83
+ useEffect(() => {
84
+ if (mode === 'agent') {
85
+ generateAgentViewGraph();
86
+ } else {
87
+ generateBlackboardViewGraph();
88
+ }
89
+ }, [edgeType, edgeStrokeWidth, edgeAnimation, mode, generateAgentViewGraph, generateBlackboardViewGraph]);
90
+
91
+ const onNodesChange = useCallback(
92
+ (changes: NodeChange[]) => {
93
+ const updatedNodes = applyNodeChanges(changes, nodes);
94
+ useGraphStore.setState({ nodes: updatedNodes });
95
+
96
+ // Update position in store for persistence
97
+ changes.forEach((change) => {
98
+ if (change.type === 'position' && change.position) {
99
+ updateNodePosition(change.id, change.position);
100
+ }
101
+ });
102
+ },
103
+ [nodes, updateNodePosition]
104
+ );
105
+
106
+ const onEdgesChange = useCallback(
107
+ (changes: EdgeChange[]) => {
108
+ const updatedEdges = applyEdgeChanges(changes, edges);
109
+ useGraphStore.setState({ edges: updatedEdges });
110
+ },
111
+ [edges]
112
+ );
113
+
114
+ // Auto-layout handler
115
+ const handleAutoLayout = useCallback(() => {
116
+ const nodeSpacing = useSettingsStore.getState().advanced.nodeSpacing;
117
+ const rankSpacing = useSettingsStore.getState().advanced.rankSpacing;
118
+ const layoutedNodes = applyDagreLayout(nodes, edges, layoutDirection || 'TB', nodeSpacing, rankSpacing);
119
+
120
+ // Update nodes with new positions
121
+ layoutedNodes.forEach((node) => {
122
+ updateNodePosition(node.id, node.position);
123
+ });
124
+
125
+ useGraphStore.setState({ nodes: layoutedNodes });
126
+ setContextMenu(null);
127
+ setShowModuleSubmenu(false);
128
+ }, [nodes, edges, layoutDirection, updateNodePosition]);
129
+
130
+ // Auto-zoom handler
131
+ const handleAutoZoom = useCallback(() => {
132
+ fitView({ padding: 0.1, duration: 300 });
133
+ setContextMenu(null);
134
+ setShowModuleSubmenu(false);
135
+ }, [fitView]);
136
+
137
+ // Add module handler
138
+ const handleAddModule = useCallback((moduleType: string, clickX: number, clickY: number) => {
139
+ const moduleInstance = {
140
+ id: uuidv4(),
141
+ type: moduleType,
142
+ position: { x: clickX, y: clickY },
143
+ size: { width: 600, height: 400 },
144
+ visible: true,
145
+ };
146
+
147
+ addModule(moduleInstance);
148
+ setContextMenu(null);
149
+ setShowModuleSubmenu(false);
150
+ }, [addModule]);
151
+
152
+ // Context menu handler
153
+ const onPaneContextMenu = useCallback((event: React.MouseEvent | MouseEvent) => {
154
+ event.preventDefault();
155
+ setContextMenu({
156
+ x: event.clientX,
157
+ y: event.clientY,
158
+ });
159
+ setShowModuleSubmenu(false);
160
+ }, []);
161
+
162
+ // Close context menu on click outside
163
+ const onPaneClick = useCallback(() => {
164
+ setContextMenu(null);
165
+ setShowModuleSubmenu(false);
166
+ }, []);
167
+
168
+ // Node drag handler - prevent overlaps with collision detection
169
+ const onNodeDrag = useCallback(
170
+ (_event: React.MouseEvent | MouseEvent, node: Node) => {
171
+ const intersections = getIntersectingNodes(node);
172
+
173
+ // If there are intersecting nodes, snap back to prevent overlap
174
+ if (intersections.length > 0) {
175
+ // Revert to previous position by updating the nodes
176
+ useGraphStore.setState((state) => ({
177
+ nodes: state.nodes.map((n) =>
178
+ n.id === node.id
179
+ ? { ...n, position: n.position } // Keep previous position
180
+ : n
181
+ ),
182
+ }));
183
+ }
184
+ },
185
+ [getIntersectingNodes]
186
+ );
187
+
188
+ // Node drag stop handler - persist position with 300ms debounce
189
+ const onNodeDragStop = useCallback(
190
+ (_event: React.MouseEvent | MouseEvent, node: Node) => {
191
+ saveNodePosition(node.id, node.position);
192
+ },
193
+ [saveNodePosition]
194
+ );
195
+
196
+ // Node double-click handler - open detail window
197
+ const onNodeDoubleClick = useCallback(
198
+ (_event: React.MouseEvent, node: Node) => {
199
+ openDetailWindow(node.id);
200
+ },
201
+ [openDetailWindow]
202
+ );
203
+
204
+ const defaultEdgeOptions = useMemo(
205
+ () => ({
206
+ type: edgeType,
207
+ animated: edgeAnimation,
208
+ style: {
209
+ stroke: 'var(--color-edge-default)',
210
+ strokeWidth: edgeStrokeWidth,
211
+ },
212
+ }),
213
+ [edgeType, edgeAnimation, edgeStrokeWidth]
214
+ );
215
+
216
+ return (
217
+ <div style={{ width: '100%', height: '100%', position: 'relative' }}>
218
+ <ReactFlow
219
+ nodes={nodes}
220
+ edges={edges}
221
+ onNodesChange={onNodesChange}
222
+ onEdgesChange={onEdgesChange}
223
+ onNodeDrag={onNodeDrag}
224
+ onNodeDragStop={onNodeDragStop}
225
+ onNodeDoubleClick={onNodeDoubleClick}
226
+ nodeTypes={nodeTypes}
227
+ edgeTypes={edgeTypes}
228
+ defaultEdgeOptions={defaultEdgeOptions}
229
+ onPaneContextMenu={onPaneContextMenu}
230
+ onPaneClick={onPaneClick}
231
+ style={{
232
+ backgroundColor: 'var(--color-bg-elevated)',
233
+ }}
234
+ >
235
+ <Background
236
+ color="var(--color-border-subtle)"
237
+ gap={16}
238
+ size={1}
239
+ style={{
240
+ backgroundColor: 'var(--color-bg-elevated)',
241
+ }}
242
+ />
243
+ <Controls
244
+ style={{
245
+ backgroundColor: 'var(--color-bg-surface)',
246
+ border: '1px solid var(--color-border-default)',
247
+ borderRadius: 'var(--radius-lg)',
248
+ overflow: 'hidden',
249
+ boxShadow: 'var(--shadow-lg)',
250
+ }}
251
+ showZoom={true}
252
+ showFitView={true}
253
+ showInteractive={true}
254
+ />
255
+ <MiniMap />
256
+ </ReactFlow>
257
+
258
+ {/* Context Menu */}
259
+ {contextMenu && (
260
+ <div
261
+ style={{
262
+ position: 'fixed',
263
+ top: contextMenu.y,
264
+ left: contextMenu.x,
265
+ background: 'var(--color-bg-surface)',
266
+ border: 'var(--border-default)',
267
+ borderRadius: 'var(--radius-md)',
268
+ boxShadow: 'var(--shadow-lg)',
269
+ zIndex: 1000,
270
+ minWidth: 180,
271
+ }}
272
+ >
273
+ <button
274
+ onClick={handleAutoLayout}
275
+ style={{
276
+ display: 'block',
277
+ width: '100%',
278
+ padding: 'var(--spacing-2) var(--spacing-4)',
279
+ border: 'none',
280
+ background: 'transparent',
281
+ cursor: 'pointer',
282
+ textAlign: 'left',
283
+ fontSize: 'var(--font-size-body-sm)',
284
+ color: 'var(--color-text-primary)',
285
+ transition: 'var(--transition-colors)',
286
+ }}
287
+ onMouseEnter={(e) => {
288
+ e.currentTarget.style.background = 'var(--color-bg-overlay)';
289
+ }}
290
+ onMouseLeave={(e) => {
291
+ e.currentTarget.style.background = 'transparent';
292
+ }}
293
+ >
294
+ Auto Layout
295
+ </button>
296
+
297
+ <button
298
+ onClick={handleAutoZoom}
299
+ style={{
300
+ display: 'block',
301
+ width: '100%',
302
+ padding: 'var(--spacing-2) var(--spacing-4)',
303
+ border: 'none',
304
+ background: 'transparent',
305
+ cursor: 'pointer',
306
+ textAlign: 'left',
307
+ fontSize: 'var(--font-size-body-sm)',
308
+ color: 'var(--color-text-primary)',
309
+ transition: 'var(--transition-colors)',
310
+ }}
311
+ onMouseEnter={(e) => {
312
+ e.currentTarget.style.background = 'var(--color-bg-overlay)';
313
+ }}
314
+ onMouseLeave={(e) => {
315
+ e.currentTarget.style.background = 'transparent';
316
+ }}
317
+ >
318
+ Auto Zoom
319
+ </button>
320
+
321
+ <div style={{ position: 'relative' }}>
322
+ <button
323
+ onMouseEnter={() => setShowModuleSubmenu(true)}
324
+ onMouseLeave={(e) => {
325
+ // Only close submenu if not moving to submenu itself
326
+ const relatedTarget = e.relatedTarget as HTMLElement;
327
+ if (!relatedTarget || !relatedTarget.closest('.module-submenu')) {
328
+ setShowModuleSubmenu(false);
329
+ }
330
+ }}
331
+ style={{
332
+ display: 'flex',
333
+ alignItems: 'center',
334
+ justifyContent: 'space-between',
335
+ width: '100%',
336
+ padding: 'var(--spacing-2) var(--spacing-4)',
337
+ border: 'none',
338
+ background: showModuleSubmenu ? 'var(--color-bg-overlay)' : 'transparent',
339
+ cursor: 'pointer',
340
+ textAlign: 'left',
341
+ fontSize: 'var(--font-size-body-sm)',
342
+ color: 'var(--color-text-primary)',
343
+ transition: 'var(--transition-colors)',
344
+ }}
345
+ >
346
+ <span>Add Module</span>
347
+ <span style={{ marginLeft: 'var(--spacing-2)' }}>▶</span>
348
+ </button>
349
+
350
+ {/* Module Submenu */}
351
+ {showModuleSubmenu && (
352
+ <div
353
+ className="module-submenu"
354
+ onMouseEnter={() => setShowModuleSubmenu(true)}
355
+ onMouseLeave={() => setShowModuleSubmenu(false)}
356
+ style={{
357
+ position: 'absolute',
358
+ top: 0,
359
+ left: '100%',
360
+ background: 'var(--color-bg-surface)',
361
+ border: 'var(--border-default)',
362
+ borderRadius: 'var(--radius-md)',
363
+ boxShadow: 'var(--shadow-lg)',
364
+ zIndex: 1001,
365
+ minWidth: 160,
366
+ }}
367
+ >
368
+ {moduleRegistry.getAll().map((module) => (
369
+ <button
370
+ key={module.id}
371
+ onClick={() => handleAddModule(module.id, contextMenu.x, contextMenu.y)}
372
+ style={{
373
+ display: 'flex',
374
+ alignItems: 'center',
375
+ gap: 'var(--gap-sm)',
376
+ width: '100%',
377
+ padding: 'var(--spacing-2) var(--spacing-4)',
378
+ border: 'none',
379
+ background: 'transparent',
380
+ cursor: 'pointer',
381
+ textAlign: 'left',
382
+ fontSize: 'var(--font-size-body-sm)',
383
+ color: 'var(--color-text-primary)',
384
+ transition: 'var(--transition-colors)',
385
+ }}
386
+ onMouseEnter={(e) => {
387
+ e.currentTarget.style.background = 'var(--color-bg-overlay)';
388
+ }}
389
+ onMouseLeave={(e) => {
390
+ e.currentTarget.style.background = 'transparent';
391
+ }}
392
+ >
393
+ {module.icon && <span>{module.icon}</span>}
394
+ <span>{module.name}</span>
395
+ </button>
396
+ ))}
397
+ </div>
398
+ )}
399
+ </div>
400
+ </div>
401
+ )}
402
+ </div>
403
+ );
404
+ };
405
+
406
+ export default GraphCanvas;
@@ -0,0 +1,128 @@
1
+ import React from 'react';
2
+ import {
3
+ BaseEdge,
4
+ EdgeProps,
5
+ getBezierPath,
6
+ getStraightPath,
7
+ getSmoothStepPath,
8
+ getSimpleBezierPath,
9
+ EdgeLabelRenderer
10
+ } from '@xyflow/react';
11
+ import { useSettingsStore } from '../../store/settingsStore';
12
+
13
+ /**
14
+ * Phase 4: Graph Visualization & Dual Views - MessageFlowEdge Component
15
+ *
16
+ * Custom edge for Agent View showing message flow between agents.
17
+ * Features:
18
+ * - Animated edge to show active message flow
19
+ * - Label with message type and count (e.g., "Movie (3)")
20
+ * - Arrow marker at target
21
+ *
22
+ * SPECIFICATION: docs/specs/003-real-time-dashboard/PLAN.md Phase 4
23
+ */
24
+
25
+ export interface MessageFlowEdgeData {
26
+ messageType: string;
27
+ messageCount: number;
28
+ artifactIds: string[];
29
+ latestTimestamp: string;
30
+ labelOffset?: number; // Phase 11: Vertical offset to prevent label overlap
31
+ }
32
+
33
+ const MessageFlowEdge: React.FC<EdgeProps> = ({
34
+ id,
35
+ sourceX,
36
+ sourceY,
37
+ targetX,
38
+ targetY,
39
+ sourcePosition,
40
+ targetPosition,
41
+ label,
42
+ style = {},
43
+ markerEnd,
44
+ data,
45
+ }) => {
46
+ // Get edge settings from settings store
47
+ const edgeType = useSettingsStore((state) => state.graph.edgeType);
48
+ const edgeStrokeWidth = useSettingsStore((state) => state.graph.edgeStrokeWidth);
49
+ const edgeAnimation = useSettingsStore((state) => state.graph.edgeAnimation);
50
+ const showEdgeLabels = useSettingsStore((state) => state.graph.showEdgeLabels);
51
+
52
+ // Use appropriate path function based on settings
53
+ const getPath = () => {
54
+ const params = { sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition };
55
+ switch (edgeType) {
56
+ case 'straight':
57
+ return getStraightPath(params);
58
+ case 'smoothstep':
59
+ return getSmoothStepPath(params);
60
+ case 'simplebezier':
61
+ return getSimpleBezierPath(params);
62
+ case 'bezier':
63
+ default:
64
+ return getBezierPath(params);
65
+ }
66
+ };
67
+
68
+ const [edgePath, labelX, labelY] = getPath();
69
+
70
+ // Phase 11 Bug Fix: Apply label offset to prevent overlap when multiple edges exist
71
+ const edgeData = data as MessageFlowEdgeData | undefined;
72
+ const labelOffset = edgeData?.labelOffset || 0;
73
+
74
+ const [isHovered, setIsHovered] = React.useState(false);
75
+
76
+ return (
77
+ <>
78
+ <BaseEdge
79
+ id={id}
80
+ path={edgePath}
81
+ style={{
82
+ ...style,
83
+ stroke: 'var(--color-edge-message)',
84
+ strokeWidth: isHovered ? edgeStrokeWidth + 1 : edgeStrokeWidth,
85
+ animation: edgeAnimation ? 'dash 20s linear infinite' : 'none',
86
+ transition: 'var(--transition-all)',
87
+ filter: isHovered ? 'drop-shadow(0 0 4px var(--color-edge-message))' : 'none',
88
+ }}
89
+ markerEnd={markerEnd}
90
+ />
91
+ {label && showEdgeLabels && (
92
+ <EdgeLabelRenderer>
93
+ <div
94
+ style={{
95
+ position: 'absolute',
96
+ transform: `translate(-50%, -50%) translate(${labelX}px,${labelY + labelOffset}px)`,
97
+ fontSize: 'var(--font-size-caption)',
98
+ fontWeight: 'var(--font-weight-medium)',
99
+ background: 'var(--color-edge-label-bg)',
100
+ color: 'var(--color-edge-label-text)',
101
+ padding: 'var(--spacing-1) var(--spacing-2)',
102
+ borderRadius: 'var(--radius-sm)',
103
+ border: 'var(--border-width-1) solid var(--color-edge-message)',
104
+ pointerEvents: 'all',
105
+ backdropFilter: 'blur(var(--blur-sm))',
106
+ boxShadow: 'var(--shadow-sm)',
107
+ transition: 'var(--transition-all)',
108
+ }}
109
+ className="nodrag nopan"
110
+ onMouseEnter={() => setIsHovered(true)}
111
+ onMouseLeave={() => setIsHovered(false)}
112
+ >
113
+ {label}
114
+ </div>
115
+ </EdgeLabelRenderer>
116
+ )}
117
+ <style>{`
118
+ @keyframes dash {
119
+ to {
120
+ stroke-dashoffset: -100;
121
+ }
122
+ }
123
+ `}</style>
124
+ </>
125
+ );
126
+ };
127
+
128
+ export default MessageFlowEdge;
@@ -0,0 +1,62 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { ReactFlowProvider } from '@xyflow/react';
4
+ import MessageNode from './MessageNode';
5
+ import { MessageNodeData } from '../../types/graph';
6
+ import { NodeProps } from '@xyflow/react';
7
+
8
+ describe('MessageNode', () => {
9
+ const createNodeProps = (data: MessageNodeData, selected = false): NodeProps =>
10
+ ({
11
+ id: 'msg-1',
12
+ data,
13
+ selected,
14
+ type: 'message',
15
+ isConnectable: true,
16
+ dragging: false,
17
+ zIndex: 0,
18
+ selectable: true,
19
+ deletable: true,
20
+ draggable: true,
21
+ }) as unknown as NodeProps;
22
+
23
+ it('should render artifact type', () => {
24
+ const data: MessageNodeData = {
25
+ artifactType: 'Movie',
26
+ payloadPreview: '{"title": "Test Movie"}',
27
+ payload: { title: 'Test Movie' },
28
+ producedBy: 'movie',
29
+ consumedBy: ['tagline'],
30
+ timestamp: Date.now(),
31
+ };
32
+
33
+ render(
34
+ <ReactFlowProvider>
35
+ <MessageNode {...createNodeProps(data)} />
36
+ </ReactFlowProvider>
37
+ );
38
+ expect(screen.getByText('Movie')).toBeInTheDocument();
39
+ });
40
+
41
+ it('should render produced by', () => {
42
+ const data: MessageNodeData = {
43
+ artifactType: 'Movie',
44
+ payloadPreview: '{"title": "Test Movie"}',
45
+ payload: { title: 'Test Movie' },
46
+ producedBy: 'movie',
47
+ consumedBy: [],
48
+ timestamp: Date.now(),
49
+ };
50
+
51
+ render(
52
+ <ReactFlowProvider>
53
+ <MessageNode {...createNodeProps(data)} />
54
+ </ReactFlowProvider>
55
+ );
56
+ // Text is split across elements: <div>by: <span>movie</span></div>
57
+ // Use getByText with function matcher to find text across elements
58
+ expect(screen.getByText((_content, element) => {
59
+ return element?.textContent === 'by: movie';
60
+ })).toBeInTheDocument();
61
+ });
62
+ });