ai-parrot 0.17.2__cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.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.
Files changed (535) hide show
  1. agentui/.prettierrc +15 -0
  2. agentui/QUICKSTART.md +272 -0
  3. agentui/README.md +59 -0
  4. agentui/env.example +16 -0
  5. agentui/jsconfig.json +14 -0
  6. agentui/package-lock.json +4242 -0
  7. agentui/package.json +34 -0
  8. agentui/scripts/postinstall/apply-patches.mjs +260 -0
  9. agentui/src/app.css +61 -0
  10. agentui/src/app.d.ts +13 -0
  11. agentui/src/app.html +12 -0
  12. agentui/src/components/LoadingSpinner.svelte +64 -0
  13. agentui/src/components/ThemeSwitcher.svelte +159 -0
  14. agentui/src/components/index.js +4 -0
  15. agentui/src/lib/api/bots.ts +60 -0
  16. agentui/src/lib/api/chat.ts +22 -0
  17. agentui/src/lib/api/http.ts +25 -0
  18. agentui/src/lib/components/BotCard.svelte +33 -0
  19. agentui/src/lib/components/ChatBubble.svelte +63 -0
  20. agentui/src/lib/components/Toast.svelte +21 -0
  21. agentui/src/lib/config.ts +20 -0
  22. agentui/src/lib/stores/auth.svelte.ts +73 -0
  23. agentui/src/lib/stores/theme.svelte.js +64 -0
  24. agentui/src/lib/stores/toast.svelte.ts +31 -0
  25. agentui/src/lib/utils/conversation.ts +39 -0
  26. agentui/src/routes/+layout.svelte +20 -0
  27. agentui/src/routes/+page.svelte +232 -0
  28. agentui/src/routes/login/+page.svelte +200 -0
  29. agentui/src/routes/talk/[agentId]/+page.svelte +297 -0
  30. agentui/src/routes/talk/[agentId]/+page.ts +7 -0
  31. agentui/static/README.md +1 -0
  32. agentui/svelte.config.js +11 -0
  33. agentui/tailwind.config.ts +53 -0
  34. agentui/tsconfig.json +3 -0
  35. agentui/vite.config.ts +10 -0
  36. ai_parrot-0.17.2.dist-info/METADATA +472 -0
  37. ai_parrot-0.17.2.dist-info/RECORD +535 -0
  38. ai_parrot-0.17.2.dist-info/WHEEL +6 -0
  39. ai_parrot-0.17.2.dist-info/entry_points.txt +2 -0
  40. ai_parrot-0.17.2.dist-info/licenses/LICENSE +21 -0
  41. ai_parrot-0.17.2.dist-info/top_level.txt +6 -0
  42. crew-builder/.prettierrc +15 -0
  43. crew-builder/QUICKSTART.md +259 -0
  44. crew-builder/README.md +113 -0
  45. crew-builder/env.example +17 -0
  46. crew-builder/jsconfig.json +14 -0
  47. crew-builder/package-lock.json +4182 -0
  48. crew-builder/package.json +37 -0
  49. crew-builder/scripts/postinstall/apply-patches.mjs +260 -0
  50. crew-builder/src/app.css +62 -0
  51. crew-builder/src/app.d.ts +13 -0
  52. crew-builder/src/app.html +12 -0
  53. crew-builder/src/components/LoadingSpinner.svelte +64 -0
  54. crew-builder/src/components/ThemeSwitcher.svelte +149 -0
  55. crew-builder/src/components/index.js +9 -0
  56. crew-builder/src/lib/api/bots.ts +60 -0
  57. crew-builder/src/lib/api/chat.ts +80 -0
  58. crew-builder/src/lib/api/client.ts +56 -0
  59. crew-builder/src/lib/api/crew/crew.ts +136 -0
  60. crew-builder/src/lib/api/index.ts +5 -0
  61. crew-builder/src/lib/api/o365/auth.ts +65 -0
  62. crew-builder/src/lib/auth/auth.ts +54 -0
  63. crew-builder/src/lib/components/AgentNode.svelte +43 -0
  64. crew-builder/src/lib/components/BotCard.svelte +33 -0
  65. crew-builder/src/lib/components/ChatBubble.svelte +67 -0
  66. crew-builder/src/lib/components/ConfigPanel.svelte +278 -0
  67. crew-builder/src/lib/components/JsonTreeNode.svelte +76 -0
  68. crew-builder/src/lib/components/JsonViewer.svelte +24 -0
  69. crew-builder/src/lib/components/MarkdownEditor.svelte +48 -0
  70. crew-builder/src/lib/components/ThemeToggle.svelte +36 -0
  71. crew-builder/src/lib/components/Toast.svelte +67 -0
  72. crew-builder/src/lib/components/Toolbar.svelte +157 -0
  73. crew-builder/src/lib/components/index.ts +10 -0
  74. crew-builder/src/lib/config.ts +8 -0
  75. crew-builder/src/lib/stores/auth.svelte.ts +228 -0
  76. crew-builder/src/lib/stores/crewStore.ts +369 -0
  77. crew-builder/src/lib/stores/theme.svelte.js +145 -0
  78. crew-builder/src/lib/stores/toast.svelte.ts +69 -0
  79. crew-builder/src/lib/utils/conversation.ts +39 -0
  80. crew-builder/src/lib/utils/markdown.ts +122 -0
  81. crew-builder/src/lib/utils/talkHistory.ts +47 -0
  82. crew-builder/src/routes/+layout.svelte +20 -0
  83. crew-builder/src/routes/+page.svelte +539 -0
  84. crew-builder/src/routes/agents/+page.svelte +247 -0
  85. crew-builder/src/routes/agents/[agentId]/+page.svelte +288 -0
  86. crew-builder/src/routes/agents/[agentId]/+page.ts +7 -0
  87. crew-builder/src/routes/builder/+page.svelte +204 -0
  88. crew-builder/src/routes/crew/ask/+page.svelte +1052 -0
  89. crew-builder/src/routes/crew/ask/+page.ts +1 -0
  90. crew-builder/src/routes/integrations/o365/+page.svelte +304 -0
  91. crew-builder/src/routes/login/+page.svelte +197 -0
  92. crew-builder/src/routes/talk/[agentId]/+page.svelte +487 -0
  93. crew-builder/src/routes/talk/[agentId]/+page.ts +7 -0
  94. crew-builder/static/README.md +1 -0
  95. crew-builder/svelte.config.js +11 -0
  96. crew-builder/tailwind.config.ts +53 -0
  97. crew-builder/tsconfig.json +3 -0
  98. crew-builder/vite.config.ts +10 -0
  99. mcp_servers/calculator_server.py +309 -0
  100. parrot/__init__.py +27 -0
  101. parrot/__pycache__/__init__.cpython-310.pyc +0 -0
  102. parrot/__pycache__/version.cpython-310.pyc +0 -0
  103. parrot/_version.py +34 -0
  104. parrot/a2a/__init__.py +48 -0
  105. parrot/a2a/client.py +658 -0
  106. parrot/a2a/discovery.py +89 -0
  107. parrot/a2a/mixin.py +257 -0
  108. parrot/a2a/models.py +376 -0
  109. parrot/a2a/server.py +770 -0
  110. parrot/agents/__init__.py +29 -0
  111. parrot/bots/__init__.py +12 -0
  112. parrot/bots/a2a_agent.py +19 -0
  113. parrot/bots/abstract.py +3139 -0
  114. parrot/bots/agent.py +1129 -0
  115. parrot/bots/basic.py +9 -0
  116. parrot/bots/chatbot.py +669 -0
  117. parrot/bots/data.py +1618 -0
  118. parrot/bots/database/__init__.py +5 -0
  119. parrot/bots/database/abstract.py +3071 -0
  120. parrot/bots/database/cache.py +286 -0
  121. parrot/bots/database/models.py +468 -0
  122. parrot/bots/database/prompts.py +154 -0
  123. parrot/bots/database/retries.py +98 -0
  124. parrot/bots/database/router.py +269 -0
  125. parrot/bots/database/sql.py +41 -0
  126. parrot/bots/db/__init__.py +6 -0
  127. parrot/bots/db/abstract.py +556 -0
  128. parrot/bots/db/bigquery.py +602 -0
  129. parrot/bots/db/cache.py +85 -0
  130. parrot/bots/db/documentdb.py +668 -0
  131. parrot/bots/db/elastic.py +1014 -0
  132. parrot/bots/db/influx.py +898 -0
  133. parrot/bots/db/mock.py +96 -0
  134. parrot/bots/db/multi.py +783 -0
  135. parrot/bots/db/prompts.py +185 -0
  136. parrot/bots/db/sql.py +1255 -0
  137. parrot/bots/db/tools.py +212 -0
  138. parrot/bots/document.py +680 -0
  139. parrot/bots/hrbot.py +15 -0
  140. parrot/bots/kb.py +170 -0
  141. parrot/bots/mcp.py +36 -0
  142. parrot/bots/orchestration/README.md +463 -0
  143. parrot/bots/orchestration/__init__.py +1 -0
  144. parrot/bots/orchestration/agent.py +155 -0
  145. parrot/bots/orchestration/crew.py +3330 -0
  146. parrot/bots/orchestration/fsm.py +1179 -0
  147. parrot/bots/orchestration/hr.py +434 -0
  148. parrot/bots/orchestration/storage/__init__.py +4 -0
  149. parrot/bots/orchestration/storage/memory.py +100 -0
  150. parrot/bots/orchestration/storage/mixin.py +119 -0
  151. parrot/bots/orchestration/verify.py +202 -0
  152. parrot/bots/product.py +204 -0
  153. parrot/bots/prompts/__init__.py +96 -0
  154. parrot/bots/prompts/agents.py +155 -0
  155. parrot/bots/prompts/data.py +216 -0
  156. parrot/bots/prompts/output_generation.py +8 -0
  157. parrot/bots/scraper/__init__.py +3 -0
  158. parrot/bots/scraper/models.py +122 -0
  159. parrot/bots/scraper/scraper.py +1173 -0
  160. parrot/bots/scraper/templates.py +115 -0
  161. parrot/bots/stores/__init__.py +5 -0
  162. parrot/bots/stores/local.py +172 -0
  163. parrot/bots/webdev.py +81 -0
  164. parrot/cli.py +17 -0
  165. parrot/clients/__init__.py +16 -0
  166. parrot/clients/base.py +1491 -0
  167. parrot/clients/claude.py +1191 -0
  168. parrot/clients/factory.py +129 -0
  169. parrot/clients/google.py +4567 -0
  170. parrot/clients/gpt.py +1975 -0
  171. parrot/clients/grok.py +432 -0
  172. parrot/clients/groq.py +986 -0
  173. parrot/clients/hf.py +582 -0
  174. parrot/clients/models.py +18 -0
  175. parrot/conf.py +395 -0
  176. parrot/embeddings/__init__.py +9 -0
  177. parrot/embeddings/base.py +157 -0
  178. parrot/embeddings/google.py +98 -0
  179. parrot/embeddings/huggingface.py +74 -0
  180. parrot/embeddings/openai.py +84 -0
  181. parrot/embeddings/processor.py +88 -0
  182. parrot/exceptions.c +13868 -0
  183. parrot/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
  184. parrot/exceptions.pxd +22 -0
  185. parrot/exceptions.pxi +15 -0
  186. parrot/exceptions.pyx +44 -0
  187. parrot/generators/__init__.py +29 -0
  188. parrot/generators/base.py +200 -0
  189. parrot/generators/html.py +293 -0
  190. parrot/generators/react.py +205 -0
  191. parrot/generators/streamlit.py +203 -0
  192. parrot/generators/template.py +105 -0
  193. parrot/handlers/__init__.py +4 -0
  194. parrot/handlers/agent.py +861 -0
  195. parrot/handlers/agents/__init__.py +1 -0
  196. parrot/handlers/agents/abstract.py +900 -0
  197. parrot/handlers/bots.py +338 -0
  198. parrot/handlers/chat.py +915 -0
  199. parrot/handlers/creation.sql +192 -0
  200. parrot/handlers/crew/ARCHITECTURE.md +362 -0
  201. parrot/handlers/crew/README_BOTMANAGER_PERSISTENCE.md +303 -0
  202. parrot/handlers/crew/README_REDIS_PERSISTENCE.md +366 -0
  203. parrot/handlers/crew/__init__.py +0 -0
  204. parrot/handlers/crew/handler.py +801 -0
  205. parrot/handlers/crew/models.py +229 -0
  206. parrot/handlers/crew/redis_persistence.py +523 -0
  207. parrot/handlers/jobs/__init__.py +10 -0
  208. parrot/handlers/jobs/job.py +384 -0
  209. parrot/handlers/jobs/mixin.py +627 -0
  210. parrot/handlers/jobs/models.py +115 -0
  211. parrot/handlers/jobs/worker.py +31 -0
  212. parrot/handlers/models.py +596 -0
  213. parrot/handlers/o365_auth.py +105 -0
  214. parrot/handlers/stream.py +337 -0
  215. parrot/interfaces/__init__.py +6 -0
  216. parrot/interfaces/aws.py +143 -0
  217. parrot/interfaces/credentials.py +113 -0
  218. parrot/interfaces/database.py +27 -0
  219. parrot/interfaces/google.py +1123 -0
  220. parrot/interfaces/hierarchy.py +1227 -0
  221. parrot/interfaces/http.py +651 -0
  222. parrot/interfaces/images/__init__.py +0 -0
  223. parrot/interfaces/images/plugins/__init__.py +24 -0
  224. parrot/interfaces/images/plugins/abstract.py +58 -0
  225. parrot/interfaces/images/plugins/analisys.py +148 -0
  226. parrot/interfaces/images/plugins/classify.py +150 -0
  227. parrot/interfaces/images/plugins/classifybase.py +182 -0
  228. parrot/interfaces/images/plugins/detect.py +150 -0
  229. parrot/interfaces/images/plugins/exif.py +1103 -0
  230. parrot/interfaces/images/plugins/hash.py +52 -0
  231. parrot/interfaces/images/plugins/vision.py +104 -0
  232. parrot/interfaces/images/plugins/yolo.py +66 -0
  233. parrot/interfaces/images/plugins/zerodetect.py +197 -0
  234. parrot/interfaces/o365.py +978 -0
  235. parrot/interfaces/onedrive.py +822 -0
  236. parrot/interfaces/sharepoint.py +1435 -0
  237. parrot/interfaces/soap.py +257 -0
  238. parrot/loaders/__init__.py +8 -0
  239. parrot/loaders/abstract.py +1131 -0
  240. parrot/loaders/audio.py +199 -0
  241. parrot/loaders/basepdf.py +53 -0
  242. parrot/loaders/basevideo.py +1568 -0
  243. parrot/loaders/csv.py +409 -0
  244. parrot/loaders/docx.py +116 -0
  245. parrot/loaders/epubloader.py +316 -0
  246. parrot/loaders/excel.py +199 -0
  247. parrot/loaders/factory.py +55 -0
  248. parrot/loaders/files/__init__.py +0 -0
  249. parrot/loaders/files/abstract.py +39 -0
  250. parrot/loaders/files/html.py +26 -0
  251. parrot/loaders/files/text.py +63 -0
  252. parrot/loaders/html.py +152 -0
  253. parrot/loaders/markdown.py +442 -0
  254. parrot/loaders/pdf.py +373 -0
  255. parrot/loaders/pdfmark.py +320 -0
  256. parrot/loaders/pdftables.py +506 -0
  257. parrot/loaders/ppt.py +476 -0
  258. parrot/loaders/qa.py +63 -0
  259. parrot/loaders/splitters/__init__.py +10 -0
  260. parrot/loaders/splitters/base.py +138 -0
  261. parrot/loaders/splitters/md.py +228 -0
  262. parrot/loaders/splitters/token.py +143 -0
  263. parrot/loaders/txt.py +26 -0
  264. parrot/loaders/video.py +89 -0
  265. parrot/loaders/videolocal.py +218 -0
  266. parrot/loaders/videounderstanding.py +377 -0
  267. parrot/loaders/vimeo.py +167 -0
  268. parrot/loaders/web.py +599 -0
  269. parrot/loaders/youtube.py +504 -0
  270. parrot/manager/__init__.py +5 -0
  271. parrot/manager/manager.py +1030 -0
  272. parrot/mcp/__init__.py +28 -0
  273. parrot/mcp/adapter.py +105 -0
  274. parrot/mcp/cli.py +174 -0
  275. parrot/mcp/client.py +119 -0
  276. parrot/mcp/config.py +75 -0
  277. parrot/mcp/integration.py +842 -0
  278. parrot/mcp/oauth.py +933 -0
  279. parrot/mcp/server.py +225 -0
  280. parrot/mcp/transports/__init__.py +3 -0
  281. parrot/mcp/transports/base.py +279 -0
  282. parrot/mcp/transports/grpc_session.py +163 -0
  283. parrot/mcp/transports/http.py +312 -0
  284. parrot/mcp/transports/mcp.proto +108 -0
  285. parrot/mcp/transports/quic.py +1082 -0
  286. parrot/mcp/transports/sse.py +330 -0
  287. parrot/mcp/transports/stdio.py +309 -0
  288. parrot/mcp/transports/unix.py +395 -0
  289. parrot/mcp/transports/websocket.py +547 -0
  290. parrot/memory/__init__.py +16 -0
  291. parrot/memory/abstract.py +209 -0
  292. parrot/memory/agent.py +32 -0
  293. parrot/memory/cache.py +175 -0
  294. parrot/memory/core.py +555 -0
  295. parrot/memory/file.py +153 -0
  296. parrot/memory/mem.py +131 -0
  297. parrot/memory/redis.py +613 -0
  298. parrot/models/__init__.py +46 -0
  299. parrot/models/basic.py +118 -0
  300. parrot/models/compliance.py +208 -0
  301. parrot/models/crew.py +395 -0
  302. parrot/models/detections.py +654 -0
  303. parrot/models/generation.py +85 -0
  304. parrot/models/google.py +223 -0
  305. parrot/models/groq.py +23 -0
  306. parrot/models/openai.py +30 -0
  307. parrot/models/outputs.py +285 -0
  308. parrot/models/responses.py +938 -0
  309. parrot/notifications/__init__.py +743 -0
  310. parrot/openapi/__init__.py +3 -0
  311. parrot/openapi/components.yaml +641 -0
  312. parrot/openapi/config.py +322 -0
  313. parrot/outputs/__init__.py +32 -0
  314. parrot/outputs/formats/__init__.py +108 -0
  315. parrot/outputs/formats/altair.py +359 -0
  316. parrot/outputs/formats/application.py +122 -0
  317. parrot/outputs/formats/base.py +351 -0
  318. parrot/outputs/formats/bokeh.py +356 -0
  319. parrot/outputs/formats/card.py +424 -0
  320. parrot/outputs/formats/chart.py +436 -0
  321. parrot/outputs/formats/d3.py +255 -0
  322. parrot/outputs/formats/echarts.py +310 -0
  323. parrot/outputs/formats/generators/__init__.py +0 -0
  324. parrot/outputs/formats/generators/abstract.py +61 -0
  325. parrot/outputs/formats/generators/panel.py +145 -0
  326. parrot/outputs/formats/generators/streamlit.py +86 -0
  327. parrot/outputs/formats/generators/terminal.py +63 -0
  328. parrot/outputs/formats/holoviews.py +310 -0
  329. parrot/outputs/formats/html.py +147 -0
  330. parrot/outputs/formats/jinja2.py +46 -0
  331. parrot/outputs/formats/json.py +87 -0
  332. parrot/outputs/formats/map.py +933 -0
  333. parrot/outputs/formats/markdown.py +172 -0
  334. parrot/outputs/formats/matplotlib.py +237 -0
  335. parrot/outputs/formats/mixins/__init__.py +0 -0
  336. parrot/outputs/formats/mixins/emaps.py +855 -0
  337. parrot/outputs/formats/plotly.py +341 -0
  338. parrot/outputs/formats/seaborn.py +310 -0
  339. parrot/outputs/formats/table.py +397 -0
  340. parrot/outputs/formats/template_report.py +138 -0
  341. parrot/outputs/formats/yaml.py +125 -0
  342. parrot/outputs/formatter.py +152 -0
  343. parrot/outputs/templates/__init__.py +95 -0
  344. parrot/pipelines/__init__.py +0 -0
  345. parrot/pipelines/abstract.py +210 -0
  346. parrot/pipelines/detector.py +124 -0
  347. parrot/pipelines/models.py +90 -0
  348. parrot/pipelines/planogram.py +3002 -0
  349. parrot/pipelines/table.sql +97 -0
  350. parrot/plugins/__init__.py +106 -0
  351. parrot/plugins/importer.py +80 -0
  352. parrot/py.typed +0 -0
  353. parrot/registry/__init__.py +18 -0
  354. parrot/registry/registry.py +594 -0
  355. parrot/scheduler/__init__.py +1189 -0
  356. parrot/scheduler/models.py +60 -0
  357. parrot/security/__init__.py +16 -0
  358. parrot/security/prompt_injection.py +268 -0
  359. parrot/security/security_events.sql +25 -0
  360. parrot/services/__init__.py +1 -0
  361. parrot/services/mcp/__init__.py +8 -0
  362. parrot/services/mcp/config.py +13 -0
  363. parrot/services/mcp/server.py +295 -0
  364. parrot/services/o365_remote_auth.py +235 -0
  365. parrot/stores/__init__.py +7 -0
  366. parrot/stores/abstract.py +352 -0
  367. parrot/stores/arango.py +1090 -0
  368. parrot/stores/bigquery.py +1377 -0
  369. parrot/stores/cache.py +106 -0
  370. parrot/stores/empty.py +10 -0
  371. parrot/stores/faiss_store.py +1157 -0
  372. parrot/stores/kb/__init__.py +9 -0
  373. parrot/stores/kb/abstract.py +68 -0
  374. parrot/stores/kb/cache.py +165 -0
  375. parrot/stores/kb/doc.py +325 -0
  376. parrot/stores/kb/hierarchy.py +346 -0
  377. parrot/stores/kb/local.py +457 -0
  378. parrot/stores/kb/prompt.py +28 -0
  379. parrot/stores/kb/redis.py +659 -0
  380. parrot/stores/kb/store.py +115 -0
  381. parrot/stores/kb/user.py +374 -0
  382. parrot/stores/models.py +59 -0
  383. parrot/stores/pgvector.py +3 -0
  384. parrot/stores/postgres.py +2853 -0
  385. parrot/stores/utils/__init__.py +0 -0
  386. parrot/stores/utils/chunking.py +197 -0
  387. parrot/telemetry/__init__.py +3 -0
  388. parrot/telemetry/mixin.py +111 -0
  389. parrot/template/__init__.py +3 -0
  390. parrot/template/engine.py +259 -0
  391. parrot/tools/__init__.py +23 -0
  392. parrot/tools/abstract.py +644 -0
  393. parrot/tools/agent.py +363 -0
  394. parrot/tools/arangodbsearch.py +537 -0
  395. parrot/tools/arxiv_tool.py +188 -0
  396. parrot/tools/calculator/__init__.py +3 -0
  397. parrot/tools/calculator/operations/__init__.py +38 -0
  398. parrot/tools/calculator/operations/calculus.py +80 -0
  399. parrot/tools/calculator/operations/statistics.py +76 -0
  400. parrot/tools/calculator/tool.py +150 -0
  401. parrot/tools/cloudwatch.py +988 -0
  402. parrot/tools/codeinterpreter/__init__.py +127 -0
  403. parrot/tools/codeinterpreter/executor.py +371 -0
  404. parrot/tools/codeinterpreter/internals.py +473 -0
  405. parrot/tools/codeinterpreter/models.py +643 -0
  406. parrot/tools/codeinterpreter/prompts.py +224 -0
  407. parrot/tools/codeinterpreter/tool.py +664 -0
  408. parrot/tools/company_info/__init__.py +6 -0
  409. parrot/tools/company_info/tool.py +1138 -0
  410. parrot/tools/correlationanalysis.py +437 -0
  411. parrot/tools/database/abstract.py +286 -0
  412. parrot/tools/database/bq.py +115 -0
  413. parrot/tools/database/cache.py +284 -0
  414. parrot/tools/database/models.py +95 -0
  415. parrot/tools/database/pg.py +343 -0
  416. parrot/tools/databasequery.py +1159 -0
  417. parrot/tools/db.py +1800 -0
  418. parrot/tools/ddgo.py +370 -0
  419. parrot/tools/decorators.py +271 -0
  420. parrot/tools/dftohtml.py +282 -0
  421. parrot/tools/document.py +549 -0
  422. parrot/tools/ecs.py +819 -0
  423. parrot/tools/edareport.py +368 -0
  424. parrot/tools/elasticsearch.py +1049 -0
  425. parrot/tools/employees.py +462 -0
  426. parrot/tools/epson/__init__.py +96 -0
  427. parrot/tools/excel.py +683 -0
  428. parrot/tools/file/__init__.py +13 -0
  429. parrot/tools/file/abstract.py +76 -0
  430. parrot/tools/file/gcs.py +378 -0
  431. parrot/tools/file/local.py +284 -0
  432. parrot/tools/file/s3.py +511 -0
  433. parrot/tools/file/tmp.py +309 -0
  434. parrot/tools/file/tool.py +501 -0
  435. parrot/tools/file_reader.py +129 -0
  436. parrot/tools/flowtask/__init__.py +19 -0
  437. parrot/tools/flowtask/tool.py +761 -0
  438. parrot/tools/gittoolkit.py +508 -0
  439. parrot/tools/google/__init__.py +18 -0
  440. parrot/tools/google/base.py +169 -0
  441. parrot/tools/google/tools.py +1251 -0
  442. parrot/tools/googlelocation.py +5 -0
  443. parrot/tools/googleroutes.py +5 -0
  444. parrot/tools/googlesearch.py +5 -0
  445. parrot/tools/googlesitesearch.py +5 -0
  446. parrot/tools/googlevoice.py +2 -0
  447. parrot/tools/gvoice.py +695 -0
  448. parrot/tools/ibisworld/README.md +225 -0
  449. parrot/tools/ibisworld/__init__.py +11 -0
  450. parrot/tools/ibisworld/tool.py +366 -0
  451. parrot/tools/jiratoolkit.py +1718 -0
  452. parrot/tools/manager.py +1098 -0
  453. parrot/tools/math.py +152 -0
  454. parrot/tools/metadata.py +476 -0
  455. parrot/tools/msteams.py +1621 -0
  456. parrot/tools/msword.py +635 -0
  457. parrot/tools/multidb.py +580 -0
  458. parrot/tools/multistoresearch.py +369 -0
  459. parrot/tools/networkninja.py +167 -0
  460. parrot/tools/nextstop/__init__.py +4 -0
  461. parrot/tools/nextstop/base.py +286 -0
  462. parrot/tools/nextstop/employee.py +733 -0
  463. parrot/tools/nextstop/store.py +462 -0
  464. parrot/tools/notification.py +435 -0
  465. parrot/tools/o365/__init__.py +42 -0
  466. parrot/tools/o365/base.py +295 -0
  467. parrot/tools/o365/bundle.py +522 -0
  468. parrot/tools/o365/events.py +554 -0
  469. parrot/tools/o365/mail.py +992 -0
  470. parrot/tools/o365/onedrive.py +497 -0
  471. parrot/tools/o365/sharepoint.py +641 -0
  472. parrot/tools/openapi_toolkit.py +904 -0
  473. parrot/tools/openweather.py +527 -0
  474. parrot/tools/pdfprint.py +1001 -0
  475. parrot/tools/powerbi.py +518 -0
  476. parrot/tools/powerpoint.py +1113 -0
  477. parrot/tools/pricestool.py +146 -0
  478. parrot/tools/products/__init__.py +246 -0
  479. parrot/tools/prophet_tool.py +171 -0
  480. parrot/tools/pythonpandas.py +630 -0
  481. parrot/tools/pythonrepl.py +910 -0
  482. parrot/tools/qsource.py +436 -0
  483. parrot/tools/querytoolkit.py +395 -0
  484. parrot/tools/quickeda.py +827 -0
  485. parrot/tools/resttool.py +553 -0
  486. parrot/tools/retail/__init__.py +0 -0
  487. parrot/tools/retail/bby.py +528 -0
  488. parrot/tools/sandboxtool.py +703 -0
  489. parrot/tools/sassie/__init__.py +352 -0
  490. parrot/tools/scraping/__init__.py +7 -0
  491. parrot/tools/scraping/docs/select.md +466 -0
  492. parrot/tools/scraping/documentation.md +1278 -0
  493. parrot/tools/scraping/driver.py +436 -0
  494. parrot/tools/scraping/models.py +576 -0
  495. parrot/tools/scraping/options.py +85 -0
  496. parrot/tools/scraping/orchestrator.py +517 -0
  497. parrot/tools/scraping/readme.md +740 -0
  498. parrot/tools/scraping/tool.py +3115 -0
  499. parrot/tools/seasonaldetection.py +642 -0
  500. parrot/tools/shell_tool/__init__.py +5 -0
  501. parrot/tools/shell_tool/actions.py +408 -0
  502. parrot/tools/shell_tool/engine.py +155 -0
  503. parrot/tools/shell_tool/models.py +322 -0
  504. parrot/tools/shell_tool/tool.py +442 -0
  505. parrot/tools/site_search.py +214 -0
  506. parrot/tools/textfile.py +418 -0
  507. parrot/tools/think.py +378 -0
  508. parrot/tools/toolkit.py +298 -0
  509. parrot/tools/webapp_tool.py +187 -0
  510. parrot/tools/whatif.py +1279 -0
  511. parrot/tools/workday/MULTI_WSDL_EXAMPLE.md +249 -0
  512. parrot/tools/workday/__init__.py +6 -0
  513. parrot/tools/workday/models.py +1389 -0
  514. parrot/tools/workday/tool.py +1293 -0
  515. parrot/tools/yfinance_tool.py +306 -0
  516. parrot/tools/zipcode.py +217 -0
  517. parrot/utils/__init__.py +2 -0
  518. parrot/utils/helpers.py +73 -0
  519. parrot/utils/parsers/__init__.py +5 -0
  520. parrot/utils/parsers/toml.c +12078 -0
  521. parrot/utils/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
  522. parrot/utils/parsers/toml.pyx +21 -0
  523. parrot/utils/toml.py +11 -0
  524. parrot/utils/types.cpp +20936 -0
  525. parrot/utils/types.cpython-310-x86_64-linux-gnu.so +0 -0
  526. parrot/utils/types.pyx +213 -0
  527. parrot/utils/uv.py +11 -0
  528. parrot/version.py +10 -0
  529. parrot/yaml-rs/Cargo.lock +350 -0
  530. parrot/yaml-rs/Cargo.toml +19 -0
  531. parrot/yaml-rs/pyproject.toml +19 -0
  532. parrot/yaml-rs/python/yaml_rs/__init__.py +81 -0
  533. parrot/yaml-rs/src/lib.rs +222 -0
  534. requirements/docker-compose.yml +24 -0
  535. requirements/requirements-dev.txt +21 -0
