flock-core 0.5.0b28__py3-none-any.whl → 0.5.56b0__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 (359) 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.56b0.dist-info/METADATA +747 -0
  162. flock_core-0.5.56b0.dist-info/RECORD +398 -0
  163. flock_core-0.5.56b0.dist-info/entry_points.txt +2 -0
  164. {flock_core-0.5.0b28.dist-info → flock_core-0.5.56b0.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 -22
  197. flock/components/utility/example_utility_component.py +0 -250
  198. flock/components/utility/feedback_utility_component.py +0 -206
  199. flock/components/utility/memory_utility_component.py +0 -550
  200. flock/components/utility/metrics_utility_component.py +0 -700
  201. flock/config.py +0 -61
  202. flock/core/__init__.py +0 -110
  203. flock/core/agent/__init__.py +0 -16
  204. flock/core/agent/default_agent.py +0 -216
  205. flock/core/agent/flock_agent_components.py +0 -104
  206. flock/core/agent/flock_agent_execution.py +0 -101
  207. flock/core/agent/flock_agent_integration.py +0 -260
  208. flock/core/agent/flock_agent_lifecycle.py +0 -186
  209. flock/core/agent/flock_agent_serialization.py +0 -381
  210. flock/core/api/__init__.py +0 -10
  211. flock/core/api/custom_endpoint.py +0 -45
  212. flock/core/api/endpoints.py +0 -254
  213. flock/core/api/main.py +0 -162
  214. flock/core/api/models.py +0 -97
  215. flock/core/api/run_store.py +0 -224
  216. flock/core/api/runner.py +0 -44
  217. flock/core/api/service.py +0 -214
  218. flock/core/component/__init__.py +0 -15
  219. flock/core/component/agent_component_base.py +0 -309
  220. flock/core/component/evaluation_component.py +0 -62
  221. flock/core/component/routing_component.py +0 -74
  222. flock/core/component/utility_component.py +0 -69
  223. flock/core/config/flock_agent_config.py +0 -58
  224. flock/core/config/scheduled_agent_config.py +0 -40
  225. flock/core/context/context.py +0 -213
  226. flock/core/context/context_manager.py +0 -37
  227. flock/core/context/context_vars.py +0 -10
  228. flock/core/evaluation/utils.py +0 -396
  229. flock/core/execution/batch_executor.py +0 -369
  230. flock/core/execution/evaluation_executor.py +0 -438
  231. flock/core/execution/local_executor.py +0 -31
  232. flock/core/execution/opik_executor.py +0 -103
  233. flock/core/execution/temporal_executor.py +0 -164
  234. flock/core/flock.py +0 -634
  235. flock/core/flock_agent.py +0 -336
  236. flock/core/flock_factory.py +0 -613
  237. flock/core/flock_scheduler.py +0 -166
  238. flock/core/flock_server_manager.py +0 -136
  239. flock/core/interpreter/python_interpreter.py +0 -689
  240. flock/core/mcp/__init__.py +0 -1
  241. flock/core/mcp/flock_mcp_server.py +0 -680
  242. flock/core/mcp/mcp_client_manager.py +0 -201
  243. flock/core/mcp/types/__init__.py +0 -1
  244. flock/core/mixin/dspy_integration.py +0 -403
  245. flock/core/mixin/prompt_parser.py +0 -125
  246. flock/core/orchestration/__init__.py +0 -15
  247. flock/core/orchestration/flock_batch_processor.py +0 -94
  248. flock/core/orchestration/flock_evaluator.py +0 -113
  249. flock/core/orchestration/flock_execution.py +0 -295
  250. flock/core/orchestration/flock_initialization.py +0 -149
  251. flock/core/orchestration/flock_server_manager.py +0 -67
  252. flock/core/orchestration/flock_web_server.py +0 -117
  253. flock/core/registry/__init__.py +0 -45
  254. flock/core/registry/agent_registry.py +0 -69
  255. flock/core/registry/callable_registry.py +0 -139
  256. flock/core/registry/component_discovery.py +0 -142
  257. flock/core/registry/component_registry.py +0 -64
  258. flock/core/registry/config_mapping.py +0 -64
  259. flock/core/registry/decorators.py +0 -137
  260. flock/core/registry/registry_hub.py +0 -205
  261. flock/core/registry/server_registry.py +0 -57
  262. flock/core/registry/type_registry.py +0 -86
  263. flock/core/serialization/__init__.py +0 -13
  264. flock/core/serialization/callable_registry.py +0 -52
  265. flock/core/serialization/flock_serializer.py +0 -832
  266. flock/core/serialization/json_encoder.py +0 -41
  267. flock/core/serialization/secure_serializer.py +0 -175
  268. flock/core/serialization/serializable.py +0 -342
  269. flock/core/serialization/serialization_utils.py +0 -412
  270. flock/core/util/file_path_utils.py +0 -223
  271. flock/core/util/hydrator.py +0 -309
  272. flock/core/util/input_resolver.py +0 -164
  273. flock/core/util/loader.py +0 -59
  274. flock/core/util/splitter.py +0 -219
  275. flock/di.py +0 -27
  276. flock/platform/docker_tools.py +0 -49
  277. flock/platform/jaeger_install.py +0 -86
  278. flock/webapp/__init__.py +0 -1
  279. flock/webapp/app/__init__.py +0 -0
  280. flock/webapp/app/api/__init__.py +0 -0
  281. flock/webapp/app/api/agent_management.py +0 -241
  282. flock/webapp/app/api/execution.py +0 -709
  283. flock/webapp/app/api/flock_management.py +0 -129
  284. flock/webapp/app/api/registry_viewer.py +0 -30
  285. flock/webapp/app/chat.py +0 -665
  286. flock/webapp/app/config.py +0 -104
  287. flock/webapp/app/dependencies.py +0 -117
  288. flock/webapp/app/main.py +0 -1070
  289. flock/webapp/app/middleware.py +0 -113
  290. flock/webapp/app/models_ui.py +0 -7
  291. flock/webapp/app/services/__init__.py +0 -0
  292. flock/webapp/app/services/feedback_file_service.py +0 -363
  293. flock/webapp/app/services/flock_service.py +0 -337
  294. flock/webapp/app/services/sharing_models.py +0 -81
  295. flock/webapp/app/services/sharing_store.py +0 -762
  296. flock/webapp/app/templates/theme_mapper.html +0 -326
  297. flock/webapp/app/theme_mapper.py +0 -812
  298. flock/webapp/app/utils.py +0 -85
  299. flock/webapp/run.py +0 -215
  300. flock/webapp/static/css/chat.css +0 -301
  301. flock/webapp/static/css/components.css +0 -167
  302. flock/webapp/static/css/header.css +0 -39
  303. flock/webapp/static/css/layout.css +0 -46
  304. flock/webapp/static/css/sidebar.css +0 -127
  305. flock/webapp/static/css/two-pane.css +0 -48
  306. flock/webapp/templates/base.html +0 -200
  307. flock/webapp/templates/chat.html +0 -152
  308. flock/webapp/templates/chat_settings.html +0 -19
  309. flock/webapp/templates/flock_editor.html +0 -16
  310. flock/webapp/templates/index.html +0 -12
  311. flock/webapp/templates/partials/_agent_detail_form.html +0 -93
  312. flock/webapp/templates/partials/_agent_list.html +0 -18
  313. flock/webapp/templates/partials/_agent_manager_view.html +0 -51
  314. flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
  315. flock/webapp/templates/partials/_chat_container.html +0 -15
  316. flock/webapp/templates/partials/_chat_messages.html +0 -57
  317. flock/webapp/templates/partials/_chat_settings_form.html +0 -85
  318. flock/webapp/templates/partials/_create_flock_form.html +0 -50
  319. flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
  320. flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
  321. flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
  322. flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
  323. flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
  324. flock/webapp/templates/partials/_env_vars_table.html +0 -23
  325. flock/webapp/templates/partials/_execution_form.html +0 -118
  326. flock/webapp/templates/partials/_execution_view_container.html +0 -28
  327. flock/webapp/templates/partials/_flock_file_list.html +0 -23
  328. flock/webapp/templates/partials/_flock_properties_form.html +0 -52
  329. flock/webapp/templates/partials/_flock_upload_form.html +0 -16
  330. flock/webapp/templates/partials/_header_flock_status.html +0 -5
  331. flock/webapp/templates/partials/_load_manager_view.html +0 -49
  332. flock/webapp/templates/partials/_registry_table.html +0 -25
  333. flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
  334. flock/webapp/templates/partials/_results_display.html +0 -78
  335. flock/webapp/templates/partials/_settings_env_content.html +0 -9
  336. flock/webapp/templates/partials/_settings_theme_content.html +0 -14
  337. flock/webapp/templates/partials/_settings_view.html +0 -36
  338. flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
  339. flock/webapp/templates/partials/_share_link_snippet.html +0 -35
  340. flock/webapp/templates/partials/_sidebar.html +0 -74
  341. flock/webapp/templates/partials/_streaming_results_container.html +0 -195
  342. flock/webapp/templates/partials/_structured_data_view.html +0 -40
  343. flock/webapp/templates/partials/_theme_preview.html +0 -36
  344. flock/webapp/templates/registry_viewer.html +0 -84
  345. flock/webapp/templates/shared_run_page.html +0 -140
  346. flock/workflow/__init__.py +0 -0
  347. flock/workflow/activities.py +0 -196
  348. flock/workflow/agent_activities.py +0 -24
  349. flock/workflow/agent_execution_activity.py +0 -202
  350. flock/workflow/flock_workflow.py +0 -214
  351. flock/workflow/temporal_config.py +0 -96
  352. flock/workflow/temporal_setup.py +0 -68
  353. flock_core-0.5.0b28.dist-info/METADATA +0 -274
  354. flock_core-0.5.0b28.dist-info/RECORD +0 -561
  355. flock_core-0.5.0b28.dist-info/entry_points.txt +0 -2
  356. /flock/{core/logging → logging}/formatters/themes.py +0 -0
  357. /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
  358. /flock/{core/mcp → mcp}/util/__init__.py +0 -0
  359. {flock_core-0.5.0b28.dist-info → flock_core-0.5.56b0.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.")