flock-core 0.5.0b28__py3-none-any.whl → 0.5.0b51__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 (469) 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/frontend/README.md +678 -0
  17. flock/frontend/docs/DESIGN_SYSTEM.md +1980 -0
  18. flock/frontend/index.html +12 -0
  19. flock/frontend/package-lock.json +4347 -0
  20. flock/frontend/package.json +48 -0
  21. flock/frontend/src/App.tsx +79 -0
  22. flock/frontend/src/__tests__/e2e/critical-scenarios.test.tsx +587 -0
  23. flock/frontend/src/__tests__/integration/filtering-e2e.test.tsx +387 -0
  24. flock/frontend/src/__tests__/integration/graph-rendering.test.tsx +640 -0
  25. flock/frontend/src/__tests__/integration/indexeddb-persistence.test.tsx +699 -0
  26. flock/frontend/src/components/common/BuildInfo.tsx +39 -0
  27. flock/frontend/src/components/common/EmptyState.module.css +115 -0
  28. flock/frontend/src/components/common/EmptyState.tsx +128 -0
  29. flock/frontend/src/components/common/ErrorBoundary.module.css +169 -0
  30. flock/frontend/src/components/common/ErrorBoundary.tsx +118 -0
  31. flock/frontend/src/components/common/KeyboardShortcutsDialog.css +251 -0
  32. flock/frontend/src/components/common/KeyboardShortcutsDialog.tsx +151 -0
  33. flock/frontend/src/components/common/LoadingSpinner.module.css +97 -0
  34. flock/frontend/src/components/common/LoadingSpinner.tsx +29 -0
  35. flock/frontend/src/components/controls/PublishControl.css +547 -0
  36. flock/frontend/src/components/controls/PublishControl.test.tsx +543 -0
  37. flock/frontend/src/components/controls/PublishControl.tsx +432 -0
  38. flock/frontend/src/components/details/DetailWindowContainer.tsx +62 -0
  39. flock/frontend/src/components/details/LiveOutputTab.test.tsx +792 -0
  40. flock/frontend/src/components/details/LiveOutputTab.tsx +220 -0
  41. flock/frontend/src/components/details/MessageHistoryTab.tsx +299 -0
  42. flock/frontend/src/components/details/NodeDetailWindow.test.tsx +501 -0
  43. flock/frontend/src/components/details/NodeDetailWindow.tsx +218 -0
  44. flock/frontend/src/components/details/RunStatusTab.tsx +307 -0
  45. flock/frontend/src/components/details/tabs.test.tsx +1015 -0
  46. flock/frontend/src/components/filters/CorrelationIDFilter.module.css +102 -0
  47. flock/frontend/src/components/filters/CorrelationIDFilter.test.tsx +197 -0
  48. flock/frontend/src/components/filters/CorrelationIDFilter.tsx +121 -0
  49. flock/frontend/src/components/filters/FilterBar.module.css +29 -0
  50. flock/frontend/src/components/filters/FilterBar.test.tsx +133 -0
  51. flock/frontend/src/components/filters/FilterBar.tsx +33 -0
  52. flock/frontend/src/components/filters/FilterPills.module.css +79 -0
  53. flock/frontend/src/components/filters/FilterPills.test.tsx +173 -0
  54. flock/frontend/src/components/filters/FilterPills.tsx +67 -0
  55. flock/frontend/src/components/filters/TimeRangeFilter.module.css +91 -0
  56. flock/frontend/src/components/filters/TimeRangeFilter.test.tsx +154 -0
  57. flock/frontend/src/components/filters/TimeRangeFilter.tsx +105 -0
  58. flock/frontend/src/components/graph/AgentNode.test.tsx +75 -0
  59. flock/frontend/src/components/graph/AgentNode.tsx +322 -0
  60. flock/frontend/src/components/graph/GraphCanvas.tsx +406 -0
  61. flock/frontend/src/components/graph/MessageFlowEdge.tsx +128 -0
  62. flock/frontend/src/components/graph/MessageNode.test.tsx +62 -0
  63. flock/frontend/src/components/graph/MessageNode.tsx +116 -0
  64. flock/frontend/src/components/graph/MiniMap.tsx +47 -0
  65. flock/frontend/src/components/graph/TransformEdge.tsx +123 -0
  66. flock/frontend/src/components/layout/DashboardLayout.css +407 -0
  67. flock/frontend/src/components/layout/DashboardLayout.tsx +300 -0
  68. flock/frontend/src/components/layout/Header.module.css +88 -0
  69. flock/frontend/src/components/layout/Header.tsx +52 -0
  70. flock/frontend/src/components/modules/EventLogModule.test.tsx +401 -0
  71. flock/frontend/src/components/modules/EventLogModule.tsx +396 -0
  72. flock/frontend/src/components/modules/EventLogModuleWrapper.tsx +17 -0
  73. flock/frontend/src/components/modules/ModuleRegistry.test.ts +333 -0
  74. flock/frontend/src/components/modules/ModuleRegistry.ts +85 -0
  75. flock/frontend/src/components/modules/ModuleWindow.tsx +155 -0
  76. flock/frontend/src/components/modules/registerModules.ts +20 -0
  77. flock/frontend/src/components/settings/AdvancedSettings.tsx +175 -0
  78. flock/frontend/src/components/settings/AppearanceSettings.tsx +185 -0
  79. flock/frontend/src/components/settings/GraphSettings.tsx +110 -0
  80. flock/frontend/src/components/settings/SettingsPanel.css +327 -0
  81. flock/frontend/src/components/settings/SettingsPanel.tsx +131 -0
  82. flock/frontend/src/components/settings/ThemeSelector.tsx +298 -0
  83. flock/frontend/src/hooks/useKeyboardShortcuts.ts +148 -0
  84. flock/frontend/src/hooks/useModulePersistence.test.ts +442 -0
  85. flock/frontend/src/hooks/useModulePersistence.ts +154 -0
  86. flock/frontend/src/hooks/useModules.ts +139 -0
  87. flock/frontend/src/hooks/usePersistence.ts +139 -0
  88. flock/frontend/src/main.tsx +13 -0
  89. flock/frontend/src/services/api.ts +213 -0
  90. flock/frontend/src/services/indexeddb.test.ts +793 -0
  91. flock/frontend/src/services/indexeddb.ts +794 -0
  92. flock/frontend/src/services/layout.test.ts +437 -0
  93. flock/frontend/src/services/layout.ts +146 -0
  94. flock/frontend/src/services/themeApplicator.ts +140 -0
  95. flock/frontend/src/services/themeService.ts +77 -0
  96. flock/frontend/src/services/websocket.test.ts +595 -0
  97. flock/frontend/src/services/websocket.ts +685 -0
  98. flock/frontend/src/store/filterStore.test.ts +242 -0
  99. flock/frontend/src/store/filterStore.ts +103 -0
  100. flock/frontend/src/store/graphStore.test.ts +186 -0
  101. flock/frontend/src/store/graphStore.ts +414 -0
  102. flock/frontend/src/store/moduleStore.test.ts +253 -0
  103. flock/frontend/src/store/moduleStore.ts +57 -0
  104. flock/frontend/src/store/settingsStore.ts +188 -0
  105. flock/frontend/src/store/streamStore.ts +68 -0
  106. flock/frontend/src/store/uiStore.test.ts +54 -0
  107. flock/frontend/src/store/uiStore.ts +110 -0
  108. flock/frontend/src/store/wsStore.ts +34 -0
  109. flock/frontend/src/styles/index.css +15 -0
  110. flock/frontend/src/styles/scrollbar.css +47 -0
  111. flock/frontend/src/styles/variables.css +488 -0
  112. flock/frontend/src/test/setup.ts +1 -0
  113. flock/frontend/src/types/filters.ts +14 -0
  114. flock/frontend/src/types/graph.ts +55 -0
  115. flock/frontend/src/types/modules.ts +7 -0
  116. flock/frontend/src/types/theme.ts +55 -0
  117. flock/frontend/src/utils/mockData.ts +85 -0
  118. flock/frontend/src/utils/performance.ts +16 -0
  119. flock/frontend/src/utils/transforms.test.ts +860 -0
  120. flock/frontend/src/utils/transforms.ts +323 -0
  121. flock/frontend/src/vite-env.d.ts +17 -0
  122. flock/frontend/tsconfig.json +27 -0
  123. flock/frontend/tsconfig.node.json +11 -0
  124. flock/frontend/vite.config.ts +25 -0
  125. flock/frontend/vitest.config.ts +11 -0
  126. flock/{core/util → helper}/cli_helper.py +4 -3
  127. flock/{core/logging → logging}/__init__.py +2 -3
  128. flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
  129. flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
  130. flock/{core/logging → logging}/formatters/themed_formatter.py +69 -115
  131. flock/{core/logging → logging}/logging.py +77 -61
  132. flock/{core/logging → logging}/telemetry.py +20 -26
  133. flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
  134. flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +6 -9
  135. flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
  136. flock/{core/logging → logging}/trace_and_logged.py +20 -24
  137. flock/mcp/__init__.py +91 -0
  138. flock/{core/mcp/mcp_client.py → mcp/client.py} +103 -154
  139. flock/{core/mcp/mcp_config.py → mcp/config.py} +62 -117
  140. flock/mcp/manager.py +255 -0
  141. flock/mcp/servers/sse/__init__.py +1 -1
  142. flock/mcp/servers/sse/flock_sse_server.py +11 -53
  143. flock/mcp/servers/stdio/__init__.py +1 -1
  144. flock/mcp/servers/stdio/flock_stdio_server.py +8 -48
  145. flock/mcp/servers/streamable_http/flock_streamable_http_server.py +17 -62
  146. flock/mcp/servers/websockets/flock_websocket_server.py +7 -40
  147. flock/{core/mcp/flock_mcp_tool.py → mcp/tool.py} +16 -26
  148. flock/mcp/types/__init__.py +42 -0
  149. flock/{core/mcp → mcp}/types/callbacks.py +9 -15
  150. flock/{core/mcp → mcp}/types/factories.py +7 -6
  151. flock/{core/mcp → mcp}/types/handlers.py +13 -18
  152. flock/{core/mcp → mcp}/types/types.py +70 -74
  153. flock/{core/mcp → mcp}/util/helpers.py +1 -1
  154. flock/orchestrator.py +645 -0
  155. flock/registry.py +148 -0
  156. flock/runtime.py +262 -0
  157. flock/service.py +140 -0
  158. flock/store.py +69 -0
  159. flock/subscription.py +111 -0
  160. flock/themes/andromeda.toml +1 -1
  161. flock/themes/apple-system-colors.toml +1 -1
  162. flock/themes/arcoiris.toml +1 -1
  163. flock/themes/atomonelight.toml +1 -1
  164. flock/themes/ayu copy.toml +1 -1
  165. flock/themes/ayu-light.toml +1 -1
  166. flock/themes/belafonte-day.toml +1 -1
  167. flock/themes/belafonte-night.toml +1 -1
  168. flock/themes/blulocodark.toml +1 -1
  169. flock/themes/breeze.toml +1 -1
  170. flock/themes/broadcast.toml +1 -1
  171. flock/themes/brogrammer.toml +1 -1
  172. flock/themes/builtin-dark.toml +1 -1
  173. flock/themes/builtin-pastel-dark.toml +1 -1
  174. flock/themes/catppuccin-latte.toml +1 -1
  175. flock/themes/catppuccin-macchiato.toml +1 -1
  176. flock/themes/catppuccin-mocha.toml +1 -1
  177. flock/themes/cga.toml +1 -1
  178. flock/themes/chalk.toml +1 -1
  179. flock/themes/ciapre.toml +1 -1
  180. flock/themes/coffee-theme.toml +1 -1
  181. flock/themes/cyberpunkscarletprotocol.toml +1 -1
  182. flock/themes/dark+.toml +1 -1
  183. flock/themes/darkermatrix.toml +1 -1
  184. flock/themes/darkside.toml +1 -1
  185. flock/themes/desert.toml +1 -1
  186. flock/themes/django.toml +1 -1
  187. flock/themes/djangosmooth.toml +1 -1
  188. flock/themes/doomone.toml +1 -1
  189. flock/themes/dotgov.toml +1 -1
  190. flock/themes/dracula+.toml +1 -1
  191. flock/themes/duckbones.toml +1 -1
  192. flock/themes/encom.toml +1 -1
  193. flock/themes/espresso.toml +1 -1
  194. flock/themes/everblush.toml +1 -1
  195. flock/themes/fairyfloss.toml +1 -1
  196. flock/themes/fideloper.toml +1 -1
  197. flock/themes/fishtank.toml +1 -1
  198. flock/themes/flexoki-light.toml +1 -1
  199. flock/themes/floraverse.toml +1 -1
  200. flock/themes/framer.toml +1 -1
  201. flock/themes/galizur.toml +1 -1
  202. flock/themes/github.toml +1 -1
  203. flock/themes/grass.toml +1 -1
  204. flock/themes/grey-green.toml +1 -1
  205. flock/themes/gruvboxlight.toml +1 -1
  206. flock/themes/guezwhoz.toml +1 -1
  207. flock/themes/harper.toml +1 -1
  208. flock/themes/hax0r-blue.toml +1 -1
  209. flock/themes/hopscotch.256.toml +1 -1
  210. flock/themes/ic-green-ppl.toml +1 -1
  211. flock/themes/iceberg-dark.toml +1 -1
  212. flock/themes/japanesque.toml +1 -1
  213. flock/themes/jubi.toml +1 -1
  214. flock/themes/kibble.toml +1 -1
  215. flock/themes/kolorit.toml +1 -1
  216. flock/themes/kurokula.toml +1 -1
  217. flock/themes/materialdesigncolors.toml +1 -1
  218. flock/themes/matrix.toml +1 -1
  219. flock/themes/mellifluous.toml +1 -1
  220. flock/themes/midnight-in-mojave.toml +1 -1
  221. flock/themes/monokai-remastered.toml +1 -1
  222. flock/themes/monokai-soda.toml +1 -1
  223. flock/themes/neon.toml +1 -1
  224. flock/themes/neopolitan.toml +1 -1
  225. flock/themes/nord-light.toml +1 -1
  226. flock/themes/ocean.toml +1 -1
  227. flock/themes/onehalfdark.toml +1 -1
  228. flock/themes/onehalflight.toml +1 -1
  229. flock/themes/palenighthc.toml +1 -1
  230. flock/themes/paulmillr.toml +1 -1
  231. flock/themes/pencildark.toml +1 -1
  232. flock/themes/pnevma.toml +1 -1
  233. flock/themes/purple-rain.toml +1 -1
  234. flock/themes/purplepeter.toml +1 -1
  235. flock/themes/raycast-dark.toml +1 -1
  236. flock/themes/red-sands.toml +1 -1
  237. flock/themes/relaxed.toml +1 -1
  238. flock/themes/retro.toml +1 -1
  239. flock/themes/rose-pine.toml +1 -1
  240. flock/themes/royal.toml +1 -1
  241. flock/themes/ryuuko.toml +1 -1
  242. flock/themes/sakura.toml +1 -1
  243. flock/themes/scarlet-protocol.toml +1 -1
  244. flock/themes/seoulbones-dark.toml +1 -1
  245. flock/themes/shades-of-purple.toml +1 -1
  246. flock/themes/smyck.toml +1 -1
  247. flock/themes/softserver.toml +1 -1
  248. flock/themes/solarized-darcula.toml +1 -1
  249. flock/themes/square.toml +1 -1
  250. flock/themes/sugarplum.toml +1 -1
  251. flock/themes/thayer-bright.toml +1 -1
  252. flock/themes/tokyonight.toml +1 -1
  253. flock/themes/tomorrow.toml +1 -1
  254. flock/themes/ubuntu.toml +1 -1
  255. flock/themes/ultradark.toml +1 -1
  256. flock/themes/ultraviolent.toml +1 -1
  257. flock/themes/unikitty.toml +1 -1
  258. flock/themes/urple.toml +1 -1
  259. flock/themes/vesper.toml +1 -1
  260. flock/themes/vimbones.toml +1 -1
  261. flock/themes/wildcherry.toml +1 -1
  262. flock/themes/wilmersdorf.toml +1 -1
  263. flock/themes/wryan.toml +1 -1
  264. flock/themes/xcodedarkhc.toml +1 -1
  265. flock/themes/xcodelight.toml +1 -1
  266. flock/themes/zenbones-light.toml +1 -1
  267. flock/themes/zenwritten-dark.toml +1 -1
  268. flock/utilities.py +301 -0
  269. flock/{components/utility → utility}/output_utility_component.py +68 -53
  270. flock/visibility.py +107 -0
  271. flock_core-0.5.0b51.dist-info/METADATA +747 -0
  272. flock_core-0.5.0b51.dist-info/RECORD +508 -0
  273. flock_core-0.5.0b51.dist-info/entry_points.txt +2 -0
  274. {flock_core-0.5.0b28.dist-info → flock_core-0.5.0b51.dist-info}/licenses/LICENSE +1 -1
  275. flock/adapter/__init__.py +0 -14
  276. flock/adapter/azure_adapter.py +0 -68
  277. flock/adapter/chroma_adapter.py +0 -73
  278. flock/adapter/faiss_adapter.py +0 -97
  279. flock/adapter/pinecone_adapter.py +0 -51
  280. flock/adapter/vector_base.py +0 -47
  281. flock/cli/assets/release_notes.md +0 -140
  282. flock/cli/config.py +0 -8
  283. flock/cli/constants.py +0 -36
  284. flock/cli/create_agent.py +0 -1
  285. flock/cli/create_flock.py +0 -280
  286. flock/cli/execute_flock.py +0 -620
  287. flock/cli/load_agent.py +0 -1
  288. flock/cli/load_examples.py +0 -1
  289. flock/cli/load_flock.py +0 -192
  290. flock/cli/load_release_notes.py +0 -20
  291. flock/cli/loaded_flock_cli.py +0 -254
  292. flock/cli/manage_agents.py +0 -459
  293. flock/cli/registry_management.py +0 -889
  294. flock/cli/runner.py +0 -41
  295. flock/cli/settings.py +0 -857
  296. flock/cli/utils.py +0 -135
  297. flock/cli/view_results.py +0 -29
  298. flock/cli/yaml_editor.py +0 -396
  299. flock/components/__init__.py +0 -30
  300. flock/components/evaluation/__init__.py +0 -9
  301. flock/components/evaluation/declarative_evaluation_component.py +0 -606
  302. flock/components/routing/__init__.py +0 -15
  303. flock/components/routing/conditional_routing_component.py +0 -494
  304. flock/components/routing/default_routing_component.py +0 -103
  305. flock/components/routing/llm_routing_component.py +0 -206
  306. flock/components/utility/__init__.py +0 -22
  307. flock/components/utility/example_utility_component.py +0 -250
  308. flock/components/utility/feedback_utility_component.py +0 -206
  309. flock/components/utility/memory_utility_component.py +0 -550
  310. flock/components/utility/metrics_utility_component.py +0 -700
  311. flock/config.py +0 -61
  312. flock/core/__init__.py +0 -110
  313. flock/core/agent/__init__.py +0 -16
  314. flock/core/agent/default_agent.py +0 -216
  315. flock/core/agent/flock_agent_components.py +0 -104
  316. flock/core/agent/flock_agent_execution.py +0 -101
  317. flock/core/agent/flock_agent_integration.py +0 -260
  318. flock/core/agent/flock_agent_lifecycle.py +0 -186
  319. flock/core/agent/flock_agent_serialization.py +0 -381
  320. flock/core/api/__init__.py +0 -10
  321. flock/core/api/custom_endpoint.py +0 -45
  322. flock/core/api/endpoints.py +0 -254
  323. flock/core/api/main.py +0 -162
  324. flock/core/api/models.py +0 -97
  325. flock/core/api/run_store.py +0 -224
  326. flock/core/api/runner.py +0 -44
  327. flock/core/api/service.py +0 -214
  328. flock/core/component/__init__.py +0 -15
  329. flock/core/component/agent_component_base.py +0 -309
  330. flock/core/component/evaluation_component.py +0 -62
  331. flock/core/component/routing_component.py +0 -74
  332. flock/core/component/utility_component.py +0 -69
  333. flock/core/config/flock_agent_config.py +0 -58
  334. flock/core/config/scheduled_agent_config.py +0 -40
  335. flock/core/context/context.py +0 -213
  336. flock/core/context/context_manager.py +0 -37
  337. flock/core/context/context_vars.py +0 -10
  338. flock/core/evaluation/utils.py +0 -396
  339. flock/core/execution/batch_executor.py +0 -369
  340. flock/core/execution/evaluation_executor.py +0 -438
  341. flock/core/execution/local_executor.py +0 -31
  342. flock/core/execution/opik_executor.py +0 -103
  343. flock/core/execution/temporal_executor.py +0 -164
  344. flock/core/flock.py +0 -634
  345. flock/core/flock_agent.py +0 -336
  346. flock/core/flock_factory.py +0 -613
  347. flock/core/flock_scheduler.py +0 -166
  348. flock/core/flock_server_manager.py +0 -136
  349. flock/core/interpreter/python_interpreter.py +0 -689
  350. flock/core/mcp/__init__.py +0 -1
  351. flock/core/mcp/flock_mcp_server.py +0 -680
  352. flock/core/mcp/mcp_client_manager.py +0 -201
  353. flock/core/mcp/types/__init__.py +0 -1
  354. flock/core/mixin/dspy_integration.py +0 -403
  355. flock/core/mixin/prompt_parser.py +0 -125
  356. flock/core/orchestration/__init__.py +0 -15
  357. flock/core/orchestration/flock_batch_processor.py +0 -94
  358. flock/core/orchestration/flock_evaluator.py +0 -113
  359. flock/core/orchestration/flock_execution.py +0 -295
  360. flock/core/orchestration/flock_initialization.py +0 -149
  361. flock/core/orchestration/flock_server_manager.py +0 -67
  362. flock/core/orchestration/flock_web_server.py +0 -117
  363. flock/core/registry/__init__.py +0 -45
  364. flock/core/registry/agent_registry.py +0 -69
  365. flock/core/registry/callable_registry.py +0 -139
  366. flock/core/registry/component_discovery.py +0 -142
  367. flock/core/registry/component_registry.py +0 -64
  368. flock/core/registry/config_mapping.py +0 -64
  369. flock/core/registry/decorators.py +0 -137
  370. flock/core/registry/registry_hub.py +0 -205
  371. flock/core/registry/server_registry.py +0 -57
  372. flock/core/registry/type_registry.py +0 -86
  373. flock/core/serialization/__init__.py +0 -13
  374. flock/core/serialization/callable_registry.py +0 -52
  375. flock/core/serialization/flock_serializer.py +0 -832
  376. flock/core/serialization/json_encoder.py +0 -41
  377. flock/core/serialization/secure_serializer.py +0 -175
  378. flock/core/serialization/serializable.py +0 -342
  379. flock/core/serialization/serialization_utils.py +0 -412
  380. flock/core/util/file_path_utils.py +0 -223
  381. flock/core/util/hydrator.py +0 -309
  382. flock/core/util/input_resolver.py +0 -164
  383. flock/core/util/loader.py +0 -59
  384. flock/core/util/splitter.py +0 -219
  385. flock/di.py +0 -27
  386. flock/platform/docker_tools.py +0 -49
  387. flock/platform/jaeger_install.py +0 -86
  388. flock/webapp/__init__.py +0 -1
  389. flock/webapp/app/__init__.py +0 -0
  390. flock/webapp/app/api/__init__.py +0 -0
  391. flock/webapp/app/api/agent_management.py +0 -241
  392. flock/webapp/app/api/execution.py +0 -709
  393. flock/webapp/app/api/flock_management.py +0 -129
  394. flock/webapp/app/api/registry_viewer.py +0 -30
  395. flock/webapp/app/chat.py +0 -665
  396. flock/webapp/app/config.py +0 -104
  397. flock/webapp/app/dependencies.py +0 -117
  398. flock/webapp/app/main.py +0 -1070
  399. flock/webapp/app/middleware.py +0 -113
  400. flock/webapp/app/models_ui.py +0 -7
  401. flock/webapp/app/services/__init__.py +0 -0
  402. flock/webapp/app/services/feedback_file_service.py +0 -363
  403. flock/webapp/app/services/flock_service.py +0 -337
  404. flock/webapp/app/services/sharing_models.py +0 -81
  405. flock/webapp/app/services/sharing_store.py +0 -762
  406. flock/webapp/app/templates/theme_mapper.html +0 -326
  407. flock/webapp/app/theme_mapper.py +0 -812
  408. flock/webapp/app/utils.py +0 -85
  409. flock/webapp/run.py +0 -215
  410. flock/webapp/static/css/chat.css +0 -301
  411. flock/webapp/static/css/components.css +0 -167
  412. flock/webapp/static/css/header.css +0 -39
  413. flock/webapp/static/css/layout.css +0 -46
  414. flock/webapp/static/css/sidebar.css +0 -127
  415. flock/webapp/static/css/two-pane.css +0 -48
  416. flock/webapp/templates/base.html +0 -200
  417. flock/webapp/templates/chat.html +0 -152
  418. flock/webapp/templates/chat_settings.html +0 -19
  419. flock/webapp/templates/flock_editor.html +0 -16
  420. flock/webapp/templates/index.html +0 -12
  421. flock/webapp/templates/partials/_agent_detail_form.html +0 -93
  422. flock/webapp/templates/partials/_agent_list.html +0 -18
  423. flock/webapp/templates/partials/_agent_manager_view.html +0 -51
  424. flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
  425. flock/webapp/templates/partials/_chat_container.html +0 -15
  426. flock/webapp/templates/partials/_chat_messages.html +0 -57
  427. flock/webapp/templates/partials/_chat_settings_form.html +0 -85
  428. flock/webapp/templates/partials/_create_flock_form.html +0 -50
  429. flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
  430. flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
  431. flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
  432. flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
  433. flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
  434. flock/webapp/templates/partials/_env_vars_table.html +0 -23
  435. flock/webapp/templates/partials/_execution_form.html +0 -118
  436. flock/webapp/templates/partials/_execution_view_container.html +0 -28
  437. flock/webapp/templates/partials/_flock_file_list.html +0 -23
  438. flock/webapp/templates/partials/_flock_properties_form.html +0 -52
  439. flock/webapp/templates/partials/_flock_upload_form.html +0 -16
  440. flock/webapp/templates/partials/_header_flock_status.html +0 -5
  441. flock/webapp/templates/partials/_load_manager_view.html +0 -49
  442. flock/webapp/templates/partials/_registry_table.html +0 -25
  443. flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
  444. flock/webapp/templates/partials/_results_display.html +0 -78
  445. flock/webapp/templates/partials/_settings_env_content.html +0 -9
  446. flock/webapp/templates/partials/_settings_theme_content.html +0 -14
  447. flock/webapp/templates/partials/_settings_view.html +0 -36
  448. flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
  449. flock/webapp/templates/partials/_share_link_snippet.html +0 -35
  450. flock/webapp/templates/partials/_sidebar.html +0 -74
  451. flock/webapp/templates/partials/_streaming_results_container.html +0 -195
  452. flock/webapp/templates/partials/_structured_data_view.html +0 -40
  453. flock/webapp/templates/partials/_theme_preview.html +0 -36
  454. flock/webapp/templates/registry_viewer.html +0 -84
  455. flock/webapp/templates/shared_run_page.html +0 -140
  456. flock/workflow/__init__.py +0 -0
  457. flock/workflow/activities.py +0 -196
  458. flock/workflow/agent_activities.py +0 -24
  459. flock/workflow/agent_execution_activity.py +0 -202
  460. flock/workflow/flock_workflow.py +0 -214
  461. flock/workflow/temporal_config.py +0 -96
  462. flock/workflow/temporal_setup.py +0 -68
  463. flock_core-0.5.0b28.dist-info/METADATA +0 -274
  464. flock_core-0.5.0b28.dist-info/RECORD +0 -561
  465. flock_core-0.5.0b28.dist-info/entry_points.txt +0 -2
  466. /flock/{core/logging → logging}/formatters/themes.py +0 -0
  467. /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
  468. /flock/{core/mcp → mcp}/util/__init__.py +0 -0
  469. {flock_core-0.5.0b28.dist-info → flock_core-0.5.0b51.dist-info}/WHEEL +0 -0
