@_vrsen/openswarm 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +152 -0
- package/bin/openswarm.js +38 -0
- package/config.py +34 -0
- package/data_analyst_agent/.cursor/rules/data_analyst.mdc +43 -0
- package/data_analyst_agent/__init__.py +3 -0
- package/data_analyst_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/data_analyst_agent/__pycache__/data_analyst_agent.cpython-312.pyc +0 -0
- package/data_analyst_agent/data_analyst_agent.py +45 -0
- package/data_analyst_agent/instructions.md +173 -0
- package/data_analyst_agent/test_files/test_file.csv +21 -0
- package/data_analyst_agent/tools/__init__.py +6 -0
- package/deep_research/__init__.py +1 -0
- package/deep_research/__pycache__/__init__.cpython-312.pyc +0 -0
- package/deep_research/__pycache__/deep_research.cpython-312.pyc +0 -0
- package/deep_research/deep_research.py +27 -0
- package/deep_research/instructions.md +104 -0
- package/deep_research/tools/__init__.py +1 -0
- package/docs_agent/__init__.py +3 -0
- package/docs_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/docs_agent/__pycache__/docs_agent.cpython-312.pyc +0 -0
- package/docs_agent/docs_agent.py +61 -0
- package/docs_agent/instructions.md +418 -0
- package/docs_agent/tools/ConvertDocument.py +323 -0
- package/docs_agent/tools/CreateDocument.py +287 -0
- package/docs_agent/tools/ListDocuments.py +134 -0
- package/docs_agent/tools/ModifyDocument.py +247 -0
- package/docs_agent/tools/RestoreDocument.py +79 -0
- package/docs_agent/tools/ViewDocument.py +153 -0
- package/docs_agent/tools/__init__.py +1 -0
- package/docs_agent/tools/__pycache__/ConvertDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/CreateDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/ListDocuments.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/ModifyDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/RestoreDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/ViewDocument.cpython-312.pyc +0 -0
- package/docs_agent/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__init__.py +1 -0
- package/docs_agent/tools/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/doc_file_utils.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_blocks.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_constants.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_core.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_css.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_images.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_page.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_paragraphs.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_playwright.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_selectors.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_docx_shared.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/__pycache__/html_validation.cpython-312.pyc +0 -0
- package/docs_agent/tools/utils/doc_file_utils.py +29 -0
- package/docs_agent/tools/utils/html_docx_blocks.py +262 -0
- package/docs_agent/tools/utils/html_docx_constants.py +78 -0
- package/docs_agent/tools/utils/html_docx_core.py +138 -0
- package/docs_agent/tools/utils/html_docx_css.py +262 -0
- package/docs_agent/tools/utils/html_docx_images.py +293 -0
- package/docs_agent/tools/utils/html_docx_page.py +185 -0
- package/docs_agent/tools/utils/html_docx_paragraphs.py +342 -0
- package/docs_agent/tools/utils/html_docx_playwright.py +184 -0
- package/docs_agent/tools/utils/html_docx_selectors.py +196 -0
- package/docs_agent/tools/utils/html_docx_shared.py +23 -0
- package/docs_agent/tools/utils/html_docx_tables.py +942 -0
- package/docs_agent/tools/utils/html_validation.py +102 -0
- package/helpers.py +59 -0
- package/image_generation_agent/__init__.py +1 -0
- package/image_generation_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/image_generation_agent/__pycache__/image_generation_agent.cpython-312.pyc +0 -0
- package/image_generation_agent/image_generation_agent.py +31 -0
- package/image_generation_agent/instructions.md +80 -0
- package/image_generation_agent/tools/CombineImages.py +211 -0
- package/image_generation_agent/tools/EditImages.py +200 -0
- package/image_generation_agent/tools/GenerateImages.py +184 -0
- package/image_generation_agent/tools/RemoveBackground.py +108 -0
- package/image_generation_agent/tools/__init__.py +2 -0
- package/image_generation_agent/tools/__pycache__/CombineImages.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/__pycache__/EditImages.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/__pycache__/GenerateImages.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/__pycache__/RemoveBackground.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/utils/__init__.py +2 -0
- package/image_generation_agent/tools/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/utils/__pycache__/image_io.cpython-312.pyc +0 -0
- package/image_generation_agent/tools/utils/image_io.py +308 -0
- package/onboard.py +325 -0
- package/orchestrator/__init__.py +3 -0
- package/orchestrator/__pycache__/__init__.cpython-312.pyc +0 -0
- package/orchestrator/__pycache__/orchestrator.cpython-312.pyc +0 -0
- package/orchestrator/instructions.md +90 -0
- package/orchestrator/orchestrator.py +33 -0
- package/package.json +49 -0
- package/patches/__init__.py +1 -0
- package/patches/__pycache__/__init__.cpython-312.pyc +0 -0
- package/patches/__pycache__/patch_agency_swarm_dual_comms.cpython-312.pyc +0 -0
- package/patches/__pycache__/patch_file_attachment_refs.cpython-312.pyc +0 -0
- package/patches/__pycache__/patch_ipython_interpreter_composio.cpython-312.pyc +0 -0
- package/patches/dom-to-pptx+1.1.5.patch +133440 -0
- package/patches/patch_agency_swarm_dual_comms.py +199 -0
- package/patches/patch_file_attachment_refs.py +74 -0
- package/patches/patch_ipython_interpreter_composio.py +54 -0
- package/pyproject.toml +67 -0
- package/run.py +343 -0
- package/server.py +26 -0
- package/shared_instructions.md +119 -0
- package/shared_tools/CopyFile.py +68 -0
- package/shared_tools/ExecuteTool.py +184 -0
- package/shared_tools/FindTools.py +101 -0
- package/shared_tools/ManageConnections.py +43 -0
- package/shared_tools/SearchTools.py +44 -0
- package/shared_tools/__init__.py +7 -0
- package/shared_tools/__pycache__/CopyFile.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/ExecuteTool.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/FindTools.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/ManageConnections.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/SearchTools.cpython-312.pyc +0 -0
- package/shared_tools/__pycache__/__init__.cpython-312.pyc +0 -0
- package/slides_agent/.cursor/rules/slides-agent-workflow.mdc +9 -0
- package/slides_agent/__init__.py +1 -0
- package/slides_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/slides_agent/__pycache__/slides_agent.cpython-312.pyc +0 -0
- package/slides_agent/instructions.md +298 -0
- package/slides_agent/pptx/SKILL.md +528 -0
- package/slides_agent/pptx/html2pptx.md +625 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/slides_agent/pptx/ooxml/schemas/mce/mc.xsd +75 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/slides_agent/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/slides_agent/pptx/ooxml/scripts/pack.py +169 -0
- package/slides_agent/pptx/ooxml/scripts/unpack.py +29 -0
- package/slides_agent/pptx/ooxml/scripts/validate.py +69 -0
- package/slides_agent/pptx/ooxml/scripts/validation/__init__.py +15 -0
- package/slides_agent/pptx/ooxml/scripts/validation/base.py +951 -0
- package/slides_agent/pptx/ooxml/scripts/validation/docx.py +274 -0
- package/slides_agent/pptx/ooxml/scripts/validation/pptx.py +315 -0
- package/slides_agent/pptx/ooxml/scripts/validation/redlining.py +279 -0
- package/slides_agent/pptx/ooxml.md +427 -0
- package/slides_agent/pptx/scripts/html2pptx.js +1092 -0
- package/slides_agent/pptx/scripts/inventory.py +1020 -0
- package/slides_agent/pptx/scripts/rearrange.py +231 -0
- package/slides_agent/pptx/scripts/replace.py +385 -0
- package/slides_agent/pptx/scripts/thumbnail.py +451 -0
- package/slides_agent/slides_agent.py +109 -0
- package/slides_agent/test_deck/_theme.css +92 -0
- package/slides_agent/test_deck/assets/placeholder.svg +11 -0
- package/slides_agent/test_deck/slide_01_title.html +10 -0
- package/slides_agent/test_deck/slide_02_image_split.html +23 -0
- package/slides_agent/test_deck/slide_03_kpi.html +21 -0
- package/slides_agent/tools/ApplyPptxTextReplacements.py +91 -0
- package/slides_agent/tools/BuildPptxFromHtmlSlides.py +221 -0
- package/slides_agent/tools/CheckSlide.py +218 -0
- package/slides_agent/tools/CheckSlideCanvasOverflow.py +221 -0
- package/slides_agent/tools/CreateImageMontage.py +261 -0
- package/slides_agent/tools/CreatePptxThumbnailGrid.py +168 -0
- package/slides_agent/tools/DeleteSlide.py +78 -0
- package/slides_agent/tools/DownloadImage.py +79 -0
- package/slides_agent/tools/EnsureRasterImage.py +157 -0
- package/slides_agent/tools/ExtractPptxTextInventory.py +104 -0
- package/slides_agent/tools/GenerateImage.py +189 -0
- package/slides_agent/tools/ImageSearch.py +127 -0
- package/slides_agent/tools/InsertNewSlides.py +393 -0
- package/slides_agent/tools/ManageTheme.py +112 -0
- package/slides_agent/tools/ModifySlide.py +563 -0
- package/slides_agent/tools/ReadSlide.py +26 -0
- package/slides_agent/tools/RearrangePptxSlidesFromTemplate.py +114 -0
- package/slides_agent/tools/RestoreSnapshot.py +89 -0
- package/slides_agent/tools/SlideScreenshot.py +66 -0
- package/slides_agent/tools/__init__.py +54 -0
- package/slides_agent/tools/__pycache__/ApplyPptxTextReplacements.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/BuildPptxFromHtmlSlides.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/CheckSlide.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/CheckSlideCanvasOverflow.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/CreateImageMontage.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/CreatePptxThumbnailGrid.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/DeleteSlide.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/DownloadImage.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/EnsureRasterImage.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ExtractPptxTextInventory.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/GenerateImage.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ImageSearch.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/InsertNewSlides.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ManageTheme.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ModifySlide.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/ReadSlide.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/RearrangePptxSlidesFromTemplate.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/RestoreSnapshot.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/SlideScreenshot.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/slide_file_utils.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/slide_html_utils.cpython-312.pyc +0 -0
- package/slides_agent/tools/__pycache__/template_registry.cpython-312.pyc +0 -0
- package/slides_agent/tools/deck_utils.py +31 -0
- package/slides_agent/tools/html2pptx_runner.js +1183 -0
- package/slides_agent/tools/html_writer_instructions.md +149 -0
- package/slides_agent/tools/slide_file_utils.py +108 -0
- package/slides_agent/tools/slide_html_utils.py +354 -0
- package/slides_agent/tools/template_registry.py +55 -0
- package/swarm.py +82 -0
- package/video_generation_agent/__init__.py +1 -0
- package/video_generation_agent/__pycache__/__init__.cpython-312.pyc +0 -0
- package/video_generation_agent/__pycache__/video_generation_agent.cpython-312.pyc +0 -0
- package/video_generation_agent/instructions.md +178 -0
- package/video_generation_agent/tools/AddSubtitles.py +425 -0
- package/video_generation_agent/tools/CombineImages.py +166 -0
- package/video_generation_agent/tools/CombineVideos.py +113 -0
- package/video_generation_agent/tools/EditAudio.py +297 -0
- package/video_generation_agent/tools/EditImage.py +144 -0
- package/video_generation_agent/tools/EditVideoContent.py +369 -0
- package/video_generation_agent/tools/GenerateImage.py +133 -0
- package/video_generation_agent/tools/GenerateVideo.py +556 -0
- package/video_generation_agent/tools/TrimVideo.py +233 -0
- package/video_generation_agent/tools/__init__.py +1 -0
- package/video_generation_agent/tools/__pycache__/AddSubtitles.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/CombineImages.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/CombineVideos.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/EditAudio.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/EditImage.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/EditVideoContent.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/GenerateImage.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/GenerateVideo.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/__pycache__/TrimVideo.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/utils/__init__.py +1 -0
- package/video_generation_agent/tools/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/utils/__pycache__/image_utils.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/utils/__pycache__/video_utils.cpython-312.pyc +0 -0
- package/video_generation_agent/tools/utils/image_utils.py +174 -0
- package/video_generation_agent/tools/utils/video_utils.py +522 -0
- package/video_generation_agent/video_generation_agent.py +26 -0
- package/virtual_assistant/__init__.py +1 -0
- package/virtual_assistant/__pycache__/__init__.cpython-312.pyc +0 -0
- package/virtual_assistant/__pycache__/virtual_assistant.cpython-312.pyc +0 -0
- package/virtual_assistant/instructions.md +206 -0
- package/virtual_assistant/tools/AddLabelToEmail.py +154 -0
- package/virtual_assistant/tools/CheckEventsForDate.py +218 -0
- package/virtual_assistant/tools/CheckUnreadSlackMessages.py +216 -0
- package/virtual_assistant/tools/CreateCalendarEvent.py +261 -0
- package/virtual_assistant/tools/DeleteCalendarEvent.py +137 -0
- package/virtual_assistant/tools/DeleteDraft.py +95 -0
- package/virtual_assistant/tools/DraftEmail.py +239 -0
- package/virtual_assistant/tools/EditFile.py +113 -0
- package/virtual_assistant/tools/FindEmails.py +330 -0
- package/virtual_assistant/tools/GetCurrentTime.py +69 -0
- package/virtual_assistant/tools/GetSlackUserInfo.py +117 -0
- package/virtual_assistant/tools/ListDirectory.py +113 -0
- package/virtual_assistant/tools/ListSkills.py +94 -0
- package/virtual_assistant/tools/ManageLabels.py +295 -0
- package/virtual_assistant/tools/ProductSearch.py +254 -0
- package/virtual_assistant/tools/ReadEmail.py +251 -0
- package/virtual_assistant/tools/ReadFile.py +108 -0
- package/virtual_assistant/tools/ReadSlackMessages.py +191 -0
- package/virtual_assistant/tools/RemoveLabelFromEmail.py +137 -0
- package/virtual_assistant/tools/RescheduleCalendarEvent.py +227 -0
- package/virtual_assistant/tools/ScholarSearch.py +216 -0
- package/virtual_assistant/tools/SendDraft.py +101 -0
- package/virtual_assistant/tools/SendSlackMessage.py +148 -0
- package/virtual_assistant/tools/WriteFile.py +95 -0
- package/virtual_assistant/tools/__init__.py +1 -0
- package/virtual_assistant/tools/__pycache__/AddLabelToEmail.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/CheckEventsForDate.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/CheckUnreadSlackMessages.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/CreateCalendarEvent.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/DeleteCalendarEvent.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/DeleteDraft.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/DraftEmail.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/EditFile.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/FindEmails.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/GetCurrentTime.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/GetSlackUserInfo.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ListDirectory.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ListSkills.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ManageLabels.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ProductSearch.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ReadEmail.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ReadFile.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ReadSlackMessages.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/RemoveLabelFromEmail.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/RescheduleCalendarEvent.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/ScholarSearch.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/SendDraft.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/SendSlackMessage.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/WriteFile.cpython-312.pyc +0 -0
- package/virtual_assistant/tools/__pycache__/__init__.cpython-312.pyc +0 -0
- package/virtual_assistant/virtual_assistant.py +52 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
from agency_swarm.tools import BaseTool
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
import json
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
from helpers import execute_composio_tool
|
|
8
|
+
|
|
9
|
+
class CheckUnreadSlackMessages(BaseTool):
|
|
10
|
+
"""
|
|
11
|
+
Retrieves unread Slack messages using the search API.
|
|
12
|
+
|
|
13
|
+
Efficiently finds unread messages with minimal API calls:
|
|
14
|
+
1. Searches for recent messages (1 call)
|
|
15
|
+
2. Checks unread status for top conversations (max 10 calls)
|
|
16
|
+
|
|
17
|
+
Returns sender, message preview, timestamp, permalink, and attachment info.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
conversation_types: Literal["dm", "channels", "all"] = Field(
|
|
21
|
+
default="dm",
|
|
22
|
+
description=(
|
|
23
|
+
"'dm' for direct messages only (default), "
|
|
24
|
+
"'channels' for public/private channels only, "
|
|
25
|
+
"'all' for both"
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
max_messages: int = Field(
|
|
30
|
+
default=20,
|
|
31
|
+
ge=1,
|
|
32
|
+
le=50,
|
|
33
|
+
description="Maximum number of unread messages to return (1-50). Default is 20."
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
days_back: int = Field(
|
|
37
|
+
default=7,
|
|
38
|
+
ge=1,
|
|
39
|
+
le=30,
|
|
40
|
+
description="How many days back to search for messages (1-30). Default is 7."
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
include_bots: bool = Field(
|
|
44
|
+
default=True,
|
|
45
|
+
description="Include messages from bots. Default is True."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def run(self):
|
|
49
|
+
try:
|
|
50
|
+
search_results = self._search_recent_messages(execute_composio_tool)
|
|
51
|
+
|
|
52
|
+
if not search_results:
|
|
53
|
+
return json.dumps({
|
|
54
|
+
"total_unread": 0,
|
|
55
|
+
"messages": [],
|
|
56
|
+
"summary": "No recent messages found."
|
|
57
|
+
}, indent=2)
|
|
58
|
+
|
|
59
|
+
unread_messages = self._filter_unread(execute_composio_tool, search_results)
|
|
60
|
+
|
|
61
|
+
# Sort by timestamp (newest first) and limit
|
|
62
|
+
unread_messages.sort(key=lambda x: x.get("_ts", "0"), reverse=True)
|
|
63
|
+
unread_messages = unread_messages[:self.max_messages]
|
|
64
|
+
|
|
65
|
+
# Clean up internal fields
|
|
66
|
+
for msg in unread_messages:
|
|
67
|
+
msg.pop("_ts", None)
|
|
68
|
+
|
|
69
|
+
# Build summary
|
|
70
|
+
if not unread_messages:
|
|
71
|
+
summary = "No unread messages."
|
|
72
|
+
else:
|
|
73
|
+
conv_ids = set(msg["conversation_id"] for msg in unread_messages)
|
|
74
|
+
summary = f"{len(unread_messages)} unread message{'s' if len(unread_messages) > 1 else ''} from {len(conv_ids)} conversation{'s' if len(conv_ids) > 1 else ''}."
|
|
75
|
+
|
|
76
|
+
return json.dumps({
|
|
77
|
+
"total_unread": len(unread_messages),
|
|
78
|
+
"messages": unread_messages,
|
|
79
|
+
"summary": summary
|
|
80
|
+
}, indent=2)
|
|
81
|
+
|
|
82
|
+
except Exception as e:
|
|
83
|
+
return f"Error fetching unread Slack messages: {str(e)}"
|
|
84
|
+
|
|
85
|
+
def _search_recent_messages(self, execute_tool) -> list:
|
|
86
|
+
"""Searches for recent messages (1 API call)."""
|
|
87
|
+
from datetime import timedelta
|
|
88
|
+
|
|
89
|
+
start_date = (datetime.now() - timedelta(days=self.days_back)).strftime("%Y-%m-%d")
|
|
90
|
+
|
|
91
|
+
if self.conversation_types == "dm":
|
|
92
|
+
query = f"after:{start_date} is:dm"
|
|
93
|
+
elif self.conversation_types == "channels":
|
|
94
|
+
query = f"after:{start_date} -is:dm"
|
|
95
|
+
else:
|
|
96
|
+
query = f"after:{start_date}"
|
|
97
|
+
|
|
98
|
+
result = execute_tool(
|
|
99
|
+
tool_name="SLACK_SEARCH_MESSAGES",
|
|
100
|
+
arguments={
|
|
101
|
+
"query": query,
|
|
102
|
+
"sort": "timestamp",
|
|
103
|
+
"sort_dir": "desc",
|
|
104
|
+
"count": min(self.max_messages * 2, 100)
|
|
105
|
+
},
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if isinstance(result, dict) and result.get("error"):
|
|
109
|
+
return []
|
|
110
|
+
|
|
111
|
+
return result.get("data", {}).get("messages", {}).get("matches", [])
|
|
112
|
+
|
|
113
|
+
def _filter_unread(self, execute_tool, messages: list) -> list:
|
|
114
|
+
"""Filters to unread messages only (max 2 API calls for last_read checks)."""
|
|
115
|
+
# Group messages by channel
|
|
116
|
+
by_channel = {}
|
|
117
|
+
for msg in messages:
|
|
118
|
+
channel = msg.get("channel", {})
|
|
119
|
+
channel_id = channel.get("id")
|
|
120
|
+
if not channel_id:
|
|
121
|
+
continue
|
|
122
|
+
|
|
123
|
+
# Filter bots if needed
|
|
124
|
+
if not self.include_bots and (msg.get("bot_id") or msg.get("subtype")):
|
|
125
|
+
continue
|
|
126
|
+
|
|
127
|
+
if channel_id not in by_channel:
|
|
128
|
+
by_channel[channel_id] = {
|
|
129
|
+
"name": self._get_display_name(channel),
|
|
130
|
+
"messages": []
|
|
131
|
+
}
|
|
132
|
+
by_channel[channel_id]["messages"].append(msg)
|
|
133
|
+
|
|
134
|
+
# Check last_read for top 10 channels (to limit API calls)
|
|
135
|
+
unread_messages = []
|
|
136
|
+
channels_checked = 0
|
|
137
|
+
|
|
138
|
+
for channel_id, conv_data in by_channel.items():
|
|
139
|
+
if channels_checked >= 10:
|
|
140
|
+
break
|
|
141
|
+
|
|
142
|
+
channels_checked += 1
|
|
143
|
+
|
|
144
|
+
# Get last_read timestamp
|
|
145
|
+
info_result = execute_tool(
|
|
146
|
+
tool_name="SLACK_RETRIEVE_CONVERSATION_INFORMATION",
|
|
147
|
+
arguments={"channel": channel_id},
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if isinstance(info_result, dict) and info_result.get("error"):
|
|
151
|
+
continue
|
|
152
|
+
|
|
153
|
+
last_read = info_result.get("data", {}).get("channel", {}).get("last_read", "0")
|
|
154
|
+
|
|
155
|
+
# Filter to messages after last_read
|
|
156
|
+
for msg in conv_data["messages"]:
|
|
157
|
+
ts = msg.get("ts", "0")
|
|
158
|
+
if ts > last_read:
|
|
159
|
+
unread_messages.append(self._format_message(
|
|
160
|
+
msg, conv_data["name"], channel_id
|
|
161
|
+
))
|
|
162
|
+
|
|
163
|
+
return unread_messages
|
|
164
|
+
|
|
165
|
+
def _get_display_name(self, channel: dict) -> str:
|
|
166
|
+
"""Gets display name for channel."""
|
|
167
|
+
if channel.get("is_im"):
|
|
168
|
+
return channel.get("name", "Direct Message")
|
|
169
|
+
return f"#{channel.get('name', 'Unknown')}"
|
|
170
|
+
|
|
171
|
+
def _format_message(self, msg: dict, conv_name: str, channel_id: str) -> dict:
|
|
172
|
+
"""Formats a message for output."""
|
|
173
|
+
files = msg.get("files", [])
|
|
174
|
+
attachments = [f.get("name") or f.get("title") or "file" for f in files] if files else None
|
|
175
|
+
|
|
176
|
+
text = msg.get("text", "")
|
|
177
|
+
if len(text) > 200:
|
|
178
|
+
text = text[:197] + "..."
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
"conversation": conv_name,
|
|
182
|
+
"conversation_id": channel_id,
|
|
183
|
+
"sender": msg.get("username", "Unknown"),
|
|
184
|
+
"text": text,
|
|
185
|
+
"timestamp": self._format_timestamp(msg.get("ts")),
|
|
186
|
+
"permalink": msg.get("permalink", ""),
|
|
187
|
+
"has_attachment": len(files) > 0,
|
|
188
|
+
"attachments": attachments,
|
|
189
|
+
"_ts": msg.get("ts")
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
def _format_timestamp(self, ts: str) -> str:
|
|
193
|
+
"""Formats Slack timestamp."""
|
|
194
|
+
if not ts:
|
|
195
|
+
return ""
|
|
196
|
+
try:
|
|
197
|
+
unix_ts = float(ts.split(".")[0])
|
|
198
|
+
return datetime.fromtimestamp(unix_ts).strftime("%Y-%m-%d %H:%M")
|
|
199
|
+
except (ValueError, TypeError):
|
|
200
|
+
return ts
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
if __name__ == "__main__":
|
|
204
|
+
import sys
|
|
205
|
+
import os
|
|
206
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
|
|
207
|
+
|
|
208
|
+
print("CheckUnreadSlackMessages Test")
|
|
209
|
+
print("-" * 40)
|
|
210
|
+
|
|
211
|
+
tool = CheckUnreadSlackMessages(
|
|
212
|
+
conversation_types="all",
|
|
213
|
+
max_messages=10,
|
|
214
|
+
days_back=7
|
|
215
|
+
)
|
|
216
|
+
print(tool.run())
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
from typing import Literal, Optional, List
|
|
2
|
+
from agency_swarm.tools import BaseTool
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
from helpers import execute_composio_tool
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CreateCalendarEvent(BaseTool):
|
|
10
|
+
"""
|
|
11
|
+
Creates a calendar event in Google Calendar or Outlook.
|
|
12
|
+
|
|
13
|
+
The event is automatically accepted for the user after creation.
|
|
14
|
+
Returns the event ID and a link to view the event.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
provider: Literal["google", "outlook"] = Field(
|
|
18
|
+
...,
|
|
19
|
+
description="Calendar provider: 'google' (Google Calendar) or 'outlook'"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
title: str = Field(
|
|
23
|
+
...,
|
|
24
|
+
description="Title/subject of the event"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
start_datetime: str = Field(
|
|
28
|
+
...,
|
|
29
|
+
description="Start date and time in ISO 8601 format (e.g., '2026-01-15T14:00:00')"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
duration_hours: int = Field(
|
|
33
|
+
default=1,
|
|
34
|
+
ge=0,
|
|
35
|
+
description="Duration in hours (default 1). Use with duration_minutes for partial hours."
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
duration_minutes: int = Field(
|
|
39
|
+
default=0,
|
|
40
|
+
ge=0,
|
|
41
|
+
le=59,
|
|
42
|
+
description="Duration in minutes (0-59). Combined with duration_hours."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
timezone: str = Field(
|
|
46
|
+
default="UTC",
|
|
47
|
+
description="Timezone in IANA format (e.g., 'America/New_York', 'Europe/London', 'Asia/Dubai')"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
description: Optional[str] = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description="Description/notes for the event"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
location: Optional[str] = Field(
|
|
56
|
+
default=None,
|
|
57
|
+
description="Location of the event (address or meeting room)"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
attendees: Optional[List[str]] = Field(
|
|
61
|
+
default=None,
|
|
62
|
+
description="List of attendee email addresses to invite"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
create_meeting_link: bool = Field(
|
|
66
|
+
default=False,
|
|
67
|
+
description="If True, creates a video meeting link (Google Meet or Teams)"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def run(self):
|
|
71
|
+
try:
|
|
72
|
+
if self.provider == "google":
|
|
73
|
+
return self._create_google_event(execute_composio_tool)
|
|
74
|
+
else:
|
|
75
|
+
return self._create_outlook_event(execute_composio_tool)
|
|
76
|
+
|
|
77
|
+
except Exception as e:
|
|
78
|
+
return f"Error creating calendar event: {str(e)}"
|
|
79
|
+
|
|
80
|
+
def _create_google_event(self, execute_tool) -> str:
|
|
81
|
+
"""Creates a Google Calendar event and accepts it."""
|
|
82
|
+
arguments = {
|
|
83
|
+
"calendar_id": "primary",
|
|
84
|
+
"start_datetime": self.start_datetime,
|
|
85
|
+
"event_duration_hour": self.duration_hours,
|
|
86
|
+
"event_duration_minutes": self.duration_minutes,
|
|
87
|
+
"timezone": self.timezone,
|
|
88
|
+
"summary": self.title,
|
|
89
|
+
"create_meeting_room": self.create_meeting_link,
|
|
90
|
+
"exclude_organizer": False, # Include organizer as attendee
|
|
91
|
+
"send_updates": True
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if self.description:
|
|
95
|
+
arguments["description"] = self.description
|
|
96
|
+
|
|
97
|
+
if self.location:
|
|
98
|
+
arguments["location"] = self.location
|
|
99
|
+
|
|
100
|
+
if self.attendees:
|
|
101
|
+
arguments["attendees"] = self.attendees
|
|
102
|
+
|
|
103
|
+
result = execute_tool(
|
|
104
|
+
tool_name="GOOGLECALENDAR_CREATE_EVENT",
|
|
105
|
+
arguments=arguments,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if isinstance(result, dict) and result.get("error"):
|
|
109
|
+
return f"Error creating Google Calendar event: {result.get('error')}"
|
|
110
|
+
|
|
111
|
+
data = result.get("data", {})
|
|
112
|
+
if "response_data" in data:
|
|
113
|
+
data = data["response_data"]
|
|
114
|
+
event_id = data.get("id")
|
|
115
|
+
|
|
116
|
+
if event_id:
|
|
117
|
+
accept_result = execute_tool(
|
|
118
|
+
tool_name="GOOGLECALENDAR_PATCH_EVENT",
|
|
119
|
+
arguments={
|
|
120
|
+
"calendar_id": "primary",
|
|
121
|
+
"event_id": event_id,
|
|
122
|
+
"rsvp_response": "accepted",
|
|
123
|
+
"send_updates": "none"
|
|
124
|
+
},
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
accepted = not (isinstance(accept_result, dict) and accept_result.get("error"))
|
|
128
|
+
else:
|
|
129
|
+
accepted = False
|
|
130
|
+
|
|
131
|
+
meeting_link = None
|
|
132
|
+
conference_data = data.get("conferenceData", {})
|
|
133
|
+
entry_points = conference_data.get("entryPoints", [])
|
|
134
|
+
for entry in entry_points:
|
|
135
|
+
if entry.get("entryPointType") == "video":
|
|
136
|
+
meeting_link = entry.get("uri")
|
|
137
|
+
break
|
|
138
|
+
|
|
139
|
+
return json.dumps({
|
|
140
|
+
"provider": "google",
|
|
141
|
+
"success": True,
|
|
142
|
+
"event_id": event_id,
|
|
143
|
+
"title": self.title,
|
|
144
|
+
"start": data.get("start", {}).get("dateTime"),
|
|
145
|
+
"end": data.get("end", {}).get("dateTime"),
|
|
146
|
+
"accepted": accepted,
|
|
147
|
+
"meeting_link": meeting_link,
|
|
148
|
+
"html_link": data.get("htmlLink", "")
|
|
149
|
+
}, indent=2)
|
|
150
|
+
|
|
151
|
+
def _create_outlook_event(self, execute_tool) -> str:
|
|
152
|
+
"""Creates an Outlook calendar event."""
|
|
153
|
+
from datetime import datetime, timedelta
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
start_dt = datetime.fromisoformat(self.start_datetime.replace("Z", "+00:00"))
|
|
157
|
+
except ValueError:
|
|
158
|
+
start_dt = datetime.fromisoformat(self.start_datetime)
|
|
159
|
+
|
|
160
|
+
duration = timedelta(hours=self.duration_hours, minutes=self.duration_minutes)
|
|
161
|
+
end_dt = start_dt + duration
|
|
162
|
+
end_datetime = end_dt.strftime("%Y-%m-%dT%H:%M:%S")
|
|
163
|
+
|
|
164
|
+
arguments = {
|
|
165
|
+
"user_id": "me",
|
|
166
|
+
"subject": self.title,
|
|
167
|
+
"start_datetime": self.start_datetime,
|
|
168
|
+
"end_datetime": end_datetime,
|
|
169
|
+
"time_zone": self.timezone,
|
|
170
|
+
"is_html": False
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if self.description:
|
|
174
|
+
arguments["body"] = self.description
|
|
175
|
+
|
|
176
|
+
if self.location:
|
|
177
|
+
arguments["location"] = self.location
|
|
178
|
+
|
|
179
|
+
if self.attendees:
|
|
180
|
+
arguments["attendees_info"] = [{"email": email} for email in self.attendees]
|
|
181
|
+
|
|
182
|
+
if self.create_meeting_link:
|
|
183
|
+
arguments["is_online_meeting"] = True
|
|
184
|
+
arguments["online_meeting_provider"] = "teamsForBusiness"
|
|
185
|
+
|
|
186
|
+
result = execute_tool(
|
|
187
|
+
tool_name="OUTLOOK_CALENDAR_CREATE_EVENT",
|
|
188
|
+
arguments=arguments,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
if isinstance(result, dict) and result.get("error"):
|
|
192
|
+
return f"Error creating Outlook event: {result.get('error')}"
|
|
193
|
+
|
|
194
|
+
data = result.get("data", {})
|
|
195
|
+
|
|
196
|
+
# Extract meeting link if created
|
|
197
|
+
meeting_link = None
|
|
198
|
+
online_meeting = data.get("onlineMeeting", {})
|
|
199
|
+
if online_meeting:
|
|
200
|
+
meeting_link = online_meeting.get("joinUrl")
|
|
201
|
+
|
|
202
|
+
return json.dumps({
|
|
203
|
+
"provider": "outlook",
|
|
204
|
+
"success": True,
|
|
205
|
+
"event_id": data.get("id"),
|
|
206
|
+
"title": self.title,
|
|
207
|
+
"start": data.get("start", {}).get("dateTime"),
|
|
208
|
+
"end": data.get("end", {}).get("dateTime"),
|
|
209
|
+
"accepted": True, # Organizer is automatically accepted
|
|
210
|
+
"meeting_link": meeting_link,
|
|
211
|
+
"web_link": data.get("webLink", "")
|
|
212
|
+
}, indent=2)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
if __name__ == "__main__":
|
|
216
|
+
import sys
|
|
217
|
+
import os
|
|
218
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
|
|
219
|
+
|
|
220
|
+
print("=" * 60)
|
|
221
|
+
print("CreateCalendarEvent Test Suite")
|
|
222
|
+
print("=" * 60)
|
|
223
|
+
print()
|
|
224
|
+
|
|
225
|
+
# Test 1: Create Google Calendar event
|
|
226
|
+
print("Test 1: Create Google Calendar event")
|
|
227
|
+
print("-" * 60)
|
|
228
|
+
tool = CreateCalendarEvent(
|
|
229
|
+
provider="google",
|
|
230
|
+
title="Test Event from Virtual Assistant",
|
|
231
|
+
start_datetime="2026-01-08T15:00:00",
|
|
232
|
+
duration_hours=0,
|
|
233
|
+
duration_minutes=30,
|
|
234
|
+
timezone="Asia/Dubai",
|
|
235
|
+
description="This is a test event created by the Virtual Assistant tool.",
|
|
236
|
+
create_meeting_link=False
|
|
237
|
+
)
|
|
238
|
+
result = tool.run()
|
|
239
|
+
print(result)
|
|
240
|
+
print()
|
|
241
|
+
|
|
242
|
+
# Test 2: Create Outlook event
|
|
243
|
+
print("Test 2: Create Outlook Calendar event")
|
|
244
|
+
print("-" * 60)
|
|
245
|
+
tool = CreateCalendarEvent(
|
|
246
|
+
provider="outlook",
|
|
247
|
+
title="Test Outlook Event",
|
|
248
|
+
start_datetime="2026-01-08T16:00:00",
|
|
249
|
+
duration_hours=1,
|
|
250
|
+
duration_minutes=0,
|
|
251
|
+
timezone="UTC",
|
|
252
|
+
description="This is a test Outlook event."
|
|
253
|
+
)
|
|
254
|
+
result = tool.run()
|
|
255
|
+
print(result)
|
|
256
|
+
print()
|
|
257
|
+
|
|
258
|
+
print("=" * 60)
|
|
259
|
+
print("Tests completed! Remember to delete test events from calendars.")
|
|
260
|
+
print("=" * 60)
|
|
261
|
+
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
from agency_swarm.tools import BaseTool
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from helpers import execute_composio_tool
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DeleteCalendarEvent(BaseTool):
|
|
10
|
+
"""
|
|
11
|
+
Deletes a calendar event.
|
|
12
|
+
|
|
13
|
+
Supports both Google Calendar and Outlook.
|
|
14
|
+
Use CheckEventsForDate first to get the event_id of the event to delete.
|
|
15
|
+
|
|
16
|
+
WARNING: This action is irreversible. The event will be permanently deleted.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
provider: Literal["google", "outlook"] = Field(
|
|
20
|
+
...,
|
|
21
|
+
description="Calendar provider: 'google' or 'outlook'"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
event_id: str = Field(
|
|
25
|
+
...,
|
|
26
|
+
description="The unique ID of the event to delete (from CheckEventsForDate)"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
send_notifications: bool = Field(
|
|
30
|
+
default=True,
|
|
31
|
+
description="Whether to send cancellation notifications to attendees"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def run(self):
|
|
35
|
+
try:
|
|
36
|
+
if self.provider == "google":
|
|
37
|
+
return self._delete_google_event(execute_composio_tool)
|
|
38
|
+
else:
|
|
39
|
+
return self._delete_outlook_event(execute_composio_tool)
|
|
40
|
+
|
|
41
|
+
except Exception as e:
|
|
42
|
+
return f"Error deleting event: {str(e)}"
|
|
43
|
+
|
|
44
|
+
def _delete_google_event(self, execute_tool) -> str:
|
|
45
|
+
"""Deletes a Google Calendar event."""
|
|
46
|
+
result = execute_tool(
|
|
47
|
+
tool_name="GOOGLECALENDAR_DELETE_EVENT",
|
|
48
|
+
arguments={
|
|
49
|
+
"calendar_id": "primary",
|
|
50
|
+
"event_id": self.event_id
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if isinstance(result, dict) and result.get("error"):
|
|
55
|
+
return f"Error deleting Google Calendar event: {result.get('error')}"
|
|
56
|
+
|
|
57
|
+
return json.dumps({
|
|
58
|
+
"provider": "google",
|
|
59
|
+
"success": True,
|
|
60
|
+
"event_id": self.event_id,
|
|
61
|
+
"message": "Event deleted successfully"
|
|
62
|
+
}, indent=2)
|
|
63
|
+
|
|
64
|
+
def _delete_outlook_event(self, execute_tool) -> str:
|
|
65
|
+
"""Deletes an Outlook calendar event."""
|
|
66
|
+
result = execute_tool(
|
|
67
|
+
tool_name="OUTLOOK_DELETE_EVENT",
|
|
68
|
+
arguments={
|
|
69
|
+
"user_id": "me",
|
|
70
|
+
"event_id": self.event_id,
|
|
71
|
+
"send_notifications": self.send_notifications
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
if isinstance(result, dict) and result.get("error"):
|
|
76
|
+
return f"Error deleting Outlook event: {result.get('error')}"
|
|
77
|
+
|
|
78
|
+
return json.dumps({
|
|
79
|
+
"provider": "outlook",
|
|
80
|
+
"success": True,
|
|
81
|
+
"event_id": self.event_id,
|
|
82
|
+
"message": "Event deleted successfully",
|
|
83
|
+
"notifications_sent": self.send_notifications
|
|
84
|
+
}, indent=2)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
import sys
|
|
89
|
+
import os
|
|
90
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
|
|
91
|
+
|
|
92
|
+
print("=" * 60)
|
|
93
|
+
print("DeleteCalendarEvent Test Suite")
|
|
94
|
+
print("=" * 60)
|
|
95
|
+
print()
|
|
96
|
+
|
|
97
|
+
# First, list events to find a test event
|
|
98
|
+
from virtual_assistant.tools.CheckEventsForDate import CheckEventsForDate
|
|
99
|
+
|
|
100
|
+
print("=== Getting events for tomorrow ===")
|
|
101
|
+
from datetime import datetime, timedelta
|
|
102
|
+
tomorrow = (datetime.now() + timedelta(days=1)).strftime("%Y-%m-%d")
|
|
103
|
+
|
|
104
|
+
check_tool = CheckEventsForDate(provider="google", date=tomorrow)
|
|
105
|
+
result = check_tool.run()
|
|
106
|
+
|
|
107
|
+
import json
|
|
108
|
+
data = json.loads(result)
|
|
109
|
+
|
|
110
|
+
# Find a test event to delete
|
|
111
|
+
test_events = [e for e in data.get("events", []) if "Test" in e.get("title", "")]
|
|
112
|
+
|
|
113
|
+
if test_events:
|
|
114
|
+
event = test_events[0]
|
|
115
|
+
print(f"Found test event: {event['title']} (ID: {event['event_id']})")
|
|
116
|
+
print()
|
|
117
|
+
|
|
118
|
+
# Delete it
|
|
119
|
+
print("=== Deleting test event ===")
|
|
120
|
+
tool = DeleteCalendarEvent(
|
|
121
|
+
provider="google",
|
|
122
|
+
event_id=event["event_id"],
|
|
123
|
+
send_notifications=False
|
|
124
|
+
)
|
|
125
|
+
result = tool.run()
|
|
126
|
+
print(result)
|
|
127
|
+
else:
|
|
128
|
+
print("No test events found to delete")
|
|
129
|
+
print("Available events:")
|
|
130
|
+
for e in data.get("events", [])[:5]:
|
|
131
|
+
print(f" - {e['title']}")
|
|
132
|
+
|
|
133
|
+
print()
|
|
134
|
+
print("=" * 60)
|
|
135
|
+
print("Test completed!")
|
|
136
|
+
print("=" * 60)
|
|
137
|
+
|