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,351 @@
1
+ from typing import Any, List, Dict, Optional, Tuple, Type, TYPE_CHECKING
2
+ from abc import ABC, abstractmethod
3
+ import contextlib
4
+ from datetime import datetime
5
+ from dataclasses import is_dataclass, asdict
6
+ import pandas as pd
7
+ import numpy as np
8
+ from pydantic import BaseModel
9
+ import orjson
10
+ from datamodel.parsers.json import json_encoder # pylint: disable=E0611 # noqa
11
+ from pygments import highlight
12
+ from pygments.lexers.data import JsonLexer
13
+ from pygments.formatters.html import HtmlFormatter
14
+ if TYPE_CHECKING:
15
+ from ...tools.pythonpandas import PythonPandasTool
16
+
17
+
18
+ class BaseRenderer(ABC):
19
+ """Base class for output renderers."""
20
+
21
+ @classmethod
22
+ def get_expected_content_type(cls) -> Type:
23
+ """
24
+ Define what type of content this renderer expects.
25
+ Override in subclasses to specify expected type.
26
+
27
+ Returns:
28
+ Type: The expected type (str, pd.DataFrame, dict, etc.)
29
+ """
30
+ return str
31
+
32
+ @classmethod
33
+ def _get_content(cls, response: Any) -> Any:
34
+ """
35
+ Extract content from response based on expected type.
36
+
37
+ Args:
38
+ response: AIMessage response object
39
+
40
+ Returns:
41
+ Content in the expected type
42
+ """
43
+ expected_type = cls.get_expected_content_type()
44
+
45
+ # First, try to get the output attribute (structured data)
46
+ if hasattr(response, 'output') and response.output is not None:
47
+ output = response.output
48
+
49
+ # If output matches expected type, return it
50
+ if isinstance(output, expected_type):
51
+ return output
52
+
53
+ # Special handling for DataFrames
54
+ if expected_type == pd.DataFrame:
55
+ if isinstance(output, pd.DataFrame):
56
+ return output
57
+ # Try to convert dict/list to DataFrame
58
+ elif isinstance(output, (dict, list)):
59
+ with contextlib.suppress(Exception):
60
+ return pd.DataFrame(output)
61
+
62
+ # Fallback to string extraction for code-based renderers
63
+ if expected_type == str:
64
+ # If response has 'response' attribute (string content)
65
+ if hasattr(response, 'response') and response.response:
66
+ return response.response
67
+
68
+ # Try content attribute
69
+ if hasattr(response, 'content'):
70
+ return response.content
71
+
72
+ # Try to_text property
73
+ if hasattr(response, 'to_text'):
74
+ return response.to_text
75
+
76
+ # Try output as string
77
+ if hasattr(response, 'output'):
78
+ output = response.output
79
+ return output if isinstance(output, str) else str(output)
80
+
81
+ # Last resort: string conversion
82
+ return str(response)
83
+
84
+ def execute_code(
85
+ self,
86
+ code: str,
87
+ pandas_tool: "PythonPandasTool | None" = None,
88
+ execution_state: Optional[Dict[str, Any]] = None,
89
+ extra_namespace: Optional[Dict[str, Any]] = None,
90
+ **kwargs,
91
+ ) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
92
+ """Execute code within the PythonPandasTool or fallback namespace."""
93
+ if tool := pandas_tool:
94
+ try:
95
+ tool.execute_sync(code, debug=kwargs.get('debug', False))
96
+ return tool.locals, None
97
+ except Exception as exc:
98
+ return None, f"Execution error: {exc}"
99
+
100
+ namespace: Dict[str, Any] = {'pd': pd, 'np': np}
101
+ if extra_namespace:
102
+ namespace |= extra_namespace
103
+
104
+ locals_dict: Dict[str, Any] = {}
105
+ if execution_state:
106
+ namespace.update(execution_state.get('dataframes', {}))
107
+ namespace.update(execution_state.get('execution_results', {}))
108
+ namespace.update(execution_state.get('variables', {}))
109
+ globals_state = execution_state.get('globals') or {}
110
+ if isinstance(globals_state, dict):
111
+ namespace.update(globals_state)
112
+ locals_state = execution_state.get('locals') or {}
113
+ if isinstance(locals_state, dict):
114
+ locals_dict = locals_state.copy()
115
+
116
+ try:
117
+ exec(code, namespace, locals_dict)
118
+ combined: Dict[str, Any] = {}
119
+ combined |= namespace
120
+ combined.update(locals_dict)
121
+ return combined, None
122
+ except Exception as exc:
123
+ return None, f"Execution error: {exc}"
124
+
125
+ @staticmethod
126
+ def _create_tools_list(tool_calls: List[Any]) -> List[Dict[str, str]]:
127
+ """Create a list for tool calls."""
128
+ calls = []
129
+ for idx, tool in enumerate(tool_calls, 1):
130
+ name = getattr(tool, 'name', 'Unknown')
131
+ status = getattr(tool, 'status', 'completed')
132
+ calls.append({
133
+ "No.": str(idx),
134
+ "Tool Name": name,
135
+ "Status": status
136
+ })
137
+ return calls
138
+
139
+ @staticmethod
140
+ def _create_sources_list(sources: List[Any]) -> List[Dict[str, str]]:
141
+ """Create a list for source documents."""
142
+ sources = []
143
+ for idx, source in enumerate(sources, 1):
144
+ # Handle both SourceDocument objects and dict-like sources
145
+ if hasattr(source, 'source'):
146
+ source_name = source.source
147
+ elif isinstance(source, dict):
148
+ source_name = source.get('source', 'Unknown')
149
+ else:
150
+ source_name = str(source)
151
+ if hasattr(source, 'score'):
152
+ score = source.score
153
+ elif isinstance(source, dict):
154
+ score = source.get('score', 'N/A')
155
+ else:
156
+ score = 'N/A'
157
+ sources.append({
158
+ "No.": str(idx),
159
+ "Source": source_name,
160
+ "Score": score,
161
+ })
162
+ return sources
163
+
164
+ @staticmethod
165
+ def _serialize_any(obj: Any) -> Any:
166
+ """Serialize any Python object to a compatible format"""
167
+ # Pydantic BaseModel
168
+ if hasattr(obj, 'model_dump'):
169
+ return obj.model_dump()
170
+
171
+ # Dataclass
172
+ if hasattr(obj, '__dataclass_fields__'):
173
+ return asdict(obj)
174
+
175
+ # Dict-like
176
+ if hasattr(obj, 'items'):
177
+ return dict(obj)
178
+
179
+ # List-like
180
+ if hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes)):
181
+ return list(obj)
182
+
183
+ # Primitives
184
+ if isinstance(obj, (str, int, float, bool, type(None))):
185
+ return obj
186
+
187
+ # Fallback to string representation
188
+ return str(obj)
189
+
190
+ @staticmethod
191
+ def _clean_data(data: dict) -> dict:
192
+ """Clean data for Serialization (remove non-serializable types)"""
193
+ cleaned = {}
194
+ for key, value in data.items():
195
+ # Skip None values
196
+ if value is None:
197
+ continue
198
+
199
+ # Handle datetime objects
200
+ if hasattr(value, 'isoformat'):
201
+ cleaned[key] = value.isoformat()
202
+ # Handle Path objects
203
+ elif hasattr(value, '__fspath__'):
204
+ cleaned[key] = str(value)
205
+ # Handle nested dicts
206
+ elif isinstance(value, dict):
207
+ cleaned[key] = BaseRenderer._clean_data(value)
208
+ # Handle lists
209
+ elif isinstance(value, list):
210
+ cleaned[key] = [
211
+ BaseRenderer._clean_data(item) if isinstance(item, dict) else item
212
+ for item in value
213
+ ]
214
+ # Primitives
215
+ else:
216
+ cleaned[key] = value
217
+
218
+ return cleaned
219
+
220
+ @staticmethod
221
+ def _prepare_data(response: Any, include_metadata: bool = False) -> dict:
222
+ """
223
+ Prepare response data for serialization.
224
+
225
+ Args:
226
+ response: AIMessage or any object
227
+ include_metadata: Whether to include full metadata
228
+
229
+ Returns:
230
+ Dictionary ready for YAML serialization
231
+ """
232
+ if not hasattr(response, 'model_dump'):
233
+ # Handle other types
234
+ return BaseRenderer._serialize_any(response)
235
+ # If it's an AIMessage, extract relevant data
236
+ data = response.model_dump(
237
+ exclude_none=True,
238
+ exclude_unset=True
239
+ )
240
+
241
+ if not include_metadata:
242
+ # Return simplified version
243
+ result = {
244
+ 'input': data.get('input'),
245
+ 'output': data.get('output'),
246
+ }
247
+
248
+ # Add essential metadata
249
+ if data.get('model'):
250
+ result['model'] = data['model']
251
+ if data.get('provider'):
252
+ result['provider'] = data['provider']
253
+ if data.get('usage'):
254
+ result['usage'] = data['usage']
255
+
256
+ return result
257
+
258
+ # Full metadata mode
259
+ return BaseRenderer._clean_data(data)
260
+
261
+ def _default_serializer(self, obj: Any) -> Any:
262
+ """Custom serializer for non-JSON-serializable objects."""
263
+ if isinstance(obj, (datetime, pd.Timestamp)):
264
+ return obj.isoformat()
265
+ if isinstance(obj, pd.DataFrame):
266
+ return obj.to_dict(orient='records')
267
+ if isinstance(obj, set):
268
+ return list(obj)
269
+ raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
270
+
271
+ def _extract_data(self, response: Any) -> Any:
272
+ """
273
+ Extract serializable data based on response content type rules.
274
+ """
275
+ # 1. Check for PandasAgentResponse (duck typing to avoid circular imports)
276
+ # We check for specific attributes that define a PandasAgentResponse
277
+ output = getattr(response, 'output', None)
278
+
279
+ if output is not None:
280
+ # Handle PandasAgentResponse specifically
281
+ if hasattr(output, 'to_dataframe') and hasattr(output, 'explanation') and hasattr(output, 'data'):
282
+ # response.data is usually a PandasTable
283
+ return output.to_dataframe() if output.data is not None else []
284
+
285
+ # 2. Handle direct DataFrame output
286
+ if isinstance(output, pd.DataFrame):
287
+ return output.to_dict(orient='records')
288
+
289
+ # 3. Handle Pydantic Models
290
+ if isinstance(output, BaseModel):
291
+ return output.model_dump()
292
+
293
+ # 4. Handle Dataclasses
294
+ if is_dataclass(output):
295
+ return asdict(output)
296
+
297
+ # 5. Fallback for unstructured/plain text responses
298
+ # "if there is no 'structured output response', build a JSON with input/output"
299
+ is_structured = getattr(response, 'is_structured', False)
300
+ if not is_structured and output:
301
+ return {
302
+ "input": getattr(response, 'input', ''),
303
+ "output": output,
304
+ "metadata": getattr(response, 'metadata', {})
305
+ }
306
+
307
+ return output
308
+
309
+ def _serialize(self, data: Any, indent: Optional[int] = None) -> str:
310
+ """Serialize data to JSON string using orjson if available."""
311
+ try:
312
+ option = orjson.OPT_INDENT_2 if indent is not None else 0 # pylint: disable=E1101
313
+ # orjson returns bytes, decode to str
314
+ return orjson.dumps( # pylint: disable=E1101
315
+ data,
316
+ default=self._default_serializer,
317
+ option=option
318
+ ).decode('utf-8')
319
+ except Exception:
320
+ return json_encoder(
321
+ data
322
+ )
323
+
324
+ def _wrap_html(self, content: str) -> str:
325
+ """Helper to wrap JSON in HTML with highlighting."""
326
+ try:
327
+ formatter = HtmlFormatter(style='default', full=False, noclasses=True)
328
+ highlighted_code = highlight(content, JsonLexer(), formatter)
329
+ return f'<div class="json-response" style="padding:1em; border:1px solid #ddd; border-radius:4px;">{highlighted_code}</div>'
330
+ except ImportError:
331
+ return f'<pre><code class="language-json">{content}</code></pre>'
332
+
333
+
334
+ @abstractmethod
335
+ async def render(
336
+ self,
337
+ response: Any,
338
+ environment: str = 'terminal',
339
+ export_format: str = 'html',
340
+ include_code: bool = False,
341
+ **kwargs,
342
+ ) -> Tuple[Any, Optional[Any]]:
343
+ """
344
+ Render response in the appropriate format.
345
+
346
+ Returns:
347
+ Tuple[Any, Optional[Any]]: (content, wrapped)
348
+ - content: Primary formatted output
349
+ - wrapped: Optional wrapped version (e.g., HTML, standalone file)
350
+ """
351
+ pass
@@ -0,0 +1,356 @@
1
+ # ai_parrot/outputs/formats/charts/bokeh.py
2
+ from typing import Any, Optional, Tuple, Dict, List
3
+ import uuid
4
+ import json
5
+ from .chart import BaseChart
6
+ from . import register_renderer
7
+ from ...models.outputs import OutputMode
8
+
9
+
10
+ BOKEH_SYSTEM_PROMPT = """BOKEH CHART OUTPUT MODE:
11
+ Generate an interactive chart using Bokeh.
12
+
13
+ REQUIREMENTS:
14
+ 1. Return Python code in a markdown code block (```python)
15
+ 2. Use bokeh.plotting or bokeh.models
16
+ 3. Store the plot in a variable named 'p' (recommended), 'plot', 'fig', or 'chart'
17
+ 4. Make the chart self-contained with inline data
18
+ 5. Use appropriate glyph types (circle, line, vbar, hbar, etc.)
19
+ 6. Add titles, axis labels, and legends
20
+ 7. Configure plot dimensions and tools
21
+ 8. DO NOT call show() or save() - return code only
22
+ 9. IMPORTANT: Use 'p' as the variable name for best compatibility
23
+
24
+ EXAMPLE:
25
+ ```python
26
+ from bokeh.plotting import figure
27
+ from bokeh.models import HoverTool
28
+
29
+ x = ['A', 'B', 'C', 'D']
30
+ y = [23, 45, 12, 67]
31
+
32
+ p = figure(
33
+ x_range=x,
34
+ title="Sales by Category",
35
+ width=800,
36
+ height=400,
37
+ toolbar_location="above"
38
+ )
39
+
40
+ p.vbar(x=x, top=y, width=0.8, color='navy', alpha=0.8)
41
+
42
+ p.xaxis.axis_label = "Category"
43
+ p.yaxis.axis_label = "Sales"
44
+
45
+ hover = HoverTool(tooltips=[("Category", "@x"), ("Sales", "@top")])
46
+ p.add_tools(hover)
47
+ ```
48
+ """
49
+
50
+
51
+ @register_renderer(OutputMode.BOKEH, system_prompt=BOKEH_SYSTEM_PROMPT)
52
+ class BokehRenderer(BaseChart):
53
+ """Renderer for Bokeh charts"""
54
+
55
+ def execute_code(
56
+ self,
57
+ code: str,
58
+ pandas_tool: Any = None,
59
+ execution_state: Optional[Dict[str, Any]] = None,
60
+ **kwargs,
61
+ ) -> Tuple[Any, Optional[str]]:
62
+ """Execute Bokeh code using the shared Python execution context."""
63
+ extra_namespace = None
64
+ if pandas_tool is None:
65
+ from bokeh.plotting import figure as bokeh_figure
66
+ from bokeh import models, plotting
67
+ extra_namespace = {
68
+ 'figure': bokeh_figure,
69
+ 'models': models,
70
+ 'plotting': plotting,
71
+ }
72
+
73
+ # Execute using BaseRenderer logic
74
+ context, error = super().execute_code(
75
+ code,
76
+ pandas_tool=pandas_tool,
77
+ execution_state=execution_state,
78
+ extra_namespace=extra_namespace,
79
+ **kwargs,
80
+ )
81
+
82
+ if error:
83
+ return None, error
84
+
85
+ if not context:
86
+ return None, "Execution context was empty"
87
+
88
+ # Find all chart objects
89
+ if charts := self._find_chart_objects(context):
90
+ return charts, None
91
+
92
+ return None, "Code must define a plot variable (p, plot, fig, or chart)"
93
+
94
+ @staticmethod
95
+ def _find_chart_objects(context: Dict[str, Any]) -> List[Any]:
96
+ """Locate all Bokeh plot objects in the local namespace."""
97
+ from bokeh.embed import json_item
98
+
99
+ charts: List[Any] = []
100
+ seen_ids = set()
101
+
102
+ def is_bokeh_plot(obj: Any) -> bool:
103
+ """Check if object is a Bokeh plot/figure."""
104
+ if obj is None:
105
+ return False
106
+
107
+ # Skip renderer / BaseChart instances
108
+ if isinstance(obj, BaseChart):
109
+ return False
110
+
111
+ # Check for Bokeh plot attributes
112
+ bokeh_attrs = ['renderers', 'toolbar', 'xaxis', 'yaxis']
113
+ has_attrs = all(hasattr(obj, attr) for attr in bokeh_attrs)
114
+
115
+ if has_attrs:
116
+ return True
117
+
118
+ # Check by class name
119
+ class_name = obj.__class__.__name__
120
+ bokeh_classes = ['Figure', 'Plot', 'GridPlot']
121
+ if any(bc in class_name for bc in bokeh_classes):
122
+ return True
123
+
124
+ # Check module
125
+ module = getattr(obj.__class__, '__module__', '')
126
+ return 'bokeh' in module
127
+
128
+ def is_serializable(obj: Any) -> bool:
129
+ """Check if the Bokeh object can actually be serialized."""
130
+ try:
131
+ json_item(obj)
132
+ return True
133
+ except Exception:
134
+ return False
135
+
136
+ def add_chart(obj: Any) -> None:
137
+ if is_bokeh_plot(obj) and id(obj) not in seen_ids:
138
+ # Only add if it can actually be serialized
139
+ if is_serializable(obj):
140
+ charts.append(obj)
141
+ seen_ids.add(id(obj))
142
+ else:
143
+ # Debug: log filtered objects (optional)
144
+ # print(f"Filtered non-serializable Bokeh object: {type(obj).__name__}")
145
+ pass
146
+
147
+ # 1. Priority search for common variable names to preserve order
148
+ priority_vars = ['p', 'plot', 'fig', 'figure', 'chart']
149
+ for var_name in priority_vars:
150
+ if var_name in context:
151
+ add_chart(context[var_name])
152
+
153
+ # 2. Scan all locals for other chart objects
154
+ for var_name, obj in context.items():
155
+ if var_name.startswith('_') or var_name in priority_vars:
156
+ continue
157
+ add_chart(obj)
158
+
159
+ return charts
160
+
161
+ def _render_chart_content(self, chart_objs: Any, **kwargs) -> str:
162
+ """
163
+ Render Bokeh-specific chart content (HTML/JS).
164
+ Handles a single chart or a list of charts.
165
+ """
166
+ from bokeh.embed import json_item
167
+
168
+ # Ensure we have a list
169
+ charts = chart_objs if isinstance(chart_objs, list) else [chart_objs]
170
+
171
+ html_parts = []
172
+
173
+ for i, chart_obj in enumerate(charts):
174
+ print('CHART > ', chart_obj, type(chart_obj))
175
+ chart_id = f"bokeh-chart-{uuid.uuid4().hex[:8]}"
176
+
177
+ try:
178
+ # Get Bokeh JSON item
179
+ item = json_item(chart_obj)
180
+ item_json = json.dumps(item)
181
+ except Exception as e:
182
+ chart_html = f'''
183
+ <div class="bokeh-chart-wrapper" style="margin-bottom: 20px;">
184
+ <div class="error-container">
185
+ <h3>⚠️ Bokeh Serialization Error</h3>
186
+ <p>{str(e)}</p>
187
+ </div>
188
+ </div>
189
+ '''
190
+ html_parts.append(chart_html)
191
+ continue
192
+
193
+ chart_html = f'''
194
+ <div class="bokeh-chart-wrapper" style="margin-bottom: 20px;">
195
+ <div id="{chart_id}" style="width: 100%;"></div>
196
+ <script type="text/javascript">
197
+ (function() {{
198
+ var item = {item_json};
199
+
200
+ if (typeof Bokeh === 'undefined') {{
201
+ console.error("Bokeh library not loaded");
202
+ document.getElementById('{chart_id}').innerHTML = "Error: Bokeh library not loaded.";
203
+ return;
204
+ }}
205
+
206
+ try {{
207
+ Bokeh.embed.embed_item(item, "{chart_id}");
208
+ console.log('Bokeh chart {chart_id} rendered successfully');
209
+ }} catch (error) {{
210
+ console.error('Error rendering Bokeh chart:', error);
211
+ document.getElementById('{chart_id}').innerHTML =
212
+ '<div style="color:red; padding:10px;">⚠️ Chart Rendering Error: ' + error.message + '</div>';
213
+ }}
214
+ }})();
215
+ </script>
216
+ </div>
217
+ '''
218
+ html_parts.append(chart_html)
219
+
220
+ return "\n".join(html_parts)
221
+
222
+ def to_html(
223
+ self,
224
+ chart_obj: Any,
225
+ mode: str = 'partial',
226
+ **kwargs
227
+ ) -> str:
228
+ """
229
+ Convert Bokeh chart(s) to HTML.
230
+
231
+ Args:
232
+ chart_obj: Bokeh plot object or list of plot objects
233
+ mode: 'partial' or 'complete'
234
+ **kwargs: Additional parameters
235
+
236
+ Returns:
237
+ HTML string
238
+ """
239
+ # Bokeh libraries for <head>
240
+ try:
241
+ from bokeh import __version__ as bokeh_version
242
+ except:
243
+ bokeh_version = "3.3.0" # fallback version
244
+
245
+ extra_head = f'''
246
+ <!-- Bokeh -->
247
+ <script src="https://cdn.bokeh.org/bokeh/release/bokeh-{bokeh_version}.min.js"></script>
248
+ <script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-{bokeh_version}.min.js"></script>
249
+ <script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-{bokeh_version}.min.js"></script>
250
+ '''
251
+
252
+ kwargs['extra_head'] = kwargs.get('extra_head', extra_head)
253
+
254
+ # Call parent to_html (which calls _render_chart_content)
255
+ return super().to_html(chart_obj, mode=mode, **kwargs)
256
+
257
+ def to_json(self, chart_obj: Any) -> Optional[Any]:
258
+ """Export Bokeh JSON specification (returns list if multiple)."""
259
+ from bokeh.embed import json_item
260
+
261
+ charts = chart_obj if isinstance(chart_obj, list) else [chart_obj]
262
+ results = []
263
+
264
+ for chart in charts:
265
+ try:
266
+ item = json_item(chart)
267
+ results.append(json.loads(json.dumps(item)))
268
+ except Exception as e:
269
+ results.append({'error': str(e)})
270
+
271
+ return results if len(results) > 1 else results[0] if results else None
272
+
273
+ async def render(
274
+ self,
275
+ response: Any,
276
+ theme: str = 'monokai',
277
+ environment: str = 'html',
278
+ include_code: bool = False,
279
+ html_mode: str = 'partial',
280
+ **kwargs
281
+ ) -> Tuple[Any, Optional[Any]]:
282
+ """Render Bokeh chart(s)."""
283
+
284
+ # 1. Extract Code
285
+ code = getattr(response, 'code', None)
286
+ output_format = kwargs.get('output_format', environment)
287
+
288
+ # Fallback to extracting from text content
289
+ if not code:
290
+ content = self._get_content(response)
291
+ code = self._extract_code(content)
292
+
293
+ if not code:
294
+ error_msg = "No chart code found in response"
295
+ if output_format == 'terminal':
296
+ return error_msg, None
297
+ return self._wrap_for_environment(
298
+ f"<div class='error'>{error_msg}</div>",
299
+ output_format
300
+ ), None
301
+
302
+ # 2. Execute Code
303
+ chart_objs, error = self.execute_code(
304
+ code,
305
+ pandas_tool=kwargs.pop('pandas_tool', None),
306
+ execution_state=kwargs.pop('execution_state', None),
307
+ **kwargs,
308
+ )
309
+
310
+ if error:
311
+ if output_format == 'terminal':
312
+ return f"Error generating chart: {error}", None
313
+ return self._wrap_for_environment(
314
+ self._render_error(error, code, theme),
315
+ output_format
316
+ ), None
317
+
318
+ # 3. Handle Jupyter/Notebook Environment
319
+ if output_format in {'jupyter', 'notebook', 'ipython', 'colab'}:
320
+ from bokeh.embed import components
321
+
322
+ charts = chart_objs if isinstance(chart_objs, list) else [chart_objs]
323
+
324
+ if len(charts) == 1:
325
+ # Single chart
326
+ script, div = components(charts[0])
327
+ return code, f"{script}{div}"
328
+ else:
329
+ # Multiple charts
330
+ script, divs = components(charts)
331
+ combined = script + "".join(divs)
332
+ return code, combined
333
+
334
+ # 4. Generate HTML for Web/Terminal
335
+ html_output = self.to_html(
336
+ chart_objs,
337
+ mode=html_mode,
338
+ include_code=include_code,
339
+ code=code,
340
+ theme=theme,
341
+ title=kwargs.get('title', 'Bokeh Chart'),
342
+ icon='📊',
343
+ **kwargs
344
+ )
345
+
346
+ # 5. Return based on output format
347
+ if output_format == 'html':
348
+ return code, html_output
349
+ elif output_format == 'json':
350
+ return code, self.to_json(chart_objs)
351
+ elif output_format == 'terminal':
352
+ # For terminal, return the code and HTML
353
+ return code, html_output
354
+
355
+ # Default behavior: Return code as content, HTML as wrapped
356
+ return code, html_output