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
@@ -1,680 +0,0 @@
1
- """FlockMCPServer is the core, declarative base class for all types of MCP-Servers in the Flock framework."""
2
-
3
- import asyncio
4
- import importlib
5
- import inspect
6
- import os
7
- from abc import ABC, abstractmethod
8
- from typing import Any, Literal, TypeVar
9
-
10
- from dspy import Tool as DSPyTool
11
- from opentelemetry import trace
12
- from pydantic import (
13
- BaseModel,
14
- ConfigDict,
15
- Field,
16
- )
17
-
18
- from flock.core.component.agent_component_base import AgentComponent
19
- from flock.core.logging.logging import get_logger
20
- from flock.core.mcp.flock_mcp_tool import FlockMCPTool
21
- from flock.core.mcp.mcp_client_manager import FlockMCPClientManager
22
- from flock.core.mcp.mcp_config import FlockMCPConfiguration
23
- from flock.core.serialization.serializable import Serializable
24
- from flock.core.serialization.serialization_utils import (
25
- deserialize_component,
26
- serialize_item,
27
- )
28
-
29
- logger = get_logger("mcp.server")
30
- tracer = trace.get_tracer(__name__)
31
- T = TypeVar("T", bound="FlockMCPServer")
32
-
33
- LoggingLevel = Literal[
34
- "debug",
35
- "info",
36
- "notice",
37
- "warning",
38
- "error",
39
- "critical",
40
- "alert",
41
- "emergency",
42
- ]
43
-
44
-
45
- class FlockMCPServer(BaseModel, Serializable, ABC):
46
- """Base class for all Flock MCP Server Types.
47
-
48
- Servers serve as an abstraction-layer between the underlying MCPClientSession
49
- which is the actual connection between Flock and a (remote) MCP-Server.
50
-
51
- Servers hook into the lifecycle of their assigned agents and take care
52
- of establishing sessions, getting and converting tools and other functions
53
- without agents having to worry about the details.
54
-
55
- Tools (if provided) will be injected into the list of tools of any attached
56
- agent automatically.
57
-
58
- Servers provide lifecycle-hooks (`initialize`, `get_tools`, `get_prompts`, `list_resources`, `get_resource_contents`, `set_roots`, etc)
59
- which allow modules to hook into them. This can be used to modify data or
60
- pass headers from authentication-flows to a server.
61
-
62
- Each Server should define its configuration requirements either by:
63
- 1. Creating a subclass of FlockMCPServerConfig
64
- 2. Using FlockMCPServerConfig.with_fields() to create a config class.
65
- """
66
-
67
- config: FlockMCPConfiguration = Field(
68
- ..., description="Config for clients connecting to the server."
69
- )
70
-
71
- initialized: bool = Field(
72
- default=False,
73
- exclude=True,
74
- description="Whether or not this Server has already initialized.",
75
- )
76
-
77
- components: dict[str, AgentComponent] = Field(
78
- default={},
79
- description="Dictionary of unified agent components attached to this Server.",
80
- )
81
-
82
- # --- Underlying ConnectionManager ---
83
- # (Manages a pool of ClientConnections and does the actual talking to the MCP Server)
84
- # (Excluded from Serialization)
85
- client_manager: FlockMCPClientManager | None = Field(
86
- default=None,
87
- exclude=True,
88
- description="Underlying Connection Manager. Handles the actual underlying connections to the server.",
89
- )
90
-
91
- condition: asyncio.Condition = Field(
92
- default_factory=asyncio.Condition,
93
- exclude=True,
94
- description="Condition for asynchronous operations.",
95
- )
96
-
97
- model_config = ConfigDict(
98
- arbitrary_types_allowed=True,
99
- )
100
-
101
- def add_component(self, component: AgentComponent) -> None:
102
- """Add a unified component to this server."""
103
- if not component.name:
104
- logger.error("Component must have a name to be added.")
105
- return
106
- if self.components and component.name in self.components:
107
- logger.warning(f"Overwriting existing component: {component.name}")
108
-
109
- self.components[component.name] = component
110
- logger.debug(
111
- f"Added component '{component.name}' to server {self.config.name}"
112
- )
113
- return
114
-
115
- def remove_component(self, component_name: str) -> None:
116
- """Remove a component from this server."""
117
- if component_name in self.components:
118
- del self.components[component_name]
119
- logger.debug(
120
- f"Removed component '{component_name}' from server '{self.config.name}'"
121
- )
122
- else:
123
- logger.warning(
124
- f"Component '{component_name}' not found on server '{self.config.name}'"
125
- )
126
- return
127
-
128
- def get_component(self, component_name: str) -> AgentComponent | None:
129
- """Get a component by name."""
130
- return self.components.get(component_name)
131
-
132
- def get_enabled_components(self) -> list[AgentComponent]:
133
- """Get a list of currently enabled components attached to this server."""
134
- return [c for c in self.components.values() if c.config.enabled]
135
-
136
- @abstractmethod
137
- async def initialize(self) -> FlockMCPClientManager:
138
- """Called when initializing the server."""
139
- pass
140
-
141
- async def call_tool(
142
- self, agent_id: str, run_id: str, name: str, arguments: dict[str, Any]
143
- ) -> Any:
144
- """Call a tool via the MCP Protocol on the client's server."""
145
- with tracer.start_as_current_span("server.call_tool") as span:
146
- span.set_attribute("agent_id", agent_id)
147
- span.set_attribute("run_id", run_id)
148
- span.set_attribute("tool.name", name)
149
- span.set_attribute("arguments", str(arguments))
150
- if not self.initialized or not self.client_manager:
151
- async with self.condition:
152
- await self.pre_init()
153
- self.client_manager = await self.initialize()
154
- self.initialized = True
155
- await self.post_init()
156
- if not self.config.allow_all_tools:
157
- whitelist = self.config.feature_config.tool_whitelist
158
- if (
159
- whitelist is not None
160
- and len(whitelist) > 0
161
- and name not in whitelist
162
- ):
163
- return None
164
- async with self.condition:
165
- try:
166
- additional_params: dict[str, Any] = {
167
- "refresh_client": False,
168
- "override_headers": False,
169
- } # initialize the additional params as an empty dict.
170
-
171
- await self.before_connect(
172
- additional_params=additional_params
173
- )
174
- pre_call_args = {
175
- "agent_id": agent_id,
176
- "run_id": run_id,
177
- "tool_name": name,
178
- "arguments": arguments,
179
- }
180
- pre_call_args.update(additional_params)
181
- await self.pre_mcp_call(pre_call_args)
182
- result = await self.client_manager.call_tool(
183
- agent_id=agent_id,
184
- run_id=run_id,
185
- name=name,
186
- arguments=arguments,
187
- additional_params=additional_params,
188
- )
189
- # re-set addtional-params, just to be sure.
190
- await self.post_mcp_call(result=result)
191
- return result
192
- except Exception as mcp_error:
193
- logger.error(
194
- "Error during server.call_tool",
195
- server=self.config.name,
196
- error=str(mcp_error),
197
- )
198
- span.record_exception(mcp_error)
199
- return None
200
-
201
- async def get_tools(self, agent_id: str, run_id: str) -> list[DSPyTool]:
202
- """Retrieves a list of available tools from this server."""
203
- with tracer.start_as_current_span("server.get_tools") as span:
204
- span.set_attribute("server.name", self.config.name)
205
- span.set_attribute("agent_id", agent_id)
206
- span.set_attribute("run_id", run_id)
207
- if not self.initialized or not self.client_manager:
208
- async with self.condition:
209
- await self.pre_init()
210
- self.client_manager = await self.initialize()
211
- self.initialized = True
212
- await self.post_init()
213
-
214
- async with self.condition:
215
- try:
216
- await self.pre_mcp_call()
217
- additional_params: dict[str, Any] = {}
218
- additional_params = await self.before_connect(
219
- additional_params=additional_params
220
- )
221
- result: list[
222
- FlockMCPTool
223
- ] = await self.client_manager.get_tools(
224
- agent_id=agent_id,
225
- run_id=run_id,
226
- additional_params=additional_params,
227
- )
228
- # filtering based on whitelist
229
- if not self.config.allow_all_tools:
230
- whitelist = self.config.feature_config.tool_whitelist
231
- filtered_results: list[FlockMCPTool] = []
232
- for tool in result:
233
- if tool.name in whitelist:
234
- filtered_results.append(tool)
235
- result = filtered_results
236
- converted_tools = [
237
- t.as_dspy_tool(server=self) for t in result
238
- ]
239
- await self.post_mcp_call(result=converted_tools)
240
- return converted_tools
241
- except Exception as e:
242
- logger.error(
243
- f"Unexpected Exception ocurred while trying to get tools from server '{self.config.name}': {e}"
244
- )
245
- await self.on_error(error=e)
246
- span.record_exception(e)
247
- return []
248
- finally:
249
- self.condition.notify()
250
-
251
- async def before_connect(
252
- self, additional_params: dict[str, Any]
253
- ) -> dict[str, Any]:
254
- """Run before_connect hooks on modules."""
255
- logger.debug(
256
- f"Running before_connect hooks for modules in server '{self.config.name}'."
257
- )
258
- with tracer.start_as_current_span("server.before_connect") as span:
259
- span.set_attribute("server.name", self.config.name)
260
- try:
261
- if not additional_params:
262
- additional_params = {}
263
- for module in self.get_enabled_components():
264
- additional_params = await module.on_connect(
265
- server=self, additional_params=additional_params
266
- )
267
- except Exception as module_error:
268
- logger.error(
269
- "Error during before_connect",
270
- server=self.config.name,
271
- error=str(module_error),
272
- )
273
- span.record_exception(module_error)
274
- return additional_params
275
-
276
- async def pre_init(self) -> None:
277
- """Run pre-init hooks on modules."""
278
- logger.debug(
279
- f"Running pre-init hooks for modules in server '{self.config.name}'"
280
- )
281
- with tracer.start_as_current_span("server.pre_init") as span:
282
- span.set_attribute("server.name", self.config.name)
283
- # run whitelist checks
284
- feature_config = self.config.feature_config
285
- whitelist = (
286
- feature_config.tool_whitelist if feature_config else None
287
- )
288
- if whitelist:
289
- # Enforce whitelist usage by disabling blanket tool access
290
- self.config.allow_all_tools = False
291
- elif whitelist is None:
292
- # No whitelist configured; ensure defaults allow full access
293
- self.config.allow_all_tools = True
294
- try:
295
- for module in self.get_enabled_components():
296
- await module.on_pre_server_init(self)
297
- except Exception as module_error:
298
- logger.error(
299
- "Error during pre_init",
300
- server=self.config.name,
301
- error=str(module_error),
302
- )
303
- span.record_exception(module_error)
304
-
305
- async def post_init(self) -> None:
306
- """Run post-init hooks on modules."""
307
- logger.debug(
308
- f"Running post_init hooks for modules in server '{self.config.name}'"
309
- )
310
- with tracer.start_as_current_span("server.post_init") as span:
311
- span.set_attribute("server.name", self.config.name)
312
- try:
313
- for module in self.get_enabled_components():
314
- await module.on_post_server_init(self)
315
- except Exception as module_error:
316
- logger.error(
317
- "Error during post_init",
318
- server=self.config.name,
319
- error=str(module_error),
320
- )
321
- span.record_exception(module_error)
322
-
323
- async def pre_terminate(self) -> None:
324
- """Run pre-terminate hooks on modules."""
325
- logger.debug(
326
- f"Running post_init hooks for modules in server: '{self.config.name}'"
327
- )
328
- with tracer.start_as_current_span("server.pre_terminate") as span:
329
- span.set_attribute("server.name", self.config.name)
330
- try:
331
- for module in self.get_enabled_components():
332
- await module.on_pre_server_terminate(self)
333
- except Exception as module_error:
334
- logger.error(
335
- "Error during pre_terminate",
336
- server=self.config.name,
337
- error=str(module_error),
338
- )
339
- span.record_exception(module_error)
340
-
341
- async def post_terminate(self) -> None:
342
- """Run post-terminate hooks on modules."""
343
- logger.debug(
344
- f"Running post_terminate hooks for modules in server: '{self.config.name}'"
345
- )
346
- with tracer.start_as_current_span("server.post_terminate") as span:
347
- span.set_attribute("server.name", self.config.name)
348
- try:
349
- for module in self.get_enabled_components():
350
- await module.on_post_server_terminate(server=self)
351
- except Exception as module_error:
352
- logger.error(
353
- "Error during post_terminate",
354
- server=self.config.name,
355
- error=str(module_error),
356
- )
357
- span.record_exception(module_error)
358
-
359
- async def on_error(self, error: Exception) -> None:
360
- """Run on_error hooks on modules."""
361
- logger.debug(
362
- f"Running on_error hooks for modules in server '{self.config.name}'"
363
- )
364
- with tracer.start_as_current_span("server.on_error") as span:
365
- span.set_attribute("server.name", self.config.name)
366
- try:
367
- for module in self.get_enabled_components():
368
- await module.on_server_error(server=self, error=error)
369
- except Exception as module_error:
370
- logger.error(
371
- "Error during on_error",
372
- server=self.config.name,
373
- error=str(module_error),
374
- )
375
- span.record_exception(module_error)
376
-
377
- async def pre_mcp_call(self, arguments: Any | None = None) -> None:
378
- """Run pre_mcp_call-hooks on modules."""
379
- logger.debug(
380
- f"Running pre_mcp_call hooks for modules in server '{self.config.name}'"
381
- )
382
- with tracer.start_as_current_span("server.pre_mcp_call") as span:
383
- span.set_attribute("server.name", self.config.name)
384
- try:
385
- for module in self.get_enabled_components():
386
- await module.on_pre_mcp_call(
387
- server=self, arguments=arguments
388
- )
389
- except Exception as module_error:
390
- logger.error(
391
- f"Error during pre_mcp_call: {module_error}",
392
- server=self.config.name,
393
- error=str(module_error),
394
- )
395
- span.record_exception(module_error)
396
-
397
- async def post_mcp_call(self, result: Any) -> None:
398
- """Run Post MCP_call hooks on modules."""
399
- logger.debug(
400
- f"Running post_mcp_call hooks for modules in server '{self.config.name}'"
401
- )
402
- with tracer.start_as_current_span("server.post_mcp_call") as span:
403
- span.set_attribute("server.name", self.config.name)
404
- try:
405
- for module in self.get_enabled_components():
406
- await module.on_post_mcp_call(server=self, result=result)
407
- except Exception as module_error:
408
- logger.error(
409
- "Error during post_mcp_call",
410
- server=self.config.name,
411
- error=str(module_error),
412
- )
413
- span.record_exception(module_error)
414
-
415
- # --- Async Methods ---
416
- async def __aenter__(self) -> "FlockMCPServer":
417
- """Enter the asynchronous context for the server."""
418
- # Spin up the client-manager
419
- with tracer.start_as_current_span("server.__aenter__") as span:
420
- span.set_attribute("server.name", self.config.name)
421
- logger.info(f"server.__aenter__", server=self.config.name)
422
- try:
423
- await self.pre_init()
424
- self.client_manager = await self.initialize()
425
- await self.post_init()
426
- self.initialized = True
427
- except Exception as server_error:
428
- logger.error(
429
- f"Error during __aenter__ for server '{self.config.name}'",
430
- server=self.config.name,
431
- error=server_error,
432
- )
433
- span.record_exception(server_error)
434
-
435
- async def __aexit__(self, exc_type, exc, tb) -> None:
436
- """Exit the asynchronous context for the server."""
437
- # tell the underlying client-manager to terminate connections
438
- # and unwind the clients.
439
- with tracer.start_as_current_span("server.__aexit__") as span:
440
- span.set_attribute("server.name", self.config.name)
441
- try:
442
- await self.pre_terminate()
443
- if self.initialized and self.client_manager:
444
- # means we ran through the initialize()-method
445
- # and the client manager is present
446
- await self.client_manager.close_all()
447
- self.client_manager = None
448
- self.initialized = False
449
- await self.post_terminate()
450
- return
451
- except Exception as server_error:
452
- logger.error(
453
- f"Error during __aexit__ for server '{self.config.name}'",
454
- server=self.config.name,
455
- error=server_error,
456
- )
457
- await self.on_error(error=server_error)
458
- span.record_exception(server_error)
459
-
460
- # --- Serialization Implementation ---
461
- def to_dict(self, path_type: str = "relative") -> dict[str, Any]: # noqa: C901 - TODO: refactor to simplify serialization logic
462
- """Convert instance to dictionary representation suitable for serialization."""
463
- from flock.core.registry import get_registry
464
-
465
- registry = get_registry()
466
-
467
- exclude = ["modules", "config"]
468
-
469
- logger.debug(f"Serializing server '{self.config.name}' to dict.")
470
- # Use Pydantic's dump, exclued manually handled fields.
471
- data = self.model_dump(
472
- exclude=exclude,
473
- mode="json", # Use json mode for better handling of standard types by Pydantic
474
- exclude_none=True, # Exclude None values for cleaner output
475
- )
476
-
477
- # --- Let the config handle its own serialization ---
478
- config_data = self.config.to_dict(path_type=path_type)
479
- data["config"] = config_data
480
-
481
- builtin_by_transport = {}
482
-
483
- try:
484
- from flock.mcp.servers.sse.flock_sse_server import FlockSSEServer
485
- from flock.mcp.servers.stdio.flock_stdio_server import (
486
- FlockMCPStdioServer,
487
- )
488
- from flock.mcp.servers.streamable_http.flock_streamable_http_server import (
489
- FlockStreamableHttpServer,
490
- )
491
- from flock.mcp.servers.websockets.flock_websocket_server import (
492
- FlockWSServer,
493
- )
494
-
495
- builtin_by_transport = {
496
- "stdio": FlockMCPStdioServer,
497
- "streamable_http": FlockStreamableHttpServer,
498
- "sse": FlockSSEServer,
499
- "websockets": FlockWSServer,
500
- }
501
- except ImportError:
502
- builtin_by_transport = {}
503
-
504
- # --- Only emit full impl for non-builtins ---
505
- transport = getattr(
506
- self.config.connection_config, "transport_type", None
507
- )
508
- builtin_cls = builtin_by_transport.get(transport)
509
-
510
- if type(self) is not builtin_cls:
511
- file_path = inspect.getsourcefile(type(self))
512
- if path_type == "relative":
513
- file_path = os.path.relpath(file_path)
514
- data["implementation"] = {
515
- "class_name": type(self).__name__,
516
- "module_path": type(self).__module__,
517
- "file_path": file_path,
518
- }
519
-
520
- logger.debug(
521
- f"Base server data for '{self.config.name}': {list(data.keys())}"
522
- )
523
- serialized_modules = {}
524
-
525
- def add_serialized_component(component: Any, field_name: str):
526
- if component:
527
- comp_type = type(component)
528
- type_name = registry.get_component_type_name(
529
- comp_type
530
- ) # Get registered name
531
-
532
- if type_name:
533
- try:
534
- serialized_component_data = serialize_item(component)
535
-
536
- if not isinstance(serialized_component_data, dict):
537
- logger.error(
538
- f"Serialization of component {type_name} for field '{field_name}' did not result in a dictionary. Got: {type(serialized_component_data)}"
539
- )
540
- serialized_modules[field_name] = {
541
- "type": type_name,
542
- "name": getattr(component, "name", "unknown"),
543
- "error": "serialization_failed_non_dict",
544
- }
545
- else:
546
- serialized_component_data["type"] = type_name
547
- serialized_modules[field_name] = (
548
- serialized_component_data
549
- )
550
- logger.debug(
551
- f"Successfully serialized component for field '{field_name}' (type: {type_name})"
552
- )
553
- except Exception as e:
554
- logger.error(
555
- f"Failed to serialize component {type_name} for field '{field_name}': {e}",
556
- exc_info=True,
557
- )
558
-
559
- else:
560
- logger.warning(
561
- f"Cannot serialize unregistered component {comp_type.__name__} for field '{field_name}'"
562
- )
563
-
564
- serialized_modules = {}
565
- for module in self.modules.values():
566
- add_serialized_component(module, module.name)
567
-
568
- if serialized_modules:
569
- data["modules"] = serialized_modules
570
- logger.debug(
571
- f"Added {len(serialized_modules)} modules to server '{self.config.name}'"
572
- )
573
-
574
- def _clean(obj: Any) -> Any:
575
- if isinstance(obj, dict):
576
- return {
577
- k: _clean(v)
578
- for k, v in obj.items()
579
- if v is not None
580
- and not (isinstance(v, list | dict) and len(v) == 0)
581
- }
582
- if isinstance(obj, list):
583
- return [
584
- _clean(v)
585
- for v in obj
586
- if v is not None
587
- and not (isinstance(v, dict | list) and len(v) == 0)
588
- ]
589
- return obj
590
-
591
- data = _clean(data)
592
- return data
593
-
594
- @classmethod
595
- def from_dict(cls: type[T], data: dict[str, Any]) -> T:
596
- """Deserialize the server from a dictionary, including components."""
597
- logger.debug(
598
- f"Deserializing server from dict. Keys: {list(data.keys())}"
599
- )
600
-
601
- builtin_by_transport = {}
602
-
603
- try:
604
- from flock.mcp.servers.sse.flock_sse_server import FlockSSEServer
605
- from flock.mcp.servers.stdio.flock_stdio_server import (
606
- FlockMCPStdioServer,
607
- )
608
- from flock.mcp.servers.streamable_http.flock_streamable_http_server import (
609
- FlockStreamableHttpServer,
610
- )
611
- from flock.mcp.servers.websockets.flock_websocket_server import (
612
- FlockWSServer,
613
- )
614
-
615
- builtin_by_transport = {
616
- "stdio": FlockMCPStdioServer,
617
- "sse": FlockSSEServer,
618
- "streamable_http": FlockStreamableHttpServer,
619
- "websockets": FlockWSServer,
620
- }
621
- except ImportError:
622
- builtin_by_transport = {}
623
-
624
- # find custom impl or built-in
625
- impl = data.pop("implementation", None)
626
- if impl:
627
- mod = importlib.import_module(impl["module_path"])
628
- real_cls = getattr(mod, impl["class_name"])
629
- else:
630
- # built-in: inspect transport_type in data["config"]
631
- transport = data["config"]["connection_config"]["transport_type"]
632
- real_cls = builtin_by_transport.get(transport, cls)
633
-
634
- # deserialize the config:
635
- config_data = data.pop("config", None)
636
- if config_data:
637
- # Forcing a square into a round hole
638
- # pretty ugly, but gets the job done.
639
- try:
640
- config_field = real_cls.model_fields["config"]
641
- config_cls = config_field.annotation
642
- except (AttributeError, KeyError):
643
- # fallback if Pydantic v1 or missing
644
- config_cls = FlockMCPConfiguration
645
- config_object = config_cls.from_dict(config_data)
646
- data["config"] = config_object
647
-
648
- # now construct
649
- server = real_cls(
650
- **{
651
- k: v
652
- for k, v in data.items()
653
- if k not in ["modules", "components"]
654
- }
655
- )
656
-
657
- # re-hydrate components (both legacy modules and new components)
658
- for cname, cdata in data.get("components", {}).items():
659
- server.add_component(deserialize_component(cdata, AgentComponent))
660
-
661
- # Handle legacy modules for backward compatibility during transition
662
- for mname, mdata in data.get("modules", {}).items():
663
- logger.warning(
664
- f"Legacy module '{mname}' found during deserialization - consider migrating to unified components"
665
- )
666
- # Skip legacy modules during migration
667
-
668
- # --- Separate Data ---
669
- component_configs = {}
670
- server_data = {}
671
- component_keys = ["modules"]
672
-
673
- for key, value in data.items():
674
- if key in component_keys and value is not None:
675
- component_configs[key] = value
676
- else:
677
- server_data[key] = value
678
-
679
- logger.info(f"Successfully deserialized server '{server.config.name}'")
680
- return server