flock-core 0.4.542__py3-none-any.whl → 0.5.0__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 (501) hide show
  1. flock/__init__.py +12 -217
  2. flock/agent.py +1079 -0
  3. flock/api/themes.py +71 -0
  4. flock/artifacts.py +86 -0
  5. flock/cli.py +147 -0
  6. flock/components.py +189 -0
  7. flock/dashboard/__init__.py +30 -0
  8. flock/dashboard/collector.py +559 -0
  9. flock/dashboard/events.py +188 -0
  10. flock/dashboard/graph_builder.py +563 -0
  11. flock/dashboard/launcher.py +235 -0
  12. flock/dashboard/models/graph.py +156 -0
  13. flock/dashboard/service.py +991 -0
  14. flock/dashboard/static_v2/assets/index-DFRnI_mt.js +111 -0
  15. flock/dashboard/static_v2/assets/index-fPLNdmp1.css +1 -0
  16. flock/dashboard/static_v2/index.html +13 -0
  17. flock/dashboard/websocket.py +246 -0
  18. flock/engines/__init__.py +6 -0
  19. flock/engines/dspy_engine.py +932 -0
  20. flock/examples.py +131 -0
  21. flock/frontend/README.md +778 -0
  22. flock/frontend/docs/DESIGN_SYSTEM.md +1980 -0
  23. flock/frontend/index.html +12 -0
  24. flock/frontend/package-lock.json +4337 -0
  25. flock/frontend/package.json +48 -0
  26. flock/frontend/src/App.tsx +139 -0
  27. flock/frontend/src/__tests__/integration/graph-snapshot.test.tsx +647 -0
  28. flock/frontend/src/__tests__/integration/indexeddb-persistence.test.tsx +699 -0
  29. flock/frontend/src/components/common/BuildInfo.tsx +39 -0
  30. flock/frontend/src/components/common/EmptyState.module.css +115 -0
  31. flock/frontend/src/components/common/EmptyState.tsx +128 -0
  32. flock/frontend/src/components/common/ErrorBoundary.module.css +169 -0
  33. flock/frontend/src/components/common/ErrorBoundary.tsx +118 -0
  34. flock/frontend/src/components/common/KeyboardShortcutsDialog.css +251 -0
  35. flock/frontend/src/components/common/KeyboardShortcutsDialog.tsx +151 -0
  36. flock/frontend/src/components/common/LoadingSpinner.module.css +97 -0
  37. flock/frontend/src/components/common/LoadingSpinner.tsx +29 -0
  38. flock/frontend/src/components/controls/PublishControl.css +547 -0
  39. flock/frontend/src/components/controls/PublishControl.test.tsx +543 -0
  40. flock/frontend/src/components/controls/PublishControl.tsx +432 -0
  41. flock/frontend/src/components/details/DetailWindowContainer.tsx +58 -0
  42. flock/frontend/src/components/details/LiveOutputTab.test.tsx +792 -0
  43. flock/frontend/src/components/details/LiveOutputTab.tsx +220 -0
  44. flock/frontend/src/components/details/MessageDetailWindow.tsx +439 -0
  45. flock/frontend/src/components/details/MessageHistoryTab.tsx +374 -0
  46. flock/frontend/src/components/details/NodeDetailWindow.test.tsx +501 -0
  47. flock/frontend/src/components/details/NodeDetailWindow.tsx +218 -0
  48. flock/frontend/src/components/details/RunStatusTab.tsx +348 -0
  49. flock/frontend/src/components/details/tabs.test.tsx +1015 -0
  50. flock/frontend/src/components/filters/ArtifactTypeFilter.tsx +21 -0
  51. flock/frontend/src/components/filters/CorrelationIDFilter.module.css +102 -0
  52. flock/frontend/src/components/filters/CorrelationIDFilter.test.tsx +197 -0
  53. flock/frontend/src/components/filters/CorrelationIDFilter.tsx +121 -0
  54. flock/frontend/src/components/filters/FilterFlyout.module.css +104 -0
  55. flock/frontend/src/components/filters/FilterFlyout.tsx +80 -0
  56. flock/frontend/src/components/filters/FilterPills.module.css +220 -0
  57. flock/frontend/src/components/filters/FilterPills.test.tsx +189 -0
  58. flock/frontend/src/components/filters/FilterPills.tsx +143 -0
  59. flock/frontend/src/components/filters/ProducerFilter.tsx +21 -0
  60. flock/frontend/src/components/filters/SavedFiltersControl.module.css +60 -0
  61. flock/frontend/src/components/filters/SavedFiltersControl.test.tsx +158 -0
  62. flock/frontend/src/components/filters/SavedFiltersControl.tsx +159 -0
  63. flock/frontend/src/components/filters/TagFilter.tsx +21 -0
  64. flock/frontend/src/components/filters/TimeRangeFilter.module.css +115 -0
  65. flock/frontend/src/components/filters/TimeRangeFilter.test.tsx +154 -0
  66. flock/frontend/src/components/filters/TimeRangeFilter.tsx +110 -0
  67. flock/frontend/src/components/filters/VisibilityFilter.tsx +21 -0
  68. flock/frontend/src/components/graph/AgentNode.test.tsx +77 -0
  69. flock/frontend/src/components/graph/AgentNode.tsx +324 -0
  70. flock/frontend/src/components/graph/GraphCanvas.tsx +613 -0
  71. flock/frontend/src/components/graph/MessageFlowEdge.tsx +128 -0
  72. flock/frontend/src/components/graph/MessageNode.test.tsx +64 -0
  73. flock/frontend/src/components/graph/MessageNode.tsx +129 -0
  74. flock/frontend/src/components/graph/MiniMap.tsx +47 -0
  75. flock/frontend/src/components/graph/TransformEdge.tsx +123 -0
  76. flock/frontend/src/components/layout/DashboardLayout.css +420 -0
  77. flock/frontend/src/components/layout/DashboardLayout.tsx +287 -0
  78. flock/frontend/src/components/layout/Header.module.css +88 -0
  79. flock/frontend/src/components/layout/Header.tsx +52 -0
  80. flock/frontend/src/components/modules/HistoricalArtifactsModule.module.css +288 -0
  81. flock/frontend/src/components/modules/HistoricalArtifactsModule.tsx +450 -0
  82. flock/frontend/src/components/modules/HistoricalArtifactsModuleWrapper.tsx +13 -0
  83. flock/frontend/src/components/modules/JsonAttributeRenderer.tsx +140 -0
  84. flock/frontend/src/components/modules/ModuleRegistry.test.ts +333 -0
  85. flock/frontend/src/components/modules/ModuleRegistry.ts +93 -0
  86. flock/frontend/src/components/modules/ModuleWindow.tsx +223 -0
  87. flock/frontend/src/components/modules/TraceModuleJaeger.tsx +1971 -0
  88. flock/frontend/src/components/modules/TraceModuleJaegerWrapper.tsx +13 -0
  89. flock/frontend/src/components/modules/registerModules.ts +29 -0
  90. flock/frontend/src/components/settings/AdvancedSettings.tsx +175 -0
  91. flock/frontend/src/components/settings/AppearanceSettings.tsx +185 -0
  92. flock/frontend/src/components/settings/GraphSettings.tsx +110 -0
  93. flock/frontend/src/components/settings/MultiSelect.tsx +235 -0
  94. flock/frontend/src/components/settings/SettingsPanel.css +327 -0
  95. flock/frontend/src/components/settings/SettingsPanel.tsx +131 -0
  96. flock/frontend/src/components/settings/ThemeSelector.tsx +298 -0
  97. flock/frontend/src/components/settings/TracingSettings.tsx +404 -0
  98. flock/frontend/src/hooks/useKeyboardShortcuts.ts +148 -0
  99. flock/frontend/src/hooks/useModulePersistence.test.ts +442 -0
  100. flock/frontend/src/hooks/useModulePersistence.ts +154 -0
  101. flock/frontend/src/hooks/useModules.ts +157 -0
  102. flock/frontend/src/hooks/usePersistence.ts +141 -0
  103. flock/frontend/src/main.tsx +13 -0
  104. flock/frontend/src/services/api.ts +337 -0
  105. flock/frontend/src/services/graphService.test.ts +330 -0
  106. flock/frontend/src/services/graphService.ts +75 -0
  107. flock/frontend/src/services/indexeddb.test.ts +793 -0
  108. flock/frontend/src/services/indexeddb.ts +848 -0
  109. flock/frontend/src/services/layout.test.ts +437 -0
  110. flock/frontend/src/services/layout.ts +357 -0
  111. flock/frontend/src/services/themeApplicator.ts +140 -0
  112. flock/frontend/src/services/themeService.ts +77 -0
  113. flock/frontend/src/services/websocket.ts +650 -0
  114. flock/frontend/src/store/filterStore.test.ts +250 -0
  115. flock/frontend/src/store/filterStore.ts +272 -0
  116. flock/frontend/src/store/graphStore.test.ts +570 -0
  117. flock/frontend/src/store/graphStore.ts +462 -0
  118. flock/frontend/src/store/moduleStore.test.ts +253 -0
  119. flock/frontend/src/store/moduleStore.ts +75 -0
  120. flock/frontend/src/store/settingsStore.ts +188 -0
  121. flock/frontend/src/store/streamStore.ts +68 -0
  122. flock/frontend/src/store/uiStore.test.ts +54 -0
  123. flock/frontend/src/store/uiStore.ts +122 -0
  124. flock/frontend/src/store/wsStore.ts +34 -0
  125. flock/frontend/src/styles/index.css +15 -0
  126. flock/frontend/src/styles/scrollbar.css +47 -0
  127. flock/frontend/src/styles/variables.css +488 -0
  128. flock/frontend/src/test/setup.ts +1 -0
  129. flock/frontend/src/types/filters.ts +47 -0
  130. flock/frontend/src/types/graph.ts +95 -0
  131. flock/frontend/src/types/modules.ts +10 -0
  132. flock/frontend/src/types/theme.ts +55 -0
  133. flock/frontend/src/utils/artifacts.ts +24 -0
  134. flock/frontend/src/utils/mockData.ts +98 -0
  135. flock/frontend/src/utils/performance.ts +16 -0
  136. flock/frontend/src/vite-env.d.ts +17 -0
  137. flock/frontend/tsconfig.json +27 -0
  138. flock/frontend/tsconfig.node.json +11 -0
  139. flock/frontend/vite.config.ts +25 -0
  140. flock/frontend/vitest.config.ts +11 -0
  141. flock/{core/util → helper}/cli_helper.py +9 -5
  142. flock/{core/logging → logging}/__init__.py +2 -3
  143. flock/logging/auto_trace.py +159 -0
  144. flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
  145. flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
  146. flock/{core/logging → logging}/formatters/themed_formatter.py +69 -107
  147. flock/{core/logging → logging}/logging.py +78 -61
  148. flock/{core/logging → logging}/telemetry.py +66 -26
  149. flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
  150. flock/logging/telemetry_exporter/duckdb_exporter.py +216 -0
  151. flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +13 -10
  152. flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
  153. flock/logging/trace_and_logged.py +304 -0
  154. flock/mcp/__init__.py +91 -0
  155. flock/{core/mcp/mcp_client.py → mcp/client.py} +131 -158
  156. flock/{core/mcp/mcp_config.py → mcp/config.py} +86 -132
  157. flock/mcp/manager.py +286 -0
  158. flock/mcp/servers/sse/__init__.py +1 -1
  159. flock/mcp/servers/sse/flock_sse_server.py +16 -58
  160. flock/mcp/servers/stdio/__init__.py +1 -1
  161. flock/mcp/servers/stdio/flock_stdio_server.py +13 -53
  162. flock/mcp/servers/streamable_http/flock_streamable_http_server.py +22 -67
  163. flock/mcp/servers/websockets/flock_websocket_server.py +12 -45
  164. flock/{core/mcp/flock_mcp_tool_base.py → mcp/tool.py} +24 -78
  165. flock/mcp/types/__init__.py +42 -0
  166. flock/{core/mcp → mcp}/types/callbacks.py +12 -15
  167. flock/{core/mcp → mcp}/types/factories.py +7 -6
  168. flock/{core/mcp → mcp}/types/handlers.py +13 -18
  169. flock/{core/mcp → mcp}/types/types.py +70 -74
  170. flock/{core/mcp → mcp}/util/helpers.py +3 -3
  171. flock/orchestrator.py +970 -0
  172. flock/registry.py +148 -0
  173. flock/runtime.py +262 -0
  174. flock/service.py +277 -0
  175. flock/store.py +1214 -0
  176. flock/subscription.py +111 -0
  177. flock/themes/andromeda.toml +1 -1
  178. flock/themes/apple-system-colors.toml +1 -1
  179. flock/themes/arcoiris.toml +1 -1
  180. flock/themes/atomonelight.toml +1 -1
  181. flock/themes/ayu copy.toml +1 -1
  182. flock/themes/ayu-light.toml +1 -1
  183. flock/themes/belafonte-day.toml +1 -1
  184. flock/themes/belafonte-night.toml +1 -1
  185. flock/themes/blulocodark.toml +1 -1
  186. flock/themes/breeze.toml +1 -1
  187. flock/themes/broadcast.toml +1 -1
  188. flock/themes/brogrammer.toml +1 -1
  189. flock/themes/builtin-dark.toml +1 -1
  190. flock/themes/builtin-pastel-dark.toml +1 -1
  191. flock/themes/catppuccin-latte.toml +1 -1
  192. flock/themes/catppuccin-macchiato.toml +1 -1
  193. flock/themes/catppuccin-mocha.toml +1 -1
  194. flock/themes/cga.toml +1 -1
  195. flock/themes/chalk.toml +1 -1
  196. flock/themes/ciapre.toml +1 -1
  197. flock/themes/coffee-theme.toml +1 -1
  198. flock/themes/cyberpunkscarletprotocol.toml +1 -1
  199. flock/themes/dark+.toml +1 -1
  200. flock/themes/darkermatrix.toml +1 -1
  201. flock/themes/darkmatrix.toml +2 -2
  202. flock/themes/darkside.toml +1 -1
  203. flock/themes/deep.toml +2 -2
  204. flock/themes/desert.toml +1 -1
  205. flock/themes/django.toml +1 -1
  206. flock/themes/djangosmooth.toml +1 -1
  207. flock/themes/doomone.toml +1 -1
  208. flock/themes/dotgov.toml +1 -1
  209. flock/themes/dracula+.toml +1 -1
  210. flock/themes/duckbones.toml +1 -1
  211. flock/themes/encom.toml +1 -1
  212. flock/themes/espresso.toml +1 -1
  213. flock/themes/everblush.toml +1 -1
  214. flock/themes/fairyfloss.toml +1 -1
  215. flock/themes/fideloper.toml +1 -1
  216. flock/themes/fishtank.toml +1 -1
  217. flock/themes/flexoki-light.toml +1 -1
  218. flock/themes/floraverse.toml +1 -1
  219. flock/themes/framer.toml +1 -1
  220. flock/themes/galizur.toml +1 -1
  221. flock/themes/github.toml +1 -1
  222. flock/themes/grass.toml +1 -1
  223. flock/themes/grey-green.toml +1 -1
  224. flock/themes/gruvboxlight.toml +1 -1
  225. flock/themes/guezwhoz.toml +1 -1
  226. flock/themes/harper.toml +1 -1
  227. flock/themes/hax0r-blue.toml +1 -1
  228. flock/themes/hopscotch.256.toml +1 -1
  229. flock/themes/ic-green-ppl.toml +1 -1
  230. flock/themes/iceberg-dark.toml +1 -1
  231. flock/themes/japanesque.toml +1 -1
  232. flock/themes/jubi.toml +1 -1
  233. flock/themes/kibble.toml +1 -1
  234. flock/themes/kolorit.toml +1 -1
  235. flock/themes/kurokula.toml +1 -1
  236. flock/themes/materialdesigncolors.toml +1 -1
  237. flock/themes/matrix.toml +1 -1
  238. flock/themes/mellifluous.toml +1 -1
  239. flock/themes/midnight-in-mojave.toml +1 -1
  240. flock/themes/monokai-remastered.toml +1 -1
  241. flock/themes/monokai-soda.toml +1 -1
  242. flock/themes/neon.toml +1 -1
  243. flock/themes/neopolitan.toml +5 -5
  244. flock/themes/nord-light.toml +1 -1
  245. flock/themes/ocean.toml +1 -1
  246. flock/themes/onehalfdark.toml +1 -1
  247. flock/themes/onehalflight.toml +1 -1
  248. flock/themes/palenighthc.toml +1 -1
  249. flock/themes/paulmillr.toml +1 -1
  250. flock/themes/pencildark.toml +1 -1
  251. flock/themes/pnevma.toml +1 -1
  252. flock/themes/purple-rain.toml +1 -1
  253. flock/themes/purplepeter.toml +1 -1
  254. flock/themes/raycast-dark.toml +1 -1
  255. flock/themes/red-sands.toml +1 -1
  256. flock/themes/relaxed.toml +1 -1
  257. flock/themes/retro.toml +1 -1
  258. flock/themes/rose-pine.toml +1 -1
  259. flock/themes/royal.toml +1 -1
  260. flock/themes/ryuuko.toml +1 -1
  261. flock/themes/sakura.toml +1 -1
  262. flock/themes/scarlet-protocol.toml +1 -1
  263. flock/themes/seoulbones-dark.toml +1 -1
  264. flock/themes/shades-of-purple.toml +1 -1
  265. flock/themes/smyck.toml +1 -1
  266. flock/themes/softserver.toml +1 -1
  267. flock/themes/solarized-darcula.toml +1 -1
  268. flock/themes/square.toml +1 -1
  269. flock/themes/sugarplum.toml +1 -1
  270. flock/themes/thayer-bright.toml +1 -1
  271. flock/themes/tokyonight.toml +1 -1
  272. flock/themes/tomorrow.toml +1 -1
  273. flock/themes/ubuntu.toml +1 -1
  274. flock/themes/ultradark.toml +1 -1
  275. flock/themes/ultraviolent.toml +1 -1
  276. flock/themes/unikitty.toml +1 -1
  277. flock/themes/urple.toml +1 -1
  278. flock/themes/vesper.toml +1 -1
  279. flock/themes/vimbones.toml +1 -1
  280. flock/themes/wildcherry.toml +1 -1
  281. flock/themes/wilmersdorf.toml +1 -1
  282. flock/themes/wryan.toml +1 -1
  283. flock/themes/xcodedarkhc.toml +1 -1
  284. flock/themes/xcodelight.toml +1 -1
  285. flock/themes/zenbones-light.toml +1 -1
  286. flock/themes/zenwritten-dark.toml +1 -1
  287. flock/utilities.py +301 -0
  288. flock/utility/output_utility_component.py +226 -0
  289. flock/visibility.py +107 -0
  290. flock_core-0.5.0.dist-info/METADATA +964 -0
  291. flock_core-0.5.0.dist-info/RECORD +525 -0
  292. flock_core-0.5.0.dist-info/entry_points.txt +2 -0
  293. {flock_core-0.4.542.dist-info → flock_core-0.5.0.dist-info}/licenses/LICENSE +1 -1
  294. flock/adapter/__init__.py +0 -14
  295. flock/adapter/azure_adapter.py +0 -68
  296. flock/adapter/chroma_adapter.py +0 -73
  297. flock/adapter/faiss_adapter.py +0 -97
  298. flock/adapter/pinecone_adapter.py +0 -51
  299. flock/adapter/vector_base.py +0 -47
  300. flock/cli/assets/release_notes.md +0 -140
  301. flock/cli/config.py +0 -8
  302. flock/cli/constants.py +0 -36
  303. flock/cli/create_agent.py +0 -1
  304. flock/cli/create_flock.py +0 -280
  305. flock/cli/execute_flock.py +0 -620
  306. flock/cli/load_agent.py +0 -1
  307. flock/cli/load_examples.py +0 -1
  308. flock/cli/load_flock.py +0 -192
  309. flock/cli/load_release_notes.py +0 -20
  310. flock/cli/loaded_flock_cli.py +0 -254
  311. flock/cli/manage_agents.py +0 -459
  312. flock/cli/registry_management.py +0 -889
  313. flock/cli/runner.py +0 -41
  314. flock/cli/settings.py +0 -857
  315. flock/cli/utils.py +0 -135
  316. flock/cli/view_results.py +0 -29
  317. flock/cli/yaml_editor.py +0 -396
  318. flock/config.py +0 -56
  319. flock/core/__init__.py +0 -44
  320. flock/core/api/__init__.py +0 -10
  321. flock/core/api/custom_endpoint.py +0 -45
  322. flock/core/api/endpoints.py +0 -262
  323. flock/core/api/main.py +0 -162
  324. flock/core/api/models.py +0 -101
  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/config/flock_agent_config.py +0 -11
  329. flock/core/config/scheduled_agent_config.py +0 -40
  330. flock/core/context/context.py +0 -214
  331. flock/core/context/context_manager.py +0 -40
  332. flock/core/context/context_vars.py +0 -11
  333. flock/core/evaluation/utils.py +0 -395
  334. flock/core/execution/batch_executor.py +0 -369
  335. flock/core/execution/evaluation_executor.py +0 -438
  336. flock/core/execution/local_executor.py +0 -31
  337. flock/core/execution/opik_executor.py +0 -103
  338. flock/core/execution/temporal_executor.py +0 -166
  339. flock/core/flock.py +0 -1003
  340. flock/core/flock_agent.py +0 -1258
  341. flock/core/flock_evaluator.py +0 -60
  342. flock/core/flock_factory.py +0 -513
  343. flock/core/flock_module.py +0 -207
  344. flock/core/flock_registry.py +0 -702
  345. flock/core/flock_router.py +0 -83
  346. flock/core/flock_scheduler.py +0 -166
  347. flock/core/flock_server_manager.py +0 -136
  348. flock/core/interpreter/python_interpreter.py +0 -689
  349. flock/core/logging/live_capture.py +0 -137
  350. flock/core/logging/trace_and_logged.py +0 -59
  351. flock/core/mcp/__init__.py +0 -1
  352. flock/core/mcp/flock_mcp_server.py +0 -640
  353. flock/core/mcp/mcp_client_manager.py +0 -201
  354. flock/core/mcp/types/__init__.py +0 -1
  355. flock/core/mixin/dspy_integration.py +0 -445
  356. flock/core/mixin/prompt_parser.py +0 -125
  357. flock/core/serialization/__init__.py +0 -13
  358. flock/core/serialization/callable_registry.py +0 -52
  359. flock/core/serialization/flock_serializer.py +0 -854
  360. flock/core/serialization/json_encoder.py +0 -41
  361. flock/core/serialization/secure_serializer.py +0 -175
  362. flock/core/serialization/serializable.py +0 -342
  363. flock/core/serialization/serialization_utils.py +0 -409
  364. flock/core/util/file_path_utils.py +0 -223
  365. flock/core/util/hydrator.py +0 -309
  366. flock/core/util/input_resolver.py +0 -141
  367. flock/core/util/loader.py +0 -59
  368. flock/core/util/splitter.py +0 -219
  369. flock/di.py +0 -41
  370. flock/evaluators/__init__.py +0 -1
  371. flock/evaluators/declarative/__init__.py +0 -1
  372. flock/evaluators/declarative/declarative_evaluator.py +0 -217
  373. flock/evaluators/memory/memory_evaluator.py +0 -90
  374. flock/evaluators/test/test_case_evaluator.py +0 -38
  375. flock/evaluators/zep/zep_evaluator.py +0 -59
  376. flock/modules/__init__.py +0 -1
  377. flock/modules/assertion/__init__.py +0 -1
  378. flock/modules/assertion/assertion_module.py +0 -286
  379. flock/modules/callback/__init__.py +0 -1
  380. flock/modules/callback/callback_module.py +0 -91
  381. flock/modules/enterprise_memory/README.md +0 -99
  382. flock/modules/enterprise_memory/enterprise_memory_module.py +0 -526
  383. flock/modules/mem0/__init__.py +0 -1
  384. flock/modules/mem0/mem0_module.py +0 -126
  385. flock/modules/mem0_async/__init__.py +0 -1
  386. flock/modules/mem0_async/async_mem0_module.py +0 -126
  387. flock/modules/memory/__init__.py +0 -1
  388. flock/modules/memory/memory_module.py +0 -429
  389. flock/modules/memory/memory_parser.py +0 -125
  390. flock/modules/memory/memory_storage.py +0 -736
  391. flock/modules/output/__init__.py +0 -1
  392. flock/modules/output/output_module.py +0 -196
  393. flock/modules/performance/__init__.py +0 -1
  394. flock/modules/performance/metrics_module.py +0 -678
  395. flock/modules/zep/__init__.py +0 -1
  396. flock/modules/zep/zep_module.py +0 -192
  397. flock/platform/docker_tools.py +0 -49
  398. flock/platform/jaeger_install.py +0 -86
  399. flock/routers/__init__.py +0 -1
  400. flock/routers/agent/__init__.py +0 -1
  401. flock/routers/agent/agent_router.py +0 -236
  402. flock/routers/agent/handoff_agent.py +0 -58
  403. flock/routers/conditional/conditional_router.py +0 -486
  404. flock/routers/default/__init__.py +0 -1
  405. flock/routers/default/default_router.py +0 -80
  406. flock/routers/feedback/feedback_router.py +0 -114
  407. flock/routers/list_generator/list_generator_router.py +0 -166
  408. flock/routers/llm/__init__.py +0 -1
  409. flock/routers/llm/llm_router.py +0 -365
  410. flock/tools/__init__.py +0 -0
  411. flock/tools/azure_tools.py +0 -781
  412. flock/tools/code_tools.py +0 -167
  413. flock/tools/file_tools.py +0 -149
  414. flock/tools/github_tools.py +0 -157
  415. flock/tools/markdown_tools.py +0 -205
  416. flock/tools/system_tools.py +0 -9
  417. flock/tools/text_tools.py +0 -810
  418. flock/tools/web_tools.py +0 -92
  419. flock/tools/zendesk_tools.py +0 -501
  420. flock/webapp/__init__.py +0 -1
  421. flock/webapp/app/__init__.py +0 -0
  422. flock/webapp/app/api/__init__.py +0 -0
  423. flock/webapp/app/api/agent_management.py +0 -237
  424. flock/webapp/app/api/execution.py +0 -503
  425. flock/webapp/app/api/flock_management.py +0 -125
  426. flock/webapp/app/api/registry_viewer.py +0 -29
  427. flock/webapp/app/chat.py +0 -662
  428. flock/webapp/app/config.py +0 -104
  429. flock/webapp/app/dependencies.py +0 -117
  430. flock/webapp/app/main.py +0 -1086
  431. flock/webapp/app/middleware.py +0 -113
  432. flock/webapp/app/models_ui.py +0 -7
  433. flock/webapp/app/services/__init__.py +0 -0
  434. flock/webapp/app/services/feedback_file_service.py +0 -363
  435. flock/webapp/app/services/flock_service.py +0 -345
  436. flock/webapp/app/services/sharing_models.py +0 -81
  437. flock/webapp/app/services/sharing_store.py +0 -597
  438. flock/webapp/app/templates/theme_mapper.html +0 -326
  439. flock/webapp/app/theme_mapper.py +0 -811
  440. flock/webapp/app/utils.py +0 -85
  441. flock/webapp/run.py +0 -219
  442. flock/webapp/static/css/chat.css +0 -301
  443. flock/webapp/static/css/components.css +0 -167
  444. flock/webapp/static/css/header.css +0 -39
  445. flock/webapp/static/css/layout.css +0 -281
  446. flock/webapp/static/css/sidebar.css +0 -127
  447. flock/webapp/static/css/two-pane.css +0 -48
  448. flock/webapp/templates/base.html +0 -389
  449. flock/webapp/templates/chat.html +0 -152
  450. flock/webapp/templates/chat_settings.html +0 -19
  451. flock/webapp/templates/flock_editor.html +0 -16
  452. flock/webapp/templates/index.html +0 -12
  453. flock/webapp/templates/partials/_agent_detail_form.html +0 -93
  454. flock/webapp/templates/partials/_agent_list.html +0 -18
  455. flock/webapp/templates/partials/_agent_manager_view.html +0 -51
  456. flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
  457. flock/webapp/templates/partials/_chat_container.html +0 -15
  458. flock/webapp/templates/partials/_chat_messages.html +0 -57
  459. flock/webapp/templates/partials/_chat_settings_form.html +0 -85
  460. flock/webapp/templates/partials/_create_flock_form.html +0 -50
  461. flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
  462. flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
  463. flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
  464. flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
  465. flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
  466. flock/webapp/templates/partials/_env_vars_table.html +0 -23
  467. flock/webapp/templates/partials/_execution_form.html +0 -127
  468. flock/webapp/templates/partials/_execution_view_container.html +0 -28
  469. flock/webapp/templates/partials/_flock_file_list.html +0 -23
  470. flock/webapp/templates/partials/_flock_properties_form.html +0 -52
  471. flock/webapp/templates/partials/_flock_upload_form.html +0 -16
  472. flock/webapp/templates/partials/_header_flock_status.html +0 -5
  473. flock/webapp/templates/partials/_live_logs.html +0 -13
  474. flock/webapp/templates/partials/_load_manager_view.html +0 -49
  475. flock/webapp/templates/partials/_registry_table.html +0 -25
  476. flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
  477. flock/webapp/templates/partials/_results_display.html +0 -78
  478. flock/webapp/templates/partials/_settings_env_content.html +0 -9
  479. flock/webapp/templates/partials/_settings_theme_content.html +0 -14
  480. flock/webapp/templates/partials/_settings_view.html +0 -36
  481. flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
  482. flock/webapp/templates/partials/_share_link_snippet.html +0 -35
  483. flock/webapp/templates/partials/_sidebar.html +0 -74
  484. flock/webapp/templates/partials/_structured_data_view.html +0 -40
  485. flock/webapp/templates/partials/_theme_preview.html +0 -36
  486. flock/webapp/templates/registry_viewer.html +0 -84
  487. flock/webapp/templates/shared_run_page.html +0 -140
  488. flock/workflow/__init__.py +0 -0
  489. flock/workflow/activities.py +0 -237
  490. flock/workflow/agent_activities.py +0 -24
  491. flock/workflow/agent_execution_activity.py +0 -240
  492. flock/workflow/flock_workflow.py +0 -225
  493. flock/workflow/temporal_config.py +0 -96
  494. flock/workflow/temporal_setup.py +0 -60
  495. flock_core-0.4.542.dist-info/METADATA +0 -676
  496. flock_core-0.4.542.dist-info/RECORD +0 -572
  497. flock_core-0.4.542.dist-info/entry_points.txt +0 -2
  498. /flock/{core/logging → logging}/formatters/themes.py +0 -0
  499. /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
  500. /flock/{core/mcp → mcp}/util/__init__.py +0 -0
  501. {flock_core-0.4.542.dist-info → flock_core-0.5.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,501 @@
1
+ /**
2
+ * Unit tests for NodeDetailWindow component.
3
+ *
4
+ * Tests verify window opening, dragging, resizing, closing, multiple window support,
5
+ * and state persistence for detail windows.
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
9
+ import { render, screen, fireEvent } from '@testing-library/react';
10
+ import { useUIStore } from '../../store/uiStore';
11
+
12
+ // Mock component - will be replaced by actual implementation
13
+ const MockNodeDetailWindow = ({ nodeId }: { nodeId: string }) => {
14
+ const window = useUIStore((state) => state.detailWindows.get(nodeId));
15
+ const updateDetailWindow = useUIStore((state) => state.updateDetailWindow);
16
+ const closeDetailWindow = useUIStore((state) => state.closeDetailWindow);
17
+
18
+ if (!window) return null;
19
+
20
+ const handleDragStart = (e: React.MouseEvent) => {
21
+ const startX = e.clientX - window.position.x;
22
+ const startY = e.clientY - window.position.y;
23
+
24
+ const handleDrag = (moveEvent: MouseEvent) => {
25
+ updateDetailWindow(nodeId, {
26
+ position: {
27
+ x: moveEvent.clientX - startX,
28
+ y: moveEvent.clientY - startY,
29
+ },
30
+ });
31
+ };
32
+
33
+ const handleDragEnd = () => {
34
+ document.removeEventListener('mousemove', handleDrag);
35
+ document.removeEventListener('mouseup', handleDragEnd);
36
+ };
37
+
38
+ document.addEventListener('mousemove', handleDrag);
39
+ document.addEventListener('mouseup', handleDragEnd);
40
+ };
41
+
42
+ const handleResize = (e: React.MouseEvent) => {
43
+ e.stopPropagation();
44
+ const startWidth = window.size.width;
45
+ const startHeight = window.size.height;
46
+ const startX = e.clientX;
47
+ const startY = e.clientY;
48
+
49
+ const handleResizeMove = (moveEvent: MouseEvent) => {
50
+ const deltaX = moveEvent.clientX - startX;
51
+ const deltaY = moveEvent.clientY - startY;
52
+
53
+ updateDetailWindow(nodeId, {
54
+ size: {
55
+ width: Math.max(400, startWidth + deltaX),
56
+ height: Math.max(300, startHeight + deltaY),
57
+ },
58
+ });
59
+ };
60
+
61
+ const handleResizeEnd = () => {
62
+ document.removeEventListener('mousemove', handleResizeMove);
63
+ document.removeEventListener('mouseup', handleResizeEnd);
64
+ };
65
+
66
+ document.addEventListener('mousemove', handleResizeMove);
67
+ document.addEventListener('mouseup', handleResizeEnd);
68
+ };
69
+
70
+ return (
71
+ <div
72
+ data-testid={`detail-window-${nodeId}`}
73
+ style={{
74
+ position: 'absolute',
75
+ left: window.position.x,
76
+ top: window.position.y,
77
+ width: window.size.width,
78
+ height: window.size.height,
79
+ }}
80
+ >
81
+ <div
82
+ data-testid={`window-header-${nodeId}`}
83
+ onMouseDown={handleDragStart}
84
+ style={{ cursor: 'move', padding: '8px', background: '#333' }}
85
+ >
86
+ <span>Node: {nodeId}</span>
87
+ <button
88
+ data-testid={`close-button-${nodeId}`}
89
+ onClick={() => closeDetailWindow(nodeId)}
90
+ >
91
+ Close
92
+ </button>
93
+ </div>
94
+ <div data-testid={`window-content-${nodeId}`}>Content</div>
95
+ <div
96
+ data-testid={`resize-handle-${nodeId}`}
97
+ onMouseDown={handleResize}
98
+ style={{
99
+ position: 'absolute',
100
+ bottom: 0,
101
+ right: 0,
102
+ width: '10px',
103
+ height: '10px',
104
+ cursor: 'nwse-resize',
105
+ }}
106
+ />
107
+ </div>
108
+ );
109
+ };
110
+
111
+ describe('NodeDetailWindow', () => {
112
+ beforeEach(() => {
113
+ // Reset UI store before each test
114
+ useUIStore.setState({
115
+ mode: 'agent',
116
+ selectedNodeIds: new Set(),
117
+ detailWindows: new Map(),
118
+ defaultTab: 'liveOutput',
119
+ layoutDirection: 'TB',
120
+ autoLayoutEnabled: true,
121
+ });
122
+ });
123
+
124
+ afterEach(() => {
125
+ // Clean up any open windows
126
+ useUIStore.setState({ detailWindows: new Map() });
127
+ });
128
+
129
+ describe('Window Opening', () => {
130
+ it('should open window when openDetailWindow is called', () => {
131
+ const { rerender } = render(<MockNodeDetailWindow nodeId="agent-1" />);
132
+
133
+ // Window should not exist initially
134
+ expect(screen.queryByTestId('detail-window-agent-1')).not.toBeInTheDocument();
135
+
136
+ // Open window
137
+ useUIStore.getState().openDetailWindow('agent-1');
138
+ rerender(<MockNodeDetailWindow nodeId="agent-1" />);
139
+
140
+ // Window should now be visible
141
+ expect(screen.getByTestId('detail-window-agent-1')).toBeInTheDocument();
142
+ expect(screen.getByText('Node: agent-1')).toBeInTheDocument();
143
+ });
144
+
145
+ it('should open window with default position and size', () => {
146
+ useUIStore.getState().openDetailWindow('agent-1');
147
+ render(<MockNodeDetailWindow nodeId="agent-1" />);
148
+
149
+ const window = useUIStore.getState().detailWindows.get('agent-1');
150
+ expect(window).toBeDefined();
151
+ expect(window?.position).toEqual({ x: 100, y: 100 });
152
+ expect(window?.size).toEqual({ width: 600, height: 400 });
153
+ });
154
+
155
+ it('should open window with staggered position for multiple windows', () => {
156
+ useUIStore.getState().openDetailWindow('agent-1');
157
+ useUIStore.getState().openDetailWindow('agent-2');
158
+ useUIStore.getState().openDetailWindow('agent-3');
159
+
160
+ const window1 = useUIStore.getState().detailWindows.get('agent-1');
161
+ const window2 = useUIStore.getState().detailWindows.get('agent-2');
162
+ const window3 = useUIStore.getState().detailWindows.get('agent-3');
163
+
164
+ expect(window1?.position).toEqual({ x: 100, y: 100 });
165
+ expect(window2?.position).toEqual({ x: 120, y: 120 });
166
+ expect(window3?.position).toEqual({ x: 140, y: 140 });
167
+ });
168
+
169
+ it('should use defaultTab preference when opening window', () => {
170
+ useUIStore.setState({ defaultTab: 'messageHistory' });
171
+ useUIStore.getState().openDetailWindow('agent-1');
172
+
173
+ const window = useUIStore.getState().detailWindows.get('agent-1');
174
+ expect(window?.activeTab).toBe('messageHistory');
175
+ });
176
+
177
+ it('should not create duplicate window if already open', () => {
178
+ useUIStore.getState().openDetailWindow('agent-1');
179
+ const window1 = useUIStore.getState().detailWindows.get('agent-1');
180
+
181
+ useUIStore.getState().openDetailWindow('agent-1');
182
+ const window2 = useUIStore.getState().detailWindows.get('agent-1');
183
+
184
+ expect(window1).toBe(window2);
185
+ expect(useUIStore.getState().detailWindows.size).toBe(1);
186
+ });
187
+ });
188
+
189
+ describe('Window Dragging', () => {
190
+ it('should update window position when dragged', () => {
191
+ useUIStore.getState().openDetailWindow('agent-1');
192
+ render(<MockNodeDetailWindow nodeId="agent-1" />);
193
+
194
+ const header = screen.getByTestId('window-header-agent-1');
195
+ const initialWindow = useUIStore.getState().detailWindows.get('agent-1')!;
196
+
197
+ // Simulate drag
198
+ fireEvent.mouseDown(header, { clientX: 150, clientY: 150 });
199
+ fireEvent.mouseMove(document, { clientX: 250, clientY: 250 });
200
+ fireEvent.mouseUp(document);
201
+
202
+ const updatedWindow = useUIStore.getState().detailWindows.get('agent-1')!;
203
+ expect(updatedWindow.position.x).toBeGreaterThan(initialWindow.position.x);
204
+ expect(updatedWindow.position.y).toBeGreaterThan(initialWindow.position.y);
205
+ });
206
+
207
+ it('should allow dragging window to different positions', () => {
208
+ useUIStore.getState().openDetailWindow('agent-1');
209
+ render(<MockNodeDetailWindow nodeId="agent-1" />);
210
+
211
+ const header = screen.getByTestId('window-header-agent-1');
212
+
213
+ // First drag
214
+ fireEvent.mouseDown(header, { clientX: 100, clientY: 100 });
215
+ fireEvent.mouseMove(document, { clientX: 200, clientY: 150 });
216
+ fireEvent.mouseUp(document);
217
+
218
+ const position1 = useUIStore.getState().detailWindows.get('agent-1')!.position;
219
+
220
+ // Second drag
221
+ fireEvent.mouseDown(header, { clientX: position1.x + 50, clientY: position1.y + 50 });
222
+ fireEvent.mouseMove(document, { clientX: position1.x + 150, clientY: position1.y + 100 });
223
+ fireEvent.mouseUp(document);
224
+
225
+ const position2 = useUIStore.getState().detailWindows.get('agent-1')!.position;
226
+
227
+ expect(position2.x).toBeGreaterThan(position1.x);
228
+ expect(position2.y).toBeGreaterThan(position1.y);
229
+ });
230
+
231
+ it('should have drag cursor on header', () => {
232
+ useUIStore.getState().openDetailWindow('agent-1');
233
+ render(<MockNodeDetailWindow nodeId="agent-1" />);
234
+
235
+ const header = screen.getByTestId('window-header-agent-1');
236
+ expect(header).toHaveStyle({ cursor: 'move' });
237
+ });
238
+ });
239
+
240
+ describe('Window Resizing', () => {
241
+ it('should update window size when resized', () => {
242
+ useUIStore.getState().openDetailWindow('agent-1');
243
+ render(<MockNodeDetailWindow nodeId="agent-1" />);
244
+
245
+ const resizeHandle = screen.getByTestId('resize-handle-agent-1');
246
+ const initialWindow = useUIStore.getState().detailWindows.get('agent-1')!;
247
+
248
+ // Simulate resize
249
+ fireEvent.mouseDown(resizeHandle, { clientX: 700, clientY: 500 });
250
+ fireEvent.mouseMove(document, { clientX: 800, clientY: 600 });
251
+ fireEvent.mouseUp(document);
252
+
253
+ const updatedWindow = useUIStore.getState().detailWindows.get('agent-1')!;
254
+ expect(updatedWindow.size.width).toBeGreaterThan(initialWindow.size.width);
255
+ expect(updatedWindow.size.height).toBeGreaterThan(initialWindow.size.height);
256
+ });
257
+
258
+ it('should enforce minimum window size', () => {
259
+ useUIStore.getState().openDetailWindow('agent-1');
260
+ render(<MockNodeDetailWindow nodeId="agent-1" />);
261
+
262
+ const resizeHandle = screen.getByTestId('resize-handle-agent-1');
263
+
264
+ // Try to resize smaller than minimum (400x300)
265
+ fireEvent.mouseDown(resizeHandle, { clientX: 700, clientY: 500 });
266
+ fireEvent.mouseMove(document, { clientX: 200, clientY: 200 }); // Very small
267
+ fireEvent.mouseUp(document);
268
+
269
+ const window = useUIStore.getState().detailWindows.get('agent-1')!;
270
+ expect(window.size.width).toBeGreaterThanOrEqual(400);
271
+ expect(window.size.height).toBeGreaterThanOrEqual(300);
272
+ });
273
+
274
+ it('should have resize cursor on resize handle', () => {
275
+ useUIStore.getState().openDetailWindow('agent-1');
276
+ render(<MockNodeDetailWindow nodeId="agent-1" />);
277
+
278
+ const resizeHandle = screen.getByTestId('resize-handle-agent-1');
279
+ expect(resizeHandle).toHaveStyle({ cursor: 'nwse-resize' });
280
+ });
281
+ });
282
+
283
+ describe('Window Closing', () => {
284
+ it('should close window when close button is clicked', () => {
285
+ useUIStore.getState().openDetailWindow('agent-1');
286
+ const { rerender } = render(<MockNodeDetailWindow nodeId="agent-1" />);
287
+
288
+ expect(screen.getByTestId('detail-window-agent-1')).toBeInTheDocument();
289
+
290
+ // Click close button
291
+ const closeButton = screen.getByTestId('close-button-agent-1');
292
+ fireEvent.click(closeButton);
293
+
294
+ rerender(<MockNodeDetailWindow nodeId="agent-1" />);
295
+
296
+ expect(screen.queryByTestId('detail-window-agent-1')).not.toBeInTheDocument();
297
+ expect(useUIStore.getState().detailWindows.size).toBe(0);
298
+ });
299
+
300
+ it('should remove window from detailWindows map when closed', () => {
301
+ useUIStore.getState().openDetailWindow('agent-1');
302
+ expect(useUIStore.getState().detailWindows.has('agent-1')).toBe(true);
303
+
304
+ useUIStore.getState().closeDetailWindow('agent-1');
305
+ expect(useUIStore.getState().detailWindows.has('agent-1')).toBe(false);
306
+ });
307
+
308
+ it('should handle closing non-existent window gracefully', () => {
309
+ expect(() => {
310
+ useUIStore.getState().closeDetailWindow('non-existent');
311
+ }).not.toThrow();
312
+ });
313
+ });
314
+
315
+ describe('Multiple Windows', () => {
316
+ it('should support multiple windows open simultaneously', () => {
317
+ useUIStore.getState().openDetailWindow('agent-1');
318
+ useUIStore.getState().openDetailWindow('agent-2');
319
+ useUIStore.getState().openDetailWindow('agent-3');
320
+
321
+ render(
322
+ <>
323
+ <MockNodeDetailWindow nodeId="agent-1" />
324
+ <MockNodeDetailWindow nodeId="agent-2" />
325
+ <MockNodeDetailWindow nodeId="agent-3" />
326
+ </>
327
+ );
328
+
329
+ expect(screen.getByTestId('detail-window-agent-1')).toBeInTheDocument();
330
+ expect(screen.getByTestId('detail-window-agent-2')).toBeInTheDocument();
331
+ expect(screen.getByTestId('detail-window-agent-3')).toBeInTheDocument();
332
+ expect(useUIStore.getState().detailWindows.size).toBe(3);
333
+ });
334
+
335
+ it('should maintain independent state for each window', () => {
336
+ useUIStore.getState().openDetailWindow('agent-1');
337
+ useUIStore.getState().openDetailWindow('agent-2');
338
+
339
+ const window1 = useUIStore.getState().detailWindows.get('agent-1')!;
340
+ const window2 = useUIStore.getState().detailWindows.get('agent-2')!;
341
+
342
+ expect(window1.nodeId).toBe('agent-1');
343
+ expect(window2.nodeId).toBe('agent-2');
344
+ expect(window1.position).not.toEqual(window2.position);
345
+ });
346
+
347
+ it('should allow closing one window without affecting others', () => {
348
+ useUIStore.getState().openDetailWindow('agent-1');
349
+ useUIStore.getState().openDetailWindow('agent-2');
350
+ useUIStore.getState().openDetailWindow('agent-3');
351
+
352
+ render(
353
+ <>
354
+ <MockNodeDetailWindow nodeId="agent-1" />
355
+ <MockNodeDetailWindow nodeId="agent-2" />
356
+ <MockNodeDetailWindow nodeId="agent-3" />
357
+ </>
358
+ );
359
+
360
+ // Close middle window
361
+ fireEvent.click(screen.getByTestId('close-button-agent-2'));
362
+
363
+ expect(screen.queryByTestId('detail-window-agent-2')).not.toBeInTheDocument();
364
+ expect(screen.getByTestId('detail-window-agent-1')).toBeInTheDocument();
365
+ expect(screen.getByTestId('detail-window-agent-3')).toBeInTheDocument();
366
+ expect(useUIStore.getState().detailWindows.size).toBe(2);
367
+ });
368
+
369
+ it('should key windows by nodeId', () => {
370
+ useUIStore.getState().openDetailWindow('agent-1');
371
+ useUIStore.getState().openDetailWindow('message-123');
372
+
373
+ expect(useUIStore.getState().detailWindows.has('agent-1')).toBe(true);
374
+ expect(useUIStore.getState().detailWindows.has('message-123')).toBe(true);
375
+ });
376
+ });
377
+
378
+ describe('State Persistence', () => {
379
+ it('should persist window position updates', () => {
380
+ useUIStore.getState().openDetailWindow('agent-1');
381
+
382
+ // Update position
383
+ useUIStore.getState().updateDetailWindow('agent-1', {
384
+ position: { x: 300, y: 400 },
385
+ });
386
+
387
+ const window = useUIStore.getState().detailWindows.get('agent-1')!;
388
+ expect(window.position).toEqual({ x: 300, y: 400 });
389
+ });
390
+
391
+ it('should persist window size updates', () => {
392
+ useUIStore.getState().openDetailWindow('agent-1');
393
+
394
+ // Update size
395
+ useUIStore.getState().updateDetailWindow('agent-1', {
396
+ size: { width: 800, height: 600 },
397
+ });
398
+
399
+ const window = useUIStore.getState().detailWindows.get('agent-1')!;
400
+ expect(window.size).toEqual({ width: 800, height: 600 });
401
+ });
402
+
403
+ it('should persist active tab changes', () => {
404
+ useUIStore.getState().openDetailWindow('agent-1');
405
+
406
+ // Change active tab
407
+ useUIStore.getState().updateDetailWindow('agent-1', {
408
+ activeTab: 'messageHistory',
409
+ });
410
+
411
+ const window = useUIStore.getState().detailWindows.get('agent-1')!;
412
+ expect(window.activeTab).toBe('messageHistory');
413
+ });
414
+
415
+ it('should preserve window state during drag operations', () => {
416
+ useUIStore.getState().openDetailWindow('agent-1');
417
+ render(<MockNodeDetailWindow nodeId="agent-1" />);
418
+
419
+ const header = screen.getByTestId('window-header-agent-1');
420
+
421
+ // Perform drag
422
+ fireEvent.mouseDown(header, { clientX: 150, clientY: 150 });
423
+ fireEvent.mouseMove(document, { clientX: 350, clientY: 350 });
424
+ fireEvent.mouseUp(document);
425
+
426
+ const window = useUIStore.getState().detailWindows.get('agent-1')!;
427
+ expect(window.nodeId).toBe('agent-1');
428
+ expect(window.size).toEqual({ width: 600, height: 400 }); // Size unchanged
429
+ expect(window.activeTab).toBe('liveOutput'); // Tab unchanged
430
+ });
431
+
432
+ it('should preserve window state during resize operations', () => {
433
+ useUIStore.getState().openDetailWindow('agent-1');
434
+ render(<MockNodeDetailWindow nodeId="agent-1" />);
435
+
436
+ const resizeHandle = screen.getByTestId('resize-handle-agent-1');
437
+
438
+ // Perform resize
439
+ fireEvent.mouseDown(resizeHandle, { clientX: 700, clientY: 500 });
440
+ fireEvent.mouseMove(document, { clientX: 900, clientY: 700 });
441
+ fireEvent.mouseUp(document);
442
+
443
+ const window = useUIStore.getState().detailWindows.get('agent-1')!;
444
+ expect(window.nodeId).toBe('agent-1');
445
+ expect(window.position).toEqual({ x: 100, y: 100 }); // Position unchanged
446
+ expect(window.activeTab).toBe('liveOutput'); // Tab unchanged
447
+ });
448
+ });
449
+
450
+ describe('Edge Cases', () => {
451
+ it('should handle updateDetailWindow for non-existent window', () => {
452
+ expect(() => {
453
+ useUIStore.getState().updateDetailWindow('non-existent', {
454
+ position: { x: 100, y: 100 },
455
+ });
456
+ }).not.toThrow();
457
+
458
+ expect(useUIStore.getState().detailWindows.has('non-existent')).toBe(false);
459
+ });
460
+
461
+ it('should handle rapid open/close cycles', () => {
462
+ for (let i = 0; i < 10; i++) {
463
+ useUIStore.getState().openDetailWindow('agent-1');
464
+ expect(useUIStore.getState().detailWindows.has('agent-1')).toBe(true);
465
+
466
+ useUIStore.getState().closeDetailWindow('agent-1');
467
+ expect(useUIStore.getState().detailWindows.has('agent-1')).toBe(false);
468
+ }
469
+ });
470
+
471
+ it('should handle many simultaneous windows', () => {
472
+ const nodeIds = Array.from({ length: 20 }, (_, i) => `agent-${i}`);
473
+
474
+ nodeIds.forEach((nodeId) => {
475
+ useUIStore.getState().openDetailWindow(nodeId);
476
+ });
477
+
478
+ expect(useUIStore.getState().detailWindows.size).toBe(20);
479
+
480
+ nodeIds.forEach((nodeId) => {
481
+ expect(useUIStore.getState().detailWindows.has(nodeId)).toBe(true);
482
+ });
483
+ });
484
+
485
+ it('should handle partial window updates', () => {
486
+ useUIStore.getState().openDetailWindow('agent-1');
487
+
488
+ const original = useUIStore.getState().detailWindows.get('agent-1')!;
489
+
490
+ // Update only position
491
+ useUIStore.getState().updateDetailWindow('agent-1', {
492
+ position: { x: 500, y: 600 },
493
+ });
494
+
495
+ const updated = useUIStore.getState().detailWindows.get('agent-1')!;
496
+ expect(updated.position).toEqual({ x: 500, y: 600 });
497
+ expect(updated.size).toEqual(original.size);
498
+ expect(updated.activeTab).toEqual(original.activeTab);
499
+ });
500
+ });
501
+ });