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,132 @@
1
+ from typing import Any
2
+
3
+ from devtools import pprint
4
+ from temporalio import workflow
5
+
6
+ from flock.core.logging.formatters.base_formatter import BaseFormatter
7
+
8
+ with workflow.unsafe.imports_passed_through():
9
+ from rich.console import Console, Group
10
+ from rich.panel import Panel
11
+ from rich.table import Table
12
+
13
+
14
+ def create_rich_renderable(
15
+ value: Any,
16
+ level: int = 0,
17
+ max_length: int = -1,
18
+ ) -> Any:
19
+ """Recursively creates a Rich renderable for a given value.
20
+
21
+ - If the value is a dict, return a Table representing the dict.
22
+ - If the value is a list or tuple:
23
+ - If all items are dicts, return a Group of subtables.
24
+ - Otherwise, render each item recursively and either join them as text
25
+ (if all rendered items are strings) or return a Group.
26
+ - Otherwise, return a string (with extra newlines if it's a multi-line string).
27
+ """
28
+ if isinstance(value, dict):
29
+ # Create a subtable for the dictionary.
30
+ # You can tweak the table styles or add a title that indicates the level.
31
+ table = Table(
32
+ show_header=True,
33
+ header_style="bold green",
34
+ title=f"Subtable (Level {level})" if level > 0 else None,
35
+ title_style="bold blue",
36
+ border_style="bright_blue",
37
+ show_lines=True,
38
+ )
39
+ table.add_column("Key", style="cyan")
40
+ table.add_column("Value", style="green")
41
+ for k, v in value.items():
42
+ table.add_row(
43
+ str(k),
44
+ create_rich_renderable(v, level + 1, max_length=max_length),
45
+ )
46
+ return table
47
+
48
+ elif isinstance(value, list | tuple):
49
+ # If all items are dicts, build a Group of subtables with an index.
50
+ if all(isinstance(item, dict) for item in value):
51
+ sub_tables = []
52
+ for i, item in enumerate(value):
53
+ sub_tables.append(f"[bold]Item {i + 1}[/bold]")
54
+ sub_tables.append(
55
+ create_rich_renderable(
56
+ item, level + 1, max_length=max_length
57
+ )
58
+ )
59
+ return Group(*sub_tables)
60
+ else:
61
+ # For a mixed list, render each item recursively.
62
+ rendered_items = [
63
+ create_rich_renderable(item, level + 1, max_length=max_length)
64
+ for item in value
65
+ ]
66
+ # If all items ended up as strings, join them.
67
+ if all(isinstance(item, str) for item in rendered_items):
68
+ return "\n".join(rendered_items)
69
+ else:
70
+ return Group(*rendered_items)
71
+
72
+ else:
73
+ s = str(value).strip()
74
+ if max_length > 0 and len(s) > max_length:
75
+ omitted = len(s) - max_length
76
+ s = (
77
+ s[:max_length]
78
+ + f"[bold bright_yellow]...(+{omitted}chars)[/bold bright_yellow]"
79
+ )
80
+ if isinstance(value, str) and "\n" in value:
81
+ return f"\n{s}\n"
82
+ return s
83
+
84
+
85
+ class RichTables(BaseFormatter):
86
+ """Formats agent results in a beautiful Rich table with nested subtables."""
87
+
88
+ def __init__(self, max_length: int = -1):
89
+ self.max_length = max_length
90
+
91
+ def format_result(self, result: dict[str, Any], agent_name: str) -> Panel:
92
+ """Format an agent's result as a Rich panel containing a table."""
93
+ # Create the main table.
94
+ table = Table(
95
+ show_lines=True,
96
+ show_header=True,
97
+ header_style="bold green",
98
+ title=f"Agent Results: {agent_name}",
99
+ title_style="bold blue",
100
+ border_style="bright_blue",
101
+ )
102
+ table.add_column("Output", style="cyan")
103
+ table.add_column("Value", style="green")
104
+
105
+ # For each key/value pair, use the recursive renderable.
106
+ for key, value in result.items():
107
+ rich_renderable = create_rich_renderable(
108
+ value, level=0, max_length=self.max_length
109
+ )
110
+ table.add_row(key, rich_renderable)
111
+
112
+ # Wrap the table in a panel.
113
+ return Panel(
114
+ table,
115
+ title="🐤🐧🐓🦆",
116
+ title_align="left",
117
+ border_style="blue",
118
+ padding=(1, 2),
119
+ )
120
+
121
+ def display_result(
122
+ self, result: dict[str, Any], agent_name: str, **kwargs
123
+ ) -> None:
124
+ """Print an agent's result using Rich formatting."""
125
+ console = Console()
126
+ panel = self.format_result(result=result, agent_name=agent_name)
127
+ # pprint(result) # Optional: Print the raw result with pprint.
128
+ console.print(panel)
129
+
130
+ def display_data(self, data: dict[str, Any], **kwargs) -> None:
131
+ """Print an agent's result using Rich formatting."""
132
+ pprint(data)
@@ -0,0 +1,480 @@
1
+ #!/usr/bin/env python
2
+ """A simple interactive theme builder.
3
+
4
+ Steps:
5
+ 1. Load theme files from a folder (or pick N random ones).
6
+ 2. Display each theme’s color palette (colors only).
7
+ 3. Let the user choose a palette.
8
+ 4. Generate a number of sample tables using that palette (with randomized non-color settings).
9
+ 5. Let the user select one sample table and save its configuration to a TOML file.
10
+ """
11
+
12
+ import pathlib
13
+ import random
14
+ import re
15
+ from typing import Any
16
+
17
+ import toml
18
+ from rich import box
19
+ from rich.console import Console, Group
20
+ from rich.panel import Panel
21
+ from rich.table import Table
22
+ from rich.text import Text
23
+
24
+
25
+ def resolve_style_string(style_str: str, theme: dict) -> str:
26
+ """Replace tokens of the form "color.<section>.<key>" in style_str with
27
+ the value from theme["colors"][<section>][<key>].
28
+ """
29
+ pattern = r"color\.(\w+)\.(\w+)"
30
+
31
+ def repl(match):
32
+ section = match.group(1)
33
+ key = match.group(2)
34
+ try:
35
+ return theme["colors"][section][key]
36
+ except KeyError:
37
+ return match.group(0)
38
+
39
+ return re.sub(pattern, repl, style_str)
40
+
41
+
42
+ def generate_default_rich_block(theme: dict | None = None) -> dict[str, Any]:
43
+ """Generate a default [rich] block that includes:
44
+ - Color properties computed from the theme's [colors] blocks.
45
+ - Extra color tokens (so tokens like "color.bright.green" can be used).
46
+ - Non-color table layout properties, randomly chosen.
47
+ """
48
+
49
+ def random_background():
50
+ return random.choice(
51
+ [
52
+ f"{normal_black}",
53
+ f"{normal_blue}",
54
+ f"{primary_background}",
55
+ f"{selection_background}",
56
+ f"{cursor_cursor}",
57
+ ]
58
+ )
59
+
60
+ if theme is not None:
61
+ bright = theme["colors"].get("bright", {})
62
+ normal = theme["colors"].get("normal", {})
63
+ cursor = theme["colors"].get("cursor", {})
64
+ primary = theme["colors"].get("primary", {})
65
+ selection = theme["colors"].get("selection", {})
66
+
67
+ bright_black = bright.get("black", "#000000")
68
+ bright_blue = bright.get("blue", "#96cbfe")
69
+ bright_cyan = bright.get("cyan", "#85befd")
70
+ bright_green = bright.get("green", "#94fa36")
71
+ bright_magenta = bright.get("magenta", "#b9b6fc")
72
+ bright_red = bright.get("red", "#fd5ff1")
73
+ bright_white = bright.get("white", "#e0e0e0")
74
+ bright_yellow = bright.get("yellow", "#f5ffa8")
75
+
76
+ normal_black = normal.get("black", "#000000")
77
+ normal_blue = normal.get("blue", "#85befd")
78
+ normal_cyan = normal.get("cyan", "#85befd")
79
+ normal_green = normal.get("green", "#87c38a")
80
+ normal_magenta = normal.get("magenta", "#b9b6fc")
81
+ normal_red = normal.get("red", "#fd5ff1")
82
+ normal_white = normal.get("white", "#e0e0e0")
83
+ normal_yellow = normal.get("yellow", "#ffd7b1")
84
+
85
+ cursor_cursor = cursor.get("cursor", "#d0d0d0")
86
+ cursor_text = cursor.get("text", "#151515")
87
+
88
+ primary_background = primary.get("background", "#161719")
89
+ primary_foreground = primary.get("foreground", "#c5c8c6")
90
+ selection_background = selection.get("background", "#444444")
91
+ selection_text = selection.get("text", primary_foreground)
92
+ else:
93
+ # Fallback default values.
94
+ bright_black = "black"
95
+ bright_blue = "blue"
96
+ bright_cyan = "cyan"
97
+ bright_green = "green"
98
+ bright_magenta = "magenta"
99
+ bright_red = "red"
100
+ bright_white = "white"
101
+ bright_yellow = "yellow"
102
+ normal_black = "black"
103
+ normal_blue = "blue"
104
+ normal_cyan = "cyan"
105
+ normal_green = "green"
106
+ normal_magenta = "magenta"
107
+ normal_red = "red"
108
+ normal_white = "white"
109
+ normal_yellow = "yellow"
110
+ cursor_cursor = "gray"
111
+ cursor_text = "white"
112
+ primary_background = "black"
113
+ primary_foreground = "white"
114
+ selection_background = "gray"
115
+ selection_text = "white"
116
+
117
+ # Color properties.
118
+ default_color_props = {
119
+ "panel_style": f"on {random_background()}",
120
+ "table_header_style": f"bold {selection_text} on {selection_background}",
121
+ "table_title_style": f"bold {primary_foreground}",
122
+ "table_border_style": bright_blue,
123
+ "panel_border_style": bright_blue,
124
+ "column_output": f"bold {primary_foreground}",
125
+ "column_value": primary_foreground,
126
+ }
127
+ # Extra color tokens.
128
+ extra_color_props = {
129
+ "bright_black": bright_black,
130
+ "bright_blue": bright_blue,
131
+ "bright_cyan": bright_cyan,
132
+ "bright_green": bright_green,
133
+ "bright_magenta": bright_magenta,
134
+ "bright_red": bright_red,
135
+ "bright_white": bright_white,
136
+ "bright_yellow": bright_yellow,
137
+ "normal_black": normal_black,
138
+ "normal_blue": normal_blue,
139
+ "normal_cyan": normal_cyan,
140
+ "normal_green": normal_green,
141
+ "normal_magenta": normal_magenta,
142
+ "normal_red": normal_red,
143
+ "normal_white": normal_white,
144
+ "normal_yellow": normal_yellow,
145
+ "cursor_cursor": cursor_cursor,
146
+ "cursor_text": cursor_text,
147
+ }
148
+ # Non-color layout properties, randomly chosen.
149
+ default_non_color_props = {
150
+ "table_show_lines": random.choice([True, False]),
151
+ "table_box": random.choice(
152
+ ["ROUNDED", "SIMPLE", "SQUARE", "MINIMAL", "HEAVY", "DOUBLE_EDGE"]
153
+ ),
154
+ "panel_padding": random.choice([[1, 2], [1, 1], [2, 2], [0, 2]]),
155
+ "panel_title_align": random.choice(["left", "center", "right"]),
156
+ "table_row_styles": random.choice(
157
+ [["", "dim"], ["", "italic"], ["", "underline"]]
158
+ ),
159
+ }
160
+ # Extra table layout properties (non-content).
161
+ default_extra_table_props = {
162
+ "table_safe_box": True,
163
+ "table_padding": [0, 1],
164
+ "table_collapse_padding": False,
165
+ "table_pad_edge": True,
166
+ "table_expand": False,
167
+ "table_show_footer": False,
168
+ "table_show_edge": True,
169
+ "table_leading": 0,
170
+ "table_style": "none",
171
+ "table_footer_style": "none",
172
+ "table_caption": "",
173
+ "table_caption_style": "none",
174
+ "table_title_justify": "center",
175
+ "table_caption_justify": "center",
176
+ "table_highlight": False,
177
+ }
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
+ If the file does not contain a [rich] block, one is generated and saved.
191
+ """
192
+ with open(filepath) as f:
193
+ theme = toml.load(f)
194
+ if "rich" not in theme:
195
+ theme["rich"] = generate_default_rich_block(theme)
196
+ with open(filepath, "w") as f:
197
+ toml.dump(theme, f)
198
+ return theme
199
+
200
+
201
+ def get_default_styles(theme: dict | None) -> dict[str, Any]:
202
+ """Build a style mapping from the theme by merging defaults with any overrides
203
+ in the [rich] block. Also resolves any color tokens.
204
+ """
205
+ if theme is None:
206
+ final_styles = generate_default_rich_block(None)
207
+ else:
208
+ defaults = generate_default_rich_block(theme)
209
+ rich_props = theme.get("rich", {})
210
+ final_styles = {
211
+ key: rich_props.get(key, defaults[key]) for key in defaults
212
+ }
213
+ # Ensure tuple for padding properties.
214
+ final_styles["panel_padding"] = tuple(final_styles["panel_padding"])
215
+ if "table_padding" in final_styles:
216
+ final_styles["table_padding"] = tuple(final_styles["table_padding"])
217
+ # Resolve tokens.
218
+ if theme is not None:
219
+ for key, value in final_styles.items():
220
+ if isinstance(value, str):
221
+ final_styles[key] = resolve_style_string(value, theme)
222
+ return final_styles
223
+
224
+
225
+ def create_rich_renderable(
226
+ value: Any,
227
+ level: int = 0,
228
+ theme: dict | None = None,
229
+ styles: dict[str, Any] | None = None,
230
+ ) -> Any:
231
+ """Recursively creates a Rich renderable.
232
+
233
+ - If value is a dict, renders it as a Table.
234
+ - If a list/tuple, renders each item.
235
+ - Otherwise, returns the string representation.
236
+ """
237
+ if styles is None:
238
+ styles = get_default_styles(theme)
239
+
240
+ if isinstance(value, dict):
241
+ box_style = (
242
+ getattr(box, styles["table_box"])
243
+ if isinstance(styles["table_box"], str)
244
+ else styles["table_box"]
245
+ )
246
+ table_kwargs = {
247
+ "show_header": True,
248
+ "header_style": styles["table_header_style"],
249
+ "title": f"Subtable (Level {level})" if level > 0 else None,
250
+ "title_style": styles["table_title_style"],
251
+ "border_style": styles["table_border_style"],
252
+ "show_lines": styles["table_show_lines"],
253
+ "box": box_style,
254
+ "row_styles": styles["table_row_styles"],
255
+ "safe_box": styles.get("table_safe_box"),
256
+ "padding": styles.get("table_padding"),
257
+ "collapse_padding": styles.get("table_collapse_padding"),
258
+ "pad_edge": styles.get("table_pad_edge"),
259
+ "expand": styles.get("table_expand"),
260
+ "show_footer": styles.get("table_show_footer"),
261
+ "show_edge": styles.get("table_show_edge"),
262
+ "leading": styles.get("table_leading"),
263
+ "style": styles.get("table_style"),
264
+ "footer_style": styles.get("table_footer_style"),
265
+ "caption": styles.get("table_caption"),
266
+ "caption_style": styles.get("table_caption_style"),
267
+ "title_justify": styles.get("table_title_justify"),
268
+ "caption_justify": styles.get("table_caption_justify"),
269
+ "highlight": styles.get("table_highlight"),
270
+ }
271
+ table = Table(**table_kwargs)
272
+ table.add_column("Key", style=styles["column_output"])
273
+ table.add_column("Value", style=styles["column_value"])
274
+ for k, v in value.items():
275
+ table.add_row(
276
+ str(k), create_rich_renderable(v, level + 1, theme, styles)
277
+ )
278
+ return table
279
+
280
+ elif isinstance(value, (list, tuple)):
281
+ if all(isinstance(item, dict) for item in value):
282
+ sub_tables = []
283
+ for i, item in enumerate(value):
284
+ sub_tables.append(f"[bold]Item {i + 1}[/bold]")
285
+ sub_tables.append(
286
+ create_rich_renderable(item, level + 1, theme, styles)
287
+ )
288
+ return Group(*sub_tables)
289
+ else:
290
+ rendered_items = [
291
+ create_rich_renderable(item, level + 1, theme, styles)
292
+ for item in value
293
+ ]
294
+ if all(isinstance(item, str) for item in rendered_items):
295
+ return "\n".join(rendered_items)
296
+ else:
297
+ return Group(*rendered_items)
298
+ else:
299
+ if isinstance(value, str) and "\n" in value:
300
+ return f"\n{value}\n"
301
+ return str(value)
302
+
303
+
304
+ # --- Theme Builder Functions --- #
305
+
306
+
307
+ def load_theme_files(theme_dir: pathlib.Path) -> list[pathlib.Path]:
308
+ """Return a list of .toml theme files in the given directory."""
309
+ return list(theme_dir.glob("*.toml"))
310
+
311
+
312
+ def display_color_palette(theme: dict) -> None:
313
+ """Display the color palette from a theme's [colors] sections with a color preview."""
314
+ console = Console()
315
+ palette_table = Table(
316
+ title="Color Palette", show_header=True, header_style="bold"
317
+ )
318
+ palette_table.add_column("Section", style="bold")
319
+ palette_table.add_column("Key", style="italic")
320
+ palette_table.add_column("Value", style="bold")
321
+ palette_table.add_column("Preview", justify="center")
322
+
323
+ # Iterate over the colors in each section.
324
+ for section, colors in theme.get("colors", {}).items():
325
+ for key, value in colors.items():
326
+ # Create a Text object with a fixed-width string (here, six spaces)
327
+ # styled with a background color of the actual color value.
328
+ preview = Text(" ", style=f"on {value}")
329
+ palette_table.add_row(section, key, value, preview)
330
+
331
+ console.print(palette_table)
332
+
333
+
334
+ def generate_sample_rich_blocks(
335
+ chosen_theme: dict, count: int
336
+ ) -> list[dict[str, Any]]:
337
+ """Generate a list of sample rich blocks (randomized layout) using the chosen theme's colors."""
338
+ samples = []
339
+ for _ in range(count):
340
+ samples.append(generate_default_rich_block(chosen_theme))
341
+ return samples
342
+
343
+
344
+ def generate_sample_table(sample_theme: dict, dummy_data: dict) -> Panel:
345
+ """Generate a sample table using the given theme dictionary (which includes a [rich] block)
346
+ and some dummy data.
347
+ """
348
+ # Here we use our create_rich_renderable to build a table for dummy_data.
349
+ # For simplicity, we create our own panel.
350
+ styles = get_default_styles(sample_theme)
351
+ # Build a basic table (using our earlier functions)
352
+ table = create_rich_renderable(
353
+ dummy_data, theme=sample_theme, styles=styles
354
+ )
355
+ return Panel(
356
+ table,
357
+ title="Sample Table",
358
+ title_align=styles["panel_title_align"],
359
+ border_style=styles["panel_border_style"],
360
+ padding=styles["panel_padding"],
361
+ style=styles["panel_style"],
362
+ )
363
+
364
+
365
+ def save_theme(theme: dict, filename: pathlib.Path) -> None:
366
+ """Save the given theme dictionary to the specified TOML file."""
367
+ with open(filename, "w") as f:
368
+ toml.dump(theme, f)
369
+
370
+
371
+ # --- Main Interactive Loop --- #
372
+
373
+
374
+ def main():
375
+ console = Console(force_terminal=True, color_system="truecolor")
376
+ themes_dir = pathlib.Path(__file__).parent.parent.parent.parent / "themes"
377
+ theme_files = load_theme_files(themes_dir)
378
+
379
+ if not theme_files:
380
+ console.print("[red]No theme files found in the themes folder.[/red]")
381
+ return
382
+
383
+ # Ask the user: load all themes or N random themes?
384
+ console.print("[bold]Theme Builder[/bold]")
385
+ choice = console.input(
386
+ "Load [bold](a)ll[/bold] themes or [bold](n)[/bold] random ones? (a/n): "
387
+ )
388
+ if choice.lower() == "n":
389
+ n = console.input("How many random themes? ")
390
+ try:
391
+ n = int(n)
392
+ except ValueError:
393
+ n = len(theme_files)
394
+ theme_files = random.sample(theme_files, min(n, len(theme_files)))
395
+
396
+ # Display palettes for each theme file.
397
+ console.print("\n[underline]Available Color Palettes:[/underline]")
398
+ palettes = []
399
+ for idx, tf in enumerate(theme_files):
400
+ theme_dict = load_theme_from_file(str(tf))
401
+ palettes.append((tf, theme_dict))
402
+ console.print(f"\n[bold]Theme #{idx} - {tf.name}[/bold]")
403
+ display_color_palette(theme_dict)
404
+
405
+ # Let the user choose a palette by index.
406
+ sel = console.input("\nEnter the number of the palette to use: ")
407
+ try:
408
+ sel = int(sel)
409
+ chosen_theme = palettes[sel][1]
410
+ except (ValueError, IndexError):
411
+ console.print("[red]Invalid selection. Exiting.[/red]")
412
+ return
413
+
414
+ console.print("\n[underline]Selected Palette:[/underline]")
415
+ display_color_palette(chosen_theme)
416
+
417
+ # Ask the user how many sample tables to generate.
418
+ count = console.input("\nHow many sample tables to generate? (default 3): ")
419
+ try:
420
+ count = int(count)
421
+ except ValueError:
422
+ count = 3
423
+
424
+ # Generate sample rich blocks from the chosen theme.
425
+ sample_rich_blocks = generate_sample_rich_blocks(chosen_theme, count)
426
+
427
+ # For each sample, create a new theme dict that uses the chosen palette and the sample rich block.
428
+ dummy_data = {
429
+ "Agent": "Test Agent",
430
+ "Status": "Running",
431
+ "Metrics": {
432
+ "CPU": "20%",
433
+ "Memory": "512MB",
434
+ "Nested": {"value1": 1, "value2": 2},
435
+ },
436
+ "Logs": [
437
+ "Initialization complete",
438
+ "Running process...",
439
+ {"Step": "Completed", "Time": "2025-02-07T12:00:00Z"},
440
+ ],
441
+ }
442
+
443
+ samples = []
444
+ for i, rich_block in enumerate(sample_rich_blocks):
445
+ # Build a sample theme: copy the chosen theme and override its [rich] block.
446
+ sample_theme = dict(
447
+ chosen_theme
448
+ ) # shallow copy (good enough if colors remain unchanged)
449
+ sample_theme["rich"] = rich_block
450
+ sample_table = generate_sample_table(sample_theme, dummy_data)
451
+ samples.append((sample_theme, sample_table))
452
+ console.print(f"\n[bold]Sample Table #{i}[/bold]")
453
+ console.print(sample_table)
454
+
455
+ # Let the user choose one sample or regenerate.
456
+ sel2 = console.input(
457
+ "\nEnter the number of the sample table you like, or type [bold]r[/bold] to regenerate: "
458
+ )
459
+ if sel2.lower() == "r":
460
+ console.print("Regenerating samples...")
461
+ main() # restart the builder
462
+ return
463
+ try:
464
+ sel2 = int(sel2)
465
+ chosen_sample_theme = samples[sel2][0]
466
+ except (ValueError, IndexError):
467
+ console.print("[red]Invalid selection. Exiting.[/red]")
468
+ return
469
+
470
+ # Ask for file name to save the chosen theme.
471
+ filename = console.input(
472
+ "\nEnter a filename to save the chosen theme (e.g. mytheme.toml): "
473
+ )
474
+ save_path = themes_dir / filename
475
+ save_theme(chosen_sample_theme, save_path)
476
+ console.print(f"\n[green]Theme saved as {save_path}.[/green]")
477
+
478
+
479
+ if __name__ == "__main__":
480
+ main()