flock-core 0.5.0b27__py3-none-any.whl → 0.5.0b50__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 (357) 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/{core/util → helper}/cli_helper.py +4 -3
  17. flock/{core/logging → logging}/__init__.py +2 -3
  18. flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
  19. flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
  20. flock/{core/logging → logging}/formatters/themed_formatter.py +69 -115
  21. flock/{core/logging → logging}/logging.py +77 -61
  22. flock/{core/logging → logging}/telemetry.py +20 -26
  23. flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
  24. flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +6 -9
  25. flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
  26. flock/{core/logging → logging}/trace_and_logged.py +20 -24
  27. flock/mcp/__init__.py +91 -0
  28. flock/{core/mcp/mcp_client.py → mcp/client.py} +103 -154
  29. flock/{core/mcp/mcp_config.py → mcp/config.py} +62 -117
  30. flock/mcp/manager.py +255 -0
  31. flock/mcp/servers/sse/__init__.py +1 -1
  32. flock/mcp/servers/sse/flock_sse_server.py +11 -53
  33. flock/mcp/servers/stdio/__init__.py +1 -1
  34. flock/mcp/servers/stdio/flock_stdio_server.py +8 -48
  35. flock/mcp/servers/streamable_http/flock_streamable_http_server.py +17 -62
  36. flock/mcp/servers/websockets/flock_websocket_server.py +7 -40
  37. flock/{core/mcp/flock_mcp_tool.py → mcp/tool.py} +16 -26
  38. flock/mcp/types/__init__.py +42 -0
  39. flock/{core/mcp → mcp}/types/callbacks.py +9 -15
  40. flock/{core/mcp → mcp}/types/factories.py +7 -6
  41. flock/{core/mcp → mcp}/types/handlers.py +13 -18
  42. flock/{core/mcp → mcp}/types/types.py +70 -74
  43. flock/{core/mcp → mcp}/util/helpers.py +1 -1
  44. flock/orchestrator.py +645 -0
  45. flock/registry.py +148 -0
  46. flock/runtime.py +262 -0
  47. flock/service.py +140 -0
  48. flock/store.py +69 -0
  49. flock/subscription.py +111 -0
  50. flock/themes/andromeda.toml +1 -1
  51. flock/themes/apple-system-colors.toml +1 -1
  52. flock/themes/arcoiris.toml +1 -1
  53. flock/themes/atomonelight.toml +1 -1
  54. flock/themes/ayu copy.toml +1 -1
  55. flock/themes/ayu-light.toml +1 -1
  56. flock/themes/belafonte-day.toml +1 -1
  57. flock/themes/belafonte-night.toml +1 -1
  58. flock/themes/blulocodark.toml +1 -1
  59. flock/themes/breeze.toml +1 -1
  60. flock/themes/broadcast.toml +1 -1
  61. flock/themes/brogrammer.toml +1 -1
  62. flock/themes/builtin-dark.toml +1 -1
  63. flock/themes/builtin-pastel-dark.toml +1 -1
  64. flock/themes/catppuccin-latte.toml +1 -1
  65. flock/themes/catppuccin-macchiato.toml +1 -1
  66. flock/themes/catppuccin-mocha.toml +1 -1
  67. flock/themes/cga.toml +1 -1
  68. flock/themes/chalk.toml +1 -1
  69. flock/themes/ciapre.toml +1 -1
  70. flock/themes/coffee-theme.toml +1 -1
  71. flock/themes/cyberpunkscarletprotocol.toml +1 -1
  72. flock/themes/dark+.toml +1 -1
  73. flock/themes/darkermatrix.toml +1 -1
  74. flock/themes/darkside.toml +1 -1
  75. flock/themes/desert.toml +1 -1
  76. flock/themes/django.toml +1 -1
  77. flock/themes/djangosmooth.toml +1 -1
  78. flock/themes/doomone.toml +1 -1
  79. flock/themes/dotgov.toml +1 -1
  80. flock/themes/dracula+.toml +1 -1
  81. flock/themes/duckbones.toml +1 -1
  82. flock/themes/encom.toml +1 -1
  83. flock/themes/espresso.toml +1 -1
  84. flock/themes/everblush.toml +1 -1
  85. flock/themes/fairyfloss.toml +1 -1
  86. flock/themes/fideloper.toml +1 -1
  87. flock/themes/fishtank.toml +1 -1
  88. flock/themes/flexoki-light.toml +1 -1
  89. flock/themes/floraverse.toml +1 -1
  90. flock/themes/framer.toml +1 -1
  91. flock/themes/galizur.toml +1 -1
  92. flock/themes/github.toml +1 -1
  93. flock/themes/grass.toml +1 -1
  94. flock/themes/grey-green.toml +1 -1
  95. flock/themes/gruvboxlight.toml +1 -1
  96. flock/themes/guezwhoz.toml +1 -1
  97. flock/themes/harper.toml +1 -1
  98. flock/themes/hax0r-blue.toml +1 -1
  99. flock/themes/hopscotch.256.toml +1 -1
  100. flock/themes/ic-green-ppl.toml +1 -1
  101. flock/themes/iceberg-dark.toml +1 -1
  102. flock/themes/japanesque.toml +1 -1
  103. flock/themes/jubi.toml +1 -1
  104. flock/themes/kibble.toml +1 -1
  105. flock/themes/kolorit.toml +1 -1
  106. flock/themes/kurokula.toml +1 -1
  107. flock/themes/materialdesigncolors.toml +1 -1
  108. flock/themes/matrix.toml +1 -1
  109. flock/themes/mellifluous.toml +1 -1
  110. flock/themes/midnight-in-mojave.toml +1 -1
  111. flock/themes/monokai-remastered.toml +1 -1
  112. flock/themes/monokai-soda.toml +1 -1
  113. flock/themes/neon.toml +1 -1
  114. flock/themes/neopolitan.toml +1 -1
  115. flock/themes/nord-light.toml +1 -1
  116. flock/themes/ocean.toml +1 -1
  117. flock/themes/onehalfdark.toml +1 -1
  118. flock/themes/onehalflight.toml +1 -1
  119. flock/themes/palenighthc.toml +1 -1
  120. flock/themes/paulmillr.toml +1 -1
  121. flock/themes/pencildark.toml +1 -1
  122. flock/themes/pnevma.toml +1 -1
  123. flock/themes/purple-rain.toml +1 -1
  124. flock/themes/purplepeter.toml +1 -1
  125. flock/themes/raycast-dark.toml +1 -1
  126. flock/themes/red-sands.toml +1 -1
  127. flock/themes/relaxed.toml +1 -1
  128. flock/themes/retro.toml +1 -1
  129. flock/themes/rose-pine.toml +1 -1
  130. flock/themes/royal.toml +1 -1
  131. flock/themes/ryuuko.toml +1 -1
  132. flock/themes/sakura.toml +1 -1
  133. flock/themes/scarlet-protocol.toml +1 -1
  134. flock/themes/seoulbones-dark.toml +1 -1
  135. flock/themes/shades-of-purple.toml +1 -1
  136. flock/themes/smyck.toml +1 -1
  137. flock/themes/softserver.toml +1 -1
  138. flock/themes/solarized-darcula.toml +1 -1
  139. flock/themes/square.toml +1 -1
  140. flock/themes/sugarplum.toml +1 -1
  141. flock/themes/thayer-bright.toml +1 -1
  142. flock/themes/tokyonight.toml +1 -1
  143. flock/themes/tomorrow.toml +1 -1
  144. flock/themes/ubuntu.toml +1 -1
  145. flock/themes/ultradark.toml +1 -1
  146. flock/themes/ultraviolent.toml +1 -1
  147. flock/themes/unikitty.toml +1 -1
  148. flock/themes/urple.toml +1 -1
  149. flock/themes/vesper.toml +1 -1
  150. flock/themes/vimbones.toml +1 -1
  151. flock/themes/wildcherry.toml +1 -1
  152. flock/themes/wilmersdorf.toml +1 -1
  153. flock/themes/wryan.toml +1 -1
  154. flock/themes/xcodedarkhc.toml +1 -1
  155. flock/themes/xcodelight.toml +1 -1
  156. flock/themes/zenbones-light.toml +1 -1
  157. flock/themes/zenwritten-dark.toml +1 -1
  158. flock/utilities.py +301 -0
  159. flock/{components/utility → utility}/output_utility_component.py +68 -53
  160. flock/visibility.py +107 -0
  161. flock_core-0.5.0b50.dist-info/METADATA +747 -0
  162. flock_core-0.5.0b50.dist-info/RECORD +398 -0
  163. flock_core-0.5.0b50.dist-info/entry_points.txt +2 -0
  164. {flock_core-0.5.0b27.dist-info → flock_core-0.5.0b50.dist-info}/licenses/LICENSE +1 -1
  165. flock/adapter/__init__.py +0 -14
  166. flock/adapter/azure_adapter.py +0 -68
  167. flock/adapter/chroma_adapter.py +0 -73
  168. flock/adapter/faiss_adapter.py +0 -97
  169. flock/adapter/pinecone_adapter.py +0 -51
  170. flock/adapter/vector_base.py +0 -47
  171. flock/cli/assets/release_notes.md +0 -140
  172. flock/cli/config.py +0 -8
  173. flock/cli/constants.py +0 -36
  174. flock/cli/create_agent.py +0 -1
  175. flock/cli/create_flock.py +0 -280
  176. flock/cli/execute_flock.py +0 -620
  177. flock/cli/load_agent.py +0 -1
  178. flock/cli/load_examples.py +0 -1
  179. flock/cli/load_flock.py +0 -192
  180. flock/cli/load_release_notes.py +0 -20
  181. flock/cli/loaded_flock_cli.py +0 -254
  182. flock/cli/manage_agents.py +0 -459
  183. flock/cli/registry_management.py +0 -889
  184. flock/cli/runner.py +0 -41
  185. flock/cli/settings.py +0 -857
  186. flock/cli/utils.py +0 -135
  187. flock/cli/view_results.py +0 -29
  188. flock/cli/yaml_editor.py +0 -396
  189. flock/components/__init__.py +0 -30
  190. flock/components/evaluation/__init__.py +0 -9
  191. flock/components/evaluation/declarative_evaluation_component.py +0 -606
  192. flock/components/routing/__init__.py +0 -15
  193. flock/components/routing/conditional_routing_component.py +0 -494
  194. flock/components/routing/default_routing_component.py +0 -103
  195. flock/components/routing/llm_routing_component.py +0 -206
  196. flock/components/utility/__init__.py +0 -15
  197. flock/components/utility/memory_utility_component.py +0 -550
  198. flock/components/utility/metrics_utility_component.py +0 -700
  199. flock/config.py +0 -61
  200. flock/core/__init__.py +0 -110
  201. flock/core/agent/__init__.py +0 -16
  202. flock/core/agent/default_agent.py +0 -180
  203. flock/core/agent/flock_agent_components.py +0 -104
  204. flock/core/agent/flock_agent_execution.py +0 -101
  205. flock/core/agent/flock_agent_integration.py +0 -260
  206. flock/core/agent/flock_agent_lifecycle.py +0 -186
  207. flock/core/agent/flock_agent_serialization.py +0 -381
  208. flock/core/api/__init__.py +0 -10
  209. flock/core/api/custom_endpoint.py +0 -45
  210. flock/core/api/endpoints.py +0 -254
  211. flock/core/api/main.py +0 -162
  212. flock/core/api/models.py +0 -97
  213. flock/core/api/run_store.py +0 -224
  214. flock/core/api/runner.py +0 -44
  215. flock/core/api/service.py +0 -214
  216. flock/core/component/__init__.py +0 -15
  217. flock/core/component/agent_component_base.py +0 -309
  218. flock/core/component/evaluation_component.py +0 -62
  219. flock/core/component/routing_component.py +0 -74
  220. flock/core/component/utility_component.py +0 -69
  221. flock/core/config/flock_agent_config.py +0 -58
  222. flock/core/config/scheduled_agent_config.py +0 -40
  223. flock/core/context/context.py +0 -213
  224. flock/core/context/context_manager.py +0 -37
  225. flock/core/context/context_vars.py +0 -10
  226. flock/core/evaluation/utils.py +0 -396
  227. flock/core/execution/batch_executor.py +0 -369
  228. flock/core/execution/evaluation_executor.py +0 -438
  229. flock/core/execution/local_executor.py +0 -31
  230. flock/core/execution/opik_executor.py +0 -103
  231. flock/core/execution/temporal_executor.py +0 -164
  232. flock/core/flock.py +0 -634
  233. flock/core/flock_agent.py +0 -336
  234. flock/core/flock_factory.py +0 -551
  235. flock/core/flock_scheduler.py +0 -166
  236. flock/core/flock_server_manager.py +0 -136
  237. flock/core/interpreter/python_interpreter.py +0 -689
  238. flock/core/mcp/__init__.py +0 -1
  239. flock/core/mcp/flock_mcp_server.py +0 -680
  240. flock/core/mcp/mcp_client_manager.py +0 -201
  241. flock/core/mcp/types/__init__.py +0 -1
  242. flock/core/mixin/dspy_integration.py +0 -403
  243. flock/core/mixin/prompt_parser.py +0 -125
  244. flock/core/orchestration/__init__.py +0 -15
  245. flock/core/orchestration/flock_batch_processor.py +0 -94
  246. flock/core/orchestration/flock_evaluator.py +0 -113
  247. flock/core/orchestration/flock_execution.py +0 -295
  248. flock/core/orchestration/flock_initialization.py +0 -149
  249. flock/core/orchestration/flock_server_manager.py +0 -67
  250. flock/core/orchestration/flock_web_server.py +0 -117
  251. flock/core/registry/__init__.py +0 -45
  252. flock/core/registry/agent_registry.py +0 -69
  253. flock/core/registry/callable_registry.py +0 -139
  254. flock/core/registry/component_discovery.py +0 -142
  255. flock/core/registry/component_registry.py +0 -64
  256. flock/core/registry/config_mapping.py +0 -64
  257. flock/core/registry/decorators.py +0 -137
  258. flock/core/registry/registry_hub.py +0 -205
  259. flock/core/registry/server_registry.py +0 -57
  260. flock/core/registry/type_registry.py +0 -86
  261. flock/core/serialization/__init__.py +0 -13
  262. flock/core/serialization/callable_registry.py +0 -52
  263. flock/core/serialization/flock_serializer.py +0 -832
  264. flock/core/serialization/json_encoder.py +0 -41
  265. flock/core/serialization/secure_serializer.py +0 -175
  266. flock/core/serialization/serializable.py +0 -342
  267. flock/core/serialization/serialization_utils.py +0 -412
  268. flock/core/util/file_path_utils.py +0 -223
  269. flock/core/util/hydrator.py +0 -309
  270. flock/core/util/input_resolver.py +0 -164
  271. flock/core/util/loader.py +0 -59
  272. flock/core/util/splitter.py +0 -219
  273. flock/di.py +0 -27
  274. flock/platform/docker_tools.py +0 -49
  275. flock/platform/jaeger_install.py +0 -86
  276. flock/webapp/__init__.py +0 -1
  277. flock/webapp/app/__init__.py +0 -0
  278. flock/webapp/app/api/__init__.py +0 -0
  279. flock/webapp/app/api/agent_management.py +0 -241
  280. flock/webapp/app/api/execution.py +0 -709
  281. flock/webapp/app/api/flock_management.py +0 -129
  282. flock/webapp/app/api/registry_viewer.py +0 -30
  283. flock/webapp/app/chat.py +0 -665
  284. flock/webapp/app/config.py +0 -104
  285. flock/webapp/app/dependencies.py +0 -117
  286. flock/webapp/app/main.py +0 -1070
  287. flock/webapp/app/middleware.py +0 -113
  288. flock/webapp/app/models_ui.py +0 -7
  289. flock/webapp/app/services/__init__.py +0 -0
  290. flock/webapp/app/services/feedback_file_service.py +0 -363
  291. flock/webapp/app/services/flock_service.py +0 -337
  292. flock/webapp/app/services/sharing_models.py +0 -81
  293. flock/webapp/app/services/sharing_store.py +0 -598
  294. flock/webapp/app/templates/theme_mapper.html +0 -326
  295. flock/webapp/app/theme_mapper.py +0 -812
  296. flock/webapp/app/utils.py +0 -85
  297. flock/webapp/run.py +0 -215
  298. flock/webapp/static/css/chat.css +0 -301
  299. flock/webapp/static/css/components.css +0 -167
  300. flock/webapp/static/css/header.css +0 -39
  301. flock/webapp/static/css/layout.css +0 -46
  302. flock/webapp/static/css/sidebar.css +0 -127
  303. flock/webapp/static/css/two-pane.css +0 -48
  304. flock/webapp/templates/base.html +0 -200
  305. flock/webapp/templates/chat.html +0 -152
  306. flock/webapp/templates/chat_settings.html +0 -19
  307. flock/webapp/templates/flock_editor.html +0 -16
  308. flock/webapp/templates/index.html +0 -12
  309. flock/webapp/templates/partials/_agent_detail_form.html +0 -93
  310. flock/webapp/templates/partials/_agent_list.html +0 -18
  311. flock/webapp/templates/partials/_agent_manager_view.html +0 -51
  312. flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
  313. flock/webapp/templates/partials/_chat_container.html +0 -15
  314. flock/webapp/templates/partials/_chat_messages.html +0 -57
  315. flock/webapp/templates/partials/_chat_settings_form.html +0 -85
  316. flock/webapp/templates/partials/_create_flock_form.html +0 -50
  317. flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
  318. flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
  319. flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
  320. flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
  321. flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
  322. flock/webapp/templates/partials/_env_vars_table.html +0 -23
  323. flock/webapp/templates/partials/_execution_form.html +0 -118
  324. flock/webapp/templates/partials/_execution_view_container.html +0 -28
  325. flock/webapp/templates/partials/_flock_file_list.html +0 -23
  326. flock/webapp/templates/partials/_flock_properties_form.html +0 -52
  327. flock/webapp/templates/partials/_flock_upload_form.html +0 -16
  328. flock/webapp/templates/partials/_header_flock_status.html +0 -5
  329. flock/webapp/templates/partials/_load_manager_view.html +0 -49
  330. flock/webapp/templates/partials/_registry_table.html +0 -25
  331. flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
  332. flock/webapp/templates/partials/_results_display.html +0 -78
  333. flock/webapp/templates/partials/_settings_env_content.html +0 -9
  334. flock/webapp/templates/partials/_settings_theme_content.html +0 -14
  335. flock/webapp/templates/partials/_settings_view.html +0 -36
  336. flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
  337. flock/webapp/templates/partials/_share_link_snippet.html +0 -35
  338. flock/webapp/templates/partials/_sidebar.html +0 -74
  339. flock/webapp/templates/partials/_streaming_results_container.html +0 -195
  340. flock/webapp/templates/partials/_structured_data_view.html +0 -40
  341. flock/webapp/templates/partials/_theme_preview.html +0 -36
  342. flock/webapp/templates/registry_viewer.html +0 -84
  343. flock/webapp/templates/shared_run_page.html +0 -140
  344. flock/workflow/__init__.py +0 -0
  345. flock/workflow/activities.py +0 -196
  346. flock/workflow/agent_activities.py +0 -24
  347. flock/workflow/agent_execution_activity.py +0 -202
  348. flock/workflow/flock_workflow.py +0 -214
  349. flock/workflow/temporal_config.py +0 -96
  350. flock/workflow/temporal_setup.py +0 -68
  351. flock_core-0.5.0b27.dist-info/METADATA +0 -274
  352. flock_core-0.5.0b27.dist-info/RECORD +0 -559
  353. flock_core-0.5.0b27.dist-info/entry_points.txt +0 -2
  354. /flock/{core/logging → logging}/formatters/themes.py +0 -0
  355. /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
  356. /flock/{core/mcp → mcp}/util/__init__.py +0 -0
  357. {flock_core-0.5.0b27.dist-info → flock_core-0.5.0b50.dist-info}/WHEEL +0 -0
