@_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,330 @@
|
|
|
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 FindEmails(BaseTool):
|
|
10
|
+
"""
|
|
11
|
+
Searches and retrieves emails with flexible filtering options.
|
|
12
|
+
|
|
13
|
+
For Gmail: Uses Gmail's powerful query syntax (is:unread, from:, subject:, etc.)
|
|
14
|
+
For Outlook: Uses structured filters for folder, read status, sender, etc.
|
|
15
|
+
|
|
16
|
+
Common use cases:
|
|
17
|
+
- Find unread emails: query="is:unread" (Gmail) or is_read=False (Outlook)
|
|
18
|
+
- Find emails in inbox: query="in:inbox" or label_ids=["INBOX"]
|
|
19
|
+
- Find starred emails: query="is:starred" or label_ids=["STARRED"]
|
|
20
|
+
- Find emails from someone: query="from:someone@example.com"
|
|
21
|
+
- Find emails with attachments: query="has:attachment"
|
|
22
|
+
- Find emails after date: query="after:2026/01/01"
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
provider: Literal["gmail", "outlook"] = Field(
|
|
26
|
+
...,
|
|
27
|
+
description="Email provider: 'gmail' or 'outlook'"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Gmail-specific: flexible query
|
|
31
|
+
query: Optional[str] = Field(
|
|
32
|
+
default=None,
|
|
33
|
+
description="Gmail search query. Examples: 'is:unread', 'from:user@example.com', 'subject:meeting', 'has:attachment', 'after:2026/01/01', 'in:inbox -in:trash'. Can combine with AND/OR."
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Common filters (work for both)
|
|
37
|
+
label_ids: Optional[List[str]] = Field(
|
|
38
|
+
default=None,
|
|
39
|
+
description="Gmail: Label IDs to filter by (e.g., ['INBOX', 'UNREAD', 'STARRED']). Outlook: ignored, use folder instead."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Outlook-specific filters
|
|
43
|
+
folder: Optional[str] = Field(
|
|
44
|
+
default="inbox",
|
|
45
|
+
description="Outlook folder: 'inbox', 'archive', 'sentitems', 'drafts', 'deleteditems', 'junkemail'. Gmail: ignored."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
is_read: Optional[bool] = Field(
|
|
49
|
+
default=None,
|
|
50
|
+
description="Outlook: Filter by read status (True=read, False=unread, None=all). Gmail: use query='is:unread' instead."
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
from_address: Optional[str] = Field(
|
|
54
|
+
default=None,
|
|
55
|
+
description="Filter by sender email address. Gmail: use query='from:...' instead."
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
subject_contains: Optional[str] = Field(
|
|
59
|
+
default=None,
|
|
60
|
+
description="Filter by subject containing text. Gmail: use query='subject:...' instead."
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
has_attachments: Optional[bool] = Field(
|
|
64
|
+
default=None,
|
|
65
|
+
description="Filter by attachment presence. Gmail: use query='has:attachment' instead."
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
received_after: Optional[str] = Field(
|
|
69
|
+
default=None,
|
|
70
|
+
description="Filter emails received after date (ISO format: 2026-01-01T00:00:00Z). Gmail: use query='after:2026/01/01' instead."
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Pagination and limits
|
|
74
|
+
limit: int = Field(
|
|
75
|
+
default=20,
|
|
76
|
+
ge=1,
|
|
77
|
+
le=100,
|
|
78
|
+
description="Maximum number of emails to return (1-100)"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
page_token: Optional[str] = Field(
|
|
82
|
+
default=None,
|
|
83
|
+
description="Token for fetching next page of results"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def run(self):
|
|
87
|
+
try:
|
|
88
|
+
if self.provider == "gmail":
|
|
89
|
+
return self._find_gmail_emails(execute_composio_tool)
|
|
90
|
+
else:
|
|
91
|
+
return self._find_outlook_emails(execute_composio_tool)
|
|
92
|
+
|
|
93
|
+
except Exception as e:
|
|
94
|
+
return f"Error finding emails: {str(e)}"
|
|
95
|
+
|
|
96
|
+
def _find_gmail_emails(self, execute_tool) -> str:
|
|
97
|
+
"""Finds emails in Gmail using query syntax."""
|
|
98
|
+
arguments = {
|
|
99
|
+
"user_id": "me",
|
|
100
|
+
"max_results": self.limit,
|
|
101
|
+
"include_payload": False,
|
|
102
|
+
"verbose": False
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Add query if provided
|
|
106
|
+
if self.query:
|
|
107
|
+
arguments["query"] = self.query
|
|
108
|
+
|
|
109
|
+
# Add label filtering
|
|
110
|
+
if self.label_ids:
|
|
111
|
+
arguments["label_ids"] = self.label_ids
|
|
112
|
+
|
|
113
|
+
# Add pagination
|
|
114
|
+
if self.page_token:
|
|
115
|
+
arguments["page_token"] = self.page_token
|
|
116
|
+
|
|
117
|
+
# Execute search
|
|
118
|
+
result = execute_tool(
|
|
119
|
+
tool_name="GMAIL_FETCH_EMAILS",
|
|
120
|
+
arguments=arguments,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if isinstance(result, dict) and result.get("error"):
|
|
124
|
+
return f"Error searching Gmail: {result.get('error')}"
|
|
125
|
+
|
|
126
|
+
data = result.get("data", {})
|
|
127
|
+
messages = data.get("messages", [])
|
|
128
|
+
next_page_token = data.get("nextPageToken")
|
|
129
|
+
|
|
130
|
+
if not messages:
|
|
131
|
+
return json.dumps({
|
|
132
|
+
"provider": "gmail",
|
|
133
|
+
"query": self.query,
|
|
134
|
+
"count": 0,
|
|
135
|
+
"emails": [],
|
|
136
|
+
"next_page_token": None
|
|
137
|
+
}, indent=2)
|
|
138
|
+
|
|
139
|
+
# Sort by timestamp (newest first by default)
|
|
140
|
+
messages_sorted = sorted(
|
|
141
|
+
messages,
|
|
142
|
+
key=lambda m: m.get("messageTimestamp", ""),
|
|
143
|
+
reverse=True
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Format output
|
|
147
|
+
formatted_emails = []
|
|
148
|
+
for msg in messages_sorted:
|
|
149
|
+
formatted_emails.append({
|
|
150
|
+
"subject": msg.get("subject", "(No subject)"),
|
|
151
|
+
"from": msg.get("sender", "Unknown"),
|
|
152
|
+
"message_id": msg.get("messageId"),
|
|
153
|
+
"thread_id": msg.get("threadId"),
|
|
154
|
+
"received_at": msg.get("messageTimestamp"),
|
|
155
|
+
"labels": msg.get("labelIds", []),
|
|
156
|
+
"snippet": msg.get("snippet", "")[:100] if msg.get("snippet") else ""
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
return json.dumps({
|
|
160
|
+
"provider": "gmail",
|
|
161
|
+
"query": self.query,
|
|
162
|
+
"count": len(formatted_emails),
|
|
163
|
+
"emails": formatted_emails,
|
|
164
|
+
"next_page_token": next_page_token
|
|
165
|
+
}, indent=2)
|
|
166
|
+
|
|
167
|
+
def _find_outlook_emails(self, execute_tool) -> str:
|
|
168
|
+
"""Finds emails in Outlook using structured filters."""
|
|
169
|
+
arguments = {
|
|
170
|
+
"user_id": "me",
|
|
171
|
+
"folder": self.folder or "inbox",
|
|
172
|
+
"top": self.limit,
|
|
173
|
+
"orderby": ["receivedDateTime desc"],
|
|
174
|
+
"select": ["id", "subject", "from", "receivedDateTime", "conversationId", "categories", "isRead", "hasAttachments", "bodyPreview"]
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# Apply filters
|
|
178
|
+
if self.is_read is not None:
|
|
179
|
+
arguments["is_read"] = self.is_read
|
|
180
|
+
|
|
181
|
+
if self.from_address:
|
|
182
|
+
arguments["from_address"] = self.from_address
|
|
183
|
+
|
|
184
|
+
if self.subject_contains:
|
|
185
|
+
arguments["subject_contains"] = self.subject_contains
|
|
186
|
+
|
|
187
|
+
if self.has_attachments is not None:
|
|
188
|
+
arguments["has_attachments"] = self.has_attachments
|
|
189
|
+
|
|
190
|
+
if self.received_after:
|
|
191
|
+
arguments["received_date_time_gt"] = self.received_after
|
|
192
|
+
|
|
193
|
+
if self.label_ids:
|
|
194
|
+
arguments["categories"] = self.label_ids
|
|
195
|
+
|
|
196
|
+
# Add pagination
|
|
197
|
+
if self.page_token:
|
|
198
|
+
try:
|
|
199
|
+
arguments["skip"] = int(self.page_token)
|
|
200
|
+
except ValueError:
|
|
201
|
+
return f"Error: Invalid page_token for Outlook. Expected a number."
|
|
202
|
+
|
|
203
|
+
# Execute search
|
|
204
|
+
result = execute_tool(
|
|
205
|
+
tool_name="OUTLOOK_LIST_MESSAGES",
|
|
206
|
+
arguments=arguments,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
if isinstance(result, dict) and result.get("error"):
|
|
210
|
+
return f"Error searching Outlook: {result.get('error')}"
|
|
211
|
+
|
|
212
|
+
data = result.get("data", {})
|
|
213
|
+
messages = data.get("value", [])
|
|
214
|
+
|
|
215
|
+
# Calculate next page token
|
|
216
|
+
current_skip = int(self.page_token) if self.page_token else 0
|
|
217
|
+
next_page_token = None
|
|
218
|
+
if len(messages) == self.limit:
|
|
219
|
+
next_page_token = str(current_skip + self.limit)
|
|
220
|
+
|
|
221
|
+
if not messages:
|
|
222
|
+
return json.dumps({
|
|
223
|
+
"provider": "outlook",
|
|
224
|
+
"folder": self.folder,
|
|
225
|
+
"filters": {
|
|
226
|
+
"is_read": self.is_read,
|
|
227
|
+
"from_address": self.from_address,
|
|
228
|
+
"subject_contains": self.subject_contains,
|
|
229
|
+
"has_attachments": self.has_attachments
|
|
230
|
+
},
|
|
231
|
+
"count": 0,
|
|
232
|
+
"emails": [],
|
|
233
|
+
"next_page_token": None
|
|
234
|
+
}, indent=2)
|
|
235
|
+
|
|
236
|
+
# Format output
|
|
237
|
+
formatted_emails = []
|
|
238
|
+
for msg in messages:
|
|
239
|
+
from_info = msg.get("from", {}).get("emailAddress", {})
|
|
240
|
+
formatted_emails.append({
|
|
241
|
+
"subject": msg.get("subject", "(No subject)"),
|
|
242
|
+
"from": f"{from_info.get('name', '')} <{from_info.get('address', 'Unknown')}>",
|
|
243
|
+
"message_id": msg.get("id"),
|
|
244
|
+
"conversation_id": msg.get("conversationId"),
|
|
245
|
+
"received_at": msg.get("receivedDateTime"),
|
|
246
|
+
"categories": msg.get("categories", []),
|
|
247
|
+
"is_read": msg.get("isRead"),
|
|
248
|
+
"has_attachments": msg.get("hasAttachments"),
|
|
249
|
+
"snippet": (msg.get("bodyPreview") or "")[:100]
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
return json.dumps({
|
|
253
|
+
"provider": "outlook",
|
|
254
|
+
"folder": self.folder,
|
|
255
|
+
"filters": {
|
|
256
|
+
"is_read": self.is_read,
|
|
257
|
+
"from_address": self.from_address,
|
|
258
|
+
"subject_contains": self.subject_contains,
|
|
259
|
+
"has_attachments": self.has_attachments
|
|
260
|
+
},
|
|
261
|
+
"count": len(formatted_emails),
|
|
262
|
+
"emails": formatted_emails,
|
|
263
|
+
"next_page_token": next_page_token
|
|
264
|
+
}, indent=2)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
if __name__ == "__main__":
|
|
268
|
+
import sys
|
|
269
|
+
import os
|
|
270
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
|
|
271
|
+
|
|
272
|
+
print("=" * 60)
|
|
273
|
+
print("FindEmails Test Suite")
|
|
274
|
+
print("=" * 60)
|
|
275
|
+
print()
|
|
276
|
+
|
|
277
|
+
# Test 1: Gmail - Find unread emails
|
|
278
|
+
print("Test 1: Gmail - Find unread emails")
|
|
279
|
+
print("-" * 60)
|
|
280
|
+
tool = FindEmails(provider="gmail", query="is:unread", limit=3)
|
|
281
|
+
result = tool.run()
|
|
282
|
+
data = json.loads(result)
|
|
283
|
+
print(f"Query: {data.get('query')}")
|
|
284
|
+
print(f"Count: {data.get('count')}")
|
|
285
|
+
if data.get("emails"):
|
|
286
|
+
print(f"First email: {data['emails'][0]['subject'][:50]}...")
|
|
287
|
+
print()
|
|
288
|
+
|
|
289
|
+
# Test 2: Gmail - Find starred emails
|
|
290
|
+
print("Test 2: Gmail - Find starred emails in inbox")
|
|
291
|
+
print("-" * 60)
|
|
292
|
+
tool = FindEmails(provider="gmail", query="is:starred in:inbox", limit=3)
|
|
293
|
+
result = tool.run()
|
|
294
|
+
data = json.loads(result)
|
|
295
|
+
print(f"Query: {data.get('query')}")
|
|
296
|
+
print(f"Count: {data.get('count')}")
|
|
297
|
+
print()
|
|
298
|
+
|
|
299
|
+
# Test 3: Gmail - Find emails with attachments
|
|
300
|
+
print("Test 3: Gmail - Find emails with attachments")
|
|
301
|
+
print("-" * 60)
|
|
302
|
+
tool = FindEmails(provider="gmail", query="has:attachment", limit=3)
|
|
303
|
+
result = tool.run()
|
|
304
|
+
data = json.loads(result)
|
|
305
|
+
print(f"Query: {data.get('query')}")
|
|
306
|
+
print(f"Count: {data.get('count')}")
|
|
307
|
+
print()
|
|
308
|
+
|
|
309
|
+
# Test 4: Gmail - Find emails from specific sender
|
|
310
|
+
print("Test 4: Gmail - Find emails from specific sender")
|
|
311
|
+
print("-" * 60)
|
|
312
|
+
tool = FindEmails(provider="gmail", query="from:noreply", limit=3)
|
|
313
|
+
result = tool.run()
|
|
314
|
+
data = json.loads(result)
|
|
315
|
+
print(f"Query: {data.get('query')}")
|
|
316
|
+
print(f"Count: {data.get('count')}")
|
|
317
|
+
print()
|
|
318
|
+
|
|
319
|
+
# Test 5: Outlook - Find unread emails
|
|
320
|
+
print("Test 5: Outlook - Find unread emails in inbox")
|
|
321
|
+
print("-" * 60)
|
|
322
|
+
tool = FindEmails(provider="outlook", folder="inbox", is_read=False, limit=3)
|
|
323
|
+
result = tool.run()
|
|
324
|
+
print(result[:500])
|
|
325
|
+
print()
|
|
326
|
+
|
|
327
|
+
print("=" * 60)
|
|
328
|
+
print("All tests completed!")
|
|
329
|
+
print("=" * 60)
|
|
330
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from agency_swarm.tools import BaseTool
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
import pytz
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class GetCurrentTime(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Retrieves the current date and time in a specified timezone.
|
|
10
|
+
Use this when you need to know what time it is, or to provide accurate time-based information.
|
|
11
|
+
"""
|
|
12
|
+
timezone: str = Field(
|
|
13
|
+
default="UTC",
|
|
14
|
+
description="The timezone to retrieve the current time in (e.g., 'UTC', 'US/Eastern', 'Europe/London', 'Asia/Tokyo'). Defaults to UTC."
|
|
15
|
+
)
|
|
16
|
+
include_day_of_week: bool = Field(
|
|
17
|
+
default=True,
|
|
18
|
+
description="If True, includes the day of the week in the output. Defaults to True."
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def run(self):
|
|
22
|
+
"""Retrieves the current date and time in the specified timezone."""
|
|
23
|
+
try:
|
|
24
|
+
tz = pytz.timezone(self.timezone)
|
|
25
|
+
current_time = datetime.now(tz)
|
|
26
|
+
|
|
27
|
+
if self.include_day_of_week:
|
|
28
|
+
formatted_time = current_time.strftime("%A, %B %d, %Y - %I:%M:%S %p %Z")
|
|
29
|
+
else:
|
|
30
|
+
formatted_time = current_time.strftime("%B %d, %Y - %I:%M:%S %p %Z")
|
|
31
|
+
|
|
32
|
+
return f"Current time in {self.timezone}: {formatted_time}"
|
|
33
|
+
|
|
34
|
+
except pytz.exceptions.UnknownTimeZoneError:
|
|
35
|
+
return f"Error: Unknown timezone '{self.timezone}'. Please provide a valid timezone (e.g., 'UTC', 'US/Eastern', 'Europe/London')."
|
|
36
|
+
except Exception as e:
|
|
37
|
+
return f"Error retrieving current time: {str(e)}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
# Test 1: Current time in UTC
|
|
42
|
+
print("=== Test 1: Current time in UTC ===")
|
|
43
|
+
tool = GetCurrentTime(timezone="UTC")
|
|
44
|
+
print(tool.run())
|
|
45
|
+
print()
|
|
46
|
+
|
|
47
|
+
# Test 2: Current time in US/Eastern
|
|
48
|
+
print("=== Test 2: Current time in US/Eastern ===")
|
|
49
|
+
tool = GetCurrentTime(timezone="US/Eastern")
|
|
50
|
+
print(tool.run())
|
|
51
|
+
print()
|
|
52
|
+
|
|
53
|
+
# Test 3: Current time in Europe/London without day of week
|
|
54
|
+
print("=== Test 3: Current time in Europe/London (without day of week) ===")
|
|
55
|
+
tool = GetCurrentTime(timezone="Europe/London", include_day_of_week=False)
|
|
56
|
+
print(tool.run())
|
|
57
|
+
print()
|
|
58
|
+
|
|
59
|
+
# Test 4: Current time in Asia/Tokyo
|
|
60
|
+
print("=== Test 4: Current time in Asia/Tokyo ===")
|
|
61
|
+
tool = GetCurrentTime(timezone="Asia/Tokyo")
|
|
62
|
+
print(tool.run())
|
|
63
|
+
print()
|
|
64
|
+
|
|
65
|
+
# Test 5: Invalid timezone
|
|
66
|
+
print("=== Test 5: Invalid timezone ===")
|
|
67
|
+
tool = GetCurrentTime(timezone="Invalid/Timezone")
|
|
68
|
+
print(tool.run())
|
|
69
|
+
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from agency_swarm.tools import BaseTool
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from helpers import execute_composio_tool
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class GetSlackUserInfo(BaseTool):
|
|
9
|
+
"""
|
|
10
|
+
Gets Slack user details by ID, email, or name. Returns name, email, title, and status.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
user: str = Field(
|
|
14
|
+
...,
|
|
15
|
+
description="User ID (U06NF4U24KE), email, or display name to look up"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def run(self):
|
|
19
|
+
try:
|
|
20
|
+
# Determine lookup method
|
|
21
|
+
if self.user.startswith("U") and len(self.user) == 11:
|
|
22
|
+
return self._get_by_id(execute_composio_tool, self.user)
|
|
23
|
+
elif "@" in self.user:
|
|
24
|
+
return self._get_by_email(execute_composio_tool, self.user)
|
|
25
|
+
else:
|
|
26
|
+
return self._get_by_name(execute_composio_tool, self.user)
|
|
27
|
+
|
|
28
|
+
except Exception as e:
|
|
29
|
+
return f"Error: {str(e)}"
|
|
30
|
+
|
|
31
|
+
def _get_by_id(self, execute_tool, slack_user_id: str) -> str:
|
|
32
|
+
"""Gets user by Slack user ID."""
|
|
33
|
+
result = execute_tool(
|
|
34
|
+
tool_name="SLACK_GET_USER_INFO",
|
|
35
|
+
arguments={"user": slack_user_id},
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if result.get("error"):
|
|
39
|
+
return f"Error: User '{slack_user_id}' not found"
|
|
40
|
+
|
|
41
|
+
user_data = result.get("data", {}).get("user", {})
|
|
42
|
+
return self._format_user(user_data)
|
|
43
|
+
|
|
44
|
+
def _get_by_email(self, execute_tool, email: str) -> str:
|
|
45
|
+
"""Gets user by email address."""
|
|
46
|
+
result = execute_tool(
|
|
47
|
+
tool_name="SLACK_FIND_USER_BY_EMAIL_ADDRESS",
|
|
48
|
+
arguments={"email": email},
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if result.get("error"):
|
|
52
|
+
return f"Error: User with email '{email}' not found"
|
|
53
|
+
|
|
54
|
+
user_data = result.get("data", {}).get("user", {})
|
|
55
|
+
return self._format_user(user_data)
|
|
56
|
+
|
|
57
|
+
def _get_by_name(self, execute_tool, name: str) -> str:
|
|
58
|
+
"""Gets user by name search."""
|
|
59
|
+
result = execute_tool(
|
|
60
|
+
tool_name="SLACK_FIND_USERS",
|
|
61
|
+
arguments={"query": name},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if result.get("error"):
|
|
65
|
+
return f"Error: Could not search for user '{name}'"
|
|
66
|
+
|
|
67
|
+
members = result.get("data", {}).get("members", [])
|
|
68
|
+
|
|
69
|
+
# Find best match
|
|
70
|
+
name_lower = name.lower()
|
|
71
|
+
for member in members:
|
|
72
|
+
username = member.get("name", "").lower()
|
|
73
|
+
display = member.get("profile", {}).get("display_name", "").lower()
|
|
74
|
+
real = member.get("profile", {}).get("real_name", "").lower()
|
|
75
|
+
|
|
76
|
+
if name_lower in [username, display, real] or name_lower in real:
|
|
77
|
+
return self._format_user(member)
|
|
78
|
+
|
|
79
|
+
if members:
|
|
80
|
+
return self._format_user(members[0])
|
|
81
|
+
|
|
82
|
+
return f"Error: User '{name}' not found"
|
|
83
|
+
|
|
84
|
+
def _format_user(self, user: dict) -> str:
|
|
85
|
+
"""Formats user data for output."""
|
|
86
|
+
profile = user.get("profile", {})
|
|
87
|
+
|
|
88
|
+
info = {
|
|
89
|
+
"id": user.get("id"),
|
|
90
|
+
"name": profile.get("real_name") or user.get("name"),
|
|
91
|
+
"display_name": profile.get("display_name") or None,
|
|
92
|
+
"email": profile.get("email") or None,
|
|
93
|
+
"title": profile.get("title") or None,
|
|
94
|
+
"status": profile.get("status_text") or None,
|
|
95
|
+
"timezone": user.get("tz_label") or None,
|
|
96
|
+
"is_bot": user.get("is_bot", False),
|
|
97
|
+
"is_admin": user.get("is_admin", False)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Remove None values
|
|
101
|
+
info = {k: v for k, v in info.items() if v is not None and v != ""}
|
|
102
|
+
|
|
103
|
+
return json.dumps(info, indent=2)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if __name__ == "__main__":
|
|
107
|
+
import sys
|
|
108
|
+
import os
|
|
109
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
|
|
110
|
+
|
|
111
|
+
print("GetSlackUserInfo Test")
|
|
112
|
+
print("-" * 40)
|
|
113
|
+
|
|
114
|
+
# Test by name
|
|
115
|
+
tool = GetSlackUserInfo(user="test_user")
|
|
116
|
+
print(tool.run())
|
|
117
|
+
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from agency_swarm.tools import BaseTool
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ListDirectory(BaseTool):
|
|
9
|
+
"""
|
|
10
|
+
Lists files and directories in a given path.
|
|
11
|
+
Use this tool to explore the project structure and understand the codebase layout.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
directory_path: str = Field(
|
|
15
|
+
...,
|
|
16
|
+
description="The absolute path to the directory to list",
|
|
17
|
+
)
|
|
18
|
+
recursive: Optional[bool] = Field(
|
|
19
|
+
False,
|
|
20
|
+
description="If True, list files recursively up to 3 levels deep. Default is False.",
|
|
21
|
+
)
|
|
22
|
+
max_depth: Optional[int] = Field(
|
|
23
|
+
3,
|
|
24
|
+
description="Maximum depth for recursive listing. Default is 3.",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def run(self):
|
|
28
|
+
try:
|
|
29
|
+
if not os.path.isabs(self.directory_path):
|
|
30
|
+
return f"Error: directory_path must be an absolute path. Got: {self.directory_path}"
|
|
31
|
+
|
|
32
|
+
if not os.path.exists(self.directory_path):
|
|
33
|
+
return f"Error: Directory does not exist: {self.directory_path}"
|
|
34
|
+
|
|
35
|
+
if not os.path.isdir(self.directory_path):
|
|
36
|
+
return f"Error: Path is not a directory: {self.directory_path}"
|
|
37
|
+
|
|
38
|
+
def list_dir_tree(path: str, prefix: str = "", depth: int = 0) -> str:
|
|
39
|
+
if depth > self.max_depth:
|
|
40
|
+
return ""
|
|
41
|
+
|
|
42
|
+
result = []
|
|
43
|
+
try:
|
|
44
|
+
entries = sorted(os.listdir(path))
|
|
45
|
+
except PermissionError:
|
|
46
|
+
return f"{prefix}[Permission Denied]\n"
|
|
47
|
+
|
|
48
|
+
# Filter out hidden files and common ignore patterns
|
|
49
|
+
ignore_patterns = {
|
|
50
|
+
"__pycache__",
|
|
51
|
+
".git",
|
|
52
|
+
".venv",
|
|
53
|
+
"venv",
|
|
54
|
+
"node_modules",
|
|
55
|
+
".pytest_cache",
|
|
56
|
+
".mypy_cache",
|
|
57
|
+
".DS_Store",
|
|
58
|
+
"*.pyc",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
filtered_entries = []
|
|
62
|
+
for entry in entries:
|
|
63
|
+
if entry.startswith("."):
|
|
64
|
+
continue
|
|
65
|
+
if entry in ignore_patterns:
|
|
66
|
+
continue
|
|
67
|
+
filtered_entries.append(entry)
|
|
68
|
+
|
|
69
|
+
for i, entry in enumerate(filtered_entries):
|
|
70
|
+
entry_path = os.path.join(path, entry)
|
|
71
|
+
is_last = i == len(filtered_entries) - 1
|
|
72
|
+
|
|
73
|
+
if is_last:
|
|
74
|
+
connector = "└── "
|
|
75
|
+
new_prefix = prefix + " "
|
|
76
|
+
else:
|
|
77
|
+
connector = "├── "
|
|
78
|
+
new_prefix = prefix + "│ "
|
|
79
|
+
|
|
80
|
+
if os.path.isdir(entry_path):
|
|
81
|
+
result.append(f"{prefix}{connector}{entry}/\n")
|
|
82
|
+
if self.recursive and depth < self.max_depth:
|
|
83
|
+
result.append(
|
|
84
|
+
list_dir_tree(entry_path, new_prefix, depth + 1)
|
|
85
|
+
)
|
|
86
|
+
else:
|
|
87
|
+
result.append(f"{prefix}{connector}{entry}\n")
|
|
88
|
+
|
|
89
|
+
return "".join(result)
|
|
90
|
+
|
|
91
|
+
output = f"{self.directory_path}/\n"
|
|
92
|
+
output += list_dir_tree(self.directory_path)
|
|
93
|
+
|
|
94
|
+
if not output.strip():
|
|
95
|
+
return f"Directory is empty: {self.directory_path}"
|
|
96
|
+
|
|
97
|
+
return output.rstrip()
|
|
98
|
+
|
|
99
|
+
except Exception as e:
|
|
100
|
+
return f"Error listing directory: {str(e)}"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
# Test the tool with current directory
|
|
105
|
+
import pathlib
|
|
106
|
+
|
|
107
|
+
current_dir = str(pathlib.Path(__file__).parent.parent.absolute())
|
|
108
|
+
|
|
109
|
+
tool = ListDirectory(directory_path=current_dir, recursive=True)
|
|
110
|
+
print("Listing directory structure:")
|
|
111
|
+
print(tool.run())
|
|
112
|
+
|
|
113
|
+
|