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,369 +0,0 @@
1
- import asyncio
2
- import concurrent.futures # For real parallelism via threads
3
- from pathlib import Path
4
- from typing import TYPE_CHECKING, Any
5
-
6
- from box import Box
7
- from opentelemetry import trace
8
- from pandas import DataFrame
9
- from rich.progress import ( # Import Rich Progress
10
- BarColumn,
11
- Progress,
12
- SpinnerColumn,
13
- TextColumn,
14
- TimeElapsedColumn,
15
- )
16
-
17
- from flock.config import TELEMETRY
18
- from flock.core.context.context import FlockContext
19
- from flock.core.context.context_vars import FLOCK_BATCH_SILENT_MODE
20
- from flock.core.flock_agent import FlockAgent
21
- from flock.core.logging.logging import get_logger
22
-
23
- try:
24
- import pandas as pd
25
-
26
- PANDAS_AVAILABLE = True
27
- except ImportError:
28
- pd = None
29
- PANDAS_AVAILABLE = False
30
-
31
- if TYPE_CHECKING:
32
- from flock.core.flock import Flock
33
-
34
- logger = get_logger("flock")
35
- TELEMETRY.setup_tracing() # Setup OpenTelemetry
36
- tracer = trace.get_tracer(__name__)
37
-
38
-
39
- class BatchProcessor:
40
- def __init__(self, flock_instance: "Flock"):
41
- self.flock = flock_instance
42
-
43
- async def run_batch_async(
44
- self,
45
- start_agent: FlockAgent | str,
46
- batch_inputs: list[dict[str, Any]] | DataFrame | str,
47
- input_mapping: dict[str, str] | None = None,
48
- static_inputs: dict[str, Any] | None = None,
49
- parallel: bool = True,
50
- max_workers: int = 5,
51
- use_temporal: bool | None = None,
52
- box_results: bool = True,
53
- return_errors: bool = False,
54
- silent_mode: bool = False,
55
- write_to_csv: str | None = None,
56
- hide_columns: list[str] | None = None,
57
- delimiter: str = ",",
58
- ) -> list[Box | dict | None | Exception]:
59
- """Runs the specified agent/workflow for each item in a batch asynchronously.
60
-
61
- Args:
62
- start_agent: Agent instance or name to start each run.
63
- batch_inputs: Input data in one of these forms:
64
- - List of dictionaries, each representing inputs for one run
65
- - Pandas DataFrame where each row is inputs for one run
66
- - String path to a CSV file to load as DataFrame
67
- input_mapping: Maps DataFrame/CSV column names to agent input keys (required for DataFrame/CSV).
68
- static_inputs: Dictionary of inputs constant across all batch runs.
69
- parallel: Whether to run local jobs in parallel (ignored if use_temporal=True).
70
- max_workers: Max concurrent local workers (used if parallel=True and use_temporal=False).
71
- use_temporal: Override Flock's 'enable_temporal' setting for this batch.
72
- box_results: Wrap successful dictionary results in Box objects.
73
- return_errors: If True, return Exception objects for failed runs instead of raising.
74
- silent_mode: If True, suppress output and show progress bar instead.
75
- write_to_csv: Path to save results as CSV file.
76
- hide_columns: List of column names to hide from output.
77
-
78
- Returns:
79
- List containing results (Box/dict), None (if error and not return_errors),
80
- or Exception objects (if error and return_errors). Order matches input.
81
-
82
- Raises:
83
- ValueError: For invalid input combinations.
84
- ImportError: If DataFrame/CSV used without pandas.
85
- Exception: First exception from a run if return_errors is False.
86
- """
87
- effective_use_temporal = (
88
- use_temporal
89
- if use_temporal is not None
90
- else self.flock.enable_temporal
91
- )
92
- exec_mode = (
93
- "Temporal"
94
- if effective_use_temporal
95
- else ("Parallel Local" if parallel else "Sequential Local")
96
- )
97
- logger.info(
98
- f"Starting batch run for agent '{start_agent}'. Execution: {exec_mode}, Silent: {silent_mode}"
99
- )
100
-
101
- # --- Input Preparation ---
102
- prepared_batch_inputs: list[dict[str, Any]] = []
103
-
104
- if input_mapping == {}:
105
- input_mapping = None
106
- if static_inputs == {}:
107
- static_inputs = None
108
-
109
- if isinstance(batch_inputs, str):
110
- # Handle CSV file input
111
- try:
112
- df = pd.read_csv(batch_inputs)
113
- logger.debug(
114
- f"Loaded CSV file with {len(df)} rows: {batch_inputs}"
115
- )
116
- batch_inputs = df # Convert to DataFrame for unified handling
117
- except Exception as e:
118
- raise ValueError(
119
- f"Failed to load CSV file '{batch_inputs}': {e}"
120
- )
121
-
122
- if isinstance(batch_inputs, DataFrame):
123
- # Handle DataFrame input
124
- logger.debug(
125
- f"Converting DataFrame ({len(batch_inputs)} rows) to batch inputs."
126
- )
127
- for _, row in batch_inputs.iterrows():
128
- if input_mapping:
129
- item_input = {
130
- agent_key: row[df_col]
131
- for df_col, agent_key in input_mapping.items()
132
- if df_col in row
133
- }
134
- else:
135
- item_input = row.to_dict()
136
- prepared_batch_inputs.append(item_input)
137
- else:
138
- # Handle list of dictionaries
139
- if not isinstance(batch_inputs, list):
140
- raise ValueError(
141
- "batch_inputs must be a list of dictionaries, DataFrame, or CSV file path"
142
- )
143
-
144
- if input_mapping:
145
- # Apply mapping to dictionary inputs
146
- logger.debug("Applying input mapping to dictionary inputs")
147
- for item in batch_inputs:
148
- mapped_input = {}
149
- for df_col, agent_key in input_mapping.items():
150
- if df_col in item:
151
- mapped_input[agent_key] = item[df_col]
152
- else:
153
- logger.warning(
154
- f"Input mapping key '{df_col}' not found in input dictionary"
155
- )
156
- prepared_batch_inputs.append(mapped_input)
157
- else:
158
- # Use dictionaries as-is if no mapping provided
159
- prepared_batch_inputs = batch_inputs
160
-
161
- logger.debug(
162
- f"Using provided list of {len(prepared_batch_inputs)} batch inputs."
163
- )
164
-
165
- if not prepared_batch_inputs:
166
- return []
167
-
168
- # --- Setup Progress Bar if Silent ---
169
- progress_context = None
170
- progress_task_id = None
171
- if silent_mode:
172
- progress = Progress(
173
- SpinnerColumn(),
174
- TextColumn("[progress.description]{task.description}"),
175
- BarColumn(),
176
- TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
177
- TextColumn("({task.completed}/{task.total})"),
178
- TimeElapsedColumn(),
179
- # transient=True # Optionally remove progress bar when done
180
- )
181
- progress_context = progress # Use as context manager
182
- progress_task_id = progress.add_task(
183
- f"Processing Batch ({exec_mode})",
184
- total=len(prepared_batch_inputs),
185
- )
186
- progress.start()
187
-
188
- results = [None] * len(prepared_batch_inputs) # Pre-allocate results list
189
-
190
- # --- Worker Definitions ---
191
- # We implement two flavours:
192
- # * async_worker: used for Temporal or sequential runs (keeps the original behaviour)
193
- # * thread_worker: executes the run in a dedicated thread via ThreadPoolExecutor for true parallelism.
194
-
195
- async def async_worker(index: int, item_inputs: dict[str, Any]):
196
- """Original coroutine worker used for non-threaded execution paths."""
197
- full_input = {**(static_inputs or {}), **item_inputs}
198
- context = FlockContext()
199
- context.set_variable(FLOCK_BATCH_SILENT_MODE, silent_mode)
200
-
201
- run_desc = f"Batch item {index + 1}"
202
- logger.debug(f"{run_desc} started (async).")
203
- try:
204
- result = await self.flock.run_async(
205
- start_agent,
206
- full_input,
207
- box_result=box_results,
208
- context=context,
209
- )
210
- results[index] = result
211
- logger.debug(f"{run_desc} finished successfully.")
212
- except Exception as e:
213
- logger.error(f"{run_desc} failed: {e}", exc_info=not return_errors)
214
- if return_errors:
215
- results[index] = e
216
- else:
217
- raise # Propagate to calling gather
218
- finally:
219
- if progress_context:
220
- progress.update(progress_task_id, advance=1)
221
-
222
- # ThreadPool worker for real parallelism (suitable for blocking I/O)
223
- def _thread_worker(index: int, item_inputs: dict[str, Any]):
224
- """Synchronous helper executed inside a worker thread."""
225
- full_input = {**(static_inputs or {}), **item_inputs}
226
- run_desc = f"Batch item {index + 1}"
227
- logger.debug(f"{run_desc} started (thread).")
228
- try:
229
- # Use the synchronous wrapper to avoid nested event-loop issues inside threads
230
- result = self.flock.run(
231
- agent=start_agent,
232
- input=full_input,
233
- box_result=box_results,
234
- )
235
- logger.debug(f"{run_desc} finished successfully.")
236
- return index, result, None
237
- except Exception as e:
238
- logger.error(f"{run_desc} failed: {e}")
239
- return index, None, e
240
-
241
- async def thread_worker(executor, index: int, item_inputs: dict[str, Any]):
242
- """Coroutine wrapper that submits _thread_worker to the specified executor."""
243
- loop = asyncio.get_running_loop()
244
- idx, res, err = await loop.run_in_executor(
245
- executor, _thread_worker, index, item_inputs
246
- )
247
- # Handle result / error on the asyncio side
248
- if err:
249
- if return_errors:
250
- results[idx] = err
251
- else:
252
- raise err
253
- else:
254
- results[idx] = res
255
- if progress_context:
256
- progress.update(progress_task_id, advance=1)
257
-
258
- tasks = []
259
- try:
260
- if effective_use_temporal:
261
- # Temporal Batching (Simplified: sequential execution for this example)
262
- # A real implementation might use start_workflow or signals
263
- logger.info(
264
- "Running batch using Temporal (executing sequentially for now)..."
265
- )
266
- for i, item_data in enumerate(prepared_batch_inputs):
267
- await async_worker(i, item_data) # Run sequentially for demo
268
- # TODO: Implement true parallel Temporal workflow execution if needed
269
-
270
- elif parallel:
271
- # --- Real parallelism using ThreadPoolExecutor ---
272
- logger.info(
273
- f"Running batch in parallel (threads) with max_workers={max_workers}..."
274
- )
275
- loop = asyncio.get_running_loop()
276
- with concurrent.futures.ThreadPoolExecutor(
277
- max_workers=max_workers, thread_name_prefix="flock-batch"
278
- ) as executor:
279
- for i, item_data in enumerate(prepared_batch_inputs):
280
- tasks.append(
281
- asyncio.create_task(
282
- thread_worker(executor, i, item_data)
283
- )
284
- )
285
-
286
- # Wait for all tasks allowing exceptions to propagate as needed
287
- await asyncio.gather(*tasks)
288
-
289
- else: # Sequential Local
290
- logger.info("Running batch sequentially...")
291
- for i, item_data in enumerate(prepared_batch_inputs):
292
- await async_worker(i, item_data) # Already handles errors internally based on return_errors
293
-
294
- logger.info("Batch execution finished.")
295
-
296
- except Exception as batch_error:
297
- # This catch handles errors re-raised from workers when return_errors=False
298
- logger.error(f"Batch execution stopped due to error: {batch_error}")
299
- # No need to cancel tasks here as gather would have stopped
300
- if not return_errors:
301
- raise # Re-raise the first error encountered if not returning errors
302
- finally:
303
- if progress_context:
304
- progress.stop()
305
-
306
- if write_to_csv:
307
- try:
308
- df = pd.DataFrame(results)
309
- if hide_columns:
310
- df = df.drop(columns=hide_columns)
311
- # create write_to_csv directory if it doesn't exist
312
- Path(write_to_csv).parent.mkdir(parents=True, exist_ok=True)
313
- df.to_csv(write_to_csv, index=False, sep=delimiter)
314
- logger.info(f"Results written to CSV file: {write_to_csv}")
315
- except Exception as e:
316
- logger.error(f"Failed to write results to CSV: {e}")
317
-
318
- return results
319
-
320
- def run_batch( # Synchronous wrapper
321
- self,
322
- start_agent: FlockAgent | str,
323
- batch_inputs: list[dict[str, Any]] | DataFrame | str,
324
- input_mapping: dict[str, str] | None = None,
325
- static_inputs: dict[str, Any] | None = None,
326
- parallel: bool = True,
327
- max_workers: int = 5,
328
- use_temporal: bool | None = None,
329
- box_results: bool = True,
330
- return_errors: bool = False,
331
- silent_mode: bool = False,
332
- write_to_csv: str | None = None,
333
- hide_columns: list[str] | None = None,
334
- delimiter: str = ",",
335
- ) -> list[Box | dict | None | Exception]:
336
- """Synchronous wrapper for run_batch_async."""
337
- # (Standard asyncio run wrapper - same as in previous suggestion)
338
- try:
339
- loop = asyncio.get_running_loop()
340
- if loop.is_closed():
341
- raise RuntimeError("Event loop is closed")
342
- except RuntimeError:
343
- loop = asyncio.new_event_loop()
344
- asyncio.set_event_loop(loop)
345
-
346
- coro = self.run_batch_async(
347
- start_agent=start_agent,
348
- batch_inputs=batch_inputs,
349
- input_mapping=input_mapping,
350
- static_inputs=static_inputs,
351
- parallel=parallel,
352
- max_workers=max_workers,
353
- use_temporal=use_temporal,
354
- box_results=box_results,
355
- return_errors=return_errors,
356
- silent_mode=silent_mode,
357
- write_to_csv=write_to_csv,
358
- hide_columns=hide_columns,
359
- delimiter=delimiter,
360
- )
361
-
362
- if asyncio.get_event_loop() is loop and not loop.is_running():
363
- results = loop.run_until_complete(coro)
364
- # loop.close() # Avoid closing potentially shared loop
365
- return results
366
- else:
367
- # Run within an existing loop
368
- future = asyncio.ensure_future(coro)
369
- return loop.run_until_complete(future)