deepagents-cli 0.0.36__tar.gz → 0.0.37__tar.gz
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.
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/.gitignore +3 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/CHANGELOG.md +13 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/PKG-INFO +2 -2
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_version.py +1 -1
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/app.py +1 -1
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/config.py +3 -1
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/__init__.py +3 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/bundler.py +34 -21
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/commands.py +61 -48
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/config.py +60 -30
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/deploy/templates.py +20 -43
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/integrations/sandbox_factory.py +5 -2
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/model_config.py +2 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/pyproject.toml +2 -2
- deepagents_cli-0.0.37/tests/unit_tests/deploy/test_bundler.py +245 -0
- deepagents_cli-0.0.37/tests/unit_tests/deploy/test_commands.py +75 -0
- deepagents_cli-0.0.37/tests/unit_tests/deploy/test_config.py +302 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_config.py +4 -4
- deepagents_cli-0.0.37/tests/unit_tests/tools/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/uv.lock +2 -2
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/DEV.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/Makefile +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/README.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/THREAT_MODEL.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/__main__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_ask_user_types.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_cli_context.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_debug.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_env_vars.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_server_config.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_session_stats.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/_testing_models.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/agent.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/app.tcss +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/ask_user.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/remember/SKILL.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/clipboard.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/command_registry.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/configurable_model.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/default_agent_prompt.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/editor.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/file_ops.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/formatting.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/hooks.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/input.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/integrations/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/integrations/sandbox_provider.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/local_context.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/main.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/mcp_tools.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/mcp_trust.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/media_utils.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/non_interactive.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/offload.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/output.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/project_utils.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/py.typed +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/remote_client.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/server.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/server_graph.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/server_manager.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/sessions.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/skills/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/skills/commands.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/skills/invocation.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/skills/load.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/subagents.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/system_prompt.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/textual_adapter.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/theme.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/token_state.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/tool_display.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/tools.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/ui.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/unicode_security.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/update_check.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/_links.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/approval.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/ask_user.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/autocomplete.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/chat_input.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/diff.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/history.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/loading.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/mcp_viewer.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/message_store.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/messages.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/model_selector.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/notification_settings.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/status.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/theme_selector.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/thread_selector.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/tool_renderers.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/tool_widgets.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/deepagents_cli/widgets/welcome.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/arxiv-search/SKILL.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/examples/skills/web-research/SKILL.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/images/cli.png +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/scripts/check_imports.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/scripts/debug_server.sh +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/scripts/install.sh +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/README.md +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/conftest.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/test_acp_mode.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/test_compact_resume.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/conftest.py +0 -0
- {deepagents_cli-0.0.36/tests/unit_tests/tools → deepagents_cli-0.0.37/tests/unit_tests/deploy}/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/skills/__init__.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/skills/test_commands.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/skills/test_load.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_agent.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_agent_friendly.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_app.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_approval.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_args.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_ask_user.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_ask_user_middleware.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_autocomplete.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_charset.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_chat_input.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_command_registry.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_compact_tool.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_configurable_model.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_debug.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_editor.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_end_to_end.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_env_vars.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_exception_handling.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_file_ops.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_history.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_hooks.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_imports.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_input_parsing.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_links.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_loading.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_local_context.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_main.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_main_args.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_mcp_tools.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_mcp_trust.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_mcp_viewer.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_media_utils.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_message_store.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_messages.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_model_config.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_model_selector.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_model_switch.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_non_interactive.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_offload.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_output.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_reload.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_remote_client.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server_config.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server_graph.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server_helpers.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_server_manager.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_sessions.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_skill_invocation.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_status.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_subagents.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_textual_adapter.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_theme.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_thread_selector.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_token_tracker.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_ui.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_unicode_security.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_update_check.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_version.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/test_welcome.py +0 -0
- {deepagents_cli-0.0.36 → deepagents_cli-0.0.37}/tests/unit_tests/tools/test_fetch_url.py +0 -0
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.37](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.36...deepagents-cli==0.0.37) (2026-04-10)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* Permissions for `deepagents deploy` ([#2651](https://github.com/langchain-ai/deepagents/issues/2651)) ([5d93b73](https://github.com/langchain-ai/deepagents/commit/5d93b736af6ffb165f33569233d533ced95a6943))
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Add missing model provider deps to `deepagents deploy` bundler [closes [#2647](https://github.com/langchain-ai/deepagents/issues/2647)] ([#2660](https://github.com/langchain-ai/deepagents/issues/2660)) ([b710a69](https://github.com/langchain-ai/deepagents/commit/b710a69b12e49479045eaa54dfb709326473500b))
|
|
12
|
+
* `AGENTS.md` in system prompt twice ([#2652](https://github.com/langchain-ai/deepagents/issues/2652)) ([9052be9](https://github.com/langchain-ai/deepagents/commit/9052be98d9f4ef9b11a88c9b1df3fae5e5ac666c))
|
|
13
|
+
* Harden `deepagents deploy` config parsing and add unit tests ([#2636](https://github.com/langchain-ai/deepagents/issues/2636)) ([0469d14](https://github.com/langchain-ai/deepagents/commit/0469d1429d129e604fc1b622263923162f719314))
|
|
14
|
+
* Load `deepagents deploy` project `.env` before deploy/dev config validation ([#2644](https://github.com/langchain-ai/deepagents/issues/2644)) ([8299091](https://github.com/langchain-ai/deepagents/commit/829909166606f8a9d9571b00da725845bad08da7))
|
|
15
|
+
|
|
3
16
|
## [0.0.36](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.35...deepagents-cli==0.0.36) (2026-04-09)
|
|
4
17
|
|
|
5
18
|
### Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.37
|
|
4
4
|
Summary: Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities.
|
|
5
5
|
Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
|
|
6
6
|
Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
|
|
@@ -27,7 +27,7 @@ Classifier: Topic :: Terminals
|
|
|
27
27
|
Requires-Python: <4.0,>=3.11
|
|
28
28
|
Requires-Dist: aiosqlite<1.0.0,>=0.19.0
|
|
29
29
|
Requires-Dist: deepagents-acp>=0.0.4
|
|
30
|
-
Requires-Dist: deepagents==0.5.
|
|
30
|
+
Requires-Dist: deepagents==0.5.2
|
|
31
31
|
Requires-Dist: httpx<1.0.0,>=0.28.1
|
|
32
32
|
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.0
|
|
33
33
|
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Version information and lightweight constants for `deepagents-cli`."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.0.
|
|
3
|
+
__version__ = "0.0.37" # x-release-please-version
|
|
4
4
|
|
|
5
5
|
DOCS_URL = "https://docs.langchain.com/oss/python/deepagents/cli"
|
|
6
6
|
"""URL for `deepagents-cli` documentation."""
|
|
@@ -1478,7 +1478,7 @@ class DeepAgentsApp(App):
|
|
|
1478
1478
|
cmd = upgrade_command()
|
|
1479
1479
|
self.notify(
|
|
1480
1480
|
f"Update available: v{latest} (current: v{cli_version}). "
|
|
1481
|
-
f"Run: {cmd}\n"
|
|
1481
|
+
f"Run: {cmd}\n\n"
|
|
1482
1482
|
f"Enable auto-updates: /auto-update",
|
|
1483
1483
|
severity="information",
|
|
1484
1484
|
timeout=15,
|
|
@@ -1937,7 +1937,9 @@ def _get_provider_kwargs(
|
|
|
1937
1937
|
result["api_key"] = api_key
|
|
1938
1938
|
|
|
1939
1939
|
if provider == "openrouter":
|
|
1940
|
-
from deepagents.
|
|
1940
|
+
from deepagents.profiles._openrouter import (
|
|
1941
|
+
check_openrouter_version, # noqa: PLC2701
|
|
1942
|
+
)
|
|
1941
1943
|
|
|
1942
1944
|
check_openrouter_version()
|
|
1943
1945
|
_apply_openrouter_defaults(result)
|
|
@@ -6,8 +6,11 @@ from deepagents_cli.deploy.commands import (
|
|
|
6
6
|
execute_init_command,
|
|
7
7
|
setup_deploy_parsers,
|
|
8
8
|
)
|
|
9
|
+
from deepagents_cli.deploy.config import SandboxProvider, SandboxScope
|
|
9
10
|
|
|
10
11
|
__all__ = [
|
|
12
|
+
"SandboxProvider",
|
|
13
|
+
"SandboxScope",
|
|
11
14
|
"execute_deploy_command",
|
|
12
15
|
"execute_dev_command",
|
|
13
16
|
"execute_init_command",
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
Reads the canonical project layout:
|
|
4
4
|
|
|
5
5
|
```txt
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
<project>/
|
|
7
|
+
deepagents.toml # required — agent + sandbox config
|
|
8
|
+
AGENTS.md # required — system prompt + seeded memory
|
|
9
|
+
.env # optional — environment variables
|
|
10
|
+
mcp.json # optional — HTTP/SSE MCP servers
|
|
11
|
+
skills/ # optional — auto-seeded into skills namespace
|
|
11
12
|
```
|
|
12
13
|
|
|
13
14
|
...and writes everything `langgraph deploy` needs to a build directory.
|
|
@@ -35,13 +36,22 @@ from deepagents_cli.deploy.templates import (
|
|
|
35
36
|
|
|
36
37
|
logger = logging.getLogger(__name__)
|
|
37
38
|
|
|
38
|
-
_MODEL_PROVIDER_DEPS = {
|
|
39
|
+
_MODEL_PROVIDER_DEPS: dict[str, str] = {
|
|
39
40
|
"anthropic": "langchain-anthropic",
|
|
40
|
-
"
|
|
41
|
+
"azure_openai": "langchain-openai",
|
|
42
|
+
"baseten": "langchain-baseten",
|
|
43
|
+
"cohere": "langchain-cohere",
|
|
44
|
+
"deepseek": "langchain-deepseek",
|
|
45
|
+
"fireworks": "langchain-fireworks",
|
|
41
46
|
"google_genai": "langchain-google-genai",
|
|
42
47
|
"google_vertexai": "langchain-google-vertexai",
|
|
43
48
|
"groq": "langchain-groq",
|
|
44
49
|
"mistralai": "langchain-mistralai",
|
|
50
|
+
"nvidia": "langchain-nvidia-ai-endpoints",
|
|
51
|
+
"openai": "langchain-openai",
|
|
52
|
+
"openrouter": "langchain-openrouter",
|
|
53
|
+
"perplexity": "langchain-perplexity",
|
|
54
|
+
"xai": "langchain-xai",
|
|
45
55
|
}
|
|
46
56
|
"""Dependencies inferred from a provider: prefix on the model string."""
|
|
47
57
|
|
|
@@ -76,8 +86,8 @@ def bundle(
|
|
|
76
86
|
shutil.copy2(project_root / MCP_FILENAME, build_dir / "_mcp.json")
|
|
77
87
|
logger.info("Copied %s → _mcp.json", MCP_FILENAME)
|
|
78
88
|
|
|
79
|
-
# 3b. Copy .env from the project root if present (
|
|
80
|
-
# deepagents.toml
|
|
89
|
+
# 3b. Copy .env from the project root if present (alongside
|
|
90
|
+
# deepagents.toml). The bundler skips .env when
|
|
81
91
|
# building the seed payload so secrets never land in _seed.json.
|
|
82
92
|
env_src = project_root / ".env"
|
|
83
93
|
env_present = env_src.is_file()
|
|
@@ -87,7 +97,7 @@ def bundle(
|
|
|
87
97
|
|
|
88
98
|
# 4. Render deploy_graph.py.
|
|
89
99
|
(build_dir / "deploy_graph.py").write_text(
|
|
90
|
-
_render_deploy_graph(config,
|
|
100
|
+
_render_deploy_graph(config, mcp_present=mcp_present),
|
|
91
101
|
encoding="utf-8",
|
|
92
102
|
)
|
|
93
103
|
logger.info("Generated deploy_graph.py")
|
|
@@ -118,17 +128,18 @@ def _build_seed(
|
|
|
118
128
|
|
|
119
129
|
```txt
|
|
120
130
|
{
|
|
121
|
-
"memories": { "AGENTS.md": "..." },
|
|
122
|
-
"skills": { "
|
|
131
|
+
"memories": { "/AGENTS.md": "..." },
|
|
132
|
+
"skills": { "/<skill>/SKILL.md": "...", ... }
|
|
123
133
|
}
|
|
124
134
|
```
|
|
125
135
|
|
|
126
|
-
`memories` always contains
|
|
127
|
-
via `/memories/AGENTS.md`.
|
|
128
|
-
by `
|
|
136
|
+
`memories` always contains `/AGENTS.md` — the middleware loads it at
|
|
137
|
+
startup via `/memories/AGENTS.md`. Agent reads of `/memories/` and
|
|
138
|
+
`/skills/` are denied by `FilesystemPermission` rules.
|
|
129
139
|
|
|
130
|
-
`skills` walks `
|
|
131
|
-
skills dir; the runtime namespace handles the
|
|
140
|
+
`skills` walks `skills/` if present. Keys are paths relative to the
|
|
141
|
+
skills dir with a leading slash; the runtime namespace handles the
|
|
142
|
+
scoping.
|
|
132
143
|
"""
|
|
133
144
|
# Keys must match what CompositeBackend passes to the mounted
|
|
134
145
|
# StoreBackend after stripping the route prefix: for a read of
|
|
@@ -149,7 +160,6 @@ def _build_seed(
|
|
|
149
160
|
|
|
150
161
|
def _render_deploy_graph(
|
|
151
162
|
config: DeployConfig,
|
|
152
|
-
system_prompt: str,
|
|
153
163
|
*,
|
|
154
164
|
mcp_present: bool,
|
|
155
165
|
) -> str:
|
|
@@ -169,7 +179,6 @@ def _render_deploy_graph(
|
|
|
169
179
|
|
|
170
180
|
return DEPLOY_GRAPH_TEMPLATE.format(
|
|
171
181
|
model=config.agent.model,
|
|
172
|
-
system_prompt=system_prompt,
|
|
173
182
|
sandbox_template=config.sandbox.template,
|
|
174
183
|
sandbox_image=config.sandbox.image,
|
|
175
184
|
sandbox_scope=config.sandbox.scope,
|
|
@@ -231,8 +240,12 @@ def print_bundle_summary(config: DeployConfig, build_dir: Path) -> None:
|
|
|
231
240
|
if seed_path.exists():
|
|
232
241
|
try:
|
|
233
242
|
seed = json.loads(seed_path.read_text(encoding="utf-8"))
|
|
234
|
-
except
|
|
235
|
-
|
|
243
|
+
except (json.JSONDecodeError, OSError) as exc:
|
|
244
|
+
logger.warning(
|
|
245
|
+
"Failed to parse %s; summary may be incomplete: %s",
|
|
246
|
+
seed_path,
|
|
247
|
+
exc,
|
|
248
|
+
)
|
|
236
249
|
|
|
237
250
|
print(f"\n Agent: {config.agent.name}")
|
|
238
251
|
print(f" Model: {config.agent.model}")
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
"""CLI commands for `deepagents deploy`.
|
|
1
|
+
"""CLI commands for `deepagents init`, `dev`, and `deploy`.
|
|
2
2
|
|
|
3
|
-
Registered with the CLI via `
|
|
4
|
-
|
|
5
|
-
Commands:
|
|
6
|
-
- `deepagents deploy` — Bundle and deploy to LangGraph Platform
|
|
7
|
-
- `deepagents deploy --dry-run` — Show what would be generated
|
|
8
|
-
- `deepagents init [NAME]` — Scaffold a new deploy project folder
|
|
3
|
+
Registered with the CLI via `setup_deploy_parsers` in `main.py`.
|
|
9
4
|
"""
|
|
10
5
|
|
|
11
6
|
from __future__ import annotations
|
|
@@ -70,7 +65,7 @@ def setup_deploy_parsers(
|
|
|
70
65
|
"--config",
|
|
71
66
|
type=str,
|
|
72
67
|
default=None,
|
|
73
|
-
help="Path to deepagents.toml (default: auto-discovered from cwd
|
|
68
|
+
help="Path to deepagents.toml (default: auto-discovered from cwd)",
|
|
74
69
|
)
|
|
75
70
|
dev_parser.add_argument(
|
|
76
71
|
"--port",
|
|
@@ -100,7 +95,7 @@ def setup_deploy_parsers(
|
|
|
100
95
|
"--config",
|
|
101
96
|
type=str,
|
|
102
97
|
default=None,
|
|
103
|
-
help="Path to deepagents.toml (default: auto-discovered from cwd
|
|
98
|
+
help="Path to deepagents.toml (default: auto-discovered from cwd)",
|
|
104
99
|
)
|
|
105
100
|
deploy_parser.add_argument(
|
|
106
101
|
"--dry-run",
|
|
@@ -197,14 +192,16 @@ def _init_project(*, name: str, force: bool = False) -> None:
|
|
|
197
192
|
]
|
|
198
193
|
|
|
199
194
|
for filename, content in files:
|
|
200
|
-
(project_dir / filename).write_text(content)
|
|
195
|
+
(project_dir / filename).write_text(content, encoding="utf-8")
|
|
201
196
|
|
|
202
197
|
# Create skills/ directory with a starter skill.
|
|
203
198
|
skills_dir = project_dir / SKILLS_DIRNAME
|
|
204
199
|
skills_dir.mkdir(exist_ok=True)
|
|
205
200
|
starter_skill_dir = skills_dir / STARTER_SKILL_NAME
|
|
206
201
|
starter_skill_dir.mkdir(exist_ok=True)
|
|
207
|
-
(starter_skill_dir / "SKILL.md").write_text(
|
|
202
|
+
(starter_skill_dir / "SKILL.md").write_text(
|
|
203
|
+
generate_starter_skill_md(), encoding="utf-8"
|
|
204
|
+
)
|
|
208
205
|
|
|
209
206
|
print(f"Created {name}/ with:")
|
|
210
207
|
for filename, _ in files:
|
|
@@ -227,6 +224,7 @@ def _deploy(
|
|
|
227
224
|
config_path: Path to config file, or `None` for default.
|
|
228
225
|
dry_run: If `True`, generate artifacts but don't deploy.
|
|
229
226
|
"""
|
|
227
|
+
from deepagents_cli.config import _load_dotenv
|
|
230
228
|
from deepagents_cli.deploy.bundler import bundle, print_bundle_summary
|
|
231
229
|
from deepagents_cli.deploy.config import (
|
|
232
230
|
DEFAULT_CONFIG_FILENAME,
|
|
@@ -242,6 +240,11 @@ def _deploy(
|
|
|
242
240
|
cfg_path = discovered or Path.cwd() / DEFAULT_CONFIG_FILENAME
|
|
243
241
|
|
|
244
242
|
project_root = cfg_path.parent
|
|
243
|
+
# Ensure the project .env is loaded into os.environ before validation.
|
|
244
|
+
# The main CLI bootstrap loads .env lazily (on first `settings` access),
|
|
245
|
+
# but deploy/dev commands may never touch `settings`, so the project
|
|
246
|
+
# .env would be missing when _validate_model_credentials checks os.environ.
|
|
247
|
+
_load_dotenv(start_path=project_root)
|
|
245
248
|
|
|
246
249
|
# Load and validate config
|
|
247
250
|
try:
|
|
@@ -262,10 +265,7 @@ def _deploy(
|
|
|
262
265
|
raise SystemExit(1)
|
|
263
266
|
|
|
264
267
|
# Bundle
|
|
265
|
-
|
|
266
|
-
build_dir = Path(tempfile.mkdtemp(prefix="deepagents-deploy-"))
|
|
267
|
-
else:
|
|
268
|
-
build_dir = Path(tempfile.mkdtemp(prefix="deepagents-deploy-"))
|
|
268
|
+
build_dir = Path(tempfile.mkdtemp(prefix="deepagents-deploy-"))
|
|
269
269
|
|
|
270
270
|
try:
|
|
271
271
|
bundle(config, project_root, build_dir)
|
|
@@ -276,14 +276,13 @@ def _deploy(
|
|
|
276
276
|
print(f"Inspect the build directory: {build_dir}")
|
|
277
277
|
return
|
|
278
278
|
|
|
279
|
-
# Deploy via langgraph CLI
|
|
279
|
+
# Deploy via langgraph CLI.
|
|
280
280
|
_run_langgraph_deploy(build_dir, name=config.agent.name)
|
|
281
|
+
finally:
|
|
282
|
+
if not dry_run:
|
|
283
|
+
import shutil
|
|
281
284
|
|
|
282
|
-
|
|
283
|
-
if dry_run:
|
|
284
|
-
# Keep build dir for inspection on dry run
|
|
285
|
-
raise
|
|
286
|
-
raise
|
|
285
|
+
shutil.rmtree(build_dir, ignore_errors=True)
|
|
287
286
|
|
|
288
287
|
|
|
289
288
|
def _dev(
|
|
@@ -298,7 +297,7 @@ def _dev(
|
|
|
298
297
|
served locally instead of pushed to LangGraph Platform. Hot-reloading
|
|
299
298
|
is provided by `langgraph dev` itself watching the build directory;
|
|
300
299
|
edits to the source project (`deepagents.toml`, skills, `AGENTS.md`)
|
|
301
|
-
require re-running `deepagents
|
|
300
|
+
require re-running `deepagents dev` to re-bundle.
|
|
302
301
|
|
|
303
302
|
Args:
|
|
304
303
|
config_path: Path to `deepagents.toml`, or `None` for default.
|
|
@@ -309,6 +308,7 @@ def _dev(
|
|
|
309
308
|
"""
|
|
310
309
|
import shutil
|
|
311
310
|
|
|
311
|
+
from deepagents_cli.config import _load_dotenv
|
|
312
312
|
from deepagents_cli.deploy.bundler import bundle, print_bundle_summary
|
|
313
313
|
from deepagents_cli.deploy.config import (
|
|
314
314
|
DEFAULT_CONFIG_FILENAME,
|
|
@@ -322,12 +322,17 @@ def _dev(
|
|
|
322
322
|
discovered = find_config()
|
|
323
323
|
cfg_path = discovered or Path.cwd() / DEFAULT_CONFIG_FILENAME
|
|
324
324
|
project_root = cfg_path.parent
|
|
325
|
+
# Ensure the project .env is loaded before validation (see _deploy).
|
|
326
|
+
_load_dotenv(start_path=project_root)
|
|
325
327
|
|
|
326
328
|
try:
|
|
327
329
|
config = load_config(cfg_path)
|
|
328
330
|
except FileNotFoundError:
|
|
329
331
|
print(f"Error: Config file not found: {cfg_path}")
|
|
330
332
|
raise SystemExit(1) from None
|
|
333
|
+
except ValueError as e:
|
|
334
|
+
print(f"Error: Invalid config: {e}")
|
|
335
|
+
raise SystemExit(1) from None
|
|
331
336
|
|
|
332
337
|
errors = config.validate(project_root)
|
|
333
338
|
if errors:
|
|
@@ -337,35 +342,43 @@ def _dev(
|
|
|
337
342
|
raise SystemExit(1)
|
|
338
343
|
|
|
339
344
|
build_dir = Path(tempfile.mkdtemp(prefix="deepagents-dev-"))
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
if shutil.which("langgraph") is None:
|
|
344
|
-
print(
|
|
345
|
-
"Error: `langgraph` CLI not found. Install it with:\n"
|
|
346
|
-
" pip install 'langgraph-cli[inmem]'"
|
|
347
|
-
)
|
|
348
|
-
raise SystemExit(1)
|
|
345
|
+
try:
|
|
346
|
+
bundle(config, project_root, build_dir)
|
|
347
|
+
print_bundle_summary(config, build_dir)
|
|
349
348
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
]
|
|
357
|
-
if allow_blocking:
|
|
358
|
-
cmd.append("--allow-blocking")
|
|
349
|
+
if shutil.which("langgraph") is None:
|
|
350
|
+
print(
|
|
351
|
+
"Error: `langgraph` CLI not found. Install it with:\n"
|
|
352
|
+
" pip install 'langgraph-cli[inmem]'"
|
|
353
|
+
)
|
|
354
|
+
raise SystemExit(1)
|
|
359
355
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
356
|
+
cmd = [
|
|
357
|
+
"langgraph",
|
|
358
|
+
"dev",
|
|
359
|
+
"--no-browser",
|
|
360
|
+
"--port",
|
|
361
|
+
str(port),
|
|
362
|
+
]
|
|
363
|
+
if allow_blocking:
|
|
364
|
+
cmd.append("--allow-blocking")
|
|
365
|
+
|
|
366
|
+
print(f"\nStarting langgraph dev on http://localhost:{port}")
|
|
367
|
+
print(f"Build directory: {build_dir}")
|
|
368
|
+
print(f"Running: {' '.join(cmd)}\n")
|
|
369
|
+
|
|
370
|
+
# Pass through stdout/stderr so the user sees dev server logs live.
|
|
371
|
+
try:
|
|
372
|
+
result = subprocess.run(cmd, cwd=str(build_dir), check=False)
|
|
373
|
+
except KeyboardInterrupt:
|
|
374
|
+
print("\nShutting down.")
|
|
375
|
+
return
|
|
363
376
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
377
|
+
if result.returncode != 0:
|
|
378
|
+
print(f"\nDev server exited with error (exit code {result.returncode}).")
|
|
379
|
+
raise SystemExit(result.returncode)
|
|
380
|
+
finally:
|
|
381
|
+
shutil.rmtree(build_dir, ignore_errors=True)
|
|
369
382
|
|
|
370
383
|
|
|
371
384
|
def _run_langgraph_deploy(build_dir: Path, *, name: str) -> None:
|
|
@@ -11,9 +11,9 @@ The new minimal surface has exactly two sections:
|
|
|
11
11
|
read it at runtime, but writes/edits to that path are blocked by a read-only
|
|
12
12
|
middleware in the generated graph.
|
|
13
13
|
|
|
14
|
-
Skills (`
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
Skills (`skills/`) and MCP servers (`mcp.json`) are auto-detected from the
|
|
15
|
+
project layout. The agent's system prompt is read from `AGENTS.md` at bundle
|
|
16
|
+
time — there is no `system_prompt` key.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
from __future__ import annotations
|
|
@@ -23,12 +23,18 @@ import os
|
|
|
23
23
|
import tomllib
|
|
24
24
|
from dataclasses import dataclass, field
|
|
25
25
|
from pathlib import Path
|
|
26
|
-
from typing import Any
|
|
26
|
+
from typing import Any, Literal, get_args
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
""
|
|
28
|
+
SandboxProvider = Literal["none", "daytona", "langsmith", "modal", "runloop"]
|
|
29
|
+
"""Valid sandbox provider identifiers."""
|
|
30
|
+
|
|
31
|
+
SandboxScope = Literal["thread", "assistant"]
|
|
32
|
+
"""Valid sandbox scope values."""
|
|
33
|
+
|
|
34
|
+
VALID_SANDBOX_PROVIDERS: frozenset[str] = frozenset(get_args(SandboxProvider))
|
|
35
|
+
"""Valid sandbox providers for deploy (subset of sandbox_factory, plus `"none"`)."""
|
|
36
|
+
|
|
37
|
+
VALID_SANDBOX_SCOPES: frozenset[str] = frozenset(get_args(SandboxScope))
|
|
32
38
|
|
|
33
39
|
DEFAULT_CONFIG_FILENAME = "deepagents.toml"
|
|
34
40
|
|
|
@@ -40,13 +46,15 @@ MCP_FILENAME = "mcp.json"
|
|
|
40
46
|
|
|
41
47
|
@dataclass(frozen=True)
|
|
42
48
|
class AgentConfig:
|
|
43
|
-
"""
|
|
49
|
+
"""`[agent]` section — core agent identity."""
|
|
44
50
|
|
|
45
51
|
name: str
|
|
46
52
|
model: str = "anthropic:claude-sonnet-4-6"
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
def __post_init__(self) -> None: # noqa: D105 — simple guard, not a public API
|
|
55
|
+
if not self.name.strip():
|
|
56
|
+
msg = "AgentConfig.name must be non-empty"
|
|
57
|
+
raise ValueError(msg)
|
|
50
58
|
|
|
51
59
|
|
|
52
60
|
@dataclass(frozen=True)
|
|
@@ -65,10 +73,10 @@ class SandboxConfig:
|
|
|
65
73
|
same assistant share a single sandbox and its filesystem.
|
|
66
74
|
"""
|
|
67
75
|
|
|
68
|
-
provider:
|
|
76
|
+
provider: SandboxProvider = "none"
|
|
69
77
|
template: str = "deepagents-deploy"
|
|
70
78
|
image: str = "python:3"
|
|
71
|
-
scope:
|
|
79
|
+
scope: SandboxScope = "thread"
|
|
72
80
|
|
|
73
81
|
|
|
74
82
|
@dataclass(frozen=True)
|
|
@@ -82,8 +90,7 @@ class DeployConfig:
|
|
|
82
90
|
"""Validate config against the filesystem.
|
|
83
91
|
|
|
84
92
|
Args:
|
|
85
|
-
project_root: Directory containing `deepagents.toml
|
|
86
|
-
the `src/` dir in the canonical layout).
|
|
93
|
+
project_root: Directory containing `deepagents.toml`.
|
|
87
94
|
|
|
88
95
|
Returns:
|
|
89
96
|
List of validation error strings. Empty if valid.
|
|
@@ -168,13 +175,19 @@ def load_config(config_path: Path) -> DeployConfig:
|
|
|
168
175
|
msg = f"Config file not found: {config_path}"
|
|
169
176
|
raise FileNotFoundError(msg)
|
|
170
177
|
|
|
171
|
-
|
|
172
|
-
|
|
178
|
+
try:
|
|
179
|
+
with config_path.open("rb") as f:
|
|
180
|
+
data = tomllib.load(f)
|
|
181
|
+
except tomllib.TOMLDecodeError as exc:
|
|
182
|
+
msg = f"Syntax error in {config_path}: {exc}"
|
|
183
|
+
raise ValueError(msg) from exc
|
|
173
184
|
|
|
174
185
|
return _parse_config(data)
|
|
175
186
|
|
|
176
187
|
|
|
177
188
|
_ALLOWED_SECTIONS = frozenset({"agent", "sandbox"})
|
|
189
|
+
_ALLOWED_AGENT_KEYS = frozenset({"name", "model"})
|
|
190
|
+
_ALLOWED_SANDBOX_KEYS = frozenset({"provider", "template", "image", "scope"})
|
|
178
191
|
|
|
179
192
|
|
|
180
193
|
def _parse_config(data: dict[str, Any]) -> DeployConfig:
|
|
@@ -195,18 +208,33 @@ def _parse_config(data: dict[str, Any]) -> DeployConfig:
|
|
|
195
208
|
msg = "[agent].name is required in deepagents.toml"
|
|
196
209
|
raise ValueError(msg)
|
|
197
210
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
211
|
+
unknown_agent = set(agent_data.keys()) - _ALLOWED_AGENT_KEYS
|
|
212
|
+
if unknown_agent:
|
|
213
|
+
msg = (
|
|
214
|
+
f"Unknown key(s) in [agent]: {sorted(unknown_agent)}. "
|
|
215
|
+
f"Allowed: {sorted(_ALLOWED_AGENT_KEYS)}"
|
|
216
|
+
)
|
|
217
|
+
raise ValueError(msg)
|
|
218
|
+
|
|
219
|
+
# Only pass keys present in TOML; dataclass defaults handle the rest.
|
|
220
|
+
agent_kwargs: dict[str, Any] = {"name": agent_data["name"]}
|
|
221
|
+
if "model" in agent_data:
|
|
222
|
+
agent_kwargs["model"] = agent_data["model"]
|
|
223
|
+
agent = AgentConfig(**agent_kwargs)
|
|
202
224
|
|
|
203
225
|
sandbox_data = data.get("sandbox", {})
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
226
|
+
unknown_sandbox = set(sandbox_data.keys()) - _ALLOWED_SANDBOX_KEYS
|
|
227
|
+
if unknown_sandbox:
|
|
228
|
+
msg = (
|
|
229
|
+
f"Unknown key(s) in [sandbox]: {sorted(unknown_sandbox)}. "
|
|
230
|
+
f"Allowed: {sorted(_ALLOWED_SANDBOX_KEYS)}"
|
|
231
|
+
)
|
|
232
|
+
raise ValueError(msg)
|
|
233
|
+
|
|
234
|
+
sandbox_kwargs: dict[str, Any] = {
|
|
235
|
+
k: sandbox_data[k] for k in _ALLOWED_SANDBOX_KEYS if k in sandbox_data
|
|
236
|
+
}
|
|
237
|
+
sandbox = SandboxConfig(**sandbox_kwargs)
|
|
210
238
|
|
|
211
239
|
return DeployConfig(agent=agent, sandbox=sandbox)
|
|
212
240
|
|
|
@@ -261,7 +289,7 @@ def _validate_model_credentials(model: str) -> list[str]:
|
|
|
261
289
|
|
|
262
290
|
|
|
263
291
|
def _validate_sandbox_credentials(provider: str) -> list[str]:
|
|
264
|
-
"""Check that
|
|
292
|
+
"""Check that at least one required API key env var is set for the provider."""
|
|
265
293
|
required_vars = _SANDBOX_PROVIDER_ENV.get(provider)
|
|
266
294
|
if required_vars is None:
|
|
267
295
|
return []
|
|
@@ -276,9 +304,11 @@ def _validate_sandbox_credentials(provider: str) -> list[str]:
|
|
|
276
304
|
|
|
277
305
|
|
|
278
306
|
def find_config(start_path: Path | None = None) -> Path | None:
|
|
279
|
-
"""Find `deepagents.toml` in
|
|
307
|
+
"""Find `deepagents.toml` in *start_path* (or cwd if not given).
|
|
308
|
+
|
|
309
|
+
Only checks the single directory — does not walk parent directories.
|
|
280
310
|
|
|
281
|
-
Returns the path if found, or
|
|
311
|
+
Returns the path if found, or `None` otherwise.
|
|
282
312
|
"""
|
|
283
313
|
current = (start_path or Path.cwd()).resolve()
|
|
284
314
|
candidate = current / DEFAULT_CONFIG_FILENAME
|