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,668 @@
1
+ """
2
+ DocumentDB Agent Implementation for AI-Parrot.
3
+
4
+ Concrete implementation of AbstractDBAgent for AWS DocumentDB
5
+ (MongoDB-compatible) with support for MQL query language.
6
+ """
7
+
8
+ from typing import Dict, Any, List, Optional, Union
9
+ import asyncio
10
+ import json
11
+ from datetime import datetime
12
+ from pydantic import Field
13
+ from asyncdb import AsyncDB
14
+ from navconfig import config, BASE_DIR
15
+
16
+ from .abstract import (
17
+ AbstractDBAgent,
18
+ DatabaseSchema,
19
+ TableMetadata,
20
+ )
21
+ from ...tools.abstract import AbstractTool, ToolResult, AbstractToolArgsSchema
22
+
23
+
24
+ class CollectionQueryExecutionArgs(AbstractToolArgsSchema):
25
+ """Arguments for DocumentDB collection query execution."""
26
+ collection_name: str = Field(description="Collection name to query")
27
+ query: Dict[str, Any] = Field(
28
+ default_factory=dict, description="MongoDB query filter"
29
+ )
30
+ limit: Optional[int] = Field(
31
+ default=100, description="Maximum number of documents to return"
32
+ )
33
+ projection: Optional[Dict[str, int]] = Field(
34
+ default=None, description="Fields to include/exclude in results"
35
+ )
36
+
37
+
38
+ class CollectionMetadata:
39
+ """Metadata for DocumentDB collections."""
40
+ def __init__(
41
+ self,
42
+ name: str,
43
+ database: str,
44
+ document_count: int,
45
+ fields: List[Dict[str, str]],
46
+ sample_documents: List[Dict[str, Any]] = None,
47
+ indexes: List[Dict[str, Any]] = None
48
+ ):
49
+ self.name = name
50
+ self.database = database
51
+ self.document_count = document_count
52
+ self.fields = fields
53
+ self.sample_documents = sample_documents or []
54
+ self.indexes = indexes or []
55
+
56
+
57
+ class DocumentDBAgent(AbstractDBAgent):
58
+ """
59
+ DocumentDB Agent for document database introspection and MQL query generation.
60
+
61
+ Supports AWS DocumentDB (MongoDB-compatible) with MongoDB Query Language (MQL).
62
+ """
63
+
64
+ def __init__(
65
+ self,
66
+ name: str = "DocumentDBAgent",
67
+ host: str = None,
68
+ port: int = 27017,
69
+ database: str = None,
70
+ username: str = None,
71
+ password: str = None,
72
+ credentials: Union[str, Dict[str, Any]] = None,
73
+ ssl: bool = True,
74
+ tls_ca_file: str = None,
75
+ max_sample_documents: int = 10,
76
+ **kwargs
77
+ ):
78
+ """
79
+ Initialize DocumentDB Agent.
80
+
81
+ Args:
82
+ name: Agent name
83
+ host: DocumentDB hostname
84
+ port: DocumentDB port (default: 27017)
85
+ database: Database name
86
+ username: Username for authentication
87
+ password: Password for authentication
88
+ credentials: Credentials dict or connection string (overrides individual params)
89
+ ssl: Enable SSL/TLS connection (default: True)
90
+ tls_ca_file: Path to TLS CA certificate file
91
+ max_sample_documents: Maximum sample documents per collection
92
+ """
93
+ self.host = host
94
+ self.port = port
95
+ self.database_name = database
96
+ self.username = username
97
+ self.password = password
98
+ self.ssl = ssl
99
+ self.tls_ca_file = tls_ca_file
100
+ self.max_sample_documents = max_sample_documents
101
+ self.db_connection: Optional[Any] = None
102
+ self.collections_cache: Dict[str, CollectionMetadata] = {}
103
+
104
+ # Get default credentials if not provided
105
+ if not credentials and not all([host, database]):
106
+ credentials = self._get_default_credentials()
107
+
108
+ super().__init__(
109
+ name=name,
110
+ credentials=credentials,
111
+ schema_name=database,
112
+ **kwargs
113
+ )
114
+
115
+ # Add DocumentDB-specific tools
116
+ self._setup_documentdb_tools()
117
+
118
+ def _get_default_credentials(self) -> Dict[str, Any]:
119
+ """Get default credentials from config (similar to DatabaseQueryTool)."""
120
+ return {
121
+ 'driver': 'mongo',
122
+ 'host': config.get('DOCUMENTDB_HOSTNAME', fallback='localhost'),
123
+ 'port': config.get('DOCUMENTDB_PORT', fallback=27017),
124
+ 'database': config.get('DOCUMENTDB_DATABASE', fallback='test'),
125
+ 'username': config.get('DOCUMENTDB_USERNAME'),
126
+ 'password': config.get('DOCUMENTDB_PASSWORD'),
127
+ 'tlsCAFile': config.get('DOCUMENTDB_TLS_CA_FILE') or BASE_DIR.joinpath('env', "global-bundle.pem"),
128
+ 'ssl': config.get('DOCUMENTDB_USE_SSL', fallback=True),
129
+ 'collection_name': config.get('DOCUMENTDB_COLLECTION', fallback='mycollection'),
130
+ 'dbtype': 'documentdb'
131
+ }
132
+
133
+ def _setup_documentdb_tools(self):
134
+ """Setup DocumentDB-specific tools."""
135
+ # Add collection query execution tool
136
+ collection_query_tool = CollectionQueryExecutionTool(agent=self)
137
+ self.tool_manager.register_tool(collection_query_tool)
138
+
139
+ # Add collection exploration tool
140
+ collection_exploration_tool = CollectionExplorationTool(agent=self)
141
+ self.tool_manager.register_tool(collection_exploration_tool)
142
+
143
+ async def connect_database(self) -> None:
144
+ """Connect to DocumentDB using AsyncDB with mongo driver."""
145
+ # Parse credentials
146
+ if isinstance(self.credentials, dict):
147
+ creds = self.credentials.copy()
148
+ self.host = creds.get('host', self.host)
149
+ self.port = creds.get('port', self.port)
150
+ self.database_name = creds.get('database', self.database_name)
151
+ self.username = creds.get('username', self.username)
152
+ self.password = creds.get('password', self.password)
153
+ self.ssl = creds.get('ssl', self.ssl)
154
+ self.tls_ca_file = creds.get('tlsCAFile', self.tls_ca_file)
155
+
156
+ if not self.host:
157
+ raise ValueError("DocumentDB host is required")
158
+ if not self.database_name:
159
+ raise ValueError("DocumentDB database name is required")
160
+
161
+ try:
162
+ # Build connection parameters for AsyncDB
163
+ params = {
164
+ 'host': self.host,
165
+ 'port': self.port,
166
+ 'database': self.database_name,
167
+ 'dbtype': 'documentdb'
168
+ }
169
+
170
+ if self.username:
171
+ params['username'] = self.username
172
+ if self.password:
173
+ params['password'] = self.password
174
+ if self.ssl:
175
+ params['ssl'] = self.ssl
176
+ if self.tls_ca_file:
177
+ params['tlsCAFile'] = str(self.tls_ca_file)
178
+
179
+ # Create AsyncDB instance
180
+ self.db = AsyncDB('mongo', params=params)
181
+
182
+ # Test connection
183
+ async with await self.db.connection() as conn:
184
+ await conn.use(self.database_name)
185
+ # Simple ping to verify connection
186
+ result = await conn.execute({"ping": 1})
187
+
188
+ self.logger.info(
189
+ f"Successfully connected to DocumentDB at {self.host}:{self.port}"
190
+ )
191
+
192
+ except Exception as e:
193
+ self.logger.error(f"Failed to connect to DocumentDB: {e}")
194
+ raise
195
+
196
+ async def extract_schema_metadata(self) -> DatabaseSchema:
197
+ """Extract schema metadata from DocumentDB (collections, fields, documents)."""
198
+ if not self.db:
199
+ await self.connect_database()
200
+
201
+ try:
202
+ async with await self.db.connection() as conn:
203
+ await conn.use(self.database_name)
204
+
205
+ # Get list of collections
206
+ collections_result = await conn.execute({"listCollections": 1})
207
+ collection_names = [
208
+ col['name'] for col in collections_result.get('cursor', {}).get('firstBatch', [])
209
+ if not col['name'].startswith('system.')
210
+ ]
211
+
212
+ # Extract metadata for each collection
213
+ all_collections = []
214
+ for collection_name in collection_names:
215
+ collection_metadata = await self._extract_collection_metadata(
216
+ conn, collection_name
217
+ )
218
+ all_collections.append(collection_metadata)
219
+
220
+ # Cache for later use
221
+ cache_key = f"{self.database_name}.{collection_name}"
222
+ self.collections_cache[cache_key] = collection_metadata
223
+
224
+ # Convert collections to TableMetadata format
225
+ tables = self._convert_collections_to_tables(all_collections)
226
+
227
+ schema_metadata = DatabaseSchema(
228
+ database_name=self.database_name,
229
+ database_type="documentdb",
230
+ tables=tables,
231
+ views=[], # DocumentDB doesn't have traditional views
232
+ functions=[],
233
+ procedures=[],
234
+ metadata={
235
+ "collections_analyzed": len(all_collections),
236
+ "extraction_timestamp": datetime.now().isoformat(),
237
+ "host": self.host,
238
+ "port": self.port
239
+ }
240
+ )
241
+
242
+ self.logger.info(
243
+ f"Extracted metadata for {len(all_collections)} collections from {self.database_name}"
244
+ )
245
+
246
+ return schema_metadata
247
+
248
+ except Exception as e:
249
+ self.logger.error(f"Failed to extract DocumentDB schema metadata: {e}")
250
+ raise
251
+
252
+ async def _extract_collection_metadata(
253
+ self,
254
+ conn: Any,
255
+ collection_name: str
256
+ ) -> CollectionMetadata:
257
+ """Extract detailed metadata for a specific collection."""
258
+ try:
259
+ # Get document count
260
+ count_result = await conn.count(collection_name, {})
261
+ document_count = count_result if isinstance(count_result, int) else 0
262
+
263
+ # Get sample documents to infer schema
264
+ sample_docs = await conn.fetch(
265
+ collection_name,
266
+ {},
267
+ limit=self.max_sample_documents
268
+ )
269
+
270
+ # Infer fields from sample documents
271
+ fields = self._infer_fields_from_documents(sample_docs)
272
+
273
+ # Get indexes
274
+ indexes = []
275
+ try:
276
+ indexes_cursor = await conn.execute({
277
+ "listIndexes": collection_name
278
+ })
279
+ indexes = list(indexes_cursor.get('cursor', {}).get('firstBatch', []))
280
+ except Exception as e:
281
+ self.logger.warning(f"Could not get indexes for {collection_name}: {e}")
282
+
283
+ return CollectionMetadata(
284
+ name=collection_name,
285
+ database=self.database_name,
286
+ document_count=document_count,
287
+ fields=fields,
288
+ sample_documents=sample_docs[:5] if sample_docs else [],
289
+ indexes=indexes
290
+ )
291
+
292
+ except Exception as e:
293
+ self.logger.warning(
294
+ f"Could not extract metadata for collection {collection_name}: {e}"
295
+ )
296
+ return CollectionMetadata(
297
+ name=collection_name,
298
+ database=self.database_name,
299
+ document_count=0,
300
+ fields=[],
301
+ sample_documents=[],
302
+ indexes=[]
303
+ )
304
+
305
+ def _infer_fields_from_documents(
306
+ self,
307
+ documents: List[Dict[str, Any]]
308
+ ) -> List[Dict[str, str]]:
309
+ """Infer field schema from sample documents."""
310
+ if not documents:
311
+ return []
312
+
313
+ # Collect all fields and their types
314
+ field_types = {}
315
+ for doc in documents:
316
+ for key, value in doc.items():
317
+ if key not in field_types:
318
+ field_types[key] = set()
319
+ field_types[key].add(type(value).__name__)
320
+
321
+ # Create field list
322
+ fields = []
323
+ for field_name, types in sorted(field_types.items()):
324
+ type_str = ' | '.join(sorted(types))
325
+ fields.append({
326
+ "name": field_name,
327
+ "type": type_str
328
+ })
329
+
330
+ return fields
331
+
332
+ def _convert_collections_to_tables(
333
+ self,
334
+ collections: List[CollectionMetadata]
335
+ ) -> List[TableMetadata]:
336
+ """Convert DocumentDB collections to TableMetadata format."""
337
+ tables = []
338
+
339
+ for collection in collections:
340
+ # Create columns list from fields
341
+ columns = []
342
+ for field in collection.fields:
343
+ columns.append({
344
+ "name": field["name"],
345
+ "type": field["type"],
346
+ "nullable": True, # MongoDB fields are generally nullable
347
+ "description": f"Field: {field['name']}"
348
+ })
349
+
350
+ # Create table metadata
351
+ table_metadata = TableMetadata(
352
+ name=collection.name,
353
+ schema=self.database_name,
354
+ columns=columns,
355
+ primary_keys=["_id"], # MongoDB always has _id
356
+ foreign_keys=[], # DocumentDB doesn't enforce foreign keys
357
+ indexes=[idx.get('name', '') for idx in collection.indexes],
358
+ description=f"DocumentDB collection with {collection.document_count} documents",
359
+ sample_data=collection.sample_documents
360
+ )
361
+
362
+ tables.append(table_metadata)
363
+
364
+ return tables
365
+
366
+ async def generate_query(
367
+ self,
368
+ natural_language_query: str,
369
+ target_tables: Optional[List[str]] = None,
370
+ query_type: str = "find"
371
+ ) -> Dict[str, Any]:
372
+ """Generate MongoDB query from natural language."""
373
+ try:
374
+ # Get schema context for the query
375
+ schema_context = []
376
+ if self.schema_metadata:
377
+ # Filter collections based on target_tables
378
+ collections_to_use = self.schema_metadata.tables
379
+ if target_tables:
380
+ collections_to_use = [
381
+ t for t in collections_to_use if t.name in target_tables
382
+ ]
383
+
384
+ for table in collections_to_use[:3]: # Limit to top 3
385
+ schema_context.append({
386
+ 'collection': table.name,
387
+ 'fields': [col['name'] for col in table.columns],
388
+ 'sample_count': len(table.sample_data)
389
+ })
390
+
391
+ # Build MQL query generation prompt
392
+ prompt = self._build_mql_query_prompt(
393
+ natural_language_query=natural_language_query,
394
+ schema_context=schema_context
395
+ )
396
+
397
+ # Generate query using LLM
398
+ async with self._llm as client:
399
+ response = await client.ask(
400
+ prompt=prompt,
401
+ model=self._llm_model,
402
+ temperature=0.1
403
+ )
404
+
405
+ # Extract MQL query from response
406
+ mql_query = self._extract_mql_from_response(response.output or response.response)
407
+
408
+ result = {
409
+ "query": mql_query,
410
+ "query_type": "mql",
411
+ "collections_used": target_tables or [],
412
+ "schema_context_used": len(schema_context),
413
+ "natural_language_input": natural_language_query
414
+ }
415
+
416
+ return result
417
+
418
+ except Exception as e:
419
+ self.logger.error(f"Failed to generate MQL query: {e}")
420
+ raise
421
+
422
+ def _build_mql_query_prompt(
423
+ self,
424
+ natural_language_query: str,
425
+ schema_context: List[Dict[str, Any]]
426
+ ) -> str:
427
+ """Build prompt for MQL query generation."""
428
+ prompt = f"""
429
+ You are an expert MongoDB/DocumentDB query developer.
430
+ Generate a MongoDB query based on the natural language request and the provided schema information.
431
+
432
+ Natural Language Request: {natural_language_query}
433
+
434
+ Available Collections and Schema:
435
+ """
436
+ for i, context in enumerate(schema_context, 1):
437
+ prompt += f"\n{i}. Collection: {context['collection']}\n"
438
+ prompt += f" Fields: {', '.join(context['fields'])}\n"
439
+
440
+ prompt += """
441
+
442
+ MongoDB Query Guidelines:
443
+ 1. Use standard MongoDB query syntax
444
+ 2. Return query as a JSON object
445
+ 3. Use the find command structure: {"find": "collection_name", "filter": {...}, "limit": N}
446
+ 4. Common operators: $eq, $ne, $gt, $lt, $gte, $lte, $in, $nin, $and, $or, $not
447
+ 5. For text search use $regex or $text
448
+ 6. Include projection to limit returned fields if needed
449
+ 7. Return only the MongoDB query as valid JSON without explanations
450
+
451
+ Example query structure:
452
+ {
453
+ "find": "users",
454
+ "filter": {"age": {"$gte": 18}, "status": "active"},
455
+ "limit": 10,
456
+ "sort": {"created_at": -1}
457
+ }
458
+
459
+ MongoDB Query (JSON only):"""
460
+
461
+ return prompt
462
+
463
+ def _extract_mql_from_response(self, response_text: str) -> Dict[str, Any]:
464
+ """Extract MQL query from LLM response."""
465
+ # Remove markdown code blocks if present
466
+ if "```" in response_text:
467
+ lines = response_text.split('\n')
468
+ json_lines = []
469
+ in_code_block = False
470
+
471
+ for line in lines:
472
+ if line.strip().startswith("```"):
473
+ in_code_block = not in_code_block
474
+ continue
475
+ elif in_code_block or (line.strip().startswith('{') or json_lines):
476
+ json_lines.append(line)
477
+
478
+ response_text = '\n'.join(json_lines).strip()
479
+
480
+ # Parse JSON
481
+ try:
482
+ return json.loads(response_text)
483
+ except json.JSONDecodeError:
484
+ # Try to extract first JSON object
485
+ import re
486
+ match = re.search(r'\{.*\}', response_text, re.DOTALL)
487
+ if match:
488
+ return json.loads(match.group())
489
+ else:
490
+ return {"filter": {}}
491
+
492
+ async def execute_query(
493
+ self,
494
+ query: Union[str, Dict[str, Any]],
495
+ limit: Optional[int] = 100
496
+ ) -> Dict[str, Any]:
497
+ """Execute MongoDB query against DocumentDB."""
498
+ try:
499
+ if not self.db:
500
+ await self.connect_database()
501
+
502
+ # Parse query if string
503
+ if isinstance(query, str):
504
+ query = json.loads(query)
505
+
506
+ async with await self.db.connection() as conn:
507
+ await conn.use(self.database_name)
508
+
509
+ # Extract query components
510
+ collection_name = query.get('find') or query.get('collection')
511
+ filter_query = query.get('filter', {})
512
+ query_limit = query.get('limit', limit)
513
+ projection = query.get('projection')
514
+ sort = query.get('sort')
515
+
516
+ if not collection_name:
517
+ raise ValueError("Query must specify a collection name")
518
+
519
+ # Execute query
520
+ results = await conn.fetch(
521
+ collection_name,
522
+ filter_query,
523
+ limit=query_limit
524
+ )
525
+
526
+ return {
527
+ "success": True,
528
+ "data": results,
529
+ "record_count": len(results),
530
+ "query": query,
531
+ "collection": collection_name
532
+ }
533
+
534
+ except Exception as e:
535
+ self.logger.error(f"DocumentDB query execution failed: {e}")
536
+ return {
537
+ "success": False,
538
+ "error": str(e),
539
+ "query": query
540
+ }
541
+
542
+ async def close(self):
543
+ """Close DocumentDB connection."""
544
+ if self.db:
545
+ await self.db.close()
546
+
547
+
548
+ class CollectionQueryExecutionTool(AbstractTool):
549
+ """Tool for executing queries against DocumentDB collections."""
550
+
551
+ name = "execute_documentdb_query"
552
+ description = "Execute MongoDB queries against the DocumentDB database"
553
+ args_schema = CollectionQueryExecutionArgs
554
+
555
+ def __init__(self, agent: DocumentDBAgent, **kwargs):
556
+ super().__init__(**kwargs)
557
+ self.agent = agent
558
+
559
+ async def _execute(
560
+ self,
561
+ collection_name: str,
562
+ query: Dict[str, Any] = None,
563
+ limit: Optional[int] = 100,
564
+ projection: Optional[Dict[str, int]] = None
565
+ ) -> ToolResult:
566
+ """Execute collection query."""
567
+ try:
568
+ # Build query object
569
+ full_query = {
570
+ "find": collection_name,
571
+ "filter": query or {},
572
+ "limit": limit
573
+ }
574
+ if projection:
575
+ full_query["projection"] = projection
576
+
577
+ result = await self.agent.execute_query(full_query, limit)
578
+
579
+ return ToolResult(
580
+ status="success" if result["success"] else "error",
581
+ result=result,
582
+ error=result.get("error"),
583
+ metadata={
584
+ "collection": collection_name,
585
+ "limit": limit
586
+ }
587
+ )
588
+
589
+ except Exception as e:
590
+ return ToolResult(
591
+ status="error",
592
+ result=None,
593
+ error=str(e),
594
+ metadata={"collection": collection_name}
595
+ )
596
+
597
+
598
+ class CollectionExplorationTool(AbstractTool):
599
+ """Tool for exploring DocumentDB collections and their metadata."""
600
+
601
+ name = "explore_collections"
602
+ description = "Explore available collections and fields in DocumentDB"
603
+
604
+ class ExplorationArgs(AbstractToolArgsSchema):
605
+ """Exploration arguments schema."""
606
+ collection: Optional[str] = Field(
607
+ default=None, description="Specific collection to explore"
608
+ )
609
+ show_sample_data: bool = Field(
610
+ default=True, description="Include sample data in results"
611
+ )
612
+
613
+ args_schema = ExplorationArgs
614
+
615
+ def __init__(self, agent: DocumentDBAgent, **kwargs):
616
+ super().__init__(**kwargs)
617
+ self.agent = agent
618
+
619
+ async def _execute(
620
+ self,
621
+ collection: Optional[str] = None,
622
+ show_sample_data: bool = True
623
+ ) -> ToolResult:
624
+ """Explore collections in DocumentDB."""
625
+ try:
626
+ if not self.agent.schema_metadata:
627
+ await self.agent.extract_schema_metadata()
628
+
629
+ exploration_result = {
630
+ "collections": [],
631
+ "total_collections": 0
632
+ }
633
+
634
+ # Filter by collection if specified
635
+ tables_to_explore = self.agent.schema_metadata.tables
636
+ if collection:
637
+ tables_to_explore = [t for t in tables_to_explore if t.name == collection]
638
+
639
+ for table in tables_to_explore:
640
+ collection_info = {
641
+ "name": table.name,
642
+ "document_count": table.description,
643
+ "fields": [col['name'] for col in table.columns],
644
+ "indexes": table.indexes
645
+ }
646
+
647
+ if show_sample_data and table.sample_data:
648
+ collection_info["sample_documents"] = table.sample_data[:3]
649
+
650
+ exploration_result["collections"].append(collection_info)
651
+
652
+ exploration_result["total_collections"] = len(exploration_result["collections"])
653
+
654
+ return ToolResult(
655
+ status="success",
656
+ result=exploration_result,
657
+ metadata={
658
+ "database": self.agent.database_name,
659
+ "collection_filter": collection
660
+ }
661
+ )
662
+
663
+ except Exception as e:
664
+ return ToolResult(
665
+ status="error",
666
+ result=None,
667
+ error=str(e)
668
+ )