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,501 @@
1
+ from typing import Literal, Optional, Dict, Any, List, Union
2
+ from pathlib import Path
3
+ from io import BytesIO, StringIO
4
+ import logging
5
+ from pydantic import Field
6
+ from ..abstract import AbstractTool, AbstractToolArgsSchema, ToolResult
7
+ from .abstract import FileManagerInterface
8
+ from .local import LocalFileManager
9
+ from .tmp import TempFileManager
10
+ from .s3 import S3FileManager
11
+ from .gcs import GCSFileManager
12
+
13
+
14
+ class FileManagerFactory:
15
+ """Factory for creating file managers"""
16
+
17
+ @staticmethod
18
+ def create(
19
+ manager_type: Literal["fs", "temp", "s3", "gcs"],
20
+ **kwargs
21
+ ) -> FileManagerInterface:
22
+ """Create a file manager instance"""
23
+ managers = {
24
+ "fs": LocalFileManager,
25
+ "temp": TempFileManager,
26
+ "s3": S3FileManager,
27
+ "gcs": GCSFileManager,
28
+ }
29
+
30
+ if manager_type not in managers:
31
+ raise ValueError(
32
+ f"Unknown manager type: {manager_type}. "
33
+ f"Available: {list(managers.keys())}"
34
+ )
35
+
36
+ return managers[manager_type](**kwargs)
37
+
38
+
39
+ class FileManagerToolArgs(AbstractToolArgsSchema):
40
+ """
41
+ Arguments schema for FileManagerTool.
42
+
43
+ The operation field determines which file operation to perform.
44
+ Each operation requires different additional fields.
45
+ """
46
+
47
+ operation: Literal[
48
+ "list", "upload", "download", "copy", "delete",
49
+ "exists", "get_url", "get_metadata", "create"
50
+ ] = Field(
51
+ ...,
52
+ description=(
53
+ "The file operation to perform. Options:\n"
54
+ "- 'list': List files in a directory\n"
55
+ "- 'upload': Upload a file to storage\n"
56
+ "- 'download': Download a file from storage\n"
57
+ "- 'copy': Copy a file within storage\n"
58
+ "- 'delete': Delete a file from storage\n"
59
+ "- 'exists': Check if a file exists\n"
60
+ "- 'get_url': Get a URL to access a file\n"
61
+ "- 'get_metadata': Get detailed file metadata\n"
62
+ "- 'create': Create a new file with content"
63
+ )
64
+ )
65
+
66
+ # Common fields
67
+ path: Optional[Union[str, Path]] = Field(
68
+ None,
69
+ description="File or directory path. Used by most operations."
70
+ )
71
+
72
+ # List operation
73
+ pattern: Optional[str] = Field(
74
+ "*",
75
+ description="Filename pattern for list operation (e.g., '*.txt', '*.pdf')"
76
+ )
77
+
78
+ # Upload operation
79
+ source_path: Optional[str] = Field(
80
+ None,
81
+ description="Source file path for upload operation"
82
+ )
83
+ destination: Optional[str] = Field(
84
+ None,
85
+ description="Destination path or directory"
86
+ )
87
+ destination_name: Optional[str] = Field(
88
+ None,
89
+ description="Custom name for uploaded file (uses source name if not provided)"
90
+ )
91
+
92
+ # Copy operation
93
+ source: Optional[str] = Field(
94
+ None,
95
+ description="Source file path for copy operation"
96
+ )
97
+
98
+ # Create operation
99
+ content: Optional[str] = Field(
100
+ None,
101
+ description="Text content for create operation"
102
+ )
103
+ encoding: Optional[str] = Field(
104
+ "utf-8",
105
+ description="Text encoding for create operation"
106
+ )
107
+
108
+ # URL operation
109
+ expiry_seconds: Optional[int] = Field(
110
+ 3600,
111
+ description="URL expiry time in seconds (default: 3600 = 1 hour)"
112
+ )
113
+
114
+
115
+ class FileManagerTool(AbstractTool):
116
+ """
117
+ Tool for AI agents to interact with file systems.
118
+
119
+ Provides secure file operations across different storage backends:
120
+ - 'fs': Local filesystem
121
+ - 'temp': Temporary storage (auto-cleanup)
122
+ - 's3': AWS S3 buckets
123
+ - 'gcs': Google Cloud Storage
124
+
125
+ Usage Pattern:
126
+ The LLM must specify an 'operation' field to route to the correct action.
127
+ Each operation has specific required and optional fields.
128
+
129
+ Examples:
130
+ List files: {"operation": "list", "path": "documents", "pattern": "*.pdf"}
131
+ Upload: {"operation": "upload", "source_path": "/tmp/file.txt", "destination": "uploads"}
132
+ Download: {"operation": "download", "path": "reports/summary.pdf", "destination": "/tmp/summary.pdf"}
133
+ Get URL: {"operation": "get_url", "path": "shared/file.zip", "expiry_seconds": 7200}
134
+ Create: {"operation": "create", "path": "output.txt", "content": "Hello, World!"}
135
+ """
136
+
137
+ name: str = "file_manager"
138
+ description: str = "Manage files across different storage backends (local, S3, GCS, temp)"
139
+ args_schema: type[AbstractToolArgsSchema] = FileManagerToolArgs
140
+
141
+ def __init__(
142
+ self,
143
+ manager_type: Literal["fs", "temp", "s3", "gcs"] = "fs",
144
+ default_output_dir: str = "./outputs",
145
+ allowed_operations: Optional[set] = None,
146
+ max_file_size: int = 100 * 1024 * 1024, # 100MB
147
+ auto_create_dirs: bool = True,
148
+ **manager_kwargs
149
+ ):
150
+ """
151
+ Initialize file manager tool.
152
+
153
+ Args:
154
+ manager_type: Type of file manager ("fs", "temp", "s3", "gcs")
155
+ default_output_dir: Default directory for file operations
156
+ allowed_operations: Set of allowed operations (None = all allowed)
157
+ max_file_size: Maximum file size in bytes
158
+ auto_create_dirs: Automatically create directories
159
+ **manager_kwargs: Additional arguments for the specific manager
160
+ """
161
+ super().__init__()
162
+
163
+ self.manager_type = manager_type
164
+ self.default_output_dir = default_output_dir
165
+ self.max_file_size = max_file_size
166
+ self.auto_create_dirs = auto_create_dirs
167
+ self.logger = logging.getLogger('ai_parrot.tools.FileManager')
168
+
169
+ # Default to all operations if not specified
170
+ self.allowed_operations = allowed_operations or {
171
+ "list", "upload", "download", "copy", "delete",
172
+ "exists", "get_url", "get_metadata", "create"
173
+ }
174
+
175
+ # Create the appropriate file manager
176
+ self.manager = self._create_manager(manager_type, **manager_kwargs)
177
+
178
+ # Update description with specific manager type
179
+ self.description = (
180
+ f"Manage files in {manager_type} storage. "
181
+ f"Default output directory: {default_output_dir}. "
182
+ f"Allowed operations: {', '.join(sorted(self.allowed_operations))}. "
183
+ f"Max file size: {max_file_size / (1024*1024):.1f}MB"
184
+ )
185
+
186
+ self.logger.info(
187
+ f"FileManagerTool initialized with {manager_type} manager, "
188
+ f"output dir: {default_output_dir}"
189
+ )
190
+
191
+ def _create_manager(
192
+ self,
193
+ manager_type: str,
194
+ **kwargs
195
+ ) -> FileManagerInterface:
196
+ """Create file manager with type-specific defaults"""
197
+ if manager_type == "fs":
198
+ return FileManagerFactory.create(
199
+ manager_type,
200
+ base_path=kwargs.get('base_path', Path.cwd()),
201
+ sandboxed=kwargs.get('sandboxed', True),
202
+ **{k: v for k, v in kwargs.items() if k not in ['base_path', 'sandboxed']}
203
+ )
204
+ elif manager_type == "temp":
205
+ return FileManagerFactory.create(
206
+ manager_type,
207
+ cleanup_on_exit=kwargs.get('cleanup_on_exit', True),
208
+ **{k: v for k, v in kwargs.items() if k != 'cleanup_on_exit'}
209
+ )
210
+ else: # s3 or gcs
211
+ return FileManagerFactory.create(manager_type, **kwargs)
212
+
213
+ def _check_operation(self, operation: str):
214
+ """Check if operation is allowed"""
215
+ if operation not in self.allowed_operations:
216
+ raise PermissionError(
217
+ f"Operation '{operation}' not allowed. "
218
+ f"Allowed: {self.allowed_operations}"
219
+ )
220
+
221
+ def _check_file_size(self, size: int):
222
+ """Check if file size is within limits"""
223
+ if size > self.max_file_size:
224
+ raise ValueError(
225
+ f"File size ({size} bytes) exceeds maximum "
226
+ f"allowed size ({self.max_file_size} bytes)"
227
+ )
228
+
229
+ def _resolve_output_path(self, path: Optional[str] = None) -> str:
230
+ """Resolve path relative to default output directory"""
231
+ if path is None:
232
+ return self.default_output_dir
233
+
234
+ if Path(path).is_absolute() or path.startswith(self.default_output_dir):
235
+ return path
236
+
237
+ return str(Path(self.default_output_dir) / path)
238
+
239
+ async def _execute(self, **kwargs) -> ToolResult:
240
+ """
241
+ Execute file operation based on the operation field.
242
+
243
+ This is the main router method that dispatches to specific operations.
244
+ The LLM must provide an 'operation' field to determine which action to perform.
245
+
246
+ Args:
247
+ **kwargs: Arguments matching FileManagerToolArgs schema
248
+
249
+ Returns:
250
+ ToolResult with operation results
251
+ """
252
+ # Validate and extract operation
253
+ args = FileManagerToolArgs(**kwargs)
254
+ operation = args.operation
255
+
256
+ self.logger.info(f"Executing operation: {operation}")
257
+
258
+ # Check if operation is allowed
259
+ self._check_operation(operation)
260
+
261
+ try:
262
+ # Route to appropriate operation
263
+ if operation == "list":
264
+ result = await self._list_files(args)
265
+ elif operation == "upload":
266
+ result = await self._upload_file(args)
267
+ elif operation == "download":
268
+ result = await self._download_file(args)
269
+ elif operation == "copy":
270
+ result = await self._copy_file(args)
271
+ elif operation == "delete":
272
+ result = await self._delete_file(args)
273
+ elif operation == "exists":
274
+ result = await self._exists(args)
275
+ elif operation == "get_url":
276
+ result = await self._get_file_url(args)
277
+ elif operation == "get_metadata":
278
+ result = await self._get_file_metadata(args)
279
+ elif operation == "create":
280
+ result = await self._create_file(args)
281
+ else:
282
+ return ToolResult(
283
+ success=False,
284
+ result=None,
285
+ error=f"Unknown operation: {operation}"
286
+ )
287
+
288
+ return ToolResult(
289
+ success=True,
290
+ result=result,
291
+ metadata={
292
+ "operation": operation,
293
+ "manager_type": self.manager_type
294
+ }
295
+ )
296
+
297
+ except Exception as e:
298
+ self.logger.error(f"Operation {operation} failed: {str(e)}", exc_info=True)
299
+ return ToolResult(
300
+ success=False,
301
+ error=str(e),
302
+ metadata={
303
+ "operation": operation,
304
+ "manager_type": self.manager_type
305
+ }
306
+ )
307
+
308
+ async def _list_files(self, args: FileManagerToolArgs) -> Dict[str, Any]:
309
+ """List files in a directory"""
310
+ path = self._resolve_output_path(args.path) if args.path else ""
311
+ pattern = args.pattern or "*"
312
+
313
+ self.logger.info(f"Listing files in '{path}' with pattern '{pattern}'")
314
+
315
+ files = await self.manager.list_files(path, pattern)
316
+
317
+ return {
318
+ "files": [
319
+ {
320
+ "name": f.name,
321
+ "path": f.path,
322
+ "size": f.size,
323
+ "content_type": f.content_type,
324
+ "modified_at": f.modified_at.isoformat() if f.modified_at else None,
325
+ "url": f.url
326
+ }
327
+ for f in files
328
+ ],
329
+ "count": len(files),
330
+ "directory": path,
331
+ "pattern": pattern
332
+ }
333
+
334
+ async def _upload_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
335
+ """Upload a file to storage"""
336
+ if not args.source_path:
337
+ raise ValueError("source_path is required for upload operation")
338
+
339
+ source = Path(args.source_path)
340
+
341
+ if not source.exists():
342
+ raise FileNotFoundError(f"Source file not found: {args.source_path}")
343
+
344
+ # Check file size
345
+ file_size = source.stat().st_size
346
+ self._check_file_size(file_size)
347
+
348
+ # Determine destination
349
+ dest = args.destination_name or source.name
350
+
351
+ if args.destination:
352
+ dest = str(Path(args.destination) / dest)
353
+
354
+ dest = self._resolve_output_path(dest)
355
+
356
+ self.logger.info(f"Uploading '{args.source_path}' to '{dest}'")
357
+
358
+ metadata = await self.manager.upload_file(source, dest)
359
+
360
+ return {
361
+ "uploaded": True,
362
+ "name": metadata.name,
363
+ "path": metadata.path,
364
+ "size": metadata.size,
365
+ "content_type": metadata.content_type,
366
+ "url": metadata.url
367
+ }
368
+
369
+ async def _download_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
370
+ """Download a file from storage"""
371
+ if not args.path:
372
+ raise ValueError("path is required for download operation")
373
+
374
+ # Default destination in output dir
375
+ if args.destination is None:
376
+ destination = self._resolve_output_path(Path(args.path).name)
377
+ else:
378
+ destination = args.destination
379
+
380
+ dest_path = Path(destination)
381
+
382
+ self.logger.info(f"Downloading '{args.path}' to '{destination}'")
383
+
384
+ result = await self.manager.download_file(args.path, dest_path)
385
+
386
+ return {
387
+ "downloaded": True,
388
+ "source": args.path,
389
+ "destination": str(result),
390
+ "size": dest_path.stat().st_size if dest_path.exists() else 0
391
+ }
392
+
393
+ async def _copy_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
394
+ """Copy a file within storage"""
395
+ if not args.source:
396
+ raise ValueError("source is required for copy operation")
397
+ if not args.destination:
398
+ raise ValueError("destination is required for copy operation")
399
+
400
+ self.logger.info(f"Copying '{args.source}' to '{args.destination}'")
401
+
402
+ metadata = await self.manager.copy_file(args.source, args.destination)
403
+
404
+ return {
405
+ "copied": True,
406
+ "source": args.source,
407
+ "destination": args.destination,
408
+ "name": metadata.name,
409
+ "size": metadata.size,
410
+ "url": metadata.url
411
+ }
412
+
413
+ async def _delete_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
414
+ """Delete a file from storage"""
415
+ if not args.path:
416
+ raise ValueError("path is required for delete operation")
417
+
418
+ self.logger.info(f"Deleting file '{args.path}'")
419
+
420
+ deleted = await self.manager.delete_file(args.path)
421
+
422
+ return {
423
+ "deleted": deleted,
424
+ "path": args.path
425
+ }
426
+
427
+ async def _exists(self, args: FileManagerToolArgs) -> Dict[str, Any]:
428
+ """Check if a file exists"""
429
+ if not args.path:
430
+ raise ValueError("path is required for exists operation")
431
+
432
+ exists = await self.manager.exists(args.path)
433
+
434
+ return {
435
+ "exists": exists,
436
+ "path": args.path
437
+ }
438
+
439
+ async def _get_file_url(self, args: FileManagerToolArgs) -> Dict[str, Any]:
440
+ """Get a URL to access the file"""
441
+ if not args.path:
442
+ raise ValueError("path is required for get_url operation")
443
+
444
+ expiry = args.expiry_seconds or 3600
445
+
446
+ url = await self.manager.get_file_url(args.path, expiry)
447
+
448
+ return {
449
+ "url": url,
450
+ "path": args.path,
451
+ "expiry_seconds": expiry
452
+ }
453
+
454
+ async def _get_file_metadata(self, args: FileManagerToolArgs) -> Dict[str, Any]:
455
+ """Get detailed metadata about a file"""
456
+ if not args.path:
457
+ raise ValueError("path is required for get_metadata operation")
458
+
459
+ metadata = await self.manager.get_file_metadata(args.path)
460
+
461
+ return {
462
+ "name": metadata.name,
463
+ "path": metadata.path,
464
+ "size": metadata.size,
465
+ "content_type": metadata.content_type,
466
+ "modified_at": metadata.modified_at.isoformat() if metadata.modified_at else None,
467
+ "url": metadata.url
468
+ }
469
+
470
+ async def _create_file(self, args: FileManagerToolArgs) -> Dict[str, Any]:
471
+ """Create a new file with content"""
472
+ if not args.path:
473
+ raise ValueError("path is required for create operation")
474
+ if not args.content:
475
+ raise ValueError("content is required for create operation")
476
+
477
+ # Convert string to bytes
478
+ encoding = args.encoding or 'utf-8'
479
+ content_bytes = args.content.encode(encoding)
480
+
481
+ # Check size
482
+ self._check_file_size(len(content_bytes))
483
+
484
+ dest = self._resolve_output_path(args.path)
485
+
486
+ self.logger.info(f"Creating file '{dest}' ({len(content_bytes)} bytes)")
487
+
488
+ # Use create_from_bytes
489
+ metadata = await self.manager.create_from_bytes(
490
+ dest,
491
+ BytesIO(content_bytes)
492
+ )
493
+
494
+ return {
495
+ "created": True,
496
+ "name": metadata.name,
497
+ "path": metadata.path,
498
+ "size": metadata.size,
499
+ "content_type": metadata.content_type,
500
+ "url": metadata.url
501
+ }
@@ -0,0 +1,129 @@
1
+ """FileReaderTool implementation for reading various file formats."""
2
+ from __future__ import annotations
3
+
4
+ import asyncio
5
+ from pathlib import Path
6
+ from typing import Any, Dict, Optional, Tuple
7
+
8
+ import aiofiles
9
+ import pandas as pd
10
+ from pydantic import Field
11
+
12
+ from markitdown import MarkItDown
13
+
14
+ from .abstract import AbstractTool, AbstractToolArgsSchema
15
+
16
+
17
+ class FileReaderToolArgs(AbstractToolArgsSchema):
18
+ """Arguments for :class:`FileReaderTool`."""
19
+
20
+ file_path: str = Field(description="Path to the file to read")
21
+ encoding: Optional[str] = Field(
22
+ default="utf-8",
23
+ description="Text encoding to use for textual files",
24
+ )
25
+ sheet_name: Optional[str] = Field(
26
+ default=None,
27
+ description="Optional sheet name for Excel workbooks",
28
+ )
29
+
30
+
31
+ class FileReaderTool(AbstractTool):
32
+ """Tool that reads a file and returns its textual representation."""
33
+
34
+ name = "FileReaderTool"
35
+ description = "Read text, document, or tabular files into structured content"
36
+ args_schema = FileReaderToolArgs
37
+
38
+ _TEXT_EXTENSIONS = {".txt", ".md", ".markdown", ".log", ".csv"}
39
+ _MARKITDOWN_EXTENSIONS = {".pdf", ".ppt", ".pptx", ".doc", ".docx"}
40
+ _TABULAR_EXTENSIONS = {".csv", ".tsv", ".xls", ".xlsx", ".xlsm", ".xlsb"}
41
+
42
+ def __init__(self, *args, **kwargs) -> None:
43
+ super().__init__(*args, **kwargs)
44
+ self._markitdown = MarkItDown()
45
+
46
+ async def _execute(
47
+ self,
48
+ file_path: str,
49
+ encoding: Optional[str] = "utf-8",
50
+ sheet_name: Optional[str] = None,
51
+ **_: Any,
52
+ ) -> Dict[str, Any]:
53
+ path = Path(file_path).expanduser().resolve()
54
+
55
+ if not path.exists():
56
+ raise FileNotFoundError(f"File not found: {path}")
57
+
58
+ if path.is_dir():
59
+ raise IsADirectoryError(f"Expected a file but received directory: {path}")
60
+
61
+ extension = path.suffix.lower()
62
+
63
+ if extension in self._TABULAR_EXTENSIONS:
64
+ content, metadata = await self._read_tabular_file(path, extension, sheet_name, encoding)
65
+ content_type = "tabular_json"
66
+ elif extension in self._MARKITDOWN_EXTENSIONS:
67
+ content, metadata = await self._read_markitdown_file(path)
68
+ content_type = "markdown"
69
+ elif extension in self._TEXT_EXTENSIONS:
70
+ content = await self._read_text_file(path, encoding=encoding)
71
+ metadata = {"encoding": encoding}
72
+ content_type = "text"
73
+ else:
74
+ raise ValueError(f"Unsupported file extension: {extension}")
75
+
76
+ return {
77
+ "file_path": str(path),
78
+ "content_type": content_type,
79
+ "content": content,
80
+ "metadata": {
81
+ "extension": extension,
82
+ **(metadata or {}),
83
+ },
84
+ }
85
+
86
+ async def _read_text_file(self, path: Path, encoding: Optional[str]) -> str:
87
+ async with aiofiles.open(path, mode="r", encoding=encoding or "utf-8") as file:
88
+ return await file.read()
89
+
90
+ async def _read_markitdown_file(self, path: Path) -> Tuple[str, Dict[str, Any]]:
91
+ loop = asyncio.get_running_loop()
92
+
93
+ def convert() -> Tuple[str, Dict[str, Any]]:
94
+ result = self._markitdown.convert(str(path))
95
+ text_content = getattr(result, "text_content", "")
96
+ metadata = getattr(result, "metadata", None)
97
+ if text_content is None:
98
+ text_content = ""
99
+ return text_content, metadata or {}
100
+
101
+ return await loop.run_in_executor(None, convert)
102
+
103
+ async def _read_tabular_file(
104
+ self,
105
+ path: Path,
106
+ extension: str,
107
+ sheet_name: Optional[str],
108
+ encoding: Optional[str],
109
+ ) -> Tuple[str, Dict[str, Any]]:
110
+ loop = asyncio.get_running_loop()
111
+
112
+ def load_dataframe() -> Tuple[str, Dict[str, Any]]:
113
+ if extension == ".csv" or extension == ".tsv":
114
+ sep = "\t" if extension == ".tsv" else ","
115
+ df = pd.read_csv(path, sep=sep, encoding=encoding or "utf-8")
116
+ else:
117
+ df = pd.read_excel(path, sheet_name=sheet_name)
118
+
119
+ json_content = df.to_json(orient="records", date_format="iso")
120
+ metadata: Dict[str, Any] = {
121
+ "rows": len(df.index),
122
+ "columns": list(df.columns),
123
+ }
124
+ if sheet_name is not None and extension != ".csv" and extension != ".tsv":
125
+ metadata["sheet_name"] = sheet_name
126
+
127
+ return json_content, metadata
128
+
129
+ return await loop.run_in_executor(None, load_dataframe)
@@ -0,0 +1,19 @@
1
+ from .tool import (
2
+ FlowtaskToolkit,
3
+ FlowtaskTool, # Backward compatibility alias
4
+ FlowtaskComponentInput,
5
+ FlowtaskTaskExecutionInput,
6
+ FlowtaskRemoteExecutionInput,
7
+ FlowtaskCodeExecutionInput,
8
+ TaskCodeFormat,
9
+ )
10
+
11
+ __all__ = [
12
+ "FlowtaskToolkit",
13
+ "FlowtaskTool",
14
+ "FlowtaskComponentInput",
15
+ "FlowtaskTaskExecutionInput",
16
+ "FlowtaskRemoteExecutionInput",
17
+ "FlowtaskCodeExecutionInput",
18
+ "TaskCodeFormat",
19
+ ]