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.
- agentui/.prettierrc +15 -0
- agentui/QUICKSTART.md +272 -0
- agentui/README.md +59 -0
- agentui/env.example +16 -0
- agentui/jsconfig.json +14 -0
- agentui/package-lock.json +4242 -0
- agentui/package.json +34 -0
- agentui/scripts/postinstall/apply-patches.mjs +260 -0
- agentui/src/app.css +61 -0
- agentui/src/app.d.ts +13 -0
- agentui/src/app.html +12 -0
- agentui/src/components/LoadingSpinner.svelte +64 -0
- agentui/src/components/ThemeSwitcher.svelte +159 -0
- agentui/src/components/index.js +4 -0
- agentui/src/lib/api/bots.ts +60 -0
- agentui/src/lib/api/chat.ts +22 -0
- agentui/src/lib/api/http.ts +25 -0
- agentui/src/lib/components/BotCard.svelte +33 -0
- agentui/src/lib/components/ChatBubble.svelte +63 -0
- agentui/src/lib/components/Toast.svelte +21 -0
- agentui/src/lib/config.ts +20 -0
- agentui/src/lib/stores/auth.svelte.ts +73 -0
- agentui/src/lib/stores/theme.svelte.js +64 -0
- agentui/src/lib/stores/toast.svelte.ts +31 -0
- agentui/src/lib/utils/conversation.ts +39 -0
- agentui/src/routes/+layout.svelte +20 -0
- agentui/src/routes/+page.svelte +232 -0
- agentui/src/routes/login/+page.svelte +200 -0
- agentui/src/routes/talk/[agentId]/+page.svelte +297 -0
- agentui/src/routes/talk/[agentId]/+page.ts +7 -0
- agentui/static/README.md +1 -0
- agentui/svelte.config.js +11 -0
- agentui/tailwind.config.ts +53 -0
- agentui/tsconfig.json +3 -0
- agentui/vite.config.ts +10 -0
- ai_parrot-0.17.2.dist-info/METADATA +472 -0
- ai_parrot-0.17.2.dist-info/RECORD +535 -0
- ai_parrot-0.17.2.dist-info/WHEEL +6 -0
- ai_parrot-0.17.2.dist-info/entry_points.txt +2 -0
- ai_parrot-0.17.2.dist-info/licenses/LICENSE +21 -0
- ai_parrot-0.17.2.dist-info/top_level.txt +6 -0
- crew-builder/.prettierrc +15 -0
- crew-builder/QUICKSTART.md +259 -0
- crew-builder/README.md +113 -0
- crew-builder/env.example +17 -0
- crew-builder/jsconfig.json +14 -0
- crew-builder/package-lock.json +4182 -0
- crew-builder/package.json +37 -0
- crew-builder/scripts/postinstall/apply-patches.mjs +260 -0
- crew-builder/src/app.css +62 -0
- crew-builder/src/app.d.ts +13 -0
- crew-builder/src/app.html +12 -0
- crew-builder/src/components/LoadingSpinner.svelte +64 -0
- crew-builder/src/components/ThemeSwitcher.svelte +149 -0
- crew-builder/src/components/index.js +9 -0
- crew-builder/src/lib/api/bots.ts +60 -0
- crew-builder/src/lib/api/chat.ts +80 -0
- crew-builder/src/lib/api/client.ts +56 -0
- crew-builder/src/lib/api/crew/crew.ts +136 -0
- crew-builder/src/lib/api/index.ts +5 -0
- crew-builder/src/lib/api/o365/auth.ts +65 -0
- crew-builder/src/lib/auth/auth.ts +54 -0
- crew-builder/src/lib/components/AgentNode.svelte +43 -0
- crew-builder/src/lib/components/BotCard.svelte +33 -0
- crew-builder/src/lib/components/ChatBubble.svelte +67 -0
- crew-builder/src/lib/components/ConfigPanel.svelte +278 -0
- crew-builder/src/lib/components/JsonTreeNode.svelte +76 -0
- crew-builder/src/lib/components/JsonViewer.svelte +24 -0
- crew-builder/src/lib/components/MarkdownEditor.svelte +48 -0
- crew-builder/src/lib/components/ThemeToggle.svelte +36 -0
- crew-builder/src/lib/components/Toast.svelte +67 -0
- crew-builder/src/lib/components/Toolbar.svelte +157 -0
- crew-builder/src/lib/components/index.ts +10 -0
- crew-builder/src/lib/config.ts +8 -0
- crew-builder/src/lib/stores/auth.svelte.ts +228 -0
- crew-builder/src/lib/stores/crewStore.ts +369 -0
- crew-builder/src/lib/stores/theme.svelte.js +145 -0
- crew-builder/src/lib/stores/toast.svelte.ts +69 -0
- crew-builder/src/lib/utils/conversation.ts +39 -0
- crew-builder/src/lib/utils/markdown.ts +122 -0
- crew-builder/src/lib/utils/talkHistory.ts +47 -0
- crew-builder/src/routes/+layout.svelte +20 -0
- crew-builder/src/routes/+page.svelte +539 -0
- crew-builder/src/routes/agents/+page.svelte +247 -0
- crew-builder/src/routes/agents/[agentId]/+page.svelte +288 -0
- crew-builder/src/routes/agents/[agentId]/+page.ts +7 -0
- crew-builder/src/routes/builder/+page.svelte +204 -0
- crew-builder/src/routes/crew/ask/+page.svelte +1052 -0
- crew-builder/src/routes/crew/ask/+page.ts +1 -0
- crew-builder/src/routes/integrations/o365/+page.svelte +304 -0
- crew-builder/src/routes/login/+page.svelte +197 -0
- crew-builder/src/routes/talk/[agentId]/+page.svelte +487 -0
- crew-builder/src/routes/talk/[agentId]/+page.ts +7 -0
- crew-builder/static/README.md +1 -0
- crew-builder/svelte.config.js +11 -0
- crew-builder/tailwind.config.ts +53 -0
- crew-builder/tsconfig.json +3 -0
- crew-builder/vite.config.ts +10 -0
- mcp_servers/calculator_server.py +309 -0
- parrot/__init__.py +27 -0
- parrot/__pycache__/__init__.cpython-310.pyc +0 -0
- parrot/__pycache__/version.cpython-310.pyc +0 -0
- parrot/_version.py +34 -0
- parrot/a2a/__init__.py +48 -0
- parrot/a2a/client.py +658 -0
- parrot/a2a/discovery.py +89 -0
- parrot/a2a/mixin.py +257 -0
- parrot/a2a/models.py +376 -0
- parrot/a2a/server.py +770 -0
- parrot/agents/__init__.py +29 -0
- parrot/bots/__init__.py +12 -0
- parrot/bots/a2a_agent.py +19 -0
- parrot/bots/abstract.py +3139 -0
- parrot/bots/agent.py +1129 -0
- parrot/bots/basic.py +9 -0
- parrot/bots/chatbot.py +669 -0
- parrot/bots/data.py +1618 -0
- parrot/bots/database/__init__.py +5 -0
- parrot/bots/database/abstract.py +3071 -0
- parrot/bots/database/cache.py +286 -0
- parrot/bots/database/models.py +468 -0
- parrot/bots/database/prompts.py +154 -0
- parrot/bots/database/retries.py +98 -0
- parrot/bots/database/router.py +269 -0
- parrot/bots/database/sql.py +41 -0
- parrot/bots/db/__init__.py +6 -0
- parrot/bots/db/abstract.py +556 -0
- parrot/bots/db/bigquery.py +602 -0
- parrot/bots/db/cache.py +85 -0
- parrot/bots/db/documentdb.py +668 -0
- parrot/bots/db/elastic.py +1014 -0
- parrot/bots/db/influx.py +898 -0
- parrot/bots/db/mock.py +96 -0
- parrot/bots/db/multi.py +783 -0
- parrot/bots/db/prompts.py +185 -0
- parrot/bots/db/sql.py +1255 -0
- parrot/bots/db/tools.py +212 -0
- parrot/bots/document.py +680 -0
- parrot/bots/hrbot.py +15 -0
- parrot/bots/kb.py +170 -0
- parrot/bots/mcp.py +36 -0
- parrot/bots/orchestration/README.md +463 -0
- parrot/bots/orchestration/__init__.py +1 -0
- parrot/bots/orchestration/agent.py +155 -0
- parrot/bots/orchestration/crew.py +3330 -0
- parrot/bots/orchestration/fsm.py +1179 -0
- parrot/bots/orchestration/hr.py +434 -0
- parrot/bots/orchestration/storage/__init__.py +4 -0
- parrot/bots/orchestration/storage/memory.py +100 -0
- parrot/bots/orchestration/storage/mixin.py +119 -0
- parrot/bots/orchestration/verify.py +202 -0
- parrot/bots/product.py +204 -0
- parrot/bots/prompts/__init__.py +96 -0
- parrot/bots/prompts/agents.py +155 -0
- parrot/bots/prompts/data.py +216 -0
- parrot/bots/prompts/output_generation.py +8 -0
- parrot/bots/scraper/__init__.py +3 -0
- parrot/bots/scraper/models.py +122 -0
- parrot/bots/scraper/scraper.py +1173 -0
- parrot/bots/scraper/templates.py +115 -0
- parrot/bots/stores/__init__.py +5 -0
- parrot/bots/stores/local.py +172 -0
- parrot/bots/webdev.py +81 -0
- parrot/cli.py +17 -0
- parrot/clients/__init__.py +16 -0
- parrot/clients/base.py +1491 -0
- parrot/clients/claude.py +1191 -0
- parrot/clients/factory.py +129 -0
- parrot/clients/google.py +4567 -0
- parrot/clients/gpt.py +1975 -0
- parrot/clients/grok.py +432 -0
- parrot/clients/groq.py +986 -0
- parrot/clients/hf.py +582 -0
- parrot/clients/models.py +18 -0
- parrot/conf.py +395 -0
- parrot/embeddings/__init__.py +9 -0
- parrot/embeddings/base.py +157 -0
- parrot/embeddings/google.py +98 -0
- parrot/embeddings/huggingface.py +74 -0
- parrot/embeddings/openai.py +84 -0
- parrot/embeddings/processor.py +88 -0
- parrot/exceptions.c +13868 -0
- parrot/exceptions.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/exceptions.pxd +22 -0
- parrot/exceptions.pxi +15 -0
- parrot/exceptions.pyx +44 -0
- parrot/generators/__init__.py +29 -0
- parrot/generators/base.py +200 -0
- parrot/generators/html.py +293 -0
- parrot/generators/react.py +205 -0
- parrot/generators/streamlit.py +203 -0
- parrot/generators/template.py +105 -0
- parrot/handlers/__init__.py +4 -0
- parrot/handlers/agent.py +861 -0
- parrot/handlers/agents/__init__.py +1 -0
- parrot/handlers/agents/abstract.py +900 -0
- parrot/handlers/bots.py +338 -0
- parrot/handlers/chat.py +915 -0
- parrot/handlers/creation.sql +192 -0
- parrot/handlers/crew/ARCHITECTURE.md +362 -0
- parrot/handlers/crew/README_BOTMANAGER_PERSISTENCE.md +303 -0
- parrot/handlers/crew/README_REDIS_PERSISTENCE.md +366 -0
- parrot/handlers/crew/__init__.py +0 -0
- parrot/handlers/crew/handler.py +801 -0
- parrot/handlers/crew/models.py +229 -0
- parrot/handlers/crew/redis_persistence.py +523 -0
- parrot/handlers/jobs/__init__.py +10 -0
- parrot/handlers/jobs/job.py +384 -0
- parrot/handlers/jobs/mixin.py +627 -0
- parrot/handlers/jobs/models.py +115 -0
- parrot/handlers/jobs/worker.py +31 -0
- parrot/handlers/models.py +596 -0
- parrot/handlers/o365_auth.py +105 -0
- parrot/handlers/stream.py +337 -0
- parrot/interfaces/__init__.py +6 -0
- parrot/interfaces/aws.py +143 -0
- parrot/interfaces/credentials.py +113 -0
- parrot/interfaces/database.py +27 -0
- parrot/interfaces/google.py +1123 -0
- parrot/interfaces/hierarchy.py +1227 -0
- parrot/interfaces/http.py +651 -0
- parrot/interfaces/images/__init__.py +0 -0
- parrot/interfaces/images/plugins/__init__.py +24 -0
- parrot/interfaces/images/plugins/abstract.py +58 -0
- parrot/interfaces/images/plugins/analisys.py +148 -0
- parrot/interfaces/images/plugins/classify.py +150 -0
- parrot/interfaces/images/plugins/classifybase.py +182 -0
- parrot/interfaces/images/plugins/detect.py +150 -0
- parrot/interfaces/images/plugins/exif.py +1103 -0
- parrot/interfaces/images/plugins/hash.py +52 -0
- parrot/interfaces/images/plugins/vision.py +104 -0
- parrot/interfaces/images/plugins/yolo.py +66 -0
- parrot/interfaces/images/plugins/zerodetect.py +197 -0
- parrot/interfaces/o365.py +978 -0
- parrot/interfaces/onedrive.py +822 -0
- parrot/interfaces/sharepoint.py +1435 -0
- parrot/interfaces/soap.py +257 -0
- parrot/loaders/__init__.py +8 -0
- parrot/loaders/abstract.py +1131 -0
- parrot/loaders/audio.py +199 -0
- parrot/loaders/basepdf.py +53 -0
- parrot/loaders/basevideo.py +1568 -0
- parrot/loaders/csv.py +409 -0
- parrot/loaders/docx.py +116 -0
- parrot/loaders/epubloader.py +316 -0
- parrot/loaders/excel.py +199 -0
- parrot/loaders/factory.py +55 -0
- parrot/loaders/files/__init__.py +0 -0
- parrot/loaders/files/abstract.py +39 -0
- parrot/loaders/files/html.py +26 -0
- parrot/loaders/files/text.py +63 -0
- parrot/loaders/html.py +152 -0
- parrot/loaders/markdown.py +442 -0
- parrot/loaders/pdf.py +373 -0
- parrot/loaders/pdfmark.py +320 -0
- parrot/loaders/pdftables.py +506 -0
- parrot/loaders/ppt.py +476 -0
- parrot/loaders/qa.py +63 -0
- parrot/loaders/splitters/__init__.py +10 -0
- parrot/loaders/splitters/base.py +138 -0
- parrot/loaders/splitters/md.py +228 -0
- parrot/loaders/splitters/token.py +143 -0
- parrot/loaders/txt.py +26 -0
- parrot/loaders/video.py +89 -0
- parrot/loaders/videolocal.py +218 -0
- parrot/loaders/videounderstanding.py +377 -0
- parrot/loaders/vimeo.py +167 -0
- parrot/loaders/web.py +599 -0
- parrot/loaders/youtube.py +504 -0
- parrot/manager/__init__.py +5 -0
- parrot/manager/manager.py +1030 -0
- parrot/mcp/__init__.py +28 -0
- parrot/mcp/adapter.py +105 -0
- parrot/mcp/cli.py +174 -0
- parrot/mcp/client.py +119 -0
- parrot/mcp/config.py +75 -0
- parrot/mcp/integration.py +842 -0
- parrot/mcp/oauth.py +933 -0
- parrot/mcp/server.py +225 -0
- parrot/mcp/transports/__init__.py +3 -0
- parrot/mcp/transports/base.py +279 -0
- parrot/mcp/transports/grpc_session.py +163 -0
- parrot/mcp/transports/http.py +312 -0
- parrot/mcp/transports/mcp.proto +108 -0
- parrot/mcp/transports/quic.py +1082 -0
- parrot/mcp/transports/sse.py +330 -0
- parrot/mcp/transports/stdio.py +309 -0
- parrot/mcp/transports/unix.py +395 -0
- parrot/mcp/transports/websocket.py +547 -0
- parrot/memory/__init__.py +16 -0
- parrot/memory/abstract.py +209 -0
- parrot/memory/agent.py +32 -0
- parrot/memory/cache.py +175 -0
- parrot/memory/core.py +555 -0
- parrot/memory/file.py +153 -0
- parrot/memory/mem.py +131 -0
- parrot/memory/redis.py +613 -0
- parrot/models/__init__.py +46 -0
- parrot/models/basic.py +118 -0
- parrot/models/compliance.py +208 -0
- parrot/models/crew.py +395 -0
- parrot/models/detections.py +654 -0
- parrot/models/generation.py +85 -0
- parrot/models/google.py +223 -0
- parrot/models/groq.py +23 -0
- parrot/models/openai.py +30 -0
- parrot/models/outputs.py +285 -0
- parrot/models/responses.py +938 -0
- parrot/notifications/__init__.py +743 -0
- parrot/openapi/__init__.py +3 -0
- parrot/openapi/components.yaml +641 -0
- parrot/openapi/config.py +322 -0
- parrot/outputs/__init__.py +32 -0
- parrot/outputs/formats/__init__.py +108 -0
- parrot/outputs/formats/altair.py +359 -0
- parrot/outputs/formats/application.py +122 -0
- parrot/outputs/formats/base.py +351 -0
- parrot/outputs/formats/bokeh.py +356 -0
- parrot/outputs/formats/card.py +424 -0
- parrot/outputs/formats/chart.py +436 -0
- parrot/outputs/formats/d3.py +255 -0
- parrot/outputs/formats/echarts.py +310 -0
- parrot/outputs/formats/generators/__init__.py +0 -0
- parrot/outputs/formats/generators/abstract.py +61 -0
- parrot/outputs/formats/generators/panel.py +145 -0
- parrot/outputs/formats/generators/streamlit.py +86 -0
- parrot/outputs/formats/generators/terminal.py +63 -0
- parrot/outputs/formats/holoviews.py +310 -0
- parrot/outputs/formats/html.py +147 -0
- parrot/outputs/formats/jinja2.py +46 -0
- parrot/outputs/formats/json.py +87 -0
- parrot/outputs/formats/map.py +933 -0
- parrot/outputs/formats/markdown.py +172 -0
- parrot/outputs/formats/matplotlib.py +237 -0
- parrot/outputs/formats/mixins/__init__.py +0 -0
- parrot/outputs/formats/mixins/emaps.py +855 -0
- parrot/outputs/formats/plotly.py +341 -0
- parrot/outputs/formats/seaborn.py +310 -0
- parrot/outputs/formats/table.py +397 -0
- parrot/outputs/formats/template_report.py +138 -0
- parrot/outputs/formats/yaml.py +125 -0
- parrot/outputs/formatter.py +152 -0
- parrot/outputs/templates/__init__.py +95 -0
- parrot/pipelines/__init__.py +0 -0
- parrot/pipelines/abstract.py +210 -0
- parrot/pipelines/detector.py +124 -0
- parrot/pipelines/models.py +90 -0
- parrot/pipelines/planogram.py +3002 -0
- parrot/pipelines/table.sql +97 -0
- parrot/plugins/__init__.py +106 -0
- parrot/plugins/importer.py +80 -0
- parrot/py.typed +0 -0
- parrot/registry/__init__.py +18 -0
- parrot/registry/registry.py +594 -0
- parrot/scheduler/__init__.py +1189 -0
- parrot/scheduler/models.py +60 -0
- parrot/security/__init__.py +16 -0
- parrot/security/prompt_injection.py +268 -0
- parrot/security/security_events.sql +25 -0
- parrot/services/__init__.py +1 -0
- parrot/services/mcp/__init__.py +8 -0
- parrot/services/mcp/config.py +13 -0
- parrot/services/mcp/server.py +295 -0
- parrot/services/o365_remote_auth.py +235 -0
- parrot/stores/__init__.py +7 -0
- parrot/stores/abstract.py +352 -0
- parrot/stores/arango.py +1090 -0
- parrot/stores/bigquery.py +1377 -0
- parrot/stores/cache.py +106 -0
- parrot/stores/empty.py +10 -0
- parrot/stores/faiss_store.py +1157 -0
- parrot/stores/kb/__init__.py +9 -0
- parrot/stores/kb/abstract.py +68 -0
- parrot/stores/kb/cache.py +165 -0
- parrot/stores/kb/doc.py +325 -0
- parrot/stores/kb/hierarchy.py +346 -0
- parrot/stores/kb/local.py +457 -0
- parrot/stores/kb/prompt.py +28 -0
- parrot/stores/kb/redis.py +659 -0
- parrot/stores/kb/store.py +115 -0
- parrot/stores/kb/user.py +374 -0
- parrot/stores/models.py +59 -0
- parrot/stores/pgvector.py +3 -0
- parrot/stores/postgres.py +2853 -0
- parrot/stores/utils/__init__.py +0 -0
- parrot/stores/utils/chunking.py +197 -0
- parrot/telemetry/__init__.py +3 -0
- parrot/telemetry/mixin.py +111 -0
- parrot/template/__init__.py +3 -0
- parrot/template/engine.py +259 -0
- parrot/tools/__init__.py +23 -0
- parrot/tools/abstract.py +644 -0
- parrot/tools/agent.py +363 -0
- parrot/tools/arangodbsearch.py +537 -0
- parrot/tools/arxiv_tool.py +188 -0
- parrot/tools/calculator/__init__.py +3 -0
- parrot/tools/calculator/operations/__init__.py +38 -0
- parrot/tools/calculator/operations/calculus.py +80 -0
- parrot/tools/calculator/operations/statistics.py +76 -0
- parrot/tools/calculator/tool.py +150 -0
- parrot/tools/cloudwatch.py +988 -0
- parrot/tools/codeinterpreter/__init__.py +127 -0
- parrot/tools/codeinterpreter/executor.py +371 -0
- parrot/tools/codeinterpreter/internals.py +473 -0
- parrot/tools/codeinterpreter/models.py +643 -0
- parrot/tools/codeinterpreter/prompts.py +224 -0
- parrot/tools/codeinterpreter/tool.py +664 -0
- parrot/tools/company_info/__init__.py +6 -0
- parrot/tools/company_info/tool.py +1138 -0
- parrot/tools/correlationanalysis.py +437 -0
- parrot/tools/database/abstract.py +286 -0
- parrot/tools/database/bq.py +115 -0
- parrot/tools/database/cache.py +284 -0
- parrot/tools/database/models.py +95 -0
- parrot/tools/database/pg.py +343 -0
- parrot/tools/databasequery.py +1159 -0
- parrot/tools/db.py +1800 -0
- parrot/tools/ddgo.py +370 -0
- parrot/tools/decorators.py +271 -0
- parrot/tools/dftohtml.py +282 -0
- parrot/tools/document.py +549 -0
- parrot/tools/ecs.py +819 -0
- parrot/tools/edareport.py +368 -0
- parrot/tools/elasticsearch.py +1049 -0
- parrot/tools/employees.py +462 -0
- parrot/tools/epson/__init__.py +96 -0
- parrot/tools/excel.py +683 -0
- parrot/tools/file/__init__.py +13 -0
- parrot/tools/file/abstract.py +76 -0
- parrot/tools/file/gcs.py +378 -0
- parrot/tools/file/local.py +284 -0
- parrot/tools/file/s3.py +511 -0
- parrot/tools/file/tmp.py +309 -0
- parrot/tools/file/tool.py +501 -0
- parrot/tools/file_reader.py +129 -0
- parrot/tools/flowtask/__init__.py +19 -0
- parrot/tools/flowtask/tool.py +761 -0
- parrot/tools/gittoolkit.py +508 -0
- parrot/tools/google/__init__.py +18 -0
- parrot/tools/google/base.py +169 -0
- parrot/tools/google/tools.py +1251 -0
- parrot/tools/googlelocation.py +5 -0
- parrot/tools/googleroutes.py +5 -0
- parrot/tools/googlesearch.py +5 -0
- parrot/tools/googlesitesearch.py +5 -0
- parrot/tools/googlevoice.py +2 -0
- parrot/tools/gvoice.py +695 -0
- parrot/tools/ibisworld/README.md +225 -0
- parrot/tools/ibisworld/__init__.py +11 -0
- parrot/tools/ibisworld/tool.py +366 -0
- parrot/tools/jiratoolkit.py +1718 -0
- parrot/tools/manager.py +1098 -0
- parrot/tools/math.py +152 -0
- parrot/tools/metadata.py +476 -0
- parrot/tools/msteams.py +1621 -0
- parrot/tools/msword.py +635 -0
- parrot/tools/multidb.py +580 -0
- parrot/tools/multistoresearch.py +369 -0
- parrot/tools/networkninja.py +167 -0
- parrot/tools/nextstop/__init__.py +4 -0
- parrot/tools/nextstop/base.py +286 -0
- parrot/tools/nextstop/employee.py +733 -0
- parrot/tools/nextstop/store.py +462 -0
- parrot/tools/notification.py +435 -0
- parrot/tools/o365/__init__.py +42 -0
- parrot/tools/o365/base.py +295 -0
- parrot/tools/o365/bundle.py +522 -0
- parrot/tools/o365/events.py +554 -0
- parrot/tools/o365/mail.py +992 -0
- parrot/tools/o365/onedrive.py +497 -0
- parrot/tools/o365/sharepoint.py +641 -0
- parrot/tools/openapi_toolkit.py +904 -0
- parrot/tools/openweather.py +527 -0
- parrot/tools/pdfprint.py +1001 -0
- parrot/tools/powerbi.py +518 -0
- parrot/tools/powerpoint.py +1113 -0
- parrot/tools/pricestool.py +146 -0
- parrot/tools/products/__init__.py +246 -0
- parrot/tools/prophet_tool.py +171 -0
- parrot/tools/pythonpandas.py +630 -0
- parrot/tools/pythonrepl.py +910 -0
- parrot/tools/qsource.py +436 -0
- parrot/tools/querytoolkit.py +395 -0
- parrot/tools/quickeda.py +827 -0
- parrot/tools/resttool.py +553 -0
- parrot/tools/retail/__init__.py +0 -0
- parrot/tools/retail/bby.py +528 -0
- parrot/tools/sandboxtool.py +703 -0
- parrot/tools/sassie/__init__.py +352 -0
- parrot/tools/scraping/__init__.py +7 -0
- parrot/tools/scraping/docs/select.md +466 -0
- parrot/tools/scraping/documentation.md +1278 -0
- parrot/tools/scraping/driver.py +436 -0
- parrot/tools/scraping/models.py +576 -0
- parrot/tools/scraping/options.py +85 -0
- parrot/tools/scraping/orchestrator.py +517 -0
- parrot/tools/scraping/readme.md +740 -0
- parrot/tools/scraping/tool.py +3115 -0
- parrot/tools/seasonaldetection.py +642 -0
- parrot/tools/shell_tool/__init__.py +5 -0
- parrot/tools/shell_tool/actions.py +408 -0
- parrot/tools/shell_tool/engine.py +155 -0
- parrot/tools/shell_tool/models.py +322 -0
- parrot/tools/shell_tool/tool.py +442 -0
- parrot/tools/site_search.py +214 -0
- parrot/tools/textfile.py +418 -0
- parrot/tools/think.py +378 -0
- parrot/tools/toolkit.py +298 -0
- parrot/tools/webapp_tool.py +187 -0
- parrot/tools/whatif.py +1279 -0
- parrot/tools/workday/MULTI_WSDL_EXAMPLE.md +249 -0
- parrot/tools/workday/__init__.py +6 -0
- parrot/tools/workday/models.py +1389 -0
- parrot/tools/workday/tool.py +1293 -0
- parrot/tools/yfinance_tool.py +306 -0
- parrot/tools/zipcode.py +217 -0
- parrot/utils/__init__.py +2 -0
- parrot/utils/helpers.py +73 -0
- parrot/utils/parsers/__init__.py +5 -0
- parrot/utils/parsers/toml.c +12078 -0
- parrot/utils/parsers/toml.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/utils/parsers/toml.pyx +21 -0
- parrot/utils/toml.py +11 -0
- parrot/utils/types.cpp +20936 -0
- parrot/utils/types.cpython-310-x86_64-linux-gnu.so +0 -0
- parrot/utils/types.pyx +213 -0
- parrot/utils/uv.py +11 -0
- parrot/version.py +10 -0
- parrot/yaml-rs/Cargo.lock +350 -0
- parrot/yaml-rs/Cargo.toml +19 -0
- parrot/yaml-rs/pyproject.toml +19 -0
- parrot/yaml-rs/python/yaml_rs/__init__.py +81 -0
- parrot/yaml-rs/src/lib.rs +222 -0
- requirements/docker-compose.yml +24 -0
- requirements/requirements-dev.txt +21 -0
parrot/bots/db/multi.py
ADDED
|
@@ -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")
|