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,783 @@
1
+ """
2
+ Database Agents Integration Guide for AI-Parrot.
3
+
4
+ This module provides examples and utilities for integrating and using
5
+ the different database agents (SQL, InfluxDB, Elasticsearch) together.
6
+ """
7
+
8
+ import asyncio
9
+ from typing import Dict, Any, List, Optional
10
+ from pathlib import Path
11
+ import json
12
+ from pydantic import Field
13
+ import argparse
14
+ # Import all database agents
15
+ from .abstract import AbstractDBAgent
16
+ from .sql import SQLDbAgent, create_sql_agent
17
+ from .influx import InfluxDBAgent, create_influxdb_agent
18
+ from .elastic import ElasticDbAgent, create_elasticsearch_agent
19
+
20
+ # Import base components
21
+ from ..abstract import AbstractBot
22
+ from ...stores.abstract import AbstractStore
23
+ from ...tools.abstract import AbstractTool, ToolResult, AbstractToolArgsSchema
24
+ from ...stores import supported_stores
25
+
26
+
27
+ class MultiDatabaseAgent(AbstractBot):
28
+ """
29
+ Multi-Database Agent that can work with multiple database types simultaneously.
30
+
31
+ This agent coordinates between different database agents and can route queries
32
+ to the appropriate database based on the natural language request.
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ name: str = "MultiDatabaseAgent",
38
+ database_configs: Dict[str, Dict[str, Any]] = None,
39
+ knowledge_store: AbstractStore = None,
40
+ **kwargs
41
+ ):
42
+ """
43
+ Initialize Multi-Database Agent.
44
+
45
+ Args:
46
+ name: Agent name
47
+ database_configs: Configuration for each database type
48
+ knowledge_store: Shared knowledge store for all databases
49
+ """
50
+ super().__init__(name=name, **kwargs)
51
+
52
+ self.database_configs = database_configs or {}
53
+ self.knowledge_store = knowledge_store
54
+ self.database_agents: Dict[str, AbstractDBAgent] = {}
55
+
56
+ # Initialize database agents
57
+ asyncio.create_task(self._initialize_database_agents())
58
+
59
+ async def _initialize_database_agents(self):
60
+ """Initialize all configured database agents."""
61
+ for db_name, config in self.database_configs.items():
62
+ try:
63
+ agent = await self._create_database_agent(db_name, config)
64
+ self.database_agents[db_name] = agent
65
+ self.logger.info(f"Initialized {config['type']} agent: {db_name}")
66
+ except Exception as e:
67
+ self.logger.error(f"Failed to initialize {db_name}: {e}")
68
+
69
+ async def _create_database_agent(self, db_name: str, config: Dict[str, Any]) -> AbstractDBAgent:
70
+ """Create a database agent based on configuration."""
71
+ db_type = config.get('type', '').lower()
72
+
73
+ if db_type in ['postgresql', 'mysql', 'sqlserver']:
74
+ agent = create_sql_agent(
75
+ database_flavor=db_type,
76
+ connection_string=config['connection_string'],
77
+ schema_name=config.get('schema_name'),
78
+ knowledge_store=self.knowledge_store,
79
+ name=f"{db_name}_agent"
80
+ )
81
+ elif db_type == 'influxdb':
82
+ agent = create_influxdb_agent(
83
+ url=config['url'],
84
+ token=config['token'],
85
+ org=config['org'],
86
+ bucket=config.get('bucket'),
87
+ knowledge_store=self.knowledge_store,
88
+ name=f"{db_name}_agent"
89
+ )
90
+ elif db_type == 'elasticsearch':
91
+ agent = create_elasticsearch_agent(
92
+ url=config.get('url'),
93
+ username=config.get('username'),
94
+ password=config.get('password'),
95
+ api_key=config.get('api_key'),
96
+ cloud_id=config.get('cloud_id'),
97
+ knowledge_store=self.knowledge_store,
98
+ name=f"{db_name}_agent"
99
+ )
100
+ else:
101
+ raise ValueError(f"Unsupported database type: {db_type}")
102
+
103
+ # Initialize the agent
104
+ await agent.initialize_schema()
105
+ return agent
106
+
107
+ async def route_query_to_database(
108
+ self,
109
+ natural_language_query: str,
110
+ preferred_database: Optional[str] = None
111
+ ) -> Dict[str, Any]:
112
+ """
113
+ Route a natural language query to the most appropriate database.
114
+
115
+ Args:
116
+ natural_language_query: Natural language description of the query
117
+ preferred_database: Specific database to use (optional)
118
+
119
+ Returns:
120
+ Query result with routing information
121
+ """
122
+ if preferred_database and preferred_database in self.database_agents:
123
+ # Use specified database
124
+ agent = self.database_agents[preferred_database]
125
+ result = await agent.generate_query(natural_language_query)
126
+ result['routed_to'] = preferred_database
127
+ result['routing_reason'] = 'user_specified'
128
+ return result
129
+
130
+ # Auto-route based on query content
131
+ best_agent, routing_reason = await self._determine_best_agent(natural_language_query)
132
+
133
+ if best_agent:
134
+ result = await best_agent.generate_query(natural_language_query)
135
+ result['routed_to'] = self._get_agent_name(best_agent)
136
+ result['routing_reason'] = routing_reason
137
+ return result
138
+ else:
139
+ raise ValueError("No suitable database agent found for the query")
140
+
141
+ async def _determine_best_agent(self, query: str) -> tuple[Optional[AbstractDBAgent], str]:
142
+ """Determine the best database agent for a query."""
143
+ query_lower = query.lower()
144
+
145
+ # Time-series keywords suggest InfluxDB
146
+ time_series_keywords = [
147
+ 'time series', 'over time', 'last hour', 'last day', 'last week',
148
+ 'trend', 'monitoring', 'metrics', 'sensor', 'measurement',
149
+ 'aggregateWindow', 'mean()', 'sum()', 'count()', 'range'
150
+ ]
151
+
152
+ # Document/search keywords suggest Elasticsearch
153
+ document_keywords = [
154
+ 'search', 'text search', 'full text', 'documents', 'logs',
155
+ 'match', 'analyze', 'aggregation', 'bucket', 'terms'
156
+ ]
157
+
158
+ # SQL keywords suggest SQL database
159
+ sql_keywords = [
160
+ 'join', 'table', 'foreign key', 'primary key', 'index',
161
+ 'transaction', 'acid', 'relational', 'normalize'
162
+ ]
163
+
164
+ # Score each agent type
165
+ scores = {}
166
+
167
+ for agent_name, agent in self.database_agents.items():
168
+ score = 0
169
+
170
+ if isinstance(agent, InfluxDBAgent):
171
+ score += sum(1 for keyword in time_series_keywords if keyword in query_lower)
172
+ elif isinstance(agent, ElasticDbAgent):
173
+ score += sum(1 for keyword in document_keywords if keyword in query_lower)
174
+ elif isinstance(agent, SQLDbAgent):
175
+ score += sum(1 for keyword in sql_keywords if keyword in query_lower)
176
+
177
+ scores[agent_name] = score
178
+
179
+ if not scores:
180
+ return None, "no_agents_available"
181
+
182
+ # Return agent with highest score
183
+ best_agent_name = max(scores, key=scores.get)
184
+ best_score = scores[best_agent_name]
185
+
186
+ if best_score > 0:
187
+ return self.database_agents[best_agent_name], f"keyword_match_score_{best_score}"
188
+
189
+ # If no clear winner, use first available agent
190
+ first_agent_name = next(iter(self.database_agents))
191
+ return self.database_agents[first_agent_name], "default_fallback"
192
+
193
+ def _get_agent_name(self, agent: AbstractDBAgent) -> str:
194
+ """Get the name/key of an agent."""
195
+ for name, stored_agent in self.database_agents.items():
196
+ if stored_agent is agent:
197
+ return name
198
+ return "unknown"
199
+
200
+ async def search_across_databases(
201
+ self,
202
+ search_term: str,
203
+ databases: Optional[List[str]] = None
204
+ ) -> Dict[str, List[Dict[str, Any]]]:
205
+ """Search for schema information across multiple databases."""
206
+ results = {}
207
+
208
+ target_databases = databases or list(self.database_agents.keys())
209
+
210
+ for db_name in target_databases:
211
+ if db_name in self.database_agents:
212
+ try:
213
+ agent = self.database_agents[db_name]
214
+ search_results = await agent.search_schema(search_term)
215
+ results[db_name] = search_results
216
+ except Exception as e:
217
+ self.logger.warning(f"Search failed for {db_name}: {e}")
218
+ results[db_name] = []
219
+
220
+ return results
221
+
222
+ async def get_database_summary(self) -> Dict[str, Any]:
223
+ """Get a summary of all connected databases."""
224
+ summary = {
225
+ "total_databases": len(self.database_agents),
226
+ "databases": {}
227
+ }
228
+
229
+ for db_name, agent in self.database_agents.items():
230
+ try:
231
+ if hasattr(agent, 'schema_metadata') and agent.schema_metadata:
232
+ metadata = agent.schema_metadata
233
+ summary["databases"][db_name] = {
234
+ "type": metadata.database_type,
235
+ "name": metadata.database_name,
236
+ "tables_count": len(metadata.tables),
237
+ "views_count": len(metadata.views),
238
+ "status": "connected"
239
+ }
240
+ else:
241
+ summary["databases"][db_name] = {
242
+ "type": "unknown",
243
+ "status": "no_metadata"
244
+ }
245
+ except Exception as e:
246
+ summary["databases"][db_name] = {
247
+ "status": "error",
248
+ "error": str(e)
249
+ }
250
+
251
+ return summary
252
+
253
+ async def close_all_connections(self):
254
+ """Close all database connections."""
255
+ for agent in self.database_agents.values():
256
+ try:
257
+ await agent.close()
258
+ except Exception as e:
259
+ self.logger.warning(f"Error closing agent connection: {e}")
260
+
261
+
262
+ # Configuration examples and utilities
263
+ class DatabaseConfigBuilder:
264
+ """Helper class to build database configurations."""
265
+
266
+ @staticmethod
267
+ def postgresql_config(
268
+ host: str,
269
+ port: int = 5432,
270
+ database: str = None,
271
+ username: str = None,
272
+ password: str = None,
273
+ schema: str = "public"
274
+ ) -> Dict[str, Any]:
275
+ """Build PostgreSQL configuration."""
276
+ connection_string = f"postgresql://{username}:{password}@{host}:{port}/{database}"
277
+ return {
278
+ "type": "postgresql",
279
+ "connection_string": connection_string,
280
+ "schema_name": schema
281
+ }
282
+
283
+ @staticmethod
284
+ def mysql_config(
285
+ host: str,
286
+ port: int = 3306,
287
+ database: str = None,
288
+ username: str = None,
289
+ password: str = None
290
+ ) -> Dict[str, Any]:
291
+ """Build MySQL configuration."""
292
+ connection_string = f"mysql://{username}:{password}@{host}:{port}/{database}"
293
+ return {
294
+ "type": "mysql",
295
+ "connection_string": connection_string
296
+ }
297
+
298
+ @staticmethod
299
+ def influxdb_config(
300
+ url: str,
301
+ token: str,
302
+ org: str,
303
+ bucket: str = None
304
+ ) -> Dict[str, Any]:
305
+ """Build InfluxDB configuration."""
306
+ return {
307
+ "type": "influxdb",
308
+ "url": url,
309
+ "token": token,
310
+ "org": org,
311
+ "bucket": bucket
312
+ }
313
+
314
+ @staticmethod
315
+ def elasticsearch_config(
316
+ url: str = None,
317
+ username: str = None,
318
+ password: str = None,
319
+ api_key: str = None,
320
+ cloud_id: str = None
321
+ ) -> Dict[str, Any]:
322
+ """Build Elasticsearch configuration."""
323
+ config = {"type": "elasticsearch"}
324
+
325
+ if cloud_id:
326
+ config["cloud_id"] = cloud_id
327
+ else:
328
+ config["url"] = url
329
+
330
+ if api_key:
331
+ config["api_key"] = api_key
332
+ else:
333
+ config["username"] = username
334
+ config["password"] = password
335
+
336
+ return config
337
+
338
+
339
+ # Example usage and integration patterns
340
+ async def example_multi_database_usage():
341
+ """Example of using multiple database agents together."""
342
+
343
+ # Build database configurations
344
+ db_configs = {
345
+ "main_db": DatabaseConfigBuilder.postgresql_config(
346
+ host="localhost",
347
+ database="myapp",
348
+ username="user",
349
+ password="pass"
350
+ ),
351
+ "metrics_db": DatabaseConfigBuilder.influxdb_config(
352
+ url="http://localhost:8086",
353
+ token="my-token",
354
+ org="my-org",
355
+ bucket="metrics"
356
+ ),
357
+ "search_db": DatabaseConfigBuilder.elasticsearch_config(
358
+ url="http://localhost:9200",
359
+ username="elastic",
360
+ password="password"
361
+ )
362
+ }
363
+
364
+ # Create multi-database agent
365
+ multi_agent = MultiDatabaseAgent(
366
+ name="CompanyDataAgent",
367
+ database_configs=db_configs
368
+ )
369
+
370
+ # Wait for initialization
371
+ await asyncio.sleep(2)
372
+
373
+ # Example queries
374
+ queries = [
375
+ "Show me all users created in the last month", # Should route to SQL
376
+ "What's the average CPU usage over the last hour?", # Should route to InfluxDB
377
+ "Search for documents containing 'error' in the logs", # Should route to Elasticsearch
378
+ ]
379
+
380
+ for query in queries:
381
+ try:
382
+ result = await multi_agent.route_query_to_database(query)
383
+ print(f"Query: {query}")
384
+ print(f"Routed to: {result['routed_to']}")
385
+ print(f"Reason: {result['routing_reason']}")
386
+ print(f"Generated query: {result['query']}")
387
+ print("-" * 50)
388
+ except Exception as e:
389
+ print(f"Error processing query '{query}': {e}")
390
+
391
+ # Search across all databases
392
+ search_results = await multi_agent.search_across_databases("user")
393
+ print("Search results for 'user':")
394
+ for db_name, results in search_results.items():
395
+ print(f"{db_name}: {len(results)} results")
396
+
397
+ # Get database summary
398
+ summary = await multi_agent.get_database_summary()
399
+ print("Database summary:", json.dumps(summary, indent=2))
400
+
401
+ # Clean up
402
+ await multi_agent.close_all_connections()
403
+
404
+
405
+ async def example_individual_agent_usage():
406
+ """Example of using individual database agents."""
407
+
408
+ # SQL Agent example
409
+ print("=== SQL Agent Example ===")
410
+ sql_agent = create_sql_agent(
411
+ database_flavor='postgresql',
412
+ connection_string='postgresql://user:pass@localhost/db',
413
+ schema_name='public'
414
+ )
415
+
416
+ await sql_agent.initialize_schema()
417
+
418
+ sql_result = await sql_agent.generate_query(
419
+ "Find all orders with total amount greater than 1000"
420
+ )
421
+ print(f"SQL Query: {sql_result['query']}")
422
+
423
+ # InfluxDB Agent example
424
+ print("\n=== InfluxDB Agent Example ===")
425
+ influx_agent = create_influxdb_agent(
426
+ url='http://localhost:8086',
427
+ token='my-token',
428
+ org='my-org',
429
+ bucket='sensors'
430
+ )
431
+
432
+ await influx_agent.initialize_schema()
433
+
434
+ influx_result = await influx_agent.generate_query(
435
+ "Show average temperature by location over the last 24 hours"
436
+ )
437
+ print(f"Flux Query: {influx_result['query']}")
438
+
439
+ # Elasticsearch Agent example
440
+ print("\n=== Elasticsearch Agent Example ===")
441
+ es_agent = create_elasticsearch_agent(
442
+ url='http://localhost:9200',
443
+ username='elastic',
444
+ password='password'
445
+ )
446
+
447
+ await es_agent.initialize_schema()
448
+
449
+ es_result = await es_agent.generate_query(
450
+ "Find all log entries with status code 500 from the last hour"
451
+ )
452
+ print(f"Elasticsearch Query: {json.dumps(es_result['query'], indent=2)}")
453
+
454
+ # Clean up
455
+ await sql_agent.close()
456
+ await influx_agent.close()
457
+ await es_agent.close()
458
+
459
+
460
+ # Integration with AI-Parrot's existing components
461
+ class DatabaseAgentToolkit:
462
+ """
463
+ Toolkit for integrating database agents with AI-Parrot's tool system.
464
+ Provides a unified interface for database operations across different database types.
465
+ """
466
+
467
+ def __init__(self, multi_agent: MultiDatabaseAgent):
468
+ self.multi_agent = multi_agent
469
+
470
+ def get_tools(self) -> List:
471
+ """Get all database tools for use with AI-Parrot agents."""
472
+ class DatabaseQueryArgs(AbstractToolArgsSchema):
473
+ query: str = Field(description="Natural language database query")
474
+ database: Optional[str] = Field(default=None, description="Specific database to use")
475
+ execute: bool = Field(default=False, description="Whether to execute the generated query")
476
+
477
+ class DatabaseSearchArgs(AbstractToolArgsSchema):
478
+ search_term: str = Field(description="Term to search for in database schemas")
479
+ databases: Optional[List[str]] = Field(default=None, description="Specific databases to search")
480
+
481
+ class DatabaseQueryTool(AbstractTool):
482
+ """Tool for generating and executing database queries."""
483
+ name = "database_query"
484
+ description = "Generate and optionally execute database queries from natural language"
485
+ args_schema = DatabaseQueryArgs
486
+
487
+ def __init__(self, toolkit):
488
+ super().__init__()
489
+ self.toolkit = toolkit
490
+
491
+ async def _execute(
492
+ self,
493
+ query: str,
494
+ database: Optional[str] = None,
495
+ execute: bool = False
496
+ ) -> ToolResult:
497
+ try:
498
+ # Generate query
499
+ result = await self.toolkit.multi_agent.route_query_to_database(query, database)
500
+
501
+ if execute:
502
+ # Execute the generated query
503
+ routed_agent = self.toolkit.multi_agent.database_agents[result['routed_to']]
504
+ execution_result = await routed_agent.execute_query(result['query'])
505
+ result['execution_result'] = execution_result
506
+
507
+ return ToolResult(
508
+ status="success",
509
+ result=result,
510
+ metadata={
511
+ "natural_language_query": query,
512
+ "database_used": result.get('routed_to'),
513
+ "executed": execute
514
+ }
515
+ )
516
+ except Exception as e:
517
+ return ToolResult(
518
+ status="error",
519
+ result=None,
520
+ error=str(e),
521
+ metadata={"query": query}
522
+ )
523
+
524
+ class DatabaseSearchTool(AbstractTool):
525
+ """Tool for searching across multiple databases."""
526
+ name = "database_search"
527
+ description = "Search for tables, fields, and schema information across databases"
528
+ args_schema = DatabaseSearchArgs
529
+
530
+ def __init__(self, toolkit):
531
+ super().__init__()
532
+ self.toolkit = toolkit
533
+
534
+ async def _execute(
535
+ self,
536
+ search_term: str,
537
+ databases: Optional[List[str]] = None
538
+ ) -> ToolResult:
539
+ try:
540
+ results = await self.toolkit.multi_agent.search_across_databases(
541
+ search_term,
542
+ databases
543
+ )
544
+
545
+ return ToolResult(
546
+ status="success",
547
+ result=results,
548
+ metadata={
549
+ "search_term": search_term,
550
+ "databases_searched": list(results.keys()),
551
+ "total_results": sum(len(r) for r in results.values())
552
+ }
553
+ )
554
+ except Exception as e:
555
+ return ToolResult(
556
+ status="error",
557
+ result=None,
558
+ error=str(e),
559
+ metadata={"search_term": search_term}
560
+ )
561
+
562
+ return [
563
+ DatabaseQueryTool(self),
564
+ DatabaseSearchTool(self)
565
+ ]
566
+
567
+
568
+ # Configuration management
569
+ class DatabaseAgentConfig:
570
+ """Configuration management for database agents."""
571
+
572
+ def __init__(self, config_file: Optional[Path] = None):
573
+ self.config_file = config_file or Path("database_agents.json")
574
+ self.config_data = self._load_config()
575
+
576
+ def _load_config(self) -> Dict[str, Any]:
577
+ """Load configuration from file."""
578
+ if self.config_file.exists():
579
+ with open(self.config_file, 'r') as f:
580
+ return json.load(f)
581
+ return {"databases": {}, "settings": {}}
582
+
583
+ def save_config(self):
584
+ """Save configuration to file."""
585
+ with open(self.config_file, 'w') as f:
586
+ json.dump(self.config_data, f, indent=2)
587
+
588
+ def add_database(self, name: str, config: Dict[str, Any]):
589
+ """Add a database configuration."""
590
+ self.config_data["databases"][name] = config
591
+ self.save_config()
592
+
593
+ def remove_database(self, name: str):
594
+ """Remove a database configuration."""
595
+ if name in self.config_data["databases"]:
596
+ del self.config_data["databases"][name]
597
+ self.save_config()
598
+
599
+ def get_database_configs(self) -> Dict[str, Dict[str, Any]]:
600
+ """Get all database configurations."""
601
+ return self.config_data.get("databases", {})
602
+
603
+ def set_setting(self, key: str, value: Any):
604
+ """Set a configuration setting."""
605
+ if "settings" not in self.config_data:
606
+ self.config_data["settings"] = {}
607
+ self.config_data["settings"][key] = value
608
+ self.save_config()
609
+
610
+ def get_setting(self, key: str, default: Any = None) -> Any:
611
+ """Get a configuration setting."""
612
+ return self.config_data.get("settings", {}).get(key, default)
613
+
614
+
615
+ # Factory for creating agents from configuration
616
+ class DatabaseAgentFactory:
617
+ """Factory for creating database agents from configuration."""
618
+
619
+ @staticmethod
620
+ async def create_from_config(config_file: Optional[Path] = None) -> MultiDatabaseAgent:
621
+ """Create MultiDatabaseAgent from configuration file."""
622
+ config_manager = DatabaseAgentConfig(config_file)
623
+ db_configs = config_manager.get_database_configs()
624
+
625
+ if not db_configs:
626
+ raise ValueError("No database configurations found")
627
+
628
+ # Create knowledge store if configured
629
+ knowledge_store = None
630
+ knowledge_config = config_manager.get_setting("knowledge_store")
631
+ if knowledge_config:
632
+ knowledge_store = await DatabaseAgentFactory._create_knowledge_store(knowledge_config)
633
+
634
+ return MultiDatabaseAgent(
635
+ database_configs=db_configs,
636
+ knowledge_store=knowledge_store
637
+ )
638
+
639
+ @staticmethod
640
+ async def _create_knowledge_store(config: Dict[str, Any]):
641
+ """Create knowledge store from configuration."""
642
+ # This would integrate with AI-Parrot's existing store system
643
+
644
+ store_type = config.get("type", "pgvector")
645
+ if store_type in supported_stores:
646
+ store_class = supported_stores[store_type]
647
+ return store_class(**config.get("params", {}))
648
+
649
+ return None
650
+
651
+
652
+ # Example configuration file structure
653
+ EXAMPLE_CONFIG = {
654
+ "databases": {
655
+ "main_postgres": {
656
+ "type": "postgresql",
657
+ "connection_string": "postgresql://user:pass@localhost:5432/myapp",
658
+ "schema_name": "public"
659
+ },
660
+ "metrics_influx": {
661
+ "type": "influxdb",
662
+ "url": "http://localhost:8086",
663
+ "token": "${INFLUX_TOKEN}",
664
+ "org": "my-org",
665
+ "bucket": "metrics"
666
+ },
667
+ "logs_elastic": {
668
+ "type": "elasticsearch",
669
+ "url": "http://localhost:9200",
670
+ "username": "elastic",
671
+ "password": "${ELASTIC_PASSWORD}"
672
+ }
673
+ },
674
+ "settings": {
675
+ "knowledge_store": {
676
+ "type": "pgvector",
677
+ "params": {
678
+ "connection_string": "postgresql://user:pass@localhost:5432/knowledge",
679
+ "collection_name": "database_schemas"
680
+ }
681
+ },
682
+ "default_query_timeout": 30,
683
+ "max_sample_records": 10,
684
+ "auto_analyze_schema": True
685
+ }
686
+ }
687
+
688
+
689
+ # Integration with AI-Parrot's existing bot system
690
+ def integrate_with_parrot_bot(bot: AbstractBot, database_configs: Dict[str, Dict[str, Any]]):
691
+ """
692
+ Integrate database agents with an existing AI-Parrot bot.
693
+
694
+ Args:
695
+ bot: Existing AI-Parrot bot instance
696
+ database_configs: Database configurations
697
+ """
698
+ async def initialize_db_integration():
699
+ # Create multi-database agent
700
+ multi_agent = MultiDatabaseAgent(
701
+ name=f"{bot.name}_DatabaseAgent",
702
+ database_configs=database_configs,
703
+ knowledge_store=getattr(bot, 'knowledge_store', None)
704
+ )
705
+
706
+ # Wait for initialization
707
+ await asyncio.sleep(2)
708
+
709
+ # Create toolkit
710
+ toolkit = DatabaseAgentToolkit(multi_agent)
711
+
712
+ # Add database tools to the bot
713
+ for tool in toolkit.get_tools():
714
+ bot.add_tool(tool)
715
+
716
+ # Store reference for cleanup
717
+ bot._database_multi_agent = multi_agent
718
+
719
+ return multi_agent
720
+
721
+ # Add initialization as a startup task
722
+ asyncio.create_task(initialize_db_integration())
723
+
724
+
725
+ # Command-line interface for testing and management
726
+ async def cli_example():
727
+ """Example CLI interface for database agents."""
728
+ parser = argparse.ArgumentParser(description="Database Agents CLI")
729
+ parser.add_argument("--config", type=Path, help="Configuration file path")
730
+ parser.add_argument("--query", type=str, help="Natural language query to execute")
731
+ parser.add_argument("--search", type=str, help="Search term for schema exploration")
732
+ parser.add_argument("--list-databases", action="store_true", help="List all configured databases")
733
+ parser.add_argument("--execute", action="store_true", help="Execute generated queries")
734
+
735
+ args = parser.parse_args()
736
+
737
+ try:
738
+ # Create agent from configuration
739
+ multi_agent = await DatabaseAgentFactory.create_from_config(args.config)
740
+
741
+ if args.list_databases:
742
+ summary = await multi_agent.get_database_summary()
743
+ print("Configured Databases:")
744
+ for db_name, info in summary["databases"].items():
745
+ print(f" {db_name}: {info['type']} ({info['status']})")
746
+
747
+ if args.query:
748
+ print(f"Processing query: {args.query}")
749
+ result = await multi_agent.route_query_to_database(args.query)
750
+ print(f"Routed to: {result['routed_to']}")
751
+ print(f"Generated query: {result['query']}")
752
+
753
+ if args.execute:
754
+ agent = multi_agent.database_agents[result['routed_to']]
755
+ execution_result = await agent.execute_query(result['query'])
756
+ if execution_result.get('success'):
757
+ print(f"Results: {len(execution_result.get('data', []))} rows")
758
+ else:
759
+ print(f"Execution failed: {execution_result.get('error')}")
760
+
761
+ if args.search:
762
+ print(f"Searching for: {args.search}")
763
+ results = await multi_agent.search_across_databases(args.search)
764
+ for db_name, search_results in results.items():
765
+ print(f"{db_name}: {len(search_results)} matches")
766
+
767
+ await multi_agent.close_all_connections()
768
+
769
+ except Exception as e:
770
+ print(f"Error: {e}")
771
+
772
+
773
+ if __name__ == "__main__":
774
+ # Example usage
775
+ print("Database Agents Integration Example")
776
+ print("===================================")
777
+
778
+ # You can run different examples:
779
+ # asyncio.run(example_multi_database_usage())
780
+ # asyncio.run(example_individual_agent_usage())
781
+ # asyncio.run(cli_example())
782
+
783
+ print("Run with: python -m parrot.agents.database.integration --help")