@@ -0,0 +1,397 @@
1
+ from typing import Any, Optional, Tuple, List, Dict, Union
2
+ import json
3
+ import pandas as pd
4
+ from .base import BaseRenderer
5
+ from . import register_renderer
6
+ from ...models.outputs import OutputMode
7
+
8
+ try:
9
+ from rich.table import Table as RichTable
10
+ from rich.console import Console
11
+ RICH_AVAILABLE = True
12
+ except ImportError:
13
+ RICH_AVAILABLE = False
14
+
15
+ try:
16
+ from ipywidgets import HTML as IPyHTML
17
+ IPYWIDGETS_AVAILABLE = True
18
+ except ImportError:
19
+ IPYWIDGETS_AVAILABLE = False
20
+
21
+
22
+ GRIDJS_SYSTEM_PROMPT = """
23
+ **GRID.JS CODE GENERATION MODE**
24
+
25
+ **Objective:** Generate a single, valid Grid.js Javascript code block.
26
+
27
+ **INSTRUCTIONS:**
28
+ 1. **Analyze Request:** Understand the user's goal for the table.
29
+ 2. **Generate Grid.js Code:** Create a complete Grid.js or ag-grid configuration.
30
+ 3. **Use Sample Data:** If the user asks for a type of table but doesn't provide data, generate appropriate sample data to illustrate the table's structure.
31
+ 4. **Output:** Return ONLY the Javascript code inside a ```javascript code block. Do not add explanations.
32
+
33
+ **BASIC STRUCTURE EXAMPLE:**
34
+
35
+ * If the user requests a gridjs table, respond with code similar to the following:
36
+ ```javascript
37
+ new gridjs.Grid({
38
+ columns: ["Name", "Email", "Phone Number"],
39
+ data: [
40
+ ["John", "john@example.com", "(353) 01 222 3333"],
41
+ ["Mark", "mark@gmail.com", "(01) 22 888 4444"],
42
+ ["Eoin", "eoin@gmail.com", "0097 22 654 00033"],
43
+ ["Sarah", "sarahcdd@gmail.com", "+322 876 1233"],
44
+ ["Afshin", "afshin@mail.com", "(353) 22 87 8356"]
45
+ ]
46
+ }).render(document.getElementById("wrapper"));
47
+ ```
48
+
49
+ * if the user requests a ag-grid table, respond with code similar to the following:
50
+ ```javascript
51
+ const columnDefs = [
52
+ { headerName: "Make", field: "make" },
53
+ { headerName: "Model", field: "model" },
54
+ { headerName: "Price", field: "price" }
55
+ ];
56
+ const rowData = [
57
+ { make: "Toyota", model: "Celica", price: 35000 },
58
+ { make: "Ford", model: "Mondeo", price: 32000 },
59
+ { make: "Porsche", model: "Boxster", price: 72000 }
60
+ ];
61
+ const gridOptions = {
62
+ columnDefs: columnDefs,
63
+ rowData: rowData
64
+ };
65
+ new agGrid.Grid(document.getElementById('myGrid'), gridOptions);
66
+ ```
67
+ """
68
+
69
+ @register_renderer(OutputMode.TABLE, system_prompt=GRIDJS_SYSTEM_PROMPT)
70
+ class TableRenderer(BaseRenderer):
71
+ """
72
+ Renderer for Tables supporting Rich (Terminal), HTML (Simple), Grid.js, and Ag-Grid.
73
+ """
74
+
75
+ def _extract_data(self, response: Any) -> pd.DataFrame:
76
+ """Extract data into a Pandas DataFrame."""
77
+ # 1. Handle PandasAgentResponse
78
+ output = getattr(response, 'output', None)
79
+
80
+ if output is not None:
81
+ if hasattr(output, 'to_dataframe'):
82
+ return output.to_dataframe()
83
+ if hasattr(output, 'data') and output.data is not None:
84
+ return pd.DataFrame(output.data)
85
+
86
+ # 2. Handle direct DataFrame
87
+ if isinstance(output, pd.DataFrame):
88
+ return output
89
+
90
+ # 3. Handle list of dicts
91
+ if isinstance(output, list):
92
+ return pd.DataFrame(output)
93
+
94
+ # 4. Handle dict (single record or dict of lists)
95
+ if isinstance(output, dict):
96
+ return pd.DataFrame(output) if all(isinstance(v, list) for v in output.values()) else pd.DataFrame([output])
97
+
98
+ # 5. Fallback: Check response.data attribute directly (AIMessage)
99
+ if hasattr(response, 'data') and response.data is not None:
100
+ if isinstance(response.data, pd.DataFrame):
101
+ return response.data
102
+ return pd.DataFrame(response.data)
103
+
104
+ return pd.DataFrame()
105
+
106
+ def _render_rich_table(self, df: pd.DataFrame, title: str) -> Any:
107
+ """Render a Rich Table object."""
108
+ if not RICH_AVAILABLE:
109
+ return df.to_string()
110
+
111
+ table = RichTable(title=title, show_header=True, header_style="bold magenta")
112
+
113
+ # Add columns
114
+ for column in df.columns:
115
+ table.add_column(str(column), overflow="fold")
116
+
117
+ # Add rows
118
+ for _, row in df.iterrows():
119
+ table.add_row(*[str(item) for item in row])
120
+
121
+ return table
122
+
123
+ def _render_simple_table(self, data: Any) -> str:
124
+ if isinstance(data, pd.DataFrame):
125
+ return data.to_html(index=False)
126
+ elif isinstance(data, list) and all(isinstance(i, dict) for i in data):
127
+ df = pd.DataFrame(data)
128
+ return df.to_html(index=False)
129
+ elif isinstance(data, str):
130
+ return data
131
+ else:
132
+ raise TypeError(f"Unsupported data type for simple table: {type(data)}")
133
+
134
+ def _generate_gridjs_code(self, df: pd.DataFrame, element_id: str = "wrapper") -> str:
135
+ """Generate Grid.js configuration and render code."""
136
+ columns = df.columns.tolist()
137
+ # Convert data to JSON-serializable list of lists
138
+ data = df.values.tolist()
139
+
140
+ # Serialize safely to avoid JS syntax errors
141
+ json_data = json.dumps(data)
142
+ json_columns = json.dumps(columns)
143
+
144
+ return f"""
145
+ new gridjs.Grid({{
146
+ columns: {json_columns},
147
+ data: {json_data},
148
+ search: true,
149
+ sort: true,
150
+ pagination: {{
151
+ limit: 10
152
+ }},
153
+ className: {{
154
+ table: 'table-body'
155
+ }}
156
+ }}).render(document.getElementById("{element_id}"));
157
+ """
158
+
159
+ def _generate_aggrid_code(self, df: pd.DataFrame, element_id: str = "wrapper") -> str:
160
+ """Generate Ag-Grid configuration and render code."""
161
+ # Define columns definition
162
+ column_defs = [
163
+ {"headerName": col, "field": col, "sortable": True, "filter": True} for col in df.columns
164
+ ]
165
+
166
+ # Data is list of dicts for Ag-Grid
167
+ row_data = df.to_dict(orient='records')
168
+
169
+ json_col_defs = json.dumps(column_defs)
170
+ json_row_data = json.dumps(row_data)
171
+
172
+ return f"""
173
+ const gridOptions = {{
174
+ columnDefs: {json_col_defs},
175
+ rowData: {json_row_data},
176
+ pagination: true,
177
+ paginationPageSize: 10,
178
+ defaultColDef: {{
179
+ flex: 1,
180
+ minWidth: 100,
181
+ resizable: true,
182
+ }}
183
+ }};
184
+ const gridDiv = document.getElementById("{element_id}");
185
+ agGrid.createGrid(gridDiv, gridOptions);
186
+ """
187
+
188
+ def _build_html_document(
189
+ self,
190
+ table_content: str,
191
+ table_mode: str,
192
+ title: str = "Table",
193
+ html_mode: str = "partial",
194
+ element_id: str = "wrapper",
195
+ script_nonce: Optional[str] = None,
196
+ style_nonce: Optional[str] = None,
197
+ content_security_policy: Optional[str] = None,
198
+ ) -> str:
199
+ """
200
+ Build the final HTML output (partial or complete).
201
+
202
+ Args:
203
+ table_content: The HTML table or JS code.
204
+ table_mode: 'simple', 'grid', or 'ag-grid'.
205
+ html_mode: 'partial' (embeddable) or 'complete' (standalone).
206
+ """
207
+ head_content = ""
208
+ partial_head_content = ""
209
+ body_content = ""
210
+ script_nonce_attr = f' nonce="{script_nonce}"' if script_nonce else ""
211
+ style_nonce_attr = f' nonce="{style_nonce}"' if style_nonce else ""
212
+
213
+ # 1. Configuration based on mode
214
+ if table_mode == 'grid':
215
+ # Grid.js CDNs
216
+ head_content = f"""
217
+ <link href="https://unpkg.com/gridjs/dist/theme/mermaid.min.css" rel="stylesheet" />
218
+ <script src="https://unpkg.com/gridjs/dist/gridjs.umd.js" defer></script>
219
+ """
220
+ partial_head_content = head_content
221
+ body_content = f"""
222
+ <div id="{element_id}"></div>
223
+ <script{script_nonce_attr}>
224
+ document.addEventListener('DOMContentLoaded', function () {{
225
+ {table_content}
226
+ }});
227
+ </script>
228
+ """
229
+
230
+ elif table_mode == 'ag-grid':
231
+ # Ag-Grid CDNs
232
+ head_content = """
233
+ <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js" defer></script>
234
+ """
235
+ partial_head_content = head_content
236
+ # Note: Ag-Grid requires a height on the container
237
+ body_content = f"""
238
+ <div id="{element_id}" class="ag-theme-alpine" style="height: 500px; width: 100%;"></div>
239
+ <script{script_nonce_attr}>
240
+ document.addEventListener('DOMContentLoaded', function () {{
241
+ if (window.agGrid && document.getElementById('{element_id}')) {{
242
+ {table_content}
243
+ }}
244
+ }});
245
+ </script>
246
+ """
247
+
248
+ else:
249
+ # simple
250
+ # Basic Bootstrap for simple tables
251
+ head_content = f"""
252
+ <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
253
+ <style{style_nonce_attr}>
254
+ .dataframe {{ width: 100%; }}
255
+ .dataframe td, .dataframe th {{ padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }}
256
+ </style>
257
+ """
258
+ partial_head_content = f"""
259
+ <style{style_nonce_attr}>
260
+ @import url('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css');
261
+ .dataframe {{ width: 100%; }}
262
+ .dataframe td, .dataframe th {{ padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }}
263
+ </style>
264
+ """
265
+ body_content = f'<div class="table-responsive">{table_content}</div>'
266
+
267
+ # Optional CSP meta for complete documents. This is useful when a nonce is provided
268
+ # so that inline scripts/styles still satisfy strict policies.
269
+ csp_meta_tag = ""
270
+ if html_mode == "complete":
271
+ if content_security_policy:
272
+ csp_meta_tag = f"<meta http-equiv=\"Content-Security-Policy\" content=\"{content_security_policy}\">"
273
+ elif script_nonce or style_nonce:
274
+ csp_parts = [
275
+ "default-src 'self' https://cdn.jsdelivr.net https://unpkg.com",
276
+ "img-src 'self' data: https://cdn.jsdelivr.net https://unpkg.com",
277
+ "font-src 'self' data: https://cdn.jsdelivr.net https://unpkg.com",
278
+ ]
279
+ script_src = ["'self'", "https://cdn.jsdelivr.net", "https://unpkg.com"]
280
+ style_src = ["'self'", "https://cdn.jsdelivr.net", "https://unpkg.com"]
281
+
282
+ if script_nonce:
283
+ script_src.append(f"'nonce-{script_nonce}'")
284
+ else:
285
+ script_src.append("'unsafe-inline'")
286
+
287
+ if style_nonce:
288
+ style_src.append(f"'nonce-{style_nonce}'")
289
+ else:
290
+ style_src.append("'unsafe-inline'")
291
+
292
+ csp_parts.append(f"script-src {' '.join(script_src)}")
293
+ csp_parts.append(f"style-src {' '.join(style_src)}")
294
+ csp_meta_tag = f"<meta http-equiv=\"Content-Security-Policy\" content=\"{' ; '.join(csp_parts)}\">"
295
+
296
+ # 2. Return Partial (Embeddable)
297
+ if html_mode == "partial":
298
+ return f"""
299
+ <div>
300
+ {partial_head_content}
301
+ {body_content}
302
+ </div>
303
+ """
304
+
305
+ # 3. Return Complete (Standalone)
306
+ return f"""<!DOCTYPE html>
307
+ <html lang="en">
308
+ <head>
309
+ <meta charset="UTF-8">
310
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
311
+ {csp_meta_tag}
312
+ <title>{title}</title>
313
+ {head_content}
314
+ </head>
315
+ <body>
316
+ <div class="container mt-4">
317
+ <h2>{title}</h2>
318
+ {body_content}
319
+ </div>
320
+ </body>
321
+ </html>"""
322
+
323
+ async def render(
324
+ self,
325
+ response: Any,
326
+ table_mode: str = 'simple', # simple, grid, ag-grid
327
+ title: str = 'Table',
328
+ environment: str = 'terminal',
329
+ html_mode: str = 'partial',
330
+ **kwargs,
331
+ ) -> Tuple[Any, Optional[Any]]:
332
+ """
333
+ Render table in the appropriate format.
334
+
335
+ Returns:
336
+ Tuple[Any, Optional[Any]]: (raw_data_df, rendered_output)
337
+ """
338
+ # 1. Extract Data
339
+ df = self._extract_data(response)
340
+
341
+ if df.empty:
342
+ return "No Data Available", None
343
+
344
+ data_content = df.to_dict(orient='records')
345
+
346
+ output_format = kwargs.get('output_format', environment)
347
+
348
+ # 2. Environment: Terminal -> Rich Table
349
+ if output_format == 'terminal':
350
+ rich_table = self._render_rich_table(df, title)
351
+ return data_content, rich_table
352
+
353
+ # 3. Prepare Content for HTML/JS
354
+ content = ""
355
+ if table_mode == 'simple':
356
+ # Convert to HTML Table
357
+ content = df.to_html(classes="table table-striped table-bordered", index=False)
358
+
359
+ elif table_mode == 'grid':
360
+ # Generate Grid.js Code
361
+ # Check if code was pre-generated by LLM (in response.code) - Future proofing
362
+ if hasattr(response, 'code') and isinstance(response.code, str) and "new gridjs.Grid" in response.code:
363
+ content = response.code
364
+ else:
365
+ content = self._generate_gridjs_code(df, "wrapper_grid")
366
+
367
+ elif table_mode == 'ag-grid':
368
+ # Generate Ag-Grid Code
369
+ if hasattr(response, 'code') and isinstance(response.code, str) and "new agGrid.Grid" in response.code:
370
+ content = response.code
371
+ else:
372
+ content = self._generate_aggrid_code(df, "wrapper_ag")
373
+
374
+ # 4. Build Wrapped HTML
375
+ wrapper_id = f"wrapper_{table_mode}" if table_mode != 'simple' else "wrapper"
376
+ script_nonce = kwargs.get('script_nonce')
377
+ style_nonce = kwargs.get('style_nonce')
378
+ content_security_policy = kwargs.get('content_security_policy')
379
+ wrapped_html = self._build_html_document(
380
+ content,
381
+ table_mode,
382
+ title=title,
383
+ html_mode=html_mode,
384
+ element_id=wrapper_id,
385
+ script_nonce=script_nonce,
386
+ style_nonce=style_nonce,
387
+ content_security_policy=content_security_policy,
388
+ )
389
+
390
+ # 5. Environment: Jupyter -> Widget
391
+ if output_format in {'jupyter', 'notebook', 'colab'}:
392
+ if IPYWIDGETS_AVAILABLE:
393
+ return df, IPyHTML(value=wrapped_html)
394
+ return df, wrapped_html
395
+
396
+ # 6. Environment: HTML (return string)
397
+ return data_content, wrapped_html
@@ -0,0 +1,138 @@
1
+ from typing import Any, Dict, Optional
2
+ from dataclasses import asdict
3
+ from ...models.outputs import OutputMode
4
+ from ...template.engine import TemplateEngine
5
+ from . import register_renderer
6
+ from .base import BaseRenderer
7
+
8
+
9
+ @register_renderer(OutputMode.TEMPLATE_REPORT)
10
+ class TemplateReportRenderer(BaseRenderer):
11
+ """
12
+ Renders AI output using Jinja2 templates via the TemplateEngine.
13
+
14
+ Supports both file-based templates and in-memory templates via add_template().
15
+ """
16
+
17
+ def __init__(self, template_engine: Optional[TemplateEngine] = None):
18
+ """
19
+ Initialize the TemplateReportRenderer.
20
+
21
+ Args:
22
+ template_engine: Optional TemplateEngine instance. If not provided,
23
+ one will be created on first use.
24
+ """
25
+ self._template_engine = template_engine
26
+
27
+ @property
28
+ def template_engine(self) -> TemplateEngine:
29
+ """
30
+ Lazy initialization of TemplateEngine if not provided.
31
+
32
+ Returns:
33
+ TemplateEngine instance
34
+ """
35
+ if self._template_engine is None:
36
+ # Initialize with no template directories (will use in-memory only)
37
+ self._template_engine = TemplateEngine()
38
+ return self._template_engine
39
+
40
+ def add_template(self, name: str, content: str) -> None:
41
+ """
42
+ Add an in-memory template to the engine.
43
+
44
+ Args:
45
+ name: Template name (e.g., 'report.html', 'summary.md')
46
+ content: Jinja2 template content
47
+
48
+ Example:
49
+ renderer.add_template('report.html', '<h1>{{ title }}</h1>')
50
+ """
51
+ self.template_engine.add_templates({name: content})
52
+
53
+ async def render(self, data: Any, **kwargs: Any) -> str:
54
+ """
55
+ Renders data using a Jinja2 template asynchronously.
56
+
57
+ Args:
58
+ data: The data to render. Can be:
59
+ - dict: passed directly to template
60
+ - Pydantic model: converted via model_dump()
61
+ - dataclass: converted via asdict()
62
+ - any object with attributes: accessible in template
63
+ **kwargs: Additional arguments:
64
+ - template: (required) Template name to use
65
+ - template_engine: (optional) Override the default engine
66
+ - Additional kwargs are passed to the template context
67
+
68
+ Returns:
69
+ Rendered template content as string
70
+
71
+ Raises:
72
+ ValueError: If template is not provided or not found
73
+
74
+ Example:
75
+ result = await renderer.render(
76
+ {"title": "Report", "items": [1, 2, 3]},
77
+ template="report.html"
78
+ )
79
+ """
80
+ # Get template name
81
+ template_name: str = kwargs.pop("template", None)
82
+ if not template_name:
83
+ raise ValueError(
84
+ "Template name must be provided via 'template' kwarg. "
85
+ "Example: renderer.render(data, template='report.html')"
86
+ )
87
+
88
+ # Allow overriding the template engine
89
+ engine = kwargs.pop("template_engine", None) or self.template_engine
90
+
91
+ # Prepare the template context
92
+ context = self._prepare_template_context(data, kwargs)
93
+
94
+ # Render the template
95
+ try:
96
+ return await engine.render(template_name, context)
97
+ except FileNotFoundError as e:
98
+ raise ValueError(
99
+ f"Template '{template_name}' not found. "
100
+ f"Use add_template() to add in-memory templates or "
101
+ f"ensure the template exists in the template directories."
102
+ ) from e
103
+ except Exception as e:
104
+ raise RuntimeError(
105
+ f"Failed to render template '{template_name}': {e}"
106
+ ) from e
107
+
108
+ def _prepare_template_context(
109
+ self, data: Any, extra_kwargs: Dict[str, Any]
110
+ ) -> Dict[str, Any]:
111
+ """
112
+ Prepare the context dictionary for template rendering.
113
+
114
+ Args:
115
+ data: The main data to render
116
+ extra_kwargs: Additional kwargs to include in context
117
+
118
+ Returns:
119
+ Dictionary to pass to template
120
+ """
121
+ # Start with extra kwargs
122
+ context = dict(extra_kwargs)
123
+
124
+ # Handle different data types
125
+ if isinstance(data, dict):
126
+ # Merge dict data with kwargs (data takes precedence)
127
+ context |= data
128
+ elif hasattr(data, 'model_dump'):
129
+ # Pydantic model
130
+ context |= data.model_dump()
131
+ elif hasattr(data, '__dataclass_fields__'):
132
+ # Dataclass
133
+ context |= asdict(data)
134
+ else:
135
+ # Primitive or unknown type - wrap as 'data'
136
+ context['data'] = data
137
+
138
+ return context
@@ -0,0 +1,125 @@
1
+ from typing import Any, Tuple
2
+ import json
3
+ from dataclasses import is_dataclass, asdict
4
+ from pydantic import BaseModel
5
+ try:
6
+ import yaml_rs # pylint: disable=E0401 # noqa
7
+ YAML_RS_AVAILABLE = True
8
+ except ImportError:
9
+ YAML_RS_AVAILABLE = False
10
+ import pandas as pd
11
+ from datamodel.parsers.json import json_encoder # pylint: disable=E0611 # noqa
12
+ from . import register_renderer
13
+ from .base import BaseRenderer
14
+ from ...models.outputs import OutputMode
15
+
16
+
17
+ @register_renderer(OutputMode.YAML)
18
+ class YAMLRenderer(BaseRenderer):
19
+ """Renderer for YAML output using yaml-rs (Rust) or PyYAML fallback"""
20
+
21
+ def _json_as_yaml(self, data: Any, indent: int = 2) -> str:
22
+ """
23
+ Fallback: Format JSON as YAML-like structure.
24
+ Useful when yaml_rs is missing or fails on specific types.
25
+ """
26
+ try:
27
+ # First ensure it's serializable via json_encoder logic
28
+ if not isinstance(data, str):
29
+ data = json.loads(json_encoder(data))
30
+
31
+ import yaml
32
+ return yaml.dump(data, indent=indent, sort_keys=False, default_flow_style=False)
33
+ except ImportError:
34
+ # Manual JSON-to-YAML-ish conversion if PyYAML is also missing
35
+ json_str = json.dumps(data, indent=indent, sort_keys=False)
36
+ yaml_like = json_str.replace('{', '').replace('}', '')
37
+ yaml_like = yaml_like.replace('[', '').replace(']', '')
38
+ yaml_like = yaml_like.replace('",', '"')
39
+ return yaml_like.replace('"', '')
40
+
41
+ def _serialize(self, data: Any, indent: int = 2, sort_keys: bool = False) -> str:
42
+ """Serialize data to YAML string."""
43
+ try:
44
+ if isinstance(data, pd.DataFrame):
45
+ data = data.to_dict(orient='records')
46
+ elif is_dataclass(data):
47
+ data = asdict(data)
48
+ elif isinstance(data, BaseModel):
49
+ data = data.model_dump()
50
+ if not YAML_RS_AVAILABLE:
51
+ return self._json_as_yaml(data, indent)
52
+ try:
53
+ return yaml_rs.dumps(data, indent=indent, sort_keys=sort_keys)
54
+ except Exception:
55
+ # Fallback to python implementation on error
56
+ return self._json_as_yaml(data, indent)
57
+ except Exception as e:
58
+ print('DATA > ', data)
59
+ return f"error_serializing_to_yaml: {str(e)}"
60
+
61
+ def _wrap_output(self, yaml_string: str, environment: str) -> Any:
62
+ """
63
+ Wrap the YAML string into an environment-specific container.
64
+ """
65
+ # --- Terminal (Rich) ---
66
+ if environment == 'terminal':
67
+ try:
68
+ from rich.panel import Panel as RichPanel
69
+ from rich.syntax import Syntax
70
+
71
+ syntax = Syntax(yaml_string, "yaml", theme="monokai", line_numbers=True)
72
+ return RichPanel(syntax, title="YAML Output", border_style="green")
73
+ except ImportError:
74
+ return yaml_string
75
+
76
+ # --- Jupyter / Notebook ---
77
+ elif environment in {'jupyter', 'notebook'}:
78
+ try:
79
+ from ipywidgets import HTML
80
+ from pygments import highlight
81
+ from pygments.lexers import YamlLexer
82
+ from pygments.formatters import HtmlFormatter
83
+
84
+ formatter = HtmlFormatter(style='colorful', noclasses=True)
85
+ highlighted_html = highlight(yaml_string, YamlLexer(), formatter)
86
+
87
+ return HTML(
88
+ value=f'<div style="max-height: 500px; overflow-y: auto; background-color: #f8f8f8; padding: 10px;">{highlighted_html}</div>'
89
+ )
90
+ except ImportError:
91
+ return self._wrap_html(yaml_string)
92
+
93
+ # --- HTML ---
94
+ elif environment == 'html':
95
+ return self._wrap_html(yaml_string)
96
+
97
+ # Default
98
+ return yaml_string
99
+
100
+ async def render(
101
+ self,
102
+ response: Any,
103
+ environment: str = 'default',
104
+ **kwargs,
105
+ ) -> Tuple[str, Any]:
106
+ """
107
+ Render response as YAML.
108
+
109
+ Returns:
110
+ Tuple[str, Any]: (yaml_string, wrapped_content)
111
+ """
112
+ indent = kwargs.get('indent', 2)
113
+ sort_keys = kwargs.get('sort_keys', False)
114
+ output_format = kwargs.get('output_format', environment)
115
+
116
+ # 1. Extract Data
117
+ data = self._extract_data(response)
118
+
119
+ # 2. Serialize to content string
120
+ yaml_string = self._serialize(data, indent=indent, sort_keys=sort_keys)
121
+
122
+ # 3. Wrap content based on environment
123
+ wrapped_output = self._wrap_output(yaml_string, output_format)
124
+
125
+ return yaml_string, wrapped_output