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/tools/ecs.py
ADDED
|
@@ -0,0 +1,819 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AWS ECS and EKS Tool for AI-Parrot
|
|
3
|
+
|
|
4
|
+
Provides helpers to inspect Fargate tasks, ECS services, and EKS clusters.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
|
+
from datetime import datetime, timedelta, timezone
|
|
9
|
+
import re
|
|
10
|
+
import base64
|
|
11
|
+
import ssl
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from botocore.exceptions import ClientError
|
|
14
|
+
from botocore import session as boto_session
|
|
15
|
+
from botocore.signers import RequestSigner
|
|
16
|
+
from pydantic import Field, field_validator
|
|
17
|
+
import aiohttp
|
|
18
|
+
from ..interfaces.aws import AWSInterface
|
|
19
|
+
from .abstract import AbstractTool, AbstractToolArgsSchema, ToolResult
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ECSOperation(str, Enum):
|
|
23
|
+
"""Supported ECS/EKS operations."""
|
|
24
|
+
|
|
25
|
+
LIST_ECS_CLUSTERS = "list_ecs_clusters"
|
|
26
|
+
LIST_ECS_SERVICES = "list_ecs_services"
|
|
27
|
+
LIST_SERVICES = "list_services"
|
|
28
|
+
LIST_ECS_TASKS = "list_ecs_tasks"
|
|
29
|
+
LIST_TASKS = "list_tasks"
|
|
30
|
+
DESCRIBE_ECS_TASKS = "describe_ecs_tasks"
|
|
31
|
+
DESCRIBE_TASKS = "describe_tasks"
|
|
32
|
+
GET_FARGATE_TASK_LOGS = "get_fargate_task_logs"
|
|
33
|
+
GET_FARGATE_LOGS = "get_fargate_logs"
|
|
34
|
+
DESCRIBE_EKS_CLUSTER = "describe_eks_cluster"
|
|
35
|
+
GET_EKS_CLUSTER_INFO = "get_eks_cluster_info"
|
|
36
|
+
LIST_EKS_CLUSTERS = "list_eks_clusters"
|
|
37
|
+
LIST_EKS_NODEGROUPS = "list_eks_nodegroups"
|
|
38
|
+
DESCRIBE_EKS_NODEGROUP = "describe_eks_nodegroup"
|
|
39
|
+
LIST_EKS_FARGATE_PROFILES = "list_eks_fargate_profiles"
|
|
40
|
+
DESCRIBE_EKS_FARGATE_PROFILE = "describe_eks_fargate_profile"
|
|
41
|
+
LIST_EKS_PODS = "list_eks_pods"
|
|
42
|
+
LIST_EC2_INSTANCES = "list_ec2_instances"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ECSToolArgs(AbstractToolArgsSchema):
|
|
46
|
+
"""Arguments schema for ECS/EKS operations."""
|
|
47
|
+
|
|
48
|
+
operation: ECSOperation = Field(
|
|
49
|
+
..., description="Operation to perform for ECS/Fargate or EKS"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
cluster_name: Optional[str] = Field(
|
|
53
|
+
None, description="ECS or EKS cluster name"
|
|
54
|
+
)
|
|
55
|
+
service_name: Optional[str] = Field(
|
|
56
|
+
None, description="ECS service name"
|
|
57
|
+
)
|
|
58
|
+
task_arns: Optional[List[str]] = Field(
|
|
59
|
+
None, description="Specific task ARNs to describe"
|
|
60
|
+
)
|
|
61
|
+
launch_type: Optional[str] = Field(
|
|
62
|
+
None, description="Filter tasks by launch type (e.g., 'FARGATE')"
|
|
63
|
+
)
|
|
64
|
+
desired_status: Optional[str] = Field(
|
|
65
|
+
None, description="Filter tasks by desired status (e.g., 'RUNNING')"
|
|
66
|
+
)
|
|
67
|
+
log_group_name: Optional[str] = Field(
|
|
68
|
+
None, description="CloudWatch log group used by Fargate tasks"
|
|
69
|
+
)
|
|
70
|
+
log_stream_prefix: Optional[str] = Field(
|
|
71
|
+
None, description="Prefix for CloudWatch log streams"
|
|
72
|
+
)
|
|
73
|
+
start_time: Optional[str] = Field(
|
|
74
|
+
None,
|
|
75
|
+
description=(
|
|
76
|
+
"Start time for log retrieval (ISO format or relative like '-1h', '-24h')."
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
limit: Optional[int] = Field(
|
|
80
|
+
100, description="Maximum number of log events to return"
|
|
81
|
+
)
|
|
82
|
+
eks_nodegroup: Optional[str] = Field(
|
|
83
|
+
None, description="EKS nodegroup name to describe"
|
|
84
|
+
)
|
|
85
|
+
eks_fargate_profile: Optional[str] = Field(
|
|
86
|
+
None, description="EKS Fargate profile name to describe"
|
|
87
|
+
)
|
|
88
|
+
namespace: Optional[str] = Field(
|
|
89
|
+
None, description="Kubernetes namespace to filter pods (default: all namespaces)"
|
|
90
|
+
)
|
|
91
|
+
instance_state: Optional[str] = Field(
|
|
92
|
+
None, description="Filter EC2 instances by state (e.g., 'running', 'stopped', 'terminated')"
|
|
93
|
+
)
|
|
94
|
+
instance_ids: Optional[List[str]] = Field(
|
|
95
|
+
None, description="Specific EC2 instance IDs to describe"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
@field_validator("start_time", mode="before")
|
|
99
|
+
@classmethod
|
|
100
|
+
def validate_start_time(cls, value):
|
|
101
|
+
if value is None or value == "now":
|
|
102
|
+
return value
|
|
103
|
+
return value
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class ECSTool(AbstractTool):
|
|
107
|
+
"""
|
|
108
|
+
Tool for inspecting AWS ECS/Fargate tasks, EKS Kubernetes clusters, and EC2 instances.
|
|
109
|
+
|
|
110
|
+
Capabilities include:
|
|
111
|
+
- Listing ECS clusters, services, and tasks
|
|
112
|
+
- Describing ECS tasks (useful for Fargate workloads)
|
|
113
|
+
- Fetching Fargate task logs from CloudWatch
|
|
114
|
+
- Inspecting EKS cluster, nodegroup, and Fargate profile metadata
|
|
115
|
+
- Listing Kubernetes pods in EKS clusters
|
|
116
|
+
- Listing and describing EC2 instances
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
name: str = "aws_ecs_eks_tool"
|
|
120
|
+
description: str = "Inspect AWS ECS/Fargate tasks, EKS Kubernetes clusters, and EC2 instances"
|
|
121
|
+
args_schema: type[AbstractToolArgsSchema] = ECSToolArgs
|
|
122
|
+
|
|
123
|
+
def __init__(self, aws_id: str = "default", region_name: Optional[str] = None, **kwargs):
|
|
124
|
+
super().__init__()
|
|
125
|
+
self.aws = AWSInterface(aws_id=aws_id, region_name=region_name, **kwargs)
|
|
126
|
+
|
|
127
|
+
def _parse_time(self, value: Optional[str]) -> Optional[datetime]:
|
|
128
|
+
if value is None or value == "now":
|
|
129
|
+
return datetime.utc(tz=timezone.utc)
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
return datetime.fromisoformat(value.replace("Z", "+00:00"))
|
|
133
|
+
except (ValueError, AttributeError):
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
if value.startswith("-"):
|
|
137
|
+
raw = value[1:]
|
|
138
|
+
match = re.match(r"(\d+)([smhd])", raw)
|
|
139
|
+
if not match:
|
|
140
|
+
raise ValueError(f"Invalid time format: {value}")
|
|
141
|
+
|
|
142
|
+
amount, unit = match.groups()
|
|
143
|
+
amount = int(amount)
|
|
144
|
+
if unit == "s":
|
|
145
|
+
delta = timedelta(seconds=amount)
|
|
146
|
+
elif unit == "m":
|
|
147
|
+
delta = timedelta(minutes=amount)
|
|
148
|
+
elif unit == "h":
|
|
149
|
+
delta = timedelta(hours=amount)
|
|
150
|
+
elif unit == "d":
|
|
151
|
+
delta = timedelta(days=amount)
|
|
152
|
+
else:
|
|
153
|
+
raise ValueError(f"Unsupported time unit: {unit}")
|
|
154
|
+
|
|
155
|
+
return datetime.now(timezone.utc) - delta
|
|
156
|
+
|
|
157
|
+
raise ValueError(f"Invalid time format: {value}")
|
|
158
|
+
|
|
159
|
+
async def _list_ecs_clusters(self) -> List[str]:
|
|
160
|
+
async with self.aws.client("ecs") as ecs:
|
|
161
|
+
response = await ecs.list_clusters()
|
|
162
|
+
return response.get("clusterArns", [])
|
|
163
|
+
|
|
164
|
+
async def _list_services(self, cluster: str) -> List[str]:
|
|
165
|
+
async with self.aws.client("ecs") as ecs:
|
|
166
|
+
response = await ecs.list_services(cluster=cluster)
|
|
167
|
+
return response.get("serviceArns", [])
|
|
168
|
+
|
|
169
|
+
async def _list_tasks(
|
|
170
|
+
self,
|
|
171
|
+
cluster: str,
|
|
172
|
+
service_name: Optional[str] = None,
|
|
173
|
+
desired_status: Optional[str] = None,
|
|
174
|
+
launch_type: Optional[str] = None,
|
|
175
|
+
) -> List[str]:
|
|
176
|
+
params: Dict[str, Any] = {"cluster": cluster}
|
|
177
|
+
if service_name:
|
|
178
|
+
params["serviceName"] = service_name
|
|
179
|
+
if desired_status:
|
|
180
|
+
params["desiredStatus"] = desired_status
|
|
181
|
+
if launch_type:
|
|
182
|
+
params["launchType"] = launch_type
|
|
183
|
+
|
|
184
|
+
async with self.aws.client("ecs") as ecs:
|
|
185
|
+
response = await ecs.list_tasks(**params)
|
|
186
|
+
return response.get("taskArns", [])
|
|
187
|
+
|
|
188
|
+
async def _describe_tasks(self, cluster: str, task_arns: List[str]) -> List[Dict[str, Any]]:
|
|
189
|
+
async with self.aws.client("ecs") as ecs:
|
|
190
|
+
response = await ecs.describe_tasks(cluster=cluster, tasks=task_arns)
|
|
191
|
+
return response.get("tasks", [])
|
|
192
|
+
|
|
193
|
+
async def _get_fargate_logs(
|
|
194
|
+
self,
|
|
195
|
+
log_group_name: str,
|
|
196
|
+
log_stream_prefix: Optional[str] = None,
|
|
197
|
+
start_time: Optional[datetime] = None,
|
|
198
|
+
limit: int = 100,
|
|
199
|
+
) -> List[Dict[str, Any]]:
|
|
200
|
+
params: Dict[str, Any] = {
|
|
201
|
+
"logGroupName": log_group_name,
|
|
202
|
+
"limit": limit,
|
|
203
|
+
}
|
|
204
|
+
if log_stream_prefix:
|
|
205
|
+
params["logStreamNamePrefix"] = log_stream_prefix
|
|
206
|
+
if start_time:
|
|
207
|
+
params["startTime"] = int(start_time.timestamp() * 1000)
|
|
208
|
+
|
|
209
|
+
async with self.aws.client("logs") as logs:
|
|
210
|
+
response = await logs.filter_log_events(**params)
|
|
211
|
+
return [
|
|
212
|
+
{
|
|
213
|
+
"timestamp": datetime.fromtimestamp(event["timestamp"] / 1000).isoformat(),
|
|
214
|
+
"message": event.get("message"),
|
|
215
|
+
"log_stream": event.get("logStreamName"),
|
|
216
|
+
}
|
|
217
|
+
for event in response.get("events", [])
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
async def _describe_eks_cluster(self, cluster_name: str) -> Dict[str, Any]:
|
|
221
|
+
async with self.aws.client("eks") as eks:
|
|
222
|
+
response = await eks.describe_cluster(name=cluster_name)
|
|
223
|
+
cluster = response.get("cluster", {})
|
|
224
|
+
return {
|
|
225
|
+
"name": cluster.get("name"),
|
|
226
|
+
"status": cluster.get("status"),
|
|
227
|
+
"version": cluster.get("version"),
|
|
228
|
+
"endpoint": cluster.get("endpoint"),
|
|
229
|
+
"arn": cluster.get("arn"),
|
|
230
|
+
"created_at": cluster.get("createdAt").isoformat()
|
|
231
|
+
if cluster.get("createdAt")
|
|
232
|
+
else None,
|
|
233
|
+
"role_arn": cluster.get("roleArn"),
|
|
234
|
+
"platform_version": cluster.get("platformVersion"),
|
|
235
|
+
"kubernetes_network_config": cluster.get("kubernetesNetworkConfig"),
|
|
236
|
+
"logging": cluster.get("logging"),
|
|
237
|
+
"resources_vpc_config": cluster.get("resourcesVpcConfig"),
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async def _get_eks_cluster_info(self, cluster_name: str) -> Dict[str, Any]:
|
|
241
|
+
"""Backward-compatible alias for describing an EKS cluster."""
|
|
242
|
+
return await self._describe_eks_cluster(cluster_name)
|
|
243
|
+
|
|
244
|
+
async def _list_eks_clusters(self) -> List[str]:
|
|
245
|
+
async with self.aws.client("eks") as eks:
|
|
246
|
+
response = await eks.list_clusters()
|
|
247
|
+
return response.get("clusters", [])
|
|
248
|
+
|
|
249
|
+
async def list_eks_clusters(self) -> List[str]:
|
|
250
|
+
"""Public helper for listing available EKS clusters."""
|
|
251
|
+
|
|
252
|
+
return await self._list_eks_clusters()
|
|
253
|
+
|
|
254
|
+
async def _list_eks_nodegroups(self, cluster_name: str) -> List[str]:
|
|
255
|
+
async with self.aws.client("eks") as eks:
|
|
256
|
+
response = await eks.list_nodegroups(clusterName=cluster_name)
|
|
257
|
+
return response.get("nodegroups", [])
|
|
258
|
+
|
|
259
|
+
async def _describe_eks_nodegroup(self, cluster_name: str, nodegroup: str) -> Dict[str, Any]:
|
|
260
|
+
async with self.aws.client("eks") as eks:
|
|
261
|
+
response = await eks.describe_nodegroup(clusterName=cluster_name, nodegroupName=nodegroup)
|
|
262
|
+
return response.get("nodegroup", {})
|
|
263
|
+
|
|
264
|
+
async def _list_eks_fargate_profiles(self, cluster_name: str) -> List[str]:
|
|
265
|
+
async with self.aws.client("eks") as eks:
|
|
266
|
+
response = await eks.list_fargate_profiles(clusterName=cluster_name)
|
|
267
|
+
return response.get("fargateProfileNames", [])
|
|
268
|
+
|
|
269
|
+
async def _describe_eks_fargate_profile(
|
|
270
|
+
self, cluster_name: str, fargate_profile: str
|
|
271
|
+
) -> Dict[str, Any]:
|
|
272
|
+
async with self.aws.client("eks") as eks:
|
|
273
|
+
response = await eks.describe_fargate_profile(
|
|
274
|
+
clusterName=cluster_name, fargateProfileName=fargate_profile
|
|
275
|
+
)
|
|
276
|
+
return response.get("fargateProfile", {})
|
|
277
|
+
|
|
278
|
+
async def _get_eks_token(self, cluster_name: str) -> str:
|
|
279
|
+
"""Generate an authentication token for EKS cluster using STS."""
|
|
280
|
+
try:
|
|
281
|
+
session = boto_session.Session()
|
|
282
|
+
client = session.create_client('sts', region_name=self.aws._region)
|
|
283
|
+
|
|
284
|
+
service_id = client.meta.service_model.service_id
|
|
285
|
+
signer = RequestSigner(
|
|
286
|
+
service_id,
|
|
287
|
+
self.aws._region,
|
|
288
|
+
'sts',
|
|
289
|
+
'v4',
|
|
290
|
+
session.get_credentials(),
|
|
291
|
+
session.get_component('event_emitter')
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
params = {
|
|
295
|
+
'method': 'GET',
|
|
296
|
+
'url': f'https://sts.{self.aws._region}.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15',
|
|
297
|
+
'body': {},
|
|
298
|
+
'headers': {
|
|
299
|
+
'x-k8s-aws-id': cluster_name
|
|
300
|
+
},
|
|
301
|
+
'context': {}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
signed_url = signer.generate_presigned_url(
|
|
305
|
+
params,
|
|
306
|
+
region_name=self.aws._region,
|
|
307
|
+
expires_in=60,
|
|
308
|
+
operation_name=''
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
token = f"k8s-aws-v1.{base64.urlsafe_b64encode(signed_url.encode()).decode().rstrip('=')}"
|
|
312
|
+
return token
|
|
313
|
+
except Exception as exc:
|
|
314
|
+
raise ValueError(f"Failed to generate EKS token: {exc}")
|
|
315
|
+
|
|
316
|
+
async def _list_eks_pods(
|
|
317
|
+
self, cluster_name: str, namespace: Optional[str] = None
|
|
318
|
+
) -> List[Dict[str, Any]]:
|
|
319
|
+
"""
|
|
320
|
+
List all pods in an EKS cluster.
|
|
321
|
+
|
|
322
|
+
This method authenticates with the EKS cluster using AWS STS and queries
|
|
323
|
+
the Kubernetes API to retrieve pod information.
|
|
324
|
+
"""
|
|
325
|
+
try:
|
|
326
|
+
# Import aiohttp for making HTTP requests to k8s API
|
|
327
|
+
# Get cluster endpoint and certificate
|
|
328
|
+
cluster_info = await self._describe_eks_cluster(cluster_name)
|
|
329
|
+
endpoint = cluster_info.get("endpoint")
|
|
330
|
+
ca_data = cluster_info.get("resources_vpc_config", {})
|
|
331
|
+
|
|
332
|
+
if not endpoint:
|
|
333
|
+
raise ValueError(f"Could not get endpoint for cluster {cluster_name}")
|
|
334
|
+
|
|
335
|
+
# Get authentication token
|
|
336
|
+
token = await self._get_eks_token(cluster_name)
|
|
337
|
+
|
|
338
|
+
# Prepare the API URL
|
|
339
|
+
if namespace:
|
|
340
|
+
url = f"{endpoint}/api/v1/namespaces/{namespace}/pods"
|
|
341
|
+
else:
|
|
342
|
+
url = f"{endpoint}/api/v1/pods"
|
|
343
|
+
|
|
344
|
+
# Create SSL context (skip verification for simplicity, or use cluster CA)
|
|
345
|
+
ssl_context = ssl.create_default_context()
|
|
346
|
+
ssl_context.check_hostname = False
|
|
347
|
+
ssl_context.verify_mode = ssl.CERT_NONE
|
|
348
|
+
|
|
349
|
+
headers = {
|
|
350
|
+
"Authorization": f"Bearer {token}",
|
|
351
|
+
"Accept": "application/json"
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async with aiohttp.ClientSession() as session:
|
|
355
|
+
async with session.get(url, headers=headers, ssl=ssl_context) as response:
|
|
356
|
+
if response.status != 200:
|
|
357
|
+
error_text = await response.text()
|
|
358
|
+
raise ValueError(
|
|
359
|
+
f"Failed to list pods: HTTP {response.status} - {error_text}"
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
data = await response.json()
|
|
363
|
+
items = data.get("items", [])
|
|
364
|
+
|
|
365
|
+
# Extract relevant pod information
|
|
366
|
+
pods = []
|
|
367
|
+
for item in items:
|
|
368
|
+
metadata = item.get("metadata", {})
|
|
369
|
+
spec = item.get("spec", {})
|
|
370
|
+
status = item.get("status", {})
|
|
371
|
+
|
|
372
|
+
pod_info = {
|
|
373
|
+
"name": metadata.get("name"),
|
|
374
|
+
"namespace": metadata.get("namespace"),
|
|
375
|
+
"uid": metadata.get("uid"),
|
|
376
|
+
"creation_timestamp": metadata.get("creationTimestamp"),
|
|
377
|
+
"labels": metadata.get("labels", {}),
|
|
378
|
+
"annotations": metadata.get("annotations", {}),
|
|
379
|
+
"node_name": spec.get("nodeName"),
|
|
380
|
+
"phase": status.get("phase"),
|
|
381
|
+
"pod_ip": status.get("podIP"),
|
|
382
|
+
"host_ip": status.get("hostIP"),
|
|
383
|
+
"start_time": status.get("startTime"),
|
|
384
|
+
"conditions": status.get("conditions", []),
|
|
385
|
+
"container_statuses": status.get("containerStatuses", []),
|
|
386
|
+
}
|
|
387
|
+
pods.append(pod_info)
|
|
388
|
+
|
|
389
|
+
return pods
|
|
390
|
+
|
|
391
|
+
except ImportError as e:
|
|
392
|
+
raise ValueError(
|
|
393
|
+
"aiohttp is required to list EKS pods. Install it with: pip install aiohttp"
|
|
394
|
+
) from e
|
|
395
|
+
except Exception as exc:
|
|
396
|
+
raise ValueError(
|
|
397
|
+
f"Failed to list EKS pods: {exc}"
|
|
398
|
+
) from exc
|
|
399
|
+
|
|
400
|
+
async def _list_ec2_instances(
|
|
401
|
+
self,
|
|
402
|
+
instance_state: Optional[str] = None,
|
|
403
|
+
instance_ids: Optional[List[str]] = None,
|
|
404
|
+
) -> List[Dict[str, Any]]:
|
|
405
|
+
"""
|
|
406
|
+
List EC2 instances in the AWS account.
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
instance_state: Filter by instance state (e.g., 'running', 'stopped')
|
|
410
|
+
instance_ids: Specific instance IDs to describe
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
List of EC2 instance information dictionaries
|
|
414
|
+
"""
|
|
415
|
+
params: Dict[str, Any] = {}
|
|
416
|
+
|
|
417
|
+
# Build filters
|
|
418
|
+
filters = []
|
|
419
|
+
if instance_state:
|
|
420
|
+
filters.append(
|
|
421
|
+
{"Name": "instance-state-name", "Values": [instance_state]}
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
if filters:
|
|
425
|
+
params["Filters"] = filters
|
|
426
|
+
|
|
427
|
+
if instance_ids:
|
|
428
|
+
params["InstanceIds"] = instance_ids
|
|
429
|
+
|
|
430
|
+
async with self.aws.client("ec2") as ec2:
|
|
431
|
+
response = await ec2.describe_instances(**params)
|
|
432
|
+
|
|
433
|
+
instances = []
|
|
434
|
+
for reservation in response.get("Reservations", []):
|
|
435
|
+
for instance in reservation.get("Instances", []):
|
|
436
|
+
# Extract relevant instance information
|
|
437
|
+
instance_info = {
|
|
438
|
+
"instance_id": instance.get("InstanceId"),
|
|
439
|
+
"instance_type": instance.get("InstanceType"),
|
|
440
|
+
"state": instance.get("State", {}).get("Name"),
|
|
441
|
+
"state_code": instance.get("State", {}).get("Code"),
|
|
442
|
+
"launch_time": instance.get("LaunchTime").isoformat()
|
|
443
|
+
if instance.get("LaunchTime")
|
|
444
|
+
else None,
|
|
445
|
+
"availability_zone": instance.get("Placement", {}).get(
|
|
446
|
+
"AvailabilityZone"
|
|
447
|
+
),
|
|
448
|
+
"private_ip": instance.get("PrivateIpAddress"),
|
|
449
|
+
"public_ip": instance.get("PublicIpAddress"),
|
|
450
|
+
"private_dns": instance.get("PrivateDnsName"),
|
|
451
|
+
"public_dns": instance.get("PublicDnsName"),
|
|
452
|
+
"vpc_id": instance.get("VpcId"),
|
|
453
|
+
"subnet_id": instance.get("SubnetId"),
|
|
454
|
+
"architecture": instance.get("Architecture"),
|
|
455
|
+
"image_id": instance.get("ImageId"),
|
|
456
|
+
"key_name": instance.get("KeyName"),
|
|
457
|
+
"platform": instance.get("Platform"),
|
|
458
|
+
"tags": {
|
|
459
|
+
tag.get("Key"): tag.get("Value")
|
|
460
|
+
for tag in instance.get("Tags", [])
|
|
461
|
+
},
|
|
462
|
+
"security_groups": [
|
|
463
|
+
{
|
|
464
|
+
"id": sg.get("GroupId"),
|
|
465
|
+
"name": sg.get("GroupName"),
|
|
466
|
+
}
|
|
467
|
+
for sg in instance.get("SecurityGroups", [])
|
|
468
|
+
],
|
|
469
|
+
}
|
|
470
|
+
instances.append(instance_info)
|
|
471
|
+
|
|
472
|
+
return instances
|
|
473
|
+
|
|
474
|
+
async def _execute(self, **kwargs) -> ToolResult:
|
|
475
|
+
try:
|
|
476
|
+
operation = kwargs.get("operation")
|
|
477
|
+
|
|
478
|
+
if operation == ECSOperation.LIST_ECS_CLUSTERS:
|
|
479
|
+
clusters = await self._list_ecs_clusters()
|
|
480
|
+
return ToolResult(
|
|
481
|
+
success=True,
|
|
482
|
+
status="completed",
|
|
483
|
+
result={"clusters": clusters, "count": len(clusters)},
|
|
484
|
+
metadata={"operation": "list_ecs_clusters"},
|
|
485
|
+
error=None,
|
|
486
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
if operation in (
|
|
490
|
+
ECSOperation.LIST_ECS_SERVICES,
|
|
491
|
+
ECSOperation.LIST_SERVICES,
|
|
492
|
+
):
|
|
493
|
+
if not kwargs.get("cluster_name"):
|
|
494
|
+
return ToolResult(
|
|
495
|
+
success=False,
|
|
496
|
+
status="error",
|
|
497
|
+
result=None,
|
|
498
|
+
error="cluster_name is required for list_ecs_services",
|
|
499
|
+
metadata={},
|
|
500
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
501
|
+
)
|
|
502
|
+
services = await self._list_services(kwargs["cluster_name"])
|
|
503
|
+
return ToolResult(
|
|
504
|
+
success=True,
|
|
505
|
+
status="completed",
|
|
506
|
+
result={"services": services, "count": len(services)},
|
|
507
|
+
metadata={
|
|
508
|
+
"operation": ECSOperation.LIST_ECS_SERVICES.value,
|
|
509
|
+
"cluster": kwargs["cluster_name"],
|
|
510
|
+
},
|
|
511
|
+
error=None,
|
|
512
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
if operation in (ECSOperation.LIST_ECS_TASKS, ECSOperation.LIST_TASKS):
|
|
516
|
+
if not kwargs.get("cluster_name"):
|
|
517
|
+
return ToolResult(
|
|
518
|
+
success=False,
|
|
519
|
+
status="error",
|
|
520
|
+
result=None,
|
|
521
|
+
error="cluster_name is required for list_ecs_tasks",
|
|
522
|
+
metadata={},
|
|
523
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
524
|
+
)
|
|
525
|
+
tasks = await self._list_tasks(
|
|
526
|
+
cluster=kwargs["cluster_name"],
|
|
527
|
+
service_name=kwargs.get("service_name"),
|
|
528
|
+
desired_status=kwargs.get("desired_status"),
|
|
529
|
+
launch_type=kwargs.get("launch_type"),
|
|
530
|
+
)
|
|
531
|
+
return ToolResult(
|
|
532
|
+
success=True,
|
|
533
|
+
status="completed",
|
|
534
|
+
result={"tasks": tasks, "count": len(tasks)},
|
|
535
|
+
metadata={
|
|
536
|
+
"operation": ECSOperation.LIST_ECS_TASKS.value,
|
|
537
|
+
"cluster": kwargs["cluster_name"],
|
|
538
|
+
"service": kwargs.get("service_name"),
|
|
539
|
+
},
|
|
540
|
+
error=None,
|
|
541
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
if operation in (
|
|
545
|
+
ECSOperation.DESCRIBE_ECS_TASKS,
|
|
546
|
+
ECSOperation.DESCRIBE_TASKS,
|
|
547
|
+
):
|
|
548
|
+
if not kwargs.get("cluster_name") or not kwargs.get("task_arns"):
|
|
549
|
+
return ToolResult(
|
|
550
|
+
success=False,
|
|
551
|
+
status="error",
|
|
552
|
+
result=None,
|
|
553
|
+
error="cluster_name and task_arns are required for describe_ecs_tasks",
|
|
554
|
+
metadata={},
|
|
555
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
556
|
+
)
|
|
557
|
+
details = await self._describe_tasks(
|
|
558
|
+
cluster=kwargs["cluster_name"], task_arns=kwargs["task_arns"]
|
|
559
|
+
)
|
|
560
|
+
return ToolResult(
|
|
561
|
+
success=True,
|
|
562
|
+
status="completed",
|
|
563
|
+
result={"tasks": details, "count": len(details)},
|
|
564
|
+
metadata={
|
|
565
|
+
"operation": ECSOperation.DESCRIBE_ECS_TASKS.value,
|
|
566
|
+
"cluster": kwargs["cluster_name"],
|
|
567
|
+
},
|
|
568
|
+
error=None,
|
|
569
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
if operation in (
|
|
573
|
+
ECSOperation.GET_FARGATE_TASK_LOGS,
|
|
574
|
+
ECSOperation.GET_FARGATE_LOGS,
|
|
575
|
+
):
|
|
576
|
+
if not kwargs.get("log_group_name"):
|
|
577
|
+
return ToolResult(
|
|
578
|
+
success=False,
|
|
579
|
+
status="error",
|
|
580
|
+
result=None,
|
|
581
|
+
error="log_group_name is required for get_fargate_task_logs",
|
|
582
|
+
metadata={},
|
|
583
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
584
|
+
)
|
|
585
|
+
start_time = self._parse_time(kwargs.get("start_time")) if kwargs.get("start_time") else None
|
|
586
|
+
events = await self._get_fargate_logs(
|
|
587
|
+
log_group_name=kwargs["log_group_name"],
|
|
588
|
+
log_stream_prefix=kwargs.get("log_stream_prefix"),
|
|
589
|
+
start_time=start_time,
|
|
590
|
+
limit=kwargs.get("limit", 100),
|
|
591
|
+
)
|
|
592
|
+
return ToolResult(
|
|
593
|
+
success=True,
|
|
594
|
+
status="completed",
|
|
595
|
+
result={"events": events, "count": len(events)},
|
|
596
|
+
metadata={
|
|
597
|
+
"operation": ECSOperation.GET_FARGATE_TASK_LOGS.value,
|
|
598
|
+
"log_group": kwargs["log_group_name"],
|
|
599
|
+
"log_stream_prefix": kwargs.get("log_stream_prefix"),
|
|
600
|
+
},
|
|
601
|
+
error=None,
|
|
602
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
if operation in (
|
|
606
|
+
ECSOperation.DESCRIBE_EKS_CLUSTER,
|
|
607
|
+
ECSOperation.GET_EKS_CLUSTER_INFO,
|
|
608
|
+
):
|
|
609
|
+
if not kwargs.get("cluster_name"):
|
|
610
|
+
return ToolResult(
|
|
611
|
+
success=False,
|
|
612
|
+
status="error",
|
|
613
|
+
result=None,
|
|
614
|
+
error="cluster_name is required for describe_eks_cluster",
|
|
615
|
+
metadata={},
|
|
616
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
617
|
+
)
|
|
618
|
+
info = await self._describe_eks_cluster(kwargs["cluster_name"])
|
|
619
|
+
return ToolResult(
|
|
620
|
+
success=True,
|
|
621
|
+
status="completed",
|
|
622
|
+
result=info,
|
|
623
|
+
metadata={
|
|
624
|
+
"operation": ECSOperation.DESCRIBE_EKS_CLUSTER.value,
|
|
625
|
+
"cluster": kwargs["cluster_name"],
|
|
626
|
+
},
|
|
627
|
+
error=None,
|
|
628
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
629
|
+
)
|
|
630
|
+
|
|
631
|
+
if operation == ECSOperation.LIST_EKS_CLUSTERS:
|
|
632
|
+
clusters = await self._list_eks_clusters()
|
|
633
|
+
return ToolResult(
|
|
634
|
+
success=True,
|
|
635
|
+
status="completed",
|
|
636
|
+
result={"clusters": clusters, "count": len(clusters)},
|
|
637
|
+
metadata={"operation": ECSOperation.LIST_EKS_CLUSTERS.value},
|
|
638
|
+
error=None,
|
|
639
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
640
|
+
)
|
|
641
|
+
|
|
642
|
+
if operation == ECSOperation.LIST_EKS_NODEGROUPS:
|
|
643
|
+
if not kwargs.get("cluster_name"):
|
|
644
|
+
return ToolResult(
|
|
645
|
+
success=False,
|
|
646
|
+
status="error",
|
|
647
|
+
result=None,
|
|
648
|
+
error="cluster_name is required for list_eks_nodegroups",
|
|
649
|
+
metadata={},
|
|
650
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
651
|
+
)
|
|
652
|
+
nodegroups = await self._list_eks_nodegroups(kwargs["cluster_name"])
|
|
653
|
+
return ToolResult(
|
|
654
|
+
success=True,
|
|
655
|
+
status="completed",
|
|
656
|
+
result={"nodegroups": nodegroups, "count": len(nodegroups)},
|
|
657
|
+
metadata={
|
|
658
|
+
"operation": ECSOperation.LIST_EKS_NODEGROUPS.value,
|
|
659
|
+
"cluster": kwargs["cluster_name"],
|
|
660
|
+
},
|
|
661
|
+
error=None,
|
|
662
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
if operation == ECSOperation.DESCRIBE_EKS_NODEGROUP:
|
|
666
|
+
if not kwargs.get("cluster_name") or not kwargs.get("eks_nodegroup"):
|
|
667
|
+
return ToolResult(
|
|
668
|
+
success=False,
|
|
669
|
+
status="error",
|
|
670
|
+
result=None,
|
|
671
|
+
error="cluster_name and eks_nodegroup are required for describe_eks_nodegroup",
|
|
672
|
+
metadata={},
|
|
673
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
674
|
+
)
|
|
675
|
+
nodegroup = await self._describe_eks_nodegroup(
|
|
676
|
+
cluster_name=kwargs["cluster_name"], nodegroup=kwargs["eks_nodegroup"]
|
|
677
|
+
)
|
|
678
|
+
return ToolResult(
|
|
679
|
+
success=True,
|
|
680
|
+
status="completed",
|
|
681
|
+
result=nodegroup,
|
|
682
|
+
metadata={
|
|
683
|
+
"operation": ECSOperation.DESCRIBE_EKS_NODEGROUP.value,
|
|
684
|
+
"cluster": kwargs["cluster_name"],
|
|
685
|
+
"nodegroup": kwargs["eks_nodegroup"],
|
|
686
|
+
},
|
|
687
|
+
error=None,
|
|
688
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
if operation == ECSOperation.LIST_EKS_FARGATE_PROFILES:
|
|
692
|
+
if not kwargs.get("cluster_name"):
|
|
693
|
+
return ToolResult(
|
|
694
|
+
success=False,
|
|
695
|
+
status="error",
|
|
696
|
+
result=None,
|
|
697
|
+
error="cluster_name is required for list_eks_fargate_profiles",
|
|
698
|
+
metadata={},
|
|
699
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
700
|
+
)
|
|
701
|
+
profiles = await self._list_eks_fargate_profiles(kwargs["cluster_name"])
|
|
702
|
+
return ToolResult(
|
|
703
|
+
success=True,
|
|
704
|
+
status="completed",
|
|
705
|
+
result={"fargate_profiles": profiles, "count": len(profiles)},
|
|
706
|
+
metadata={
|
|
707
|
+
"operation": ECSOperation.LIST_EKS_FARGATE_PROFILES.value,
|
|
708
|
+
"cluster": kwargs["cluster_name"],
|
|
709
|
+
},
|
|
710
|
+
error=None,
|
|
711
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
if operation == ECSOperation.DESCRIBE_EKS_FARGATE_PROFILE:
|
|
715
|
+
if not kwargs.get("cluster_name") or not kwargs.get("eks_fargate_profile"):
|
|
716
|
+
return ToolResult(
|
|
717
|
+
success=False,
|
|
718
|
+
status="error",
|
|
719
|
+
result=None,
|
|
720
|
+
error=(
|
|
721
|
+
"cluster_name and eks_fargate_profile are required for "
|
|
722
|
+
"describe_eks_fargate_profile"
|
|
723
|
+
),
|
|
724
|
+
metadata={},
|
|
725
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
726
|
+
)
|
|
727
|
+
profile = await self._describe_eks_fargate_profile(
|
|
728
|
+
cluster_name=kwargs["cluster_name"],
|
|
729
|
+
fargate_profile=kwargs["eks_fargate_profile"],
|
|
730
|
+
)
|
|
731
|
+
return ToolResult(
|
|
732
|
+
success=True,
|
|
733
|
+
status="completed",
|
|
734
|
+
result=profile,
|
|
735
|
+
metadata={
|
|
736
|
+
"operation": ECSOperation.DESCRIBE_EKS_FARGATE_PROFILE.value,
|
|
737
|
+
"cluster": kwargs["cluster_name"],
|
|
738
|
+
"fargate_profile": kwargs["eks_fargate_profile"],
|
|
739
|
+
},
|
|
740
|
+
error=None,
|
|
741
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
742
|
+
)
|
|
743
|
+
|
|
744
|
+
if operation == ECSOperation.LIST_EKS_PODS:
|
|
745
|
+
if not kwargs.get("cluster_name"):
|
|
746
|
+
return ToolResult(
|
|
747
|
+
success=False,
|
|
748
|
+
status="error",
|
|
749
|
+
result=None,
|
|
750
|
+
error="cluster_name is required for list_eks_pods",
|
|
751
|
+
metadata={},
|
|
752
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
753
|
+
)
|
|
754
|
+
pods = await self._list_eks_pods(
|
|
755
|
+
cluster_name=kwargs["cluster_name"],
|
|
756
|
+
namespace=kwargs.get("namespace"),
|
|
757
|
+
)
|
|
758
|
+
return ToolResult(
|
|
759
|
+
success=True,
|
|
760
|
+
status="completed",
|
|
761
|
+
result={"pods": pods, "count": len(pods)},
|
|
762
|
+
metadata={
|
|
763
|
+
"operation": ECSOperation.LIST_EKS_PODS.value,
|
|
764
|
+
"cluster": kwargs["cluster_name"],
|
|
765
|
+
"namespace": kwargs.get("namespace", "all"),
|
|
766
|
+
},
|
|
767
|
+
error=None,
|
|
768
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
if operation == ECSOperation.LIST_EC2_INSTANCES:
|
|
772
|
+
instances = await self._list_ec2_instances(
|
|
773
|
+
instance_state=kwargs.get("instance_state"),
|
|
774
|
+
instance_ids=kwargs.get("instance_ids"),
|
|
775
|
+
)
|
|
776
|
+
return ToolResult(
|
|
777
|
+
success=True,
|
|
778
|
+
status="completed",
|
|
779
|
+
result={"instances": instances, "count": len(instances)},
|
|
780
|
+
metadata={
|
|
781
|
+
"operation": ECSOperation.LIST_EC2_INSTANCES.value,
|
|
782
|
+
"instance_state": kwargs.get("instance_state"),
|
|
783
|
+
},
|
|
784
|
+
error=None,
|
|
785
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
return ToolResult(
|
|
789
|
+
success=False,
|
|
790
|
+
status="error",
|
|
791
|
+
result=None,
|
|
792
|
+
error=f"Unknown operation: {operation}",
|
|
793
|
+
metadata={"operation": str(operation)},
|
|
794
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
except ClientError as exc:
|
|
798
|
+
error_code = exc.response["Error"].get("Code")
|
|
799
|
+
error_msg = exc.response["Error"].get("Message")
|
|
800
|
+
return ToolResult(
|
|
801
|
+
success=False,
|
|
802
|
+
status="aws_error",
|
|
803
|
+
result=None,
|
|
804
|
+
error=f"AWS Error ({error_code}): {error_msg}",
|
|
805
|
+
metadata={"operation": kwargs.get("operation"), "error_code": error_code},
|
|
806
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
807
|
+
)
|
|
808
|
+
except Exception as exc:
|
|
809
|
+
return ToolResult(
|
|
810
|
+
success=False,
|
|
811
|
+
status="error",
|
|
812
|
+
result=None,
|
|
813
|
+
error=f"ECS/EKS operation failed: {exc}",
|
|
814
|
+
metadata={
|
|
815
|
+
"operation": kwargs.get("operation"),
|
|
816
|
+
"exception_type": type(exc).__name__,
|
|
817
|
+
},
|
|
818
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
819
|
+
)
|