@@ -1,832 +0,0 @@
1
- # src/flock/core/serialization/flock_serializer.py
2
- """Handles serialization and deserialization logic for Flock instances."""
3
-
4
- import importlib
5
- import importlib.util
6
- import inspect
7
- import os
8
- import re
9
- import sys
10
- from dataclasses import is_dataclass
11
- from typing import TYPE_CHECKING, Any, Literal
12
-
13
- from pydantic import BaseModel, create_model
14
-
15
- from flock.core.logging.logging import get_logger
16
-
17
- # Need registry access
18
- from flock.core.registry import get_registry
19
- from flock.core.serialization.serialization_utils import (
20
- # Assuming this handles basic serialization needs
21
- extract_pydantic_models_from_type_string,
22
- )
23
-
24
- if TYPE_CHECKING:
25
- from flock.core.flock import Flock
26
-
27
-
28
- logger = get_logger("serialization.flock")
29
- registry = get_registry()
30
-
31
-
32
- class FlockSerializer:
33
- """Provides static methods for serializing and deserializing Flock instances."""
34
-
35
- @staticmethod
36
- def serialize(
37
- flock_instance: "Flock",
38
- path_type: Literal["absolute", "relative"] = "relative",
39
- ) -> dict[str, Any]:
40
- """Convert Flock instance to dictionary representation.
41
-
42
- Args:
43
- flock_instance: The Flock instance to serialize.
44
- path_type: How file paths should be formatted ('absolute' or 'relative').
45
- """
46
- logger.debug(
47
- f"Serializing Flock instance '{flock_instance.name}' to dict."
48
- )
49
- # Use Pydantic's dump for base fields defined in Flock's model
50
- data = flock_instance.model_dump(mode="json", exclude_none=True)
51
- logger.info(
52
- f"Serializing Flock '{flock_instance.name}' with {len(flock_instance._agents)} agents"
53
- )
54
-
55
- data["agents"] = {}
56
- data["mcp_servers"] = {}
57
- custom_types = {}
58
- components = {}
59
-
60
- for name, server_instance in flock_instance._servers.items():
61
- try:
62
- # Servers handle their own serialization via their to_dict method
63
- server_data = server_instance.to_dict(path_type=path_type)
64
- data["mcp_servers"][name] = server_data
65
-
66
- # --- Extract Component Information ---
67
-
68
- # Modules
69
- if "modules" in server_data:
70
- for module_name, module_data in server_data[
71
- "modules"
72
- ].items():
73
- if module_data and "type" in module_data:
74
- component_type = module_data["type"]
75
- if component_type not in components:
76
- logger.debug(
77
- f"Adding module component '{component_type}' from module '{module_name}' in server '{name}'"
78
- )
79
- components[component_type] = (
80
- FlockSerializer._get_component_definition(
81
- component_type, path_type
82
- )
83
- )
84
- except Exception as e:
85
- logger.error(
86
- f"Failed to serialize server '{name}' within Flock: {e}",
87
- exc_info=True,
88
- )
89
-
90
- for name, agent_instance in flock_instance._agents.items():
91
- try:
92
- logger.debug(f"Serializing agent '{name}'")
93
- # Agents handle their own serialization via their to_dict
94
- agent_data = (
95
- agent_instance.to_dict()
96
- ) # This now uses the agent's refined to_dict
97
- data["agents"][name] = agent_data
98
-
99
- # --- Extract Types from Agent Signatures ---
100
- input_types = []
101
- if agent_instance.input:
102
- input_types = FlockSerializer._extract_types_from_signature(
103
- agent_instance.input
104
- )
105
- if input_types:
106
- logger.debug(
107
- f"Found input types in agent '{name}': {input_types}"
108
- )
109
-
110
- output_types = []
111
- if agent_instance.output:
112
- output_types = (
113
- FlockSerializer._extract_types_from_signature(
114
- agent_instance.output
115
- )
116
- )
117
- if output_types:
118
- logger.debug(
119
- f"Found output types in agent '{name}': {output_types}"
120
- )
121
-
122
- all_types = set(input_types + output_types)
123
- if all_types:
124
- custom_types.update(
125
- FlockSerializer._get_type_definitions(list(all_types))
126
- )
127
-
128
- # --- Extract Component Information ---
129
- # Evaluator
130
- if (
131
- "evaluator" in agent_data
132
- and agent_data["evaluator"]
133
- and "type" in agent_data["evaluator"]
134
- ):
135
- component_type = agent_data["evaluator"]["type"]
136
- if component_type not in components:
137
- logger.debug(
138
- f"Adding evaluator component '{component_type}' from agent '{name}'"
139
- )
140
- components[component_type] = (
141
- FlockSerializer._get_component_definition(
142
- component_type, path_type
143
- )
144
- )
145
-
146
- # Modules
147
- if "modules" in agent_data:
148
- for module_name, module_data in agent_data[
149
- "modules"
150
- ].items():
151
- if module_data and "type" in module_data:
152
- component_type = module_data["type"]
153
- if component_type not in components:
154
- logger.debug(
155
- f"Adding module component '{component_type}' from module '{module_name}' in agent '{name}'"
156
- )
157
- components[component_type] = (
158
- FlockSerializer._get_component_definition(
159
- component_type, path_type
160
- )
161
- )
162
-
163
- # Router
164
- if (
165
- "handoff_router" in agent_data
166
- and agent_data["handoff_router"]
167
- and "type" in agent_data["handoff_router"]
168
- ):
169
- component_type = agent_data["handoff_router"]["type"]
170
- if component_type not in components:
171
- logger.debug(
172
- f"Adding router component '{component_type}' from agent '{name}'"
173
- )
174
- components[component_type] = (
175
- FlockSerializer._get_component_definition(
176
- component_type, path_type
177
- )
178
- )
179
-
180
- # Description (Callables)
181
- if agent_data.get("description_callable"):
182
- logger.debug(
183
- f"Adding description callable '{agent_data['description_callable']}' from agent '{name}'"
184
- )
185
- description_callable_name = agent_data[
186
- "description_callable"
187
- ]
188
- description_callable = agent_instance.description
189
- path_str = registry.get_callable_path_string(
190
- description_callable
191
- )
192
- if path_str:
193
- logger.debug(
194
- f"Adding description callable '{description_callable_name}' (from path '{path_str}') to components"
195
- )
196
- components[description_callable_name] = (
197
- FlockSerializer._get_callable_definition(
198
- path_str, description_callable_name, path_type
199
- )
200
- )
201
-
202
- if agent_data.get("input_callable"):
203
- logger.debug(
204
- f"Adding input callable '{agent_data['input_callable']}' from agent '{name}'"
205
- )
206
- input_callable_name = agent_data["input_callable"]
207
- input_callable = agent_instance.input
208
- path_str = registry.get_callable_path_string(
209
- input_callable
210
- )
211
- if path_str:
212
- logger.debug(
213
- f"Adding input callable '{input_callable_name}' (from path '{path_str}') to components"
214
- )
215
- components[input_callable_name] = (
216
- FlockSerializer._get_callable_definition(
217
- path_str, input_callable_name, path_type
218
- )
219
- )
220
-
221
- if agent_data.get("output_callable"):
222
- logger.debug(
223
- f"Adding output callable '{agent_data['output_callable']}' from agent '{name}'"
224
- )
225
- output_callable_name = agent_data["output_callable"]
226
- output_callable = agent_instance.output
227
- path_str = registry.get_callable_path_string(
228
- output_callable
229
- )
230
- if path_str:
231
- logger.debug(
232
- f"Adding output callable '{output_callable_name}' (from path '{path_str}') to components"
233
- )
234
- components[output_callable_name] = (
235
- FlockSerializer._get_callable_definition(
236
- path_str, output_callable_name, path_type
237
- )
238
- )
239
-
240
- # Tools (Callables)
241
- if agent_data.get("tools"):
242
- logger.debug(
243
- f"Extracting tool information from agent '{name}': {agent_data['tools']}"
244
- )
245
- tool_objs = (
246
- agent_instance.tools if agent_instance.tools else []
247
- )
248
- for i, tool_name in enumerate(agent_data["tools"]):
249
- if tool_name not in components and i < len(tool_objs):
250
- tool = tool_objs[i]
251
- if callable(tool) and not isinstance(tool, type):
252
- path_str = (
253
- registry.get_callable_path_string(tool)
254
- )
255
- if path_str:
256
- logger.debug(
257
- f"Adding tool '{tool_name}' (from path '{path_str}') to components"
258
- )
259
- components[tool_name] = (
260
- FlockSerializer._get_callable_definition(
261
- path_str, tool_name, path_type
262
- )
263
- )
264
-
265
- except Exception as e:
266
- logger.error(
267
- f"Failed to serialize agent '{name}' within Flock: {e}",
268
- exc_info=True,
269
- )
270
-
271
- if custom_types:
272
- logger.info(f"Adding {len(custom_types)} custom type definitions")
273
- data["types"] = custom_types
274
- if components:
275
- logger.info(
276
- f"Adding {len(components)} component/callable definitions"
277
- )
278
- data["components"] = components
279
-
280
- data["dependencies"] = FlockSerializer._get_dependencies()
281
- data["metadata"] = {
282
- "path_type": path_type,
283
- "flock_version": "0.4.0",
284
- } # Example version
285
-
286
- logger.debug(f"Flock '{flock_instance.name}' serialization complete.")
287
- return data
288
-
289
- @staticmethod
290
- def deserialize(cls: type["Flock"], data: dict[str, Any]) -> "Flock":
291
- """Create Flock instance from dictionary representation."""
292
- # Import concrete types needed for instantiation
293
- from flock.core.flock import Flock # Import the actual class
294
- from flock.core.flock_agent import FlockAgent as ConcreteFlockAgent
295
- from flock.core.mcp.flock_mcp_server import (
296
- FlockMCPServer as ConcreteFlockMCPServer,
297
- )
298
-
299
- logger.debug(
300
- f"Deserializing Flock from dict. Provided keys: {list(data.keys())}"
301
- )
302
-
303
- metadata = data.pop("metadata", {})
304
- path_type = metadata.get(
305
- "path_type", "relative"
306
- ) # Default to relative for loading flexibility
307
- logger.debug(
308
- f"Using path_type '{path_type}' from metadata for component loading"
309
- )
310
-
311
- if "types" in data:
312
- logger.info(f"Processing {len(data['types'])} type definitions")
313
- FlockSerializer._register_type_definitions(data.pop("types"))
314
-
315
- if "components" in data:
316
- logger.info(
317
- f"Processing {len(data['components'])} component/callable definitions"
318
- )
319
- FlockSerializer._register_component_definitions(
320
- data.pop("components"), path_type
321
- )
322
-
323
- if "dependencies" in data:
324
- logger.debug(f"Checking {len(data['dependencies'])} dependencies")
325
- FlockSerializer._check_dependencies(data.pop("dependencies"))
326
-
327
- agents_data = data.pop("agents", {})
328
- server_data = data.pop("mcp_servers", {})
329
- logger.info(f"Found {len(server_data)} servers to deserialize")
330
- logger.info(f"Found {len(agents_data)} agents to deserialize")
331
-
332
- try:
333
- # Pass only fields defined in Flock's Pydantic model to constructor
334
- init_data = {
335
- k: v for k, v in data.items() if k in Flock.model_fields
336
- }
337
- logger.debug(
338
- f"Creating Flock instance with fields: {list(init_data.keys())}"
339
- )
340
- flock_instance = cls(**init_data) # Use cls which is Flock
341
- except Exception as e:
342
- logger.error(
343
- f"Pydantic validation/init failed for Flock: {e}", exc_info=True
344
- )
345
- raise ValueError(
346
- f"Failed to initialize Flock from dict: {e}"
347
- ) from e
348
-
349
- # Deserialize and add server AFTER Flock instance exists and BEFORE Agents have been added
350
- for name, server_data in server_data.items():
351
- try:
352
- logger.debug(f"Deserializing server '{name}'")
353
- server_data.setdefault("name", name)
354
- server_instance = ConcreteFlockMCPServer.from_dict(server_data)
355
- flock_instance.add_server(server_instance)
356
- logger.debug(f"Successfully added server '{name}' to Flock")
357
- except Exception as e:
358
- logger.error(
359
- f"Failed to deserialize/add server '{name}': {e}",
360
- exc_info=True,
361
- )
362
-
363
- # Deserialize and add agents AFTER Flock instance exists
364
- for name, agent_data in agents_data.items():
365
- try:
366
- logger.debug(f"Deserializing agent '{name}'")
367
- agent_data.setdefault("name", name)
368
- agent_instance = ConcreteFlockAgent.from_dict(agent_data)
369
- flock_instance.add_agent(agent_instance)
370
- logger.debug(f"Successfully added agent '{name}' to Flock")
371
- except Exception as e:
372
- logger.error(
373
- f"Failed to deserialize/add agent '{name}': {e}",
374
- exc_info=True,
375
- )
376
-
377
- logger.info(
378
- f"Successfully deserialized Flock '{flock_instance.name}' with {len(flock_instance._agents)} agents"
379
- )
380
- return flock_instance
381
-
382
- # --- Helper methods moved from Flock ---
383
- # (Keep all the _extract..., _get..., _register..., _create... methods here)
384
- # Ensure they use FlockSerializer._... or are standalone functions called directly.
385
- # Make static if they don't need instance state (which they shouldn't here).
386
-
387
- @staticmethod
388
- def _extract_types_from_signature(signature: str) -> list[str]:
389
- """Extract type names from an input/output signature string."""
390
- if not signature:
391
- return []
392
- from flock.core.util.input_resolver import (
393
- split_top_level, # Import locally if needed
394
- )
395
-
396
- type_names = set()
397
- try:
398
- parts = split_top_level(signature)
399
- for part in parts:
400
- if ":" in part:
401
- type_str = part.split(":", 1)[1].split("|", 1)[0].strip()
402
- # Use the more robust extractor
403
- models = extract_pydantic_models_from_type_string(type_str)
404
- for model in models:
405
- type_names.add(model.__name__)
406
- except Exception as e:
407
- logger.warning(
408
- f"Could not fully parse types from signature '{signature}': {e}"
409
- )
410
- return list(type_names)
411
-
412
- @staticmethod
413
- def _get_type_definitions(type_names: list[str]) -> dict[str, Any]:
414
- """Get definitions for the specified custom types from the registry."""
415
- type_definitions = {}
416
- for type_name in type_names:
417
- try:
418
- type_obj = registry.get_type(
419
- type_name
420
- ) # Throws KeyError if not found
421
- type_def = FlockSerializer._extract_type_definition(
422
- type_name, type_obj
423
- )
424
- if type_def:
425
- type_definitions[type_name] = type_def
426
- except KeyError:
427
- logger.warning(
428
- f"Type '{type_name}' requested but not found in registry."
429
- )
430
- except Exception as e:
431
- logger.warning(
432
- f"Could not extract definition for type {type_name}: {e}"
433
- )
434
- return type_definitions
435
-
436
- @staticmethod
437
- def _extract_type_definition(
438
- type_name: str, type_obj: type
439
- ) -> dict[str, Any] | None:
440
- """Extract a definition for a custom type (Pydantic or Dataclass)."""
441
- # Definition includes module path and schema/fields
442
- module_path = getattr(type_obj, "__module__", "unknown")
443
- type_def = {"module_path": module_path}
444
- try:
445
- if issubclass(type_obj, BaseModel):
446
- type_def["type"] = "pydantic.BaseModel"
447
- schema = type_obj.model_json_schema()
448
- if "title" in schema and schema["title"] == type_name:
449
- del schema["title"]
450
- type_def["schema"] = schema
451
- return type_def
452
- elif is_dataclass(type_obj):
453
- type_def["type"] = "dataclass"
454
- fields = {}
455
- for field_name, field in getattr(
456
- type_obj, "__dataclass_fields__", {}
457
- ).items():
458
- # Attempt to get a string representation of the type
459
- try:
460
- type_repr = str(field.type)
461
- except Exception:
462
- type_repr = "unknown"
463
- fields[field_name] = {
464
- "type": type_repr,
465
- "default": str(field.default)
466
- if field.default is not inspect.Parameter.empty
467
- else None,
468
- }
469
- type_def["fields"] = fields
470
- return type_def
471
- else:
472
- logger.debug(
473
- f"Type '{type_name}' is not Pydantic or Dataclass, skipping detailed definition."
474
- )
475
- return (
476
- None # Don't include non-data types in the 'types' section
477
- )
478
- except Exception as e:
479
- logger.warning(f"Error extracting definition for {type_name}: {e}")
480
- return None
481
-
482
- @staticmethod
483
- def _get_component_definition(
484
- component_type_name: str, path_type: Literal["absolute", "relative"]
485
- ) -> dict[str, Any]:
486
- """Get definition for a component type from the registry."""
487
- component_def = {
488
- "type": "flock_component",
489
- "module_path": "unknown",
490
- "file_path": None,
491
- }
492
- try:
493
- component_class = registry.get_component(
494
- component_type_name
495
- ) # Raises KeyError if not found
496
- component_def["module_path"] = getattr(
497
- component_class, "__module__", "unknown"
498
- )
499
- component_def["description"] = (
500
- inspect.getdoc(component_class)
501
- or f"{component_type_name} component"
502
- )
503
-
504
- # Get file path
505
- try:
506
- file_path_abs = inspect.getfile(component_class)
507
- component_def["file_path"] = (
508
- os.path.relpath(file_path_abs)
509
- if path_type == "relative"
510
- else file_path_abs
511
- )
512
- except (TypeError, ValueError) as e:
513
- logger.debug(
514
- f"Could not determine file path for component {component_type_name}: {e}"
515
- )
516
-
517
- except KeyError:
518
- logger.warning(
519
- f"Component class '{component_type_name}' not found in registry."
520
- )
521
- component_def["description"] = (
522
- f"{component_type_name} component (class not found in registry)"
523
- )
524
- except Exception as e:
525
- logger.warning(
526
- f"Could not extract full definition for component {component_type_name}: {e}"
527
- )
528
- return component_def
529
-
530
- @staticmethod
531
- def _get_callable_definition(
532
- callable_path: str,
533
- func_name: str,
534
- path_type: Literal["absolute", "relative"],
535
- ) -> dict[str, Any]:
536
- """Get definition for a callable using its registry path."""
537
- callable_def = {
538
- "type": "flock_callable",
539
- "module_path": "unknown",
540
- "file_path": None,
541
- }
542
- try:
543
- func = registry.get_callable(
544
- callable_path
545
- ) # Raises KeyError if not found
546
- callable_def["module_path"] = getattr(func, "__module__", "unknown")
547
- callable_def["description"] = (
548
- inspect.getdoc(func) or f"Callable function {func_name}"
549
- )
550
- # Get file path
551
- try:
552
- file_path_abs = inspect.getfile(func)
553
- callable_def["file_path"] = (
554
- os.path.relpath(file_path_abs)
555
- if path_type == "relative"
556
- else file_path_abs
557
- )
558
- except (TypeError, ValueError) as e:
559
- logger.debug(
560
- f"Could not determine file path for callable {callable_path}: {e}"
561
- )
562
-
563
- except KeyError:
564
- logger.warning(
565
- f"Callable '{callable_path}' (for tool '{func_name}') not found in registry."
566
- )
567
- callable_def["description"] = (
568
- f"Callable {func_name} (function not found in registry)"
569
- )
570
- except Exception as e:
571
- logger.warning(
572
- f"Could not extract full definition for callable {callable_path}: {e}"
573
- )
574
- return callable_def
575
-
576
- @staticmethod
577
- def _get_dependencies() -> list[str]:
578
- """Get list of core dependencies required by Flock."""
579
- # Basic static list for now
580
- return [
581
- "pydantic>=2.0.0",
582
- "flock-core>=0.4.0",
583
- ] # Update version as needed
584
-
585
- @staticmethod
586
- def _register_type_definitions(type_defs: dict[str, Any]) -> None:
587
- """Register type definitions from serialized data."""
588
- # (Logic remains largely the same as original, ensure it uses FlockRegistry)
589
- for type_name, type_def in type_defs.items():
590
- logger.debug(f"Registering type definition for: {type_name}")
591
- # Prioritize direct import
592
- module_path = type_def.get("module_path")
593
- registered = False
594
- if module_path and module_path != "unknown":
595
- try:
596
- module = importlib.import_module(module_path)
597
- if hasattr(module, type_name):
598
- type_obj = getattr(module, type_name)
599
- registry.register_type(type_obj, type_name)
600
- logger.info(
601
- f"Registered type '{type_name}' from module '{module_path}'"
602
- )
603
- registered = True
604
- except ImportError:
605
- logger.debug(
606
- f"Could not import module {module_path} for type {type_name}"
607
- )
608
- except Exception as e:
609
- logger.warning(
610
- f"Error registering type {type_name} from module: {e}"
611
- )
612
-
613
- if registered:
614
- continue
615
-
616
- # Attempt dynamic creation if direct import failed or wasn't possible
617
- type_kind = type_def.get("type")
618
- if type_kind == "pydantic.BaseModel" and "schema" in type_def:
619
- FlockSerializer._create_pydantic_model(type_name, type_def)
620
- elif type_kind == "dataclass" and "fields" in type_def:
621
- FlockSerializer._create_dataclass(type_name, type_def)
622
- else:
623
- logger.warning(
624
- f"Cannot dynamically register type '{type_name}' with kind '{type_kind}'"
625
- )
626
-
627
- @staticmethod
628
- def _create_pydantic_model(
629
- type_name: str, type_def: dict[str, Any]
630
- ) -> None:
631
- """Dynamically create and register a Pydantic model from schema."""
632
- # (Logic remains the same, ensure it uses registry.register_type)
633
- schema = type_def.get("schema", {})
634
- try:
635
- fields = {}
636
- properties = schema.get("properties", {})
637
- required = schema.get("required", [])
638
- for field_name, field_schema in properties.items():
639
- field_type = FlockSerializer._get_type_from_schema(field_schema)
640
- default = ... if field_name in required else None
641
- fields[field_name] = (field_type, default)
642
-
643
- DynamicModel = create_model(type_name, **fields)
644
- registry.register_type(DynamicModel, type_name)
645
- logger.info(
646
- f"Dynamically created and registered Pydantic model: {type_name}"
647
- )
648
- except Exception as e:
649
- logger.error(f"Failed to create Pydantic model {type_name}: {e}")
650
-
651
- @staticmethod
652
- def _get_type_from_schema(field_schema: dict[str, Any]) -> Any:
653
- """Convert JSON schema type to Python type."""
654
- # (Logic remains the same)
655
- schema_type = field_schema.get("type")
656
- type_mapping = {
657
- "string": str,
658
- "integer": int,
659
- "number": float,
660
- "boolean": bool,
661
- "array": list,
662
- "object": dict,
663
- }
664
- if schema_type in type_mapping:
665
- return type_mapping[schema_type]
666
- if "enum" in field_schema:
667
- from typing import Literal
668
-
669
- return Literal[tuple(field_schema["enum"])] # type: ignore
670
- return Any
671
-
672
- @staticmethod
673
- def _create_dataclass(type_name: str, type_def: dict[str, Any]) -> None:
674
- """Dynamically create and register a dataclass."""
675
- # (Logic remains the same, ensure it uses registry.register_type)
676
- from dataclasses import make_dataclass
677
-
678
- fields_def = type_def.get("fields", {})
679
- try:
680
- fields = []
681
- for field_name, field_props in fields_def.items():
682
- # Safely map type strings to actual types
683
- field_type_str = field_props.get("type", "str")
684
- type_mapping = {
685
- "str": str,
686
- "int": int,
687
- "float": float,
688
- "bool": bool,
689
- "list": list,
690
- "dict": dict,
691
- "List": list,
692
- "Dict": dict,
693
- "Any": Any,
694
- }
695
- field_type = type_mapping.get(field_type_str, Any)
696
- fields.append((field_name, field_type))
697
-
698
- DynamicDataclass = make_dataclass(type_name, fields)
699
- registry.register_type(DynamicDataclass, type_name)
700
- logger.info(
701
- f"Dynamically created and registered dataclass: {type_name}"
702
- )
703
- except Exception as e:
704
- logger.error(f"Failed to create dataclass {type_name}: {e}")
705
-
706
- @staticmethod
707
- def _register_component_definitions(
708
- component_defs: dict[str, Any],
709
- path_type: Literal["absolute", "relative"],
710
- ) -> None:
711
- """Register component/callable definitions from serialized data."""
712
- # (Logic remains the same, ensure it uses registry.register_component/register_callable)
713
- # Key change: Ensure file_path is handled correctly based on path_type from metadata
714
- for name, comp_def in component_defs.items():
715
- logger.debug(
716
- f"Registering component/callable definition for: {name}"
717
- )
718
- kind = comp_def.get("type")
719
- module_path = comp_def.get("module_path")
720
- file_path = comp_def.get("file_path")
721
- registered = False
722
-
723
- # Resolve file path if relative
724
- if (
725
- path_type == "relative"
726
- and file_path
727
- and not os.path.isabs(file_path)
728
- ):
729
- abs_file_path = os.path.abspath(file_path)
730
- logger.debug(
731
- f"Resolved relative path '{file_path}' to absolute '{abs_file_path}'"
732
- )
733
- file_path = abs_file_path # Use absolute path for loading
734
-
735
- # 1. Try importing from module_path
736
- if module_path and module_path != "unknown":
737
- try:
738
- module = importlib.import_module(module_path)
739
- if hasattr(module, name):
740
- obj = getattr(module, name)
741
- if kind == "flock_callable" and callable(obj):
742
- registry.register_callable(
743
- obj, name
744
- ) # Register by simple name
745
- # Also register by full path if possible
746
- full_path = f"{module_path}.{name}"
747
- if full_path != name:
748
- registry.register_callable(obj, full_path)
749
- logger.info(
750
- f"Registered callable '{name}' from module '{module_path}'"
751
- )
752
- registered = True
753
- elif kind == "flock_component" and isinstance(
754
- obj, type
755
- ):
756
- registry.register_component(obj, name)
757
- logger.info(
758
- f"Registered component '{name}' from module '{module_path}'"
759
- )
760
- registered = True
761
- except (ImportError, AttributeError):
762
- logger.debug(
763
- f"Could not import '{name}' from module '{module_path}', trying file path."
764
- )
765
- except Exception as e:
766
- logger.warning(
767
- f"Error registering '{name}' from module '{module_path}': {e}"
768
- )
769
-
770
- if registered:
771
- continue
772
-
773
- # 2. Try importing from file_path if module import failed or wasn't possible
774
- if file_path and os.path.exists(file_path):
775
- logger.debug(
776
- f"Attempting to load '{name}' from file: {file_path}"
777
- )
778
- try:
779
- mod_name = f"flock_dynamic_{name}" # Unique module name
780
- spec = importlib.util.spec_from_file_location(
781
- mod_name, file_path
782
- )
783
- if spec and spec.loader:
784
- module = importlib.util.module_from_spec(spec)
785
- sys.modules[spec.name] = (
786
- module # Important for pickle/cloudpickle
787
- )
788
- spec.loader.exec_module(module)
789
- if hasattr(module, name):
790
- obj = getattr(module, name)
791
- if kind == "flock_callable" and callable(obj):
792
- registry.register_callable(obj, name)
793
- logger.info(
794
- f"Registered callable '{name}' from file '{file_path}'"
795
- )
796
- elif kind == "flock_component" and isinstance(
797
- obj, type
798
- ):
799
- registry.register_component(obj, name)
800
- logger.info(
801
- f"Registered component '{name}' from file '{file_path}'"
802
- )
803
- else:
804
- logger.warning(
805
- f"'{name}' not found in loaded file '{file_path}'"
806
- )
807
- else:
808
- logger.warning(
809
- f"Could not create import spec for file '{file_path}'"
810
- )
811
- except Exception as e:
812
- logger.error(
813
- f"Error loading '{name}' from file '{file_path}': {e}",
814
- exc_info=True,
815
- )
816
- elif not registered:
817
- logger.warning(
818
- f"Could not register '{name}'. No valid module or file path found."
819
- )
820
-
821
- @staticmethod
822
- def _check_dependencies(dependencies: list[str]) -> None:
823
- """Check if required dependencies are available (basic check)."""
824
- # (Logic remains the same)
825
- for dep in dependencies:
826
- match = re.match(r"([^>=<]+)", dep)
827
- if match:
828
- pkg_name = match.group(1).replace("-", "_")
829
- try:
830
- importlib.import_module(pkg_name)
831
- except ImportError:
832
- logger.warning(f"Dependency '{dep}' might be missing.")