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,95 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# SCHEMA-CENTRIC DATA MODELS
|
|
3
|
+
# ============================================================================
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
from typing import Dict, Any, List, Optional
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from pydantic import Field
|
|
9
|
+
import yaml
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class SchemaMetadata:
|
|
13
|
+
"""Metadata for a single schema (client)."""
|
|
14
|
+
database_name: str
|
|
15
|
+
schema: str
|
|
16
|
+
table_count: int
|
|
17
|
+
view_count: int
|
|
18
|
+
total_rows: Optional[int] = None
|
|
19
|
+
last_analyzed: Optional[datetime] = None
|
|
20
|
+
database_type: Optional[str] = Field(default='postgresql')
|
|
21
|
+
tables: Dict[str, 'TableMetadata'] = field(default_factory=dict)
|
|
22
|
+
views: Dict[str, 'TableMetadata'] = field(default_factory=dict)
|
|
23
|
+
functions: List[Dict[str, Any]] = field(default_factory=list)
|
|
24
|
+
|
|
25
|
+
def get_all_objects(self) -> Dict[str, 'TableMetadata']:
|
|
26
|
+
"""Get all tables and views."""
|
|
27
|
+
return {**self.tables, **self.views}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class TableMetadata:
|
|
32
|
+
"""Enhanced table metadata for large-scale operations."""
|
|
33
|
+
schema: str
|
|
34
|
+
tablename: str
|
|
35
|
+
table_type: str # 'BASE TABLE', 'VIEW'
|
|
36
|
+
full_name: str # schema.table for easy reference
|
|
37
|
+
comment: Optional[str] = None
|
|
38
|
+
columns: List[Dict[str, Any]] = field(default_factory=list)
|
|
39
|
+
primary_keys: List[str] = field(default_factory=list)
|
|
40
|
+
foreign_keys: List[Dict[str, Any]] = field(default_factory=list)
|
|
41
|
+
indexes: List[Dict[str, Any]] = field(default_factory=list)
|
|
42
|
+
row_count: Optional[int] = None
|
|
43
|
+
sample_data: List[Dict[str, Any]] = field(default_factory=list)
|
|
44
|
+
|
|
45
|
+
# Performance and usage metadata
|
|
46
|
+
last_accessed: Optional[datetime] = None
|
|
47
|
+
access_frequency: int = 0
|
|
48
|
+
avg_query_time: Optional[float] = None
|
|
49
|
+
|
|
50
|
+
def __post_init__(self):
|
|
51
|
+
if not self.full_name:
|
|
52
|
+
self.full_name = f'"{self.schema}"."{self.tablename}"'
|
|
53
|
+
|
|
54
|
+
def to_yaml_context(self) -> str:
|
|
55
|
+
"""Convert to YAML context optimized for LLM consumption."""
|
|
56
|
+
# Include only essential information to avoid token bloat
|
|
57
|
+
essential_columns = self.columns[:20] # Limit to first 20 columns
|
|
58
|
+
|
|
59
|
+
data = {
|
|
60
|
+
'table': self.full_name,
|
|
61
|
+
'type': self.table_type,
|
|
62
|
+
'description': self.comment or f"{self.table_type.lower()} in {self.schema} schema",
|
|
63
|
+
'columns': [
|
|
64
|
+
{
|
|
65
|
+
'name': col['name'],
|
|
66
|
+
'type': col['type'],
|
|
67
|
+
'nullable': col.get('nullable', True),
|
|
68
|
+
'description': col.get('comment')
|
|
69
|
+
}
|
|
70
|
+
for col in essential_columns
|
|
71
|
+
],
|
|
72
|
+
'primary_keys': self.primary_keys,
|
|
73
|
+
'row_count': self.row_count,
|
|
74
|
+
'sample_values': self._get_sample_column_values()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if len(self.columns) > 20:
|
|
78
|
+
data['note'] = f"Showing 20 of {len(self.columns)} columns. Use schema search tools for complete structure."
|
|
79
|
+
|
|
80
|
+
return yaml.dump(data, default_flow_style=False, sort_keys=False)
|
|
81
|
+
|
|
82
|
+
def _get_sample_column_values(self) -> Dict[str, List]:
|
|
83
|
+
"""Extract sample values per column for context."""
|
|
84
|
+
if not self.sample_data:
|
|
85
|
+
return {}
|
|
86
|
+
|
|
87
|
+
sample_values = {}
|
|
88
|
+
for row in self.sample_data[:3]: # First 3 rows
|
|
89
|
+
for col_name, value in row.items():
|
|
90
|
+
if col_name not in sample_values:
|
|
91
|
+
sample_values[col_name] = []
|
|
92
|
+
if value is not None and len(sample_values[col_name]) < 3:
|
|
93
|
+
sample_values[col_name].append(str(value))
|
|
94
|
+
|
|
95
|
+
return sample_values
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
from typing import Optional, List
|
|
2
|
+
from sqlalchemy import text
|
|
3
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from .abstract import AbstractSchemaManagerTool
|
|
6
|
+
from .models import TableMetadata
|
|
7
|
+
from ..abstract import ToolResult
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class PgSchemaSearchTool(AbstractSchemaManagerTool):
|
|
11
|
+
"""PostgreSQL-specific schema manager tool."""
|
|
12
|
+
|
|
13
|
+
name = "PgSchemaSearchTool"
|
|
14
|
+
description = "Schema management for PostgreSQL databases. You MUST use this tool to discover and understand schema tables and their columns using 'search_term' before trying to run a query using DatabaseQueryTool."
|
|
15
|
+
|
|
16
|
+
async def _execute(
|
|
17
|
+
self,
|
|
18
|
+
search_term: str,
|
|
19
|
+
schema_name: Optional[str] = None,
|
|
20
|
+
table_name: Optional[str] = None,
|
|
21
|
+
search_type: str = "all",
|
|
22
|
+
limit: int = 10
|
|
23
|
+
) -> ToolResult:
|
|
24
|
+
"""Execute schema search with proper cache-first strategy."""
|
|
25
|
+
try:
|
|
26
|
+
# Determine target schemas
|
|
27
|
+
target_schemas = [schema_name] if schema_name else self.allowed_schemas
|
|
28
|
+
|
|
29
|
+
# Step 1: Try cache first
|
|
30
|
+
self.logger.debug(f"🔍 Searching cache for '{search_term}' in schemas: {target_schemas}")
|
|
31
|
+
cache_results = await self._search_in_cache(
|
|
32
|
+
search_term=search_term,
|
|
33
|
+
schema_name=schema_name,
|
|
34
|
+
table_name=table_name,
|
|
35
|
+
search_type=search_type,
|
|
36
|
+
limit=limit
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Step 2: If cache is empty, search database
|
|
40
|
+
if not cache_results:
|
|
41
|
+
self.logger.info(f"💾 Cache miss for '{search_term}', searching database...")
|
|
42
|
+
db_results = await self._search_in_database(
|
|
43
|
+
search_term=search_term,
|
|
44
|
+
schema_name=schema_name,
|
|
45
|
+
table_name=table_name,
|
|
46
|
+
search_type=search_type,
|
|
47
|
+
limit=limit
|
|
48
|
+
)
|
|
49
|
+
results = db_results
|
|
50
|
+
source = "database"
|
|
51
|
+
else:
|
|
52
|
+
self.logger.info(f"✅ Cache hit for '{search_term}': {len(cache_results)} results")
|
|
53
|
+
results = cache_results
|
|
54
|
+
source = "cache"
|
|
55
|
+
|
|
56
|
+
# Step 3: Format results
|
|
57
|
+
formatted_results = []
|
|
58
|
+
for table in results:
|
|
59
|
+
fmt = await self._format_table_result(table, search_term, search_type)
|
|
60
|
+
if fmt:
|
|
61
|
+
formatted_results.append(fmt)
|
|
62
|
+
|
|
63
|
+
return ToolResult(
|
|
64
|
+
status="success",
|
|
65
|
+
result=formatted_results,
|
|
66
|
+
metadata={
|
|
67
|
+
"search_term": search_term,
|
|
68
|
+
"schema_name": schema_name,
|
|
69
|
+
"table_name": table_name,
|
|
70
|
+
"search_type": search_type,
|
|
71
|
+
"results_count": len(formatted_results),
|
|
72
|
+
"searched_schemas": target_schemas,
|
|
73
|
+
"source": source
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
except Exception as e:
|
|
77
|
+
self.logger.error(f"Schema search failed: {e}")
|
|
78
|
+
return ToolResult(
|
|
79
|
+
status="error",
|
|
80
|
+
result=None,
|
|
81
|
+
error=str(e),
|
|
82
|
+
metadata={
|
|
83
|
+
"search_term": search_term,
|
|
84
|
+
"schema_name": schema_name,
|
|
85
|
+
"table_name": table_name
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
async def _search_in_cache(
|
|
90
|
+
self,
|
|
91
|
+
search_term: str,
|
|
92
|
+
schema_name: Optional[str] = None,
|
|
93
|
+
table_name: Optional[str] = None,
|
|
94
|
+
search_type: str = "all",
|
|
95
|
+
limit: int = 10
|
|
96
|
+
) -> List[TableMetadata]:
|
|
97
|
+
"""Search in cache first - Step 1."""
|
|
98
|
+
# Case 1: Specific schema and table lookup
|
|
99
|
+
if schema_name and table_name:
|
|
100
|
+
self.logger.debug(f"🔍 Specific lookup: {schema_name}.{table_name}")
|
|
101
|
+
table_meta = await self.metadata_cache.get_table_metadata(schema_name, table_name)
|
|
102
|
+
return [table_meta] if table_meta else []
|
|
103
|
+
|
|
104
|
+
# Case 2: General search using cache's similarity search
|
|
105
|
+
target_schemas = [schema_name] if schema_name else self.allowed_schemas
|
|
106
|
+
self.logger.debug(f"🔍 General cache search in schemas: {target_schemas}")
|
|
107
|
+
|
|
108
|
+
return await self.metadata_cache.search_similar_tables(
|
|
109
|
+
schema_names=target_schemas,
|
|
110
|
+
query=search_term,
|
|
111
|
+
limit=limit
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
async def _search_in_database(
|
|
115
|
+
self,
|
|
116
|
+
search_term: str,
|
|
117
|
+
schema_name: Optional[str] = None,
|
|
118
|
+
table_name: Optional[str] = None,
|
|
119
|
+
search_type: str = "all",
|
|
120
|
+
limit: int = 10
|
|
121
|
+
) -> List[TableMetadata]:
|
|
122
|
+
"""Search directly in database when cache is empty - Step 2."""
|
|
123
|
+
async with self.session_maker() as session:
|
|
124
|
+
target_schemas = [schema_name] if schema_name else self.allowed_schemas
|
|
125
|
+
|
|
126
|
+
# Case 1: Specific table lookup
|
|
127
|
+
if table_name:
|
|
128
|
+
self.logger.debug(f"💾 DB lookup for specific table: {table_name} in {target_schemas}")
|
|
129
|
+
search_query = """
|
|
130
|
+
SELECT DISTINCT
|
|
131
|
+
ist.table_schema,
|
|
132
|
+
ist.table_name,
|
|
133
|
+
ist.table_type,
|
|
134
|
+
obj_description(pgc.oid) as comment
|
|
135
|
+
FROM information_schema.tables ist
|
|
136
|
+
LEFT JOIN pg_namespace pgn ON pgn.nspname = ist.table_schema
|
|
137
|
+
LEFT JOIN pg_class pgc ON pgc.relname = ist.table_name
|
|
138
|
+
AND pgc.relnamespace = pgn.oid
|
|
139
|
+
WHERE ist.table_schema = ANY(:schemas)
|
|
140
|
+
AND ist.table_name = :table_name
|
|
141
|
+
AND ist.table_type IN ('BASE TABLE', 'VIEW')
|
|
142
|
+
LIMIT 1
|
|
143
|
+
"""
|
|
144
|
+
params = {"schemas": target_schemas, "table_name": table_name}
|
|
145
|
+
else:
|
|
146
|
+
# Case 2: General pattern search
|
|
147
|
+
self.logger.debug(f"💾 DB pattern search for '{search_term}' in {target_schemas}")
|
|
148
|
+
search_query = """
|
|
149
|
+
SELECT DISTINCT
|
|
150
|
+
ist.table_schema,
|
|
151
|
+
ist.table_name,
|
|
152
|
+
ist.table_type,
|
|
153
|
+
obj_description(pgc.oid) as comment
|
|
154
|
+
FROM information_schema.tables ist
|
|
155
|
+
LEFT JOIN pg_namespace pgn ON pgn.nspname = ist.table_schema
|
|
156
|
+
LEFT JOIN pg_class pgc ON pgc.relname = ist.table_name
|
|
157
|
+
AND pgc.relnamespace = pgn.oid
|
|
158
|
+
WHERE ist.table_schema = ANY(:schemas)
|
|
159
|
+
AND (
|
|
160
|
+
ist.table_name ILIKE :term
|
|
161
|
+
OR
|
|
162
|
+
(ist.table_schema || '.' || ist.table_name) ILIKE :term
|
|
163
|
+
)
|
|
164
|
+
AND ist.table_type IN ('BASE TABLE', 'VIEW')
|
|
165
|
+
ORDER BY ist.table_name
|
|
166
|
+
LIMIT :limit
|
|
167
|
+
"""
|
|
168
|
+
params = {
|
|
169
|
+
"schemas": target_schemas,
|
|
170
|
+
"term": f"%{search_term}%",
|
|
171
|
+
"limit": limit
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
result = await session.execute(text(search_query), params)
|
|
175
|
+
rows = result.fetchall()
|
|
176
|
+
|
|
177
|
+
results = []
|
|
178
|
+
for row in rows:
|
|
179
|
+
try:
|
|
180
|
+
# Analyze and get full metadata
|
|
181
|
+
metadata = await self.analyze_table(
|
|
182
|
+
session,
|
|
183
|
+
row.table_schema,
|
|
184
|
+
row.table_name,
|
|
185
|
+
row.table_type,
|
|
186
|
+
row.comment
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Step 4: Store in cache for future use
|
|
190
|
+
await self.metadata_cache.store_table_metadata(metadata)
|
|
191
|
+
self.logger.debug(f"💾 Stored {row.table_schema}.{row.table_name} in cache")
|
|
192
|
+
|
|
193
|
+
results.append(metadata)
|
|
194
|
+
except Exception as e:
|
|
195
|
+
self.logger.warning(
|
|
196
|
+
f"Failed to analyze table {row.table_schema}.{row.table_name}: {e}"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
return results
|
|
200
|
+
|
|
201
|
+
async def analyze_schema(self, schema_name: str) -> int:
|
|
202
|
+
"""Analyze individual PostgreSQL schema and return table count."""
|
|
203
|
+
async with self.session_maker() as session:
|
|
204
|
+
# Get all tables and views in schema
|
|
205
|
+
tables_query = """
|
|
206
|
+
SELECT DISTINCT
|
|
207
|
+
ist.table_name,
|
|
208
|
+
ist.table_type,
|
|
209
|
+
obj_description(pgc.oid) as comment
|
|
210
|
+
FROM information_schema.tables ist
|
|
211
|
+
LEFT JOIN pg_namespace pgn ON pgn.nspname = ist.table_schema
|
|
212
|
+
LEFT JOIN pg_class pgc ON pgc.relname = ist.table_name
|
|
213
|
+
AND pgc.relnamespace = pgn.oid
|
|
214
|
+
WHERE ist.table_schema = :schema_name
|
|
215
|
+
AND ist.table_type IN ('BASE TABLE', 'VIEW')
|
|
216
|
+
ORDER BY ist.table_name
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
result = await session.execute(
|
|
220
|
+
text(tables_query),
|
|
221
|
+
{"schema_name": schema_name}
|
|
222
|
+
)
|
|
223
|
+
tables_data = result.fetchall()
|
|
224
|
+
|
|
225
|
+
# Analyze each table
|
|
226
|
+
for table_row in tables_data:
|
|
227
|
+
table_name = table_row.table_name
|
|
228
|
+
table_type = table_row.table_type
|
|
229
|
+
comment = table_row.comment
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
table_metadata = await self.analyze_table(
|
|
233
|
+
session, schema_name, table_name, table_type, comment
|
|
234
|
+
)
|
|
235
|
+
await self.metadata_cache.store_table_metadata(table_metadata)
|
|
236
|
+
except Exception as e:
|
|
237
|
+
self.logger.warning(
|
|
238
|
+
f"Failed to analyze table {schema_name}.{table_name}: {e}"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
return len(tables_data)
|
|
242
|
+
|
|
243
|
+
async def analyze_table(
|
|
244
|
+
self,
|
|
245
|
+
session: AsyncSession,
|
|
246
|
+
schema_name: str,
|
|
247
|
+
table_name: str,
|
|
248
|
+
table_type: str,
|
|
249
|
+
comment: Optional[str]
|
|
250
|
+
) -> TableMetadata:
|
|
251
|
+
"""Analyze individual PostgreSQL table metadata."""
|
|
252
|
+
|
|
253
|
+
# Get column information
|
|
254
|
+
columns_query = """
|
|
255
|
+
SELECT DISTINCT
|
|
256
|
+
isc.column_name,
|
|
257
|
+
isc.data_type,
|
|
258
|
+
isc.is_nullable,
|
|
259
|
+
isc.column_default,
|
|
260
|
+
isc.character_maximum_length,
|
|
261
|
+
isc.ordinal_position,
|
|
262
|
+
col_description(pgc.oid, isc.ordinal_position) as comment
|
|
263
|
+
FROM information_schema.columns isc
|
|
264
|
+
LEFT JOIN pg_namespace pgn ON pgn.nspname = isc.table_schema
|
|
265
|
+
LEFT JOIN pg_class pgc ON pgc.relname = isc.table_name
|
|
266
|
+
AND pgc.relnamespace = pgn.oid
|
|
267
|
+
WHERE isc.table_schema = :schema_name
|
|
268
|
+
AND isc.table_name = :table_name
|
|
269
|
+
ORDER BY isc.ordinal_position
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
result = await session.execute(
|
|
273
|
+
text(columns_query),
|
|
274
|
+
{"schema_name": schema_name, "table_name": table_name}
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
columns = []
|
|
278
|
+
for col_row in result.fetchall():
|
|
279
|
+
columns.append({
|
|
280
|
+
"name": col_row.column_name,
|
|
281
|
+
"type": col_row.data_type,
|
|
282
|
+
"nullable": col_row.is_nullable == "YES",
|
|
283
|
+
"default": col_row.column_default,
|
|
284
|
+
"max_length": col_row.character_maximum_length,
|
|
285
|
+
"comment": col_row.comment
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
# Get primary keys
|
|
289
|
+
pk_query = """
|
|
290
|
+
SELECT column_name
|
|
291
|
+
FROM information_schema.key_column_usage kcu
|
|
292
|
+
JOIN information_schema.table_constraints tc
|
|
293
|
+
ON kcu.constraint_name = tc.constraint_name
|
|
294
|
+
AND kcu.table_schema = tc.table_schema
|
|
295
|
+
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
296
|
+
AND kcu.table_schema = :schema_name
|
|
297
|
+
AND kcu.table_name = :table_name
|
|
298
|
+
ORDER BY ordinal_position
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
pk_result = await session.execute(
|
|
302
|
+
text(pk_query),
|
|
303
|
+
{"schema_name": schema_name, "table_name": table_name}
|
|
304
|
+
)
|
|
305
|
+
primary_keys = [row.column_name for row in pk_result.fetchall()]
|
|
306
|
+
|
|
307
|
+
# Get row count estimate
|
|
308
|
+
row_count = None
|
|
309
|
+
if table_type == 'BASE TABLE':
|
|
310
|
+
try:
|
|
311
|
+
count_query = 'SELECT reltuples::bigint FROM pg_class WHERE relname = :table_name'
|
|
312
|
+
count_result = await session.execute(text(count_query), {"table_name": table_name})
|
|
313
|
+
row_count = count_result.scalar()
|
|
314
|
+
except Exception:
|
|
315
|
+
pass
|
|
316
|
+
|
|
317
|
+
# Get sample data
|
|
318
|
+
sample_data = []
|
|
319
|
+
if table_type == 'BASE TABLE' and row_count and row_count < 1000000:
|
|
320
|
+
try:
|
|
321
|
+
sample_query = f'SELECT * FROM "{schema_name}"."{table_name}" LIMIT 3'
|
|
322
|
+
sample_result = await session.execute(text(sample_query))
|
|
323
|
+
rows = sample_result.fetchall()
|
|
324
|
+
if rows:
|
|
325
|
+
column_names = list(sample_result.keys())
|
|
326
|
+
sample_data = [dict(zip(column_names, row)) for row in rows]
|
|
327
|
+
except Exception:
|
|
328
|
+
pass
|
|
329
|
+
|
|
330
|
+
return TableMetadata(
|
|
331
|
+
schema=schema_name,
|
|
332
|
+
tablename=table_name,
|
|
333
|
+
table_type=table_type,
|
|
334
|
+
full_name=f'"{schema_name}"."{table_name}"',
|
|
335
|
+
comment=comment,
|
|
336
|
+
columns=columns,
|
|
337
|
+
primary_keys=primary_keys,
|
|
338
|
+
foreign_keys=[],
|
|
339
|
+
indexes=[],
|
|
340
|
+
row_count=row_count,
|
|
341
|
+
sample_data=sample_data,
|
|
342
|
+
last_accessed=datetime.now()
|
|
343
|
+
)
|