@_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,185 @@
1
+ from typing import Dict, Optional, Tuple
2
+
3
+ from docx import Document
4
+ from docx.enum.section import WD_ORIENT
5
+ from docx.oxml import OxmlElement
6
+ from docx.oxml.ns import qn
7
+ from docx.shared import Pt
8
+
9
+ from .html_docx_constants import _PAGE_SIZES_PT
10
+ from .html_docx_css import _parse_background_color, _parse_float, _parse_length_to_pt
11
+
12
+ _DEFAULT_DOCX_MARGIN_PT = 72.0
13
+
14
+
15
+ def _apply_page_settings(doc: Document, html_content: str) -> None:
16
+ page_css = _extract_page_css(html_content)
17
+ margins_pt = _extract_page_margin_box_pt(page_css)
18
+ page_size = _extract_page_size_pt(page_css)
19
+ for section in doc.sections:
20
+ if page_size:
21
+ width_pt, height_pt, is_landscape = page_size
22
+ if is_landscape:
23
+ section.orientation = WD_ORIENT.LANDSCAPE
24
+ section.page_width = Pt(width_pt)
25
+ section.page_height = Pt(height_pt)
26
+ elif "landscape" in page_css and section.orientation != WD_ORIENT.LANDSCAPE:
27
+ section.orientation = WD_ORIENT.LANDSCAPE
28
+ section.page_width, section.page_height = (
29
+ section.page_height,
30
+ section.page_width,
31
+ )
32
+ if margins_pt is not None:
33
+ top, right, bottom, left = margins_pt
34
+ if top is not None:
35
+ section.top_margin = Pt(top)
36
+ if right is not None:
37
+ section.right_margin = Pt(right)
38
+ if bottom is not None:
39
+ section.bottom_margin = Pt(bottom)
40
+ if left is not None:
41
+ section.left_margin = Pt(left)
42
+
43
+
44
+ def _apply_page_background(doc: Document, body_style: Dict[str, str]) -> None:
45
+ bg_color = _parse_background_color(body_style)
46
+ if not bg_color:
47
+ return
48
+ doc_element = doc._part._element
49
+ background = doc_element.find(qn("w:background"))
50
+ if background is None:
51
+ background = OxmlElement("w:background")
52
+ doc_element.insert(0, background)
53
+ background.set(qn("w:color"), bg_color)
54
+
55
+
56
+ def _ensure_display_background_shape(doc: Document) -> None:
57
+ settings = doc._part.settings._element
58
+ existing = settings.find(qn("w:displayBackgroundShape"))
59
+ if existing is None:
60
+ elem = OxmlElement("w:displayBackgroundShape")
61
+ settings.append(elem)
62
+
63
+
64
+ def _extract_page_css(html_content: str) -> str:
65
+ lower = html_content.lower()
66
+ start = lower.find("@page")
67
+ if start == -1:
68
+ return ""
69
+ block_start = lower.find("{", start)
70
+ if block_start == -1:
71
+ return ""
72
+ block_end = lower.find("}", block_start)
73
+ if block_end == -1:
74
+ return ""
75
+ return lower[block_start + 1:block_end]
76
+
77
+
78
+ def _extract_page_margin_box_pt(
79
+ page_css: str,
80
+ ) -> Optional[Tuple[Optional[float], Optional[float], Optional[float], Optional[float]]]:
81
+ top = right = bottom = left = None
82
+ shorthand: Optional[Tuple[float, float, float, float]] = None
83
+
84
+ for rule in page_css.split(";"):
85
+ if ":" not in rule:
86
+ continue
87
+ key, value = [part.strip() for part in rule.split(":", 1)]
88
+ if key == "margin":
89
+ shorthand = _parse_margin_shorthand_pt(value)
90
+ elif key == "margin-top":
91
+ top = _parse_length_to_pt(value)
92
+ elif key == "margin-right":
93
+ right = _parse_length_to_pt(value)
94
+ elif key == "margin-bottom":
95
+ bottom = _parse_length_to_pt(value)
96
+ elif key == "margin-left":
97
+ left = _parse_length_to_pt(value)
98
+
99
+ if shorthand is not None:
100
+ s_top, s_right, s_bottom, s_left = shorthand
101
+ top = top if top is not None else s_top
102
+ right = right if right is not None else s_right
103
+ bottom = bottom if bottom is not None else s_bottom
104
+ left = left if left is not None else s_left
105
+
106
+ if all(value is None for value in (top, right, bottom, left)):
107
+ return None
108
+ return top, right, bottom, left
109
+
110
+
111
+ def _parse_margin_shorthand_pt(value: str) -> Optional[Tuple[float, float, float, float]]:
112
+ parts = [part for part in value.replace(",", " ").split() if part]
113
+ if not parts:
114
+ return None
115
+
116
+ parsed = [_parse_length_to_pt(part) for part in parts]
117
+ if any(part is None for part in parsed):
118
+ return None
119
+
120
+ values = [float(part) for part in parsed if part is not None]
121
+ if len(values) == 1:
122
+ return values[0], values[0], values[0], values[0]
123
+ if len(values) == 2:
124
+ return values[0], values[1], values[0], values[1]
125
+ if len(values) == 3:
126
+ return values[0], values[1], values[2], values[1]
127
+ return values[0], values[1], values[2], values[3]
128
+
129
+
130
+ def _extract_page_geometry_pt(
131
+ html_content: str,
132
+ ) -> Tuple[float, float, float, float, float, float]:
133
+ page_css = _extract_page_css(html_content)
134
+ page_size = _extract_page_size_pt(page_css)
135
+ if page_size is None:
136
+ width_pt, height_pt = _PAGE_SIZES_PT["a4"]
137
+ else:
138
+ width_pt, height_pt, _is_landscape = page_size
139
+
140
+ margins_pt = _extract_page_margin_box_pt(page_css)
141
+ if margins_pt is None:
142
+ return (
143
+ width_pt,
144
+ height_pt,
145
+ _DEFAULT_DOCX_MARGIN_PT,
146
+ _DEFAULT_DOCX_MARGIN_PT,
147
+ _DEFAULT_DOCX_MARGIN_PT,
148
+ _DEFAULT_DOCX_MARGIN_PT,
149
+ )
150
+
151
+ top, right, bottom, left = margins_pt
152
+ return (
153
+ width_pt,
154
+ height_pt,
155
+ top if top is not None else _DEFAULT_DOCX_MARGIN_PT,
156
+ right if right is not None else _DEFAULT_DOCX_MARGIN_PT,
157
+ bottom if bottom is not None else _DEFAULT_DOCX_MARGIN_PT,
158
+ left if left is not None else _DEFAULT_DOCX_MARGIN_PT,
159
+ )
160
+
161
+
162
+ def _extract_page_size_pt(page_css: str) -> Optional[Tuple[float, float, bool]]:
163
+ if "size" not in page_css:
164
+ return None
165
+ for rule in page_css.split(";"):
166
+ if "size" not in rule:
167
+ continue
168
+ key, value = [part.strip() for part in rule.split(":", 1)]
169
+ if key != "size":
170
+ continue
171
+ tokens = [token.strip().lower() for token in value.split() if token.strip()]
172
+ if not tokens:
173
+ return None
174
+ size_token = next((token for token in tokens if token in _PAGE_SIZES_PT), None)
175
+ if not size_token:
176
+ return None
177
+ width_pt, height_pt = _PAGE_SIZES_PT[size_token]
178
+ is_landscape = "landscape" in tokens
179
+ is_portrait = "portrait" in tokens
180
+ if is_landscape and width_pt < height_pt:
181
+ width_pt, height_pt = height_pt, width_pt
182
+ if is_portrait and width_pt > height_pt:
183
+ width_pt, height_pt = height_pt, width_pt
184
+ return width_pt, height_pt, is_landscape
185
+ return None
@@ -0,0 +1,342 @@
1
+ from typing import Dict
2
+
3
+ from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING
4
+ from docx.oxml import OxmlElement
5
+ from docx.oxml.ns import qn
6
+ from docx.shared import Pt
7
+
8
+ from .html_docx_constants import (
9
+ _LIST_BASE_HANGING_TWIPS,
10
+ _LIST_BASE_LEFT_TWIPS,
11
+ _NAMED_COLORS,
12
+ _PADDING_SCALE,
13
+ )
14
+ from .html_docx_css import (
15
+ _border_sz,
16
+ _normalize_font_family,
17
+ _parse_background_color,
18
+ _parse_border_left,
19
+ _parse_box_values,
20
+ _parse_color,
21
+ _parse_float,
22
+ _parse_font_size_pt,
23
+ _parse_length_to_pt,
24
+ _parse_padding,
25
+ _parse_px_to_pt,
26
+ )
27
+
28
+
29
+ def _apply_paragraph_style(paragraph, style_map: Dict[str, str]) -> None:
30
+ alignment = style_map.get("text-align", "").lower()
31
+ if alignment == "left":
32
+ paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
33
+ elif alignment == "center":
34
+ paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
35
+ elif alignment == "right":
36
+ paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
37
+ elif alignment == "justify":
38
+ paragraph.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
39
+
40
+ _apply_paragraph_spacing(paragraph, style_map)
41
+ _apply_paragraph_borders(paragraph, style_map)
42
+ _apply_paragraph_container_styles(paragraph, style_map)
43
+ _apply_paragraph_line_height(paragraph, style_map)
44
+
45
+
46
+ def _apply_run_style(run, style_map: Dict[str, str]) -> None:
47
+ font_family = style_map.get("font-family")
48
+ if font_family:
49
+ _set_run_font(run, _normalize_font_family(font_family))
50
+
51
+ font_size = style_map.get("font-size")
52
+ if font_size:
53
+ size_pt = _parse_font_size_pt(font_size)
54
+ if size_pt is not None:
55
+ run.font.size = Pt(size_pt)
56
+
57
+ color = style_map.get("color")
58
+ if color:
59
+ rgb = _parse_color(color)
60
+ if rgb is not None:
61
+ run.font.color.rgb = rgb
62
+
63
+ font_weight = style_map.get("font-weight", "").strip().lower()
64
+ if font_weight in {"bold", "bolder"}:
65
+ run.font.bold = True
66
+ else:
67
+ weight = _parse_float(font_weight) if font_weight else None
68
+ if weight is not None and weight >= 600:
69
+ run.font.bold = True
70
+
71
+ font_style = style_map.get("font-style", "").strip().lower()
72
+ if font_style == "italic":
73
+ run.font.italic = True
74
+
75
+ text_decoration = style_map.get("text-decoration", "").strip().lower()
76
+ if "underline" in text_decoration:
77
+ run.font.underline = True
78
+
79
+ letter_spacing = style_map.get("letter-spacing", "").strip().lower()
80
+ if letter_spacing:
81
+ spacing_pt = _parse_px_to_pt(letter_spacing)
82
+ if spacing_pt is not None:
83
+ r_pr = run._r.get_or_add_rPr()
84
+ spacing = r_pr.find(qn("w:spacing"))
85
+ if spacing is None:
86
+ spacing = OxmlElement("w:spacing")
87
+ r_pr.append(spacing)
88
+ spacing.set(qn("w:val"), str(int(spacing_pt * 20)))
89
+
90
+
91
+ def _set_run_font(run, font_name: str) -> None:
92
+ run.font.name = font_name
93
+ r_pr = run._r.get_or_add_rPr()
94
+ r_fonts = r_pr.find(qn("w:rFonts"))
95
+ if r_fonts is None:
96
+ r_fonts = OxmlElement("w:rFonts")
97
+ r_pr.append(r_fonts)
98
+ r_fonts.set(qn("w:ascii"), font_name)
99
+ r_fonts.set(qn("w:hAnsi"), font_name)
100
+ r_fonts.set(qn("w:cs"), font_name)
101
+ r_fonts.set(qn("w:eastAsia"), font_name)
102
+
103
+
104
+ def _apply_paragraph_container_styles(paragraph, style_map: Dict[str, str]) -> None:
105
+ bg_color = _parse_background_color(style_map)
106
+ if bg_color:
107
+ p_pr = paragraph._p.get_or_add_pPr()
108
+ shd = p_pr.find(qn("w:shd"))
109
+ if shd is None:
110
+ shd = OxmlElement("w:shd")
111
+ p_pr.append(shd)
112
+ shd.set(qn("w:val"), "clear")
113
+ shd.set(qn("w:color"), "auto")
114
+ shd.set(qn("w:fill"), bg_color)
115
+
116
+ border_left = _parse_border_left(style_map)
117
+ if border_left:
118
+ width_pt, color = border_left
119
+ p_pr = paragraph._p.get_or_add_pPr()
120
+ p_bdr = p_pr.find(qn("w:pBdr"))
121
+ if p_bdr is None:
122
+ p_bdr = OxmlElement("w:pBdr")
123
+ p_pr.append(p_bdr)
124
+ left = OxmlElement("w:left")
125
+ left.set(qn("w:val"), "single")
126
+ left.set(qn("w:sz"), _border_sz(width_pt))
127
+ left.set(qn("w:color"), color)
128
+ p_bdr.append(left)
129
+
130
+ padding = _parse_padding(style_map.get("padding", ""))
131
+ if padding:
132
+ top, right, bottom, left = padding
133
+ if left:
134
+ paragraph.paragraph_format.left_indent = Pt(left * _PADDING_SCALE)
135
+ if right:
136
+ paragraph.paragraph_format.right_indent = Pt(right * _PADDING_SCALE)
137
+
138
+
139
+ def _apply_paragraph_line_height(paragraph, style_map: Dict[str, str]) -> None:
140
+ line_height = style_map.get("line-height", "").strip().lower()
141
+ if not line_height:
142
+ # Spacer-div pattern: <div style="height: Xpt"> with no other content.
143
+ # Convert the height to an exact line-height so the paragraph takes up
144
+ # the intended vertical space. Zero values are the divider pattern
145
+ # (<div style="height: 0pt; border-top: ...">), which should keep default
146
+ # spacing so the border renders correctly.
147
+ height_str = style_map.get("height", "").strip().lower()
148
+ if height_str:
149
+ height_pt = _parse_length_to_pt(height_str)
150
+ if height_pt:
151
+ paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.EXACTLY
152
+ paragraph.paragraph_format.line_spacing = Pt(height_pt)
153
+ return
154
+ paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.SINGLE
155
+ paragraph.paragraph_format.line_spacing = 1
156
+ return
157
+ if line_height.endswith("px") or line_height.endswith("pt"):
158
+ height_pt = _parse_px_to_pt(line_height)
159
+ if height_pt is not None:
160
+ paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.EXACTLY
161
+ paragraph.paragraph_format.line_spacing = Pt(height_pt)
162
+ return
163
+ value = _parse_float(line_height)
164
+ if value:
165
+ paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE
166
+ paragraph.paragraph_format.line_spacing = value
167
+
168
+
169
+ def _apply_paragraph_spacing(paragraph, style_map: Dict[str, str]) -> None:
170
+ paragraph.paragraph_format.space_before = Pt(0)
171
+ paragraph.paragraph_format.space_after = Pt(0)
172
+
173
+ margin = _parse_box_values(style_map.get("margin", ""))
174
+ margin_top = _parse_px_to_pt(style_map.get("margin-top", ""))
175
+ margin_bottom = _parse_px_to_pt(style_map.get("margin-bottom", ""))
176
+
177
+ if margin:
178
+ top, _, bottom, _ = margin
179
+ if top is not None:
180
+ paragraph.paragraph_format.space_before = Pt(top)
181
+ if bottom is not None:
182
+ paragraph.paragraph_format.space_after = Pt(bottom)
183
+
184
+ if margin_top is not None:
185
+ paragraph.paragraph_format.space_before = Pt(margin_top)
186
+ if margin_bottom is not None:
187
+ paragraph.paragraph_format.space_after = Pt(margin_bottom)
188
+
189
+
190
+ def _apply_paragraph_borders(paragraph, style_map: Dict[str, str]) -> None:
191
+ top = _parse_paragraph_border(style_map.get("border-top", ""))
192
+ bottom = _parse_paragraph_border(style_map.get("border-bottom", ""))
193
+ if not top and not bottom:
194
+ return
195
+
196
+ p_pr = paragraph._p.get_or_add_pPr()
197
+ p_bdr = p_pr.find(qn("w:pBdr"))
198
+ if p_bdr is None:
199
+ p_bdr = OxmlElement("w:pBdr")
200
+ p_pr.append(p_bdr)
201
+
202
+ if top:
203
+ width_pt, color = top
204
+ elem = OxmlElement("w:top")
205
+ elem.set(qn("w:val"), "single")
206
+ elem.set(qn("w:sz"), _border_sz(width_pt))
207
+ elem.set(qn("w:color"), color)
208
+ p_bdr.append(elem)
209
+ if bottom:
210
+ width_pt, color = bottom
211
+ elem = OxmlElement("w:bottom")
212
+ elem.set(qn("w:val"), "single")
213
+ elem.set(qn("w:sz"), _border_sz(width_pt))
214
+ elem.set(qn("w:color"), color)
215
+ p_bdr.append(elem)
216
+
217
+
218
+ def _parse_paragraph_border(border: str):
219
+ if not border:
220
+ return None
221
+ parts = border.split()
222
+ width_pt = _parse_px_to_pt(parts[0]) if parts else None
223
+ color = None
224
+ for part in parts:
225
+ if part.startswith("#"):
226
+ color = part[1:].upper()
227
+ break
228
+ if part.lower() in _NAMED_COLORS:
229
+ r, g, b = _NAMED_COLORS[part.lower()]
230
+ color = f"{r:02X}{g:02X}{b:02X}"
231
+ break
232
+ if width_pt and color:
233
+ return width_pt, color
234
+ return None
235
+
236
+
237
+ def _add_paragraph_spacing(paragraph, before_pt: float = 0, after_pt: float = 0) -> None:
238
+ pf = paragraph.paragraph_format
239
+ if before_pt:
240
+ current = pf.space_before.pt if pf.space_before else 0
241
+ pf.space_before = Pt(current + before_pt)
242
+ if after_pt:
243
+ current = pf.space_after.pt if pf.space_after else 0
244
+ pf.space_after = Pt(current + after_pt)
245
+
246
+
247
+ def _add_paragraph_indent(paragraph, left_pt: float = 0, right_pt: float = 0) -> None:
248
+ pf = paragraph.paragraph_format
249
+ if left_pt:
250
+ current = pf.left_indent.pt if pf.left_indent else 0
251
+ pf.left_indent = Pt(current + left_pt)
252
+ if right_pt:
253
+ current = pf.right_indent.pt if pf.right_indent else 0
254
+ pf.right_indent = Pt(current + right_pt)
255
+
256
+
257
+ def _add_list_indent_padding(paragraph, left_pt: float = 0, right_pt: float = 0) -> None:
258
+ p_pr = paragraph._p.get_or_add_pPr()
259
+ ind = p_pr.find(qn("w:ind"))
260
+ if ind is None:
261
+ ind = OxmlElement("w:ind")
262
+ p_pr.append(ind)
263
+ if left_pt:
264
+ current = ind.get(qn("w:left"))
265
+ if current and current.isdigit():
266
+ current_val = int(current)
267
+ else:
268
+ current_val = _LIST_BASE_LEFT_TWIPS
269
+ ind.set(qn("w:left"), str(current_val + int(left_pt * 20)))
270
+ if ind.get(qn("w:hanging")) is None:
271
+ ind.set(qn("w:hanging"), str(_LIST_BASE_HANGING_TWIPS))
272
+ if right_pt:
273
+ current = ind.get(qn("w:right"))
274
+ current_val = int(current) if current and current.isdigit() else 0
275
+ ind.set(qn("w:right"), str(current_val + int(right_pt * 20)))
276
+
277
+
278
+ def _apply_ul_margin_indent(paragraph, additional_left_pt: float) -> None:
279
+ """Shift a list item right by the parent <ul> margin-left.
280
+
281
+ When a <ul> has margin-left: X, the entire list must shift X pt to the right.
282
+ We add X to w:ind w:left while explicitly preserving w:hanging so the bullet
283
+ character and text-start gap are kept intact (paragraph-level w:ind overrides
284
+ the abstractNum's w:ind entirely, so we must carry both values).
285
+ """
286
+ if not additional_left_pt:
287
+ return
288
+ p_pr = paragraph._p.get_or_add_pPr()
289
+ ind = p_pr.find(qn("w:ind"))
290
+ if ind is None:
291
+ ind = OxmlElement("w:ind")
292
+ p_pr.append(ind)
293
+ current_left = ind.get(qn("w:left"))
294
+ base_left = int(current_left) if current_left and current_left.isdigit() else _LIST_BASE_LEFT_TWIPS
295
+ current_hanging = ind.get(qn("w:hanging"))
296
+ base_hanging = int(current_hanging) if current_hanging and current_hanging.isdigit() else _LIST_BASE_HANGING_TWIPS
297
+ ind.set(qn("w:left"), str(base_left + int(additional_left_pt * 20)))
298
+ ind.set(qn("w:hanging"), str(base_hanging))
299
+
300
+
301
+ def _apply_list_indent(paragraph, indent_pt: float) -> None:
302
+ _set_list_indent_xml(paragraph, indent_pt)
303
+
304
+
305
+ def _set_list_indent_xml(paragraph, indent_pt: float) -> None:
306
+ p_pr = paragraph._p.get_or_add_pPr()
307
+ ind = p_pr.find(qn("w:ind"))
308
+ if ind is None:
309
+ ind = OxmlElement("w:ind")
310
+ p_pr.append(ind)
311
+ left_twips = ind.get(qn("w:left"))
312
+ if left_twips and left_twips.isdigit():
313
+ base_left = int(left_twips)
314
+ else:
315
+ base_left = _LIST_BASE_LEFT_TWIPS
316
+ ind.set(qn("w:left"), str(base_left + int(indent_pt * 20)))
317
+ if ind.get(qn("w:hanging")) is None:
318
+ ind.set(qn("w:hanging"), str(_LIST_BASE_HANGING_TWIPS))
319
+
320
+
321
+ def _resolve_list_indent_pt(parent_style: Dict[str, str]) -> float:
322
+ margin_left = parent_style.get("margin-left", "")
323
+ if margin_left:
324
+ value = _parse_length_to_pt(margin_left)
325
+ if value:
326
+ return value
327
+ margin = parent_style.get("margin", "")
328
+ if margin:
329
+ values = _parse_padding(margin)
330
+ if values:
331
+ return values[3]
332
+ padding_left = parent_style.get("padding-left", "")
333
+ if padding_left:
334
+ value = _parse_length_to_pt(padding_left)
335
+ if value:
336
+ return value
337
+ padding = parent_style.get("padding", "")
338
+ if padding:
339
+ values = _parse_padding(padding)
340
+ if values:
341
+ return values[3]
342
+ return 0.0