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,206 +0,0 @@
1
- # src/flock/components/routing/llm_routing_component.py
2
- """LLM-based routing component implementation for the unified component architecture."""
3
-
4
- import json
5
- from typing import TYPE_CHECKING, Any
6
-
7
- import litellm
8
- from pydantic import Field
9
-
10
- from flock.core.component.agent_component_base import AgentComponentConfig
11
- from flock.core.component.routing_component import RoutingComponent
12
- from flock.core.context.context import FlockContext
13
-
14
- # HandOffRequest removed - using agent.next_agent directly
15
- from flock.core.logging.logging import get_logger
16
- from flock.core.registry import flock_component
17
-
18
- if TYPE_CHECKING:
19
- from flock.core.flock_agent import FlockAgent
20
-
21
- logger = get_logger("components.routing.llm")
22
-
23
-
24
- class LLMRoutingConfig(AgentComponentConfig):
25
- """Configuration for the LLM routing component."""
26
-
27
- temperature: float = Field(
28
- default=0.2, description="Temperature for LLM routing decisions"
29
- )
30
- max_tokens: int = Field(
31
- default=500, description="Maximum tokens for LLM response"
32
- )
33
- confidence_threshold: float = Field(
34
- default=0.5, description="Minimum confidence threshold for routing"
35
- )
36
- model: str = Field(
37
- default="azure/gpt-4.1", description="Model to use for routing decisions"
38
- )
39
- prompt_template: str = Field(
40
- default="""You are a workflow routing assistant. Given the current agent's output and available next agents, determine which agent should execute next.
41
-
42
- Current Agent: {current_agent_name}
43
- Current Output: {current_output}
44
-
45
- Available Agents:
46
- {available_agents}
47
-
48
- Select the most appropriate next agent based on the current output. Respond with JSON in this exact format:
49
- {{"next_agent": "agent_name", "confidence": 0.8, "reasoning": "explanation"}}
50
-
51
- If no agent is suitable, use "next_agent": "" to end the workflow.""",
52
- description="Template for LLM routing prompt"
53
- )
54
-
55
-
56
- @flock_component(config_class=LLMRoutingConfig)
57
- class LLMRoutingComponent(RoutingComponent):
58
- """Router that uses an LLM to determine the next agent in a workflow.
59
-
60
- This component analyzes the current agent's output and uses an LLM to
61
- intelligently select the most appropriate next agent from available options.
62
- """
63
-
64
- config: LLMRoutingConfig = Field(
65
- default_factory=LLMRoutingConfig
66
- )
67
-
68
- def __init__(
69
- self,
70
- name: str = "llm_router",
71
- config: LLMRoutingConfig | None = None,
72
- **data,
73
- ):
74
- if config is None:
75
- config = LLMRoutingConfig()
76
- super().__init__(name=name, config=config, **data)
77
-
78
- def _get_available_agents(
79
- self, agent_definitions: dict[str, Any], current_agent_name: str
80
- ) -> list[str]:
81
- """Get list of available agent names except the current one."""
82
- available = []
83
- for agent_name in agent_definitions:
84
- if agent_name != current_agent_name:
85
- available.append(agent_name)
86
- return available
87
-
88
- def _create_selection_prompt(
89
- self,
90
- current_agent: "FlockAgent",
91
- result: dict[str, Any],
92
- available_agents: list[str],
93
- ) -> str:
94
- """Create the prompt for LLM agent selection."""
95
- # Format available agents
96
- agents_list = []
97
- for agent_name in available_agents:
98
- agents_list.append(f"- {agent_name}")
99
-
100
- available_agents_str = "\n".join(agents_list) if agents_list else "None available"
101
-
102
- # Format current output
103
- current_output = json.dumps(result, indent=2) if result else "No output"
104
-
105
- return self.config.prompt_template.format(
106
- current_agent_name=current_agent.name,
107
- current_output=current_output,
108
- available_agents=available_agents_str
109
- )
110
-
111
- async def _select_next_agent(
112
- self,
113
- current_agent: "FlockAgent",
114
- result: dict[str, Any],
115
- available_agents: list[str],
116
- ) -> tuple[str, float]:
117
- """Use an LLM to select the best next agent."""
118
- if not available_agents:
119
- logger.warning("No available agents for LLM routing")
120
- return "", 0.0
121
-
122
- # Create the selection prompt
123
- prompt = self._create_selection_prompt(current_agent, result, available_agents)
124
-
125
- try:
126
- # Call the LLM
127
- response = await litellm.acompletion(
128
- model=self.config.model,
129
- messages=[
130
- {"role": "user", "content": prompt}
131
- ],
132
- temperature=self.config.temperature,
133
- max_tokens=self.config.max_tokens,
134
- )
135
-
136
- response_content = response.choices[0].message.content.strip()
137
- logger.debug(f"LLM routing response: {response_content}")
138
-
139
- # Parse the JSON response
140
- try:
141
- routing_decision = json.loads(response_content)
142
- next_agent = routing_decision.get("next_agent", "")
143
- confidence = routing_decision.get("confidence", 0.0)
144
- reasoning = routing_decision.get("reasoning", "No reasoning provided")
145
-
146
- logger.info(f"LLM routing decision: {next_agent} (confidence: {confidence}) - {reasoning}")
147
-
148
- # Validate the selected agent is available
149
- if next_agent and next_agent not in available_agents and next_agent != "":
150
- logger.warning(f"LLM selected unavailable agent '{next_agent}', ending workflow")
151
- return "", 0.0
152
-
153
- return next_agent, confidence
154
-
155
- except json.JSONDecodeError as e:
156
- logger.error(f"Failed to parse LLM response as JSON: {e}")
157
- return "", 0.0
158
-
159
- except Exception as e:
160
- logger.error(f"Error calling LLM for routing: {e}")
161
- return "", 0.0
162
-
163
- async def determine_next_step(
164
- self,
165
- agent: "FlockAgent",
166
- result: dict[str, Any],
167
- context: FlockContext | None = None,
168
- ) -> None:
169
- """Use LLM to determine the next agent based on current output."""
170
- if not context:
171
- logger.warning("No context provided for LLM routing")
172
- return
173
-
174
- logger.info(f"LLM routing from agent '{agent.name}'")
175
-
176
- # Get available agents from context
177
- agent_definitions = getattr(context, 'agent_definitions', {})
178
- available_agents = self._get_available_agents(agent_definitions, agent.name)
179
-
180
- logger.debug(f"Available agents for LLM routing: {available_agents}")
181
-
182
- if not available_agents:
183
- logger.warning("No available agents for LLM routing")
184
- return
185
-
186
- # Use LLM to select the next agent
187
- next_agent_name, confidence = await self._select_next_agent(
188
- agent, result, available_agents
189
- )
190
-
191
- logger.info(f"LLM routing result: {next_agent_name} (confidence: {confidence})")
192
-
193
- # Check confidence threshold
194
- if not next_agent_name or confidence < self.config.confidence_threshold:
195
- logger.warning(
196
- f"LLM routing confidence {confidence} below threshold {self.config.confidence_threshold}"
197
- )
198
- return
199
-
200
- # Validate the selected agent exists
201
- if next_agent_name not in agent_definitions:
202
- logger.error(f"LLM selected non-existent agent '{next_agent_name}'")
203
- return
204
-
205
- logger.info(f"Successfully routed to agent '{next_agent_name}' with confidence {confidence}")
206
- agent.next_agent = next_agent_name
@@ -1,22 +0,0 @@
1
- # src/flock/components/utility/__init__.py
2
- """Utility components for the Flock framework."""
3
-
4
- from .example_utility_component import ExampleUtilityComponent, ExampleUtilityConfig, ExampleRecord
5
- from .feedback_utility_component import FeedbackUtilityComponent, FeedbackUtilityConfig
6
- from .memory_utility_component import MemoryUtilityComponent, MemoryUtilityConfig
7
- from .metrics_utility_component import MetricsUtilityComponent, MetricsUtilityConfig
8
- from .output_utility_component import OutputUtilityComponent, OutputUtilityConfig
9
-
10
- __all__ = [
11
- "ExampleUtilityComponent",
12
- "ExampleUtilityConfig",
13
- "ExampleRecord",
14
- "FeedbackUtilityComponent",
15
- "FeedbackUtilityConfig",
16
- "MemoryUtilityComponent",
17
- "MemoryUtilityConfig",
18
- "MetricsUtilityComponent",
19
- "MetricsUtilityConfig",
20
- "OutputUtilityComponent",
21
- "OutputUtilityConfig",
22
- ]
@@ -1,250 +0,0 @@
1
- """Example utility component for n-shot learning."""
2
-
3
- from datetime import datetime, timedelta
4
- from typing import Any, Literal
5
-
6
- from pydantic import Field
7
-
8
- from flock.core.component.agent_component_base import AgentComponentConfig
9
- from flock.core.component.utility_component import UtilityComponent
10
- from flock.core.context.context import FlockContext
11
- from flock.core.logging.logging import get_logger
12
- from flock.core.registry import flock_component
13
-
14
- if TYPE_CHECKING:
15
- from flock.core.flock_agent import FlockAgent
16
- from flock.webapp.app.services.sharing_store import SharedLinkStoreInterface
17
-
18
- logger = get_logger("components.utility.example")
19
-
20
-
21
- class ExampleUtilityConfig(AgentComponentConfig):
22
- """Configuration for the ExampleUtilityComponent."""
23
-
24
- # Storage configuration
25
- storage_type: Literal["sqlite", "azure"] = Field(
26
- default="sqlite",
27
- description="Type of storage backend for example data"
28
- )
29
-
30
- # SQLite configuration
31
- sqlite_db_path: str = Field(
32
- default="./flock_examples.db",
33
- description="Path to SQLite database file"
34
- )
35
-
36
- # Azure Table Storage configuration
37
- azure_connection_string: str | None = Field(
38
- default=None,
39
- description="Azure Table Storage connection string"
40
- )
41
- azure_table_name: str = Field(
42
- default="flockexamples",
43
- description="Azure Table Storage table name"
44
- )
45
-
46
- # Example selection criteria
47
- max_examples: int = Field(
48
- default=5,
49
- description="Maximum number of examples to include"
50
- )
51
- example_timeframe_days: int = Field(
52
- default=30,
53
- description="Only include examples from the last N days"
54
- )
55
-
56
- # Example injection settings
57
- example_input_key: str = Field(
58
- default="examples_context",
59
- description="Input key to use for injected examples"
60
- )
61
-
62
- # Example filtering
63
- example_filter_keywords: list[str] = Field(
64
- default_factory=list,
65
- description="Keywords to filter examples (only include examples containing these)"
66
- )
67
- example_exclude_keywords: list[str] = Field(
68
- default_factory=list,
69
- description="Keywords to exclude examples containing these"
70
- )
71
-
72
-
73
- @flock_component(config_class=ExampleUtilityConfig)
74
- class ExampleUtilityComponent(UtilityComponent):
75
- """Utility component that injects relevant examples into agent inputs for n-shot learning."""
76
-
77
- config: ExampleUtilityConfig = Field(
78
- default_factory=ExampleUtilityConfig,
79
- description="Example component configuration"
80
- )
81
-
82
- def __init__(self, name: str = "examples", config: ExampleUtilityConfig | None = None, **data):
83
- super().__init__(name=name, config=config or ExampleUtilityConfig(), **data)
84
- self._store: SharedLinkStoreInterface | None = None
85
-
86
- async def _get_store(self) -> SharedLinkStoreInterface:
87
- """Get the appropriate example store based on configuration."""
88
- if self._store is None:
89
- if self.config.storage_type == "sqlite":
90
- from flock.webapp.app.services.sharing_store import SQLiteSharedLinkStore
91
- self._store = SQLiteSharedLinkStore(self.config.sqlite_db_path)
92
- elif self.config.storage_type == "azure":
93
- if not self.config.azure_connection_string:
94
- raise ValueError("Azure connection string is required for Azure storage")
95
- from flock.webapp.app.services.sharing_store import AzureTableSharedLinkStore
96
- self._store = AzureTableSharedLinkStore(
97
- connection_string=self.config.azure_connection_string,
98
- table_name=self.config.azure_table_name
99
- )
100
- else:
101
- raise ValueError(f"Unsupported storage type: {self.config.storage_type}")
102
-
103
- await self._store.initialize()
104
-
105
- return self._store
106
-
107
- @staticmethod
108
- def seed_examples(examples: list["ExampleRecord"]) -> None:
109
- """Seed examples into the storage system.
110
-
111
- Args:
112
- examples: List of ExampleRecord objects to seed
113
- """
114
- import asyncio
115
-
116
- async def _seed_examples():
117
- # Create a default component for seeding
118
- component = ExampleUtilityComponent()
119
- store = await component._get_store()
120
-
121
- for example in examples:
122
- await store.save_example(example)
123
-
124
- logger.info(f"Seeded {len(examples)} examples into storage")
125
-
126
- # Run the async function
127
- asyncio.run(_seed_examples())
128
-
129
- async def _get_relevant_examples(
130
- self,
131
- agent_name: str,
132
- inputs: dict[str, Any]
133
- ) -> list["ExampleRecord"]:
134
- """Get relevant examples for the given agent and inputs."""
135
- store = await self._get_store()
136
-
137
- # Get all examples for this agent
138
- all_examples = await store.get_all_examples_for_agent(agent_name)
139
-
140
- # Filter by timeframe
141
- cutoff_date = datetime.utcnow() - timedelta(days=self.config.example_timeframe_days)
142
- filtered_examples = [
143
- ex for ex in all_examples
144
- if ex.created_at >= cutoff_date
145
- ]
146
-
147
- # Filter by keywords if specified
148
- if self.config.example_filter_keywords:
149
- filtered_examples = [
150
- ex for ex in filtered_examples
151
- if any(keyword.lower() in ex.content.lower() for keyword in self.config.example_filter_keywords)
152
- ]
153
-
154
- # Exclude by keywords if specified
155
- if self.config.example_exclude_keywords:
156
- filtered_examples = [
157
- ex for ex in filtered_examples
158
- if not any(keyword.lower() in ex.content.lower() for keyword in self.config.example_exclude_keywords)
159
- ]
160
-
161
- # Sort by recency and limit
162
- filtered_examples.sort(key=lambda ex: ex.created_at, reverse=True)
163
- return filtered_examples[:self.config.max_examples]
164
-
165
- def _format_examples_for_injection(
166
- self,
167
- example_records: list["ExampleRecord"]
168
- ) -> str:
169
- """Format example records for injection into agent input."""
170
- if not example_records:
171
- return "No relevant examples available."
172
-
173
- formatted_parts = []
174
- formatted_parts.append(f"Here are {len(example_records)} examples to guide your response:")
175
-
176
- for i, ex in enumerate(example_records, 1):
177
- ex_text = f"\nExample {i} (ID: {ex.example_id}):"
178
- ex_text += f"\n{ex.content}"
179
- ex_text += f"\nDate: {ex.created_at.strftime('%Y-%m-%d')}"
180
- formatted_parts.append(ex_text)
181
-
182
- return "\n".join(formatted_parts)
183
-
184
- async def on_pre_evaluate(
185
- self,
186
- agent: "FlockAgent",
187
- inputs: dict[str, Any],
188
- context: FlockContext | None = None,
189
- ) -> dict[str, Any]:
190
- """Inject relevant examples into agent inputs before evaluation."""
191
- logger.debug(f"Injecting examples for agent '{agent.name}'")
192
-
193
- try:
194
- # Get relevant examples for this agent
195
- example_records = await self._get_relevant_examples(agent.name, inputs)
196
-
197
- # Format examples for injection
198
- formatted_examples = self._format_examples_for_injection(example_records)
199
-
200
- # Create a copy of inputs to avoid modifying the original
201
- enhanced_inputs = inputs.copy()
202
-
203
- # Inject examples using the configured key
204
- enhanced_inputs[self.config.example_input_key] = formatted_examples
205
-
206
- logger.debug(f"Injected {len(example_records)} examples into '{self.config.example_input_key}'")
207
-
208
- return enhanced_inputs
209
-
210
- except Exception as e:
211
- logger.error(f"Error injecting examples: {e}")
212
- # Return original inputs if example injection fails
213
- return inputs
214
-
215
-
216
- # Example record model
217
- class ExampleRecord:
218
- """Record for storing example data."""
219
-
220
- def __init__(
221
- self,
222
- agent_name: str,
223
- example_id: str,
224
- content: str,
225
- created_at: datetime | None = None
226
- ):
227
- self.agent_name = agent_name
228
- self.example_id = example_id
229
- self.content = content
230
- self.created_at = created_at or datetime.utcnow()
231
-
232
- def to_dict(self) -> dict[str, Any]:
233
- """Convert to dictionary for storage."""
234
- return {
235
- "agent_name": self.agent_name,
236
- "example_id": self.example_id,
237
- "content": self.content,
238
- "created_at": self.created_at.isoformat(),
239
- "context_type": "example"
240
- }
241
-
242
- @classmethod
243
- def from_dict(cls, data: dict[str, Any]) -> "ExampleRecord":
244
- """Create from dictionary from storage."""
245
- return cls(
246
- agent_name=data["agent_name"],
247
- example_id=data["example_id"],
248
- content=data["content"],
249
- created_at=datetime.fromisoformat(data["created_at"])
250
- )
@@ -1,206 +0,0 @@
1
- """Feedback utility component for learning from user feedback."""
2
-
3
- from datetime import datetime, timedelta
4
- from typing import TYPE_CHECKING, Any, Literal
5
-
6
- from pydantic import Field
7
-
8
- from flock.core.component.agent_component_base import AgentComponentConfig
9
- from flock.core.component.utility_component import UtilityComponent
10
- from flock.core.context.context import FlockContext
11
- from flock.core.logging.logging import get_logger
12
- from flock.core.registry import flock_component
13
-
14
- if TYPE_CHECKING:
15
- from flock.core.flock_agent import FlockAgent
16
- from flock.webapp.app.services.sharing_models import FeedbackRecord
17
- from flock.webapp.app.services.sharing_store import SharedLinkStoreInterface
18
-
19
- logger = get_logger("components.utility.feedback")
20
-
21
-
22
- class FeedbackUtilityConfig(AgentComponentConfig):
23
- """Configuration for the FeedbackUtilityComponent."""
24
-
25
- # Storage configuration
26
- storage_type: Literal["sqlite", "azure"] = Field(
27
- default="sqlite",
28
- description="Type of storage backend for feedback data"
29
- )
30
-
31
- # SQLite configuration
32
- sqlite_db_path: str = Field(
33
- default="./flock_feedback.db",
34
- description="Path to SQLite database file"
35
- )
36
-
37
- # Azure Table Storage configuration
38
- azure_connection_string: str | None = Field(
39
- default=None,
40
- description="Azure Table Storage connection string"
41
- )
42
- azure_table_name: str = Field(
43
- default="flockfeedback",
44
- description="Azure Table Storage table name"
45
- )
46
-
47
- # Feedback selection criteria
48
- max_feedback_items: int = Field(
49
- default=5,
50
- description="Maximum number of feedback items to include"
51
- )
52
- feedback_timeframe_days: int = Field(
53
- default=30,
54
- description="Only include feedback from the last N days"
55
- )
56
-
57
- # Feedback injection settings
58
- feedback_input_key: str = Field(
59
- default="feedback_context",
60
- description="Input key to use for injected feedback"
61
- )
62
- include_expected_responses: bool = Field(
63
- default=True,
64
- description="Whether to include expected responses from feedback"
65
- )
66
- include_actual_responses: bool = Field(
67
- default=False,
68
- description="Whether to include actual responses from feedback"
69
- )
70
-
71
- # Feedback filtering
72
- feedback_filter_keywords: list[str] = Field(
73
- default_factory=list,
74
- description="Keywords to filter feedback (only include feedback containing these)"
75
- )
76
- feedback_exclude_keywords: list[str] = Field(
77
- default_factory=list,
78
- description="Keywords to exclude feedback containing these"
79
- )
80
-
81
-
82
- @flock_component(config_class=FeedbackUtilityConfig)
83
- class FeedbackUtilityComponent(UtilityComponent):
84
- """Utility component that injects relevant feedback into agent inputs."""
85
-
86
- config: FeedbackUtilityConfig = Field(
87
- default_factory=FeedbackUtilityConfig,
88
- description="Feedback component configuration"
89
- )
90
-
91
- def __init__(self, name: str = "feedback", config: FeedbackUtilityConfig | None = None, **data):
92
- super().__init__(name=name, config=config or FeedbackUtilityConfig(), **data)
93
- self._store: SharedLinkStoreInterface | None = None
94
-
95
- async def _get_store(self) -> SharedLinkStoreInterface:
96
- """Get the appropriate feedback store based on configuration."""
97
- if self._store is None:
98
- if self.config.storage_type == "sqlite":
99
- from flock.webapp.app.services.sharing_store import SQLiteSharedLinkStore
100
- self._store = SQLiteSharedLinkStore(self.config.sqlite_db_path)
101
- elif self.config.storage_type == "azure":
102
- if not self.config.azure_connection_string:
103
- raise ValueError("Azure connection string is required for Azure storage")
104
- from flock.webapp.app.services.sharing_store import AzureTableSharedLinkStore
105
- self._store = AzureTableSharedLinkStore(
106
- connection_string=self.config.azure_connection_string,
107
- table_name=self.config.azure_table_name
108
- )
109
- else:
110
- raise ValueError(f"Unsupported storage type: {self.config.storage_type}")
111
-
112
- await self._store.initialize()
113
-
114
- return self._store
115
-
116
- async def _get_relevant_feedback(
117
- self,
118
- agent_name: str,
119
- inputs: dict[str, Any]
120
- ) -> list["FeedbackRecord"]:
121
- """Get relevant feedback for the given agent and inputs."""
122
- store = await self._get_store()
123
-
124
- # Get all feedback for this agent
125
- all_feedback = await store.get_all_feedback_records_for_agent(agent_name)
126
-
127
- # Filter by timeframe
128
- cutoff_date = datetime.utcnow() - timedelta(days=self.config.feedback_timeframe_days)
129
- filtered_feedback = [
130
- fb for fb in all_feedback
131
- if fb.created_at >= cutoff_date
132
- ]
133
-
134
- # Filter by keywords if specified
135
- if self.config.feedback_filter_keywords:
136
- filtered_feedback = [
137
- fb for fb in filtered_feedback
138
- if any(keyword.lower() in fb.reason.lower() for keyword in self.config.feedback_filter_keywords)
139
- ]
140
-
141
- # Exclude by keywords if specified
142
- if self.config.feedback_exclude_keywords:
143
- filtered_feedback = [
144
- fb for fb in filtered_feedback
145
- if not any(keyword.lower() in fb.reason.lower() for keyword in self.config.feedback_exclude_keywords)
146
- ]
147
-
148
- # Sort by recency and limit
149
- filtered_feedback.sort(key=lambda fb: fb.created_at, reverse=True)
150
- return filtered_feedback[:self.config.max_feedback_items]
151
-
152
- def _format_feedback_for_injection(
153
- self,
154
- feedback_records: list["FeedbackRecord"]
155
- ) -> str:
156
- """Format feedback records for injection into agent input."""
157
- if not feedback_records:
158
- return "No relevant feedback available."
159
-
160
- formatted_parts = []
161
- formatted_parts.append(f"Here are {len(feedback_records)} pieces of relevant feedback from previous interactions:")
162
-
163
- for i, fb in enumerate(feedback_records, 1):
164
- fb_text = f"\n{i}. Feedback: {fb.reason}"
165
-
166
- if self.config.include_expected_responses and fb.expected_response:
167
- fb_text += f"\n Expected response: {fb.expected_response}"
168
-
169
- if self.config.include_actual_responses and fb.actual_response:
170
- fb_text += f"\n Actual response: {fb.actual_response}"
171
-
172
- fb_text += f"\n Date: {fb.created_at.strftime('%Y-%m-%d')}"
173
- formatted_parts.append(fb_text)
174
-
175
- return "\n".join(formatted_parts)
176
-
177
- async def on_pre_evaluate(
178
- self,
179
- agent: "FlockAgent",
180
- inputs: dict[str, Any],
181
- context: FlockContext | None = None,
182
- ) -> dict[str, Any]:
183
- """Inject relevant feedback into agent inputs before evaluation."""
184
- logger.debug(f"Injecting feedback for agent '{agent.name}'")
185
-
186
- try:
187
- # Get relevant feedback for this agent
188
- feedback_records = await self._get_relevant_feedback(agent.name, inputs)
189
-
190
- # Format feedback for injection
191
- formatted_feedback = self._format_feedback_for_injection(feedback_records)
192
-
193
- # Create a copy of inputs to avoid modifying the original
194
- enhanced_inputs = inputs.copy()
195
-
196
- # Inject feedback using the configured key
197
- enhanced_inputs[self.config.feedback_input_key] = formatted_feedback
198
-
199
- logger.debug(f"Injected {len(feedback_records)} feedback items into '{self.config.feedback_input_key}'")
200
-
201
- return enhanced_inputs
202
-
203
- except Exception as e:
204
- logger.error(f"Error injecting feedback: {e}")
205
- # Return original inputs if feedback injection fails
206
- return inputs