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
docagent_cli/server.py
ADDED
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
"""LangGraph server lifecycle management for the CLI.
|
|
2
|
+
|
|
3
|
+
Handles starting/stopping a `langgraph dev` server process and generating the
|
|
4
|
+
required `langgraph.json` configuration file.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import contextlib
|
|
11
|
+
import json
|
|
12
|
+
import logging
|
|
13
|
+
import os
|
|
14
|
+
import signal
|
|
15
|
+
import subprocess # noqa: S404
|
|
16
|
+
import sys
|
|
17
|
+
import tempfile
|
|
18
|
+
import time
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import TYPE_CHECKING, Any, Self
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from collections.abc import Callable, Iterator
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
_DEFAULT_HOST = "127.0.0.1"
|
|
28
|
+
_DEFAULT_PORT = 2024
|
|
29
|
+
_HEALTH_POLL_INTERVAL_LOCAL = 0.1
|
|
30
|
+
_HEALTH_POLL_INTERVAL_REMOTE = 0.3
|
|
31
|
+
_HEALTH_TIMEOUT = 60
|
|
32
|
+
_SHUTDOWN_TIMEOUT = 5
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _port_in_use(host: str, port: int) -> bool:
|
|
36
|
+
"""Check if a port is already in use.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
host: Host to check.
|
|
40
|
+
port: Port to check.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
`True` if the port is in use.
|
|
44
|
+
"""
|
|
45
|
+
import socket
|
|
46
|
+
|
|
47
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
48
|
+
try:
|
|
49
|
+
s.bind((host, port))
|
|
50
|
+
except OSError:
|
|
51
|
+
return True
|
|
52
|
+
else:
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _find_free_port(host: str) -> int:
|
|
57
|
+
"""Find a free port on the given host.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
host: Host to bind to.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
An available port number.
|
|
64
|
+
"""
|
|
65
|
+
import socket
|
|
66
|
+
|
|
67
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
68
|
+
s.bind((host, 0))
|
|
69
|
+
return s.getsockname()[1]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_server_url(host: str = _DEFAULT_HOST, port: int = _DEFAULT_PORT) -> str:
|
|
73
|
+
"""Build the server base URL.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
host: Server host.
|
|
77
|
+
port: Server port.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Base URL string.
|
|
81
|
+
"""
|
|
82
|
+
return f"http://{host}:{port}"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def generate_langgraph_json(
|
|
86
|
+
output_dir: str | Path,
|
|
87
|
+
*,
|
|
88
|
+
graph_ref: str = "./server_graph.py:graph",
|
|
89
|
+
env_file: str | None = None,
|
|
90
|
+
checkpointer_path: str | None = None,
|
|
91
|
+
) -> Path:
|
|
92
|
+
"""Generate a `langgraph.json` config file for `langgraph dev`.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
output_dir: Directory to write the config file.
|
|
96
|
+
graph_ref: Python module:variable reference to the graph.
|
|
97
|
+
env_file: Optional path to an env file.
|
|
98
|
+
checkpointer_path: Import path to an async context manager that yields a
|
|
99
|
+
`BaseCheckpointSaver`. When set, the server persists checkpoint data
|
|
100
|
+
to disk instead of in-memory.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Path to the generated config file.
|
|
104
|
+
"""
|
|
105
|
+
config: dict[str, Any] = {
|
|
106
|
+
"dependencies": ["."],
|
|
107
|
+
"graphs": {
|
|
108
|
+
"agent": graph_ref,
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
if env_file:
|
|
112
|
+
config["env"] = env_file
|
|
113
|
+
if checkpointer_path:
|
|
114
|
+
config["checkpointer"] = {"path": checkpointer_path}
|
|
115
|
+
|
|
116
|
+
output_path = Path(output_dir) / "langgraph.json"
|
|
117
|
+
output_path.write_text(json.dumps(config, indent=2))
|
|
118
|
+
return output_path
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ---------------------------------------------------------------------------
|
|
122
|
+
# Scoped env-var management
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@contextlib.contextmanager
|
|
127
|
+
def _scoped_env_overrides(
|
|
128
|
+
overrides: dict[str, str],
|
|
129
|
+
) -> Iterator[None]:
|
|
130
|
+
"""Apply env-var overrides, rolling back only on exception.
|
|
131
|
+
|
|
132
|
+
Separates the concern of temporary `os.environ` mutations from subprocess
|
|
133
|
+
management, making both independently testable.
|
|
134
|
+
|
|
135
|
+
On normal exit the overrides are left in place (the caller "keeps"
|
|
136
|
+
them). On exception the previous values are restored so the next attempt
|
|
137
|
+
starts from a known-good state.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
overrides: Key/value pairs to set in `os.environ`.
|
|
141
|
+
|
|
142
|
+
Yields:
|
|
143
|
+
Control to the caller.
|
|
144
|
+
"""
|
|
145
|
+
prev: dict[str, str | None] = {}
|
|
146
|
+
for key, val in overrides.items():
|
|
147
|
+
prev[key] = os.environ.get(key)
|
|
148
|
+
os.environ[key] = val
|
|
149
|
+
try:
|
|
150
|
+
yield
|
|
151
|
+
except Exception:
|
|
152
|
+
for key, old_val in prev.items():
|
|
153
|
+
if old_val is None:
|
|
154
|
+
os.environ.pop(key, None)
|
|
155
|
+
else:
|
|
156
|
+
os.environ[key] = old_val
|
|
157
|
+
raise
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# ---------------------------------------------------------------------------
|
|
161
|
+
# Health checking
|
|
162
|
+
# ---------------------------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
async def wait_for_server_healthy(
|
|
166
|
+
url: str,
|
|
167
|
+
*,
|
|
168
|
+
timeout: float = _HEALTH_TIMEOUT, # noqa: ASYNC109
|
|
169
|
+
process: subprocess.Popen | None = None,
|
|
170
|
+
read_log: Callable[[], str] | None = None,
|
|
171
|
+
local: bool = False,
|
|
172
|
+
) -> None:
|
|
173
|
+
"""Poll a LangGraph server health endpoint until it responds.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
url: Server base URL (health endpoint is `{url}/ok`).
|
|
177
|
+
timeout: Max seconds to wait.
|
|
178
|
+
process: Optional subprocess handle; if the process exits early
|
|
179
|
+
we fail fast instead of waiting for the timeout.
|
|
180
|
+
read_log: Optional callable returning log file contents (for
|
|
181
|
+
error messages on early exit).
|
|
182
|
+
local: Use a shorter poll interval for local servers.
|
|
183
|
+
|
|
184
|
+
Raises:
|
|
185
|
+
RuntimeError: If the server doesn't become healthy in time.
|
|
186
|
+
"""
|
|
187
|
+
import httpx
|
|
188
|
+
|
|
189
|
+
poll_interval = (
|
|
190
|
+
_HEALTH_POLL_INTERVAL_LOCAL if local else _HEALTH_POLL_INTERVAL_REMOTE
|
|
191
|
+
)
|
|
192
|
+
health_url = f"{url}/ok"
|
|
193
|
+
deadline = time.monotonic() + timeout
|
|
194
|
+
last_status: int | None = None
|
|
195
|
+
last_exc: Exception | None = None
|
|
196
|
+
|
|
197
|
+
async with httpx.AsyncClient() as client:
|
|
198
|
+
while time.monotonic() < deadline:
|
|
199
|
+
if process and process.poll() is not None:
|
|
200
|
+
output = read_log() if read_log else ""
|
|
201
|
+
msg = f"Server process exited with code {process.returncode}"
|
|
202
|
+
if output:
|
|
203
|
+
msg += f"\n{output[-3000:]}"
|
|
204
|
+
raise RuntimeError(msg)
|
|
205
|
+
|
|
206
|
+
try:
|
|
207
|
+
resp = await client.get(health_url, timeout=2)
|
|
208
|
+
if resp.status_code == 200: # noqa: PLR2004
|
|
209
|
+
logger.info("Server is healthy at %s", url)
|
|
210
|
+
return
|
|
211
|
+
last_status = resp.status_code
|
|
212
|
+
logger.debug("Health check returned status %d", resp.status_code)
|
|
213
|
+
except (httpx.TransportError, OSError) as exc:
|
|
214
|
+
logger.debug("Health check attempt failed: %s", exc)
|
|
215
|
+
last_exc = exc
|
|
216
|
+
|
|
217
|
+
await asyncio.sleep(poll_interval)
|
|
218
|
+
|
|
219
|
+
msg = f"Server did not become healthy within {timeout}s"
|
|
220
|
+
if last_status is not None:
|
|
221
|
+
msg += f" (last status: {last_status})"
|
|
222
|
+
elif last_exc is not None:
|
|
223
|
+
msg += f" (last error: {last_exc})"
|
|
224
|
+
raise RuntimeError(msg)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# ---------------------------------------------------------------------------
|
|
228
|
+
# Server command / env construction
|
|
229
|
+
# ---------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _build_server_cmd(config_path: Path, *, host: str, port: int) -> list[str]:
|
|
233
|
+
"""Build the `langgraph dev` command line.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
config_path: Path to the `langgraph.json` config file.
|
|
237
|
+
host: Host to bind.
|
|
238
|
+
port: Port to bind.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
Command argv list.
|
|
242
|
+
"""
|
|
243
|
+
return [
|
|
244
|
+
sys.executable,
|
|
245
|
+
"-m",
|
|
246
|
+
"langgraph_cli",
|
|
247
|
+
"dev",
|
|
248
|
+
"--host",
|
|
249
|
+
host,
|
|
250
|
+
"--port",
|
|
251
|
+
str(port),
|
|
252
|
+
"--no-browser",
|
|
253
|
+
"--no-reload",
|
|
254
|
+
"--config",
|
|
255
|
+
str(config_path),
|
|
256
|
+
]
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _build_server_env() -> dict[str, str]:
|
|
260
|
+
"""Build the environment dict for the server subprocess.
|
|
261
|
+
|
|
262
|
+
Copies `os.environ`, sets required flags, and strips auth-related variables
|
|
263
|
+
that are not needed (and could interfere) for the local dev server.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
Environment dict for `subprocess.Popen`.
|
|
267
|
+
"""
|
|
268
|
+
env = os.environ.copy()
|
|
269
|
+
env["PYTHONDONTWRITEBYTECODE"] = "1"
|
|
270
|
+
env["LANGGRAPH_AUTH_TYPE"] = "noop"
|
|
271
|
+
for key in (
|
|
272
|
+
"LANGGRAPH_AUTH",
|
|
273
|
+
"LANGGRAPH_CLOUD_LICENSE_KEY",
|
|
274
|
+
"LANGSMITH_CONTROL_PLANE_API_KEY",
|
|
275
|
+
"LANGSMITH_TENANT_ID",
|
|
276
|
+
):
|
|
277
|
+
env.pop(key, None)
|
|
278
|
+
return env
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
# ---------------------------------------------------------------------------
|
|
282
|
+
# ServerProcess
|
|
283
|
+
# ---------------------------------------------------------------------------
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class ServerProcess:
|
|
287
|
+
"""Manages a `langgraph dev` server subprocess.
|
|
288
|
+
|
|
289
|
+
Focuses on subprocess lifecycle (start, stop, restart) and health checking.
|
|
290
|
+
Env-var management for restarts (e.g. configuration changes requiring a full
|
|
291
|
+
restart) is handled by `_scoped_env_overrides`, keeping this class focused
|
|
292
|
+
on process management.
|
|
293
|
+
"""
|
|
294
|
+
|
|
295
|
+
def __init__(
|
|
296
|
+
self,
|
|
297
|
+
*,
|
|
298
|
+
host: str = _DEFAULT_HOST,
|
|
299
|
+
port: int = _DEFAULT_PORT,
|
|
300
|
+
config_dir: str | Path | None = None,
|
|
301
|
+
owns_config_dir: bool = False,
|
|
302
|
+
) -> None:
|
|
303
|
+
"""Initialize server process manager.
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
host: Host to bind the server to.
|
|
307
|
+
port: Initial port to bind the server to.
|
|
308
|
+
|
|
309
|
+
May be reassigned automatically by `start()` if the port is
|
|
310
|
+
already in use.
|
|
311
|
+
config_dir: Directory containing `langgraph.json`.
|
|
312
|
+
owns_config_dir: When `True`, the server will delete `config_dir`
|
|
313
|
+
on `stop()`.
|
|
314
|
+
"""
|
|
315
|
+
self.host = host
|
|
316
|
+
self.port = port
|
|
317
|
+
self.config_dir = Path(config_dir) if config_dir else None
|
|
318
|
+
self._owns_config_dir = owns_config_dir
|
|
319
|
+
self._process: subprocess.Popen | None = None
|
|
320
|
+
self._temp_dir: tempfile.TemporaryDirectory | None = None
|
|
321
|
+
self._log_file: tempfile.NamedTemporaryFile | None = None # type: ignore[type-arg]
|
|
322
|
+
self._env_overrides: dict[str, str] = {}
|
|
323
|
+
|
|
324
|
+
@property
|
|
325
|
+
def url(self) -> str:
|
|
326
|
+
"""Server base URL."""
|
|
327
|
+
return get_server_url(self.host, self.port)
|
|
328
|
+
|
|
329
|
+
@property
|
|
330
|
+
def running(self) -> bool:
|
|
331
|
+
"""Whether the server process is running."""
|
|
332
|
+
return self._process is not None and self._process.poll() is None
|
|
333
|
+
|
|
334
|
+
def _read_log_file(self) -> str:
|
|
335
|
+
"""Read the server log file contents.
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
Log file contents as a string (may be empty).
|
|
339
|
+
"""
|
|
340
|
+
if self._log_file is None:
|
|
341
|
+
return ""
|
|
342
|
+
try:
|
|
343
|
+
self._log_file.flush()
|
|
344
|
+
return Path(self._log_file.name).read_text(
|
|
345
|
+
encoding="utf-8", errors="replace"
|
|
346
|
+
)
|
|
347
|
+
except OSError:
|
|
348
|
+
logger.warning(
|
|
349
|
+
"Failed to read server log file %s",
|
|
350
|
+
self._log_file.name,
|
|
351
|
+
exc_info=True,
|
|
352
|
+
)
|
|
353
|
+
return ""
|
|
354
|
+
|
|
355
|
+
async def start(
|
|
356
|
+
self,
|
|
357
|
+
*,
|
|
358
|
+
timeout: float = _HEALTH_TIMEOUT, # noqa: ASYNC109
|
|
359
|
+
) -> None:
|
|
360
|
+
"""Start the `langgraph dev` server and wait for it to be healthy.
|
|
361
|
+
|
|
362
|
+
Args:
|
|
363
|
+
timeout: Max seconds to wait for the server to become healthy.
|
|
364
|
+
|
|
365
|
+
Raises:
|
|
366
|
+
RuntimeError: If the server fails to start or become healthy.
|
|
367
|
+
"""
|
|
368
|
+
if self.running:
|
|
369
|
+
return
|
|
370
|
+
|
|
371
|
+
work_dir = self.config_dir
|
|
372
|
+
if work_dir is None:
|
|
373
|
+
self._temp_dir = tempfile.TemporaryDirectory(prefix="docagent_server_")
|
|
374
|
+
work_dir = Path(self._temp_dir.name)
|
|
375
|
+
|
|
376
|
+
config_path = work_dir / "langgraph.json"
|
|
377
|
+
if not config_path.exists():
|
|
378
|
+
msg = (
|
|
379
|
+
f"langgraph.json not found in {work_dir}. "
|
|
380
|
+
"Call generate_langgraph_json() first."
|
|
381
|
+
)
|
|
382
|
+
raise RuntimeError(msg)
|
|
383
|
+
|
|
384
|
+
if _port_in_use(self.host, self.port):
|
|
385
|
+
self.port = _find_free_port(self.host)
|
|
386
|
+
logger.info("Default port in use, using port %d instead", self.port)
|
|
387
|
+
|
|
388
|
+
cmd = _build_server_cmd(config_path, host=self.host, port=self.port)
|
|
389
|
+
env = _build_server_env()
|
|
390
|
+
|
|
391
|
+
logger.info("Starting langgraph dev server: %s", " ".join(cmd))
|
|
392
|
+
self._log_file = tempfile.NamedTemporaryFile( # noqa: SIM115
|
|
393
|
+
prefix="docagent_server_log_",
|
|
394
|
+
suffix=".txt",
|
|
395
|
+
delete=False,
|
|
396
|
+
mode="w",
|
|
397
|
+
encoding="utf-8",
|
|
398
|
+
)
|
|
399
|
+
self._process = subprocess.Popen( # noqa: S603, ASYNC220
|
|
400
|
+
cmd,
|
|
401
|
+
cwd=str(work_dir),
|
|
402
|
+
env=env,
|
|
403
|
+
stdout=self._log_file,
|
|
404
|
+
stderr=subprocess.STDOUT,
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
try:
|
|
408
|
+
await wait_for_server_healthy(
|
|
409
|
+
self.url,
|
|
410
|
+
timeout=timeout,
|
|
411
|
+
process=self._process,
|
|
412
|
+
read_log=self._read_log_file,
|
|
413
|
+
local=True,
|
|
414
|
+
)
|
|
415
|
+
except Exception:
|
|
416
|
+
self.stop()
|
|
417
|
+
raise
|
|
418
|
+
|
|
419
|
+
def _stop_process(self) -> None:
|
|
420
|
+
"""Stop only the server subprocess and its log file.
|
|
421
|
+
|
|
422
|
+
Unlike `stop()`, this does NOT clean up the config directory or temp
|
|
423
|
+
directory, so the server can be restarted with the same config.
|
|
424
|
+
"""
|
|
425
|
+
if self._process is None:
|
|
426
|
+
return
|
|
427
|
+
|
|
428
|
+
if self._process.poll() is None:
|
|
429
|
+
logger.info("Stopping langgraph dev server (pid=%d)", self._process.pid)
|
|
430
|
+
try:
|
|
431
|
+
self._process.send_signal(signal.SIGTERM)
|
|
432
|
+
self._process.wait(timeout=_SHUTDOWN_TIMEOUT)
|
|
433
|
+
except subprocess.TimeoutExpired:
|
|
434
|
+
logger.warning("Server did not stop gracefully, killing")
|
|
435
|
+
self._process.kill()
|
|
436
|
+
try:
|
|
437
|
+
self._process.wait(timeout=2)
|
|
438
|
+
except subprocess.TimeoutExpired:
|
|
439
|
+
logger.warning(
|
|
440
|
+
"Server process pid=%d did not exit after SIGKILL",
|
|
441
|
+
self._process.pid,
|
|
442
|
+
)
|
|
443
|
+
except OSError:
|
|
444
|
+
logger.warning("Error stopping server", exc_info=True)
|
|
445
|
+
|
|
446
|
+
self._process = None
|
|
447
|
+
|
|
448
|
+
if self._log_file is not None:
|
|
449
|
+
try:
|
|
450
|
+
self._log_file.close()
|
|
451
|
+
Path(self._log_file.name).unlink()
|
|
452
|
+
except OSError:
|
|
453
|
+
logger.debug("Failed to clean up log file", exc_info=True)
|
|
454
|
+
self._log_file = None
|
|
455
|
+
|
|
456
|
+
def stop(self) -> None:
|
|
457
|
+
"""Stop the server process and clean up all resources."""
|
|
458
|
+
self._stop_process()
|
|
459
|
+
|
|
460
|
+
if self._temp_dir is not None:
|
|
461
|
+
try:
|
|
462
|
+
self._temp_dir.cleanup()
|
|
463
|
+
except OSError:
|
|
464
|
+
logger.debug("Failed to clean up temp dir", exc_info=True)
|
|
465
|
+
self._temp_dir = None
|
|
466
|
+
|
|
467
|
+
if self._owns_config_dir and self.config_dir is not None:
|
|
468
|
+
import shutil
|
|
469
|
+
|
|
470
|
+
try:
|
|
471
|
+
shutil.rmtree(self.config_dir)
|
|
472
|
+
except OSError:
|
|
473
|
+
logger.debug(
|
|
474
|
+
"Failed to clean up config dir %s", self.config_dir, exc_info=True
|
|
475
|
+
)
|
|
476
|
+
self._owns_config_dir = False
|
|
477
|
+
|
|
478
|
+
def update_env(self, **overrides: str) -> None:
|
|
479
|
+
"""Stage env var overrides to apply on the next `restart()`.
|
|
480
|
+
|
|
481
|
+
These are applied to `os.environ` immediately before the subprocess
|
|
482
|
+
starts, keeping mutation scoped to the restart call.
|
|
483
|
+
|
|
484
|
+
Args:
|
|
485
|
+
**overrides: Key/value env var pairs
|
|
486
|
+
(e.g., `DEEPAGENTS_CLI_SERVER_MODEL="anthropic:claude-sonnet-4-6"`).
|
|
487
|
+
"""
|
|
488
|
+
self._env_overrides.update(overrides)
|
|
489
|
+
|
|
490
|
+
async def restart(self, *, timeout: float = _HEALTH_TIMEOUT) -> None: # noqa: ASYNC109
|
|
491
|
+
"""Restart the server process, reusing the existing config directory.
|
|
492
|
+
|
|
493
|
+
Stops the subprocess, then starts a new one. Any env overrides staged
|
|
494
|
+
via `update_env()` are applied within a `_scoped_env_overrides` context
|
|
495
|
+
manager so that failures automatically roll back the environment to the
|
|
496
|
+
last known-good state.
|
|
497
|
+
|
|
498
|
+
Args:
|
|
499
|
+
timeout: Max seconds to wait for the server to become healthy.
|
|
500
|
+
"""
|
|
501
|
+
logger.info("Restarting langgraph dev server")
|
|
502
|
+
self._stop_process()
|
|
503
|
+
|
|
504
|
+
with _scoped_env_overrides(self._env_overrides):
|
|
505
|
+
await self.start(timeout=timeout)
|
|
506
|
+
|
|
507
|
+
self._env_overrides.clear()
|
|
508
|
+
|
|
509
|
+
async def __aenter__(self) -> Self:
|
|
510
|
+
"""Async context manager entry.
|
|
511
|
+
|
|
512
|
+
Returns:
|
|
513
|
+
The server process instance.
|
|
514
|
+
"""
|
|
515
|
+
await self.start()
|
|
516
|
+
return self
|
|
517
|
+
|
|
518
|
+
async def __aexit__(self, *args: object) -> None:
|
|
519
|
+
"""Async context manager exit."""
|
|
520
|
+
self.stop()
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""Server-side graph entry point for `langgraph dev`.
|
|
2
|
+
|
|
3
|
+
This module is referenced by the generated `langgraph.json` and exposes the CLI
|
|
4
|
+
agent graph as a module-level variable that the LangGraph server can load
|
|
5
|
+
and serve.
|
|
6
|
+
|
|
7
|
+
The graph is created at module import time via `make_graph()`, which reads
|
|
8
|
+
configuration from `ServerConfig.from_env()` — the same dataclass the CLI uses
|
|
9
|
+
to *write* the configuration via `ServerConfig.to_env()`. This shared schema
|
|
10
|
+
ensures the two sides stay in sync.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import atexit
|
|
16
|
+
import logging
|
|
17
|
+
import sys
|
|
18
|
+
import traceback
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from docagent_cli._server_config import ServerConfig
|
|
22
|
+
from docagent_cli.project_utils import ProjectContext, get_server_project_context
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
# Module-level sandbox state kept alive for the server process lifetime.
|
|
27
|
+
_sandbox_cm: Any = None
|
|
28
|
+
_sandbox_backend: Any = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _build_tools(
|
|
32
|
+
config: ServerConfig,
|
|
33
|
+
project_context: ProjectContext | None,
|
|
34
|
+
) -> tuple[list[Any], list[Any] | None]:
|
|
35
|
+
"""Assemble the tool list based on server config.
|
|
36
|
+
|
|
37
|
+
Loads built-in tools (conditionally including web search when Tavily is
|
|
38
|
+
available) and MCP tools when enabled.
|
|
39
|
+
|
|
40
|
+
MCP discovery runs synchronously via `asyncio.run` because this function is
|
|
41
|
+
called during module-level graph construction (before the server's async
|
|
42
|
+
event loop is available).
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
config: Deserialized server configuration.
|
|
46
|
+
project_context: Resolved project context for MCP discovery.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Tuple of `(tools, mcp_server_info)`.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
FileNotFoundError: If the MCP config file is not found.
|
|
53
|
+
RuntimeError: If MCP tool loading fails.
|
|
54
|
+
"""
|
|
55
|
+
from docagent_cli.config import settings
|
|
56
|
+
from docagent_cli.tools import fetch_url, http_request, web_search
|
|
57
|
+
|
|
58
|
+
tools: list[Any] = [fetch_url, http_request]
|
|
59
|
+
if settings.has_tavily:
|
|
60
|
+
tools.append(web_search)
|
|
61
|
+
|
|
62
|
+
mcp_server_info: list[Any] | None = None
|
|
63
|
+
if not config.no_mcp:
|
|
64
|
+
import asyncio
|
|
65
|
+
|
|
66
|
+
from docagent_cli.mcp_tools import resolve_and_load_mcp_tools
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
mcp_tools, _, mcp_server_info = asyncio.run(
|
|
70
|
+
resolve_and_load_mcp_tools(
|
|
71
|
+
explicit_config_path=config.mcp_config_path,
|
|
72
|
+
no_mcp=config.no_mcp,
|
|
73
|
+
trust_project_mcp=config.trust_project_mcp,
|
|
74
|
+
project_context=project_context,
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
except FileNotFoundError:
|
|
78
|
+
logger.exception("MCP config file not found: %s", config.mcp_config_path)
|
|
79
|
+
raise
|
|
80
|
+
except RuntimeError:
|
|
81
|
+
logger.exception(
|
|
82
|
+
"Failed to load MCP tools (config: %s)", config.mcp_config_path
|
|
83
|
+
)
|
|
84
|
+
raise
|
|
85
|
+
|
|
86
|
+
tools.extend(mcp_tools)
|
|
87
|
+
if mcp_tools:
|
|
88
|
+
logger.info("Loaded %d MCP tool(s)", len(mcp_tools))
|
|
89
|
+
|
|
90
|
+
return tools, mcp_server_info
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def make_graph() -> Any: # noqa: ANN401
|
|
94
|
+
"""Create the CLI agent graph from environment-based configuration.
|
|
95
|
+
|
|
96
|
+
Reads `DEEPAGENTS_CLI_SERVER_*` env vars via `ServerConfig.from_env()`
|
|
97
|
+
(the inverse of `ServerConfig.to_env()` used by the CLI process), resolves a
|
|
98
|
+
model, assembles tools, and compiles the agent graph.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Compiled LangGraph agent graph.
|
|
102
|
+
"""
|
|
103
|
+
config = ServerConfig.from_env()
|
|
104
|
+
project_context = get_server_project_context()
|
|
105
|
+
|
|
106
|
+
from docagent_cli.agent import create_cli_agent, load_async_subagents
|
|
107
|
+
from docagent_cli.config import create_model, settings
|
|
108
|
+
|
|
109
|
+
if project_context is not None:
|
|
110
|
+
settings.reload_from_environment(start_path=project_context.user_cwd)
|
|
111
|
+
|
|
112
|
+
result = create_model(config.model, extra_kwargs=config.model_params)
|
|
113
|
+
result.apply_to_settings()
|
|
114
|
+
|
|
115
|
+
tools, mcp_server_info = _build_tools(config, project_context)
|
|
116
|
+
|
|
117
|
+
# Create sandbox backend if a sandbox provider is configured.
|
|
118
|
+
# The context manager is held open at module level and cleaned up via
|
|
119
|
+
# atexit so the sandbox lives for the entire server process lifetime.
|
|
120
|
+
global _sandbox_cm, _sandbox_backend # noqa: PLW0603
|
|
121
|
+
sandbox_backend = None
|
|
122
|
+
if config.sandbox_type:
|
|
123
|
+
from docagent_cli.integrations.sandbox_factory import create_sandbox
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
_sandbox_cm = create_sandbox(
|
|
127
|
+
config.sandbox_type,
|
|
128
|
+
sandbox_id=config.sandbox_id,
|
|
129
|
+
setup_script_path=config.sandbox_setup,
|
|
130
|
+
)
|
|
131
|
+
_sandbox_backend = _sandbox_cm.__enter__() # noqa: PLC2801 # Context manager kept open for server process lifetime
|
|
132
|
+
sandbox_backend = _sandbox_backend
|
|
133
|
+
|
|
134
|
+
def _cleanup_sandbox() -> None:
|
|
135
|
+
if _sandbox_cm is not None:
|
|
136
|
+
_sandbox_cm.__exit__(None, None, None)
|
|
137
|
+
|
|
138
|
+
atexit.register(_cleanup_sandbox)
|
|
139
|
+
except ImportError:
|
|
140
|
+
logger.exception(
|
|
141
|
+
"Sandbox provider '%s' is not installed", config.sandbox_type
|
|
142
|
+
)
|
|
143
|
+
print( # noqa: T201 # stderr fallback — logger may not reach parent process
|
|
144
|
+
f"Sandbox provider '{config.sandbox_type}' is not installed",
|
|
145
|
+
file=sys.stderr,
|
|
146
|
+
)
|
|
147
|
+
sys.exit(1)
|
|
148
|
+
except NotImplementedError:
|
|
149
|
+
logger.exception("Sandbox type '%s' is not supported", config.sandbox_type)
|
|
150
|
+
print( # noqa: T201 # stderr fallback — logger may not reach parent process
|
|
151
|
+
f"Sandbox type '{config.sandbox_type}' is not supported",
|
|
152
|
+
file=sys.stderr,
|
|
153
|
+
)
|
|
154
|
+
sys.exit(1)
|
|
155
|
+
except Exception as exc:
|
|
156
|
+
logger.exception("Sandbox creation failed for '%s'", config.sandbox_type)
|
|
157
|
+
print( # noqa: T201 # stderr fallback — logger may not reach parent process
|
|
158
|
+
f"Sandbox creation failed for '{config.sandbox_type}': {exc}",
|
|
159
|
+
file=sys.stderr,
|
|
160
|
+
)
|
|
161
|
+
sys.exit(1)
|
|
162
|
+
|
|
163
|
+
async_subagents = load_async_subagents() or None
|
|
164
|
+
|
|
165
|
+
agent, _ = create_cli_agent(
|
|
166
|
+
model=result.model,
|
|
167
|
+
assistant_id=config.assistant_id,
|
|
168
|
+
tools=tools,
|
|
169
|
+
sandbox=sandbox_backend,
|
|
170
|
+
sandbox_type=config.sandbox_type,
|
|
171
|
+
system_prompt=config.system_prompt,
|
|
172
|
+
interactive=config.interactive,
|
|
173
|
+
auto_approve=config.auto_approve,
|
|
174
|
+
interrupt_shell_only=config.interrupt_shell_only,
|
|
175
|
+
shell_allow_list=config.shell_allow_list,
|
|
176
|
+
enable_ask_user=config.enable_ask_user,
|
|
177
|
+
enable_memory=config.enable_memory,
|
|
178
|
+
enable_skills=config.enable_skills,
|
|
179
|
+
enable_shell=config.enable_shell,
|
|
180
|
+
mcp_server_info=mcp_server_info,
|
|
181
|
+
cwd=project_context.user_cwd if project_context is not None else config.cwd,
|
|
182
|
+
project_context=project_context,
|
|
183
|
+
async_subagents=async_subagents,
|
|
184
|
+
)
|
|
185
|
+
return agent
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
graph = make_graph()
|
|
190
|
+
except Exception as exc:
|
|
191
|
+
logger.critical("Failed to initialize server graph", exc_info=True)
|
|
192
|
+
print( # noqa: T201 # stderr fallback — logger may not reach parent process
|
|
193
|
+
f"Failed to initialize server graph: {exc}\n{traceback.format_exc()}",
|
|
194
|
+
file=sys.stderr,
|
|
195
|
+
)
|
|
196
|
+
sys.exit(1)
|