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