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,554 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Office365 Tools Implementation.
|
|
3
|
+
|
|
4
|
+
Specific tools for interacting with Office365 services:
|
|
5
|
+
- CreateDraftMessage: Create email drafts
|
|
6
|
+
- CreateEvent: Create calendar events
|
|
7
|
+
- SearchEmail: Search through emails
|
|
8
|
+
- SendEmail: Send emails directly
|
|
9
|
+
"""
|
|
10
|
+
from typing import Dict, Any, Optional, List, Type
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
from msgraph.generated.models.email_address import EmailAddress
|
|
13
|
+
from msgraph.generated.models.item_body import ItemBody
|
|
14
|
+
from msgraph.generated.models.body_type import BodyType
|
|
15
|
+
from msgraph.generated.models.event import Event
|
|
16
|
+
from msgraph.generated.models.date_time_time_zone import DateTimeTimeZone
|
|
17
|
+
from msgraph.generated.models.location import Location
|
|
18
|
+
from msgraph.generated.models.attendee import Attendee
|
|
19
|
+
from msgraph.generated.models.attendee_type import AttendeeType
|
|
20
|
+
from msgraph.generated.models.importance import Importance
|
|
21
|
+
from kiota_abstractions.base_request_configuration import RequestConfiguration
|
|
22
|
+
|
|
23
|
+
from .base import O365Tool, O365ToolArgsSchema, O365Client
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ============================================================================
|
|
27
|
+
# CREATE EVENT TOOL
|
|
28
|
+
# ============================================================================
|
|
29
|
+
|
|
30
|
+
class CreateEventArgs(O365ToolArgsSchema):
|
|
31
|
+
"""Arguments for creating a calendar event."""
|
|
32
|
+
subject: str = Field(
|
|
33
|
+
description="Event subject/title"
|
|
34
|
+
)
|
|
35
|
+
start_datetime: str = Field(
|
|
36
|
+
description="Event start date and time in ISO format (e.g., '2025-01-20T14:00:00')"
|
|
37
|
+
)
|
|
38
|
+
end_datetime: str = Field(
|
|
39
|
+
description="Event end date and time in ISO format (e.g., '2025-01-20T15:00:00')"
|
|
40
|
+
)
|
|
41
|
+
timezone: str = Field(
|
|
42
|
+
default="UTC",
|
|
43
|
+
description="Timezone for the event (e.g., 'America/New_York', 'Europe/London')"
|
|
44
|
+
)
|
|
45
|
+
body: Optional[str] = Field(
|
|
46
|
+
default=None,
|
|
47
|
+
description="Event description/body content"
|
|
48
|
+
)
|
|
49
|
+
location: Optional[str] = Field(
|
|
50
|
+
default=None,
|
|
51
|
+
description="Event location (e.g., 'Conference Room A', 'Zoom Meeting')"
|
|
52
|
+
)
|
|
53
|
+
attendees: Optional[List[str]] = Field(
|
|
54
|
+
default=None,
|
|
55
|
+
description="List of attendee email addresses"
|
|
56
|
+
)
|
|
57
|
+
is_online_meeting: bool = Field(
|
|
58
|
+
default=False,
|
|
59
|
+
description="Whether to create an online meeting (Teams meeting)"
|
|
60
|
+
)
|
|
61
|
+
is_all_day: bool = Field(
|
|
62
|
+
default=False,
|
|
63
|
+
description="Whether this is an all-day event"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class CreateEventTool(O365Tool):
|
|
68
|
+
"""
|
|
69
|
+
Tool for creating calendar events in Office365.
|
|
70
|
+
|
|
71
|
+
This tool creates calendar events with support for:
|
|
72
|
+
- Attendees and invitations
|
|
73
|
+
- Online meetings (Teams)
|
|
74
|
+
- All-day events
|
|
75
|
+
- Timezone handling
|
|
76
|
+
- Location and descriptions
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
# Create a simple meeting
|
|
80
|
+
result = await tool.run(
|
|
81
|
+
subject="Team Standup",
|
|
82
|
+
start_datetime="2025-01-20T09:00:00",
|
|
83
|
+
end_datetime="2025-01-20T09:30:00",
|
|
84
|
+
timezone="America/New_York",
|
|
85
|
+
attendees=["team@company.com"]
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Create an online meeting
|
|
89
|
+
result = await tool.run(
|
|
90
|
+
subject="Client Presentation",
|
|
91
|
+
start_datetime="2025-01-21T14:00:00",
|
|
92
|
+
end_datetime="2025-01-21T15:00:00",
|
|
93
|
+
body="Presenting Q4 results",
|
|
94
|
+
attendees=["client@external.com"],
|
|
95
|
+
is_online_meeting=True
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Create an all-day event
|
|
99
|
+
result = await tool.run(
|
|
100
|
+
subject="Company Holiday",
|
|
101
|
+
start_datetime="2025-12-25T00:00:00",
|
|
102
|
+
end_datetime="2025-12-25T23:59:59",
|
|
103
|
+
is_all_day=True
|
|
104
|
+
)
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
name: str = "create_event"
|
|
108
|
+
description: str = (
|
|
109
|
+
"Create a calendar event in Office365. "
|
|
110
|
+
"Supports attendees, online meetings, locations, and timezone handling."
|
|
111
|
+
)
|
|
112
|
+
args_schema: Type[BaseModel] = CreateEventArgs
|
|
113
|
+
|
|
114
|
+
async def _execute_graph_operation(
|
|
115
|
+
self,
|
|
116
|
+
client: O365Client,
|
|
117
|
+
**kwargs
|
|
118
|
+
) -> Dict[str, Any]:
|
|
119
|
+
"""
|
|
120
|
+
Create a calendar event using Microsoft Graph API.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
client: Authenticated O365Client
|
|
124
|
+
**kwargs: Event parameters
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Dict with event details
|
|
128
|
+
"""
|
|
129
|
+
# Extract parameters
|
|
130
|
+
subject = kwargs.get('subject')
|
|
131
|
+
start_dt = kwargs.get('start_datetime')
|
|
132
|
+
end_dt = kwargs.get('end_datetime')
|
|
133
|
+
timezone = kwargs.get('timezone', 'UTC')
|
|
134
|
+
body_content = kwargs.get('body')
|
|
135
|
+
location_name = kwargs.get('location')
|
|
136
|
+
attendee_emails = kwargs.get('attendees', [])
|
|
137
|
+
is_online_meeting = kwargs.get('is_online_meeting', False)
|
|
138
|
+
is_all_day = kwargs.get('is_all_day', False)
|
|
139
|
+
user_id = kwargs.get('user_id')
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
# Get user context
|
|
143
|
+
mailbox = client.get_user_context(user_id=user_id)
|
|
144
|
+
|
|
145
|
+
# Build event object
|
|
146
|
+
event = Event()
|
|
147
|
+
event.subject = subject
|
|
148
|
+
event.is_all_day = is_all_day
|
|
149
|
+
|
|
150
|
+
# Set start and end times
|
|
151
|
+
event.start = DateTimeTimeZone()
|
|
152
|
+
event.start.date_time = start_dt
|
|
153
|
+
event.start.time_zone = timezone
|
|
154
|
+
|
|
155
|
+
event.end = DateTimeTimeZone()
|
|
156
|
+
event.end.date_time = end_dt
|
|
157
|
+
event.end.time_zone = timezone
|
|
158
|
+
|
|
159
|
+
# Set body if provided
|
|
160
|
+
if body_content:
|
|
161
|
+
event.body = ItemBody()
|
|
162
|
+
event.body.content = body_content
|
|
163
|
+
event.body.content_type = BodyType.Text
|
|
164
|
+
|
|
165
|
+
# Set location if provided
|
|
166
|
+
if location_name:
|
|
167
|
+
event.location = Location()
|
|
168
|
+
event.location.display_name = location_name
|
|
169
|
+
|
|
170
|
+
# Set attendees if provided
|
|
171
|
+
if attendee_emails:
|
|
172
|
+
event.attendees = []
|
|
173
|
+
for email in attendee_emails:
|
|
174
|
+
attendee = Attendee()
|
|
175
|
+
attendee.type = AttendeeType.Required
|
|
176
|
+
attendee.email_address = EmailAddress()
|
|
177
|
+
attendee.email_address.address = email
|
|
178
|
+
event.attendees.append(attendee)
|
|
179
|
+
|
|
180
|
+
# Enable online meeting if requested
|
|
181
|
+
if is_online_meeting:
|
|
182
|
+
event.is_online_meeting = True
|
|
183
|
+
# Note: online_meeting_provider might need to be set differently
|
|
184
|
+
# depending on your Graph SDK version
|
|
185
|
+
try:
|
|
186
|
+
event.online_meeting_provider = "teamsForBusiness"
|
|
187
|
+
except AttributeError:
|
|
188
|
+
# Some versions use a different property
|
|
189
|
+
self.logger.warning("Could not set online_meeting_provider, using default")
|
|
190
|
+
|
|
191
|
+
# Create the event
|
|
192
|
+
self.logger.info(f"Creating event: {subject}")
|
|
193
|
+
created_event = await mailbox.events.post(event)
|
|
194
|
+
|
|
195
|
+
self.logger.info(f"Created event with ID: {created_event.id}")
|
|
196
|
+
|
|
197
|
+
result = {
|
|
198
|
+
"status": "created",
|
|
199
|
+
"id": created_event.id,
|
|
200
|
+
"subject": created_event.subject,
|
|
201
|
+
"start": start_dt,
|
|
202
|
+
"end": end_dt,
|
|
203
|
+
"timezone": timezone,
|
|
204
|
+
"location": location_name,
|
|
205
|
+
"attendees": attendee_emails,
|
|
206
|
+
"is_online_meeting": is_online_meeting,
|
|
207
|
+
"is_all_day": is_all_day,
|
|
208
|
+
"web_link": created_event.web_link
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# Add online meeting info if available
|
|
212
|
+
if is_online_meeting and hasattr(created_event, 'online_meeting') and created_event.online_meeting:
|
|
213
|
+
result["join_url"] = getattr(created_event.online_meeting, 'join_url', None)
|
|
214
|
+
|
|
215
|
+
return result
|
|
216
|
+
|
|
217
|
+
except Exception as e:
|
|
218
|
+
self.logger.error(f"Failed to create event: {e}", exc_info=True)
|
|
219
|
+
raise
|
|
220
|
+
|
|
221
|
+
# events.py (Continued)
|
|
222
|
+
|
|
223
|
+
# ============================================================================
|
|
224
|
+
# LIST EVENTS TOOL
|
|
225
|
+
# ============================================================================
|
|
226
|
+
|
|
227
|
+
class ListEventArgs(O365ToolArgsSchema):
|
|
228
|
+
"""Arguments for listing calendar events."""
|
|
229
|
+
start_datetime: Optional[str] = Field(
|
|
230
|
+
default=None,
|
|
231
|
+
description="Optional: Start date and time for the range query in ISO format (e.g., '2025-01-01T00:00:00'). Required for /instances endpoint."
|
|
232
|
+
)
|
|
233
|
+
end_datetime: Optional[str] = Field(
|
|
234
|
+
default=None,
|
|
235
|
+
description="Optional: End date and time for the range query in ISO format (e.g., '2025-01-31T23:59:59'). Required for /instances endpoint."
|
|
236
|
+
)
|
|
237
|
+
top: Optional[int] = Field(
|
|
238
|
+
default=10,
|
|
239
|
+
description="Maximum number of events to return. Defaults to 10."
|
|
240
|
+
)
|
|
241
|
+
filter: Optional[str] = Field(
|
|
242
|
+
default=None,
|
|
243
|
+
description="OData $filter string for advanced filtering (e.g., 'subject eq \"Team Standup\"')"
|
|
244
|
+
)
|
|
245
|
+
timezone: str = Field(
|
|
246
|
+
default="UTC",
|
|
247
|
+
description="Timezone for event start/end times in the response (e.g., 'America/New_York')."
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
class ListEventsTool(O365Tool):
|
|
251
|
+
"""
|
|
252
|
+
Tool for listing events in the user's calendar.
|
|
253
|
+
|
|
254
|
+
Uses OData query parameters ($top, $filter) for customization and
|
|
255
|
+
`Prefer: outlook.timezone` header to control response timezones.
|
|
256
|
+
"""
|
|
257
|
+
name: str = "list_events"
|
|
258
|
+
description: str = (
|
|
259
|
+
"List upcoming or recent calendar events. "
|
|
260
|
+
"Can filter by date range and use OData queries for advanced filtering."
|
|
261
|
+
)
|
|
262
|
+
args_schema: Type[BaseModel] = ListEventArgs
|
|
263
|
+
|
|
264
|
+
async def _execute_graph_operation(
|
|
265
|
+
self,
|
|
266
|
+
client: O365Client,
|
|
267
|
+
**kwargs
|
|
268
|
+
) -> Dict[str, Any]:
|
|
269
|
+
"""
|
|
270
|
+
List calendar events using Microsoft Graph API.
|
|
271
|
+
"""
|
|
272
|
+
start_dt = kwargs.get('start_datetime')
|
|
273
|
+
end_dt = kwargs.get('end_datetime')
|
|
274
|
+
top = kwargs.get('top', 10)
|
|
275
|
+
filter_query = kwargs.get('filter')
|
|
276
|
+
timezone = kwargs.get('timezone', 'UTC')
|
|
277
|
+
user_id = kwargs.get('user_id')
|
|
278
|
+
|
|
279
|
+
try:
|
|
280
|
+
mailbox = client.get_user_context(user_id=user_id)
|
|
281
|
+
|
|
282
|
+
# Use RequestConfiguration for headers and query parameters
|
|
283
|
+
request_configuration = RequestConfiguration()
|
|
284
|
+
|
|
285
|
+
# Set the timezone preference header
|
|
286
|
+
request_configuration.headers.add("Prefer", f"outlook.timezone=\"{timezone}\"")
|
|
287
|
+
|
|
288
|
+
# Set top for pagination
|
|
289
|
+
request_configuration.query_parameters['$top'] = top
|
|
290
|
+
|
|
291
|
+
# Set filter
|
|
292
|
+
if filter_query:
|
|
293
|
+
request_configuration.query_parameters['$filter'] = filter_query
|
|
294
|
+
|
|
295
|
+
# Check for date range which uses the /calendarView endpoint (or /events if no range)
|
|
296
|
+
if start_dt and end_dt:
|
|
297
|
+
self.logger.info(f"Listing events between {start_dt} and {end_dt} for timezone {timezone}")
|
|
298
|
+
|
|
299
|
+
# Note: CalendarView requires start and end date
|
|
300
|
+
request_configuration.query_parameters['startDateTime'] = start_dt
|
|
301
|
+
request_configuration.query_parameters['endDateTime'] = end_dt
|
|
302
|
+
|
|
303
|
+
events_response = await mailbox.calendar.calendar_view.get(request_configuration=request_configuration)
|
|
304
|
+
else:
|
|
305
|
+
self.logger.info(f"Listing events with top={top}, timezone={timezone}")
|
|
306
|
+
events_response = await mailbox.events.get(request_configuration=request_configuration)
|
|
307
|
+
|
|
308
|
+
event_list = events_response.value or []
|
|
309
|
+
|
|
310
|
+
# Format the list for output
|
|
311
|
+
results = [
|
|
312
|
+
{
|
|
313
|
+
"id": event.id,
|
|
314
|
+
"subject": event.subject,
|
|
315
|
+
"start": event.start.date_time if event.start else None,
|
|
316
|
+
"end": event.end.date_time if event.end else None,
|
|
317
|
+
"location": event.location.display_name if event.location else None,
|
|
318
|
+
"is_online_meeting": event.is_online_meeting,
|
|
319
|
+
"web_link": event.web_link
|
|
320
|
+
} for event in event_list
|
|
321
|
+
]
|
|
322
|
+
|
|
323
|
+
return {
|
|
324
|
+
"status": "success",
|
|
325
|
+
"count": len(results),
|
|
326
|
+
"events": results
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
except Exception as e:
|
|
330
|
+
self.logger.error(f"Failed to list events: {e}", exc_info=True)
|
|
331
|
+
raise
|
|
332
|
+
|
|
333
|
+
# ============================================================================
|
|
334
|
+
# GET EVENT TOOL
|
|
335
|
+
# ============================================================================
|
|
336
|
+
|
|
337
|
+
class GetEventArgs(O365ToolArgsSchema):
|
|
338
|
+
"""Arguments for retrieving a single calendar event by ID."""
|
|
339
|
+
event_id: str = Field(
|
|
340
|
+
description="The unique ID of the calendar event to retrieve."
|
|
341
|
+
)
|
|
342
|
+
timezone: str = Field(
|
|
343
|
+
default="UTC",
|
|
344
|
+
description="Timezone for event start/end times in the response (e.g., 'America/New_York')."
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
class GetEventTool(O365Tool):
|
|
348
|
+
"""
|
|
349
|
+
Tool for retrieving a single calendar event by its ID.
|
|
350
|
+
"""
|
|
351
|
+
name: str = "get_event"
|
|
352
|
+
description: str = (
|
|
353
|
+
"Retrieve the full details of a single calendar event using its unique ID."
|
|
354
|
+
)
|
|
355
|
+
args_schema: Type[BaseModel] = GetEventArgs
|
|
356
|
+
|
|
357
|
+
async def _execute_graph_operation(
|
|
358
|
+
self,
|
|
359
|
+
client: O365Client,
|
|
360
|
+
**kwargs
|
|
361
|
+
) -> Dict[str, Any]:
|
|
362
|
+
"""
|
|
363
|
+
Get a calendar event by ID using Microsoft Graph API.
|
|
364
|
+
"""
|
|
365
|
+
event_id = kwargs.get('event_id')
|
|
366
|
+
timezone = kwargs.get('timezone', 'UTC')
|
|
367
|
+
user_id = kwargs.get('user_id')
|
|
368
|
+
|
|
369
|
+
try:
|
|
370
|
+
mailbox = client.get_user_context(user_id=user_id)
|
|
371
|
+
|
|
372
|
+
# Use RequestConfiguration for headers
|
|
373
|
+
request_configuration = RequestConfiguration()
|
|
374
|
+
request_configuration.headers.add("Prefer", f"outlook.timezone=\"{timezone}\"")
|
|
375
|
+
|
|
376
|
+
self.logger.info(f"Retrieving event with ID: {event_id}")
|
|
377
|
+
|
|
378
|
+
event = await mailbox.events.by_event_id(event_id).get(
|
|
379
|
+
request_configuration=request_configuration
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
# Format the output
|
|
383
|
+
attendees_list = [
|
|
384
|
+
{
|
|
385
|
+
"email": a.email_address.address,
|
|
386
|
+
"type": a.type.value,
|
|
387
|
+
"response": a.status.response.value
|
|
388
|
+
} for a in event.attendees
|
|
389
|
+
] if event.attendees else []
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
"status": "success",
|
|
393
|
+
"id": event.id,
|
|
394
|
+
"subject": event.subject,
|
|
395
|
+
"body_preview": event.body_preview,
|
|
396
|
+
"body": event.body.content if event.body else None,
|
|
397
|
+
"start": event.start.date_time if event.start else None,
|
|
398
|
+
"end": event.end.date_time if event.end else None,
|
|
399
|
+
"timezone": event.start.time_zone if event.start else None,
|
|
400
|
+
"location": event.location.display_name if event.location else None,
|
|
401
|
+
"is_online_meeting": event.is_online_meeting,
|
|
402
|
+
"join_url": event.online_meeting.join_url if event.online_meeting else None,
|
|
403
|
+
"attendees": attendees_list,
|
|
404
|
+
"web_link": event.web_link
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
except Exception as e:
|
|
408
|
+
self.logger.error(f"Failed to get event {event_id}: {e}", exc_info=True)
|
|
409
|
+
raise
|
|
410
|
+
|
|
411
|
+
# ============================================================================
|
|
412
|
+
# UPDATE EVENT TOOL
|
|
413
|
+
# ============================================================================
|
|
414
|
+
|
|
415
|
+
class UpdateEventArgs(O365ToolArgsSchema):
|
|
416
|
+
"""Arguments for updating a calendar event."""
|
|
417
|
+
event_id: str = Field(
|
|
418
|
+
description="The unique ID of the calendar event to update."
|
|
419
|
+
)
|
|
420
|
+
subject: Optional[str] = Field(
|
|
421
|
+
default=None,
|
|
422
|
+
description="Optional: New event subject/title"
|
|
423
|
+
)
|
|
424
|
+
start_datetime: Optional[str] = Field(
|
|
425
|
+
default=None,
|
|
426
|
+
description="Optional: New event start date and time in ISO format (e.g., '2025-01-20T14:00:00')"
|
|
427
|
+
)
|
|
428
|
+
end_datetime: Optional[str] = Field(
|
|
429
|
+
default=None,
|
|
430
|
+
description="Optional: New event end date and time in ISO format (e.g., '2025-01-20T15:00:00')"
|
|
431
|
+
)
|
|
432
|
+
timezone: str = Field(
|
|
433
|
+
default="UTC",
|
|
434
|
+
description="Timezone for the event's start/end times (e.g., 'America/New_York')."
|
|
435
|
+
)
|
|
436
|
+
body: Optional[str] = Field(
|
|
437
|
+
default=None,
|
|
438
|
+
description="Optional: New event description/body content"
|
|
439
|
+
)
|
|
440
|
+
location: Optional[str] = Field(
|
|
441
|
+
default=None,
|
|
442
|
+
description="Optional: New event location (e.g., 'Conference Room B', 'New Zoom Link'). Set to empty string to clear."
|
|
443
|
+
)
|
|
444
|
+
# Note: Updating attendees is complex (add/remove) and usually done via a full Event object replacement/PATCH,
|
|
445
|
+
# but for simplicity, we'll keep the core fields for this tool.
|
|
446
|
+
send_updates: Optional[bool] = Field(
|
|
447
|
+
default=True,
|
|
448
|
+
description="Whether to send update notifications to attendees. Defaults to True."
|
|
449
|
+
)
|
|
450
|
+
is_online_meeting: Optional[bool] = Field(
|
|
451
|
+
default=None,
|
|
452
|
+
description="Optional: Whether to make this an online meeting (Teams meeting)."
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
class UpdateEventTool(O365Tool):
|
|
456
|
+
"""
|
|
457
|
+
Tool for updating an existing calendar event in Office365.
|
|
458
|
+
|
|
459
|
+
The update uses a PATCH operation, so only fields provided will be updated.
|
|
460
|
+
"""
|
|
461
|
+
name: str = "update_event"
|
|
462
|
+
description: str = (
|
|
463
|
+
"Update an existing calendar event using its ID. "
|
|
464
|
+
"Only provide the fields you want to change."
|
|
465
|
+
)
|
|
466
|
+
args_schema: Type[BaseModel] = UpdateEventArgs
|
|
467
|
+
|
|
468
|
+
async def _execute_graph_operation(
|
|
469
|
+
self,
|
|
470
|
+
client: O365Client,
|
|
471
|
+
**kwargs
|
|
472
|
+
) -> Dict[str, Any]:
|
|
473
|
+
"""
|
|
474
|
+
Update a calendar event using Microsoft Graph API (PATCH).
|
|
475
|
+
"""
|
|
476
|
+
event_id = kwargs.get('event_id')
|
|
477
|
+
user_id = kwargs.get('user_id')
|
|
478
|
+
timezone = kwargs.get('timezone', 'UTC')
|
|
479
|
+
|
|
480
|
+
# Determine if we should send updates
|
|
481
|
+
send_updates = kwargs.get('send_updates', True)
|
|
482
|
+
|
|
483
|
+
# Build the update object (Event model with only fields to update)
|
|
484
|
+
update_event = Event()
|
|
485
|
+
|
|
486
|
+
if subject := kwargs.get('subject'):
|
|
487
|
+
update_event.subject = subject
|
|
488
|
+
|
|
489
|
+
if body_content := kwargs.get('body'):
|
|
490
|
+
update_event.body = ItemBody(content=body_content, content_type=BodyType.Text)
|
|
491
|
+
|
|
492
|
+
if location_name := kwargs.get('location'):
|
|
493
|
+
# Clear location if an empty string is passed
|
|
494
|
+
if location_name.strip() == "":
|
|
495
|
+
update_event.location = Location(display_name="")
|
|
496
|
+
else:
|
|
497
|
+
update_event.location = Location(display_name=location_name)
|
|
498
|
+
|
|
499
|
+
# Handle start and end time updates (requires both to be consistently set if changing)
|
|
500
|
+
start_dt = kwargs.get('start_datetime')
|
|
501
|
+
end_dt = kwargs.get('end_datetime')
|
|
502
|
+
|
|
503
|
+
if start_dt:
|
|
504
|
+
update_event.start = DateTimeTimeZone(date_time=start_dt, time_zone=timezone)
|
|
505
|
+
if end_dt:
|
|
506
|
+
update_event.end = DateTimeTimeZone(date_time=end_dt, time_zone=timezone)
|
|
507
|
+
|
|
508
|
+
if is_online_meeting := kwargs.get('is_online_meeting'):
|
|
509
|
+
update_event.is_online_meeting = is_online_meeting
|
|
510
|
+
# The online_meeting_provider might need to be set if creating a new one
|
|
511
|
+
if is_online_meeting:
|
|
512
|
+
try:
|
|
513
|
+
update_event.online_meeting_provider = "teamsForBusiness"
|
|
514
|
+
except AttributeError:
|
|
515
|
+
self.logger.warning("Could not set online_meeting_provider in update")
|
|
516
|
+
|
|
517
|
+
# Set up request configuration for sending updates header
|
|
518
|
+
request_configuration = RequestConfiguration()
|
|
519
|
+
if send_updates is False:
|
|
520
|
+
request_configuration.headers.add(
|
|
521
|
+
"Prefer", "outlook.sendUpdateNotificationsForRecipients=\"None\""
|
|
522
|
+
)
|
|
523
|
+
elif send_updates is True:
|
|
524
|
+
# Send updates to all attendees
|
|
525
|
+
request_configuration.headers.add(
|
|
526
|
+
"Prefer", "outlook.sendUpdateNotificationsForRecipients=\"All\""
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
try:
|
|
531
|
+
mailbox = client.get_user_context(user_id=user_id)
|
|
532
|
+
self.logger.info(f"Updating event with ID: {event_id}. Send updates: {send_updates}")
|
|
533
|
+
|
|
534
|
+
# Send the PATCH request
|
|
535
|
+
updated_event = await mailbox.events.by_event_id(event_id).patch(
|
|
536
|
+
update_event,
|
|
537
|
+
request_configuration=request_configuration
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
# Note: The PATCH request typically returns a 200 OK or 204 No Content
|
|
541
|
+
# and may not return the full updated object in all SDK versions.
|
|
542
|
+
# We return a status and the ID.
|
|
543
|
+
return {
|
|
544
|
+
"status": "updated",
|
|
545
|
+
"id": event_id,
|
|
546
|
+
"subject": subject or updated_event.subject,
|
|
547
|
+
"start": start_dt or updated_event.start.date_time if updated_event.start else None,
|
|
548
|
+
"end": end_dt or updated_event.end.date_time if updated_event.end else None,
|
|
549
|
+
"web_link": updated_event.web_link
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
except Exception as e:
|
|
553
|
+
self.logger.error(f"Failed to update event {event_id}: {e}", exc_info=True)
|
|
554
|
+
raise
|