docagent-cli 0.0.35__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docagent_cli/__init__.py +36 -0
- docagent_cli/__main__.py +6 -0
- docagent_cli/_ask_user_types.py +90 -0
- docagent_cli/_cli_context.py +27 -0
- docagent_cli/_debug.py +52 -0
- docagent_cli/_env_vars.py +56 -0
- docagent_cli/_server_config.py +352 -0
- docagent_cli/_session_stats.py +114 -0
- docagent_cli/_testing_models.py +144 -0
- docagent_cli/_version.py +17 -0
- docagent_cli/agent.py +1193 -0
- docagent_cli/app.py +4979 -0
- docagent_cli/app.tcss +283 -0
- docagent_cli/ask_user.py +301 -0
- docagent_cli/built_in_skills/__init__.py +5 -0
- docagent_cli/built_in_skills/doc-coauthoring/SKILL.md +375 -0
- docagent_cli/built_in_skills/docx/LICENSE.txt +30 -0
- docagent_cli/built_in_skills/docx/SKILL.md +590 -0
- docagent_cli/built_in_skills/docx/scripts/__init__.py +1 -0
- docagent_cli/built_in_skills/docx/scripts/accept_changes.py +135 -0
- docagent_cli/built_in_skills/docx/scripts/comment.py +318 -0
- docagent_cli/built_in_skills/docx/scripts/office/helpers/__init__.py +0 -0
- docagent_cli/built_in_skills/docx/scripts/office/helpers/merge_runs.py +199 -0
- docagent_cli/built_in_skills/docx/scripts/office/helpers/simplify_redlines.py +197 -0
- docagent_cli/built_in_skills/docx/scripts/office/pack.py +159 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/mce/mc.xsd +75 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- docagent_cli/built_in_skills/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- docagent_cli/built_in_skills/docx/scripts/office/soffice.py +183 -0
- docagent_cli/built_in_skills/docx/scripts/office/unpack.py +132 -0
- docagent_cli/built_in_skills/docx/scripts/office/validate.py +111 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/__init__.py +15 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/base.py +847 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/docx.py +446 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/pptx.py +275 -0
- docagent_cli/built_in_skills/docx/scripts/office/validators/redlining.py +247 -0
- docagent_cli/built_in_skills/docx/scripts/templates/comments.xml +3 -0
- docagent_cli/built_in_skills/docx/scripts/templates/commentsExtended.xml +3 -0
- docagent_cli/built_in_skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- docagent_cli/built_in_skills/docx/scripts/templates/commentsIds.xml +3 -0
- docagent_cli/built_in_skills/docx/scripts/templates/people.xml +3 -0
- docagent_cli/built_in_skills/pdf/LICENSE.txt +30 -0
- docagent_cli/built_in_skills/pdf/SKILL.md +314 -0
- docagent_cli/built_in_skills/pdf/forms.md +294 -0
- docagent_cli/built_in_skills/pdf/reference.md +612 -0
- docagent_cli/built_in_skills/pdf/scripts/check_bounding_boxes.py +65 -0
- docagent_cli/built_in_skills/pdf/scripts/check_fillable_fields.py +11 -0
- docagent_cli/built_in_skills/pdf/scripts/convert_pdf_to_images.py +33 -0
- docagent_cli/built_in_skills/pdf/scripts/create_validation_image.py +37 -0
- docagent_cli/built_in_skills/pdf/scripts/extract_form_field_info.py +122 -0
- docagent_cli/built_in_skills/pdf/scripts/extract_form_structure.py +115 -0
- docagent_cli/built_in_skills/pdf/scripts/fill_fillable_fields.py +98 -0
- docagent_cli/built_in_skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
- docagent_cli/built_in_skills/pptx/LICENSE.txt +30 -0
- docagent_cli/built_in_skills/pptx/SKILL.md +232 -0
- docagent_cli/built_in_skills/pptx/editing.md +205 -0
- docagent_cli/built_in_skills/pptx/pptxgenjs.md +420 -0
- docagent_cli/built_in_skills/pptx/scripts/__init__.py +0 -0
- docagent_cli/built_in_skills/pptx/scripts/add_slide.py +195 -0
- docagent_cli/built_in_skills/pptx/scripts/clean.py +286 -0
- docagent_cli/built_in_skills/pptx/scripts/office/helpers/__init__.py +0 -0
- docagent_cli/built_in_skills/pptx/scripts/office/helpers/merge_runs.py +199 -0
- docagent_cli/built_in_skills/pptx/scripts/office/helpers/simplify_redlines.py +197 -0
- docagent_cli/built_in_skills/pptx/scripts/office/pack.py +159 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/mce/mc.xsd +75 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- docagent_cli/built_in_skills/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- docagent_cli/built_in_skills/pptx/scripts/office/soffice.py +183 -0
- docagent_cli/built_in_skills/pptx/scripts/office/unpack.py +132 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validate.py +111 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/__init__.py +15 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/base.py +847 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/docx.py +446 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/pptx.py +275 -0
- docagent_cli/built_in_skills/pptx/scripts/office/validators/redlining.py +247 -0
- docagent_cli/built_in_skills/pptx/scripts/thumbnail.py +289 -0
- docagent_cli/built_in_skills/remember/SKILL.md +118 -0
- docagent_cli/built_in_skills/skill-creator/LICENSE.txt +202 -0
- docagent_cli/built_in_skills/skill-creator/SKILL.md +485 -0
- docagent_cli/built_in_skills/skill-creator/agents/analyzer.md +274 -0
- docagent_cli/built_in_skills/skill-creator/agents/comparator.md +202 -0
- docagent_cli/built_in_skills/skill-creator/agents/grader.md +223 -0
- docagent_cli/built_in_skills/skill-creator/assets/eval_review.html +146 -0
- docagent_cli/built_in_skills/skill-creator/eval-viewer/generate_review.py +471 -0
- docagent_cli/built_in_skills/skill-creator/eval-viewer/viewer.html +1325 -0
- docagent_cli/built_in_skills/skill-creator/references/schemas.md +430 -0
- docagent_cli/built_in_skills/skill-creator/scripts/__init__.py +0 -0
- docagent_cli/built_in_skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- docagent_cli/built_in_skills/skill-creator/scripts/generate_report.py +326 -0
- docagent_cli/built_in_skills/skill-creator/scripts/improve_description.py +247 -0
- docagent_cli/built_in_skills/skill-creator/scripts/package_skill.py +136 -0
- docagent_cli/built_in_skills/skill-creator/scripts/quick_validate.py +103 -0
- docagent_cli/built_in_skills/skill-creator/scripts/run_eval.py +310 -0
- docagent_cli/built_in_skills/skill-creator/scripts/run_loop.py +328 -0
- docagent_cli/built_in_skills/skill-creator/scripts/utils.py +47 -0
- docagent_cli/built_in_skills/theme-factory/LICENSE.txt +202 -0
- docagent_cli/built_in_skills/theme-factory/SKILL.md +59 -0
- docagent_cli/built_in_skills/theme-factory/theme-showcase.pdf +0 -0
- docagent_cli/built_in_skills/theme-factory/themes/arctic-frost.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/botanical-garden.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/desert-rose.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/forest-canopy.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/golden-hour.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/midnight-galaxy.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/modern-minimalist.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/ocean-depths.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/sunset-boulevard.md +19 -0
- docagent_cli/built_in_skills/theme-factory/themes/tech-innovation.md +19 -0
- docagent_cli/built_in_skills/xlsx/LICENSE.txt +30 -0
- docagent_cli/built_in_skills/xlsx/SKILL.md +292 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/helpers/__init__.py +0 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/helpers/merge_runs.py +199 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/pack.py +159 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/soffice.py +183 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/unpack.py +132 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validate.py +111 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/__init__.py +15 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/base.py +847 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/docx.py +446 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/pptx.py +275 -0
- docagent_cli/built_in_skills/xlsx/scripts/office/validators/redlining.py +247 -0
- docagent_cli/built_in_skills/xlsx/scripts/recalc.py +184 -0
- docagent_cli/clipboard.py +128 -0
- docagent_cli/command_registry.py +284 -0
- docagent_cli/config.py +2418 -0
- docagent_cli/configurable_model.py +162 -0
- docagent_cli/default_agent_prompt.md +12 -0
- docagent_cli/editor.py +142 -0
- docagent_cli/file_ops.py +473 -0
- docagent_cli/formatting.py +28 -0
- docagent_cli/hooks.py +206 -0
- docagent_cli/input.py +787 -0
- docagent_cli/integrations/__init__.py +1 -0
- docagent_cli/integrations/sandbox_factory.py +873 -0
- docagent_cli/integrations/sandbox_provider.py +71 -0
- docagent_cli/local_context.py +718 -0
- docagent_cli/main.py +1641 -0
- docagent_cli/mcp_tools.py +707 -0
- docagent_cli/mcp_trust.py +168 -0
- docagent_cli/media_utils.py +478 -0
- docagent_cli/model_config.py +1620 -0
- docagent_cli/non_interactive.py +948 -0
- docagent_cli/offload.py +371 -0
- docagent_cli/output.py +69 -0
- docagent_cli/project_utils.py +188 -0
- docagent_cli/py.typed +0 -0
- docagent_cli/remote_client.py +515 -0
- docagent_cli/server.py +520 -0
- docagent_cli/server_graph.py +196 -0
- docagent_cli/server_manager.py +365 -0
- docagent_cli/sessions.py +1262 -0
- docagent_cli/skills/__init__.py +18 -0
- docagent_cli/skills/commands.py +1090 -0
- docagent_cli/skills/load.py +192 -0
- docagent_cli/subagents.py +173 -0
- docagent_cli/system_prompt.md +247 -0
- docagent_cli/textual_adapter.py +1352 -0
- docagent_cli/theme.py +842 -0
- docagent_cli/token_state.py +31 -0
- docagent_cli/tool_display.py +298 -0
- docagent_cli/tools.py +236 -0
- docagent_cli/ui.py +420 -0
- docagent_cli/unicode_security.py +516 -0
- docagent_cli/update_check.py +454 -0
- docagent_cli/widgets/__init__.py +9 -0
- docagent_cli/widgets/_links.py +63 -0
- docagent_cli/widgets/approval.py +442 -0
- docagent_cli/widgets/ask_user.py +398 -0
- docagent_cli/widgets/autocomplete.py +691 -0
- docagent_cli/widgets/chat_input.py +1827 -0
- docagent_cli/widgets/diff.py +248 -0
- docagent_cli/widgets/history.py +188 -0
- docagent_cli/widgets/loading.py +177 -0
- docagent_cli/widgets/mcp_viewer.py +362 -0
- docagent_cli/widgets/message_store.py +675 -0
- docagent_cli/widgets/messages.py +1751 -0
- docagent_cli/widgets/model_selector.py +964 -0
- docagent_cli/widgets/status.py +372 -0
- docagent_cli/widgets/theme_selector.py +164 -0
- docagent_cli/widgets/thread_selector.py +1905 -0
- docagent_cli/widgets/tool_renderers.py +148 -0
- docagent_cli/widgets/tool_widgets.py +274 -0
- docagent_cli/widgets/welcome.py +339 -0
- docagent_cli-0.0.35.data/data/docagent_cli/default_agent_prompt.md +12 -0
- docagent_cli-0.0.35.dist-info/METADATA +200 -0
- docagent_cli-0.0.35.dist-info/RECORD +300 -0
- docagent_cli-0.0.35.dist-info/WHEEL +4 -0
- docagent_cli-0.0.35.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,873 @@
|
|
|
1
|
+
"""Sandbox lifecycle management with provider abstraction."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import contextlib
|
|
6
|
+
import importlib
|
|
7
|
+
import importlib.util
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
import shlex
|
|
11
|
+
import string
|
|
12
|
+
import time
|
|
13
|
+
from contextlib import contextmanager
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import TYPE_CHECKING, Any
|
|
16
|
+
|
|
17
|
+
from rich.markup import escape as escape_markup
|
|
18
|
+
|
|
19
|
+
from docagent_cli.config import console, get_glyphs
|
|
20
|
+
from docagent_cli.integrations.sandbox_provider import (
|
|
21
|
+
SandboxNotFoundError,
|
|
22
|
+
SandboxProvider,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from collections.abc import Generator
|
|
29
|
+
from types import ModuleType
|
|
30
|
+
|
|
31
|
+
from deepagents.backends.protocol import SandboxBackendProtocol
|
|
32
|
+
from langsmith.sandbox import SandboxTemplate
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _run_sandbox_setup(backend: SandboxBackendProtocol, setup_script_path: str) -> None:
|
|
36
|
+
"""Run users setup script in sandbox with env var expansion.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
backend: Sandbox backend instance
|
|
40
|
+
setup_script_path: Path to setup script file
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
FileNotFoundError: If the setup script does not exist.
|
|
44
|
+
RuntimeError: If the setup script fails to execute.
|
|
45
|
+
"""
|
|
46
|
+
script_path = Path(setup_script_path)
|
|
47
|
+
if not script_path.exists():
|
|
48
|
+
msg = f"Setup script not found: {setup_script_path}"
|
|
49
|
+
raise FileNotFoundError(msg)
|
|
50
|
+
|
|
51
|
+
console.print(
|
|
52
|
+
f"[dim]Running setup script: {escape_markup(setup_script_path)}...[/dim]"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Read script content
|
|
56
|
+
script_content = script_path.read_text(encoding="utf-8")
|
|
57
|
+
|
|
58
|
+
# Expand ${VAR} syntax using local environment
|
|
59
|
+
template = string.Template(script_content)
|
|
60
|
+
expanded_script = template.safe_substitute(os.environ)
|
|
61
|
+
|
|
62
|
+
# Execute expanded script in sandbox
|
|
63
|
+
result = backend.execute(f"bash -c {shlex.quote(expanded_script)}")
|
|
64
|
+
|
|
65
|
+
if result.exit_code != 0:
|
|
66
|
+
console.print(f"[red]Setup script failed (exit {result.exit_code}):[/red]")
|
|
67
|
+
console.print(f"[dim]{escape_markup(result.output)}[/dim]")
|
|
68
|
+
msg = "Setup failed - aborting"
|
|
69
|
+
raise RuntimeError(msg)
|
|
70
|
+
|
|
71
|
+
console.print(f"[green]{get_glyphs().checkmark} Setup complete[/green]")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
_PROVIDER_TO_WORKING_DIR = {
|
|
75
|
+
"agentcore": "/tmp", # noqa: S108 # AgentCore Code Interpreter working directory
|
|
76
|
+
"daytona": "/home/daytona",
|
|
77
|
+
"langsmith": "/tmp", # noqa: S108 # LangSmith sandbox working directory
|
|
78
|
+
"modal": "/workspace",
|
|
79
|
+
"runloop": "/home/user",
|
|
80
|
+
}
|
|
81
|
+
"""Map of sandbox provider names to their default working directories."""
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@contextmanager
|
|
85
|
+
def create_sandbox(
|
|
86
|
+
provider: str,
|
|
87
|
+
*,
|
|
88
|
+
sandbox_id: str | None = None,
|
|
89
|
+
setup_script_path: str | None = None,
|
|
90
|
+
) -> Generator[SandboxBackendProtocol, None, None]:
|
|
91
|
+
"""Create or connect to a sandbox of the specified provider.
|
|
92
|
+
|
|
93
|
+
This is the unified interface for sandbox creation using the
|
|
94
|
+
provider abstraction.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
provider: Sandbox provider (`'agentcore'`, `'daytona'`, `'langsmith'`,
|
|
98
|
+
`'modal'`, `'runloop'`)
|
|
99
|
+
sandbox_id: Optional existing sandbox ID to reuse
|
|
100
|
+
setup_script_path: Optional path to setup script to run after sandbox starts
|
|
101
|
+
|
|
102
|
+
Yields:
|
|
103
|
+
`SandboxBackendProtocol` instance
|
|
104
|
+
"""
|
|
105
|
+
# Get provider instance
|
|
106
|
+
provider_obj = _get_provider(provider)
|
|
107
|
+
|
|
108
|
+
# Determine if we should cleanup (only cleanup if we created it)
|
|
109
|
+
should_cleanup = sandbox_id is None
|
|
110
|
+
|
|
111
|
+
# Create or connect to sandbox
|
|
112
|
+
console.print(f"[yellow]Starting {provider} sandbox...[/yellow]")
|
|
113
|
+
backend = provider_obj.get_or_create(sandbox_id=sandbox_id)
|
|
114
|
+
glyphs = get_glyphs()
|
|
115
|
+
console.print(
|
|
116
|
+
f"[green]{glyphs.checkmark} {provider.capitalize()} sandbox ready: "
|
|
117
|
+
f"{backend.id}[/green]"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Run setup script if provided
|
|
121
|
+
if setup_script_path:
|
|
122
|
+
_run_sandbox_setup(backend, setup_script_path)
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
yield backend
|
|
126
|
+
finally:
|
|
127
|
+
if should_cleanup:
|
|
128
|
+
try:
|
|
129
|
+
console.print(
|
|
130
|
+
f"[dim]Terminating {provider} sandbox {backend.id}...[/dim]"
|
|
131
|
+
)
|
|
132
|
+
provider_obj.delete(sandbox_id=backend.id)
|
|
133
|
+
glyphs = get_glyphs()
|
|
134
|
+
console.print(
|
|
135
|
+
f"[dim]{glyphs.checkmark} {provider.capitalize()} sandbox "
|
|
136
|
+
f"{backend.id} terminated[/dim]"
|
|
137
|
+
)
|
|
138
|
+
except Exception as e: # noqa: BLE001 # Cleanup errors should not mask the original sandbox failure
|
|
139
|
+
warning = get_glyphs().warning
|
|
140
|
+
console.print(
|
|
141
|
+
f"[yellow]{warning} Cleanup failed for {provider} sandbox "
|
|
142
|
+
f"{backend.id}: {e}[/yellow]"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _get_available_sandbox_types() -> list[str]:
|
|
147
|
+
"""Get list of available sandbox provider types (internal).
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
List of available sandbox provider type names
|
|
151
|
+
"""
|
|
152
|
+
return sorted(_PROVIDER_TO_WORKING_DIR.keys())
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def get_default_working_dir(provider: str) -> str:
|
|
156
|
+
"""Get the default working directory for a given sandbox provider.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
provider: Sandbox provider name (`'agentcore'`, `'daytona'`, `'langsmith'`,
|
|
160
|
+
`'modal'`, `'runloop'`)
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
Default working directory path as string
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
ValueError: If provider is unknown
|
|
167
|
+
"""
|
|
168
|
+
if provider in _PROVIDER_TO_WORKING_DIR:
|
|
169
|
+
return _PROVIDER_TO_WORKING_DIR[provider]
|
|
170
|
+
msg = f"Unknown sandbox provider: {provider}"
|
|
171
|
+
raise ValueError(msg)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# ---------------------------------------------------------------------------
|
|
175
|
+
# Provider implementations
|
|
176
|
+
# ---------------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _import_provider_module(
|
|
180
|
+
module_name: str,
|
|
181
|
+
*,
|
|
182
|
+
provider: str,
|
|
183
|
+
package: str,
|
|
184
|
+
) -> ModuleType:
|
|
185
|
+
"""Import an optional provider module with a provider-specific error message.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
module_name: Python module name to import.
|
|
189
|
+
provider: Sandbox provider name (e.g. `'daytona'`).
|
|
190
|
+
package: PyPI package name exposed by the CLI extra.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
The imported module object.
|
|
194
|
+
|
|
195
|
+
Raises:
|
|
196
|
+
ImportError: If the optional dependency is not installed.
|
|
197
|
+
"""
|
|
198
|
+
try:
|
|
199
|
+
return importlib.import_module(module_name)
|
|
200
|
+
except ImportError as exc:
|
|
201
|
+
msg = (
|
|
202
|
+
f"The '{provider}' sandbox provider requires the '{package}' package. "
|
|
203
|
+
f"Install it with: pip install 'docagent-cli[{provider}]'"
|
|
204
|
+
)
|
|
205
|
+
raise ImportError(msg) from exc
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
_LANGSMITH_DEFAULT_TEMPLATE = "docagent-cli"
|
|
209
|
+
"""Default LangSmith sandbox template name used when no template is specified."""
|
|
210
|
+
|
|
211
|
+
_LANGSMITH_DEFAULT_IMAGE = "python:3"
|
|
212
|
+
"""Default Docker image for LangSmith sandboxes when no image is provided."""
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class _LangSmithProvider(SandboxProvider):
|
|
216
|
+
"""LangSmith sandbox provider implementation.
|
|
217
|
+
|
|
218
|
+
Manages LangSmith sandbox lifecycle using the LangSmith SDK.
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
def __init__(self, api_key: str | None = None) -> None:
|
|
222
|
+
"""Initialize LangSmith provider.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
api_key: LangSmith API key (defaults to `LANGSMITH_SANDBOX_API_KEY`,
|
|
226
|
+
then `LANGSMITH_API_KEY` env var).
|
|
227
|
+
|
|
228
|
+
Raises:
|
|
229
|
+
ValueError: If no LangSmith API key is found.
|
|
230
|
+
"""
|
|
231
|
+
from langsmith.sandbox import SandboxClient
|
|
232
|
+
|
|
233
|
+
from docagent_cli.model_config import resolve_env_var
|
|
234
|
+
|
|
235
|
+
self._api_key = (
|
|
236
|
+
api_key
|
|
237
|
+
or resolve_env_var("LANGSMITH_SANDBOX_API_KEY")
|
|
238
|
+
or resolve_env_var("LANGSMITH_API_KEY")
|
|
239
|
+
)
|
|
240
|
+
if not self._api_key:
|
|
241
|
+
msg = (
|
|
242
|
+
"No LangSmith sandbox API key found. Set "
|
|
243
|
+
"LANGSMITH_SANDBOX_API_KEY or LANGSMITH_API_KEY "
|
|
244
|
+
"(or the DEEPAGENTS_CLI_-prefixed equivalents)."
|
|
245
|
+
)
|
|
246
|
+
raise ValueError(msg)
|
|
247
|
+
self._client: SandboxClient = SandboxClient(api_key=self._api_key)
|
|
248
|
+
|
|
249
|
+
def get_or_create(
|
|
250
|
+
self,
|
|
251
|
+
*,
|
|
252
|
+
sandbox_id: str | None = None,
|
|
253
|
+
timeout: int = 180,
|
|
254
|
+
template: str | None = None,
|
|
255
|
+
template_image: str | None = None,
|
|
256
|
+
**kwargs: Any,
|
|
257
|
+
) -> SandboxBackendProtocol:
|
|
258
|
+
"""Get existing or create new LangSmith sandbox.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
sandbox_id: Optional existing sandbox name to reuse
|
|
262
|
+
timeout: Timeout in seconds for sandbox startup
|
|
263
|
+
template: Template name for the sandbox
|
|
264
|
+
template_image: Docker image for the template
|
|
265
|
+
**kwargs: Additional LangSmith-specific parameters
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
`LangSmithSandbox` instance
|
|
269
|
+
|
|
270
|
+
Raises:
|
|
271
|
+
RuntimeError: If sandbox connection or startup fails
|
|
272
|
+
TypeError: If unsupported keyword arguments are provided
|
|
273
|
+
"""
|
|
274
|
+
from deepagents.backends.langsmith import LangSmithSandbox
|
|
275
|
+
|
|
276
|
+
if kwargs:
|
|
277
|
+
msg = f"Received unsupported arguments: {list(kwargs.keys())}"
|
|
278
|
+
raise TypeError(msg)
|
|
279
|
+
if sandbox_id:
|
|
280
|
+
# Connect to existing sandbox by name
|
|
281
|
+
try:
|
|
282
|
+
sandbox = self._client.get_sandbox(name=sandbox_id)
|
|
283
|
+
except Exception as e:
|
|
284
|
+
msg = f"Failed to connect to existing sandbox '{sandbox_id}': {e}"
|
|
285
|
+
raise RuntimeError(msg) from e
|
|
286
|
+
return LangSmithSandbox(sandbox)
|
|
287
|
+
|
|
288
|
+
resolved_template_name, resolved_image_name = self._resolve_template(
|
|
289
|
+
template, template_image
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
# Create new sandbox - ensure template exists first
|
|
293
|
+
self._ensure_template(resolved_template_name, resolved_image_name)
|
|
294
|
+
|
|
295
|
+
try:
|
|
296
|
+
sandbox = self._client.create_sandbox(
|
|
297
|
+
template_name=resolved_template_name, timeout=timeout
|
|
298
|
+
)
|
|
299
|
+
except Exception as e:
|
|
300
|
+
msg = (
|
|
301
|
+
f"Failed to create sandbox from template "
|
|
302
|
+
f"'{resolved_template_name}': {e}"
|
|
303
|
+
)
|
|
304
|
+
raise RuntimeError(msg) from e
|
|
305
|
+
|
|
306
|
+
# Verify sandbox is ready by polling
|
|
307
|
+
for _ in range(timeout // 2):
|
|
308
|
+
try:
|
|
309
|
+
result = sandbox.run("echo ready", timeout=5)
|
|
310
|
+
if result.exit_code == 0:
|
|
311
|
+
break
|
|
312
|
+
except Exception: # noqa: S110, BLE001 # Sandbox not ready yet, continue polling
|
|
313
|
+
pass
|
|
314
|
+
time.sleep(2)
|
|
315
|
+
else:
|
|
316
|
+
# Cleanup on failure
|
|
317
|
+
with contextlib.suppress(Exception):
|
|
318
|
+
self._client.delete_sandbox(sandbox.name)
|
|
319
|
+
msg = f"LangSmith sandbox failed to start within {timeout} seconds"
|
|
320
|
+
raise RuntimeError(msg)
|
|
321
|
+
|
|
322
|
+
return LangSmithSandbox(sandbox)
|
|
323
|
+
|
|
324
|
+
def delete(self, *, sandbox_id: str, **kwargs: Any) -> None: # noqa: ARG002 # Required by SandboxFactory interface
|
|
325
|
+
"""Delete a LangSmith sandbox.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
sandbox_id: Sandbox name to delete
|
|
329
|
+
**kwargs: Additional parameters
|
|
330
|
+
"""
|
|
331
|
+
self._client.delete_sandbox(sandbox_id)
|
|
332
|
+
|
|
333
|
+
@staticmethod
|
|
334
|
+
def _resolve_template(
|
|
335
|
+
template: SandboxTemplate | str | None,
|
|
336
|
+
template_image: str | None = None,
|
|
337
|
+
) -> tuple[str, str]:
|
|
338
|
+
"""Resolve template name and image from kwargs.
|
|
339
|
+
|
|
340
|
+
Returns:
|
|
341
|
+
Tuple of `(template_name, template_image)`.
|
|
342
|
+
|
|
343
|
+
Always returns values, using defaults if not provided.
|
|
344
|
+
"""
|
|
345
|
+
resolved_image = template_image or _LANGSMITH_DEFAULT_IMAGE
|
|
346
|
+
if template is None:
|
|
347
|
+
return _LANGSMITH_DEFAULT_TEMPLATE, resolved_image
|
|
348
|
+
if isinstance(template, str):
|
|
349
|
+
return template, resolved_image
|
|
350
|
+
# SandboxTemplate object - extract image if not provided
|
|
351
|
+
if template_image is None and template.image:
|
|
352
|
+
resolved_image = template.image
|
|
353
|
+
return template.name, resolved_image
|
|
354
|
+
|
|
355
|
+
def _ensure_template(
|
|
356
|
+
self,
|
|
357
|
+
template_name: str,
|
|
358
|
+
template_image: str,
|
|
359
|
+
) -> None:
|
|
360
|
+
"""Ensure template exists, creating it if needed.
|
|
361
|
+
|
|
362
|
+
Raises:
|
|
363
|
+
RuntimeError: If template check or creation fails
|
|
364
|
+
"""
|
|
365
|
+
from langsmith.sandbox import ResourceNotFoundError
|
|
366
|
+
|
|
367
|
+
try:
|
|
368
|
+
self._client.get_template(template_name)
|
|
369
|
+
except ResourceNotFoundError as e:
|
|
370
|
+
if e.resource_type != "template":
|
|
371
|
+
msg = f"Unexpected resource not found: {e}"
|
|
372
|
+
raise RuntimeError(msg) from e
|
|
373
|
+
# Template doesn't exist, create it
|
|
374
|
+
try:
|
|
375
|
+
self._client.create_template(name=template_name, image=template_image)
|
|
376
|
+
except Exception as create_err:
|
|
377
|
+
msg = f"Failed to create template '{template_name}': {create_err}"
|
|
378
|
+
raise RuntimeError(msg) from create_err
|
|
379
|
+
except Exception as e:
|
|
380
|
+
msg = f"Failed to check template '{template_name}': {e}"
|
|
381
|
+
raise RuntimeError(msg) from e
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
class _DaytonaProvider(SandboxProvider):
|
|
385
|
+
"""Daytona sandbox provider — lifecycle management for Daytona sandboxes."""
|
|
386
|
+
|
|
387
|
+
def __init__(self) -> None:
|
|
388
|
+
daytona_module = _import_provider_module(
|
|
389
|
+
"daytona",
|
|
390
|
+
provider="daytona",
|
|
391
|
+
package="langchain-daytona",
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
from docagent_cli.model_config import resolve_env_var
|
|
395
|
+
|
|
396
|
+
api_key = resolve_env_var("DAYTONA_API_KEY")
|
|
397
|
+
if not api_key:
|
|
398
|
+
msg = (
|
|
399
|
+
"No Daytona API key found. Set DAYTONA_API_KEY "
|
|
400
|
+
"or DEEPAGENTS_CLI_DAYTONA_API_KEY."
|
|
401
|
+
)
|
|
402
|
+
raise ValueError(msg)
|
|
403
|
+
self._client = daytona_module.Daytona(
|
|
404
|
+
daytona_module.DaytonaConfig(
|
|
405
|
+
api_key=api_key,
|
|
406
|
+
api_url=resolve_env_var("DAYTONA_API_URL"),
|
|
407
|
+
)
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
def get_or_create(
|
|
411
|
+
self,
|
|
412
|
+
*,
|
|
413
|
+
sandbox_id: str | None = None,
|
|
414
|
+
timeout: int = 180,
|
|
415
|
+
**kwargs: Any, # noqa: ARG002
|
|
416
|
+
) -> SandboxBackendProtocol:
|
|
417
|
+
"""Get or create a Daytona sandbox.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
sandbox_id: Not supported yet — must be None.
|
|
421
|
+
timeout: Seconds to wait for startup.
|
|
422
|
+
**kwargs: Unused.
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
`DaytonaSandbox` instance.
|
|
426
|
+
|
|
427
|
+
Raises:
|
|
428
|
+
NotImplementedError: If `sandbox_id` is provided.
|
|
429
|
+
RuntimeError: If the sandbox fails to start.
|
|
430
|
+
"""
|
|
431
|
+
daytona_backend = _import_provider_module(
|
|
432
|
+
"langchain_daytona",
|
|
433
|
+
provider="daytona",
|
|
434
|
+
package="langchain-daytona",
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
if sandbox_id:
|
|
438
|
+
msg = (
|
|
439
|
+
"Connecting to existing Daytona sandbox by ID not yet supported. "
|
|
440
|
+
"Create a new sandbox by omitting sandbox_id parameter."
|
|
441
|
+
)
|
|
442
|
+
raise NotImplementedError(msg)
|
|
443
|
+
|
|
444
|
+
sandbox = self._client.create()
|
|
445
|
+
last_exc: Exception | None = None
|
|
446
|
+
for _ in range(timeout // 2):
|
|
447
|
+
try:
|
|
448
|
+
result = sandbox.process.exec("echo ready", timeout=5)
|
|
449
|
+
if result.exit_code == 0:
|
|
450
|
+
break
|
|
451
|
+
except Exception as exc: # noqa: BLE001 # Transient failures expected during readiness polling
|
|
452
|
+
last_exc = exc
|
|
453
|
+
time.sleep(2)
|
|
454
|
+
else:
|
|
455
|
+
with contextlib.suppress(Exception): # Best-effort cleanup
|
|
456
|
+
sandbox.delete()
|
|
457
|
+
detail = f" Last error: {last_exc}" if last_exc else ""
|
|
458
|
+
msg = f"Daytona sandbox failed to start within {timeout} seconds.{detail}"
|
|
459
|
+
raise RuntimeError(msg)
|
|
460
|
+
|
|
461
|
+
return daytona_backend.DaytonaSandbox(sandbox=sandbox)
|
|
462
|
+
|
|
463
|
+
def delete(self, *, sandbox_id: str, **kwargs: Any) -> None: # noqa: ARG002
|
|
464
|
+
"""Delete a Daytona sandbox by id."""
|
|
465
|
+
sandbox = self._client.get(sandbox_id)
|
|
466
|
+
self._client.delete(sandbox)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
class _ModalProvider(SandboxProvider):
|
|
470
|
+
"""Modal sandbox provider — lifecycle management for Modal sandboxes."""
|
|
471
|
+
|
|
472
|
+
def __init__(self) -> None:
|
|
473
|
+
self._modal = _import_provider_module(
|
|
474
|
+
"modal",
|
|
475
|
+
provider="modal",
|
|
476
|
+
package="langchain-modal",
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
from docagent_cli.model_config import resolve_env_var
|
|
480
|
+
|
|
481
|
+
token_id = resolve_env_var("MODAL_TOKEN_ID")
|
|
482
|
+
token_secret = resolve_env_var("MODAL_TOKEN_SECRET")
|
|
483
|
+
if token_id and token_secret:
|
|
484
|
+
try:
|
|
485
|
+
self._client = self._modal.Client.from_credentials(
|
|
486
|
+
token_id, token_secret
|
|
487
|
+
)
|
|
488
|
+
except Exception as exc:
|
|
489
|
+
msg = (
|
|
490
|
+
"Failed to authenticate with Modal using "
|
|
491
|
+
"MODAL_TOKEN_ID / MODAL_TOKEN_SECRET "
|
|
492
|
+
"(or the DEEPAGENTS_CLI_-prefixed equivalents). "
|
|
493
|
+
"Verify your credentials are valid."
|
|
494
|
+
)
|
|
495
|
+
raise ValueError(msg) from exc
|
|
496
|
+
elif token_id or token_secret:
|
|
497
|
+
logger.warning(
|
|
498
|
+
"Only one of MODAL_TOKEN_ID / MODAL_TOKEN_SECRET is set; "
|
|
499
|
+
"both are required for explicit credential auth. "
|
|
500
|
+
"Falling back to default Modal authentication.",
|
|
501
|
+
)
|
|
502
|
+
self._client = None
|
|
503
|
+
else:
|
|
504
|
+
self._client = None
|
|
505
|
+
|
|
506
|
+
lookup_kwargs: dict[str, Any] = {
|
|
507
|
+
"name": "docagent-sandbox",
|
|
508
|
+
"create_if_missing": True,
|
|
509
|
+
}
|
|
510
|
+
if self._client is not None:
|
|
511
|
+
lookup_kwargs["client"] = self._client
|
|
512
|
+
self._app = self._modal.App.lookup(**lookup_kwargs)
|
|
513
|
+
|
|
514
|
+
def get_or_create(
|
|
515
|
+
self,
|
|
516
|
+
*,
|
|
517
|
+
sandbox_id: str | None = None,
|
|
518
|
+
timeout: int = 180,
|
|
519
|
+
**kwargs: Any, # noqa: ARG002
|
|
520
|
+
) -> SandboxBackendProtocol:
|
|
521
|
+
"""Get or create a Modal sandbox.
|
|
522
|
+
|
|
523
|
+
Args:
|
|
524
|
+
sandbox_id: Existing sandbox ID, or None to create.
|
|
525
|
+
timeout: Seconds to wait for startup.
|
|
526
|
+
**kwargs: Unused.
|
|
527
|
+
|
|
528
|
+
Returns:
|
|
529
|
+
`ModalSandbox` instance.
|
|
530
|
+
|
|
531
|
+
Raises:
|
|
532
|
+
RuntimeError: If the sandbox fails to start.
|
|
533
|
+
"""
|
|
534
|
+
modal_backend = _import_provider_module(
|
|
535
|
+
"langchain_modal",
|
|
536
|
+
provider="modal",
|
|
537
|
+
package="langchain-modal",
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
client_kwargs: dict[str, Any] = {}
|
|
541
|
+
if self._client is not None:
|
|
542
|
+
client_kwargs["client"] = self._client
|
|
543
|
+
|
|
544
|
+
if sandbox_id:
|
|
545
|
+
sandbox = self._modal.Sandbox.from_id(
|
|
546
|
+
sandbox_id=sandbox_id,
|
|
547
|
+
app=self._app,
|
|
548
|
+
**client_kwargs,
|
|
549
|
+
)
|
|
550
|
+
else:
|
|
551
|
+
sandbox = self._modal.Sandbox.create(
|
|
552
|
+
app=self._app, workdir="/workspace", **client_kwargs
|
|
553
|
+
)
|
|
554
|
+
last_exc: Exception | None = None
|
|
555
|
+
for _ in range(timeout // 2):
|
|
556
|
+
if sandbox.poll() is not None:
|
|
557
|
+
msg = "Modal sandbox terminated unexpectedly during startup"
|
|
558
|
+
raise RuntimeError(msg)
|
|
559
|
+
try:
|
|
560
|
+
process = sandbox.exec("echo", "ready", timeout=5)
|
|
561
|
+
process.wait()
|
|
562
|
+
if process.returncode == 0:
|
|
563
|
+
break
|
|
564
|
+
except Exception as exc: # noqa: BLE001 # Transient failures expected during readiness polling
|
|
565
|
+
last_exc = exc
|
|
566
|
+
time.sleep(2)
|
|
567
|
+
else:
|
|
568
|
+
sandbox.terminate()
|
|
569
|
+
detail = f" Last error: {last_exc}" if last_exc else ""
|
|
570
|
+
msg = f"Modal sandbox failed to start within {timeout} seconds.{detail}"
|
|
571
|
+
raise RuntimeError(msg)
|
|
572
|
+
|
|
573
|
+
return modal_backend.ModalSandbox(sandbox=sandbox)
|
|
574
|
+
|
|
575
|
+
def delete(self, *, sandbox_id: str, **kwargs: Any) -> None: # noqa: ARG002
|
|
576
|
+
"""Terminate a Modal sandbox by id."""
|
|
577
|
+
del_kwargs: dict[str, Any] = {"sandbox_id": sandbox_id, "app": self._app}
|
|
578
|
+
if self._client is not None:
|
|
579
|
+
del_kwargs["client"] = self._client
|
|
580
|
+
sandbox = self._modal.Sandbox.from_id(**del_kwargs)
|
|
581
|
+
sandbox.terminate()
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
class _RunloopProvider(SandboxProvider):
|
|
585
|
+
"""Runloop sandbox provider — lifecycle management for Runloop devboxes."""
|
|
586
|
+
|
|
587
|
+
def __init__(self) -> None:
|
|
588
|
+
runloop_module = _import_provider_module(
|
|
589
|
+
"runloop_api_client",
|
|
590
|
+
provider="runloop",
|
|
591
|
+
package="langchain-runloop",
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
from docagent_cli.model_config import resolve_env_var
|
|
595
|
+
|
|
596
|
+
api_key = resolve_env_var("RUNLOOP_API_KEY")
|
|
597
|
+
if not api_key:
|
|
598
|
+
msg = (
|
|
599
|
+
"No Runloop API key found. Set RUNLOOP_API_KEY "
|
|
600
|
+
"or DEEPAGENTS_CLI_RUNLOOP_API_KEY."
|
|
601
|
+
)
|
|
602
|
+
raise ValueError(msg)
|
|
603
|
+
self._client = runloop_module.Runloop(bearer_token=api_key)
|
|
604
|
+
|
|
605
|
+
def get_or_create(
|
|
606
|
+
self,
|
|
607
|
+
*,
|
|
608
|
+
sandbox_id: str | None = None,
|
|
609
|
+
timeout: int = 180,
|
|
610
|
+
**kwargs: Any, # noqa: ARG002
|
|
611
|
+
) -> SandboxBackendProtocol:
|
|
612
|
+
"""Get or create a Runloop devbox.
|
|
613
|
+
|
|
614
|
+
Args:
|
|
615
|
+
sandbox_id: Existing devbox ID, or None to create.
|
|
616
|
+
timeout: Seconds to wait for startup.
|
|
617
|
+
**kwargs: Unused.
|
|
618
|
+
|
|
619
|
+
Returns:
|
|
620
|
+
`RunloopSandbox` instance.
|
|
621
|
+
|
|
622
|
+
Raises:
|
|
623
|
+
RuntimeError: If the devbox fails to start.
|
|
624
|
+
SandboxNotFoundError: If `sandbox_id` does not exist.
|
|
625
|
+
"""
|
|
626
|
+
runloop_backend = _import_provider_module(
|
|
627
|
+
"langchain_runloop",
|
|
628
|
+
provider="runloop",
|
|
629
|
+
package="langchain-runloop",
|
|
630
|
+
)
|
|
631
|
+
runloop_sdk = _import_provider_module(
|
|
632
|
+
"runloop_api_client.sdk",
|
|
633
|
+
provider="runloop",
|
|
634
|
+
package="langchain-runloop",
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
if sandbox_id:
|
|
638
|
+
try:
|
|
639
|
+
self._client.devboxes.retrieve(id=sandbox_id)
|
|
640
|
+
except KeyError as e:
|
|
641
|
+
raise SandboxNotFoundError(sandbox_id) from e
|
|
642
|
+
else:
|
|
643
|
+
view = self._client.devboxes.create()
|
|
644
|
+
sandbox_id = view.id
|
|
645
|
+
for _ in range(timeout // 2):
|
|
646
|
+
status = self._client.devboxes.retrieve(id=sandbox_id)
|
|
647
|
+
if status.status == "running":
|
|
648
|
+
break
|
|
649
|
+
time.sleep(2)
|
|
650
|
+
else:
|
|
651
|
+
self._client.devboxes.shutdown(id=sandbox_id)
|
|
652
|
+
msg = f"Devbox failed to start within {timeout} seconds"
|
|
653
|
+
raise RuntimeError(msg)
|
|
654
|
+
|
|
655
|
+
devbox = runloop_sdk.Devbox(self._client, sandbox_id)
|
|
656
|
+
return runloop_backend.RunloopSandbox(devbox=devbox)
|
|
657
|
+
|
|
658
|
+
def delete(self, *, sandbox_id: str, **kwargs: Any) -> None: # noqa: ARG002
|
|
659
|
+
"""Shut down a Runloop devbox by id."""
|
|
660
|
+
self._client.devboxes.shutdown(id=sandbox_id)
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
class _AgentCoreProvider(SandboxProvider):
|
|
664
|
+
"""AgentCore Code Interpreter sandbox provider.
|
|
665
|
+
|
|
666
|
+
Manages AgentCore session lifecycle. Sessions cannot be reconnected after
|
|
667
|
+
the CLI exits — the `sandbox_id` parameter is not supported.
|
|
668
|
+
"""
|
|
669
|
+
|
|
670
|
+
def __init__(self, region: str | None = None) -> None:
|
|
671
|
+
"""Initialize AgentCore provider.
|
|
672
|
+
|
|
673
|
+
Args:
|
|
674
|
+
region: AWS region (defaults to `AWS_REGION` /
|
|
675
|
+
`AWS_DEFAULT_REGION` / `us-west-2`).
|
|
676
|
+
|
|
677
|
+
Raises:
|
|
678
|
+
ValueError: If boto3 is installed and AWS credentials cannot
|
|
679
|
+
be resolved.
|
|
680
|
+
"""
|
|
681
|
+
self._region = region or os.environ.get(
|
|
682
|
+
"AWS_REGION", os.environ.get("AWS_DEFAULT_REGION", "us-west-2")
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
# Validate AWS credentials early for a clear error message.
|
|
686
|
+
try:
|
|
687
|
+
import boto3 # ty: ignore[unresolved-import]
|
|
688
|
+
|
|
689
|
+
session = boto3.Session()
|
|
690
|
+
credentials = session.get_credentials()
|
|
691
|
+
if credentials is None:
|
|
692
|
+
msg = (
|
|
693
|
+
"AWS credentials not found. Configure via "
|
|
694
|
+
"AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN, "
|
|
695
|
+
"~/.aws/credentials, or an IAM role."
|
|
696
|
+
)
|
|
697
|
+
raise ValueError(msg) # noqa: TRY301 # intentional raise for early credential validation
|
|
698
|
+
except ImportError:
|
|
699
|
+
logger.debug("boto3 not installed; skipping credential pre-check")
|
|
700
|
+
except ValueError:
|
|
701
|
+
raise
|
|
702
|
+
except Exception:
|
|
703
|
+
logger.warning(
|
|
704
|
+
"AWS credential pre-validation failed — the session may "
|
|
705
|
+
"fail to start. Check your AWS configuration.",
|
|
706
|
+
exc_info=True,
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
self._active_interpreters: dict[str, Any] = {}
|
|
710
|
+
|
|
711
|
+
def get_or_create(
|
|
712
|
+
self,
|
|
713
|
+
*,
|
|
714
|
+
sandbox_id: str | None = None,
|
|
715
|
+
**kwargs: Any, # noqa: ARG002 # required by SandboxProvider interface
|
|
716
|
+
) -> SandboxBackendProtocol:
|
|
717
|
+
"""Create a new AgentCore Code Interpreter session.
|
|
718
|
+
|
|
719
|
+
Args:
|
|
720
|
+
sandbox_id: Not supported — raises `NotImplementedError`
|
|
721
|
+
if provided.
|
|
722
|
+
**kwargs: Additional parameters (unused).
|
|
723
|
+
|
|
724
|
+
Returns:
|
|
725
|
+
`AgentCoreSandbox` instance wrapping the started interpreter.
|
|
726
|
+
|
|
727
|
+
Raises:
|
|
728
|
+
NotImplementedError: If `sandbox_id` is provided.
|
|
729
|
+
"""
|
|
730
|
+
if sandbox_id:
|
|
731
|
+
msg = (
|
|
732
|
+
"AgentCore does not support reconnecting to existing sessions. "
|
|
733
|
+
"Remove the --sandbox-id option."
|
|
734
|
+
)
|
|
735
|
+
raise NotImplementedError(msg)
|
|
736
|
+
|
|
737
|
+
agentcore_module = _import_provider_module(
|
|
738
|
+
"bedrock_agentcore.tools.code_interpreter_client",
|
|
739
|
+
provider="agentcore",
|
|
740
|
+
package="langchain-agentcore-codeinterpreter",
|
|
741
|
+
)
|
|
742
|
+
agentcore_backend = _import_provider_module(
|
|
743
|
+
"langchain_agentcore_codeinterpreter",
|
|
744
|
+
provider="agentcore",
|
|
745
|
+
package="langchain-agentcore-codeinterpreter",
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
interpreter = agentcore_module.CodeInterpreter(
|
|
749
|
+
region=self._region,
|
|
750
|
+
integration_source="docagent-cli",
|
|
751
|
+
)
|
|
752
|
+
try:
|
|
753
|
+
interpreter.start()
|
|
754
|
+
except Exception:
|
|
755
|
+
with contextlib.suppress(Exception):
|
|
756
|
+
interpreter.stop()
|
|
757
|
+
raise
|
|
758
|
+
|
|
759
|
+
backend = agentcore_backend.AgentCoreSandbox(interpreter=interpreter)
|
|
760
|
+
self._active_interpreters[backend.id] = interpreter
|
|
761
|
+
return backend
|
|
762
|
+
|
|
763
|
+
def delete(self, *, sandbox_id: str, **kwargs: Any) -> None: # noqa: ARG002 # required by SandboxProvider interface
|
|
764
|
+
"""Stop an AgentCore session.
|
|
765
|
+
|
|
766
|
+
Args:
|
|
767
|
+
sandbox_id: Session ID to stop.
|
|
768
|
+
**kwargs: Additional parameters (unused).
|
|
769
|
+
"""
|
|
770
|
+
interpreter = self._active_interpreters.pop(sandbox_id, None)
|
|
771
|
+
if interpreter:
|
|
772
|
+
try:
|
|
773
|
+
interpreter.stop()
|
|
774
|
+
logger.info("AgentCore session %s stopped", sandbox_id)
|
|
775
|
+
except Exception:
|
|
776
|
+
logger.warning(
|
|
777
|
+
"Failed to stop AgentCore session %s — the session may "
|
|
778
|
+
"still be running and incurring costs. Check the AWS "
|
|
779
|
+
"console to verify.",
|
|
780
|
+
sandbox_id,
|
|
781
|
+
exc_info=True,
|
|
782
|
+
)
|
|
783
|
+
else:
|
|
784
|
+
logger.info(
|
|
785
|
+
"AgentCore session %s not tracked (may have already expired)",
|
|
786
|
+
sandbox_id,
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
def _get_provider(provider_name: str) -> SandboxProvider:
|
|
791
|
+
"""Get a `SandboxProvider` instance for the specified provider (internal).
|
|
792
|
+
|
|
793
|
+
Args:
|
|
794
|
+
provider_name: Name of the provider (`'agentcore'`, `'daytona'`, `'langsmith'`,
|
|
795
|
+
`'modal'`, `'runloop'`)
|
|
796
|
+
|
|
797
|
+
Returns:
|
|
798
|
+
`SandboxProvider` instance
|
|
799
|
+
|
|
800
|
+
Raises:
|
|
801
|
+
ValueError: If `provider_name` is unknown.
|
|
802
|
+
"""
|
|
803
|
+
if provider_name == "agentcore":
|
|
804
|
+
return _AgentCoreProvider()
|
|
805
|
+
if provider_name == "daytona":
|
|
806
|
+
return _DaytonaProvider()
|
|
807
|
+
if provider_name == "langsmith":
|
|
808
|
+
return _LangSmithProvider()
|
|
809
|
+
if provider_name == "modal":
|
|
810
|
+
return _ModalProvider()
|
|
811
|
+
if provider_name == "runloop":
|
|
812
|
+
return _RunloopProvider()
|
|
813
|
+
msg = (
|
|
814
|
+
f"Unknown sandbox provider: {provider_name}. "
|
|
815
|
+
f"Available providers: {', '.join(_get_available_sandbox_types())}"
|
|
816
|
+
)
|
|
817
|
+
raise ValueError(msg)
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
def verify_sandbox_deps(provider: str) -> None:
|
|
821
|
+
"""Check that the required packages for a sandbox provider are installed.
|
|
822
|
+
|
|
823
|
+
Uses `importlib.util.find_spec` for a lightweight check with no actual
|
|
824
|
+
imports. Call this in the CLI process *before* spawning the server
|
|
825
|
+
subprocess so users get a clear, actionable error instead of an opaque
|
|
826
|
+
server crash.
|
|
827
|
+
|
|
828
|
+
Args:
|
|
829
|
+
provider: Sandbox provider name (e.g. `'daytona'`).
|
|
830
|
+
|
|
831
|
+
Raises:
|
|
832
|
+
ImportError: If the provider's backend package is not installed.
|
|
833
|
+
"""
|
|
834
|
+
if not provider or provider in {"none", "langsmith"}:
|
|
835
|
+
return
|
|
836
|
+
|
|
837
|
+
# Map provider name → (backend module, pip extra).
|
|
838
|
+
# Only the backend module is checked because the underlying SDK is a
|
|
839
|
+
# transitive dependency of the backend package.
|
|
840
|
+
backend_modules: dict[str, tuple[str, str]] = {
|
|
841
|
+
"agentcore": ("langchain_agentcore_codeinterpreter", "agentcore"),
|
|
842
|
+
"daytona": ("langchain_daytona", "daytona"),
|
|
843
|
+
"modal": ("langchain_modal", "modal"),
|
|
844
|
+
"runloop": ("langchain_runloop", "runloop"),
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
entry = backend_modules.get(provider)
|
|
848
|
+
if entry is None:
|
|
849
|
+
logger.debug(
|
|
850
|
+
"No backend_modules entry for provider %r; skipping pre-flight check",
|
|
851
|
+
provider,
|
|
852
|
+
)
|
|
853
|
+
return
|
|
854
|
+
|
|
855
|
+
module_name, extra = entry
|
|
856
|
+
try:
|
|
857
|
+
found = importlib.util.find_spec(module_name) is not None
|
|
858
|
+
except (ImportError, ValueError):
|
|
859
|
+
found = False
|
|
860
|
+
|
|
861
|
+
if not found:
|
|
862
|
+
msg = (
|
|
863
|
+
f"Missing dependencies for '{provider}' sandbox. "
|
|
864
|
+
f"Install with: pip install 'docagent-cli[{extra}]'"
|
|
865
|
+
)
|
|
866
|
+
raise ImportError(msg)
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
__all__ = [
|
|
870
|
+
"create_sandbox",
|
|
871
|
+
"get_default_working_dir",
|
|
872
|
+
"verify_sandbox_deps",
|
|
873
|
+
]
|