flock-core 0.1.2__py3-none-any.whl → 0.2.2__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 (407) hide show
  1. flock/__init__.py +1 -4
  2. flock/core/__init__.py +1 -7
  3. flock/core/context/context.py +182 -0
  4. flock/core/context/context_manager.py +34 -0
  5. flock/core/{context_vars.py → context/context_vars.py} +8 -6
  6. flock/core/execution/local_executor.py +27 -0
  7. flock/core/execution/temporal_executor.py +56 -0
  8. flock/core/flock.py +232 -208
  9. flock/core/flock_agent.py +574 -0
  10. flock/core/logging/__init__.py +2 -18
  11. flock/core/logging/formatters/base_formatter.py +36 -0
  12. flock/core/logging/formatters/formatter_factory.py +38 -0
  13. flock/core/logging/formatters/pprint_formatter.py +18 -0
  14. flock/core/logging/formatters/rich_formatters.py +132 -0
  15. flock/core/logging/formatters/theme_builder.py +480 -0
  16. flock/core/logging/formatters/themed_formatter.py +442 -0
  17. flock/core/logging/logging.py +141 -0
  18. flock/core/logging/telemetry.py +21 -0
  19. flock/core/logging/trace_and_logged.py +55 -0
  20. flock/core/mixin/dspy_integration.py +197 -0
  21. flock/core/mixin/prompt_parser.py +125 -0
  22. flock/core/registry/agent_registry.py +118 -0
  23. flock/core/tools/basic_tools.py +296 -98
  24. flock/core/tools/dev_tools/github.py +190 -0
  25. flock/core/util/cli_helper.py +25 -0
  26. flock/core/util/input_resolver.py +156 -0
  27. flock/core/util/serializable.py +93 -0
  28. flock/themes/3024-day.toml +39 -0
  29. flock/themes/3024-night.toml +77 -0
  30. flock/themes/aardvark-blue.toml +77 -0
  31. flock/themes/abernathy.toml +77 -0
  32. flock/themes/adventure.toml +77 -0
  33. flock/themes/adventuretime.toml +77 -0
  34. flock/themes/afterglow.toml +77 -0
  35. flock/themes/alabaster.toml +77 -0
  36. flock/themes/alienblood.toml +77 -0
  37. flock/themes/andromeda.toml +77 -0
  38. flock/themes/apple-classic.toml +77 -0
  39. flock/themes/apple-system-colors.toml +77 -0
  40. flock/themes/arcoiris.toml +77 -0
  41. flock/themes/argonaut copy.toml +77 -0
  42. flock/themes/argonaut.toml +39 -0
  43. flock/themes/arthur.toml +77 -0
  44. flock/themes/ateliersulphurpool.toml +77 -0
  45. flock/themes/atom.toml +38 -0
  46. flock/themes/atom_test.toml +65 -0
  47. flock/themes/atomonelight.toml +77 -0
  48. flock/themes/aurora.toml +77 -0
  49. flock/themes/ayu copy.toml +77 -0
  50. flock/themes/ayu-light.toml +77 -0
  51. flock/themes/ayu-mirage.toml +77 -0
  52. flock/themes/ayu.toml +39 -0
  53. flock/themes/banana-blueberry.toml +77 -0
  54. flock/themes/batman.toml +77 -0
  55. flock/themes/belafonte-day.toml +77 -0
  56. flock/themes/belafonte-night.toml +77 -0
  57. flock/themes/birdsofparadise.toml +77 -0
  58. flock/themes/blazer.toml +77 -0
  59. flock/themes/blue-matrix.toml +77 -0
  60. flock/themes/blueberrypie.toml +77 -0
  61. flock/themes/bluedolphin.toml +77 -0
  62. flock/themes/blulocodark.toml +77 -0
  63. flock/themes/blulocolight.toml +77 -0
  64. flock/themes/borland.toml +77 -0
  65. flock/themes/breeze.toml +77 -0
  66. flock/themes/bright-lights.toml +77 -0
  67. flock/themes/broadcast.toml +77 -0
  68. flock/themes/brogrammer.toml +77 -0
  69. flock/themes/builtin-dark.toml +77 -0
  70. flock/themes/builtin-light.toml +77 -0
  71. flock/themes/builtin-pastel-dark.toml +77 -0
  72. flock/themes/builtin-solarized-dark.toml +77 -0
  73. flock/themes/builtin-solarized-light.toml +77 -0
  74. flock/themes/builtin-tango-dark.toml +77 -0
  75. flock/themes/builtin-tango-light.toml +77 -0
  76. flock/themes/c64.toml +77 -0
  77. flock/themes/calamity.toml +77 -0
  78. flock/themes/catppuccin-frappe.toml +77 -0
  79. flock/themes/catppuccin-latte.toml +77 -0
  80. flock/themes/catppuccin-macchiato.toml +77 -0
  81. flock/themes/catppuccin-mocha.toml +77 -0
  82. flock/themes/cga.toml +77 -0
  83. flock/themes/chalk.toml +77 -0
  84. flock/themes/chalkboard.toml +77 -0
  85. flock/themes/challengerdeep.toml +77 -0
  86. flock/themes/chester.toml +77 -0
  87. flock/themes/ciapre.toml +77 -0
  88. flock/themes/clrs.toml +77 -0
  89. flock/themes/cobalt-neon.toml +77 -0
  90. flock/themes/cobalt2.toml +77 -0
  91. flock/themes/coffee-theme.toml +77 -0
  92. flock/themes/crayonponyfish.toml +77 -0
  93. flock/themes/cutiepro.toml +77 -0
  94. flock/themes/cyberdyne.toml +77 -0
  95. flock/themes/cyberpunk.toml +77 -0
  96. flock/themes/cyberpunkscarletprotocol.toml +77 -0
  97. flock/themes/dark+.toml +77 -0
  98. flock/themes/dark-pastel.toml +77 -0
  99. flock/themes/darkermatrix.toml +77 -0
  100. flock/themes/darkmatrix.toml +77 -0
  101. flock/themes/darkside.toml +77 -0
  102. flock/themes/dayfox.toml +77 -0
  103. flock/themes/deep.toml +77 -0
  104. flock/themes/desert.toml +77 -0
  105. flock/themes/dimidium.toml +77 -0
  106. flock/themes/dimmedmonokai.toml +77 -0
  107. flock/themes/django.toml +77 -0
  108. flock/themes/djangorebornagain.toml +77 -0
  109. flock/themes/djangosmooth.toml +77 -0
  110. flock/themes/doom-peacock.toml +77 -0
  111. flock/themes/doomone.toml +77 -0
  112. flock/themes/dotgov.toml +77 -0
  113. flock/themes/dracula+.toml +77 -0
  114. flock/themes/dracula.toml +77 -0
  115. flock/themes/duckbones.toml +77 -0
  116. flock/themes/duotone-dark.toml +77 -0
  117. flock/themes/earthsong.toml +77 -0
  118. flock/themes/elemental.toml +77 -0
  119. flock/themes/elementary.toml +77 -0
  120. flock/themes/encom.toml +77 -0
  121. flock/themes/espresso-libre.toml +77 -0
  122. flock/themes/espresso.toml +77 -0
  123. flock/themes/everblush.toml +77 -0
  124. flock/themes/fahrenheit.toml +77 -0
  125. flock/themes/fairyfloss.toml +77 -0
  126. flock/themes/farmhouse-dark.toml +77 -0
  127. flock/themes/farmhouse-light.toml +77 -0
  128. flock/themes/fideloper.toml +77 -0
  129. flock/themes/firefly-traditional.toml +77 -0
  130. flock/themes/firefoxdev.toml +77 -0
  131. flock/themes/firewatch.toml +77 -0
  132. flock/themes/fishtank.toml +77 -0
  133. flock/themes/flat.toml +77 -0
  134. flock/themes/flatland.toml +77 -0
  135. flock/themes/flexoki-dark.toml +77 -0
  136. flock/themes/flexoki-light.toml +77 -0
  137. flock/themes/floraverse.toml +77 -0
  138. flock/themes/forestblue.toml +77 -0
  139. flock/themes/framer.toml +77 -0
  140. flock/themes/frontenddelight.toml +77 -0
  141. flock/themes/funforrest.toml +77 -0
  142. flock/themes/galaxy.toml +77 -0
  143. flock/themes/galizur.toml +77 -0
  144. flock/themes/github-dark.toml +77 -0
  145. flock/themes/github.toml +77 -0
  146. flock/themes/glacier.toml +77 -0
  147. flock/themes/grape.toml +77 -0
  148. flock/themes/grass.toml +77 -0
  149. flock/themes/grey-green.toml +77 -0
  150. flock/themes/gruber-darker.toml +77 -0
  151. flock/themes/gruvboxdark.toml +77 -0
  152. flock/themes/gruvboxdarkhard.toml +77 -0
  153. flock/themes/gruvboxlight.toml +77 -0
  154. flock/themes/guezwhoz.toml +77 -0
  155. flock/themes/hacktober.toml +77 -0
  156. flock/themes/hardcore.toml +77 -0
  157. flock/themes/harper.toml +77 -0
  158. flock/themes/hax0r-blue.toml +77 -0
  159. flock/themes/hax0r-gr33n.toml +77 -0
  160. flock/themes/hax0r-r3d.toml +77 -0
  161. flock/themes/highway.toml +77 -0
  162. flock/themes/hipster-green.toml +77 -0
  163. flock/themes/hivacruz.toml +77 -0
  164. flock/themes/homebrew.toml +77 -0
  165. flock/themes/hopscotch.256.toml +77 -0
  166. flock/themes/hopscotch.toml +77 -0
  167. flock/themes/hurtado.toml +77 -0
  168. flock/themes/hybrid.toml +77 -0
  169. flock/themes/ic-green-ppl.toml +77 -0
  170. flock/themes/ic-orange-ppl.toml +77 -0
  171. flock/themes/iceberg-dark.toml +77 -0
  172. flock/themes/iceberg-light.toml +77 -0
  173. flock/themes/idea.toml +77 -0
  174. flock/themes/idletoes.toml +77 -0
  175. flock/themes/ir-black.toml +77 -0
  176. flock/themes/iterm2-dark-background.toml +77 -0
  177. flock/themes/iterm2-default.toml +77 -0
  178. flock/themes/iterm2-light-background.toml +77 -0
  179. flock/themes/iterm2-pastel-dark-background.toml +77 -0
  180. flock/themes/iterm2-smoooooth.toml +77 -0
  181. flock/themes/iterm2-solarized-dark.toml +77 -0
  182. flock/themes/iterm2-solarized-light.toml +77 -0
  183. flock/themes/iterm2-tango-dark.toml +77 -0
  184. flock/themes/iterm2-tango-light.toml +77 -0
  185. flock/themes/jackie-brown.toml +77 -0
  186. flock/themes/japanesque.toml +77 -0
  187. flock/themes/jellybeans.toml +77 -0
  188. flock/themes/jetbrains-darcula.toml +77 -0
  189. flock/themes/jubi.toml +77 -0
  190. flock/themes/kanagawabones.toml +77 -0
  191. flock/themes/kibble.toml +77 -0
  192. flock/themes/kolorit.toml +77 -0
  193. flock/themes/konsolas.toml +77 -0
  194. flock/themes/kurokula.toml +77 -0
  195. flock/themes/lab-fox.toml +77 -0
  196. flock/themes/laser.toml +77 -0
  197. flock/themes/later-this-evening.toml +77 -0
  198. flock/themes/lavandula.toml +77 -0
  199. flock/themes/liquidcarbon.toml +77 -0
  200. flock/themes/liquidcarbontransparent.toml +77 -0
  201. flock/themes/liquidcarbontransparentinverse.toml +77 -0
  202. flock/themes/lovelace.toml +77 -0
  203. flock/themes/man-page.toml +77 -0
  204. flock/themes/mariana.toml +77 -0
  205. flock/themes/material.toml +77 -0
  206. flock/themes/materialdark.toml +77 -0
  207. flock/themes/materialdarker.toml +77 -0
  208. flock/themes/materialdesigncolors.toml +77 -0
  209. flock/themes/materialocean.toml +77 -0
  210. flock/themes/mathias.toml +77 -0
  211. flock/themes/matrix.toml +77 -0
  212. flock/themes/medallion.toml +77 -0
  213. flock/themes/mellifluous.toml +77 -0
  214. flock/themes/midnight-in-mojave.toml +77 -0
  215. flock/themes/mirage.toml +77 -0
  216. flock/themes/misterioso.toml +77 -0
  217. flock/themes/molokai.toml +77 -0
  218. flock/themes/monalisa.toml +77 -0
  219. flock/themes/monokai-remastered.toml +77 -0
  220. flock/themes/monokai-soda.toml +77 -0
  221. flock/themes/monokai-vivid.toml +77 -0
  222. flock/themes/n0tch2k.toml +77 -0
  223. flock/themes/neobones-dark.toml +77 -0
  224. flock/themes/neobones-light.toml +77 -0
  225. flock/themes/neon.toml +77 -0
  226. flock/themes/neopolitan.toml +77 -0
  227. flock/themes/neutron.toml +77 -0
  228. flock/themes/night-owlish-light.toml +77 -0
  229. flock/themes/nightfox.toml +77 -0
  230. flock/themes/nightlion-v1.toml +77 -0
  231. flock/themes/nightlion-v2.toml +77 -0
  232. flock/themes/niji.toml +77 -0
  233. flock/themes/nocturnal-winter.toml +77 -0
  234. flock/themes/nord-light.toml +77 -0
  235. flock/themes/nord.toml +77 -0
  236. flock/themes/novel.toml +77 -0
  237. flock/themes/nvimdark.toml +77 -0
  238. flock/themes/nvimlight.toml +77 -0
  239. flock/themes/obsidian.toml +77 -0
  240. flock/themes/ocean.toml +77 -0
  241. flock/themes/oceanic-next.toml +77 -0
  242. flock/themes/oceanicmaterial.toml +77 -0
  243. flock/themes/ollie.toml +77 -0
  244. flock/themes/onehalfdark.toml +77 -0
  245. flock/themes/onehalflight.toml +77 -0
  246. flock/themes/operator-mono-dark.toml +77 -0
  247. flock/themes/overnight-slumber.toml +77 -0
  248. flock/themes/oxocarbon.toml +77 -0
  249. flock/themes/palenighthc.toml +77 -0
  250. flock/themes/pandora.toml +77 -0
  251. flock/themes/paraiso-dark.toml +77 -0
  252. flock/themes/paulmillr.toml +77 -0
  253. flock/themes/pencildark.toml +77 -0
  254. flock/themes/pencillight.toml +77 -0
  255. flock/themes/peppermint.toml +77 -0
  256. flock/themes/piatto-light.toml +77 -0
  257. flock/themes/pnevma.toml +77 -0
  258. flock/themes/popping-and-locking.toml +77 -0
  259. flock/themes/primary.toml +77 -0
  260. flock/themes/pro-light.toml +77 -0
  261. flock/themes/pro.toml +77 -0
  262. flock/themes/purple-rain.toml +77 -0
  263. flock/themes/purplepeter.toml +77 -0
  264. flock/themes/rapture.toml +77 -0
  265. flock/themes/raycast-dark.toml +77 -0
  266. flock/themes/raycast-light.toml +77 -0
  267. flock/themes/rebecca.toml +77 -0
  268. flock/themes/red-alert.toml +77 -0
  269. flock/themes/red-planet.toml +77 -0
  270. flock/themes/red-sands.toml +77 -0
  271. flock/themes/relaxed.toml +77 -0
  272. flock/themes/retro.toml +77 -0
  273. flock/themes/rippedcasts.toml +77 -0
  274. flock/themes/rose-pine-dawn.toml +77 -0
  275. flock/themes/rose-pine-moon.toml +77 -0
  276. flock/themes/rose-pine.toml +77 -0
  277. flock/themes/rouge-2.toml +77 -0
  278. flock/themes/royal.toml +77 -0
  279. flock/themes/ryuuko.toml +77 -0
  280. flock/themes/sakura.toml +77 -0
  281. flock/themes/scarlet-protocol.toml +77 -0
  282. flock/themes/seafoam-pastel.toml +77 -0
  283. flock/themes/seashells.toml +77 -0
  284. flock/themes/seoulbones-dark.toml +77 -0
  285. flock/themes/seoulbones-light.toml +77 -0
  286. flock/themes/seti.toml +77 -0
  287. flock/themes/shades-of-purple.toml +77 -0
  288. flock/themes/shaman.toml +77 -0
  289. flock/themes/slate.toml +77 -0
  290. flock/themes/sleepyhollow.toml +77 -0
  291. flock/themes/smyck.toml +77 -0
  292. flock/themes/snazzy.toml +77 -0
  293. flock/themes/softserver.toml +77 -0
  294. flock/themes/solarized-darcula.toml +77 -0
  295. flock/themes/solarized-dark---patched.toml +77 -0
  296. flock/themes/solarized-dark-higher-contrast.toml +77 -0
  297. flock/themes/spacedust.toml +77 -0
  298. flock/themes/spacegray-eighties-dull.toml +77 -0
  299. flock/themes/spacegray-eighties.toml +77 -0
  300. flock/themes/spacegray.toml +77 -0
  301. flock/themes/spiderman.toml +77 -0
  302. flock/themes/spring.toml +77 -0
  303. flock/themes/square.toml +77 -0
  304. flock/themes/sublette.toml +77 -0
  305. flock/themes/subliminal.toml +77 -0
  306. flock/themes/sugarplum.toml +77 -0
  307. flock/themes/sundried.toml +77 -0
  308. flock/themes/symfonic.toml +77 -0
  309. flock/themes/synthwave-everything.toml +77 -0
  310. flock/themes/synthwave.toml +77 -0
  311. flock/themes/synthwavealpha.toml +77 -0
  312. flock/themes/tango-adapted.toml +77 -0
  313. flock/themes/tango-half-adapted.toml +77 -0
  314. flock/themes/teerb.toml +77 -0
  315. flock/themes/terafox.toml +77 -0
  316. flock/themes/terminal-basic.toml +77 -0
  317. flock/themes/thayer-bright.toml +77 -0
  318. flock/themes/the-hulk.toml +77 -0
  319. flock/themes/tinacious-design-(dark).toml +77 -0
  320. flock/themes/tinacious-design-(light).toml +77 -0
  321. flock/themes/tokyonight-day.toml +77 -0
  322. flock/themes/tokyonight-storm.toml +77 -0
  323. flock/themes/tokyonight.toml +77 -0
  324. flock/themes/tomorrow-night-blue.toml +77 -0
  325. flock/themes/tomorrow-night-bright.toml +77 -0
  326. flock/themes/tomorrow-night-burns.toml +77 -0
  327. flock/themes/tomorrow-night-eighties.toml +77 -0
  328. flock/themes/tomorrow-night.toml +77 -0
  329. flock/themes/tomorrow.toml +77 -0
  330. flock/themes/toychest.toml +77 -0
  331. flock/themes/treehouse.toml +77 -0
  332. flock/themes/twilight.toml +77 -0
  333. flock/themes/ubuntu.toml +77 -0
  334. flock/themes/ultradark.toml +77 -0
  335. flock/themes/ultraviolent.toml +77 -0
  336. flock/themes/underthesea.toml +77 -0
  337. flock/themes/unikitty.toml +77 -0
  338. flock/themes/urple.toml +77 -0
  339. flock/themes/vaughn.toml +77 -0
  340. flock/themes/vesper.toml +77 -0
  341. flock/themes/vibrantink.toml +77 -0
  342. flock/themes/vimbones.toml +77 -0
  343. flock/themes/violet-dark.toml +77 -0
  344. flock/themes/violet-light.toml +77 -0
  345. flock/themes/warmneon.toml +77 -0
  346. flock/themes/wez.toml +77 -0
  347. flock/themes/whimsy.toml +77 -0
  348. flock/themes/wildcherry.toml +77 -0
  349. flock/themes/wilmersdorf.toml +77 -0
  350. flock/themes/wombat.toml +77 -0
  351. flock/themes/wryan.toml +77 -0
  352. flock/themes/xcodedark.toml +77 -0
  353. flock/themes/xcodedarkhc.toml +77 -0
  354. flock/themes/xcodelight.toml +77 -0
  355. flock/themes/xcodelighthc.toml +77 -0
  356. flock/themes/xcodewwdc.toml +77 -0
  357. flock/themes/zenbones-dark.toml +77 -0
  358. flock/themes/zenbones-light.toml +77 -0
  359. flock/themes/zenbones.toml +77 -0
  360. flock/themes/zenburn.toml +77 -0
  361. flock/themes/zenburned.toml +77 -0
  362. flock/themes/zenwritten-dark.toml +77 -0
  363. flock/themes/zenwritten-light.toml +77 -0
  364. flock/workflow/activities.py +175 -115
  365. flock/workflow/agent_activities.py +24 -26
  366. flock/workflow/temporal_setup.py +38 -37
  367. flock/workflow/workflow.py +58 -53
  368. flock_core-0.2.2.dist-info/METADATA +320 -0
  369. flock_core-0.2.2.dist-info/RECORD +372 -0
  370. {flock_core-0.1.2.dist-info → flock_core-0.2.2.dist-info}/licenses/LICENSE +21 -21
  371. flock/agents/__init__.py +0 -3
  372. flock/agents/batch_agent.py +0 -175
  373. flock/agents/declarative_agent.py +0 -166
  374. flock/agents/loop_agent.py +0 -178
  375. flock/agents/trigger_agent.py +0 -191
  376. flock/agents/user_agent.py +0 -230
  377. flock/app/components/__init__.py +0 -14
  378. flock/app/components/charts/agent_workflow.py +0 -14
  379. flock/app/components/charts/core_architecture.py +0 -14
  380. flock/app/components/charts/tool_system.py +0 -14
  381. flock/app/components/history_grid.py +0 -168
  382. flock/app/components/history_grid_alt.py +0 -189
  383. flock/app/components/sidebar.py +0 -19
  384. flock/app/components/theme.py +0 -9
  385. flock/app/components/util.py +0 -18
  386. flock/app/hive_app.py +0 -118
  387. flock/app/html/d3.html +0 -179
  388. flock/app/modules/__init__.py +0 -12
  389. flock/app/modules/about.py +0 -17
  390. flock/app/modules/agent_detail.py +0 -70
  391. flock/app/modules/agent_list.py +0 -59
  392. flock/app/modules/playground.py +0 -322
  393. flock/app/modules/settings.py +0 -96
  394. flock/core/agent.py +0 -150
  395. flock/core/agent_registry.py +0 -162
  396. flock/core/context.py +0 -279
  397. flock/core/handoff/handoff_base.py +0 -12
  398. flock/core/logging/error_handler.py +0 -84
  399. flock/core/logging/formatters.py +0 -122
  400. flock/core/logging/handlers.py +0 -117
  401. flock/core/logging/logger.py +0 -107
  402. flock/core/serializable.py +0 -206
  403. flock_core-0.1.2.dist-info/METADATA +0 -476
  404. flock_core-0.1.2.dist-info/RECORD +0 -48
  405. flock_core-0.1.2.dist-info/entry_points.txt +0 -2
  406. /flock/{core/config/declarative_agent_config.py → workflow/__init__.py} +0 -0
  407. {flock_core-0.1.2.dist-info → flock_core-0.2.2.dist-info}/WHEEL +0 -0