@@ -1,201 +0,0 @@
1
- """Manages a pool of connections for a particular server."""
2
-
3
- import copy
4
- from abc import ABC, abstractmethod
5
- from asyncio import Lock
6
- from typing import Any, Generic, TypeVar
7
-
8
- from opentelemetry import trace
9
- from pydantic import (
10
- BaseModel,
11
- ConfigDict,
12
- Field,
13
- )
14
-
15
- from flock.core.logging.logging import get_logger
16
- from flock.core.mcp.flock_mcp_tool import FlockMCPTool
17
- from flock.core.mcp.mcp_client import (
18
- FlockMCPClient,
19
- )
20
- from flock.core.mcp.mcp_config import FlockMCPConfiguration
21
-
22
- logger = get_logger("mcp.client_manager")
23
- tracer = trace.get_tracer(__name__)
24
-
25
- TClient = TypeVar("TClient", bound="FlockMCPClient")
26
-
27
-
28
- class FlockMCPClientManager(BaseModel, ABC, Generic[TClient]):
29
- """Handles a Pool of MCPClients of type TClient."""
30
-
31
- client_config: FlockMCPConfiguration = Field(
32
- ..., description="Configuration for clients."
33
- )
34
-
35
- lock: Lock = Field(
36
- default_factory=Lock,
37
- description="Lock for mutex access.",
38
- exclude=True,
39
- )
40
-
41
- clients: dict[str, dict[str, FlockMCPClient]] = Field(
42
- default_factory=dict,
43
- exclude=True,
44
- description="Internal Store for the clients.",
45
- )
46
-
47
- # --- Pydantic v2 Configuratioin ---
48
- model_config = ConfigDict(
49
- arbitrary_types_allowed=True,
50
- )
51
-
52
- @abstractmethod
53
- async def make_client(
54
- self,
55
- additional_params: dict[str, Any] | None = None,
56
- ) -> type[TClient]:
57
- """Instantiate-but don't connect yet-a fresh client of the concrete subtype."""
58
- # default implementation
59
- pass
60
-
61
- async def get_client(
62
- self,
63
- agent_id: str,
64
- run_id: str,
65
- additional_params: dict[str, Any] | None = None,
66
- ) -> type[TClient]:
67
- """Provides a client from the pool."""
68
- # Attempt to get a client from the client store.
69
- # clients are stored like this: agent_id -> run_id -> client
70
- with tracer.start_as_current_span("client_manager.get_client") as span:
71
- span.set_attribute("agent_id", agent_id)
72
- span.set_attribute("run_id", run_id)
73
- async with self.lock:
74
- try:
75
- logger.debug(
76
- f"Attempting to get client for server '{self.client_config.name}'"
77
- )
78
- refresh = False
79
- if additional_params:
80
- refresh = bool(
81
- additional_params.get("refresh_client", False)
82
- )
83
- client = None
84
- run_clients = self.clients.get(agent_id, None)
85
- if run_clients is None or refresh:
86
- # This means, that across all runs, no agent has ever needed a client.
87
- # This also means that we need to create a client.
88
- client = await self.make_client(
89
- additional_params=copy.deepcopy(additional_params)
90
- )
91
- # Insert the freshly created client
92
- self.clients[agent_id] = {}
93
- self.clients[agent_id][run_id] = client
94
-
95
- else:
96
- # This means there is at least one entry for the agent_id available
97
- # Now, all we need to do is check if the run_id matches the entrie's run_id
98
- client = run_clients.get(run_id, None)
99
- if client is None or refresh:
100
- # Means no client here with the respective run_id
101
- client = await self.make_client(
102
- additional_params=copy.deepcopy(
103
- additional_params
104
- )
105
- )
106
- # Insert the freshly created client.
107
- self.clients[agent_id][run_id] = client
108
-
109
- return client
110
- except Exception as e:
111
- # Log the exception and raise it so it becomes visible downstream
112
- logger.error(
113
- f"Unexpected Exception ocurred while trying to get client for server '{self.client_config.name}' with agent_id: {agent_id} and run_id: {run_id}: {e}"
114
- )
115
- span.record_exception(e)
116
- raise e
117
-
118
- async def call_tool(
119
- self,
120
- agent_id: str,
121
- run_id: str,
122
- name: str,
123
- arguments: dict[str, Any],
124
- additional_params: dict[str, Any] | None = None,
125
- ) -> Any:
126
- """Call a tool."""
127
- with tracer.start_as_current_span("client_manager.call_tool") as span:
128
- span.set_attribute("agent_id", agent_id)
129
- span.set_attribute("run_id", run_id)
130
- span.set_attribute("tool_name", name)
131
- span.set_attribute("arguments", str(arguments))
132
- try:
133
- client = await self.get_client(
134
- agent_id=agent_id,
135
- run_id=run_id,
136
- additional_params=additional_params,
137
- )
138
- result = await client.call_tool(
139
- agent_id=agent_id,
140
- run_id=run_id,
141
- name=name,
142
- arguments=arguments,
143
- )
144
- return result
145
- except Exception as e:
146
- logger.error(
147
- f"Exception occurred while trying to call tool {name} on server '{self.client_config.name}': {e}"
148
- )
149
- span.record_exception(e)
150
- return None
151
-
152
- async def get_tools(
153
- self,
154
- agent_id: str,
155
- run_id: str,
156
- additional_params: dict[str, Any] | None = None,
157
- ) -> list[FlockMCPTool]:
158
- """Retrieves a list of tools for the agents to act on."""
159
- with tracer.start_as_current_span("client_manager.get_tools") as span:
160
- span.set_attribute("agent_id", agent_id)
161
- span.set_attribute("run_id", run_id)
162
- try:
163
- client = await self.get_client(
164
- agent_id=agent_id,
165
- run_id=run_id,
166
- additional_params=additional_params,
167
- )
168
- tools: list[FlockMCPTool] = await client.get_tools(
169
- agent_id=agent_id, run_id=run_id
170
- )
171
- return tools
172
- except Exception as e:
173
- logger.error(
174
- f"Exception occurred while trying to retrieve Tools for server '{self.client_config.name}' with agent_id: {agent_id} and run_id: {run_id}: {e}"
175
- )
176
- span.record_exception(e)
177
- return []
178
-
179
- async def close_all(self) -> None:
180
- """Closes all connections in the pool and cancels background tasks."""
181
- with tracer.start_as_current_span("client_manager.close_all") as span:
182
- async with self.lock:
183
- for agent_id, run_dict in self.clients.items():
184
- logger.debug(
185
- f"Shutting down all clients for agent_id: {agent_id}"
186
- )
187
- for run_id, client in run_dict.items():
188
- logger.debug(
189
- f"Shutting down client for agent_id {agent_id} and run_id {run_id}"
190
- )
191
- try:
192
- await client.disconnect()
193
- except Exception as e:
194
- logger.error(
195
- f"Error when trying to disconnect client for server '{self.client_config.name}': {e}"
196
- )
197
- span.record_exception(e)
198
- self.clients = {} # Let the GC take care of the rest.
199
- logger.info(
200
- f"All clients disconnected for server '{self.client_config.name}'"
201
- )
@@ -1 +0,0 @@
1
- """MCP Types package."""
@@ -1,403 +0,0 @@
1
- # src/flock/core/mixin/dspy_integration.py
2
- """Mixin class for integrating with the dspy library.
3
-
4
- This mixin centralizes Flock ↔ DSPy interop. It intentionally
5
- delegates more to DSPy’s native builders (Signature, settings.context,
6
- modules) to reduce custom glue and stay aligned with DSPy updates.
7
- """
8
-
9
- import ast
10
- import re # Import re for parsing
11
- import typing
12
- from typing import Any, Literal
13
-
14
- from dspy import Tool
15
-
16
- from flock.core.logging.logging import get_logger
17
- from flock.core.util.splitter import split_top_level
18
-
19
- # Import split_top_level (assuming it's moved or copied appropriately)
20
- # Option 1: If moved to a shared util
21
- # from flock.core.util.parsing_utils import split_top_level
22
- # Option 2: If kept within this file (as in previous example)
23
- # Define split_top_level here or ensure it's imported
24
-
25
- logger = get_logger("mixin.dspy")
26
-
27
- # Type definition for agent type override
28
- AgentType = Literal["ReAct", "Completion", "ChainOfThought"] | None
29
-
30
-
31
- # Helper function to resolve type strings (can be static or module-level)
32
- def _resolve_type_string(type_str: str) -> type:
33
- """Resolves a type string into a Python type object.
34
- Handles built-ins, registered types, and common typing generics like
35
- List, Dict, Optional, Union, Literal.
36
- """
37
- # Import registry here to avoid circular imports
38
- from flock.core.registry import get_registry
39
-
40
- registry = get_registry()
41
-
42
- type_str = type_str.strip()
43
- logger.debug(f"Attempting to resolve type string: '{type_str}'")
44
-
45
- # 1. Check built-ins and registered types directly
46
- try:
47
- # This covers str, int, bool, Any, and types registered by name
48
- resolved_type = registry.get_type(type_str)
49
- logger.debug(f"Resolved '{type_str}' via registry to: {resolved_type}")
50
- return resolved_type
51
- except KeyError:
52
- logger.debug(
53
- f"'{type_str}' not found directly in registry, attempting generic parsing."
54
- )
55
- pass # Not found, continue parsing generics
56
-
57
- # 2. Handle typing generics (List, Dict, Optional, Union, Literal)
58
- # Use regex to match pattern like Generic[InnerType1, InnerType2, ...]
59
- generic_match = re.fullmatch(r"(\w+)\s*\[(.*)\]", type_str)
60
- if generic_match:
61
- base_name = generic_match.group(1).strip()
62
- args_str = generic_match.group(2).strip()
63
- logger.debug(
64
- f"Detected generic pattern: Base='{base_name}', Args='{args_str}'"
65
- )
66
-
67
- try:
68
- # Get the base generic type (e.g., list, dict, Optional) from registry/builtins
69
- BaseType = registry.get_type(
70
- base_name
71
- ) # Expects List, Dict etc. to be registered
72
- logger.debug(
73
- f"Resolved base generic type '{base_name}' to: {BaseType}"
74
- )
75
-
76
- # Special handling for Literal
77
- if BaseType is typing.Literal:
78
- # Split literal values, remove quotes, strip whitespace
79
- def parse_literal_args(args_str: str) -> tuple[str, ...]:
80
- try:
81
- return tuple(ast.literal_eval(f"[{args_str}]"))
82
- except (SyntaxError, ValueError) as exc:
83
- raise ValueError(
84
- f"Cannot parse {args_str!r} as literals"
85
- ) from exc
86
-
87
- literal_args = parse_literal_args(args_str)
88
- logger.debug(
89
- f"Parsing Literal arguments: {args_str} -> {literal_args}"
90
- )
91
- resolved_type = typing.Literal[literal_args] # type: ignore
92
- logger.debug(f"Constructed Literal type: {resolved_type}")
93
- return resolved_type
94
-
95
- # Recursively resolve arguments for other generics
96
- logger.debug(f"Splitting generic arguments: '{args_str}'")
97
- arg_strs = split_top_level(args_str)
98
- logger.debug(f"Split arguments: {arg_strs}")
99
- if not arg_strs:
100
- raise ValueError("Generic type has no arguments.")
101
-
102
- resolved_arg_types = tuple(
103
- _resolve_type_string(arg) for arg in arg_strs
104
- )
105
- logger.debug(f"Resolved generic arguments: {resolved_arg_types}")
106
-
107
- # Construct the generic type hint
108
- if BaseType is typing.Optional:
109
- if len(resolved_arg_types) != 1:
110
- raise ValueError("Optional requires exactly one argument.")
111
- # type: ignore
112
- resolved_type = typing.Union[resolved_arg_types[0], type(None)]
113
- logger.debug(
114
- f"Constructed Optional type as Union: {resolved_type}"
115
- )
116
- return resolved_type
117
- elif BaseType is typing.Union:
118
- if not resolved_arg_types:
119
- raise ValueError("Union requires at least one argument.")
120
- # type: ignore
121
- resolved_type = typing.Union[resolved_arg_types]
122
- logger.debug(f"Constructed Union type: {resolved_type}")
123
- return resolved_type
124
- elif hasattr(
125
- BaseType, "__getitem__"
126
- ): # Check if subscriptable (like list, dict, List, Dict)
127
- resolved_type = BaseType[resolved_arg_types] # type: ignore
128
- logger.debug(
129
- f"Constructed subscripted generic type: {resolved_type}"
130
- )
131
- return resolved_type
132
- else:
133
- # Base type found but cannot be subscripted
134
- logger.warning(
135
- f"Base type '{base_name}' found but is not a standard subscriptable generic. Returning base type."
136
- )
137
- return BaseType
138
-
139
- except (KeyError, ValueError, IndexError, TypeError) as e:
140
- logger.warning(
141
- f"Failed to parse generic type '{type_str}': {e}. Falling back."
142
- )
143
- # Fall through to raise KeyError below if base type itself wasn't found or parsing failed
144
-
145
- # 3. If not resolved by now, raise error
146
- logger.error(f"Type string '{type_str}' could not be resolved.")
147
- raise KeyError(f"Type '{type_str}' could not be resolved.")
148
-
149
-
150
- class DSPyIntegrationMixin:
151
- """Mixin class for integrating with the dspy library."""
152
-
153
- def create_dspy_signature_class(self, agent_name: str, description_spec: str, fields_spec: str) -> Any:
154
- """Create a DSPy Signature using DSPy's native builder.
155
-
156
- We support the Flock spec format: "field: type | description, ... -> ...".
157
- This converts to the dict-based make_signature format with
158
- InputField/OutputField and resolved Python types.
159
- """
160
- try:
161
- import dspy
162
- except ImportError as exc:
163
- logger.error("DSPy is not installed. Install with: pip install dspy-ai")
164
- raise
165
-
166
- # Split input/output part
167
- if "->" in fields_spec:
168
- inputs_spec, outputs_spec = fields_spec.split("->", 1)
169
- else:
170
- inputs_spec, outputs_spec = fields_spec, ""
171
-
172
- def parse_field(field_str: str) -> tuple[str, type, str | None] | None:
173
- field_str = field_str.strip()
174
- if not field_str:
175
- return None
176
- parts = field_str.split("|", 1)
177
- main_part = parts[0].strip()
178
- desc = parts[1].strip() if len(parts) > 1 else None
179
- if ":" in main_part:
180
- name, type_str = [s.strip() for s in main_part.split(":", 1)]
181
- else:
182
- name, type_str = main_part, "str"
183
- try:
184
- py_type = _resolve_type_string(type_str)
185
- except Exception as e:
186
- logger.warning(
187
- f"Type resolution failed for '{type_str}' in field '{name}': {e}. Falling back to str."
188
- )
189
- py_type = str
190
- return name, py_type, desc
191
-
192
- def to_field_tuples(spec: str, kind: str) -> dict[str, tuple[type, Any]]:
193
- mapping: dict[str, tuple[type, Any]] = {}
194
- if not spec.strip():
195
- return mapping
196
- for raw in split_top_level(spec):
197
- parsed = parse_field(raw)
198
- if not parsed:
199
- continue
200
- fname, ftype, fdesc = parsed
201
- FieldClass = dspy.InputField if kind == "input" else dspy.OutputField
202
- finfo = FieldClass(desc=fdesc) if fdesc is not None else FieldClass()
203
- mapping[fname] = (ftype, finfo)
204
- return mapping
205
-
206
- try:
207
- fields: dict[str, tuple[type, Any]] = {
208
- **to_field_tuples(inputs_spec, "input"),
209
- **to_field_tuples(outputs_spec, "output"),
210
- }
211
- sig = dspy.Signature(fields, description_spec or None, signature_name=f"dspy_{agent_name}")
212
- logger.info("Created DSPy Signature %s", sig.__name__)
213
- return sig
214
- except Exception as e: # pragma: no cover - defensive
215
- logger.error("Failed to create DSPy Signature for %s: %s", agent_name, e, exc_info=True)
216
- raise
217
-
218
- def _configure_language_model(
219
- self,
220
- model: str | None,
221
- use_cache: bool,
222
- temperature: float,
223
- max_tokens: int,
224
- ) -> None:
225
- """Initialize and configure the language model using dspy."""
226
- if model is None:
227
- logger.warning(
228
- "No model specified for DSPy configuration. Using DSPy default."
229
- )
230
- # Rely on DSPy's global default or raise error if none configured
231
- # import dspy
232
- # if dspy.settings.lm is None:
233
- # raise ValueError("No model specified for agent and no global DSPy LM configured.")
234
- return
235
-
236
- try:
237
- import dspy
238
- except ImportError:
239
- logger.error("DSPy is not installed; cannot configure LM.")
240
- return
241
-
242
- # Build an LM instance for per-call usage; prefer settings.context over global configure.
243
- try:
244
- lm_instance = dspy.LM(
245
- model=model,
246
- temperature=temperature,
247
- max_tokens=max_tokens,
248
- cache=use_cache,
249
- )
250
- # Do not call settings.configure() here to avoid cross-task/thread conflicts.
251
- # Callers should pass this LM via dspy.settings.context(lm=...) or program.acall(lm=...)
252
- dspy.settings # touch to ensure settings is importable
253
- logger.info(
254
- "Prepared DSPy LM (defer install to settings.context): model=%s temp=%s max_tokens=%s",
255
- model,
256
- temperature,
257
- max_tokens,
258
- )
259
- except Exception as e:
260
- logger.error("Failed to prepare DSPy LM '%s': %s", model, e, exc_info=True)
261
- raise
262
-
263
- def _select_task(
264
- self,
265
- signature: Any,
266
- override_evaluator_type: AgentType,
267
- max_tool_calls: int = 10,
268
- tools: list[Any] | None = None,
269
- mcp_tools: list[Any] | None = None,
270
- kwargs: dict[str, Any] = {},
271
- ) -> Any:
272
- """Select and instantiate the appropriate DSPy Program/Module."""
273
- try:
274
- import dspy
275
- except ImportError:
276
- logger.error(
277
- "DSPy library is not installed. Cannot select DSPy task."
278
- )
279
- raise ImportError("DSPy is required for this functionality.")
280
-
281
- processed_tools = []
282
- if tools:
283
- for tool in tools:
284
- if callable(tool): # Basic check
285
- processed_tools.append(tool)
286
- # Could add more sophisticated tool wrapping/validation here if needed
287
- else:
288
- logger.warning(
289
- f"Item '{tool}' in tools list is not callable, skipping."
290
- )
291
-
292
- processed_mcp_tools = []
293
- if mcp_tools:
294
- for mcp_tool in mcp_tools:
295
- if isinstance(mcp_tool, Tool): # Basic check
296
- processed_mcp_tools.append(mcp_tool)
297
- else:
298
- logger.warning(
299
- f"Item '{mcp_tool}' is not a dspy.primitives.Tool, skipping."
300
- )
301
-
302
- dspy_program = None
303
- selected_type = override_evaluator_type
304
-
305
- # Determine type if not overridden
306
- if not selected_type:
307
- selected_type = "ReAct" if processed_tools or processed_mcp_tools else "Predict"
308
-
309
- # Normalize common aliases/casing
310
- sel = selected_type.lower() if isinstance(selected_type, str) else selected_type
311
- if isinstance(sel, str):
312
- if sel in {"completion", "predict"}:
313
- sel = "predict"
314
- elif sel in {"react"}:
315
- sel = "react"
316
- elif sel in {"chainofthought", "cot", "chain_of_thought"}:
317
- sel = "chain_of_thought"
318
-
319
- logger.debug(
320
- f"Selecting DSPy program type: {selected_type} (Tools provided: {bool(processed_tools)}) (MCP Tools: {bool(processed_mcp_tools)}"
321
- )
322
-
323
- # Merge list of native tools and processed tools.
324
- # This makes mcp tools appear as native code functions to the llm of the agent.
325
- merged_tools = []
326
-
327
- if processed_tools:
328
- merged_tools = merged_tools + processed_tools
329
-
330
- if processed_mcp_tools:
331
- merged_tools = merged_tools + processed_mcp_tools
332
-
333
- try:
334
- if sel == "chain_of_thought":
335
- dspy_program = dspy.ChainOfThought(signature, **kwargs)
336
- elif sel == "react":
337
- if not kwargs:
338
- kwargs = {"max_iters": max_tool_calls}
339
- dspy_program = dspy.ReAct(
340
- signature, tools=merged_tools or [], **kwargs
341
- )
342
- elif sel == "predict":
343
- dspy_program = dspy.Predict(signature)
344
- else: # Fallback or handle unknown type
345
- logger.warning(
346
- f"Unknown or unsupported agent_type_override '{selected_type}'. Defaulting to dspy.Predict."
347
- )
348
- dspy_program = dspy.Predict(signature)
349
-
350
- logger.info(
351
- f"Instantiated DSPy program: {type(dspy_program).__name__}"
352
- )
353
- return dspy_program
354
- except Exception as e:
355
- logger.error(
356
- f"Failed to instantiate DSPy program of type '{selected_type}': {e}",
357
- exc_info=True,
358
- )
359
- raise RuntimeError(f"Could not create DSPy program: {e}") from e
360
-
361
- def _process_result(self, result: Any, inputs: dict[str, Any]) -> tuple[dict[str, Any], float, list]:
362
- """Convert a DSPy Prediction or mapping to a plain dict and attach LM history.
363
-
364
- Returns (result_dict, cost_placeholder, lm_history). The cost is set to 0.0;
365
- use token usage trackers elsewhere for accurate accounting.
366
- """
367
- try:
368
- import dspy
369
- except ImportError:
370
- dspy = None
371
-
372
- if result is None:
373
- logger.warning("DSPy program returned None result.")
374
- return {}, 0.0, []
375
-
376
- try:
377
- # Best-effort extraction from DSPy Prediction
378
- if dspy and isinstance(result, dspy.Prediction):
379
- output_dict = dict(result.items(include_dspy=False))
380
- elif isinstance(result, dict):
381
- output_dict = result
382
- elif hasattr(result, "items") and callable(result.items):
383
- try:
384
- output_dict = dict(result.items())
385
- except Exception:
386
- output_dict = {"raw_result": str(result)}
387
- else:
388
- output_dict = {"raw_result": str(result)}
389
-
390
- final_result = {**inputs, **output_dict}
391
-
392
- lm_history = []
393
- try:
394
- if dspy and dspy.settings.lm is not None and hasattr(dspy.settings.lm, "history"):
395
- lm_history = dspy.settings.lm.history
396
- except Exception:
397
- lm_history = []
398
-
399
- return final_result, 0.0, lm_history
400
-
401
- except Exception as conv_error: # pragma: no cover - defensive
402
- logger.error("Failed to process DSPy result into dictionary: %s", conv_error, exc_info=True)
403
- return {"error": "Failed to process result", "raw_result": str(result)}, 0.0, []