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,442 @@
1
+ """A Rich-based formatter for agent results with theme support."""
2
+
3
+ import pathlib
4
+ import random
5
+ import re
6
+ from typing import Any
7
+
8
+ from devtools import pprint
9
+ from temporalio import workflow
10
+
11
+ from flock.core.logging.formatters.base_formatter import BaseFormatter
12
+
13
+ with workflow.unsafe.imports_passed_through():
14
+ from rich import box
15
+ from rich.console import Console, Group
16
+ from rich.panel import Panel
17
+ from rich.table import Table
18
+
19
+ import toml # install with: pip install toml
20
+
21
+
22
+ def resolve_style_string(style_str: str, theme: dict) -> str:
23
+ """Replace tokens in a style string of the form.
24
+
25
+ color.<section>.<key>
26
+
27
+ with the corresponding value from theme["colors"][<section>][<key>].
28
+ If the token cannot be resolved, it is left unchanged.
29
+ """
30
+ pattern = r"color\.(\w+)\.(\w+)"
31
+
32
+ def repl(match):
33
+ section = match.group(1)
34
+ key = match.group(2)
35
+ try:
36
+ return theme["colors"][section][key]
37
+ except KeyError:
38
+ return match.group(0) # leave token unchanged if not found
39
+
40
+ return re.sub(pattern, repl, style_str)
41
+
42
+
43
+ def generate_default_rich_block(theme: dict | None = None) -> dict[str, Any]:
44
+ """Generate a default [rich] block with *all* styling properties.
45
+
46
+ For the color mapping properties the defaults are computed from the
47
+ theme's [colors] blocks (if available). This includes colors from the
48
+ "bright", "normal", and "cursor" sections.
49
+
50
+ Non color properties (layout and table specific properties) are randomly
51
+ chosen from a set of sensible alternatives.
52
+ """
53
+ if theme is not None:
54
+ # Retrieve colors from the theme.
55
+ bright_black = theme["colors"]["bright"].get("black", "#000000")
56
+ bright_blue = theme["colors"]["bright"].get("blue", "#96cbfe")
57
+ bright_cyan = theme["colors"]["bright"].get("cyan", "#85befd")
58
+ bright_green = theme["colors"]["bright"].get("green", "#94fa36")
59
+ bright_magenta = theme["colors"]["bright"].get("magenta", "#b9b6fc")
60
+ bright_red = theme["colors"]["bright"].get("red", "#fd5ff1")
61
+ bright_white = theme["colors"]["bright"].get("white", "#e0e0e0")
62
+ bright_yellow = theme["colors"]["bright"].get("yellow", "#f5ffa8")
63
+
64
+ normal_black = theme["colors"]["normal"].get("black", "#000000")
65
+ normal_blue = theme["colors"]["normal"].get("blue", "#85befd")
66
+ normal_cyan = theme["colors"]["normal"].get("cyan", "#85befd")
67
+ normal_green = theme["colors"]["normal"].get("green", "#87c38a")
68
+ normal_magenta = theme["colors"]["normal"].get("magenta", "#b9b6fc")
69
+ normal_red = theme["colors"]["normal"].get("red", "#fd5ff1")
70
+ normal_white = theme["colors"]["normal"].get("white", "#e0e0e0")
71
+ normal_yellow = theme["colors"]["normal"].get("yellow", "#ffd7b1")
72
+
73
+ cursor_cursor = theme["colors"]["cursor"].get("cursor", "#d0d0d0")
74
+ cursor_text = theme["colors"]["cursor"].get("text", "#151515")
75
+
76
+ primary_background = theme["colors"]["primary"].get(
77
+ "background", "#161719"
78
+ )
79
+ primary_foreground = theme["colors"]["primary"].get(
80
+ "foreground", "#c5c8c6"
81
+ )
82
+ selection_background = theme["colors"]["selection"].get(
83
+ "background", "#444444"
84
+ )
85
+ selection_text = theme["colors"]["selection"].get(
86
+ "text", primary_foreground
87
+ )
88
+ else:
89
+ bright_black = "black"
90
+ bright_blue = "blue"
91
+ bright_cyan = "cyan"
92
+ bright_green = "green"
93
+ bright_magenta = "magenta"
94
+ bright_red = "red"
95
+ bright_white = "white"
96
+ bright_yellow = "yellow"
97
+
98
+ normal_black = "black"
99
+ normal_blue = "blue"
100
+ normal_cyan = "cyan"
101
+ normal_green = "green"
102
+ normal_magenta = "magenta"
103
+ normal_red = "red"
104
+ normal_white = "white"
105
+ normal_yellow = "yellow"
106
+
107
+ cursor_cursor = "gray"
108
+ cursor_text = "white"
109
+
110
+ primary_background = "black"
111
+ primary_foreground = "white"
112
+ selection_background = "gray"
113
+ selection_text = "white"
114
+
115
+ # Color properties computed from the theme.
116
+ default_color_props = {
117
+ "panel_style": f"on {primary_background}",
118
+ "table_header_style": f"bold {selection_text} on {selection_background}",
119
+ "table_title_style": f"bold {primary_foreground}",
120
+ "table_border_style": bright_blue,
121
+ "panel_border_style": bright_blue,
122
+ "column_output": f"bold {primary_foreground}",
123
+ "column_value": primary_foreground,
124
+ }
125
+ # Extra color tokens so they can be used via tokens like color.bright.black, etc.
126
+ extra_color_props = {
127
+ "bright_black": bright_black,
128
+ "bright_blue": bright_blue,
129
+ "bright_cyan": bright_cyan,
130
+ "bright_green": bright_green,
131
+ "bright_magenta": bright_magenta,
132
+ "bright_red": bright_red,
133
+ "bright_white": bright_white,
134
+ "bright_yellow": bright_yellow,
135
+ "normal_black": normal_black,
136
+ "normal_blue": normal_blue,
137
+ "normal_cyan": normal_cyan,
138
+ "normal_green": normal_green,
139
+ "normal_magenta": normal_magenta,
140
+ "normal_red": normal_red,
141
+ "normal_white": normal_white,
142
+ "normal_yellow": normal_yellow,
143
+ "cursor_cursor": cursor_cursor,
144
+ "cursor_text": cursor_text,
145
+ }
146
+ # Randomly choose non color properties.
147
+ default_non_color_props = {
148
+ "table_show_lines": random.choice([True, False]),
149
+ "table_box": random.choice(
150
+ ["ROUNDED", "SIMPLE", "SQUARE", "MINIMAL", "HEAVY", "DOUBLE_EDGE"]
151
+ ),
152
+ "panel_padding": random.choice([[1, 2], [1, 1], [2, 2], [0, 2]]),
153
+ "panel_title_align": random.choice(["left", "center", "right"]),
154
+ # Add table_row_styles property.
155
+ "table_row_styles": random.choice(
156
+ [["", "dim"], ["", "italic"], ["", "underline"]]
157
+ ),
158
+ }
159
+ # Extra table layout properties (non content properties).
160
+ default_extra_table_props = {
161
+ "table_safe_box": True,
162
+ "table_padding": [0, 1],
163
+ "table_collapse_padding": False,
164
+ "table_pad_edge": True,
165
+ "table_expand": False,
166
+ "table_show_footer": False,
167
+ "table_show_edge": True,
168
+ "table_leading": 0,
169
+ "table_style": "none",
170
+ "table_footer_style": "none",
171
+ "table_caption": None,
172
+ "table_caption_style": "none",
173
+ "table_title_justify": "center",
174
+ "table_caption_justify": "center",
175
+ "table_highlight": False,
176
+ }
177
+ # Combine all defaults.
178
+ defaults = {
179
+ **default_color_props,
180
+ **extra_color_props,
181
+ **default_non_color_props,
182
+ **default_extra_table_props,
183
+ }
184
+ return defaults
185
+
186
+
187
+ def load_theme_from_file(filepath: str) -> dict:
188
+ """Load a theme from a TOML file.
189
+
190
+ The theme is expected to contain color blocks like [colors.primary],
191
+ [colors.selection], [colors.normal], [colors.cursor], etc.
192
+ If the file does not contain a [rich] block for styling properties,
193
+ one is generated (with all properties including color mappings) and
194
+ written back into the file.
195
+ """
196
+ with open(filepath) as f:
197
+ theme = toml.load(f)
198
+
199
+ if "rich" not in theme:
200
+ theme["rich"] = generate_default_rich_block(theme)
201
+ # Write the updated theme back into the file.
202
+ with open(filepath, "w") as f:
203
+ toml.dump(theme, f)
204
+
205
+ return theme
206
+
207
+
208
+ def get_default_styles(theme: dict | None) -> dict[str, Any]:
209
+ """Build a style mapping from the theme.
210
+
211
+ It first computes defaults from the [colors] block (via generate_default_rich_block)
212
+ and then overrides any property found in the [rich] block.
213
+ Finally, for every property that is a string, tokens of the form
214
+ "color.<section>.<key>" are resolved.
215
+ """
216
+ if theme is None:
217
+ final_styles = generate_default_rich_block(None)
218
+ else:
219
+ defaults = generate_default_rich_block(theme)
220
+ rich_props = theme.get("rich", {})
221
+ final_styles = {
222
+ key: rich_props.get(key, defaults[key]) for key in defaults
223
+ }
224
+
225
+ # Ensure that panel_padding and table_padding are tuples.
226
+ final_styles["panel_padding"] = tuple(final_styles["panel_padding"])
227
+ if "table_padding" in final_styles:
228
+ final_styles["table_padding"] = tuple(final_styles["table_padding"])
229
+
230
+ # Resolve tokens in every string value.
231
+ if theme is not None:
232
+ for key, value in final_styles.items():
233
+ if isinstance(value, str):
234
+ final_styles[key] = resolve_style_string(value, theme)
235
+
236
+ return final_styles
237
+
238
+
239
+ def create_rich_renderable(
240
+ value: Any,
241
+ level: int = 0,
242
+ theme: dict | None = None,
243
+ styles: dict[str, Any] | None = None,
244
+ max_length: int = -1,
245
+ ) -> Any:
246
+ """Recursively creates a Rich renderable for a given value.
247
+
248
+ - For dicts: creates a Table with headers styled via the computed properties.
249
+ - For lists/tuples: if every item is a dict, returns a Group of subtables;
250
+ otherwise, renders each item recursively.
251
+ - Other types: returns a string (adding extra newlines for multi-line strings).
252
+ """
253
+ if styles is None:
254
+ styles = get_default_styles(theme)
255
+
256
+ # If the value is a dictionary, render it as a table.
257
+ if isinstance(value, dict):
258
+ # Convert table_box string into an actual box style.
259
+ box_style = (
260
+ getattr(box, styles["table_box"])
261
+ if isinstance(styles["table_box"], str)
262
+ else styles["table_box"]
263
+ )
264
+ # Gather all table-related keyword arguments.
265
+ table_kwargs = {
266
+ "show_header": True,
267
+ "header_style": styles["table_header_style"],
268
+ "title": f"Subtable (Level {level})" if level > 0 else None,
269
+ "title_style": styles["table_title_style"],
270
+ "border_style": styles["table_border_style"],
271
+ "show_lines": styles["table_show_lines"],
272
+ "box": box_style,
273
+ "row_styles": styles["table_row_styles"],
274
+ "safe_box": styles.get("table_safe_box"),
275
+ "padding": styles.get("table_padding"),
276
+ "collapse_padding": styles.get("table_collapse_padding"),
277
+ "pad_edge": styles.get("table_pad_edge"),
278
+ "expand": styles.get("table_expand"),
279
+ "show_footer": styles.get("table_show_footer"),
280
+ "show_edge": styles.get("table_show_edge"),
281
+ "leading": styles.get("table_leading"),
282
+ "style": styles.get("table_style"),
283
+ "footer_style": styles.get("table_footer_style"),
284
+ "caption": styles.get("table_caption"),
285
+ "caption_style": styles.get("table_caption_style"),
286
+ "title_justify": styles.get("table_title_justify"),
287
+ "caption_justify": styles.get("table_caption_justify"),
288
+ "highlight": styles.get("table_highlight"),
289
+ }
290
+ table = Table(**table_kwargs)
291
+ table.add_column("Key", style=styles["column_output"])
292
+ table.add_column("Value", style=styles["column_value"])
293
+ for k, v in value.items():
294
+ table.add_row(
295
+ str(k),
296
+ create_rich_renderable(v, level + 1, theme, styles, max_length),
297
+ )
298
+ return table
299
+
300
+ # If the value is a list or tuple, render each item.
301
+ elif isinstance(value, list | tuple):
302
+ if all(isinstance(item, dict) for item in value):
303
+ sub_tables = []
304
+ for i, item in enumerate(value):
305
+ sub_tables.append(f"[bold]Item {i + 1}[/bold]")
306
+ sub_tables.append(
307
+ create_rich_renderable(
308
+ item, level + 1, theme, styles, max_length=max_length
309
+ )
310
+ )
311
+ return Group(*sub_tables)
312
+ else:
313
+ rendered_items = [
314
+ create_rich_renderable(
315
+ item, level + 1, theme, styles, max_length=max_length
316
+ )
317
+ for item in value
318
+ ]
319
+ if all(isinstance(item, str) for item in rendered_items):
320
+ return "\n".join(rendered_items)
321
+ else:
322
+ return Group(*rendered_items)
323
+
324
+ # Otherwise, return a string representation.
325
+ else:
326
+ s = str(value).strip()
327
+ if max_length > 0 and len(s) > max_length:
328
+ omitted = len(s) - max_length
329
+ s = (
330
+ s[:max_length]
331
+ + f"[bold bright_yellow]...(+{omitted}chars)[/bold bright_yellow]"
332
+ )
333
+ if isinstance(value, str) and "\n" in value:
334
+ return f"\n{s}\n"
335
+ return s
336
+
337
+
338
+ class ThemedAgentResultFormatter(BaseFormatter):
339
+ """Formats agent results in a Rich table with nested subtables and theme support."""
340
+
341
+ def __init__(self, theme: str = "atom", max_length: int = -1):
342
+ """Initialize the formatter with a theme and optional max length."""
343
+ self.theme = theme
344
+ self.styles = None
345
+ self.max_length = max_length
346
+
347
+ def format_result(
348
+ self, result: dict[str, Any], agent_name: str, theme, styles
349
+ ) -> Panel:
350
+ """Format an agent's result as a Rich Panel containing a table."""
351
+ box_style = (
352
+ getattr(box, styles["table_box"])
353
+ if isinstance(styles["table_box"], str)
354
+ else styles["table_box"]
355
+ )
356
+
357
+ # Gather table properties for the main table.
358
+ table_kwargs = {
359
+ "show_header": True,
360
+ "header_style": styles["table_header_style"],
361
+ "title": f"Agent Results: {agent_name}",
362
+ "title_style": styles["table_title_style"],
363
+ "border_style": styles["table_border_style"],
364
+ "show_lines": styles["table_show_lines"],
365
+ "box": box_style,
366
+ "row_styles": styles["table_row_styles"],
367
+ "safe_box": styles.get("table_safe_box"),
368
+ "padding": styles.get("table_padding"),
369
+ "collapse_padding": styles.get("table_collapse_padding"),
370
+ "pad_edge": styles.get("table_pad_edge"),
371
+ "expand": styles.get("table_expand"),
372
+ "show_footer": styles.get("table_show_footer"),
373
+ "show_edge": styles.get("table_show_edge"),
374
+ "leading": styles.get("table_leading"),
375
+ "style": styles.get("table_style"),
376
+ "footer_style": styles.get("table_footer_style"),
377
+ "caption": styles.get("table_caption"),
378
+ "caption_style": styles.get("table_caption_style"),
379
+ "title_justify": styles.get("table_title_justify"),
380
+ "caption_justify": styles.get("table_caption_justify"),
381
+ "highlight": styles.get("table_highlight"),
382
+ }
383
+
384
+ table = Table(**table_kwargs)
385
+ table.add_column("Output", style=styles["column_output"])
386
+ table.add_column("Value", style=styles["column_value"])
387
+ for key, value in result.items():
388
+ rich_renderable = create_rich_renderable(
389
+ value,
390
+ level=0,
391
+ theme=theme,
392
+ styles=styles,
393
+ max_length=self.max_length,
394
+ )
395
+ table.add_row(key, rich_renderable)
396
+
397
+ return Panel(
398
+ table,
399
+ title="🐤🐧🐓🦆",
400
+ title_align=styles["panel_title_align"],
401
+ border_style=styles["panel_border_style"],
402
+ padding=styles["panel_padding"],
403
+ style=styles["panel_style"],
404
+ )
405
+
406
+ def display_result(self, result: dict[str, Any], agent_name: str) -> None:
407
+ """Print an agent's result using Rich formatting."""
408
+ theme = self.theme
409
+ themes_dir = (
410
+ pathlib.Path(__file__).parent.parent.parent.parent / "themes"
411
+ )
412
+ all_themes = list(themes_dir.glob("*.toml"))
413
+ theme = theme + ".toml" if not theme.endswith(".toml") else theme
414
+ theme = (
415
+ pathlib.Path(__file__).parent.parent.parent.parent
416
+ / "themes"
417
+ / theme
418
+ )
419
+
420
+ if pathlib.Path(theme) not in all_themes:
421
+ raise ValueError(
422
+ f"Invalid theme: {theme}\nAvailable themes: {all_themes}"
423
+ )
424
+
425
+ theme_dict = load_theme_from_file(theme)
426
+
427
+ styles = get_default_styles(theme_dict)
428
+ self.styles = styles
429
+
430
+ console = Console()
431
+ panel = self.format_result(
432
+ result=result,
433
+ agent_name=agent_name,
434
+ theme=theme_dict,
435
+ styles=styles,
436
+ )
437
+ console.print(panel)
438
+
439
+ @staticmethod
440
+ def display_data(data: dict[str, Any]) -> None:
441
+ """Print agent data using Rich formatting."""
442
+ pprint(data)
@@ -0,0 +1,141 @@
1
+ # File: src/flock/core/logging.py
2
+ """A unified logging module for Flock that works both in local/worker contexts
3
+ and inside Temporal workflows.
4
+
5
+ Key points:
6
+ - We always have Temporal imported, so we cannot decide based on import.
7
+ - Instead, we dynamically check if we're in a workflow context by trying
8
+ to call `workflow.info()`.
9
+ - In a workflow, we use Temporal’s built-in logger and skip debug/info/warning
10
+ logs during replay.
11
+ - Outside workflows, we use Loguru with rich formatting.
12
+ """
13
+
14
+ import sys
15
+
16
+ from opentelemetry import trace
17
+
18
+ # Always import Temporal workflow (since it's part of the project)
19
+ from temporalio import workflow
20
+
21
+ with workflow.unsafe.imports_passed_through():
22
+ from loguru import logger as loguru_logger
23
+
24
+
25
+ def in_workflow_context() -> bool:
26
+ """Returns True if this code is running inside a Temporal workflow context.
27
+ It does this by attempting to call workflow.info() and returning True
28
+ if successful. Otherwise, it returns False.
29
+ """
30
+ try:
31
+ workflow.logger.debug("Checking if in workflow context...")
32
+ # loguru_logger.debug("Checking if in workflow context...")
33
+ # This call will succeed only if we're in a workflow context.
34
+ if hasattr(workflow.info(), "is_replaying"):
35
+ return True
36
+ else:
37
+ return False
38
+ except Exception:
39
+ return False
40
+
41
+
42
+ def get_current_trace_id() -> str:
43
+ """Fetch the current trace ID from OpenTelemetry, if available."""
44
+ current_span = trace.get_current_span()
45
+ span_context = current_span.get_span_context()
46
+ # Format the trace_id as hex (if valid)
47
+ if span_context.is_valid:
48
+ return format(span_context.trace_id, "032x")
49
+ return "no-trace"
50
+
51
+
52
+ # Configure Loguru for non-workflow (local/worker) contexts.
53
+ # Note that in workflow code, we will use Temporal's workflow.logger instead.
54
+ loguru_logger.remove()
55
+ loguru_logger.add(
56
+ sys.stderr,
57
+ level="DEBUG",
58
+ colorize=True,
59
+ format=(
60
+ "<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | "
61
+ "<cyan>[trace_id: {extra[trace_id]}]</cyan> | <magenta>[{extra[category]}]</magenta> | {message}"
62
+ ),
63
+ )
64
+ # Optionally add a file handler, e.g.:
65
+ # loguru_logger.add("logs/flock.log", rotation="100 MB", retention="30 days", level="DEBUG")
66
+
67
+
68
+ # Define a dummy logger that does nothing
69
+ class DummyLogger:
70
+ def debug(self, *args, **kwargs):
71
+ pass
72
+
73
+ def info(self, *args, **kwargs):
74
+ pass
75
+
76
+ def warning(self, *args, **kwargs):
77
+ pass
78
+
79
+ def error(self, *args, **kwargs):
80
+ pass
81
+
82
+ def exception(self, *args, **kwargs):
83
+ pass
84
+
85
+ def success(self, *args, **kwargs):
86
+ pass
87
+
88
+
89
+ dummy_logger = DummyLogger()
90
+
91
+
92
+ class FlockLogger:
93
+ """A unified logger that selects the appropriate logging mechanism based on context.
94
+
95
+ - If running in a workflow context, it uses Temporal's built‑in logger.
96
+ Additionally, if workflow.info().is_replaying is True, it suppresses debug/info/warning logs.
97
+ - Otherwise, it uses Loguru.
98
+ """
99
+
100
+ def __init__(self, name: str, enable_logging: bool = False):
101
+ self.name = name
102
+ self.enable_logging = enable_logging
103
+
104
+ def _get_logger(self):
105
+ if not self.enable_logging:
106
+ return dummy_logger
107
+ if in_workflow_context():
108
+ # Use Temporal's workflow.logger inside a workflow context.
109
+ return workflow.logger
110
+ # Bind our logger with category and trace_id
111
+ return loguru_logger.bind(
112
+ name=self.name,
113
+ category=self.name, # Customize this per module (e.g., "flock", "agent", "context")
114
+ trace_id=get_current_trace_id(),
115
+ )
116
+
117
+ def debug(self, message: str, *args, **kwargs):
118
+ self._get_logger().debug(message, *args, **kwargs)
119
+
120
+ def info(self, message: str, *args, **kwargs):
121
+ self._get_logger().info(message, *args, **kwargs)
122
+
123
+ def warning(self, message: str, *args, **kwargs):
124
+ self._get_logger().warning(message, *args, **kwargs)
125
+
126
+ def error(self, message: str, *args, **kwargs):
127
+ self._get_logger().error(message, *args, **kwargs)
128
+
129
+ def exception(self, message: str, *args, **kwargs):
130
+ self._get_logger().exception(message, *args, **kwargs)
131
+
132
+ def success(self, message: str, *args, **kwargs):
133
+ self._get_logger().success(message, *args, **kwargs)
134
+
135
+
136
+ def get_logger(name: str = "flock") -> FlockLogger:
137
+ """Returns a FlockLogger instance for the given name.
138
+
139
+ Import and use this function throughout your Flock code instead of importing Loguru directly.
140
+ """
141
+ return FlockLogger(name)
@@ -0,0 +1,21 @@
1
+ from opentelemetry import trace
2
+ from opentelemetry.exporter.jaeger.thrift import JaegerExporter
3
+ from opentelemetry.sdk.resources import Resource
4
+ from opentelemetry.sdk.trace import TracerProvider
5
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
6
+
7
+
8
+ def setup_tracing():
9
+ resource = Resource(attributes={"service.name": "flock-agent-framework"})
10
+ provider = TracerProvider(resource=resource)
11
+ trace.set_tracer_provider(provider)
12
+
13
+ # Create a Jaeger exporter
14
+ jaeger_exporter = JaegerExporter(
15
+ agent_host_name="localhost", # or the hostname where Jaeger is running
16
+ agent_port=6831, # default Jaeger agent port
17
+ )
18
+
19
+ provider.add_span_processor(BatchSpanProcessor(jaeger_exporter))
20
+ tracer = trace.get_tracer(__name__)
21
+ return tracer
@@ -0,0 +1,55 @@
1
+ import functools
2
+ import inspect
3
+
4
+ from opentelemetry import trace
5
+
6
+ from flock.core.logging.logging import get_logger
7
+
8
+ logger = get_logger("tools")
9
+ tracer = trace.get_tracer(__name__)
10
+
11
+
12
+ def traced_and_logged(func):
13
+ """A decorator that wraps a function in an OpenTelemetry span and logs its inputs,
14
+ outputs, and exceptions. Supports both synchronous and asynchronous functions.
15
+ """
16
+ if inspect.iscoroutinefunction(func):
17
+
18
+ @functools.wraps(func)
19
+ async def async_wrapper(*args, **kwargs):
20
+ with tracer.start_as_current_span(func.__name__) as span:
21
+ span.set_attribute("args", str(args))
22
+ span.set_attribute("kwargs", str(kwargs))
23
+ try:
24
+ result = await func(*args, **kwargs)
25
+ span.set_attribute("result", str(result))
26
+ logger.debug(
27
+ f"{func.__name__} executed successfully", result=result
28
+ )
29
+ return result
30
+ except Exception as e:
31
+ logger.error(f"Error in {func.__name__}", error=str(e))
32
+ span.record_exception(e)
33
+ raise
34
+
35
+ return async_wrapper
36
+ else:
37
+
38
+ @functools.wraps(func)
39
+ def wrapper(*args, **kwargs):
40
+ with tracer.start_as_current_span(func.__name__) as span:
41
+ span.set_attribute("args", str(args))
42
+ span.set_attribute("kwargs", str(kwargs))
43
+ try:
44
+ result = func(*args, **kwargs)
45
+ span.set_attribute("result", str(result))
46
+ logger.debug(
47
+ f"{func.__name__} executed successfully", result=result
48
+ )
49
+ return result
50
+ except Exception as e:
51
+ logger.error(f"Error in {func.__name__}", error=str(e))
52
+ span.record_exception(e)
53
+ raise
54
+
55
+ return wrapper