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,146 @@
1
+ from typing import List
2
+ from pydantic import BaseModel, Field
3
+ from datetime import date
4
+ from parrot.tools.querytoolkit import QueryToolkit
5
+ from parrot.tools.decorators import tool_schema
6
+
7
+
8
+ class PriceInput(BaseModel):
9
+ tenant: str = Field(..., description="Program or tenant identifier (e.g. hisense, epson, etc).")
10
+ model: str = Field(..., description="Model number of the product to query the price for.")
11
+ week: int = Field(..., description="Week number for which to retrieve the price.")
12
+ output_format: str = Field("structured", description="Output format: 'string' or 'structured'.")
13
+
14
+
15
+ class ModelPriceInput(BaseModel):
16
+ tenant: str = Field(..., description="Program or tenant identifier (e.g. hisense, epson, etc).")
17
+ model: str = Field(..., description="Model number of the product to query the price for.")
18
+ output_format: str = Field(default="pandas", description="Output format: 'string' or 'structured'.")
19
+ limit: int = Field(10, description="Number of records to retrieve.")
20
+
21
+
22
+ class WeeklyPriceInput(BaseModel):
23
+ tenant: str = Field(..., description="Program or tenant identifier (e.g. hisense, epson, etc).")
24
+ week: int = Field(..., description="Week number for which to retrieve the price.")
25
+ output_format: str = Field(default="pandas", description="Output format: 'string' or 'structured'.")
26
+ limit: int = Field(10, description="Number of records to retrieve.")
27
+
28
+ class TotalPriceInput(BaseModel):
29
+ tenant: str = Field(..., description="Program or tenant identifier (e.g. hisense, epson, etc).")
30
+ start_date: str = Field(..., description="Start date for the price query (YYYY-MM-DD).")
31
+ end_date: str = Field(..., description="End date for the price query (YYYY-MM-DD).")
32
+ output_format: str = Field(default="pandas", description="Output format: 'string' or 'structured'.")
33
+ limit: int = Field(50, description="Number of records to retrieve.")
34
+
35
+
36
+ class PriceOutput(BaseModel):
37
+ product_id: str = Field(..., description="Unique identifier for the product.")
38
+ price: float = Field(..., description="Price of the product.")
39
+ week: int = Field(..., description="Week number for which the price is applicable.")
40
+ start_date: date = Field(..., description="Start date of the pricing period.")
41
+ end_date: date = Field(..., description="End date of the pricing period.")
42
+
43
+
44
+
45
+ class PricesTool(QueryToolkit):
46
+ """Tool for querying product prices from a database or API."""
47
+
48
+ name = "prices_tool"
49
+ description = "A tool to query product prices."
50
+
51
+
52
+ @tool_schema(PriceInput, description="The price information as a string.")
53
+ async def get_model_price(
54
+ self,
55
+ tenant: str,
56
+ model: str,
57
+ week: int,
58
+ output_format: str = "structured",
59
+ ) -> PriceOutput:
60
+ """Fetches the price of a product for a given tenant, model, and week.
61
+
62
+ Args:
63
+ tenant (str): The program or tenant identifier.
64
+ model (str): The model number of the product.
65
+ week (int): The week number for which to retrieve the price.
66
+ """
67
+ sql = await self._get_query("get_pricing")
68
+ sql = sql.format(
69
+ tenant=tenant,
70
+ model=model,
71
+ week=week
72
+ )
73
+ try:
74
+ return await self._get_dataset(
75
+ sql,
76
+ output_format=output_format,
77
+ structured_obj=PriceOutput if output_format == "structured" else None
78
+ )
79
+ except ValueError as ve:
80
+ return f"No Pricing data found for the specified tenant and product, error: {ve}"
81
+ except Exception as e:
82
+ return f"Error fetching pricing data: {e}"
83
+
84
+ @tool_schema(WeeklyPriceInput, description="The price information as a string.")
85
+ async def get_weekly_price(
86
+ self,
87
+ tenant: str,
88
+ week: int,
89
+ limit: int = 10,
90
+ output_format: str = "structured",
91
+ ) -> List[PriceOutput]:
92
+ """Fetches all product prices for a given tenant and week.
93
+
94
+ Args:
95
+ tenant (str): The program or tenant identifier.
96
+ week (int): The week number for which to retrieve the price.
97
+ """
98
+ sql = await self._get_query("get_weekly_pricing")
99
+ sql = sql.format(
100
+ tenant=tenant,
101
+ week=week,
102
+ limit=limit
103
+ )
104
+ try:
105
+ return await self._get_dataset(
106
+ sql,
107
+ output_format=output_format,
108
+ structured_obj=PriceOutput if output_format == "structured" else None
109
+ )
110
+ except ValueError as ve:
111
+ return f"No Pricing data found for the specified tenant and product, error: {ve}"
112
+ except Exception as e:
113
+ return f"Error fetching pricing data: {e}"
114
+
115
+ @tool_schema(TotalPriceInput, description="The price information as a string.")
116
+ async def get_price(
117
+ self,
118
+ tenant: str,
119
+ start_date: str,
120
+ end_date: str,
121
+ limit: int = 10,
122
+ output_format: str = "structured",
123
+ ) -> List[PriceOutput]:
124
+ """Fetches all product prices for a given tenant and date range.
125
+
126
+ Args:
127
+ tenant (str): The program or tenant identifier.
128
+ week (int): The week number for which to retrieve the price.
129
+ """
130
+ sql = await self._get_query("get_total_pricing")
131
+ sql = sql.format(
132
+ tenant=tenant,
133
+ start_date=start_date,
134
+ end_date=end_date,
135
+ limit=limit
136
+ )
137
+ try:
138
+ return await self._get_dataset(
139
+ sql,
140
+ output_format=output_format,
141
+ structured_obj=PriceOutput if output_format == "structured" else None
142
+ )
143
+ except ValueError as ve:
144
+ return f"No Pricing data found for the specified tenant and product, error: {ve}"
145
+ except Exception as e:
146
+ return f"Error fetching pricing data: {e}"
@@ -0,0 +1,246 @@
1
+ from typing import Optional, Dict, Union, List, Any
2
+ from datetime import datetime
3
+ import json
4
+ from pydantic import BaseModel, Field, field_validator, ConfigDict
5
+ from navconfig import BASE_DIR
6
+ from asyncdb import AsyncDB
7
+ from asyncdb.models import Model, Field as ModelField
8
+ from querysource.conf import default_dsn
9
+ from ..abstract import AbstractTool
10
+
11
+
12
+
13
+ class ProductInput(BaseModel):
14
+ """Input schema for product information requests."""
15
+ model: str = Field(
16
+ ..., description="The product model identifier (e.g., 'X1234', 'Y5678')."
17
+ )
18
+ program_slug: str = Field(
19
+ ..., description="The program slug associated with the product (e.g., 'alpha', 'beta')."
20
+ )
21
+
22
+
23
+ class ProductInfo(BaseModel):
24
+ """Schema for the product information returned by the query."""
25
+ name: str
26
+ model: str
27
+ description: str
28
+ picture_url: str
29
+ brand: str
30
+ # pricing: Decimal
31
+ pricing: str
32
+ customer_satisfaction: Optional[str] = None
33
+ product_evaluation: Optional[str] = None
34
+ product_compliant: Optional[str] = None
35
+ # specifications: Dict[str, Union[dict, list]] = Field(
36
+ # default_factory=dict,
37
+ # description="Specifications of the product, can be a dict or list."
38
+ # )
39
+ specifications: Dict[str, Union[str, int, float, bool, list, dict]] = Field(
40
+ default_factory=dict,
41
+ description="Specifications of the product as a dictionary."
42
+ )
43
+ review_average: float
44
+ reviews: int
45
+
46
+ @field_validator('specifications', mode='before')
47
+ @classmethod
48
+ def parse_specifications(cls, v):
49
+ if v is None or v == '':
50
+ return {}
51
+ if isinstance(v, dict):
52
+ return v
53
+ if isinstance(v, (bytes, bytearray)):
54
+ v = v.decode('utf-8', errors='ignore')
55
+ if isinstance(v, str):
56
+ try:
57
+ parsed = json.loads(v)
58
+ except json.JSONDecodeError as e:
59
+ raise ValueError("Specifications field is not a valid JSON string.") from e
60
+ if not isinstance(parsed, dict):
61
+ raise TypeError("Specifications JSON must decode to a dictionary.")
62
+ return parsed
63
+ raise TypeError("specifications must be a dict or a JSON string.")
64
+
65
+ # Add a model_config to prevent additional properties
66
+ model_config = ConfigDict(
67
+ arbitrary_types_allowed=False,
68
+ extra="forbid",
69
+ )
70
+
71
+ class ProductInfoTool(AbstractTool):
72
+ """Tool to get detailed information about a specific product model."""
73
+ name = "get_product_information"
74
+ description = (
75
+ "Use this tool to get detailed information about a specific product model. "
76
+ "Provide the exact model identifier as input."
77
+ )
78
+ args_schema = ProductInput
79
+
80
+ async def _execute(self, model: str, program_slug: str) -> ProductInfo:
81
+ db = AsyncDB('pg', dsn=default_dsn)
82
+
83
+ # Use static_dir if configured, otherwise fall back to BASE_DIR
84
+ base_path = self.static_dir if hasattr(self, 'static_dir') and self.static_dir else BASE_DIR
85
+
86
+ # Try multiple paths for backward compatibility
87
+ # 1. Direct path (for when static_dir points to programs/ or taskstore/programs/)
88
+ query_file = base_path / program_slug / 'sql' / 'products.sql'
89
+
90
+ # 2. Try with 'programs/' prefix (for when static_dir points to base directory)
91
+ if not query_file.exists():
92
+ query_file = base_path / 'programs' / program_slug / 'sql' / 'products.sql'
93
+
94
+ # 3. Fallback to old structure: agents/product_report/{program_slug}/products.sql
95
+ if not query_file.exists():
96
+ query_file = base_path / 'agents' / 'product_report' / program_slug / 'products.sql'
97
+
98
+ if not query_file.exists():
99
+ raise FileNotFoundError(
100
+ f"Query file not found for program_slug '{program_slug}'. Tried:\n"
101
+ f" - {base_path / program_slug / 'sql' / 'products.sql'}\n"
102
+ f" - {base_path / 'programs' / program_slug / 'sql' / 'products.sql'}\n"
103
+ f" - {base_path / 'agents' / 'product_report' / program_slug / 'products.sql'}"
104
+ )
105
+
106
+ query = query_file.read_text()
107
+ async with await db.connection() as conn: # noqa
108
+ product_data, error = await conn.query(query, model)
109
+ if error:
110
+ raise RuntimeError(f"Database query failed: {error}")
111
+ if not product_data:
112
+ raise ValueError(f"No product found with model '{model}' in program '{program_slug}'.")
113
+
114
+ return ProductInfo(**product_data[0])
115
+
116
+
117
+ class ProductListInput(BaseModel):
118
+ """Input schema for product list requests."""
119
+ program_slug: str = Field(
120
+ ..., description="The program slug to get products from (e.g., 'google', 'hisense')."
121
+ )
122
+ models: Optional[List[str]] = Field(
123
+ default=None, description="Optional list of specific models to get. If None, gets all models."
124
+ )
125
+
126
+
127
+ class ProductListTool(AbstractTool):
128
+ """Tool to get list of products for a given program/tenant."""
129
+ name = "get_products_list"
130
+ description = (
131
+ "Use this tool to get a list of products for a given program/tenant. "
132
+ "Provide the program slug as input. Optionally provide a list of specific models."
133
+ )
134
+ args_schema = ProductListInput
135
+
136
+ async def _execute(self, program_slug: str, models: Optional[List[str]] = None) -> List[Dict[str, str]]:
137
+ """Get list of products for a program."""
138
+ db = AsyncDB('pg', dsn=default_dsn)
139
+
140
+ # Use static_dir if configured, otherwise fall back to BASE_DIR
141
+ base_path = self.static_dir if hasattr(self, 'static_dir') and self.static_dir else BASE_DIR
142
+
143
+ # Determine which SQL file to use
144
+ file_type = 'product_single.sql' if models else 'products_list.sql'
145
+
146
+ # Try multiple paths for backward compatibility
147
+ # 1. Direct path (for when static_dir points to programs/ or taskstore/programs/)
148
+ query_file = base_path / program_slug / 'sql' / file_type
149
+
150
+ # 2. Try with 'programs/' prefix (for when static_dir points to base directory)
151
+ if not query_file.exists():
152
+ query_file = base_path / 'programs' / program_slug / 'sql' / file_type
153
+
154
+ # 3. Fallback to old structure: agents/product_report/{program_slug}/<file>
155
+ if not query_file.exists():
156
+ query_file = base_path / 'agents' / 'product_report' / program_slug / file_type
157
+
158
+ if not query_file.exists():
159
+ raise FileNotFoundError(
160
+ f"Products query file not found for program_slug '{program_slug}'. Tried:\n"
161
+ f" - {base_path / program_slug / 'sql' / file_type}\n"
162
+ f" - {base_path / 'programs' / program_slug / 'sql' / file_type}\n"
163
+ f" - {base_path / 'agents' / 'product_report' / program_slug / file_type}"
164
+ )
165
+
166
+ query = query_file.read_text()
167
+ async with await db.connection() as conn: # noqa
168
+ if models:
169
+ # Execute with models parameter
170
+ products, error = await conn.query(query, models)
171
+ else:
172
+ # Execute without parameters
173
+ products, error = await conn.query(query)
174
+
175
+ if error:
176
+ raise RuntimeError(f"Database query failed: {error}")
177
+ if not products:
178
+ return []
179
+
180
+ return products
181
+
182
+
183
+ class ProductResponse(Model):
184
+ """
185
+ ProductResponse is a model that defines the structure of the response for Product agents.
186
+ """
187
+ model: Optional[str] = ModelField(
188
+ default=None,
189
+ description="Model of the product"
190
+ )
191
+ program_slug: Optional[str] = ModelField(
192
+ default=None,
193
+ description="Program/tenant identifier"
194
+ )
195
+ agent_id: Optional[str] = ModelField(
196
+ default=None,
197
+ description="Unique identifier for the agent that processed the request"
198
+ )
199
+ agent_name: Optional[str] = ModelField(
200
+ default="ProductReport",
201
+ description="Name of the agent that processed the request"
202
+ )
203
+ status: str = ModelField(default="success", description="Status of the response")
204
+ data: Optional[str] = ModelField(
205
+ default=None,
206
+ description="Data returned by the agent, can be text, JSON, etc."
207
+ )
208
+ # Optional output field for structured data
209
+ output: Optional[Any] = ModelField(
210
+ default=None,
211
+ description="Output of the agent's processing"
212
+ )
213
+ attributes: Dict[str, str] = ModelField(
214
+ default_factory=dict,
215
+ description="Attributes associated with the response"
216
+ )
217
+ # Timestamp
218
+ created_at: datetime = ModelField(
219
+ default_factory=datetime.now, description="Timestamp when response was created"
220
+ )
221
+ # Optional file paths
222
+ transcript: Optional[str] = ModelField(
223
+ default=None, description="Transcript of the conversation with the agent"
224
+ )
225
+ script_path: Optional[str] = ModelField(
226
+ default=None, description="Path to the conversational script associated with the session"
227
+ )
228
+ podcast_path: Optional[str] = ModelField(
229
+ default=None, description="Path to the podcast associated with the session"
230
+ )
231
+ pdf_path: Optional[str] = ModelField(
232
+ default=None, description="Path to the PDF associated with the session"
233
+ )
234
+ document_path: Optional[str] = ModelField(
235
+ default=None, description="Path to any document generated during session"
236
+ )
237
+ # complete list of generated files:
238
+ files: List[str] = ModelField(
239
+ default_factory=list, description="List of documents generated during the session")
240
+
241
+ class Meta:
242
+ """Meta class for ProductResponse."""
243
+ name = "products_informations"
244
+ schema = "product_report"
245
+ strict = True
246
+ frozen = False
@@ -0,0 +1,171 @@
1
+ """
2
+ ProphetForecastTool for time series forecasting using Facebook Prophet.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import asyncio
8
+ from datetime import datetime
9
+ from pathlib import Path
10
+ from typing import Any, Dict, Optional
11
+
12
+ import pandas as pd
13
+ from pydantic import Field, field_validator
14
+ from prophet import Prophet
15
+
16
+ from .abstract import AbstractTool, AbstractToolArgsSchema, ToolResult
17
+
18
+
19
+ class ProphetForecastArgs(AbstractToolArgsSchema):
20
+ """Arguments for :class:`ProphetForecastTool`."""
21
+
22
+ dataframe: str = Field(
23
+ ..., description="Name or alias of the DataFrame containing the time series"
24
+ )
25
+ ds_column: str = Field(
26
+ ..., description="Column with datestamp values (will be converted to datetime)"
27
+ )
28
+ y_column: str = Field(
29
+ ..., description="Numeric column to forecast"
30
+ )
31
+ periods: int = Field(
32
+ 365,
33
+ description="Number of future periods to forecast",
34
+ ge=1,
35
+ )
36
+ freq: str = Field(
37
+ "D",
38
+ description="Pandas frequency string for future periods (e.g., 'D', 'W', 'M')",
39
+ min_length=1,
40
+ )
41
+ include_history: bool = Field(
42
+ default=True,
43
+ description="Whether to include the historical dates in the forecast output",
44
+ )
45
+
46
+ @field_validator("periods")
47
+ @classmethod
48
+ def validate_periods(cls, value: int) -> int:
49
+ if value < 1:
50
+ raise ValueError("periods must be a positive integer")
51
+ return value
52
+
53
+
54
+ class ProphetForecastTool(AbstractTool):
55
+ """Generate time series forecasts with Facebook Prophet and return plots."""
56
+
57
+ name = "prophet_forecast"
58
+ description = (
59
+ "Fit a Facebook Prophet model on a DataFrame and generate future forecasts "
60
+ "with corresponding forecast plot image."
61
+ )
62
+ args_schema = ProphetForecastArgs
63
+
64
+ def __init__(
65
+ self,
66
+ dataframes: Optional[Dict[str, pd.DataFrame]] = None,
67
+ alias_map: Optional[Dict[str, str]] = None,
68
+ **kwargs: Any,
69
+ ) -> None:
70
+ super().__init__(**kwargs)
71
+ self.dataframes: Dict[str, pd.DataFrame] = dataframes or {}
72
+ self.alias_map: Dict[str, str] = alias_map or {}
73
+
74
+ def _default_output_dir(self) -> Path:
75
+ return self.static_dir / "reports" / "prophet_forecast"
76
+
77
+ def update_context(
78
+ self, dataframes: Dict[str, pd.DataFrame], alias_map: Optional[Dict[str, str]] = None
79
+ ) -> None:
80
+ """Update internal references to available DataFrames and aliases."""
81
+
82
+ self.dataframes = dataframes
83
+ if alias_map is not None:
84
+ self.alias_map = alias_map
85
+
86
+ async def _execute(self, **kwargs: Any) -> ToolResult:
87
+ args = self.args_schema(**kwargs)
88
+ loop = asyncio.get_running_loop()
89
+ return await loop.run_in_executor(None, self._run_forecast, args)
90
+
91
+ def _run_forecast(self, args: ProphetForecastArgs) -> ToolResult:
92
+ dataframe = self._resolve_dataframe(args.dataframe)
93
+ cleaned_df = self._prepare_dataframe(dataframe, args)
94
+
95
+ model = Prophet()
96
+ model.fit(cleaned_df)
97
+
98
+ future = model.make_future_dataframe(
99
+ periods=args.periods, freq=args.freq, include_history=args.include_history
100
+ )
101
+ forecast = model.predict(future)
102
+
103
+ plot_path = self._save_forecast_plot(model, forecast, args.dataframe)
104
+
105
+ return ToolResult(
106
+ status="success",
107
+ result={
108
+ "forecast": forecast.to_dict(orient="records"),
109
+ "forecast_columns": list(forecast.columns),
110
+ "future_dataframe": future.to_dict(orient="records"),
111
+ "figure_path": str(plot_path),
112
+ "figure_url": self.to_static_url(plot_path),
113
+ },
114
+ metadata={
115
+ "dataframe": args.dataframe,
116
+ "ds_column": args.ds_column,
117
+ "y_column": args.y_column,
118
+ "periods": args.periods,
119
+ "freq": args.freq,
120
+ },
121
+ )
122
+
123
+ def _resolve_dataframe(self, name: str) -> pd.DataFrame:
124
+ if name in self.dataframes:
125
+ return self.dataframes[name]
126
+
127
+ # Accept alias names (df1, df2, etc.)
128
+ for df_name, alias in self.alias_map.items():
129
+ if name == alias and df_name in self.dataframes:
130
+ return self.dataframes[df_name]
131
+
132
+ raise ValueError(
133
+ f"DataFrame '{name}' not found. Available: {list(self.dataframes.keys())}"
134
+ )
135
+
136
+ def _prepare_dataframe(
137
+ self, dataframe: pd.DataFrame, args: ProphetForecastArgs
138
+ ) -> pd.DataFrame:
139
+ if args.ds_column not in dataframe.columns:
140
+ raise ValueError(
141
+ f"Date column '{args.ds_column}' not found. Columns: {list(dataframe.columns)}"
142
+ )
143
+ if args.y_column not in dataframe.columns:
144
+ raise ValueError(
145
+ f"Target column '{args.y_column}' not found. Columns: {list(dataframe.columns)}"
146
+ )
147
+
148
+ df = dataframe.copy()
149
+ df[args.ds_column] = pd.to_datetime(df[args.ds_column], errors="coerce")
150
+ df[args.y_column] = pd.to_numeric(df[args.y_column], errors="coerce")
151
+
152
+ df = df.dropna(subset=[args.ds_column, args.y_column])
153
+ if df.empty:
154
+ raise ValueError("No valid rows available after cleaning for Prophet forecast")
155
+
156
+ df = df[[args.ds_column, args.y_column]].rename(
157
+ columns={args.ds_column: "ds", args.y_column: "y"}
158
+ )
159
+ return df
160
+
161
+ def _save_forecast_plot(
162
+ self, model: Prophet, forecast: pd.DataFrame, dataframe_name: str
163
+ ) -> Path:
164
+ plot_dir = self.output_dir
165
+ plot_dir.mkdir(parents=True, exist_ok=True)
166
+
167
+ fig = model.plot(forecast)
168
+ filename = f"prophet_forecast_{dataframe_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
169
+ file_path = plot_dir / filename
170
+ fig.savefig(file_path, bbox_inches="tight")
171
+ return file_path