@@ -0,0 +1,574 @@
1
+ """FlockAgent is the core, declarative base class for all agents in the Flock framework."""
2
+
3
+ from abc import ABC
4
+ from collections.abc import Awaitable, Callable
5
+ from dataclasses import dataclass, field
6
+ from typing import Any, Literal, Union
7
+
8
+ import cloudpickle
9
+ from pydantic import BaseModel, Field
10
+
11
+ from flock.core.context.context import FlockContext
12
+ from flock.core.logging.logging import get_logger
13
+ from flock.core.mixin.dspy_integration import AgentType, DSPyIntegrationMixin
14
+ from flock.core.mixin.prompt_parser import PromptParserMixin
15
+
16
+ logger = get_logger("flock")
17
+ from opentelemetry import trace
18
+
19
+ tracer = trace.get_tracer(__name__)
20
+
21
+
22
+ @dataclass
23
+ class FlockAgentConfig:
24
+ """Configuration options for a FlockAgent."""
25
+
26
+ agent_type_override: AgentType = field(
27
+ default=None,
28
+ metadata={
29
+ "description": "Overrides the agent type. TOOL USE ONLY WORKS WITH REACT"
30
+ },
31
+ )
32
+ disable_output: bool = field(
33
+ default=False, metadata={"description": "Disables the agent's output."}
34
+ )
35
+ save_to_file: bool = field(
36
+ default=False,
37
+ metadata={
38
+ "description": "Saves the serialized agent to a file every time it gets serialized."
39
+ },
40
+ )
41
+ data_type: Literal["json", "cloudpickle", "msgpack"] = "cloudpickle"
42
+
43
+
44
+ @dataclass
45
+ class HandOff:
46
+ """Base class for handoff returns."""
47
+
48
+ next_agent: Union[str, "FlockAgent"] = field(
49
+ default="", metadata={"description": "Next agent to invoke"}
50
+ )
51
+ input: dict[str, Any] = field(
52
+ default_factory=dict,
53
+ metadata={"description": "Input data for the next agent"},
54
+ )
55
+ context: FlockContext = field(
56
+ default=None, metadata={"description": "Override context parameters"}
57
+ )
58
+
59
+
60
+ class FlockAgent(BaseModel, ABC, PromptParserMixin, DSPyIntegrationMixin):
61
+ """FlockAgent is the core, declarative base class for all agents in the Flock framework.
62
+
63
+ Due to its declarative nature, FlockAgent does not rely on constructing classical prompts manually.
64
+ Instead, each agent is defined by simply declaring:
65
+ - Its expected inputs (what data it needs),
66
+ - Its expected outputs (what data it produces), and
67
+ - Any optional tools it can use during execution.
68
+
69
+ In a declarative model, you describe *what* you expect rather than *how* to compute it. This means that
70
+ instead of embedding prompt engineering logic directly in your code, you specify a concise signature.
71
+ At runtime, the Flock framework automatically:
72
+ - Resolves the inputs from a pre-computed context,
73
+ - Constructs a precise prompt for the underlying language model (using metadata such as type hints
74
+ and human-readable descriptions), and
75
+ - Invokes the appropriate tools if needed.
76
+
77
+ This approach minimizes hidden dependencies and boilerplate code. It allows developers to focus solely on
78
+ what data the agent should work with and what result it should produce, without worrying about the intricacies
79
+ of prompt formatting or context management.
80
+
81
+ For details on how Flock resolves inputs, please refer to the documentation.
82
+
83
+ Key benefits of the declarative approach include:
84
+ - **Clarity:** The agent's interface (inputs and outputs) is explicitly defined.
85
+ - **Reusability:** Agents can be easily serialized, shared, and reused since they are built as Pydantic models.
86
+ - **Modularity:** By receiving a dictionary of pre-resolved inputs, agents operate independently of the global context,
87
+ making them easier to test and debug.
88
+ - **Extensibility:** Additional metadata (like detailed descriptions for each key) can be embedded and later used to
89
+ refine the prompt for the LLM.
90
+
91
+ Since FlockAgent is a Pydantic BaseModel, it can be serialized to and from JSON. This ensures that the agent's
92
+ configuration and state are easily stored, transmitted, and reproduced.
93
+
94
+ **Implementation Example:**
95
+
96
+ Below is an example of how to define and instantiate a FlockAgent:
97
+
98
+ from flock_agent import FlockAgent
99
+ import basic_tools
100
+
101
+ # Define an agent by declaring its inputs, outputs, and optional tools.
102
+ idea_agent = FlockAgent(
103
+ name="idea_agent",
104
+ input="query: str | The search query, context: dict | The full conversation context",
105
+ output="a_fun_software_project_idea: str | The generated software project idea",
106
+ tools=[basic_tools.web_search_tavily],
107
+ )
108
+
109
+ # At runtime, Flock automatically resolves inputs and calls the agent:
110
+ resolved_inputs = {
111
+ "query": "A new social media app",
112
+ "context": {"previous_idea": "a messaging platform"}
113
+ }
114
+ result = await idea_agent.run(resolved_inputs)
115
+
116
+ In this example:
117
+ - The agent declares that it needs a `query` (a string describing what to search for) and a `context` (a dictionary
118
+ containing additional information).
119
+ - It produces a `a_fun_software_project_idea` (a string with the generated idea).
120
+ - The tool `basic_tools.web_search_tavily` is available for the agent to use if needed.
121
+ - When the agent is run, the Flock framework resolves the inputs, constructs the appropriate prompt using the
122
+ declared metadata, and returns the result.
123
+
124
+ This declarative style streamlines agent creation and execution, making the framework highly modular, testable,
125
+ and production-ready.
126
+
127
+ In the future options will be provided to optimize the "hidden" prompt generation and execution so the agent will
128
+ perform close to its theoretical maximum.
129
+ """
130
+
131
+ name: str = Field(..., description="Unique identifier for the agent.")
132
+ model: str = Field(
133
+ "openai/gpt-4o", description="The model to use (e.g., 'openai/gpt-4o')."
134
+ )
135
+ description: str | Callable[..., str] = Field(
136
+ "", description="A human-readable description of the agent."
137
+ )
138
+
139
+ input: str | Callable[..., str] | None = Field(
140
+ None,
141
+ description=(
142
+ "A comma-separated list of input keys. Optionally supports type hints (:) and descriptions (|). "
143
+ "For example: 'query: str | The search query, chapter_list: list[str] | The chapter list of the document'."
144
+ ),
145
+ )
146
+ output: str | Callable[..., str] | None = Field(
147
+ None,
148
+ description=(
149
+ "A comma-separated list of output keys. Optionally supports type hints (:) and descriptions (|). "
150
+ "For example: 'result|The generated result, summary|A brief summary'."
151
+ ),
152
+ )
153
+
154
+ tools: list[Callable[..., Any]] | None = Field(
155
+ default=None,
156
+ description="An optional list of callable tools that the agent can leverage during execution.",
157
+ )
158
+
159
+ use_cache: bool = Field(
160
+ default=False,
161
+ description="Set to True to enable caching of the agent's results.",
162
+ )
163
+
164
+ hand_off: str | Callable[..., Any] | None = Field(
165
+ None,
166
+ description=(
167
+ "Specifies the next agent in the workflow or a callable that determines the handoff. "
168
+ "This allows chaining of agents."
169
+ ),
170
+ )
171
+
172
+ termination: str | Callable[..., str] | None = Field(
173
+ None,
174
+ description="An optional termination condition or phrase used to indicate when the agent should stop processing.",
175
+ )
176
+
177
+ config: FlockAgentConfig = Field(
178
+ default_factory=FlockAgentConfig,
179
+ description="Configuration options for the agent, such as serialization settings.",
180
+ )
181
+
182
+ # Lifecycle callback fields: if provided, these callbacks are used instead of overriding the methods.
183
+ initialize_callback: Callable[[dict[str, Any]], Awaitable[None]] | None = (
184
+ Field(
185
+ default=None,
186
+ description="Optional callback function for initialization. If provided, this async function is called with the inputs.",
187
+ )
188
+ )
189
+ terminate_callback: (
190
+ Callable[[dict[str, Any], dict[str, Any]], Awaitable[None]] | None
191
+ ) = Field(
192
+ default=None,
193
+ description="Optional callback function for termination. If provided, this async function is called with the inputs and result.",
194
+ )
195
+ on_error_callback: (
196
+ Callable[[Exception, dict[str, Any]], Awaitable[None]] | None
197
+ ) = Field(
198
+ default=None,
199
+ description="Optional callback function for error handling. If provided, this async function is called with the error and inputs.",
200
+ )
201
+
202
+ # Lifecycle hooks
203
+ async def initialize(self, inputs: dict[str, Any]) -> None:
204
+ """Called at the very start of the agent's execution.
205
+
206
+ Override this method or provide an `initialize_callback` to perform setup tasks such as input validation or resource loading.
207
+ """
208
+ if self.initialize_callback is not None:
209
+ await self.initialize_callback(self, inputs)
210
+ else:
211
+ pass
212
+
213
+ async def terminate(
214
+ self, inputs: dict[str, Any], result: dict[str, Any]
215
+ ) -> None:
216
+ """Called at the very end of the agent's execution.
217
+
218
+ Override this method or provide a `terminate_callback` to perform cleanup tasks such as releasing resources or logging results.
219
+ """
220
+ if self.terminate_callback is not None:
221
+ await self.terminate_callback(self, inputs, result)
222
+ else:
223
+ pass
224
+
225
+ async def on_error(self, error: Exception, inputs: dict[str, Any]) -> None:
226
+ """Called if the agent encounters an error during execution.
227
+
228
+ Override this method or provide an `on_error_callback` to implement custom error handling or recovery strategies.
229
+ """
230
+ if self.on_error_callback is not None:
231
+ await self.on_error_callback(self, error, inputs)
232
+ else:
233
+ pass
234
+
235
+ async def evaluate(self, inputs: dict[str, Any]) -> dict[str, Any]:
236
+ """Process the agent's task using the provided inputs and return the result.
237
+
238
+ This asynchronous method is the core execution engine for a FlockAgent. It performs the following steps:
239
+
240
+ 1. **Extract Descriptions:**
241
+ Parses the agent's configured input and output strings to extract human-readable descriptions.
242
+ These strings are expected to use the format "key: type_hint | description". The method removes the
243
+ type hints and builds dictionaries that map each key to its corresponding description.
244
+
245
+ 2. **Construct the Prompt:**
246
+ Based on the extracted descriptions, the method builds a detailed prompt that clearly lists all input
247
+ fields (with their descriptions) and output fields. This prompt is designed to guide the language model,
248
+ ensuring that it understands what inputs are provided and what outputs are expected.
249
+
250
+ 3. **Configure the Language Model:**
251
+ The method initializes and configures a language model using the dspy library. The agent's model
252
+ (e.g., "openai/gpt-4o") is used to set up the language model, ensuring that it is ready to process the prompt.
253
+
254
+ 4. **Execute the Task:**
255
+ Depending on whether the agent has been configured with additional tools:
256
+ - **With Tools:** A ReAct task is instantiated. This task interleaves reasoning and tool usage,
257
+ allowing the agent to leverage external functionalities during execution.
258
+ - **Without Tools:** A Predict task is used for a straightforward generation based on the prompt.
259
+
260
+ 5. **Process the Result:**
261
+ After execution, the method attempts to convert the result to a dictionary. It also ensures that each
262
+ expected input key is present in the output (by setting a default value from the inputs if necessary).
263
+
264
+ 6. **Error Handling:**
265
+ Any exceptions raised during the process are caught, logged (or printed), and then re-raised to allow
266
+ higher-level error handling. This ensures that errors are not silently ignored and can be properly diagnosed.
267
+
268
+ **Arguments:**
269
+ inputs (dict[str, Any]): A dictionary containing all the resolved input values required by the agent.
270
+ These inputs are typically obtained from the global context or from the output of a previous agent.
271
+
272
+ **Returns:**
273
+ dict[str, Any]: A dictionary containing the output generated by the agent. This output adheres to the
274
+ agent's declared output fields and includes any fallback values for missing inputs.
275
+
276
+ **Usage Example:**
277
+
278
+ Suppose an agent is declared with the following configuration:
279
+ input = "query: str | The search query, context: dict | Additional context"
280
+ output = "idea: str | The generated software project idea"
281
+
282
+ When invoked with:
283
+ inputs = {"query": "build an app", "context": {"previous_idea": "messaging app"}}
284
+
285
+ The method will:
286
+ - Parse the descriptions to create:
287
+ input_descriptions = {"query": "The search query", "context": "Additional context"}
288
+ output_descriptions = {"idea": "The generated software project idea"}
289
+ - Construct a prompt that lists these inputs and outputs clearly.
290
+ - Configure the language model and execute the appropriate task (ReAct if tools are provided, otherwise Predict).
291
+ - Return a dictionary similar to:
292
+ {"idea": "A fun app idea based on ...", "query": "build an app", "context": {"previous_idea": "messaging app"}}
293
+ """
294
+ with tracer.start_as_current_span("agent.evaluate") as span:
295
+ span.set_attribute("agent.name", self.name)
296
+ span.set_attribute("inputs", str(inputs))
297
+ try:
298
+ # Create and configure the signature and language model.
299
+ self.__dspy_signature = self.create_dspy_signature_class(
300
+ self.name,
301
+ self.description,
302
+ f"{self.input} -> {self.output}",
303
+ )
304
+ self._configure_language_model()
305
+ agent_task = self._select_task(
306
+ self.__dspy_signature,
307
+ agent_type_override=self.config.agent_type_override,
308
+ )
309
+ # Execute the task.
310
+ result = agent_task(**inputs)
311
+ result = self._process_result(result, inputs)
312
+ span.set_attribute("result", str(result))
313
+ logger.info("Evaluation successful", agent=self.name)
314
+ return result
315
+ except Exception as eval_error:
316
+ logger.error(
317
+ "Error during evaluation",
318
+ agent=self.name,
319
+ error=str(eval_error),
320
+ )
321
+ span.record_exception(eval_error)
322
+ raise
323
+
324
+ async def run(self, inputs: dict[str, Any]) -> dict[str, Any]:
325
+ """Run the agent with the given inputs and return its generated output.
326
+
327
+ This method represents the primary execution flow for a FlockAgent and performs the following
328
+ lifecycle steps in sequence:
329
+
330
+ 1. **Initialization:**
331
+ Calls the `initialize(inputs)` hook to perform any necessary pre-run setup, such as input
332
+ validation, resource allocation, or logging. This ensures that the agent is properly configured
333
+ before processing begins.
334
+
335
+ 2. **Evaluation:**
336
+ Invokes the internal `_evaluate(inputs)` method, which constructs a detailed prompt (incorporating
337
+ input and output descriptions), configures the underlying language model via dspy, and executes the
338
+ main task (using a ReAct task if tools are provided, or a Predict task otherwise).
339
+
340
+ 3. **Termination:**
341
+ Calls the `terminate(inputs, result)` hook after evaluation, allowing the agent to clean up any
342
+ resources or perform post-run actions (such as logging the output).
343
+
344
+ 4. **Output Return:**
345
+ Returns a dictionary containing the agent's output. This output conforms to the agent's declared
346
+ output fields and may include any default or fallback values for missing inputs.
347
+
348
+ If an error occurs during any of these steps, the `on_error(error, inputs)` hook is invoked to handle
349
+ the exception (for instance, by logging detailed error information). The error is then re-raised, ensuring
350
+ that higher-level error management can address the failure.
351
+
352
+ **Arguments:**
353
+ inputs (dict[str, Any]): A dictionary containing the resolved input values required by the agent.
354
+ These inputs are typically derived from the agent's declared input signature and may include data
355
+ provided by previous agents or from a global context.
356
+
357
+ **Returns:**
358
+ dict[str, Any]: A dictionary containing the output generated by the agent. The output structure
359
+ adheres to the agent's declared output fields.
360
+
361
+ **Example:**
362
+ Suppose an agent is defined with:
363
+ input = "query: str | The search query, context: dict | Additional context"
364
+ output = "result: str | The generated idea"
365
+ When executed with:
366
+ inputs = {"query": "build a chatbot", "context": {"user": "Alice"}}
367
+ The method might return:
368
+ {"result": "A conversational chatbot that uses AI to...", "query": "build a chatbot", "context": {"user": "Alice"}}
369
+ """
370
+ with tracer.start_as_current_span("agent.run") as span:
371
+ span.set_attribute("agent.name", self.name)
372
+ span.set_attribute("inputs", str(inputs))
373
+ try:
374
+ await self.initialize(inputs)
375
+ result = await self.evaluate(inputs)
376
+ await self.terminate(inputs, result)
377
+ span.set_attribute("result", str(result))
378
+ logger.info("Agent run completed", agent=self.name)
379
+ return result
380
+ except Exception as run_error:
381
+ logger.error(
382
+ "Error running agent", agent=self.name, error=str(run_error)
383
+ )
384
+ await self.on_error(run_error, inputs)
385
+ span.record_exception(run_error)
386
+ raise
387
+
388
+ async def run_temporal(self, inputs: dict[str, Any]) -> dict[str, Any]:
389
+ """Execute this agent via a Temporal workflow for enhanced fault tolerance and asynchronous processing.
390
+
391
+ This method enables remote execution of the agent within a Temporal environment, leveraging Temporal's
392
+ capabilities for persistence, retries, and distributed error handling. The workflow encapsulates the agent's
393
+ logic so that it can run on Temporal workers, providing robustness and scalability in production systems.
394
+
395
+ The method performs these steps:
396
+ 1. **Connect to Temporal:**
397
+ Establishes a connection to the Temporal server using a Temporal client configured with the appropriate
398
+ namespace (default is "default").
399
+ 2. **Serialization:**
400
+ Serializes the agent instance (via `to_dict()`) along with the provided inputs. This step converts any
401
+ callable objects (e.g., lifecycle hooks or tools) into a storable format using cloudpickle.
402
+ 3. **Activity Invocation:**
403
+ Triggers a designated Temporal activity (e.g., `run_flock_agent_activity`) by passing the serialized agent
404
+ data and inputs. The Temporal activity is responsible for executing the agent's logic in a fault-tolerant
405
+ manner.
406
+ 4. **Return Output:**
407
+ Awaits and returns the resulting output from the Temporal workflow as a dictionary, consistent with the
408
+ output structure of the local `run()` method.
409
+
410
+ If any error occurs during these steps, the error is logged and re-raised to ensure that failure is properly
411
+ handled by higher-level error management systems.
412
+
413
+ **Arguments:**
414
+ inputs (dict[str, Any]): A dictionary containing the resolved inputs required by the agent, similar to those
415
+ provided to the local `run()` method.
416
+
417
+ **Returns:**
418
+ dict[str, Any]: A dictionary containing the output produced by the agent after remote execution via Temporal.
419
+ The output format is consistent with that of the local `run()` method.
420
+
421
+ **Example:**
422
+ Given an agent defined with:
423
+ input = "query: str | The search query, context: dict | Additional context"
424
+ output = "result: str | The generated idea"
425
+ Calling:
426
+ result = await agent.run_temporal({"query": "analyze data", "context": {"source": "sales"}})
427
+ will execute the agent on a Temporal worker and return the output in a structured dictionary format.
428
+ """
429
+ with tracer.start_as_current_span("agent.run_temporal") as span:
430
+ span.set_attribute("agent.name", self.name)
431
+ span.set_attribute("inputs", str(inputs))
432
+ try:
433
+ from temporalio.client import Client
434
+
435
+ from flock.workflow.agent_activities import (
436
+ run_flock_agent_activity,
437
+ )
438
+ from flock.workflow.temporal_setup import run_activity
439
+
440
+ client = await Client.connect(
441
+ "localhost:7233", namespace="default"
442
+ )
443
+ agent_data = self.to_dict()
444
+ inputs_data = inputs
445
+
446
+ result = await run_activity(
447
+ client,
448
+ self.name,
449
+ run_flock_agent_activity,
450
+ {"agent_data": agent_data, "inputs": inputs_data},
451
+ )
452
+ span.set_attribute("result", str(result))
453
+ logger.info("Temporal run successful", agent=self.name)
454
+ return result
455
+ except Exception as temporal_error:
456
+ logger.error(
457
+ "Error in Temporal workflow",
458
+ agent=self.name,
459
+ error=str(temporal_error),
460
+ )
461
+ span.record_exception(temporal_error)
462
+ raise
463
+
464
+ def resolve_callables(self, context) -> None:
465
+ """Resolve any callable fields in the agent instance using the provided context.
466
+
467
+ This method resolves any callable fields in the agent instance using the provided context. It iterates over
468
+ the agent's fields and replaces any callable objects (such as lifecycle hooks or tools) with their corresponding
469
+ resolved values from the context. This ensures that the agent is fully configured and ready
470
+ """
471
+ if isinstance(self.input, Callable):
472
+ self.input = self.input(context)
473
+ if isinstance(self.output, Callable):
474
+ self.output = self.output(context)
475
+ if isinstance(self.description, Callable):
476
+ self.description = self.description(context)
477
+
478
+ def to_dict(self) -> dict[str, Any]:
479
+ """Serialize the FlockAgent instance to a dictionary.
480
+
481
+ This method converts the entire agent instance—including its configuration, state, and lifecycle hooks—
482
+ into a dictionary format. It uses cloudpickle to serialize any callable objects (such as functions or
483
+ methods), converting them into hexadecimal string representations. This ensures that the agent can be
484
+ easily persisted, transmitted, or logged as JSON.
485
+
486
+ The serialization process is recursive:
487
+ - If a field is a callable (and not a class), it is serialized using cloudpickle.
488
+ - Lists and dictionaries are processed recursively to ensure that all nested callables are properly handled.
489
+
490
+ **Returns:**
491
+ dict[str, Any]: A dictionary representing the FlockAgent, which includes all of its configuration data.
492
+ This dictionary is suitable for storage, debugging, or transmission over the network.
493
+
494
+ **Example:**
495
+ For an agent defined as:
496
+ name = "idea_agent",
497
+ model = "openai/gpt-4o",
498
+ input = "query: str | The search query, context: dict | The full conversation context",
499
+ output = "idea: str | The generated idea"
500
+ Calling `agent.to_dict()` might produce:
501
+ {
502
+ "name": "idea_agent",
503
+ "model": "openai/gpt-4o",
504
+ "input": "query: str | The search query, context: dict | The full conversation context",
505
+ "output": "idea: str | The generated idea",
506
+ "tools": ["<serialized tool representation>"],
507
+ "use_cache": False,
508
+ "hand_off": None,
509
+ "termination": None,
510
+ ...
511
+ }
512
+ """
513
+
514
+ def convert_callable(obj: Any) -> Any:
515
+ if callable(obj) and not isinstance(obj, type):
516
+ return cloudpickle.dumps(obj).hex()
517
+ if isinstance(obj, list):
518
+ return [convert_callable(item) for item in obj]
519
+ if isinstance(obj, dict):
520
+ return {k: convert_callable(v) for k, v in obj.items()}
521
+ return obj
522
+
523
+ data = self.model_dump()
524
+ return convert_callable(data)
525
+
526
+ @classmethod
527
+ def from_dict(cls, data: dict[str, Any]) -> "FlockAgent":
528
+ """Deserialize a FlockAgent instance from a dictionary.
529
+
530
+ This class method reconstructs a FlockAgent from its serialized dictionary representation, as produced
531
+ by the `to_dict()` method. It recursively processes the dictionary to convert any serialized callables
532
+ (stored as hexadecimal strings via cloudpickle) back into executable callable objects.
533
+
534
+ **Arguments:**
535
+ data (dict[str, Any]): A dictionary representation of a FlockAgent, typically produced by `to_dict()`.
536
+ The dictionary should contain all configuration fields and state information necessary to fully
537
+ reconstruct the agent.
538
+
539
+ **Returns:**
540
+ FlockAgent: An instance of FlockAgent reconstructed from the provided dictionary. The deserialized agent
541
+ will have the same configuration, state, and behavior as the original instance.
542
+
543
+ **Example:**
544
+ Suppose you have the following dictionary:
545
+ {
546
+ "name": "idea_agent",
547
+ "model": "openai/gpt-4o",
548
+ "input": "query: str | The search query, context: dict | The full conversation context",
549
+ "output": "idea: str | The generated idea",
550
+ "tools": ["<serialized tool representation>"],
551
+ "use_cache": False,
552
+ "hand_off": None,
553
+ "termination": None,
554
+ ...
555
+ }
556
+ Then, calling:
557
+ agent = FlockAgent.from_dict(data)
558
+ will return a FlockAgent instance with the same properties and behavior as when it was originally serialized.
559
+ """
560
+
561
+ def convert_callable(obj: Any) -> Any:
562
+ if isinstance(obj, str) and len(obj) > 2:
563
+ try:
564
+ return cloudpickle.loads(bytes.fromhex(obj))
565
+ except Exception:
566
+ return obj
567
+ if isinstance(obj, list):
568
+ return [convert_callable(item) for item in obj]
569
+ if isinstance(obj, dict):
570
+ return {k: convert_callable(v) for k, v in obj.items()}
571
+ return obj
572
+
573
+ converted = convert_callable(data)
574
+ return cls(**converted)
@@ -1,18 +1,2 @@
1
- """Flock logging system with Rich integration and Temporal compatibility."""
2
-
3
- from flock.core.logging.error_handler import error_handler
4
- from flock.core.logging.formatters import PerformanceFormatter, StructuredFormatter
5
- from flock.core.logging.handlers import live_update_handler, performance_handler
6
- from flock.core.logging.logger import flock_logger
7
-
8
- # Install the Rich error handler by default
9
- error_handler.install()
10
-
11
- __all__ = [
12
- "PerformanceFormatter",
13
- "StructuredFormatter",
14
- "error_handler",
15
- "flock_logger",
16
- "live_update_handler",
17
- "performance_handler",
18
- ]
1
+ """Flock logging system with Rich integration and structured logging support."""
2
+
@@ -0,0 +1,36 @@
1
+ from abc import ABC, abstractmethod
2
+ from dataclasses import dataclass, field
3
+ from typing import Any
4
+
5
+
6
+ class BaseFormatter(ABC):
7
+ def __init__(self, max_length: int = 1000) -> None:
8
+ self.max_length = max_length
9
+
10
+ def display(
11
+ self,
12
+ result: dict[str, Any],
13
+ agent_name: str,
14
+ wait: bool = False,
15
+ ) -> None:
16
+ self.display_result(result, agent_name)
17
+ if wait:
18
+ input("Press Enter to continue...")
19
+
20
+ @abstractmethod
21
+ def display_result(self, result: dict[str, Any], agent_name: str) -> None:
22
+ """Display an agent's result."""
23
+ raise NotImplementedError
24
+
25
+ @abstractmethod
26
+ def display_data(self, data: dict[str, Any]) -> None:
27
+ """Display arbitrary data."""
28
+ raise NotImplementedError
29
+
30
+
31
+ @dataclass
32
+ class FormatterOptions:
33
+ formatter: type[BaseFormatter] = field(default=None)
34
+ wait_for_input: bool = field(default=False)
35
+ max_length: int = field(default=1000)
36
+ settings: Any | None = field(default=None)
@@ -0,0 +1,38 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any
3
+
4
+ from flock.core.logging.formatters.base_formatter import (
5
+ BaseFormatter,
6
+ FormatterOptions,
7
+ )
8
+ from flock.core.logging.formatters.pprint_formatter import PrettyPrintFormatter
9
+ from flock.core.logging.formatters.rich_formatters import RichTables
10
+ from flock.core.logging.formatters.themed_formatter import (
11
+ ThemedAgentResultFormatter,
12
+ )
13
+
14
+
15
+ @dataclass
16
+ class FormatterOptions:
17
+ formatter: type[BaseFormatter]
18
+ wait_for_input: bool = False
19
+ settings: dict[str, Any] | None = None
20
+
21
+
22
+ class FormatterFactory:
23
+ _formatter_map = {
24
+ PrettyPrintFormatter: PrettyPrintFormatter,
25
+ RichTables: RichTables,
26
+ ThemedAgentResultFormatter: ThemedAgentResultFormatter,
27
+ }
28
+
29
+ @staticmethod
30
+ def create_formatter(options: FormatterOptions) -> BaseFormatter:
31
+ formatter_cls = options.formatter
32
+ max_length = options.max_length
33
+ if formatter_cls in FormatterFactory._formatter_map:
34
+ formatter = FormatterFactory._formatter_map[formatter_cls]
35
+ if options.settings:
36
+ return formatter(max_length=max_length, **options.settings)
37
+ return formatter(max_length=max_length)
38
+ raise ValueError(f"Unknown formatter: {formatter_cls}")