@_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.
Files changed (316) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +152 -0
  3. package/bin/openswarm.js +38 -0
  4. package/config.py +34 -0
  5. package/data_analyst_agent/.cursor/rules/data_analyst.mdc +43 -0
  6. package/data_analyst_agent/__init__.py +3 -0
  7. package/data_analyst_agent/__pycache__/__init__.cpython-312.pyc +0 -0
  8. package/data_analyst_agent/__pycache__/data_analyst_agent.cpython-312.pyc +0 -0
  9. package/data_analyst_agent/data_analyst_agent.py +45 -0
  10. package/data_analyst_agent/instructions.md +173 -0
  11. package/data_analyst_agent/test_files/test_file.csv +21 -0
  12. package/data_analyst_agent/tools/__init__.py +6 -0
  13. package/deep_research/__init__.py +1 -0
  14. package/deep_research/__pycache__/__init__.cpython-312.pyc +0 -0
  15. package/deep_research/__pycache__/deep_research.cpython-312.pyc +0 -0
  16. package/deep_research/deep_research.py +27 -0
  17. package/deep_research/instructions.md +104 -0
  18. package/deep_research/tools/__init__.py +1 -0
  19. package/docs_agent/__init__.py +3 -0
  20. package/docs_agent/__pycache__/__init__.cpython-312.pyc +0 -0
  21. package/docs_agent/__pycache__/docs_agent.cpython-312.pyc +0 -0
  22. package/docs_agent/docs_agent.py +61 -0
  23. package/docs_agent/instructions.md +418 -0
  24. package/docs_agent/tools/ConvertDocument.py +323 -0
  25. package/docs_agent/tools/CreateDocument.py +287 -0
  26. package/docs_agent/tools/ListDocuments.py +134 -0
  27. package/docs_agent/tools/ModifyDocument.py +247 -0
  28. package/docs_agent/tools/RestoreDocument.py +79 -0
  29. package/docs_agent/tools/ViewDocument.py +153 -0
  30. package/docs_agent/tools/__init__.py +1 -0
  31. package/docs_agent/tools/__pycache__/ConvertDocument.cpython-312.pyc +0 -0
  32. package/docs_agent/tools/__pycache__/CreateDocument.cpython-312.pyc +0 -0
  33. package/docs_agent/tools/__pycache__/ListDocuments.cpython-312.pyc +0 -0
  34. package/docs_agent/tools/__pycache__/ModifyDocument.cpython-312.pyc +0 -0
  35. package/docs_agent/tools/__pycache__/RestoreDocument.cpython-312.pyc +0 -0
  36. package/docs_agent/tools/__pycache__/ViewDocument.cpython-312.pyc +0 -0
  37. package/docs_agent/tools/__pycache__/__init__.cpython-312.pyc +0 -0
  38. package/docs_agent/tools/utils/__init__.py +1 -0
  39. package/docs_agent/tools/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  40. package/docs_agent/tools/utils/__pycache__/doc_file_utils.cpython-312.pyc +0 -0
  41. package/docs_agent/tools/utils/__pycache__/html_docx_blocks.cpython-312.pyc +0 -0
  42. package/docs_agent/tools/utils/__pycache__/html_docx_constants.cpython-312.pyc +0 -0
  43. package/docs_agent/tools/utils/__pycache__/html_docx_core.cpython-312.pyc +0 -0
  44. package/docs_agent/tools/utils/__pycache__/html_docx_css.cpython-312.pyc +0 -0
  45. package/docs_agent/tools/utils/__pycache__/html_docx_images.cpython-312.pyc +0 -0
  46. package/docs_agent/tools/utils/__pycache__/html_docx_page.cpython-312.pyc +0 -0
  47. package/docs_agent/tools/utils/__pycache__/html_docx_paragraphs.cpython-312.pyc +0 -0
  48. package/docs_agent/tools/utils/__pycache__/html_docx_playwright.cpython-312.pyc +0 -0
  49. package/docs_agent/tools/utils/__pycache__/html_docx_selectors.cpython-312.pyc +0 -0
  50. package/docs_agent/tools/utils/__pycache__/html_docx_shared.cpython-312.pyc +0 -0
  51. package/docs_agent/tools/utils/__pycache__/html_validation.cpython-312.pyc +0 -0
  52. package/docs_agent/tools/utils/doc_file_utils.py +29 -0
  53. package/docs_agent/tools/utils/html_docx_blocks.py +262 -0
  54. package/docs_agent/tools/utils/html_docx_constants.py +78 -0
  55. package/docs_agent/tools/utils/html_docx_core.py +138 -0
  56. package/docs_agent/tools/utils/html_docx_css.py +262 -0
  57. package/docs_agent/tools/utils/html_docx_images.py +293 -0
  58. package/docs_agent/tools/utils/html_docx_page.py +185 -0
  59. package/docs_agent/tools/utils/html_docx_paragraphs.py +342 -0
  60. package/docs_agent/tools/utils/html_docx_playwright.py +184 -0
  61. package/docs_agent/tools/utils/html_docx_selectors.py +196 -0
  62. package/docs_agent/tools/utils/html_docx_shared.py +23 -0
  63. package/docs_agent/tools/utils/html_docx_tables.py +942 -0
  64. package/docs_agent/tools/utils/html_validation.py +102 -0
  65. package/helpers.py +59 -0
  66. package/image_generation_agent/__init__.py +1 -0
  67. package/image_generation_agent/__pycache__/__init__.cpython-312.pyc +0 -0
  68. package/image_generation_agent/__pycache__/image_generation_agent.cpython-312.pyc +0 -0
  69. package/image_generation_agent/image_generation_agent.py +31 -0
  70. package/image_generation_agent/instructions.md +80 -0
  71. package/image_generation_agent/tools/CombineImages.py +211 -0
  72. package/image_generation_agent/tools/EditImages.py +200 -0
  73. package/image_generation_agent/tools/GenerateImages.py +184 -0
  74. package/image_generation_agent/tools/RemoveBackground.py +108 -0
  75. package/image_generation_agent/tools/__init__.py +2 -0
  76. package/image_generation_agent/tools/__pycache__/CombineImages.cpython-312.pyc +0 -0
  77. package/image_generation_agent/tools/__pycache__/EditImages.cpython-312.pyc +0 -0
  78. package/image_generation_agent/tools/__pycache__/GenerateImages.cpython-312.pyc +0 -0
  79. package/image_generation_agent/tools/__pycache__/RemoveBackground.cpython-312.pyc +0 -0
  80. package/image_generation_agent/tools/utils/__init__.py +2 -0
  81. package/image_generation_agent/tools/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  82. package/image_generation_agent/tools/utils/__pycache__/image_io.cpython-312.pyc +0 -0
  83. package/image_generation_agent/tools/utils/image_io.py +308 -0
  84. package/onboard.py +325 -0
  85. package/orchestrator/__init__.py +3 -0
  86. package/orchestrator/__pycache__/__init__.cpython-312.pyc +0 -0
  87. package/orchestrator/__pycache__/orchestrator.cpython-312.pyc +0 -0
  88. package/orchestrator/instructions.md +90 -0
  89. package/orchestrator/orchestrator.py +33 -0
  90. package/package.json +49 -0
  91. package/patches/__init__.py +1 -0
  92. package/patches/__pycache__/__init__.cpython-312.pyc +0 -0
  93. package/patches/__pycache__/patch_agency_swarm_dual_comms.cpython-312.pyc +0 -0
  94. package/patches/__pycache__/patch_file_attachment_refs.cpython-312.pyc +0 -0
  95. package/patches/__pycache__/patch_ipython_interpreter_composio.cpython-312.pyc +0 -0
  96. package/patches/dom-to-pptx+1.1.5.patch +133440 -0
  97. package/patches/patch_agency_swarm_dual_comms.py +199 -0
  98. package/patches/patch_file_attachment_refs.py +74 -0
  99. package/patches/patch_ipython_interpreter_composio.py +54 -0
  100. package/pyproject.toml +67 -0
  101. package/run.py +343 -0
  102. package/server.py +26 -0
  103. package/shared_instructions.md +119 -0
  104. package/shared_tools/CopyFile.py +68 -0
  105. package/shared_tools/ExecuteTool.py +184 -0
  106. package/shared_tools/FindTools.py +101 -0
  107. package/shared_tools/ManageConnections.py +43 -0
  108. package/shared_tools/SearchTools.py +44 -0
  109. package/shared_tools/__init__.py +7 -0
  110. package/shared_tools/__pycache__/CopyFile.cpython-312.pyc +0 -0
  111. package/shared_tools/__pycache__/ExecuteTool.cpython-312.pyc +0 -0
  112. package/shared_tools/__pycache__/FindTools.cpython-312.pyc +0 -0
  113. package/shared_tools/__pycache__/ManageConnections.cpython-312.pyc +0 -0
  114. package/shared_tools/__pycache__/SearchTools.cpython-312.pyc +0 -0
  115. package/shared_tools/__pycache__/__init__.cpython-312.pyc +0 -0
  116. package/slides_agent/.cursor/rules/slides-agent-workflow.mdc +9 -0
  117. package/slides_agent/__init__.py +1 -0
  118. package/slides_agent/__pycache__/__init__.cpython-312.pyc +0 -0
  119. package/slides_agent/__pycache__/slides_agent.cpython-312.pyc +0 -0
  120. package/slides_agent/instructions.md +298 -0
  121. package/slides_agent/pptx/SKILL.md +528 -0
  122. package/slides_agent/pptx/html2pptx.md +625 -0
  123. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  124. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  125. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  126. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  127. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  128. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  129. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  130. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  131. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  132. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  133. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  134. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  135. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  136. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  137. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  138. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  139. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  140. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  141. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  142. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  143. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  144. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  145. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  146. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  147. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  148. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  149. package/slides_agent/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  150. package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  151. package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  152. package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  153. package/slides_agent/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  154. package/slides_agent/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  155. package/slides_agent/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  156. package/slides_agent/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  157. package/slides_agent/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  158. package/slides_agent/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  159. package/slides_agent/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  160. package/slides_agent/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  161. package/slides_agent/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  162. package/slides_agent/pptx/ooxml/scripts/pack.py +169 -0
  163. package/slides_agent/pptx/ooxml/scripts/unpack.py +29 -0
  164. package/slides_agent/pptx/ooxml/scripts/validate.py +69 -0
  165. package/slides_agent/pptx/ooxml/scripts/validation/__init__.py +15 -0
  166. package/slides_agent/pptx/ooxml/scripts/validation/base.py +951 -0
  167. package/slides_agent/pptx/ooxml/scripts/validation/docx.py +274 -0
  168. package/slides_agent/pptx/ooxml/scripts/validation/pptx.py +315 -0
  169. package/slides_agent/pptx/ooxml/scripts/validation/redlining.py +279 -0
  170. package/slides_agent/pptx/ooxml.md +427 -0
  171. package/slides_agent/pptx/scripts/html2pptx.js +1092 -0
  172. package/slides_agent/pptx/scripts/inventory.py +1020 -0
  173. package/slides_agent/pptx/scripts/rearrange.py +231 -0
  174. package/slides_agent/pptx/scripts/replace.py +385 -0
  175. package/slides_agent/pptx/scripts/thumbnail.py +451 -0
  176. package/slides_agent/slides_agent.py +109 -0
  177. package/slides_agent/test_deck/_theme.css +92 -0
  178. package/slides_agent/test_deck/assets/placeholder.svg +11 -0
  179. package/slides_agent/test_deck/slide_01_title.html +10 -0
  180. package/slides_agent/test_deck/slide_02_image_split.html +23 -0
  181. package/slides_agent/test_deck/slide_03_kpi.html +21 -0
  182. package/slides_agent/tools/ApplyPptxTextReplacements.py +91 -0
  183. package/slides_agent/tools/BuildPptxFromHtmlSlides.py +221 -0
  184. package/slides_agent/tools/CheckSlide.py +218 -0
  185. package/slides_agent/tools/CheckSlideCanvasOverflow.py +221 -0
  186. package/slides_agent/tools/CreateImageMontage.py +261 -0
  187. package/slides_agent/tools/CreatePptxThumbnailGrid.py +168 -0
  188. package/slides_agent/tools/DeleteSlide.py +78 -0
  189. package/slides_agent/tools/DownloadImage.py +79 -0
  190. package/slides_agent/tools/EnsureRasterImage.py +157 -0
  191. package/slides_agent/tools/ExtractPptxTextInventory.py +104 -0
  192. package/slides_agent/tools/GenerateImage.py +189 -0
  193. package/slides_agent/tools/ImageSearch.py +127 -0
  194. package/slides_agent/tools/InsertNewSlides.py +393 -0
  195. package/slides_agent/tools/ManageTheme.py +112 -0
  196. package/slides_agent/tools/ModifySlide.py +563 -0
  197. package/slides_agent/tools/ReadSlide.py +26 -0
  198. package/slides_agent/tools/RearrangePptxSlidesFromTemplate.py +114 -0
  199. package/slides_agent/tools/RestoreSnapshot.py +89 -0
  200. package/slides_agent/tools/SlideScreenshot.py +66 -0
  201. package/slides_agent/tools/__init__.py +54 -0
  202. package/slides_agent/tools/__pycache__/ApplyPptxTextReplacements.cpython-312.pyc +0 -0
  203. package/slides_agent/tools/__pycache__/BuildPptxFromHtmlSlides.cpython-312.pyc +0 -0
  204. package/slides_agent/tools/__pycache__/CheckSlide.cpython-312.pyc +0 -0
  205. package/slides_agent/tools/__pycache__/CheckSlideCanvasOverflow.cpython-312.pyc +0 -0
  206. package/slides_agent/tools/__pycache__/CreateImageMontage.cpython-312.pyc +0 -0
  207. package/slides_agent/tools/__pycache__/CreatePptxThumbnailGrid.cpython-312.pyc +0 -0
  208. package/slides_agent/tools/__pycache__/DeleteSlide.cpython-312.pyc +0 -0
  209. package/slides_agent/tools/__pycache__/DownloadImage.cpython-312.pyc +0 -0
  210. package/slides_agent/tools/__pycache__/EnsureRasterImage.cpython-312.pyc +0 -0
  211. package/slides_agent/tools/__pycache__/ExtractPptxTextInventory.cpython-312.pyc +0 -0
  212. package/slides_agent/tools/__pycache__/GenerateImage.cpython-312.pyc +0 -0
  213. package/slides_agent/tools/__pycache__/ImageSearch.cpython-312.pyc +0 -0
  214. package/slides_agent/tools/__pycache__/InsertNewSlides.cpython-312.pyc +0 -0
  215. package/slides_agent/tools/__pycache__/ManageTheme.cpython-312.pyc +0 -0
  216. package/slides_agent/tools/__pycache__/ModifySlide.cpython-312.pyc +0 -0
  217. package/slides_agent/tools/__pycache__/ReadSlide.cpython-312.pyc +0 -0
  218. package/slides_agent/tools/__pycache__/RearrangePptxSlidesFromTemplate.cpython-312.pyc +0 -0
  219. package/slides_agent/tools/__pycache__/RestoreSnapshot.cpython-312.pyc +0 -0
  220. package/slides_agent/tools/__pycache__/SlideScreenshot.cpython-312.pyc +0 -0
  221. package/slides_agent/tools/__pycache__/__init__.cpython-312.pyc +0 -0
  222. package/slides_agent/tools/__pycache__/slide_file_utils.cpython-312.pyc +0 -0
  223. package/slides_agent/tools/__pycache__/slide_html_utils.cpython-312.pyc +0 -0
  224. package/slides_agent/tools/__pycache__/template_registry.cpython-312.pyc +0 -0
  225. package/slides_agent/tools/deck_utils.py +31 -0
  226. package/slides_agent/tools/html2pptx_runner.js +1183 -0
  227. package/slides_agent/tools/html_writer_instructions.md +149 -0
  228. package/slides_agent/tools/slide_file_utils.py +108 -0
  229. package/slides_agent/tools/slide_html_utils.py +354 -0
  230. package/slides_agent/tools/template_registry.py +55 -0
  231. package/swarm.py +82 -0
  232. package/video_generation_agent/__init__.py +1 -0
  233. package/video_generation_agent/__pycache__/__init__.cpython-312.pyc +0 -0
  234. package/video_generation_agent/__pycache__/video_generation_agent.cpython-312.pyc +0 -0
  235. package/video_generation_agent/instructions.md +178 -0
  236. package/video_generation_agent/tools/AddSubtitles.py +425 -0
  237. package/video_generation_agent/tools/CombineImages.py +166 -0
  238. package/video_generation_agent/tools/CombineVideos.py +113 -0
  239. package/video_generation_agent/tools/EditAudio.py +297 -0
  240. package/video_generation_agent/tools/EditImage.py +144 -0
  241. package/video_generation_agent/tools/EditVideoContent.py +369 -0
  242. package/video_generation_agent/tools/GenerateImage.py +133 -0
  243. package/video_generation_agent/tools/GenerateVideo.py +556 -0
  244. package/video_generation_agent/tools/TrimVideo.py +233 -0
  245. package/video_generation_agent/tools/__init__.py +1 -0
  246. package/video_generation_agent/tools/__pycache__/AddSubtitles.cpython-312.pyc +0 -0
  247. package/video_generation_agent/tools/__pycache__/CombineImages.cpython-312.pyc +0 -0
  248. package/video_generation_agent/tools/__pycache__/CombineVideos.cpython-312.pyc +0 -0
  249. package/video_generation_agent/tools/__pycache__/EditAudio.cpython-312.pyc +0 -0
  250. package/video_generation_agent/tools/__pycache__/EditImage.cpython-312.pyc +0 -0
  251. package/video_generation_agent/tools/__pycache__/EditVideoContent.cpython-312.pyc +0 -0
  252. package/video_generation_agent/tools/__pycache__/GenerateImage.cpython-312.pyc +0 -0
  253. package/video_generation_agent/tools/__pycache__/GenerateVideo.cpython-312.pyc +0 -0
  254. package/video_generation_agent/tools/__pycache__/TrimVideo.cpython-312.pyc +0 -0
  255. package/video_generation_agent/tools/utils/__init__.py +1 -0
  256. package/video_generation_agent/tools/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  257. package/video_generation_agent/tools/utils/__pycache__/image_utils.cpython-312.pyc +0 -0
  258. package/video_generation_agent/tools/utils/__pycache__/video_utils.cpython-312.pyc +0 -0
  259. package/video_generation_agent/tools/utils/image_utils.py +174 -0
  260. package/video_generation_agent/tools/utils/video_utils.py +522 -0
  261. package/video_generation_agent/video_generation_agent.py +26 -0
  262. package/virtual_assistant/__init__.py +1 -0
  263. package/virtual_assistant/__pycache__/__init__.cpython-312.pyc +0 -0
  264. package/virtual_assistant/__pycache__/virtual_assistant.cpython-312.pyc +0 -0
  265. package/virtual_assistant/instructions.md +206 -0
  266. package/virtual_assistant/tools/AddLabelToEmail.py +154 -0
  267. package/virtual_assistant/tools/CheckEventsForDate.py +218 -0
  268. package/virtual_assistant/tools/CheckUnreadSlackMessages.py +216 -0
  269. package/virtual_assistant/tools/CreateCalendarEvent.py +261 -0
  270. package/virtual_assistant/tools/DeleteCalendarEvent.py +137 -0
  271. package/virtual_assistant/tools/DeleteDraft.py +95 -0
  272. package/virtual_assistant/tools/DraftEmail.py +239 -0
  273. package/virtual_assistant/tools/EditFile.py +113 -0
  274. package/virtual_assistant/tools/FindEmails.py +330 -0
  275. package/virtual_assistant/tools/GetCurrentTime.py +69 -0
  276. package/virtual_assistant/tools/GetSlackUserInfo.py +117 -0
  277. package/virtual_assistant/tools/ListDirectory.py +113 -0
  278. package/virtual_assistant/tools/ListSkills.py +94 -0
  279. package/virtual_assistant/tools/ManageLabels.py +295 -0
  280. package/virtual_assistant/tools/ProductSearch.py +254 -0
  281. package/virtual_assistant/tools/ReadEmail.py +251 -0
  282. package/virtual_assistant/tools/ReadFile.py +108 -0
  283. package/virtual_assistant/tools/ReadSlackMessages.py +191 -0
  284. package/virtual_assistant/tools/RemoveLabelFromEmail.py +137 -0
  285. package/virtual_assistant/tools/RescheduleCalendarEvent.py +227 -0
  286. package/virtual_assistant/tools/ScholarSearch.py +216 -0
  287. package/virtual_assistant/tools/SendDraft.py +101 -0
  288. package/virtual_assistant/tools/SendSlackMessage.py +148 -0
  289. package/virtual_assistant/tools/WriteFile.py +95 -0
  290. package/virtual_assistant/tools/__init__.py +1 -0
  291. package/virtual_assistant/tools/__pycache__/AddLabelToEmail.cpython-312.pyc +0 -0
  292. package/virtual_assistant/tools/__pycache__/CheckEventsForDate.cpython-312.pyc +0 -0
  293. package/virtual_assistant/tools/__pycache__/CheckUnreadSlackMessages.cpython-312.pyc +0 -0
  294. package/virtual_assistant/tools/__pycache__/CreateCalendarEvent.cpython-312.pyc +0 -0
  295. package/virtual_assistant/tools/__pycache__/DeleteCalendarEvent.cpython-312.pyc +0 -0
  296. package/virtual_assistant/tools/__pycache__/DeleteDraft.cpython-312.pyc +0 -0
  297. package/virtual_assistant/tools/__pycache__/DraftEmail.cpython-312.pyc +0 -0
  298. package/virtual_assistant/tools/__pycache__/EditFile.cpython-312.pyc +0 -0
  299. package/virtual_assistant/tools/__pycache__/FindEmails.cpython-312.pyc +0 -0
  300. package/virtual_assistant/tools/__pycache__/GetCurrentTime.cpython-312.pyc +0 -0
  301. package/virtual_assistant/tools/__pycache__/GetSlackUserInfo.cpython-312.pyc +0 -0
  302. package/virtual_assistant/tools/__pycache__/ListDirectory.cpython-312.pyc +0 -0
  303. package/virtual_assistant/tools/__pycache__/ListSkills.cpython-312.pyc +0 -0
  304. package/virtual_assistant/tools/__pycache__/ManageLabels.cpython-312.pyc +0 -0
  305. package/virtual_assistant/tools/__pycache__/ProductSearch.cpython-312.pyc +0 -0
  306. package/virtual_assistant/tools/__pycache__/ReadEmail.cpython-312.pyc +0 -0
  307. package/virtual_assistant/tools/__pycache__/ReadFile.cpython-312.pyc +0 -0
  308. package/virtual_assistant/tools/__pycache__/ReadSlackMessages.cpython-312.pyc +0 -0
  309. package/virtual_assistant/tools/__pycache__/RemoveLabelFromEmail.cpython-312.pyc +0 -0
  310. package/virtual_assistant/tools/__pycache__/RescheduleCalendarEvent.cpython-312.pyc +0 -0
  311. package/virtual_assistant/tools/__pycache__/ScholarSearch.cpython-312.pyc +0 -0
  312. package/virtual_assistant/tools/__pycache__/SendDraft.cpython-312.pyc +0 -0
  313. package/virtual_assistant/tools/__pycache__/SendSlackMessage.cpython-312.pyc +0 -0
  314. package/virtual_assistant/tools/__pycache__/WriteFile.cpython-312.pyc +0 -0
  315. package/virtual_assistant/tools/__pycache__/__init__.cpython-312.pyc +0 -0
  316. 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
+