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,309 +0,0 @@
1
- # src/flock/core/util/hydrator.py (Revised - Simpler)
2
-
3
- import asyncio
4
- import json
5
- from typing import (
6
- Any,
7
- TypeVar,
8
- get_type_hints,
9
- )
10
-
11
- from pydantic import BaseModel
12
-
13
- # Import necessary Flock components
14
- from flock.core import Flock, FlockFactory
15
- from flock.core.logging.logging import get_logger
16
-
17
- # Import helper to format type hints back to strings
18
- from flock.core.serialization.serialization_utils import _format_type_to_string
19
-
20
- logger = get_logger("hydrator")
21
- T = TypeVar("T", bound=BaseModel)
22
-
23
-
24
- def flockclass(model: str = "openai/gpt-4o", agent_description: str | None = None):
25
- """Decorator to add a .hydrate() method to a Pydantic class.
26
- Leverages a dynamic Flock agent to fill missing (None) fields.
27
-
28
- Args:
29
- model: The default LLM model identifier to use for hydration.
30
- agent_description: An optional description for the dynamically created agent.
31
- """
32
-
33
- def decorator(cls: type[T]) -> type[T]:
34
- if not issubclass(cls, BaseModel):
35
- raise TypeError(
36
- "@flockclass can only decorate Pydantic BaseModel subclasses."
37
- )
38
-
39
- # Store metadata on the class
40
- setattr(cls, "__flock_model__", model)
41
- setattr(cls, "__flock_agent_description__", agent_description)
42
-
43
- # --- Attach the async hydrate method directly ---
44
- async def hydrate_async(self) -> T:
45
- """Hydrates the object by filling None fields using a dynamic Flock agent.
46
- Uses existing non-None fields as input context.
47
- Returns the hydrated object (self).
48
- """
49
- class_name = self.__class__.__name__
50
- logger.info(f"Starting hydration for instance of {class_name}")
51
-
52
- # Get field information
53
- all_fields, type_hints = _get_model_fields(self, class_name)
54
- if all_fields is None or type_hints is None:
55
- return self # Return early if field introspection failed
56
-
57
- # Identify existing and missing fields
58
- existing_data, missing_fields = _identify_fields(self, all_fields)
59
-
60
- if not missing_fields:
61
- logger.info(f"No fields to hydrate for {class_name} instance.")
62
- return self
63
-
64
- logger.debug(f"{class_name}: Fields to hydrate: {missing_fields}")
65
- logger.debug(
66
- f"{class_name}: Existing data for context: {json.dumps(existing_data, default=str)}"
67
- )
68
-
69
- # Create agent signatures
70
- input_str, output_str, input_parts = _build_agent_signatures(
71
- existing_data,
72
- missing_fields,
73
- type_hints,
74
- all_fields,
75
- class_name,
76
- )
77
-
78
- # Create and run agent
79
- result = await _run_hydration_agent(
80
- self,
81
- input_str,
82
- output_str,
83
- input_parts,
84
- existing_data,
85
- class_name,
86
- )
87
- if result is None:
88
- return self # Return early if agent run failed
89
-
90
- # Update object fields with results
91
- _update_fields_with_results(self, result, missing_fields, class_name)
92
-
93
- return self
94
-
95
- # --- Attach the sync hydrate method directly ---
96
- def hydrate(self) -> T:
97
- """Synchronous wrapper for the async hydrate method."""
98
- try:
99
- # Try to get the current running loop
100
- loop = asyncio.get_running_loop()
101
-
102
- # If we reach here, there is a running loop
103
- if loop.is_running():
104
- # This runs the coroutine in the existing loop from a different thread
105
- import concurrent.futures
106
-
107
- with concurrent.futures.ThreadPoolExecutor() as executor:
108
- future = executor.submit(asyncio.run, hydrate_async(self))
109
- return future.result()
110
- else:
111
- # There's a loop but it's not running
112
- return loop.run_until_complete(hydrate_async(self))
113
-
114
- except RuntimeError: # No running loop
115
- # If no loop is running, create a new one and run our coroutine
116
- return asyncio.run(hydrate_async(self))
117
-
118
- # Attach the methods to the class
119
- setattr(cls, "hydrate_async", hydrate_async)
120
- setattr(cls, "hydrate", hydrate)
121
- setattr(cls, "hydrate_sync", hydrate) # Alias for backward compatibility
122
-
123
- logger.debug(f"Attached hydrate methods to class {cls.__name__}")
124
- return cls
125
-
126
- return decorator
127
-
128
-
129
- def _get_model_fields(
130
- obj: BaseModel, class_name: str
131
- ) -> tuple[dict | None, dict | None]:
132
- """Extracts field information from a Pydantic model, handling v1/v2 compatibility."""
133
- try:
134
- if hasattr(obj, "model_fields"): # Pydantic v2
135
- all_fields = obj.model_fields
136
- type_hints = {name: field.annotation for name, field in all_fields.items()}
137
- else: # Pydantic v1 fallback
138
- type_hints = get_type_hints(obj.__class__)
139
- all_fields = getattr(obj, "__fields__", {name: None for name in type_hints})
140
- return all_fields, type_hints
141
- except Exception as e:
142
- logger.error(
143
- f"Could not get fields/type hints for {class_name}: {e}",
144
- exc_info=True,
145
- )
146
- return None, None
147
-
148
-
149
- def _identify_fields(
150
- obj: BaseModel, all_fields: dict
151
- ) -> tuple[dict[str, Any], list[str]]:
152
- """Identifies existing (non-None) and missing fields in the object."""
153
- existing_data: dict[str, Any] = {}
154
- missing_fields: list[str] = []
155
-
156
- for field_name in all_fields:
157
- if hasattr(obj, field_name): # Check if attribute exists
158
- value = getattr(obj, field_name)
159
- if value is not None:
160
- existing_data[field_name] = value
161
- else:
162
- missing_fields.append(field_name)
163
-
164
- return existing_data, missing_fields
165
-
166
-
167
- def _build_agent_signatures(
168
- existing_data: dict[str, Any],
169
- missing_fields: list[str],
170
- type_hints: dict,
171
- all_fields: dict,
172
- class_name: str,
173
- ) -> tuple[str, str, list]:
174
- """Builds input and output signatures for the dynamic agent."""
175
- # Input signature based on existing data
176
- input_parts = []
177
- for name in existing_data:
178
- field_type = type_hints.get(name, Any)
179
- type_str = _format_type_to_string(field_type)
180
- field_info = all_fields.get(name)
181
- field_desc = getattr(field_info, "description", "")
182
- if field_desc:
183
- input_parts.append(f"{name}: {type_str} | {field_desc}")
184
- else:
185
- input_parts.append(f"{name}: {type_str}")
186
-
187
- input_str = (
188
- ", ".join(input_parts)
189
- if input_parts
190
- else "context_info: dict | Optional context if no fields have values"
191
- )
192
-
193
- # Output signature based on missing fields
194
- output_parts = []
195
- for name in missing_fields:
196
- field_type = type_hints.get(name, Any)
197
- type_str = _format_type_to_string(field_type)
198
- field_info = all_fields.get(name)
199
- field_desc = getattr(field_info, "description", "")
200
- if field_desc:
201
- output_parts.append(f"{name}: {type_str} | {field_desc}")
202
- else:
203
- output_parts.append(f"{name}: {type_str}")
204
-
205
- output_str = ", ".join(output_parts)
206
-
207
- return input_str, output_str, input_parts
208
-
209
-
210
- async def _run_hydration_agent(
211
- obj: BaseModel,
212
- input_str: str,
213
- output_str: str,
214
- input_parts: list,
215
- existing_data: dict[str, Any],
216
- class_name: str,
217
- ) -> dict[str, Any] | None:
218
- """Creates and runs a dynamic Flock agent to hydrate the object."""
219
- # Agent configuration
220
- agent_name = f"hydrator_{class_name}_{id(obj)}"
221
- description = (
222
- getattr(obj, "__flock_agent_description__", None)
223
- or f"Agent that completes missing data for a {class_name} object."
224
- )
225
- hydration_model = getattr(obj, "__flock_model__", "openai/gpt-4o")
226
-
227
- logger.debug(f"Creating dynamic agent '{agent_name}' for {class_name}")
228
- logger.debug(f" Input Schema: {input_str}")
229
- logger.debug(f" Output Schema: {output_str}")
230
-
231
- try:
232
- # Create agent
233
- dynamic_agent = FlockFactory.create_default_agent(
234
- name=agent_name,
235
- description=description,
236
- input=input_str,
237
- output=output_str,
238
- model=hydration_model,
239
- no_output=True,
240
- use_cache=False,
241
- )
242
-
243
- # Create temporary Flock
244
- temp_flock = Flock(
245
- name=f"temp_hydrator_flock_{agent_name}",
246
- model=hydration_model,
247
- show_flock_banner=False,
248
- )
249
- temp_flock.add_agent(dynamic_agent)
250
-
251
- # Prepare input data
252
- agent_input_data = (
253
- existing_data
254
- if input_parts
255
- else {"context_info": {"object_type": class_name}}
256
- )
257
-
258
- logger.info(f"Running hydration agent '{agent_name}' for {class_name}...")
259
-
260
- # Run agent
261
- result = await temp_flock.run_async(
262
- agent=agent_name,
263
- input=agent_input_data,
264
- box_result=False,
265
- )
266
- logger.info(f"Hydration agent returned for {class_name}: {list(result.keys())}")
267
-
268
- return result
269
-
270
- except Exception as e:
271
- logger.error(
272
- f"Hydration agent creation or run failed for {class_name}: {e}",
273
- exc_info=True,
274
- )
275
- return None
276
-
277
-
278
- def _update_fields_with_results(
279
- obj: BaseModel,
280
- result: dict[str, Any],
281
- missing_fields: list[str],
282
- class_name: str,
283
- ) -> None:
284
- """Updates object fields with results from the hydration agent."""
285
- updated_count = 0
286
- for field_name in missing_fields:
287
- if field_name in result:
288
- try:
289
- setattr(obj, field_name, result[field_name])
290
- logger.debug(
291
- f"Hydrated field '{field_name}' in {class_name} with value: {getattr(obj, field_name)}"
292
- )
293
- updated_count += 1
294
- except Exception as e:
295
- logger.warning(
296
- f"Failed to set hydrated value for '{field_name}' in {class_name}: {e}. Value received: {result[field_name]}"
297
- )
298
- else:
299
- logger.warning(
300
- f"Hydration result missing expected field for {class_name}: '{field_name}'"
301
- )
302
-
303
- logger.info(
304
- f"Hydration complete for {class_name}. Updated {updated_count}/{len(missing_fields)} fields."
305
- )
306
-
307
-
308
- # Ensure helper functions are available
309
- # from flock.core.serialization.serialization_utils import _format_type_to_string
@@ -1,164 +0,0 @@
1
- """Utility functions for resolving input keys to their corresponding values."""
2
-
3
- from flock.core.context.context import FlockContext
4
- from flock.core.util.splitter import split_top_level
5
-
6
-
7
- def get_callable_members(obj):
8
- """Extract all callable (methods/functions) members from a module or class.
9
- Returns a list of callable objects.
10
- """
11
- import inspect
12
-
13
- # Get all members of the object
14
- members = inspect.getmembers(obj)
15
-
16
- # Filter for callable members that don't start with underscore (to exclude private/special methods)
17
- callables = [
18
- member[1]
19
- for member in members
20
- if inspect.isroutine(member[1]) and not member[0].startswith("_")
21
- ]
22
-
23
- return callables
24
-
25
-
26
- def _parse_keys(keys: list[str]) -> list[str]:
27
- """Split a comma‐separated string and strip any type annotations.
28
-
29
- For example, "a, b: list[str]" becomes ["a", "b"].
30
- """
31
- res_keys = []
32
- for key in keys:
33
- if "|" in key:
34
- key = key.split("|")[0].strip()
35
- if ":" in key:
36
- key = key.split(":")[0].strip()
37
- res_keys.append(key)
38
- return res_keys
39
-
40
-
41
- def top_level_to_keys(s: str) -> list[str]:
42
- """Convert a top-level comma-separated string to a list of keys."""
43
- top_level_split = split_top_level(s)
44
- return _parse_keys(top_level_split)
45
-
46
-
47
- def resolve_inputs(
48
- input_spec: str,
49
- context: FlockContext,
50
- previous_agent_name: str,
51
- previous_agent_output:str,
52
- previous_agent_handoff_strategy:str,
53
- previous_agent_handoff_map:dict[str, str]
54
- ) -> dict:
55
- """Build a dictionary of inputs based on the input specification string and the provided context.
56
-
57
- The lookup rules are:
58
- - "context" (case-insensitive): returns the entire context.
59
- - "context.property": returns an attribute from the context.
60
- - "def.agent_name": returns the agent definition for the given agent.
61
- - "agent_name": returns the most up2date record from the given agent's history.
62
- - "agent_name.property": returns the value of a property from the state variable keyed by "agent_name.property".
63
- - "property": searches the history for the most recent value of a property.
64
- - Otherwise, if no matching value is found, fallback to the FLOCK_INITIAL_INPUT.
65
-
66
- -> Recommendations:
67
- - prefix your agent variables with the agent name or a short handle to avoid conflicts.
68
- eg. agent name: "idea_agent", variable: "ia_idea" (ia = idea agent)
69
- - or set hand off mode to strict to avoid conflicts.
70
- with strict mode, the agent will only accept inputs from the previous agent.
71
-
72
-
73
- Strategy for passing data to the next agent.
74
-
75
- Example:
76
- ReviewAgent.next_agent = SummaryAgent
77
- ReviewAgent(output = "text:str, keywords:list[str], rating:int")
78
- SummaryAgent(input = "text:str, title:str")
79
-
80
- 'append' means the difference in signature is appended to the next agent's input signature.
81
- SummaryAgent(input = "text:str, title:str, keywords:list[str], rating:int")
82
-
83
- 'override' means the target agent's signature is getting overriden.
84
- SummaryAgent(input = "text:str, keywords:list[str], rating:int")
85
-
86
- 'static' means the the target agent's signature is not changed at all.
87
- If source agent has no output fields that match the target agent's input,
88
- there will be no data passed to the next agent.
89
- SummaryAgent(input = "text:str, title:str")
90
-
91
- 'map' means the source agent's output is mapped to the target agent's input
92
- based on 'handoff_map' configuration.
93
-
94
- Args:
95
- input_spec: Comma-separated input keys (e.g., "query" or "agent_name.property").
96
- context: A FlockContext instance.
97
-
98
- Returns:
99
- A dictionary mapping each input key to its resolved value.
100
- """
101
- split_input = split_top_level(input_spec)
102
- keys = _parse_keys(split_input)
103
- inputs = {}
104
-
105
- def _normalize_empty_string(val):
106
- """Treat empty string inputs as None to match None semantics.
107
-
108
- This aligns behavior so passing "" behaves like passing None
109
- for agent input properties.
110
- """
111
- if isinstance(val, str) and val == "":
112
- return None
113
- return val
114
-
115
- for key in keys:
116
- split_key = key.split(".")
117
-
118
- # Case 1: A single key
119
- if len(split_key) == 1:
120
- # Special keyword: "context"
121
- if key.lower() == "context":
122
- inputs[key] = context
123
- continue
124
-
125
- # Try to get a historic record for an agent (if any)
126
- historic_records = context.get_agent_history(key)
127
- if historic_records:
128
- # You may choose to pass the entire record or just its data.
129
- inputs[key] = historic_records[0].data
130
- continue
131
-
132
- # Fallback to the most recent value in the state
133
- historic_value = context.get_most_recent_value(key)
134
- if historic_value is not None:
135
- inputs[key] = _normalize_empty_string(historic_value)
136
- continue
137
-
138
- # Fallback to the initial input
139
- var_value = context.get_variable(key)
140
- if var_value is not None:
141
- inputs[key] = _normalize_empty_string(var_value)
142
- continue
143
-
144
- inputs[key] = _normalize_empty_string(context.get_variable("flock." + key))
145
-
146
- # Case 2: A compound key (e.g., "agent_name.property" or "context.property")
147
- elif len(split_key) == 2:
148
- entity_name, property_name = split_key
149
-
150
- if entity_name.lower() == "context":
151
- # Try to fetch the attribute from the context
152
- inputs[key] = _normalize_empty_string(getattr(context, property_name, None))
153
- continue
154
-
155
- if entity_name.lower() == "def":
156
- # Return the agent definition for the given property name
157
- inputs[key] = _normalize_empty_string(context.get_agent_definition(property_name))
158
- continue
159
-
160
- # Otherwise, attempt to look up a state variable with the key "entity_name.property_name"
161
- inputs[key] = _normalize_empty_string(context.get_variable(f"{entity_name}.{property_name}"))
162
- continue
163
-
164
- return inputs
flock/core/util/loader.py DELETED
@@ -1,59 +0,0 @@
1
- # src/flock/core/loader.py
2
- """Provides functionality to load Flock instances from files."""
3
-
4
- from pathlib import Path
5
- from typing import TYPE_CHECKING
6
-
7
- # Use TYPE_CHECKING to avoid runtime circular import if Flock imports this module indirectly
8
- if TYPE_CHECKING:
9
- from flock.core.flock import Flock
10
-
11
- # Import locally within the function to ensure Serializable methods are available
12
- # from .serialization.serializable import Serializable # Serializable defines the file methods
13
-
14
- # Cloudpickle check needs to be top-level
15
- try:
16
- import cloudpickle
17
-
18
- PICKLE_AVAILABLE = True
19
- except ImportError:
20
- PICKLE_AVAILABLE = False
21
-
22
-
23
- def load_flock_from_file(file_path: str) -> "Flock":
24
- """Load a Flock instance from various file formats (detects type)."""
25
- # Import Flock locally within the function to avoid circular dependency at module level
26
- from flock.core.flock import Flock
27
-
28
- p = Path(file_path)
29
- if not p.exists():
30
- raise FileNotFoundError(f"Flock file not found: {file_path}")
31
-
32
- try:
33
- if p.suffix.lower() in [".yaml", ".yml"]:
34
- return Flock.from_yaml_file(p)
35
- elif p.suffix.lower() == ".json":
36
- # Assuming from_json is available via Serializable or directly on Flock
37
- return Flock.from_json(p.read_text())
38
- elif p.suffix.lower() == ".msgpack":
39
- # Assuming from_msgpack_file is available via Serializable or directly on Flock
40
- return Flock.from_msgpack_file(p)
41
- elif p.suffix.lower() == ".pkl":
42
- if PICKLE_AVAILABLE:
43
- # Assuming from_pickle_file is available via Serializable or directly on Flock
44
- return Flock.from_pickle_file(p)
45
- else:
46
- raise RuntimeError(
47
- "Cannot load Pickle file: cloudpickle not installed."
48
- )
49
- else:
50
- raise ValueError(f"Unsupported file extension: {p.suffix}")
51
- except Exception as e:
52
- # Add specific error logging if helpful
53
- from flock.core.logging.logging import get_logger
54
-
55
- logger = get_logger("loader")
56
- logger.error(
57
- f"Error loading Flock from {file_path}: {e}", exc_info=True
58
- )
59
- raise # Re-raise the original exception