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,260 +0,0 @@
1
- # src/flock/core/agent/flock_agent_integration.py
2
- """Tool and server integration functionality for FlockAgent."""
3
-
4
- from collections.abc import Callable
5
- from functools import wraps
6
- from inspect import Parameter, signature
7
- from typing import TYPE_CHECKING, Any, TypeVar, cast
8
-
9
- from flock.core.context.context import FlockContext
10
- from flock.core.logging.logging import get_logger
11
- from flock.core.mcp.flock_mcp_server import FlockMCPServer
12
- from pydantic import BaseModel
13
- from flock.core.registry import get_registry
14
- from flock.core.serialization.serialization_utils import (
15
- _format_type_to_string,
16
- collect_pydantic_models,
17
- )
18
-
19
- if TYPE_CHECKING:
20
- from flock.core.flock_agent import FlockAgent
21
-
22
- logger = get_logger("agent.integration")
23
-
24
- R = TypeVar("R", bound=str)
25
-
26
-
27
- def adapt(prop_name: str, fn: Callable[..., R]) -> Callable[[FlockContext], R]:
28
- """Coerce *fn* into the canonical ``(ctx: FlockContext) -> str`` form.
29
-
30
- Acceptable signatures
31
- ---------------------
32
- 1. ``() -> str`` (no parameters)
33
- 2. ``(ctx: FlockContext) -> str`` (exactly one positional parameter)
34
-
35
- Anything else raises ``TypeError``.
36
-
37
- The wrapper also enforces at runtime that the result is ``str``.
38
- """
39
- if not callable(fn):
40
- raise TypeError(f"{prop_name} must be a callable, got {type(fn).__name__}")
41
-
42
- sig = signature(fn)
43
- params = list(sig.parameters.values())
44
-
45
- def _validate_result(res: object) -> R:
46
- if not isinstance(res, str):
47
- raise TypeError(
48
- f"{prop_name} callable must return str, got {type(res).__name__}"
49
- )
50
- return cast(R, res)
51
-
52
- # ── Case 1: () -> str ────────────────────────────────────────────────────
53
- if len(params) == 0:
54
-
55
- @wraps(fn)
56
- def _wrapped(ctx: FlockContext) -> R:
57
- return _validate_result(fn())
58
-
59
- return _wrapped
60
-
61
- # ── Case 2: (ctx) -> str ────────────────────────────────────────────────
62
- if len(params) == 1:
63
- p: Parameter = params[0]
64
- valid_kind = p.kind in (
65
- Parameter.POSITIONAL_ONLY,
66
- Parameter.POSITIONAL_OR_KEYWORD,
67
- )
68
- valid_annotation = p.annotation in (Parameter.empty, FlockContext)
69
- has_no_default = p.default is Parameter.empty
70
-
71
- if valid_kind and valid_annotation and has_no_default:
72
-
73
- @wraps(fn)
74
- def _wrapped(ctx: FlockContext) -> R:
75
- return _validate_result(fn(ctx)) # type: ignore[arg-type]
76
-
77
- return _wrapped
78
-
79
- # ── Anything else: reject ───────────────────────────────────────────────
80
- raise TypeError(
81
- f"{prop_name} callable must be () -> str or (ctx: FlockContext) -> str; "
82
- f"got signature {sig}"
83
- )
84
-
85
- class FlockAgentIntegration:
86
- """Handles tool and server integration for FlockAgent including MCP servers and callable tools."""
87
-
88
- def __init__(self, agent: "FlockAgent"):
89
- self.agent = agent
90
-
91
- def _resolve(self, raw: str | Callable[..., str], name: str, ctx: FlockContext | None) -> str | None:
92
- # Support Pydantic BaseModel classes (alternative I/O definitions)
93
- try:
94
- if isinstance(raw, type) and issubclass(raw, BaseModel):
95
- return self._build_spec_from_pydantic(raw)
96
- # Also support instances directly (use their class schema)
97
- if isinstance(raw, BaseModel):
98
- return self._build_spec_from_pydantic(type(raw))
99
- except Exception:
100
- # If introspection failed, fall through to normal handling
101
- pass
102
-
103
- if callable(raw):
104
- raw = adapt(name, raw)(ctx or FlockContext())
105
- return raw
106
-
107
- def _build_spec_from_pydantic(self, model_cls: type[BaseModel]) -> str:
108
- """Builds a flock I/O spec string from a Pydantic BaseModel class.
109
-
110
- Format per field: "name: type | description"; description omitted when empty.
111
- Also ensures involved Pydantic models are registered in the TypeRegistry
112
- so type resolution works when constructing DSPy signatures.
113
- """
114
- # Proactively register this model and any nested models
115
- try:
116
- registry = get_registry()
117
- registry.register_type(model_cls, name=model_cls.__name__)
118
- # Register nested Pydantic models used in type hints
119
- if hasattr(model_cls, "model_fields"):
120
- for _, f in model_cls.model_fields.items():
121
- ann = getattr(f, "annotation", None)
122
- for m in collect_pydantic_models(ann):
123
- registry.register_type(m, name=m.__name__)
124
- except Exception:
125
- # Registration best-effort; continue building spec
126
- pass
127
-
128
- fields = []
129
- # Pydantic v2: class-level model_fields
130
- if not hasattr(model_cls, "model_fields") or model_cls.model_fields is None: # type: ignore[attr-defined]
131
- return ""
132
-
133
- for name, field in model_cls.model_fields.items(): # type: ignore[attr-defined]
134
- type_hint = getattr(field, "annotation", None)
135
- type_str = _format_type_to_string(type_hint) if type_hint is not None else "str"
136
- desc = getattr(field, "description", None) or ""
137
- if desc:
138
- fields.append(f"{name}: {type_str} | {desc}")
139
- else:
140
- fields.append(f"{name}: {type_str}")
141
-
142
- return ", ".join(fields)
143
-
144
- def resolve_description(self, context: FlockContext | None = None) -> str | None:
145
- """Resolve the agent's description, handling callable descriptions."""
146
- return self._resolve(self.agent.description_spec, "description", context)
147
-
148
- def resolve_input(self, context: FlockContext | None = None) -> str | None:
149
- """Resolve the agent's input, handling callable inputs."""
150
- return self._resolve(self.agent.input_spec, "input", context)
151
-
152
- def resolve_output(self, context: FlockContext | None = None) -> str | None:
153
- """Resolve the agent's output, handling callable outputs."""
154
- return self._resolve(self.agent.output_spec, "output", context)
155
-
156
- def resolve_next_agent(self, context: FlockContext | None = None) -> str | None:
157
- """Resolve the next agent, handling callable next agents."""
158
- return self._resolve(self.agent.next_agent_spec, "next_agent", context)
159
-
160
- async def get_mcp_tools(self) -> list[Any]:
161
- """Get tools from registered MCP servers."""
162
- mcp_tools = []
163
- if self.agent.servers:
164
- from flock.core.registry import get_registry
165
-
166
- registry = get_registry() # Get the registry
167
- for server in self.agent.servers:
168
- registered_server: FlockMCPServer | None = None
169
- server_tools = []
170
- if isinstance(server, FlockMCPServer):
171
- # check if registered
172
- server_name = server.config.name
173
- registered_server = registry.get_server(
174
- server_name
175
- )
176
- else:
177
- # servers must be registered.
178
- registered_server = registry.get_server(
179
- name=server
180
- )
181
- if registered_server:
182
- server_tools = await registered_server.get_tools(
183
- agent_id=self.agent.agent_id,
184
- run_id=self.agent.context.run_id,
185
- )
186
- else:
187
- logger.warning(
188
- f"No Server with name '{server.config.name if isinstance(server, FlockMCPServer) else server}' registered! Skipping."
189
- )
190
- mcp_tools = mcp_tools + server_tools
191
- return mcp_tools
192
-
193
- async def execute_with_middleware(
194
- self,
195
- current_inputs: dict[str, Any],
196
- registered_tools: list[Any],
197
- mcp_tools: list[Any]
198
- ) -> dict[str, Any]:
199
- """Execute evaluator with optional DI middleware pipeline."""
200
- container = None
201
- if self.agent.context is not None:
202
- container = self.agent.context.get_variable("di.container")
203
-
204
- # If a MiddlewarePipeline is registered in DI, wrap the evaluator
205
- result: dict[str, Any] | None = None
206
-
207
- if container is not None:
208
- try:
209
- from wd.di.middleware import (
210
- MiddlewarePipeline,
211
- )
212
-
213
- pipeline: MiddlewarePipeline | None = None
214
- try:
215
- pipeline = container.get_service(MiddlewarePipeline)
216
- except Exception:
217
- pipeline = None
218
-
219
- if pipeline is not None:
220
- # Build execution chain where the evaluator is the terminal handler
221
-
222
- async def _final_handler():
223
- return await self.agent.evaluator.evaluate_core(
224
- self.agent, current_inputs, self.agent.context, registered_tools, mcp_tools
225
- )
226
-
227
- idx = 0
228
-
229
- async def _invoke_next():
230
- nonlocal idx
231
-
232
- if idx < len(pipeline._middleware):
233
- mw = pipeline._middleware[idx]
234
- idx += 1
235
- return await mw(self.agent.context, _invoke_next) # type: ignore[arg-type]
236
- return await _final_handler()
237
-
238
- # Execute pipeline
239
- result = await _invoke_next()
240
- else:
241
- # No pipeline registered, direct evaluation
242
- result = await self.agent.evaluator.evaluate_core(
243
- self.agent, current_inputs, self.agent.context, registered_tools, mcp_tools
244
- )
245
- except ImportError:
246
- # wd.di not installed – fall back
247
- result = await self.agent.evaluator.evaluate_core(
248
- self.agent, current_inputs, self.agent.context, registered_tools, mcp_tools
249
- )
250
- else:
251
- # No DI container – standard execution
252
- result = await self.agent.evaluator.evaluate_core(
253
- self.agent,
254
- current_inputs,
255
- self.agent.context,
256
- registered_tools,
257
- mcp_tools,
258
- )
259
-
260
- return result
@@ -1,186 +0,0 @@
1
- # src/flock/core/agent/flock_agent_lifecycle.py
2
- """Lifecycle management functionality for FlockAgent."""
3
-
4
- from typing import TYPE_CHECKING, Any
5
-
6
- from opentelemetry import trace
7
-
8
- from flock.core.logging.logging import get_logger
9
-
10
- if TYPE_CHECKING:
11
- from flock.core.flock_agent import FlockAgent
12
-
13
- logger = get_logger("agent.lifecycle")
14
- tracer = trace.get_tracer(__name__)
15
-
16
-
17
- class FlockAgentLifecycle:
18
- """Handles lifecycle management for FlockAgent including initialization, evaluation, and termination."""
19
-
20
- def __init__(self, agent: "FlockAgent"):
21
- self.agent = agent
22
-
23
- async def initialize(self, inputs: dict[str, Any]) -> None:
24
- """Initialize agent and run module initializers."""
25
- logger.debug(f"Initializing agent '{self.agent.name}'")
26
- with tracer.start_as_current_span("agent.initialize") as span:
27
- span.set_attribute("agent.name", self.agent.name)
28
- span.set_attribute("inputs", str(inputs))
29
- logger.info(
30
- f"agent.initialize",
31
- agent=self.agent.name,
32
- )
33
- try:
34
- for component in self.agent.get_enabled_components():
35
- await component.on_initialize(self.agent, inputs, self.agent.context)
36
- except Exception as component_error:
37
- logger.error(
38
- "Error during initialize",
39
- agent=self.agent.name,
40
- error=str(component_error),
41
- )
42
- span.record_exception(component_error)
43
-
44
- async def terminate(
45
- self, inputs: dict[str, Any], result: dict[str, Any]
46
- ) -> None:
47
- """Terminate agent and run module terminators."""
48
- logger.debug(f"Terminating agent '{self.agent.name}'")
49
- with tracer.start_as_current_span("agent.terminate") as span:
50
- span.set_attribute("agent.name", self.agent.name)
51
- span.set_attribute("inputs", str(inputs))
52
- span.set_attribute("result", str(result))
53
- logger.info(
54
- f"agent.terminate",
55
- agent=self.agent.name,
56
- )
57
- try:
58
- current_result = result
59
- for component in self.agent.get_enabled_components():
60
- tmp_result = await component.on_terminate(
61
- self.agent, inputs, self.agent.context, current_result
62
- )
63
- # If the component returns a result, use it
64
- if tmp_result:
65
- current_result = tmp_result
66
-
67
- if self.agent.config.write_to_file:
68
- self.agent._serialization._save_output(self.agent.name, current_result)
69
-
70
- if self.agent.config.wait_for_input:
71
- # simple input prompt
72
- input("Press Enter to continue...")
73
-
74
- except Exception as component_error:
75
- logger.error(
76
- "Error during terminate",
77
- agent=self.agent.name,
78
- error=str(component_error),
79
- )
80
- span.record_exception(component_error)
81
-
82
- async def on_error(self, error: Exception, inputs: dict[str, Any]) -> None:
83
- """Handle errors and run component error handlers."""
84
- logger.error(f"Error occurred in agent '{self.agent.name}': {error}")
85
- with tracer.start_as_current_span("agent.on_error") as span:
86
- span.set_attribute("agent.name", self.agent.name)
87
- span.set_attribute("inputs", str(inputs))
88
- try:
89
- for component in self.agent.get_enabled_components():
90
- await component.on_error(self.agent, inputs, self.agent.context, error)
91
- except Exception as component_error:
92
- logger.error(
93
- "Error during on_error",
94
- agent=self.agent.name,
95
- error=str(component_error),
96
- )
97
- span.record_exception(component_error)
98
-
99
- async def evaluate(self, inputs: dict[str, Any]) -> dict[str, Any]:
100
- """Core evaluation logic, calling the assigned evaluator and components."""
101
- if not self.agent.evaluator:
102
- raise RuntimeError(
103
- f"Agent '{self.agent.name}' has no evaluator assigned."
104
- )
105
- with tracer.start_as_current_span("agent.evaluate") as span:
106
- span.set_attribute("agent.name", self.agent.name)
107
- span.set_attribute("inputs", str(inputs))
108
- logger.info(
109
- f"agent.evaluate",
110
- agent=self.agent.name,
111
- )
112
-
113
- logger.debug(f"Evaluating agent '{self.agent.name}'")
114
- current_inputs = inputs
115
-
116
- # Pre-evaluate hooks
117
- for component in self.agent.get_enabled_components():
118
- current_inputs = await component.on_pre_evaluate(
119
- self.agent, current_inputs, self.agent.context
120
- )
121
-
122
- # Actual evaluation
123
- try:
124
- # Get tools and MCP tools through integration handler
125
- registered_tools = []
126
- if self.agent.tools:
127
- registered_tools = self.agent.tools
128
-
129
- # Retrieve available mcp_tools if the evaluator needs them
130
- mcp_tools = []
131
- if self.agent.servers:
132
- mcp_tools = await self.agent._integration.get_mcp_tools()
133
-
134
- # Filter tools based on the agent's whitelist (if it has been provided)
135
- if self.agent.tool_whitelist is not None and len(self.agent.tool_whitelist) > 0:
136
- for tool in mcp_tools:
137
- if hasattr(tool, "name") and tool.name not in self.agent.tool_whitelist:
138
- mcp_tools.remove(tool)
139
- for tool in registered_tools:
140
- if hasattr(tool, "__name__") and tool.__name__ not in self.agent.tool_whitelist:
141
- registered_tools.remove(tool)
142
-
143
- # --------------------------------------------------
144
- # Use evaluator component's evaluate_core method
145
- # --------------------------------------------------
146
- result = await self.agent.evaluator.evaluate_core(
147
- self.agent, current_inputs, self.agent.context, registered_tools, mcp_tools
148
- )
149
-
150
- except Exception as eval_error:
151
- logger.error(
152
- "Error during evaluate",
153
- agent=self.agent.name,
154
- error=str(eval_error),
155
- )
156
- span.record_exception(eval_error)
157
- await self.on_error(
158
- eval_error, current_inputs
159
- ) # Call error hook
160
- raise # Re-raise the exception
161
-
162
- # Post-evaluate hooks
163
- current_result = result
164
- for component in self.agent.get_enabled_components():
165
- tmp_result = await component.on_post_evaluate(
166
- self.agent,
167
- current_inputs,
168
- self.agent.context,
169
- current_result,
170
- )
171
- # If the component returns a result, use it
172
- if tmp_result:
173
- current_result = tmp_result
174
-
175
- # Handle routing logic
176
- router = self.agent.router
177
- if router:
178
- try:
179
- self.agent.next_agent = await router.determine_next_step(
180
- self.agent, current_result, self.agent.context
181
- )
182
- except Exception as e:
183
- logger.error(f"Error in routing: {e}")
184
-
185
- logger.debug(f"Evaluation completed for agent '{self.agent.name}'")
186
- return current_result