flock-core 0.4.542__py3-none-any.whl → 0.5.0__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 (501) hide show
  1. flock/__init__.py +12 -217
  2. flock/agent.py +1079 -0
  3. flock/api/themes.py +71 -0
  4. flock/artifacts.py +86 -0
  5. flock/cli.py +147 -0
  6. flock/components.py +189 -0
  7. flock/dashboard/__init__.py +30 -0
  8. flock/dashboard/collector.py +559 -0
  9. flock/dashboard/events.py +188 -0
  10. flock/dashboard/graph_builder.py +563 -0
  11. flock/dashboard/launcher.py +235 -0
  12. flock/dashboard/models/graph.py +156 -0
  13. flock/dashboard/service.py +991 -0
  14. flock/dashboard/static_v2/assets/index-DFRnI_mt.js +111 -0
  15. flock/dashboard/static_v2/assets/index-fPLNdmp1.css +1 -0
  16. flock/dashboard/static_v2/index.html +13 -0
  17. flock/dashboard/websocket.py +246 -0
  18. flock/engines/__init__.py +6 -0
  19. flock/engines/dspy_engine.py +932 -0
  20. flock/examples.py +131 -0
  21. flock/frontend/README.md +778 -0
  22. flock/frontend/docs/DESIGN_SYSTEM.md +1980 -0
  23. flock/frontend/index.html +12 -0
  24. flock/frontend/package-lock.json +4337 -0
  25. flock/frontend/package.json +48 -0
  26. flock/frontend/src/App.tsx +139 -0
  27. flock/frontend/src/__tests__/integration/graph-snapshot.test.tsx +647 -0
  28. flock/frontend/src/__tests__/integration/indexeddb-persistence.test.tsx +699 -0
  29. flock/frontend/src/components/common/BuildInfo.tsx +39 -0
  30. flock/frontend/src/components/common/EmptyState.module.css +115 -0
  31. flock/frontend/src/components/common/EmptyState.tsx +128 -0
  32. flock/frontend/src/components/common/ErrorBoundary.module.css +169 -0
  33. flock/frontend/src/components/common/ErrorBoundary.tsx +118 -0
  34. flock/frontend/src/components/common/KeyboardShortcutsDialog.css +251 -0
  35. flock/frontend/src/components/common/KeyboardShortcutsDialog.tsx +151 -0
  36. flock/frontend/src/components/common/LoadingSpinner.module.css +97 -0
  37. flock/frontend/src/components/common/LoadingSpinner.tsx +29 -0
  38. flock/frontend/src/components/controls/PublishControl.css +547 -0
  39. flock/frontend/src/components/controls/PublishControl.test.tsx +543 -0
  40. flock/frontend/src/components/controls/PublishControl.tsx +432 -0
  41. flock/frontend/src/components/details/DetailWindowContainer.tsx +58 -0
  42. flock/frontend/src/components/details/LiveOutputTab.test.tsx +792 -0
  43. flock/frontend/src/components/details/LiveOutputTab.tsx +220 -0
  44. flock/frontend/src/components/details/MessageDetailWindow.tsx +439 -0
  45. flock/frontend/src/components/details/MessageHistoryTab.tsx +374 -0
  46. flock/frontend/src/components/details/NodeDetailWindow.test.tsx +501 -0
  47. flock/frontend/src/components/details/NodeDetailWindow.tsx +218 -0
  48. flock/frontend/src/components/details/RunStatusTab.tsx +348 -0
  49. flock/frontend/src/components/details/tabs.test.tsx +1015 -0
  50. flock/frontend/src/components/filters/ArtifactTypeFilter.tsx +21 -0
  51. flock/frontend/src/components/filters/CorrelationIDFilter.module.css +102 -0
  52. flock/frontend/src/components/filters/CorrelationIDFilter.test.tsx +197 -0
  53. flock/frontend/src/components/filters/CorrelationIDFilter.tsx +121 -0
  54. flock/frontend/src/components/filters/FilterFlyout.module.css +104 -0
  55. flock/frontend/src/components/filters/FilterFlyout.tsx +80 -0
  56. flock/frontend/src/components/filters/FilterPills.module.css +220 -0
  57. flock/frontend/src/components/filters/FilterPills.test.tsx +189 -0
  58. flock/frontend/src/components/filters/FilterPills.tsx +143 -0
  59. flock/frontend/src/components/filters/ProducerFilter.tsx +21 -0
  60. flock/frontend/src/components/filters/SavedFiltersControl.module.css +60 -0
  61. flock/frontend/src/components/filters/SavedFiltersControl.test.tsx +158 -0
  62. flock/frontend/src/components/filters/SavedFiltersControl.tsx +159 -0
  63. flock/frontend/src/components/filters/TagFilter.tsx +21 -0
  64. flock/frontend/src/components/filters/TimeRangeFilter.module.css +115 -0
  65. flock/frontend/src/components/filters/TimeRangeFilter.test.tsx +154 -0
  66. flock/frontend/src/components/filters/TimeRangeFilter.tsx +110 -0
  67. flock/frontend/src/components/filters/VisibilityFilter.tsx +21 -0
  68. flock/frontend/src/components/graph/AgentNode.test.tsx +77 -0
  69. flock/frontend/src/components/graph/AgentNode.tsx +324 -0
  70. flock/frontend/src/components/graph/GraphCanvas.tsx +613 -0
  71. flock/frontend/src/components/graph/MessageFlowEdge.tsx +128 -0
  72. flock/frontend/src/components/graph/MessageNode.test.tsx +64 -0
  73. flock/frontend/src/components/graph/MessageNode.tsx +129 -0
  74. flock/frontend/src/components/graph/MiniMap.tsx +47 -0
  75. flock/frontend/src/components/graph/TransformEdge.tsx +123 -0
  76. flock/frontend/src/components/layout/DashboardLayout.css +420 -0
  77. flock/frontend/src/components/layout/DashboardLayout.tsx +287 -0
  78. flock/frontend/src/components/layout/Header.module.css +88 -0
  79. flock/frontend/src/components/layout/Header.tsx +52 -0
  80. flock/frontend/src/components/modules/HistoricalArtifactsModule.module.css +288 -0
  81. flock/frontend/src/components/modules/HistoricalArtifactsModule.tsx +450 -0
  82. flock/frontend/src/components/modules/HistoricalArtifactsModuleWrapper.tsx +13 -0
  83. flock/frontend/src/components/modules/JsonAttributeRenderer.tsx +140 -0
  84. flock/frontend/src/components/modules/ModuleRegistry.test.ts +333 -0
  85. flock/frontend/src/components/modules/ModuleRegistry.ts +93 -0
  86. flock/frontend/src/components/modules/ModuleWindow.tsx +223 -0
  87. flock/frontend/src/components/modules/TraceModuleJaeger.tsx +1971 -0
  88. flock/frontend/src/components/modules/TraceModuleJaegerWrapper.tsx +13 -0
  89. flock/frontend/src/components/modules/registerModules.ts +29 -0
  90. flock/frontend/src/components/settings/AdvancedSettings.tsx +175 -0
  91. flock/frontend/src/components/settings/AppearanceSettings.tsx +185 -0
  92. flock/frontend/src/components/settings/GraphSettings.tsx +110 -0
  93. flock/frontend/src/components/settings/MultiSelect.tsx +235 -0
  94. flock/frontend/src/components/settings/SettingsPanel.css +327 -0
  95. flock/frontend/src/components/settings/SettingsPanel.tsx +131 -0
  96. flock/frontend/src/components/settings/ThemeSelector.tsx +298 -0
  97. flock/frontend/src/components/settings/TracingSettings.tsx +404 -0
  98. flock/frontend/src/hooks/useKeyboardShortcuts.ts +148 -0
  99. flock/frontend/src/hooks/useModulePersistence.test.ts +442 -0
  100. flock/frontend/src/hooks/useModulePersistence.ts +154 -0
  101. flock/frontend/src/hooks/useModules.ts +157 -0
  102. flock/frontend/src/hooks/usePersistence.ts +141 -0
  103. flock/frontend/src/main.tsx +13 -0
  104. flock/frontend/src/services/api.ts +337 -0
  105. flock/frontend/src/services/graphService.test.ts +330 -0
  106. flock/frontend/src/services/graphService.ts +75 -0
  107. flock/frontend/src/services/indexeddb.test.ts +793 -0
  108. flock/frontend/src/services/indexeddb.ts +848 -0
  109. flock/frontend/src/services/layout.test.ts +437 -0
  110. flock/frontend/src/services/layout.ts +357 -0
  111. flock/frontend/src/services/themeApplicator.ts +140 -0
  112. flock/frontend/src/services/themeService.ts +77 -0
  113. flock/frontend/src/services/websocket.ts +650 -0
  114. flock/frontend/src/store/filterStore.test.ts +250 -0
  115. flock/frontend/src/store/filterStore.ts +272 -0
  116. flock/frontend/src/store/graphStore.test.ts +570 -0
  117. flock/frontend/src/store/graphStore.ts +462 -0
  118. flock/frontend/src/store/moduleStore.test.ts +253 -0
  119. flock/frontend/src/store/moduleStore.ts +75 -0
  120. flock/frontend/src/store/settingsStore.ts +188 -0
  121. flock/frontend/src/store/streamStore.ts +68 -0
  122. flock/frontend/src/store/uiStore.test.ts +54 -0
  123. flock/frontend/src/store/uiStore.ts +122 -0
  124. flock/frontend/src/store/wsStore.ts +34 -0
  125. flock/frontend/src/styles/index.css +15 -0
  126. flock/frontend/src/styles/scrollbar.css +47 -0
  127. flock/frontend/src/styles/variables.css +488 -0
  128. flock/frontend/src/test/setup.ts +1 -0
  129. flock/frontend/src/types/filters.ts +47 -0
  130. flock/frontend/src/types/graph.ts +95 -0
  131. flock/frontend/src/types/modules.ts +10 -0
  132. flock/frontend/src/types/theme.ts +55 -0
  133. flock/frontend/src/utils/artifacts.ts +24 -0
  134. flock/frontend/src/utils/mockData.ts +98 -0
  135. flock/frontend/src/utils/performance.ts +16 -0
  136. flock/frontend/src/vite-env.d.ts +17 -0
  137. flock/frontend/tsconfig.json +27 -0
  138. flock/frontend/tsconfig.node.json +11 -0
  139. flock/frontend/vite.config.ts +25 -0
  140. flock/frontend/vitest.config.ts +11 -0
  141. flock/{core/util → helper}/cli_helper.py +9 -5
  142. flock/{core/logging → logging}/__init__.py +2 -3
  143. flock/logging/auto_trace.py +159 -0
  144. flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
  145. flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
  146. flock/{core/logging → logging}/formatters/themed_formatter.py +69 -107
  147. flock/{core/logging → logging}/logging.py +78 -61
  148. flock/{core/logging → logging}/telemetry.py +66 -26
  149. flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
  150. flock/logging/telemetry_exporter/duckdb_exporter.py +216 -0
  151. flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +13 -10
  152. flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
  153. flock/logging/trace_and_logged.py +304 -0
  154. flock/mcp/__init__.py +91 -0
  155. flock/{core/mcp/mcp_client.py → mcp/client.py} +131 -158
  156. flock/{core/mcp/mcp_config.py → mcp/config.py} +86 -132
  157. flock/mcp/manager.py +286 -0
  158. flock/mcp/servers/sse/__init__.py +1 -1
  159. flock/mcp/servers/sse/flock_sse_server.py +16 -58
  160. flock/mcp/servers/stdio/__init__.py +1 -1
  161. flock/mcp/servers/stdio/flock_stdio_server.py +13 -53
  162. flock/mcp/servers/streamable_http/flock_streamable_http_server.py +22 -67
  163. flock/mcp/servers/websockets/flock_websocket_server.py +12 -45
  164. flock/{core/mcp/flock_mcp_tool_base.py → mcp/tool.py} +24 -78
  165. flock/mcp/types/__init__.py +42 -0
  166. flock/{core/mcp → mcp}/types/callbacks.py +12 -15
  167. flock/{core/mcp → mcp}/types/factories.py +7 -6
  168. flock/{core/mcp → mcp}/types/handlers.py +13 -18
  169. flock/{core/mcp → mcp}/types/types.py +70 -74
  170. flock/{core/mcp → mcp}/util/helpers.py +3 -3
  171. flock/orchestrator.py +970 -0
  172. flock/registry.py +148 -0
  173. flock/runtime.py +262 -0
  174. flock/service.py +277 -0
  175. flock/store.py +1214 -0
  176. flock/subscription.py +111 -0
  177. flock/themes/andromeda.toml +1 -1
  178. flock/themes/apple-system-colors.toml +1 -1
  179. flock/themes/arcoiris.toml +1 -1
  180. flock/themes/atomonelight.toml +1 -1
  181. flock/themes/ayu copy.toml +1 -1
  182. flock/themes/ayu-light.toml +1 -1
  183. flock/themes/belafonte-day.toml +1 -1
  184. flock/themes/belafonte-night.toml +1 -1
  185. flock/themes/blulocodark.toml +1 -1
  186. flock/themes/breeze.toml +1 -1
  187. flock/themes/broadcast.toml +1 -1
  188. flock/themes/brogrammer.toml +1 -1
  189. flock/themes/builtin-dark.toml +1 -1
  190. flock/themes/builtin-pastel-dark.toml +1 -1
  191. flock/themes/catppuccin-latte.toml +1 -1
  192. flock/themes/catppuccin-macchiato.toml +1 -1
  193. flock/themes/catppuccin-mocha.toml +1 -1
  194. flock/themes/cga.toml +1 -1
  195. flock/themes/chalk.toml +1 -1
  196. flock/themes/ciapre.toml +1 -1
  197. flock/themes/coffee-theme.toml +1 -1
  198. flock/themes/cyberpunkscarletprotocol.toml +1 -1
  199. flock/themes/dark+.toml +1 -1
  200. flock/themes/darkermatrix.toml +1 -1
  201. flock/themes/darkmatrix.toml +2 -2
  202. flock/themes/darkside.toml +1 -1
  203. flock/themes/deep.toml +2 -2
  204. flock/themes/desert.toml +1 -1
  205. flock/themes/django.toml +1 -1
  206. flock/themes/djangosmooth.toml +1 -1
  207. flock/themes/doomone.toml +1 -1
  208. flock/themes/dotgov.toml +1 -1
  209. flock/themes/dracula+.toml +1 -1
  210. flock/themes/duckbones.toml +1 -1
  211. flock/themes/encom.toml +1 -1
  212. flock/themes/espresso.toml +1 -1
  213. flock/themes/everblush.toml +1 -1
  214. flock/themes/fairyfloss.toml +1 -1
  215. flock/themes/fideloper.toml +1 -1
  216. flock/themes/fishtank.toml +1 -1
  217. flock/themes/flexoki-light.toml +1 -1
  218. flock/themes/floraverse.toml +1 -1
  219. flock/themes/framer.toml +1 -1
  220. flock/themes/galizur.toml +1 -1
  221. flock/themes/github.toml +1 -1
  222. flock/themes/grass.toml +1 -1
  223. flock/themes/grey-green.toml +1 -1
  224. flock/themes/gruvboxlight.toml +1 -1
  225. flock/themes/guezwhoz.toml +1 -1
  226. flock/themes/harper.toml +1 -1
  227. flock/themes/hax0r-blue.toml +1 -1
  228. flock/themes/hopscotch.256.toml +1 -1
  229. flock/themes/ic-green-ppl.toml +1 -1
  230. flock/themes/iceberg-dark.toml +1 -1
  231. flock/themes/japanesque.toml +1 -1
  232. flock/themes/jubi.toml +1 -1
  233. flock/themes/kibble.toml +1 -1
  234. flock/themes/kolorit.toml +1 -1
  235. flock/themes/kurokula.toml +1 -1
  236. flock/themes/materialdesigncolors.toml +1 -1
  237. flock/themes/matrix.toml +1 -1
  238. flock/themes/mellifluous.toml +1 -1
  239. flock/themes/midnight-in-mojave.toml +1 -1
  240. flock/themes/monokai-remastered.toml +1 -1
  241. flock/themes/monokai-soda.toml +1 -1
  242. flock/themes/neon.toml +1 -1
  243. flock/themes/neopolitan.toml +5 -5
  244. flock/themes/nord-light.toml +1 -1
  245. flock/themes/ocean.toml +1 -1
  246. flock/themes/onehalfdark.toml +1 -1
  247. flock/themes/onehalflight.toml +1 -1
  248. flock/themes/palenighthc.toml +1 -1
  249. flock/themes/paulmillr.toml +1 -1
  250. flock/themes/pencildark.toml +1 -1
  251. flock/themes/pnevma.toml +1 -1
  252. flock/themes/purple-rain.toml +1 -1
  253. flock/themes/purplepeter.toml +1 -1
  254. flock/themes/raycast-dark.toml +1 -1
  255. flock/themes/red-sands.toml +1 -1
  256. flock/themes/relaxed.toml +1 -1
  257. flock/themes/retro.toml +1 -1
  258. flock/themes/rose-pine.toml +1 -1
  259. flock/themes/royal.toml +1 -1
  260. flock/themes/ryuuko.toml +1 -1
  261. flock/themes/sakura.toml +1 -1
  262. flock/themes/scarlet-protocol.toml +1 -1
  263. flock/themes/seoulbones-dark.toml +1 -1
  264. flock/themes/shades-of-purple.toml +1 -1
  265. flock/themes/smyck.toml +1 -1
  266. flock/themes/softserver.toml +1 -1
  267. flock/themes/solarized-darcula.toml +1 -1
  268. flock/themes/square.toml +1 -1
  269. flock/themes/sugarplum.toml +1 -1
  270. flock/themes/thayer-bright.toml +1 -1
  271. flock/themes/tokyonight.toml +1 -1
  272. flock/themes/tomorrow.toml +1 -1
  273. flock/themes/ubuntu.toml +1 -1
  274. flock/themes/ultradark.toml +1 -1
  275. flock/themes/ultraviolent.toml +1 -1
  276. flock/themes/unikitty.toml +1 -1
  277. flock/themes/urple.toml +1 -1
  278. flock/themes/vesper.toml +1 -1
  279. flock/themes/vimbones.toml +1 -1
  280. flock/themes/wildcherry.toml +1 -1
  281. flock/themes/wilmersdorf.toml +1 -1
  282. flock/themes/wryan.toml +1 -1
  283. flock/themes/xcodedarkhc.toml +1 -1
  284. flock/themes/xcodelight.toml +1 -1
  285. flock/themes/zenbones-light.toml +1 -1
  286. flock/themes/zenwritten-dark.toml +1 -1
  287. flock/utilities.py +301 -0
  288. flock/utility/output_utility_component.py +226 -0
  289. flock/visibility.py +107 -0
  290. flock_core-0.5.0.dist-info/METADATA +964 -0
  291. flock_core-0.5.0.dist-info/RECORD +525 -0
  292. flock_core-0.5.0.dist-info/entry_points.txt +2 -0
  293. {flock_core-0.4.542.dist-info → flock_core-0.5.0.dist-info}/licenses/LICENSE +1 -1
  294. flock/adapter/__init__.py +0 -14
  295. flock/adapter/azure_adapter.py +0 -68
  296. flock/adapter/chroma_adapter.py +0 -73
  297. flock/adapter/faiss_adapter.py +0 -97
  298. flock/adapter/pinecone_adapter.py +0 -51
  299. flock/adapter/vector_base.py +0 -47
  300. flock/cli/assets/release_notes.md +0 -140
  301. flock/cli/config.py +0 -8
  302. flock/cli/constants.py +0 -36
  303. flock/cli/create_agent.py +0 -1
  304. flock/cli/create_flock.py +0 -280
  305. flock/cli/execute_flock.py +0 -620
  306. flock/cli/load_agent.py +0 -1
  307. flock/cli/load_examples.py +0 -1
  308. flock/cli/load_flock.py +0 -192
  309. flock/cli/load_release_notes.py +0 -20
  310. flock/cli/loaded_flock_cli.py +0 -254
  311. flock/cli/manage_agents.py +0 -459
  312. flock/cli/registry_management.py +0 -889
  313. flock/cli/runner.py +0 -41
  314. flock/cli/settings.py +0 -857
  315. flock/cli/utils.py +0 -135
  316. flock/cli/view_results.py +0 -29
  317. flock/cli/yaml_editor.py +0 -396
  318. flock/config.py +0 -56
  319. flock/core/__init__.py +0 -44
  320. flock/core/api/__init__.py +0 -10
  321. flock/core/api/custom_endpoint.py +0 -45
  322. flock/core/api/endpoints.py +0 -262
  323. flock/core/api/main.py +0 -162
  324. flock/core/api/models.py +0 -101
  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/config/flock_agent_config.py +0 -11
  329. flock/core/config/scheduled_agent_config.py +0 -40
  330. flock/core/context/context.py +0 -214
  331. flock/core/context/context_manager.py +0 -40
  332. flock/core/context/context_vars.py +0 -11
  333. flock/core/evaluation/utils.py +0 -395
  334. flock/core/execution/batch_executor.py +0 -369
  335. flock/core/execution/evaluation_executor.py +0 -438
  336. flock/core/execution/local_executor.py +0 -31
  337. flock/core/execution/opik_executor.py +0 -103
  338. flock/core/execution/temporal_executor.py +0 -166
  339. flock/core/flock.py +0 -1003
  340. flock/core/flock_agent.py +0 -1258
  341. flock/core/flock_evaluator.py +0 -60
  342. flock/core/flock_factory.py +0 -513
  343. flock/core/flock_module.py +0 -207
  344. flock/core/flock_registry.py +0 -702
  345. flock/core/flock_router.py +0 -83
  346. flock/core/flock_scheduler.py +0 -166
  347. flock/core/flock_server_manager.py +0 -136
  348. flock/core/interpreter/python_interpreter.py +0 -689
  349. flock/core/logging/live_capture.py +0 -137
  350. flock/core/logging/trace_and_logged.py +0 -59
  351. flock/core/mcp/__init__.py +0 -1
  352. flock/core/mcp/flock_mcp_server.py +0 -640
  353. flock/core/mcp/mcp_client_manager.py +0 -201
  354. flock/core/mcp/types/__init__.py +0 -1
  355. flock/core/mixin/dspy_integration.py +0 -445
  356. flock/core/mixin/prompt_parser.py +0 -125
  357. flock/core/serialization/__init__.py +0 -13
  358. flock/core/serialization/callable_registry.py +0 -52
  359. flock/core/serialization/flock_serializer.py +0 -854
  360. flock/core/serialization/json_encoder.py +0 -41
  361. flock/core/serialization/secure_serializer.py +0 -175
  362. flock/core/serialization/serializable.py +0 -342
  363. flock/core/serialization/serialization_utils.py +0 -409
  364. flock/core/util/file_path_utils.py +0 -223
  365. flock/core/util/hydrator.py +0 -309
  366. flock/core/util/input_resolver.py +0 -141
  367. flock/core/util/loader.py +0 -59
  368. flock/core/util/splitter.py +0 -219
  369. flock/di.py +0 -41
  370. flock/evaluators/__init__.py +0 -1
  371. flock/evaluators/declarative/__init__.py +0 -1
  372. flock/evaluators/declarative/declarative_evaluator.py +0 -217
  373. flock/evaluators/memory/memory_evaluator.py +0 -90
  374. flock/evaluators/test/test_case_evaluator.py +0 -38
  375. flock/evaluators/zep/zep_evaluator.py +0 -59
  376. flock/modules/__init__.py +0 -1
  377. flock/modules/assertion/__init__.py +0 -1
  378. flock/modules/assertion/assertion_module.py +0 -286
  379. flock/modules/callback/__init__.py +0 -1
  380. flock/modules/callback/callback_module.py +0 -91
  381. flock/modules/enterprise_memory/README.md +0 -99
  382. flock/modules/enterprise_memory/enterprise_memory_module.py +0 -526
  383. flock/modules/mem0/__init__.py +0 -1
  384. flock/modules/mem0/mem0_module.py +0 -126
  385. flock/modules/mem0_async/__init__.py +0 -1
  386. flock/modules/mem0_async/async_mem0_module.py +0 -126
  387. flock/modules/memory/__init__.py +0 -1
  388. flock/modules/memory/memory_module.py +0 -429
  389. flock/modules/memory/memory_parser.py +0 -125
  390. flock/modules/memory/memory_storage.py +0 -736
  391. flock/modules/output/__init__.py +0 -1
  392. flock/modules/output/output_module.py +0 -196
  393. flock/modules/performance/__init__.py +0 -1
  394. flock/modules/performance/metrics_module.py +0 -678
  395. flock/modules/zep/__init__.py +0 -1
  396. flock/modules/zep/zep_module.py +0 -192
  397. flock/platform/docker_tools.py +0 -49
  398. flock/platform/jaeger_install.py +0 -86
  399. flock/routers/__init__.py +0 -1
  400. flock/routers/agent/__init__.py +0 -1
  401. flock/routers/agent/agent_router.py +0 -236
  402. flock/routers/agent/handoff_agent.py +0 -58
  403. flock/routers/conditional/conditional_router.py +0 -486
  404. flock/routers/default/__init__.py +0 -1
  405. flock/routers/default/default_router.py +0 -80
  406. flock/routers/feedback/feedback_router.py +0 -114
  407. flock/routers/list_generator/list_generator_router.py +0 -166
  408. flock/routers/llm/__init__.py +0 -1
  409. flock/routers/llm/llm_router.py +0 -365
  410. flock/tools/__init__.py +0 -0
  411. flock/tools/azure_tools.py +0 -781
  412. flock/tools/code_tools.py +0 -167
  413. flock/tools/file_tools.py +0 -149
  414. flock/tools/github_tools.py +0 -157
  415. flock/tools/markdown_tools.py +0 -205
  416. flock/tools/system_tools.py +0 -9
  417. flock/tools/text_tools.py +0 -810
  418. flock/tools/web_tools.py +0 -92
  419. flock/tools/zendesk_tools.py +0 -501
  420. flock/webapp/__init__.py +0 -1
  421. flock/webapp/app/__init__.py +0 -0
  422. flock/webapp/app/api/__init__.py +0 -0
  423. flock/webapp/app/api/agent_management.py +0 -237
  424. flock/webapp/app/api/execution.py +0 -503
  425. flock/webapp/app/api/flock_management.py +0 -125
  426. flock/webapp/app/api/registry_viewer.py +0 -29
  427. flock/webapp/app/chat.py +0 -662
  428. flock/webapp/app/config.py +0 -104
  429. flock/webapp/app/dependencies.py +0 -117
  430. flock/webapp/app/main.py +0 -1086
  431. flock/webapp/app/middleware.py +0 -113
  432. flock/webapp/app/models_ui.py +0 -7
  433. flock/webapp/app/services/__init__.py +0 -0
  434. flock/webapp/app/services/feedback_file_service.py +0 -363
  435. flock/webapp/app/services/flock_service.py +0 -345
  436. flock/webapp/app/services/sharing_models.py +0 -81
  437. flock/webapp/app/services/sharing_store.py +0 -597
  438. flock/webapp/app/templates/theme_mapper.html +0 -326
  439. flock/webapp/app/theme_mapper.py +0 -811
  440. flock/webapp/app/utils.py +0 -85
  441. flock/webapp/run.py +0 -219
  442. flock/webapp/static/css/chat.css +0 -301
  443. flock/webapp/static/css/components.css +0 -167
  444. flock/webapp/static/css/header.css +0 -39
  445. flock/webapp/static/css/layout.css +0 -281
  446. flock/webapp/static/css/sidebar.css +0 -127
  447. flock/webapp/static/css/two-pane.css +0 -48
  448. flock/webapp/templates/base.html +0 -389
  449. flock/webapp/templates/chat.html +0 -152
  450. flock/webapp/templates/chat_settings.html +0 -19
  451. flock/webapp/templates/flock_editor.html +0 -16
  452. flock/webapp/templates/index.html +0 -12
  453. flock/webapp/templates/partials/_agent_detail_form.html +0 -93
  454. flock/webapp/templates/partials/_agent_list.html +0 -18
  455. flock/webapp/templates/partials/_agent_manager_view.html +0 -51
  456. flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
  457. flock/webapp/templates/partials/_chat_container.html +0 -15
  458. flock/webapp/templates/partials/_chat_messages.html +0 -57
  459. flock/webapp/templates/partials/_chat_settings_form.html +0 -85
  460. flock/webapp/templates/partials/_create_flock_form.html +0 -50
  461. flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
  462. flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
  463. flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
  464. flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
  465. flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
  466. flock/webapp/templates/partials/_env_vars_table.html +0 -23
  467. flock/webapp/templates/partials/_execution_form.html +0 -127
  468. flock/webapp/templates/partials/_execution_view_container.html +0 -28
  469. flock/webapp/templates/partials/_flock_file_list.html +0 -23
  470. flock/webapp/templates/partials/_flock_properties_form.html +0 -52
  471. flock/webapp/templates/partials/_flock_upload_form.html +0 -16
  472. flock/webapp/templates/partials/_header_flock_status.html +0 -5
  473. flock/webapp/templates/partials/_live_logs.html +0 -13
  474. flock/webapp/templates/partials/_load_manager_view.html +0 -49
  475. flock/webapp/templates/partials/_registry_table.html +0 -25
  476. flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
  477. flock/webapp/templates/partials/_results_display.html +0 -78
  478. flock/webapp/templates/partials/_settings_env_content.html +0 -9
  479. flock/webapp/templates/partials/_settings_theme_content.html +0 -14
  480. flock/webapp/templates/partials/_settings_view.html +0 -36
  481. flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
  482. flock/webapp/templates/partials/_share_link_snippet.html +0 -35
  483. flock/webapp/templates/partials/_sidebar.html +0 -74
  484. flock/webapp/templates/partials/_structured_data_view.html +0 -40
  485. flock/webapp/templates/partials/_theme_preview.html +0 -36
  486. flock/webapp/templates/registry_viewer.html +0 -84
  487. flock/webapp/templates/shared_run_page.html +0 -140
  488. flock/workflow/__init__.py +0 -0
  489. flock/workflow/activities.py +0 -237
  490. flock/workflow/agent_activities.py +0 -24
  491. flock/workflow/agent_execution_activity.py +0 -240
  492. flock/workflow/flock_workflow.py +0 -225
  493. flock/workflow/temporal_config.py +0 -96
  494. flock/workflow/temporal_setup.py +0 -60
  495. flock_core-0.4.542.dist-info/METADATA +0 -676
  496. flock_core-0.4.542.dist-info/RECORD +0 -572
  497. flock_core-0.4.542.dist-info/entry_points.txt +0 -2
  498. /flock/{core/logging → logging}/formatters/themes.py +0 -0
  499. /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
  500. /flock/{core/mcp → mcp}/util/__init__.py +0 -0
  501. {flock_core-0.4.542.dist-info → flock_core-0.5.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,216 @@
1
+ """DuckDB exporter for OpenTelemetry spans - optimized for analytical queries."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+ import duckdb
7
+ from opentelemetry.sdk.trace.export import SpanExportResult
8
+ from opentelemetry.trace import Status, StatusCode
9
+
10
+ from flock.logging.telemetry_exporter.base_exporter import TelemetryExporter
11
+
12
+
13
+ class DuckDBSpanExporter(TelemetryExporter):
14
+ """Export spans to DuckDB for fast analytical queries.
15
+
16
+ DuckDB is a columnar analytical database optimized for OLAP workloads,
17
+ making it 10-100x faster than SQLite for trace analytics like:
18
+ - Aggregations (avg/p95/p99 duration)
19
+ - Time-range queries
20
+ - Service/operation filtering
21
+ - Complex analytical queries
22
+
23
+ The database is a single file with zero configuration required.
24
+ """
25
+
26
+ def __init__(self, dir: str, db_name: str = "traces.duckdb", ttl_days: int | None = None):
27
+ """Initialize the DuckDB exporter.
28
+
29
+ Args:
30
+ dir: Directory where the database file will be created
31
+ db_name: Name of the DuckDB file (default: traces.duckdb)
32
+ ttl_days: Delete traces older than this many days (default: None = keep forever)
33
+ """
34
+ super().__init__()
35
+ self.telemetry_path = Path(dir)
36
+ self.telemetry_path.mkdir(parents=True, exist_ok=True)
37
+ self.db_path = self.telemetry_path / db_name
38
+ self.ttl_days = ttl_days
39
+
40
+ # Initialize database and create schema
41
+ self._init_database()
42
+
43
+ def _init_database(self):
44
+ """Create the spans table if it doesn't exist."""
45
+ with duckdb.connect(str(self.db_path)) as conn:
46
+ conn.execute("""
47
+ CREATE TABLE IF NOT EXISTS spans (
48
+ trace_id VARCHAR NOT NULL,
49
+ span_id VARCHAR PRIMARY KEY,
50
+ parent_id VARCHAR,
51
+ name VARCHAR NOT NULL,
52
+ service VARCHAR,
53
+ operation VARCHAR,
54
+ kind VARCHAR,
55
+ start_time BIGINT NOT NULL,
56
+ end_time BIGINT NOT NULL,
57
+ duration_ms DOUBLE NOT NULL,
58
+ status_code VARCHAR NOT NULL,
59
+ status_description VARCHAR,
60
+ attributes JSON,
61
+ events JSON,
62
+ links JSON,
63
+ resource JSON,
64
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
65
+ )
66
+ """)
67
+
68
+ # Create indexes for common query patterns
69
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_trace_id ON spans(trace_id)")
70
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_service ON spans(service)")
71
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_start_time ON spans(start_time)")
72
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_name ON spans(name)")
73
+ conn.execute("CREATE INDEX IF NOT EXISTS idx_created_at ON spans(created_at)")
74
+
75
+ # Cleanup old traces if TTL is configured
76
+ if self.ttl_days is not None:
77
+ self._cleanup_old_traces()
78
+
79
+ def _cleanup_old_traces(self):
80
+ """Delete traces older than TTL_DAYS.
81
+
82
+ This runs on exporter initialization to keep the database size manageable.
83
+ """
84
+ if self.ttl_days is None:
85
+ return
86
+
87
+ try:
88
+ with duckdb.connect(str(self.db_path)) as conn:
89
+ # Delete spans older than TTL
90
+ # Note: DuckDB doesn't support ? placeholders inside INTERVAL expressions
91
+ # Safe: ttl_days is guaranteed to be an int, no injection risk
92
+ query = f"""
93
+ DELETE FROM spans
94
+ WHERE created_at < CURRENT_TIMESTAMP - INTERVAL '{self.ttl_days} DAYS'
95
+ """ # nosec B608
96
+ result = conn.execute(query)
97
+
98
+ deleted_count = result.fetchall()[0][0] if result else 0
99
+
100
+ if deleted_count > 0:
101
+ print(
102
+ f"[DuckDB TTL] Deleted {deleted_count} spans older than {self.ttl_days} days"
103
+ )
104
+
105
+ except Exception as e:
106
+ print(f"[DuckDB TTL] Error cleaning up old traces: {e}")
107
+
108
+ def _span_to_record(self, span):
109
+ """Convert a ReadableSpan to a database record."""
110
+ context = span.get_span_context()
111
+ status = span.status or Status(StatusCode.UNSET)
112
+
113
+ # Extract service and operation from span name
114
+ # Format: "ServiceName.operation_name"
115
+ parts = span.name.split(".", 1)
116
+ service = parts[0] if len(parts) > 0 else "unknown"
117
+ operation = parts[1] if len(parts) > 1 else span.name
118
+
119
+ # Calculate duration in milliseconds
120
+ duration_ms = (span.end_time - span.start_time) / 1_000_000
121
+
122
+ # Serialize complex fields to JSON
123
+ attributes_json = json.dumps(dict(span.attributes or {}))
124
+ events_json = json.dumps(
125
+ [
126
+ {
127
+ "name": event.name,
128
+ "timestamp": event.timestamp,
129
+ "attributes": dict(event.attributes or {}),
130
+ }
131
+ for event in span.events
132
+ ]
133
+ )
134
+ links_json = json.dumps(
135
+ [
136
+ {
137
+ "context": {
138
+ "trace_id": format(link.context.trace_id, "032x"),
139
+ "span_id": format(link.context.span_id, "016x"),
140
+ },
141
+ "attributes": dict(link.attributes or {}),
142
+ }
143
+ for link in span.links
144
+ ]
145
+ )
146
+ resource_json = json.dumps(dict(span.resource.attributes.items()))
147
+
148
+ # Get parent span ID if exists
149
+ parent_id = None
150
+ if span.parent and span.parent.span_id != 0:
151
+ parent_id = format(span.parent.span_id, "016x")
152
+
153
+ return {
154
+ "trace_id": format(context.trace_id, "032x"),
155
+ "span_id": format(context.span_id, "016x"),
156
+ "parent_id": parent_id,
157
+ "name": span.name,
158
+ "service": service,
159
+ "operation": operation,
160
+ "kind": span.kind.name if span.kind else None,
161
+ "start_time": span.start_time,
162
+ "end_time": span.end_time,
163
+ "duration_ms": duration_ms,
164
+ "status_code": status.status_code.name,
165
+ "status_description": status.description,
166
+ "attributes": attributes_json,
167
+ "events": events_json,
168
+ "links": links_json,
169
+ "resource": resource_json,
170
+ }
171
+
172
+ def export(self, spans):
173
+ """Export spans to DuckDB."""
174
+ try:
175
+ with duckdb.connect(str(self.db_path)) as conn:
176
+ for span in spans:
177
+ record = self._span_to_record(span)
178
+
179
+ # Insert span record
180
+ conn.execute(
181
+ """
182
+ INSERT OR REPLACE INTO spans (
183
+ trace_id, span_id, parent_id, name, service, operation,
184
+ kind, start_time, end_time, duration_ms,
185
+ status_code, status_description,
186
+ attributes, events, links, resource
187
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
188
+ """,
189
+ (
190
+ record["trace_id"],
191
+ record["span_id"],
192
+ record["parent_id"],
193
+ record["name"],
194
+ record["service"],
195
+ record["operation"],
196
+ record["kind"],
197
+ record["start_time"],
198
+ record["end_time"],
199
+ record["duration_ms"],
200
+ record["status_code"],
201
+ record["status_description"],
202
+ record["attributes"],
203
+ record["events"],
204
+ record["links"],
205
+ record["resource"],
206
+ ),
207
+ )
208
+
209
+ return SpanExportResult.SUCCESS
210
+ except Exception as e:
211
+ print(f"Error exporting spans to DuckDB: {e}")
212
+ return SpanExportResult.FAILURE
213
+
214
+ def shutdown(self) -> None:
215
+ """Cleanup resources."""
216
+ # DuckDB connections are managed per-transaction, no cleanup needed
@@ -2,17 +2,17 @@
2
2
 
3
3
  import json
4
4
 
5
+ # with workflow.unsafe.imports_passed_through():
6
+ from pathlib import Path
7
+
5
8
  from opentelemetry.sdk.trace.export import SpanExportResult
6
9
  from opentelemetry.trace import Status, StatusCode
7
- from temporalio import workflow
8
10
 
9
- from flock.core.logging.telemetry_exporter.base_exporter import (
11
+ # from temporalio import workflow
12
+ from flock.logging.telemetry_exporter.base_exporter import (
10
13
  TelemetryExporter,
11
14
  )
12
15
 
13
- with workflow.unsafe.imports_passed_through():
14
- from pathlib import Path
15
-
16
16
 
17
17
  class FileSpanExporter(TelemetryExporter):
18
18
  """A simple exporter that writes span data as JSON lines into a file."""
@@ -29,7 +29,7 @@ class FileSpanExporter(TelemetryExporter):
29
29
  context = span.get_span_context()
30
30
  status = span.status or Status(StatusCode.UNSET)
31
31
 
32
- return {
32
+ result = {
33
33
  "name": span.name,
34
34
  "context": {
35
35
  "trace_id": format(context.trace_id, "032x"),
@@ -63,12 +63,15 @@ class FileSpanExporter(TelemetryExporter):
63
63
  }
64
64
  for link in span.links
65
65
  ],
66
- "resource": {
67
- attr_key: attr_value
68
- for attr_key, attr_value in span.resource.attributes.items()
69
- },
66
+ "resource": dict(span.resource.attributes.items()),
70
67
  }
71
68
 
69
+ # Add parent_id if this span has a parent
70
+ if span.parent and span.parent.span_id != 0:
71
+ result["parent_id"] = format(span.parent.span_id, "016x")
72
+
73
+ return result
74
+
72
75
  def export(self, spans):
73
76
  """Write spans to a log file."""
74
77
  try:
@@ -7,7 +7,7 @@ from typing import Any
7
7
 
8
8
  from opentelemetry.sdk.trace.export import SpanExportResult
9
9
 
10
- from flock.core.logging.telemetry_exporter.base_exporter import (
10
+ from flock.logging.telemetry_exporter.base_exporter import (
11
11
  TelemetryExporter,
12
12
  )
13
13
 
@@ -77,7 +77,7 @@ class SqliteTelemetryExporter(TelemetryExporter):
77
77
  trace_id = format(span.context.trace_id, "032x")
78
78
  cursor.execute(
79
79
  """
80
- INSERT OR REPLACE INTO spans
80
+ INSERT OR REPLACE INTO spans
81
81
  (id, name, trace_id, span_id, start_time, end_time, attributes, status)
82
82
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
83
83
  """,
@@ -100,4 +100,3 @@ class SqliteTelemetryExporter(TelemetryExporter):
100
100
 
101
101
  def shutdown(self) -> None:
102
102
  """Cleanup resources."""
103
- pass
@@ -0,0 +1,304 @@
1
+ """A decorator that wraps a function in an OpenTelemetry span and logs its inputs, outputs, and exceptions."""
2
+
3
+ import functools
4
+ import inspect
5
+ import json
6
+
7
+ from opentelemetry import trace
8
+ from opentelemetry.trace import Status, StatusCode
9
+
10
+ from flock.logging.logging import get_logger
11
+
12
+
13
+ logger = get_logger("tools")
14
+ tracer = trace.get_tracer(__name__)
15
+
16
+
17
+ # Global trace filter configuration
18
+ class TraceFilterConfig:
19
+ """Configuration for filtering which operations get traced."""
20
+
21
+ def __init__(self):
22
+ self.services: set[str] | None = None # Whitelist: only trace these services
23
+ self.ignore_operations: set[str] = set() # Blacklist: never trace these operations
24
+
25
+ def should_trace(self, service: str, operation: str) -> bool:
26
+ """Check if an operation should be traced based on filters.
27
+
28
+ Args:
29
+ service: Service name (e.g., "Flock", "Agent")
30
+ operation: Full operation name (e.g., "Flock.publish")
31
+
32
+ Returns:
33
+ True if should trace, False otherwise
34
+ """
35
+ # Check blacklist first (highest priority)
36
+ if operation in self.ignore_operations:
37
+ return False
38
+
39
+ # Check whitelist if configured
40
+ if self.services is not None:
41
+ service_lower = service.lower()
42
+ if service_lower not in self.services:
43
+ return False
44
+
45
+ return True
46
+
47
+
48
+ # Global instance
49
+ _trace_filter_config = TraceFilterConfig()
50
+
51
+
52
+ def _serialize_value(value, max_depth=10, current_depth=0):
53
+ """Serialize a value to JSON-compatible format for span attributes.
54
+
55
+ Args:
56
+ value: The value to serialize
57
+ max_depth: Maximum recursion depth to prevent infinite loops
58
+ current_depth: Current recursion depth
59
+
60
+ Returns:
61
+ A JSON-serializable representation of the value
62
+ """
63
+ if current_depth >= max_depth:
64
+ return f"<max_depth_reached: {type(value).__name__}>"
65
+
66
+ try:
67
+ # Handle None
68
+ if value is None:
69
+ return None
70
+
71
+ # Handle primitives - these are already JSON-serializable
72
+ if isinstance(value, (str, int, float, bool)):
73
+ return value
74
+
75
+ # Handle lists/tuples
76
+ if isinstance(value, (list, tuple)):
77
+ return [_serialize_value(item, max_depth, current_depth + 1) for item in value]
78
+
79
+ # Handle dicts
80
+ if isinstance(value, dict):
81
+ return {
82
+ str(k): _serialize_value(v, max_depth, current_depth + 1) for k, v in value.items()
83
+ }
84
+
85
+ # Handle sets
86
+ if isinstance(value, set):
87
+ return [_serialize_value(item, max_depth, current_depth + 1) for item in value]
88
+
89
+ # For custom objects with __dict__, serialize their attributes
90
+ if hasattr(value, "__dict__"):
91
+ class_name = value.__class__.__name__
92
+ try:
93
+ obj_dict = {}
94
+ for k, v in value.__dict__.items():
95
+ # Skip private attributes and methods
96
+ if k.startswith("_"):
97
+ continue
98
+ # Skip methods and callables
99
+ if callable(v):
100
+ continue
101
+ try:
102
+ obj_dict[k] = _serialize_value(v, max_depth, current_depth + 1)
103
+ except Exception:
104
+ obj_dict[k] = f"<error serializing {k}>"
105
+
106
+ return {
107
+ "__class__": class_name,
108
+ "__module__": value.__class__.__module__,
109
+ **obj_dict,
110
+ }
111
+ except Exception as e:
112
+ return {"__class__": class_name, "__error__": str(e)}
113
+
114
+ # For objects with a useful string representation
115
+ result = str(value)
116
+ # If the string is too long (> 5000 chars), truncate it
117
+ if len(result) > 5000:
118
+ return result[:5000] + "... (string truncated at 5000 chars)"
119
+ return result
120
+
121
+ except Exception as e:
122
+ # If all else fails, return type information with error
123
+ return {"__type__": type(value).__name__, "__error__": str(e)}
124
+
125
+
126
+ def _extract_span_attributes(func, args, kwargs):
127
+ """Extract useful attributes from function arguments for OTEL spans.
128
+
129
+ Returns a dict of attributes and a display name for the span.
130
+ """
131
+ attributes = {}
132
+ span_name = func.__name__
133
+
134
+ # Try to get class name if this is a method
135
+ if args and hasattr(args[0], "__class__"):
136
+ obj = args[0]
137
+ class_name = obj.__class__.__name__
138
+ span_name = f"{class_name}.{func.__name__}"
139
+ attributes["class"] = class_name
140
+
141
+ # Extract agent-specific attributes
142
+ if hasattr(obj, "name"):
143
+ attributes["agent.name"] = str(obj.name)
144
+ if hasattr(obj, "description"):
145
+ attributes["agent.description"] = str(obj.description)[:200] # Truncate
146
+
147
+ # Extract context attributes (correlation_id, task_id)
148
+ for arg_name, arg_value in kwargs.items():
149
+ if arg_name == "ctx" and hasattr(arg_value, "correlation_id"):
150
+ if arg_value.correlation_id:
151
+ attributes["correlation_id"] = str(arg_value.correlation_id)
152
+ if hasattr(arg_value, "task_id"):
153
+ attributes["task_id"] = str(arg_value.task_id)
154
+
155
+ # Check positional args for Context
156
+ for arg in args[1:]: # Skip self
157
+ if hasattr(arg, "correlation_id"):
158
+ if arg.correlation_id:
159
+ attributes["correlation_id"] = str(arg.correlation_id)
160
+ if hasattr(arg, "task_id"):
161
+ attributes["task_id"] = str(arg.task_id)
162
+ break
163
+
164
+ # Add function metadata
165
+ attributes["function"] = func.__name__
166
+ attributes["module"] = func.__module__
167
+
168
+ # Capture input arguments (skip 'self' for methods)
169
+ try:
170
+ sig = inspect.signature(func)
171
+ bound_args = sig.bind(*args, **kwargs)
172
+ bound_args.apply_defaults()
173
+
174
+ # Serialize arguments
175
+ for param_name, param_value in bound_args.arguments.items():
176
+ # Skip 'self' and 'cls'
177
+ if param_name in ("self", "cls"):
178
+ continue
179
+ # Serialize the argument value to JSON-compatible format
180
+ serialized = _serialize_value(param_value)
181
+ # Convert to JSON string for OTEL attribute storage
182
+ try:
183
+ attributes[f"input.{param_name}"] = json.dumps(serialized, default=str)
184
+ except Exception:
185
+ # If JSON serialization fails, use string representation
186
+ attributes[f"input.{param_name}"] = str(serialized)
187
+ except Exception as e:
188
+ # If we can't capture inputs, just note that
189
+ attributes["input.error"] = str(e)
190
+
191
+ return attributes, span_name
192
+
193
+
194
+ def traced_and_logged(func):
195
+ """A decorator that wraps a function in an OpenTelemetry span.
196
+
197
+ Creates proper parent-child span relationships and extracts relevant
198
+ attributes for observability in Grafana/Jaeger.
199
+
200
+ Automatically extracts:
201
+ - Agent name and description
202
+ - Correlation ID and task ID from Context
203
+ - Class and method names
204
+ - Exception information
205
+
206
+ Supports both synchronous and asynchronous functions.
207
+ """
208
+ if inspect.iscoroutinefunction(func):
209
+
210
+ @functools.wraps(func)
211
+ async def async_wrapper(*args, **kwargs):
212
+ attributes, span_name = _extract_span_attributes(func, args, kwargs)
213
+
214
+ # Check if we should trace this operation
215
+ service_name = span_name.split(".")[0] if "." in span_name else span_name
216
+ if not _trace_filter_config.should_trace(service_name, span_name):
217
+ # Skip tracing, just call the function
218
+ return await func(*args, **kwargs)
219
+
220
+ with tracer.start_as_current_span(span_name) as span:
221
+ # Set all extracted attributes
222
+ for key, value in attributes.items():
223
+ span.set_attribute(key, value)
224
+
225
+ try:
226
+ result = await func(*args, **kwargs)
227
+
228
+ # Capture output value as JSON
229
+ try:
230
+ serialized_result = _serialize_value(result)
231
+ span.set_attribute(
232
+ "output.value", json.dumps(serialized_result, default=str)
233
+ )
234
+ except Exception as e:
235
+ span.set_attribute("output.value", str(result))
236
+ span.set_attribute("output.serialization_error", str(e))
237
+
238
+ # Set result type and metadata
239
+ if result is not None:
240
+ span.set_attribute("output.type", type(result).__name__)
241
+ if hasattr(result, "__len__"):
242
+ try:
243
+ span.set_attribute("output.length", len(result))
244
+ except TypeError:
245
+ pass
246
+
247
+ span.set_status(Status(StatusCode.OK))
248
+ logger.debug(f"{span_name} executed successfully")
249
+ return result
250
+
251
+ except Exception as e:
252
+ span.set_status(Status(StatusCode.ERROR, str(e)))
253
+ span.record_exception(e)
254
+ logger.exception(f"Error in {span_name}", error=str(e))
255
+ raise
256
+
257
+ return async_wrapper
258
+
259
+ @functools.wraps(func)
260
+ def wrapper(*args, **kwargs):
261
+ attributes, span_name = _extract_span_attributes(func, args, kwargs)
262
+
263
+ # Check if we should trace this operation
264
+ service_name = span_name.split(".")[0] if "." in span_name else span_name
265
+ if not _trace_filter_config.should_trace(service_name, span_name):
266
+ # Skip tracing, just call the function
267
+ return func(*args, **kwargs)
268
+
269
+ with tracer.start_as_current_span(span_name) as span:
270
+ # Set all extracted attributes
271
+ for key, value in attributes.items():
272
+ span.set_attribute(key, value)
273
+
274
+ try:
275
+ result = func(*args, **kwargs)
276
+
277
+ # Capture output value as JSON
278
+ try:
279
+ serialized_result = _serialize_value(result)
280
+ span.set_attribute("output.value", json.dumps(serialized_result, default=str))
281
+ except Exception as e:
282
+ span.set_attribute("output.value", str(result))
283
+ span.set_attribute("output.serialization_error", str(e))
284
+
285
+ # Set result type and metadata
286
+ if result is not None:
287
+ span.set_attribute("output.type", type(result).__name__)
288
+ if hasattr(result, "__len__"):
289
+ try:
290
+ span.set_attribute("output.length", len(result))
291
+ except TypeError:
292
+ pass
293
+
294
+ span.set_status(Status(StatusCode.OK))
295
+ logger.debug(f"{span_name} executed successfully")
296
+ return result
297
+
298
+ except Exception as e:
299
+ span.set_status(Status(StatusCode.ERROR, str(e)))
300
+ span.record_exception(e)
301
+ logger.exception(f"Error in {span_name}", error=str(e))
302
+ raise
303
+
304
+ return wrapper
flock/mcp/__init__.py ADDED
@@ -0,0 +1,91 @@
1
+ """MCP (Model Context Protocol) Integration for Flock-Flow.
2
+
3
+ This package provides integration with MCP servers, enabling agents to
4
+ dynamically discover and use external tools following the Model Context Protocol.
5
+
6
+ Architecture Decisions:
7
+ - AD001: Two-Level Architecture (orchestrator + agent)
8
+ - AD003: Tool Namespacing ({server}__{tool})
9
+ - AD004: Per-(agent_id, run_id) Connection Isolation
10
+ - AD005: Lazy Connection Establishment
11
+ - AD007: Graceful Degradation on MCP Failures
12
+
13
+ Key Components:
14
+ - FlockMCPConfiguration: Server configuration
15
+ - FlockMCPClient: Individual server connection
16
+ - FlockMCPClientManager: Connection pooling and lifecycle
17
+ - FlockMCPTool: MCP tool wrapper compatible with DSPy
18
+
19
+ Example Usage:
20
+ ```python
21
+ from flock import Flock
22
+ from flock.mcp import StdioServerParameters
23
+
24
+ # Create orchestrator
25
+ orchestrator = Flock()
26
+
27
+ # Register MCP server
28
+ orchestrator.add_mcp(
29
+ name="filesystem",
30
+ connection_params=StdioServerParameters(
31
+ command="uvx",
32
+ args=["mcp-server-filesystem", "/tmp"]
33
+ )
34
+ )
35
+
36
+ # Build agent with MCP access
37
+ agent = (
38
+ orchestrator.agent("file_agent")
39
+ .with_mcps(["filesystem"])
40
+ .build()
41
+ )
42
+ ```
43
+ """
44
+
45
+ from flock.mcp.client import FlockMCPClient
46
+ from flock.mcp.config import (
47
+ FlockMCPCachingConfiguration,
48
+ FlockMCPCallbackConfiguration,
49
+ FlockMCPConfiguration,
50
+ FlockMCPConnectionConfiguration,
51
+ FlockMCPFeatureConfiguration,
52
+ )
53
+ from flock.mcp.manager import FlockMCPClientManager
54
+ from flock.mcp.tool import FlockMCPTool
55
+ from flock.mcp.types import (
56
+ FlockListRootsMCPCallback,
57
+ FlockLoggingMCPCallback,
58
+ FlockMessageHandlerMCPCallback,
59
+ FlockSamplingMCPCallback,
60
+ MCPRoot,
61
+ ServerParameters,
62
+ SseServerParameters,
63
+ StdioServerParameters,
64
+ StreamableHttpServerParameters,
65
+ WebsocketServerParameters,
66
+ )
67
+
68
+
69
+ __all__ = [
70
+ "FlockListRootsMCPCallback",
71
+ "FlockLoggingMCPCallback",
72
+ "FlockMCPCachingConfiguration",
73
+ "FlockMCPCallbackConfiguration",
74
+ # Client and Manager
75
+ "FlockMCPClient",
76
+ "FlockMCPClientManager",
77
+ # Configuration
78
+ "FlockMCPConfiguration",
79
+ "FlockMCPConnectionConfiguration",
80
+ "FlockMCPFeatureConfiguration",
81
+ "FlockMCPTool",
82
+ "FlockMessageHandlerMCPCallback",
83
+ "FlockSamplingMCPCallback",
84
+ "MCPRoot",
85
+ # Types
86
+ "ServerParameters",
87
+ "SseServerParameters",
88
+ "StdioServerParameters",
89
+ "StreamableHttpServerParameters",
90
+ "WebsocketServerParameters",
91
+ ]