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
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Database Agent Architecture for AI-Parrot.
|
|
3
|
+
|
|
4
|
+
This module provides an abstract base for database introspection agents
|
|
5
|
+
that can analyze database schemas and generate queries from natural language.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from abc import abstractmethod
|
|
9
|
+
from typing import Dict, Any, List, Optional, Union
|
|
10
|
+
import uuid
|
|
11
|
+
import json
|
|
12
|
+
import asyncio
|
|
13
|
+
from string import Template
|
|
14
|
+
from sqlalchemy.ext.asyncio import AsyncEngine
|
|
15
|
+
from ..abstract import AbstractBot
|
|
16
|
+
from ...tools.manager import (
|
|
17
|
+
ToolManager,
|
|
18
|
+
)
|
|
19
|
+
from ...stores.abstract import AbstractStore
|
|
20
|
+
from .prompts import DB_AGENT_PROMPT, BASIC_HUMAN_PROMPT
|
|
21
|
+
from .tools import (
|
|
22
|
+
SchemaSearchTool,
|
|
23
|
+
QueryGenerationTool,
|
|
24
|
+
DatabaseSchema,
|
|
25
|
+
TableMetadata,
|
|
26
|
+
ExplainQueryTool,
|
|
27
|
+
)
|
|
28
|
+
from ...models import AIMessage
|
|
29
|
+
from ...tools.databasequery import DatabaseQueryTool
|
|
30
|
+
from .cache import SchemaCache
|
|
31
|
+
from ...memory import ConversationTurn
|
|
32
|
+
|
|
33
|
+
class AbstractDBAgent(AbstractBot):
|
|
34
|
+
"""
|
|
35
|
+
Abstract base class for database introspection agents.
|
|
36
|
+
|
|
37
|
+
This agent analyzes database schemas, stores metadata in a knowledge base,
|
|
38
|
+
and generates queries from natural language descriptions.
|
|
39
|
+
"""
|
|
40
|
+
system_prompt_template: str = DB_AGENT_PROMPT
|
|
41
|
+
human_prompt_template = BASIC_HUMAN_PROMPT
|
|
42
|
+
_default_temperature: float = 0.0
|
|
43
|
+
max_tokens: int = 8192
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
name: str = "DatabaseAgent",
|
|
48
|
+
credentials: Union[str, Dict[str, Any]] = None,
|
|
49
|
+
schema_name: Optional[str] = None,
|
|
50
|
+
knowledge_store: AbstractStore = None,
|
|
51
|
+
auto_analyze_schema: bool = True,
|
|
52
|
+
cache_ttl: int = 3600, # Cache TTL in seconds
|
|
53
|
+
**kwargs
|
|
54
|
+
):
|
|
55
|
+
"""
|
|
56
|
+
Initialize the database agent.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
name: Agent name
|
|
60
|
+
credentials: Database connection credentials
|
|
61
|
+
schema_name: Target schema name (optional)
|
|
62
|
+
knowledge_store: Vector store for schema metadata
|
|
63
|
+
auto_analyze_schema: Whether to automatically analyze schema on init
|
|
64
|
+
"""
|
|
65
|
+
kwargs.setdefault('temperature', self._default_temperature)
|
|
66
|
+
super().__init__(name=name, **kwargs)
|
|
67
|
+
self.role = kwargs.get(
|
|
68
|
+
'role', 'Database Analysis Assistant'
|
|
69
|
+
)
|
|
70
|
+
self.goal = kwargs.get(
|
|
71
|
+
'goal', 'Help users interact with databases using natural language'
|
|
72
|
+
)
|
|
73
|
+
self.capabilities = kwargs.get(
|
|
74
|
+
'capabilities',
|
|
75
|
+
'Database schema analysis, query generation, and data retrieval'
|
|
76
|
+
)
|
|
77
|
+
self.backstory = kwargs.get(
|
|
78
|
+
'backstory',
|
|
79
|
+
'Expert database assistant with deep knowledge of SQL and data analysis'
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
self.credentials = credentials
|
|
83
|
+
self.schema_name = schema_name
|
|
84
|
+
self.knowledge_store = knowledge_store
|
|
85
|
+
# Schema cache for metadata
|
|
86
|
+
self.cache = SchemaCache(ttl=cache_ttl)
|
|
87
|
+
self.auto_analyze_schema = auto_analyze_schema
|
|
88
|
+
|
|
89
|
+
# Initialize database-specific components
|
|
90
|
+
self.engine: Optional[AsyncEngine] = None
|
|
91
|
+
self.schema_metadata: Optional[DatabaseSchema] = None
|
|
92
|
+
|
|
93
|
+
# Initialize tool manager
|
|
94
|
+
self.tool_manager = ToolManager(
|
|
95
|
+
logger=self.logger,
|
|
96
|
+
debug=self._debug
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Add database-specific tools
|
|
100
|
+
self._setup_database_tools()
|
|
101
|
+
try:
|
|
102
|
+
self.loop = asyncio.get_running_loop()
|
|
103
|
+
except RuntimeError:
|
|
104
|
+
raise RuntimeError(
|
|
105
|
+
"An event loop is required to initialize the AbstractDBAgent."
|
|
106
|
+
)
|
|
107
|
+
asyncio.set_event_loop(self.loop)
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def tools(self):
|
|
111
|
+
"""Get list of registered tools from manager."""
|
|
112
|
+
return self.tool_manager.get_all_tools() if self.tool_manager else []
|
|
113
|
+
|
|
114
|
+
async def initialize_schema(self):
|
|
115
|
+
"""Initialize database connection and analyze schema."""
|
|
116
|
+
try:
|
|
117
|
+
await self.connect_database()
|
|
118
|
+
self.schema_metadata = await self.extract_schema_metadata()
|
|
119
|
+
|
|
120
|
+
if self.knowledge_store:
|
|
121
|
+
await self.store_schema_in_knowledge_base()
|
|
122
|
+
|
|
123
|
+
except Exception as e:
|
|
124
|
+
self.logger.error(
|
|
125
|
+
f"Failed to initialize schema: {e}"
|
|
126
|
+
)
|
|
127
|
+
raise
|
|
128
|
+
|
|
129
|
+
def _setup_database_tools(self):
|
|
130
|
+
"""Setup database-specific tools."""
|
|
131
|
+
# Add schema search tool
|
|
132
|
+
schema_search_tool = SchemaSearchTool(agent=self)
|
|
133
|
+
self.tool_manager.register_tool(schema_search_tool)
|
|
134
|
+
|
|
135
|
+
# Add query generation tool
|
|
136
|
+
query_gen_tool = QueryGenerationTool(agent=self)
|
|
137
|
+
self.tool_manager.register_tool(query_gen_tool)
|
|
138
|
+
|
|
139
|
+
# Add database query tool
|
|
140
|
+
db_query_tool = DatabaseQueryTool(agent=self)
|
|
141
|
+
self.tool_manager.register_tool(db_query_tool)
|
|
142
|
+
|
|
143
|
+
# Add explain query tool
|
|
144
|
+
explain_query_tool = ExplainQueryTool(agent=self)
|
|
145
|
+
self.tool_manager.register_tool(explain_query_tool)
|
|
146
|
+
|
|
147
|
+
async def configure(self, app=None) -> None:
|
|
148
|
+
"""Configure the database agent."""
|
|
149
|
+
await super().configure(app)
|
|
150
|
+
await self.initialize_schema()
|
|
151
|
+
|
|
152
|
+
def _define_prompt(self, config: Optional[dict] = None, **kwargs):
|
|
153
|
+
"""
|
|
154
|
+
Define the System Prompt and replace variables.
|
|
155
|
+
"""
|
|
156
|
+
# setup the prompt variables:
|
|
157
|
+
if config:
|
|
158
|
+
for key, val in config.items():
|
|
159
|
+
setattr(self, key, val)
|
|
160
|
+
|
|
161
|
+
tmpl = Template(self.system_prompt_template)
|
|
162
|
+
final_prompt = tmpl.safe_substitute(
|
|
163
|
+
name=self.name,
|
|
164
|
+
role=getattr(self, 'role', 'Database Analysis Assistant'),
|
|
165
|
+
goal=getattr(self, 'goal', 'Help users interact with databases using natural language'),
|
|
166
|
+
capabilities=getattr(self, 'capabilities', 'Database schema analysis, query generation, and data retrieval'),
|
|
167
|
+
backstory=getattr(self, 'backstory', 'Expert database assistant with deep knowledge of SQL and data analysis'),
|
|
168
|
+
rationale=getattr(self, 'rationale', 'Providing precise and helpful database interactions'),
|
|
169
|
+
**kwargs
|
|
170
|
+
)
|
|
171
|
+
self.system_prompt_template = final_prompt
|
|
172
|
+
|
|
173
|
+
async def create_system_prompt(
|
|
174
|
+
self,
|
|
175
|
+
user_context: str = "",
|
|
176
|
+
context: str = "",
|
|
177
|
+
vector_context: str = "",
|
|
178
|
+
pre_context: str = "",
|
|
179
|
+
conversation_context: str = "",
|
|
180
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
181
|
+
**kwargs
|
|
182
|
+
) -> str:
|
|
183
|
+
"""
|
|
184
|
+
Create the complete system prompt for the LLM with user context support.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
user_context: User-specific context for the database interaction
|
|
188
|
+
vector_context: Vector store context
|
|
189
|
+
conversation_context: Previous conversation context
|
|
190
|
+
metadata: Additional metadata
|
|
191
|
+
**kwargs: Additional template variables
|
|
192
|
+
"""
|
|
193
|
+
# Process contexts
|
|
194
|
+
context_parts = []
|
|
195
|
+
|
|
196
|
+
# Add user context if provided
|
|
197
|
+
if user_context:
|
|
198
|
+
context_parts.append(f"""
|
|
199
|
+
Use the following information about user's data to guide your responses:
|
|
200
|
+
**User Context:**
|
|
201
|
+
{user_context}
|
|
202
|
+
Based on the user context above, please tailor your response to their specific:
|
|
203
|
+
- Role and responsibilities
|
|
204
|
+
- Technical expertise level
|
|
205
|
+
- Business objectives
|
|
206
|
+
- Preferred communication style
|
|
207
|
+
""")
|
|
208
|
+
if context:
|
|
209
|
+
context_parts.append(f"**Additional Context:**\n{context}")
|
|
210
|
+
|
|
211
|
+
# Add vector context
|
|
212
|
+
if vector_context:
|
|
213
|
+
context_parts.append(f"**Database Context:**\n{vector_context}")
|
|
214
|
+
|
|
215
|
+
# Add metadata
|
|
216
|
+
if metadata:
|
|
217
|
+
metadata_text = "**Database Metadata:**\n"
|
|
218
|
+
for key, value in metadata.items():
|
|
219
|
+
if key == 'sources' and isinstance(value, list):
|
|
220
|
+
metadata_text += f"- {key}: {', '.join(value[:3])}{'...' if len(value) > 3 else ''}\n"
|
|
221
|
+
else:
|
|
222
|
+
metadata_text += f"- {key}: {value}\n"
|
|
223
|
+
context_parts.append(metadata_text)
|
|
224
|
+
|
|
225
|
+
# Format conversation context
|
|
226
|
+
chat_history_section = ""
|
|
227
|
+
if conversation_context:
|
|
228
|
+
chat_history_section = f"**Conversation History:**\n{conversation_context}"
|
|
229
|
+
|
|
230
|
+
# Database-specific context
|
|
231
|
+
db_context_parts = []
|
|
232
|
+
if self.schema_metadata:
|
|
233
|
+
db_info = f"**Database Information:**\n"
|
|
234
|
+
db_info += f"- Database: {self.schema_metadata.database_name}\n"
|
|
235
|
+
db_info += f"- Type: {self.schema_metadata.database_type}\n"
|
|
236
|
+
db_info += f"- Tables: {len(self.schema_metadata.tables)}\n"
|
|
237
|
+
db_info += f"- Views: {len(self.schema_metadata.views)}\n"
|
|
238
|
+
db_context_parts.append(db_info)
|
|
239
|
+
|
|
240
|
+
# Apply template substitution
|
|
241
|
+
tmpl = Template(self.system_prompt_template)
|
|
242
|
+
system_prompt = tmpl.safe_substitute(
|
|
243
|
+
user_context=user_context,
|
|
244
|
+
pre_context=pre_context,
|
|
245
|
+
context="\n\n".join(context_parts) if context_parts else "",
|
|
246
|
+
database_context="\n\n".join(db_context_parts) if db_context_parts else "",
|
|
247
|
+
chat_history=chat_history_section,
|
|
248
|
+
**kwargs
|
|
249
|
+
)
|
|
250
|
+
return system_prompt
|
|
251
|
+
|
|
252
|
+
async def cleanup(self) -> None:
|
|
253
|
+
"""Cleanup resources including cache connections."""
|
|
254
|
+
await self.cache.close()
|
|
255
|
+
await super().cleanup() if hasattr(super(), 'cleanup') else None
|
|
256
|
+
|
|
257
|
+
@abstractmethod
|
|
258
|
+
async def connect_database(self) -> None:
|
|
259
|
+
"""Connect to the database. Must be implemented by subclasses."""
|
|
260
|
+
pass
|
|
261
|
+
|
|
262
|
+
@abstractmethod
|
|
263
|
+
async def extract_schema_metadata(self) -> DatabaseSchema:
|
|
264
|
+
"""
|
|
265
|
+
Extract complete schema metadata from the database.
|
|
266
|
+
Must be implemented by subclasses based on database type.
|
|
267
|
+
"""
|
|
268
|
+
pass
|
|
269
|
+
|
|
270
|
+
@abstractmethod
|
|
271
|
+
async def generate_query(
|
|
272
|
+
self,
|
|
273
|
+
natural_language_query: str,
|
|
274
|
+
target_tables: Optional[List[str]] = None,
|
|
275
|
+
query_type: str = "SELECT"
|
|
276
|
+
) -> Dict[str, Any]:
|
|
277
|
+
"""
|
|
278
|
+
Generate database query from natural language.
|
|
279
|
+
Must be implemented by subclasses based on database type.
|
|
280
|
+
"""
|
|
281
|
+
pass
|
|
282
|
+
|
|
283
|
+
@abstractmethod
|
|
284
|
+
async def execute_query(self, query: str) -> Dict[str, Any]:
|
|
285
|
+
"""
|
|
286
|
+
Execute a query against the database.
|
|
287
|
+
Must be implemented by subclasses based on database type.
|
|
288
|
+
"""
|
|
289
|
+
pass
|
|
290
|
+
|
|
291
|
+
@abstractmethod
|
|
292
|
+
async def explain_query(self, query: str) -> str:
|
|
293
|
+
"""
|
|
294
|
+
Explain a database query (e.g. EXPLAIN ANALYZE).
|
|
295
|
+
Must be implemented by subclasses based on database type.
|
|
296
|
+
"""
|
|
297
|
+
pass
|
|
298
|
+
|
|
299
|
+
async def search_schema(
|
|
300
|
+
self,
|
|
301
|
+
search_term: str,
|
|
302
|
+
search_type: str = "all",
|
|
303
|
+
limit: int = 10
|
|
304
|
+
) -> List[Dict[str, Any]]:
|
|
305
|
+
"""
|
|
306
|
+
Search the database schema for tables or columns matching the term.
|
|
307
|
+
"""
|
|
308
|
+
if not self.schema_metadata:
|
|
309
|
+
# Try to load from cache or re-extract
|
|
310
|
+
return []
|
|
311
|
+
|
|
312
|
+
results = []
|
|
313
|
+
term = search_term.lower()
|
|
314
|
+
|
|
315
|
+
# Helper to check string match
|
|
316
|
+
def matches(text: Optional[str]) -> bool:
|
|
317
|
+
return bool(text and term in text.lower())
|
|
318
|
+
|
|
319
|
+
for table in self.schema_metadata.tables:
|
|
320
|
+
table_match = False
|
|
321
|
+
# Check table name and description
|
|
322
|
+
if search_type in ["all", "tables"]:
|
|
323
|
+
full_name = f"{table.schema}.{table.name}" if table.schema else table.name
|
|
324
|
+
if matches(table.name) or matches(table.description) or matches(full_name):
|
|
325
|
+
results.append({
|
|
326
|
+
"type": "table",
|
|
327
|
+
"name": table.name,
|
|
328
|
+
"schema": table.schema,
|
|
329
|
+
"description": table.description
|
|
330
|
+
})
|
|
331
|
+
table_match = True
|
|
332
|
+
|
|
333
|
+
# Check columns
|
|
334
|
+
if search_type in ["all", "columns"]:
|
|
335
|
+
for col in table.columns:
|
|
336
|
+
if matches(col.get("name")) or matches(col.get("description")):
|
|
337
|
+
# Add table context if not already added/searching specifically for columns
|
|
338
|
+
if not table_match:
|
|
339
|
+
results.append({
|
|
340
|
+
"type": "column",
|
|
341
|
+
"table": table.name,
|
|
342
|
+
"schema": table.schema,
|
|
343
|
+
"name": col.get("name"),
|
|
344
|
+
"description": col.get("description"),
|
|
345
|
+
"metadata": f"Type: {col.get('type')}"
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
# Sort by relevance (exact matches first? undefined for now) and limit
|
|
349
|
+
return results[:limit]
|
|
350
|
+
|
|
351
|
+
async def store_schema_in_knowledge_base(self) -> None:
|
|
352
|
+
"""Store schema metadata in the knowledge base for retrieval."""
|
|
353
|
+
if not self.knowledge_store or not self.schema_metadata:
|
|
354
|
+
return
|
|
355
|
+
|
|
356
|
+
documents = []
|
|
357
|
+
|
|
358
|
+
# Store table metadata
|
|
359
|
+
for table in self.schema_metadata.tables:
|
|
360
|
+
table_doc = {
|
|
361
|
+
"content": self._format_table_for_storage(table),
|
|
362
|
+
"metadata": {
|
|
363
|
+
"type": "table_schema",
|
|
364
|
+
"database": self.schema_metadata.database_name,
|
|
365
|
+
"schema": table.schema,
|
|
366
|
+
"tablename": table.tablename,
|
|
367
|
+
"database_type": self.schema_metadata.database_type
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
documents.append(table_doc)
|
|
371
|
+
|
|
372
|
+
# Store view metadata
|
|
373
|
+
for view in self.schema_metadata.views:
|
|
374
|
+
view_doc = {
|
|
375
|
+
"content": self._format_table_for_storage(view, is_view=True),
|
|
376
|
+
"metadata": {
|
|
377
|
+
"type": "view_schema",
|
|
378
|
+
"database": self.schema_metadata.database_name,
|
|
379
|
+
"schema": view.schema,
|
|
380
|
+
"view_name": view.tablename,
|
|
381
|
+
"database_type": self.schema_metadata.database_type
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
documents.append(view_doc)
|
|
385
|
+
|
|
386
|
+
# Store in knowledge base
|
|
387
|
+
await self.knowledge_store.add_documents(documents)
|
|
388
|
+
|
|
389
|
+
def _format_table_for_storage(self, table: TableMetadata, is_view: bool = False) -> str:
|
|
390
|
+
"""Format table metadata for storage in knowledge base."""
|
|
391
|
+
object_type = "VIEW" if is_view else "TABLE"
|
|
392
|
+
|
|
393
|
+
content = f"""
|
|
394
|
+
{object_type}: {table.schema}.{table.tablename}
|
|
395
|
+
Description: {table.description or 'No description available'}
|
|
396
|
+
|
|
397
|
+
Columns:
|
|
398
|
+
"""
|
|
399
|
+
for col in table.columns:
|
|
400
|
+
nullable = "NULL" if col.get('nullable', True) else "NOT NULL"
|
|
401
|
+
default = f" DEFAULT {col['default']}" if col.get('default') else ""
|
|
402
|
+
content += f" - {col['name']}: {col['type']} {nullable}{default}\n"
|
|
403
|
+
if col.get('description'):
|
|
404
|
+
content += f" Description: {col['description']}\n"
|
|
405
|
+
|
|
406
|
+
if table.primary_keys:
|
|
407
|
+
content += f"\nPrimary Keys: {', '.join(table.primary_keys)}\n"
|
|
408
|
+
|
|
409
|
+
if table.foreign_keys:
|
|
410
|
+
content += "\nForeign Keys:\n"
|
|
411
|
+
for fk in table.foreign_keys:
|
|
412
|
+
content += f" - {fk['column']} -> {fk['referenced_table']}.{fk['referenced_column']}\n"
|
|
413
|
+
|
|
414
|
+
if table.indexes:
|
|
415
|
+
content += "\nIndexes:\n"
|
|
416
|
+
for idx in table.indexes:
|
|
417
|
+
content += f" - {idx['name']}: {', '.join(idx['columns'])}\n"
|
|
418
|
+
|
|
419
|
+
if table.sample_data:
|
|
420
|
+
content += "\nSample Data:\n"
|
|
421
|
+
for i, row in enumerate(table.sample_data[:3]): # Limit to 3 rows
|
|
422
|
+
content += f" Row {i+1}: {json.dumps(row, default=str)}\n"
|
|
423
|
+
|
|
424
|
+
return content
|
|
425
|
+
|
|
426
|
+
async def ask(
|
|
427
|
+
self,
|
|
428
|
+
question: str = None,
|
|
429
|
+
user_context: Optional[str] = None,
|
|
430
|
+
context: Optional[str] = None,
|
|
431
|
+
session_id: Optional[str] = None,
|
|
432
|
+
user_id: Optional[str] = None,
|
|
433
|
+
use_conversation_history: bool = True,
|
|
434
|
+
**kwargs
|
|
435
|
+
) -> AIMessage:
|
|
436
|
+
"""
|
|
437
|
+
Database-specific ask method with user context support and agentic mode.
|
|
438
|
+
|
|
439
|
+
Args:
|
|
440
|
+
question: The user's question about the database
|
|
441
|
+
user_context: User-specific context for database interaction
|
|
442
|
+
session_id: Session identifier for conversation history
|
|
443
|
+
user_id: User identifier
|
|
444
|
+
use_conversation_history: Whether to use conversation history
|
|
445
|
+
**kwargs: Additional arguments for LLM
|
|
446
|
+
|
|
447
|
+
Returns:
|
|
448
|
+
AIMessage: The response from the LLM
|
|
449
|
+
"""
|
|
450
|
+
# Backwards compatibility for prompt
|
|
451
|
+
if question is None:
|
|
452
|
+
question = kwargs.get('prompt')
|
|
453
|
+
|
|
454
|
+
prompt = question # internal usage expects prompt variable name in logic below
|
|
455
|
+
# Force agentic mode for database operations
|
|
456
|
+
effective_mode = "agentic"
|
|
457
|
+
|
|
458
|
+
# Override temperature to ensure consistent database operations
|
|
459
|
+
kwargs['temperature'] = kwargs.get('temperature', self._default_temperature)
|
|
460
|
+
|
|
461
|
+
# Generate session ID if not provided
|
|
462
|
+
if not session_id:
|
|
463
|
+
session_id = f"db_session_{hash(prompt + str(user_id))}"
|
|
464
|
+
|
|
465
|
+
try:
|
|
466
|
+
# Get conversation history if enabled
|
|
467
|
+
conversation_history = None
|
|
468
|
+
conversation_context = ""
|
|
469
|
+
|
|
470
|
+
if use_conversation_history and self.conversation_memory:
|
|
471
|
+
conversation_history = await self.get_conversation_history(user_id, session_id)
|
|
472
|
+
if not conversation_history:
|
|
473
|
+
conversation_history = await self.create_conversation_history(
|
|
474
|
+
user_id, session_id
|
|
475
|
+
)
|
|
476
|
+
conversation_context = self.build_conversation_context(conversation_history)
|
|
477
|
+
|
|
478
|
+
# Get vector context from knowledge store if available
|
|
479
|
+
vector_context = ""
|
|
480
|
+
vector_metadata = {}
|
|
481
|
+
if self.knowledge_store:
|
|
482
|
+
try:
|
|
483
|
+
# Search for relevant schema information
|
|
484
|
+
search_results = await self.knowledge_store.similarity_search(
|
|
485
|
+
prompt, k=5
|
|
486
|
+
)
|
|
487
|
+
if search_results:
|
|
488
|
+
vector_context = "\n\n".join([doc.page_content for doc in search_results])
|
|
489
|
+
vector_metadata = {
|
|
490
|
+
'sources': [doc.metadata.get('source', 'unknown') for doc in search_results],
|
|
491
|
+
'tables_referenced': [doc.metadata.get('table_name') for doc in search_results if doc.metadata.get('table_name')]
|
|
492
|
+
}
|
|
493
|
+
except Exception as e:
|
|
494
|
+
self.logger.warning(f"Error retrieving vector context: {e}")
|
|
495
|
+
|
|
496
|
+
# Create system prompt with user context
|
|
497
|
+
system_prompt = await self.create_system_prompt(
|
|
498
|
+
user_context=user_context,
|
|
499
|
+
context=context or "",
|
|
500
|
+
vector_context=vector_context,
|
|
501
|
+
conversation_context=conversation_context,
|
|
502
|
+
metadata=vector_metadata,
|
|
503
|
+
**kwargs
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
# Log the operation
|
|
507
|
+
self.logger.info(
|
|
508
|
+
f"Database query in agentic mode: use_tools=True, "
|
|
509
|
+
f"effective_mode={effective_mode}, available_tools={len(self.tools)}"
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
# Make the LLM call with tools enabled
|
|
513
|
+
async with self._llm as client:
|
|
514
|
+
response = await client.ask(
|
|
515
|
+
prompt=prompt,
|
|
516
|
+
model=kwargs.get('model', self._llm_model),
|
|
517
|
+
system_prompt=system_prompt,
|
|
518
|
+
user_id=user_id,
|
|
519
|
+
session_id=session_id,
|
|
520
|
+
temperature=kwargs.get('temperature', self._default_temperature),
|
|
521
|
+
tools=self.tools if self.tools else None,
|
|
522
|
+
**{k: v for k, v in kwargs.items() if k not in ['model', 'temperature']}
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
# Update conversation memory
|
|
526
|
+
if use_conversation_history and conversation_history:
|
|
527
|
+
assistant_content = str(response.output) if response.output is not None else (response.response or "")
|
|
528
|
+
|
|
529
|
+
turn = ConversationTurn(
|
|
530
|
+
turn_id=str(uuid.uuid4()),
|
|
531
|
+
user_id=user_id,
|
|
532
|
+
user_message=prompt,
|
|
533
|
+
assistant_response=assistant_content,
|
|
534
|
+
metadata={
|
|
535
|
+
'user_context': user_context,
|
|
536
|
+
'effective_mode': effective_mode,
|
|
537
|
+
'tools_used': [tool.name for tool in response.tool_calls] if response.tool_calls else []
|
|
538
|
+
}
|
|
539
|
+
)
|
|
540
|
+
chatbot_key = getattr(self, 'chatbot_id', None)
|
|
541
|
+
if chatbot_key is not None:
|
|
542
|
+
chatbot_key = str(chatbot_key)
|
|
543
|
+
await self.conversation_memory.add_turn(
|
|
544
|
+
user_id,
|
|
545
|
+
session_id,
|
|
546
|
+
turn,
|
|
547
|
+
chatbot_id=chatbot_key
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
return response
|
|
551
|
+
|
|
552
|
+
except Exception as e:
|
|
553
|
+
self.logger.error(
|
|
554
|
+
f"Error in database ask method: {e}"
|
|
555
|
+
)
|
|
556
|
+
raise
|