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,527 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OpenWeather Tool migrated to use AbstractTool framework with aiohttp.
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
from typing import Dict, Any, Optional, Literal
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import json
|
|
8
|
+
import asyncio
|
|
9
|
+
import aiohttp
|
|
10
|
+
from pydantic import BaseModel, Field, field_validator
|
|
11
|
+
from .abstract import AbstractTool, ToolResult
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class OpenWeatherArgs(BaseModel):
|
|
15
|
+
"""Arguments schema for OpenWeatherTool."""
|
|
16
|
+
|
|
17
|
+
latitude: float = Field(
|
|
18
|
+
...,
|
|
19
|
+
description="The latitude of the location you want weather information about",
|
|
20
|
+
ge=-90.0,
|
|
21
|
+
le=90.0
|
|
22
|
+
)
|
|
23
|
+
longitude: float = Field(
|
|
24
|
+
...,
|
|
25
|
+
description="The longitude of the location you want weather information about",
|
|
26
|
+
ge=-180.0,
|
|
27
|
+
le=180.0
|
|
28
|
+
)
|
|
29
|
+
request_type: Literal['weather', 'forecast'] = Field(
|
|
30
|
+
'weather',
|
|
31
|
+
description="Type of weather information: 'weather' for current conditions, 'forecast' for future predictions"
|
|
32
|
+
)
|
|
33
|
+
units: Literal['metric', 'imperial', 'standard'] = Field(
|
|
34
|
+
'imperial',
|
|
35
|
+
description="Temperature units: 'metric' (Celsius), 'imperial' (Fahrenheit), 'standard' (Kelvin)"
|
|
36
|
+
)
|
|
37
|
+
country: str = Field(
|
|
38
|
+
'us',
|
|
39
|
+
description="Country code for the location (ISO 3166 country codes)"
|
|
40
|
+
)
|
|
41
|
+
forecast_days: int = Field(
|
|
42
|
+
3,
|
|
43
|
+
description="Number of days for forecast (only used when request_type='forecast')",
|
|
44
|
+
ge=1,
|
|
45
|
+
le=16
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
@field_validator('country')
|
|
49
|
+
@classmethod
|
|
50
|
+
def validate_country(cls, v):
|
|
51
|
+
if len(v) != 2:
|
|
52
|
+
raise ValueError("Country code must be exactly 2 characters (ISO 3166)")
|
|
53
|
+
return v.lower()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class OpenWeatherTool(AbstractTool):
|
|
57
|
+
"""
|
|
58
|
+
Tool to get weather information for specific locations using OpenWeatherMap API.
|
|
59
|
+
|
|
60
|
+
This tool provides current weather conditions and weather forecasts for any location
|
|
61
|
+
specified by latitude and longitude coordinates. It supports different temperature
|
|
62
|
+
units and can be configured for different countries.
|
|
63
|
+
|
|
64
|
+
Features:
|
|
65
|
+
- Current weather conditions
|
|
66
|
+
- Weather forecasts (up to 16 days)
|
|
67
|
+
- Multiple temperature units (Celsius, Fahrenheit, Kelvin)
|
|
68
|
+
- Country-specific formatting
|
|
69
|
+
- Comprehensive weather data including temperature, humidity, pressure, wind, etc.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
name = "openweather_tool"
|
|
73
|
+
description = (
|
|
74
|
+
"Get current weather information or forecast for specific coordinates. "
|
|
75
|
+
"Supports current weather and forecasts with configurable units and country settings. "
|
|
76
|
+
"Requires latitude and longitude coordinates."
|
|
77
|
+
)
|
|
78
|
+
args_schema = OpenWeatherArgs
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
api_key: Optional[str] = None,
|
|
83
|
+
default_units: str = 'imperial',
|
|
84
|
+
default_country: str = 'us',
|
|
85
|
+
default_request_type: str = 'weather',
|
|
86
|
+
timeout: int = 10,
|
|
87
|
+
**kwargs
|
|
88
|
+
):
|
|
89
|
+
"""
|
|
90
|
+
Initialize the OpenWeather tool.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
api_key: OpenWeatherMap API key (if None, reads from OPENWEATHER_APPID env var)
|
|
94
|
+
default_units: Default temperature units ('metric', 'imperial', 'standard')
|
|
95
|
+
default_country: Default country code
|
|
96
|
+
default_request_type: Default request type ('weather' or 'forecast')
|
|
97
|
+
timeout: Request timeout in seconds
|
|
98
|
+
**kwargs: Additional arguments for AbstractTool
|
|
99
|
+
"""
|
|
100
|
+
super().__init__(**kwargs)
|
|
101
|
+
|
|
102
|
+
# API configuration
|
|
103
|
+
self.api_key = api_key or os.getenv('OPENWEATHER_APPID')
|
|
104
|
+
if not self.api_key:
|
|
105
|
+
raise ValueError(
|
|
106
|
+
"OpenWeather API key must be provided or set in OPENWEATHER_APPID environment variable"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Default settings
|
|
110
|
+
self.default_units = default_units
|
|
111
|
+
self.default_country = default_country
|
|
112
|
+
self.default_request_type = default_request_type
|
|
113
|
+
self.timeout = timeout
|
|
114
|
+
|
|
115
|
+
# API endpoints
|
|
116
|
+
self.base_url = "https://api.openweathermap.org/data/2.5"
|
|
117
|
+
|
|
118
|
+
self.logger.info(
|
|
119
|
+
f"OpenWeather tool initialized with defaults: units={default_units}, country={default_country}"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def _default_output_dir(self) -> Optional[Path]:
|
|
123
|
+
"""Get the default output directory for weather data."""
|
|
124
|
+
return self.static_dir / "weather_data" if self.static_dir else None
|
|
125
|
+
|
|
126
|
+
def _build_url(
|
|
127
|
+
self,
|
|
128
|
+
latitude: float,
|
|
129
|
+
longitude: float,
|
|
130
|
+
request_type: str,
|
|
131
|
+
units: str,
|
|
132
|
+
forecast_days: int
|
|
133
|
+
) -> str:
|
|
134
|
+
"""
|
|
135
|
+
Build the appropriate API URL based on request type.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
latitude: Latitude coordinate
|
|
139
|
+
longitude: Longitude coordinate
|
|
140
|
+
request_type: Type of request ('weather' or 'forecast')
|
|
141
|
+
units: Temperature units
|
|
142
|
+
forecast_days: Number of forecast days
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
Complete API URL
|
|
146
|
+
"""
|
|
147
|
+
base_params = f"lat={latitude}&lon={longitude}&units={units}&appid={self.api_key}"
|
|
148
|
+
if request_type == 'weather':
|
|
149
|
+
# Current weather - exclude minutely and hourly for cleaner response
|
|
150
|
+
url = f"{self.base_url}/weather?{base_params}&exclude=minutely,hourly"
|
|
151
|
+
elif request_type == 'forecast':
|
|
152
|
+
# For forecast, use the 5-day/3-hour forecast API
|
|
153
|
+
# cnt parameter limits the number of forecast entries (each is 3 hours)
|
|
154
|
+
cnt = min(forecast_days * 8, 40) # Max 40 entries (5 days * 8 intervals per day)
|
|
155
|
+
url = f"{self.base_url}/forecast?{base_params}&cnt={cnt}"
|
|
156
|
+
else:
|
|
157
|
+
raise ValueError(f"Invalid request type: {request_type}")
|
|
158
|
+
return url
|
|
159
|
+
|
|
160
|
+
def _format_weather_response(
|
|
161
|
+
self,
|
|
162
|
+
data: Dict[str, Any],
|
|
163
|
+
request_type: str,
|
|
164
|
+
units: str,
|
|
165
|
+
latitude: float,
|
|
166
|
+
longitude: float
|
|
167
|
+
) -> Dict[str, Any]:
|
|
168
|
+
"""
|
|
169
|
+
Format the weather API response for better usability.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
data: Raw API response
|
|
173
|
+
request_type: Type of request
|
|
174
|
+
units: Temperature units used
|
|
175
|
+
latitude: Original latitude
|
|
176
|
+
longitude: Original longitude
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Formatted weather data
|
|
180
|
+
"""
|
|
181
|
+
try:
|
|
182
|
+
# Determine temperature unit symbol
|
|
183
|
+
temp_unit = {
|
|
184
|
+
'metric': '°C',
|
|
185
|
+
'imperial': '°F',
|
|
186
|
+
'standard': 'K'
|
|
187
|
+
}.get(units, '°F')
|
|
188
|
+
|
|
189
|
+
if request_type == 'weather':
|
|
190
|
+
# Format current weather
|
|
191
|
+
main = data.get('main', {})
|
|
192
|
+
weather = data.get('weather', [{}])[0]
|
|
193
|
+
wind = data.get('wind', {})
|
|
194
|
+
sys = data.get('sys', {})
|
|
195
|
+
|
|
196
|
+
formatted = {
|
|
197
|
+
'location': {
|
|
198
|
+
'latitude': latitude,
|
|
199
|
+
'longitude': longitude,
|
|
200
|
+
'city': data.get('name', 'Unknown'),
|
|
201
|
+
'country': sys.get('country', 'Unknown')
|
|
202
|
+
},
|
|
203
|
+
'current_weather': {
|
|
204
|
+
'temperature': f"{main.get('temp', 'N/A')}{temp_unit}",
|
|
205
|
+
'feels_like': f"{main.get('feels_like', 'N/A')}{temp_unit}",
|
|
206
|
+
'temperature_min': f"{main.get('temp_min', 'N/A')}{temp_unit}",
|
|
207
|
+
'temperature_max': f"{main.get('temp_max', 'N/A')}{temp_unit}",
|
|
208
|
+
'description': weather.get('description', 'N/A').title(),
|
|
209
|
+
'condition': weather.get('main', 'N/A'),
|
|
210
|
+
'humidity': f"{main.get('humidity', 'N/A')}%",
|
|
211
|
+
'pressure': f"{main.get('pressure', 'N/A')} hPa",
|
|
212
|
+
'visibility': f"{data.get('visibility', 'N/A')} m" if 'visibility' in data else 'N/A'
|
|
213
|
+
},
|
|
214
|
+
'wind': {
|
|
215
|
+
'speed': f"{wind.get('speed', 'N/A')} {'mph' if units == 'imperial' else 'm/s'}",
|
|
216
|
+
'direction': f"{wind.get('deg', 'N/A')}°" if 'deg' in wind else 'N/A',
|
|
217
|
+
'gust': f"{wind.get('gust', 'N/A')} {'mph' if units == 'imperial' else 'm/s'}" if 'gust' in wind else 'N/A'
|
|
218
|
+
},
|
|
219
|
+
'metadata': {
|
|
220
|
+
'request_type': request_type,
|
|
221
|
+
'units': units,
|
|
222
|
+
'timestamp': data.get('dt'),
|
|
223
|
+
'timezone': data.get('timezone'),
|
|
224
|
+
'sunrise': sys.get('sunrise'),
|
|
225
|
+
'sunset': sys.get('sunset')
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
else: # forecast
|
|
230
|
+
# Format forecast data
|
|
231
|
+
forecasts = []
|
|
232
|
+
for item in data.get('list', []):
|
|
233
|
+
main = item.get('main', {})
|
|
234
|
+
weather = item.get('weather', [{}])[0]
|
|
235
|
+
wind = item.get('wind', {})
|
|
236
|
+
|
|
237
|
+
forecast_item = {
|
|
238
|
+
'datetime': item.get('dt_txt', 'N/A'),
|
|
239
|
+
'timestamp': item.get('dt'),
|
|
240
|
+
'temperature': f"{main.get('temp', 'N/A')}{temp_unit}",
|
|
241
|
+
'feels_like': f"{main.get('feels_like', 'N/A')}{temp_unit}",
|
|
242
|
+
'temperature_min': f"{main.get('temp_min', 'N/A')}{temp_unit}",
|
|
243
|
+
'temperature_max': f"{main.get('temp_max', 'N/A')}{temp_unit}",
|
|
244
|
+
'description': weather.get('description', 'N/A').title(),
|
|
245
|
+
'condition': weather.get('main', 'N/A'),
|
|
246
|
+
'humidity': f"{main.get('humidity', 'N/A')}%",
|
|
247
|
+
'pressure': f"{main.get('pressure', 'N/A')} hPa",
|
|
248
|
+
'wind_speed': f"{wind.get('speed', 'N/A')} {'mph' if units == 'imperial' else 'm/s'}",
|
|
249
|
+
'precipitation_probability': f"{item.get('pop', 0) * 100:.0f}%" if 'pop' in item else 'N/A'
|
|
250
|
+
}
|
|
251
|
+
forecasts.append(forecast_item)
|
|
252
|
+
|
|
253
|
+
city = data.get('city', {})
|
|
254
|
+
formatted = {
|
|
255
|
+
'location': {
|
|
256
|
+
'latitude': latitude,
|
|
257
|
+
'longitude': longitude,
|
|
258
|
+
'city': city.get('name', 'Unknown'),
|
|
259
|
+
'country': city.get('country', 'Unknown')
|
|
260
|
+
},
|
|
261
|
+
'forecast': forecasts,
|
|
262
|
+
'forecast_summary': {
|
|
263
|
+
'total_entries': len(forecasts),
|
|
264
|
+
'forecast_period': f"{forecasts[0]['datetime']} to {forecasts[-1]['datetime']}" if forecasts else 'N/A'
|
|
265
|
+
},
|
|
266
|
+
'metadata': {
|
|
267
|
+
'request_type': request_type,
|
|
268
|
+
'units': units,
|
|
269
|
+
'timezone': city.get('timezone')
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return formatted
|
|
274
|
+
|
|
275
|
+
except Exception as e:
|
|
276
|
+
self.logger.error(f"Error formatting weather response: {e}")
|
|
277
|
+
# Return raw data if formatting fails
|
|
278
|
+
return {
|
|
279
|
+
'raw_data': data,
|
|
280
|
+
'formatting_error': str(e),
|
|
281
|
+
'metadata': {
|
|
282
|
+
'request_type': request_type,
|
|
283
|
+
'units': units,
|
|
284
|
+
'latitude': latitude,
|
|
285
|
+
'longitude': longitude
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async def _make_weather_request(self, url: str) -> Dict[str, Any]:
|
|
290
|
+
"""
|
|
291
|
+
Make HTTP request to OpenWeather API using aiohttp.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
url: Complete API URL
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
API response as dictionary
|
|
298
|
+
|
|
299
|
+
Raises:
|
|
300
|
+
Exception: If request fails or returns invalid response
|
|
301
|
+
"""
|
|
302
|
+
try:
|
|
303
|
+
timeout = aiohttp.ClientTimeout(total=self.timeout)
|
|
304
|
+
|
|
305
|
+
async with aiohttp.ClientSession(timeout=timeout) as session:
|
|
306
|
+
self.logger.info(f"Making weather API request: {url.split('&appid=')[0]}...")
|
|
307
|
+
|
|
308
|
+
async with session.get(url) as response:
|
|
309
|
+
if response.status == 200:
|
|
310
|
+
data = await response.json()
|
|
311
|
+
self.logger.info(f"Weather API request successful (status: {response.status})")
|
|
312
|
+
return data
|
|
313
|
+
else:
|
|
314
|
+
error_text = await response.text()
|
|
315
|
+
self.logger.error(f"Weather API request failed: {response.status} - {error_text}")
|
|
316
|
+
raise Exception(f"API request failed with status {response.status}: {error_text}")
|
|
317
|
+
|
|
318
|
+
except asyncio.TimeoutError:
|
|
319
|
+
raise Exception(f"Weather API request timed out after {self.timeout} seconds")
|
|
320
|
+
except aiohttp.ClientError as e:
|
|
321
|
+
raise Exception(f"HTTP client error: {str(e)}")
|
|
322
|
+
except Exception as e:
|
|
323
|
+
raise Exception(f"Weather API request failed: {str(e)}")
|
|
324
|
+
|
|
325
|
+
async def _execute(
|
|
326
|
+
self,
|
|
327
|
+
latitude: float,
|
|
328
|
+
longitude: float,
|
|
329
|
+
request_type: str = 'weather',
|
|
330
|
+
units: str = 'imperial',
|
|
331
|
+
country: str = 'us',
|
|
332
|
+
forecast_days: int = 3,
|
|
333
|
+
**kwargs
|
|
334
|
+
) -> Dict[str, Any]:
|
|
335
|
+
"""
|
|
336
|
+
Execute the weather request (AbstractTool interface).
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
latitude: Latitude coordinate
|
|
340
|
+
longitude: Longitude coordinate
|
|
341
|
+
request_type: Type of request ('weather' or 'forecast')
|
|
342
|
+
units: Temperature units ('metric', 'imperial', 'standard')
|
|
343
|
+
country: Country code
|
|
344
|
+
forecast_days: Number of forecast days (for forecast requests)
|
|
345
|
+
**kwargs: Additional arguments
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
Formatted weather data
|
|
349
|
+
"""
|
|
350
|
+
try:
|
|
351
|
+
self.logger.info(
|
|
352
|
+
f"Getting {request_type} for coordinates ({latitude}, {longitude}) "
|
|
353
|
+
f"in {units} units for country {country}"
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
# Build API URL
|
|
357
|
+
url = self._build_url(latitude, longitude, request_type, units, forecast_days)
|
|
358
|
+
|
|
359
|
+
# Make API request
|
|
360
|
+
raw_data = await self._make_weather_request(url)
|
|
361
|
+
|
|
362
|
+
# Format response
|
|
363
|
+
formatted_data = self._format_weather_response(
|
|
364
|
+
raw_data, request_type, units, latitude, longitude
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
self.logger.info(f"Weather data retrieved successfully for {request_type} request")
|
|
368
|
+
return formatted_data
|
|
369
|
+
|
|
370
|
+
except Exception as e:
|
|
371
|
+
self.logger.error(f"Error getting weather data: {e}")
|
|
372
|
+
raise
|
|
373
|
+
|
|
374
|
+
def execute_sync(
|
|
375
|
+
self,
|
|
376
|
+
latitude: float,
|
|
377
|
+
longitude: float,
|
|
378
|
+
request_type: str = 'weather',
|
|
379
|
+
units: str = 'imperial',
|
|
380
|
+
country: str = 'us',
|
|
381
|
+
forecast_days: int = 3
|
|
382
|
+
) -> Dict[str, Any]:
|
|
383
|
+
"""
|
|
384
|
+
Execute weather request synchronously.
|
|
385
|
+
|
|
386
|
+
Args:
|
|
387
|
+
latitude: Latitude coordinate
|
|
388
|
+
longitude: Longitude coordinate
|
|
389
|
+
request_type: Type of request ('weather' or 'forecast')
|
|
390
|
+
units: Temperature units
|
|
391
|
+
country: Country code
|
|
392
|
+
forecast_days: Number of forecast days
|
|
393
|
+
|
|
394
|
+
Returns:
|
|
395
|
+
Formatted weather data
|
|
396
|
+
"""
|
|
397
|
+
try:
|
|
398
|
+
loop = asyncio.get_running_loop()
|
|
399
|
+
task = loop.create_task(self.execute(
|
|
400
|
+
latitude=latitude,
|
|
401
|
+
longitude=longitude,
|
|
402
|
+
request_type=request_type,
|
|
403
|
+
units=units,
|
|
404
|
+
country=country,
|
|
405
|
+
forecast_days=forecast_days
|
|
406
|
+
))
|
|
407
|
+
return task
|
|
408
|
+
except RuntimeError:
|
|
409
|
+
return asyncio.run(self.execute(
|
|
410
|
+
latitude=latitude,
|
|
411
|
+
longitude=longitude,
|
|
412
|
+
request_type=request_type,
|
|
413
|
+
units=units,
|
|
414
|
+
country=country,
|
|
415
|
+
forecast_days=forecast_days
|
|
416
|
+
))
|
|
417
|
+
|
|
418
|
+
def get_weather_summary(self, weather_data: ToolResult) -> str:
|
|
419
|
+
"""
|
|
420
|
+
Generate a human-readable weather summary.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
weather_result: ToolResult object containing weather data
|
|
424
|
+
|
|
425
|
+
Returns:
|
|
426
|
+
Human-readable weather summary
|
|
427
|
+
"""
|
|
428
|
+
try:
|
|
429
|
+
# Extract the actual weather data from ToolResult
|
|
430
|
+
if weather_data.status != "success":
|
|
431
|
+
return f"Weather request failed: {weather_data.error or 'Unknown error'}"
|
|
432
|
+
|
|
433
|
+
weather_data = weather_data.result
|
|
434
|
+
|
|
435
|
+
if weather_data.get('current_weather'):
|
|
436
|
+
# Current weather summary
|
|
437
|
+
current = weather_data['current_weather']
|
|
438
|
+
location = weather_data['location']
|
|
439
|
+
|
|
440
|
+
summary = (
|
|
441
|
+
f"Current weather in {location['city']}, {location['country']}: "
|
|
442
|
+
f"{current['description']} with a temperature of {current['temperature']} "
|
|
443
|
+
f"(feels like {current['feels_like']}). "
|
|
444
|
+
f"Humidity: {current['humidity']}, "
|
|
445
|
+
f"Wind: {weather_data['wind']['speed']}"
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
elif weather_data.get('forecast'):
|
|
449
|
+
# Forecast summary
|
|
450
|
+
location = weather_data['location']
|
|
451
|
+
forecast_count = weather_data['forecast_summary']['total_entries']
|
|
452
|
+
period = weather_data['forecast_summary']['forecast_period']
|
|
453
|
+
|
|
454
|
+
summary = (
|
|
455
|
+
f"Weather forecast for {location['city']}, {location['country']}: "
|
|
456
|
+
f"{forecast_count} forecast entries from {period}"
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
else:
|
|
460
|
+
summary = "Weather data available (see full response for details)"
|
|
461
|
+
|
|
462
|
+
return summary
|
|
463
|
+
|
|
464
|
+
except Exception as e:
|
|
465
|
+
return f"Weather data retrieved (summary generation failed: {e})"
|
|
466
|
+
|
|
467
|
+
def save_weather_data(
|
|
468
|
+
self,
|
|
469
|
+
weather_result: ToolResult,
|
|
470
|
+
filename: Optional[str] = None
|
|
471
|
+
) -> Dict[str, Any]:
|
|
472
|
+
"""
|
|
473
|
+
Save weather data to JSON file.
|
|
474
|
+
|
|
475
|
+
Args:
|
|
476
|
+
weather_result: ToolResult object containing weather data
|
|
477
|
+
filename: Optional filename
|
|
478
|
+
|
|
479
|
+
Returns:
|
|
480
|
+
File information dictionary
|
|
481
|
+
"""
|
|
482
|
+
if not self.output_dir:
|
|
483
|
+
raise ValueError("Output directory not configured")
|
|
484
|
+
|
|
485
|
+
# Extract weather data from ToolResult
|
|
486
|
+
if weather_result.status != "success":
|
|
487
|
+
raise ValueError(f"Cannot save failed weather request: {weather_result.error}")
|
|
488
|
+
|
|
489
|
+
weather_data = weather_result.result
|
|
490
|
+
|
|
491
|
+
if not filename:
|
|
492
|
+
timestamp = self.generate_filename("weather_data", "", include_timestamp=True)
|
|
493
|
+
filename = f"{timestamp}.json"
|
|
494
|
+
elif not filename.endswith('.json'):
|
|
495
|
+
filename = f"{filename}.json"
|
|
496
|
+
|
|
497
|
+
# Ensure output directory exists
|
|
498
|
+
self.output_dir.mkdir(parents=True, exist_ok=True)
|
|
499
|
+
|
|
500
|
+
file_path = self.output_dir / filename
|
|
501
|
+
file_path = self.validate_output_path(file_path)
|
|
502
|
+
|
|
503
|
+
try:
|
|
504
|
+
# Save both the result and metadata from ToolResult
|
|
505
|
+
save_data = {
|
|
506
|
+
"weather_data": weather_data,
|
|
507
|
+
"tool_metadata": {
|
|
508
|
+
"status": weather_result.status,
|
|
509
|
+
"timestamp": weather_result.timestamp,
|
|
510
|
+
"metadata": weather_result.metadata
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
515
|
+
json.dump(save_data, f, indent=2, default=str)
|
|
516
|
+
|
|
517
|
+
file_url = self.to_static_url(file_path)
|
|
518
|
+
|
|
519
|
+
return {
|
|
520
|
+
"filename": filename,
|
|
521
|
+
"file_path": str(file_path),
|
|
522
|
+
"file_url": file_url,
|
|
523
|
+
"file_size": file_path.stat().st_size
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
except Exception as e:
|
|
527
|
+
raise ValueError(f"Error saving weather data: {e}")
|