deepagents-cli 0.0.38__tar.gz → 0.0.39__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.38 → deepagents_cli-0.0.39}/CHANGELOG.md +13 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/PKG-INFO +1 -1
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/_version.py +1 -1
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/app.py +56 -8
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/command_registry.py +50 -11
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/deploy/bundler.py +110 -10
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/deploy/commands.py +4 -1
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/deploy/config.py +141 -1
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/deploy/templates.py +111 -1
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/main.py +60 -12
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/model_config.py +10 -1
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/ui.py +3 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/update_check.py +76 -17
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/autocomplete.py +16 -9
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/chat_input.py +207 -5
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/pyproject.toml +1 -1
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/deploy/test_bundler.py +207 -16
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/deploy/test_config.py +148 -1
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_app.py +166 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_args.py +16 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_autocomplete.py +36 -8
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_chat_input.py +230 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_command_registry.py +14 -9
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_offload.py +2 -2
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_reload.py +1 -1
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_skill_invocation.py +12 -11
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_update_check.py +228 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/uv.lock +9 -9
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/.gitignore +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/DEV.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/Makefile +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/README.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/THREAT_MODEL.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/__main__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/_ask_user_types.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/_cli_context.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/_debug.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/_env_vars.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/_server_config.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/_session_stats.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/_testing_models.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/agent.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/app.tcss +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/ask_user.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/built_in_skills/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/built_in_skills/remember/SKILL.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/clipboard.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/config.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/configurable_model.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/default_agent_prompt.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/editor.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/file_ops.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/formatting.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/hooks.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/input.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/integrations/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/integrations/sandbox_factory.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/integrations/sandbox_provider.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/local_context.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/mcp_tools.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/mcp_trust.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/media_utils.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/non_interactive.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/offload.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/output.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/project_utils.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/py.typed +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/remote_client.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/server.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/server_graph.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/server_manager.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/sessions.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/skills/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/skills/commands.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/skills/invocation.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/skills/load.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/subagents.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/system_prompt.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/textual_adapter.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/theme.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/token_state.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/tool_display.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/tools.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/unicode_security.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/_links.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/approval.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/ask_user.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/diff.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/history.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/loading.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/mcp_viewer.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/message_store.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/messages.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/model_selector.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/notification_settings.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/status.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/theme_selector.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/thread_selector.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/tool_renderers.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/tool_widgets.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/deepagents_cli/widgets/welcome.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/deploy-content-writer/.env.example +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/deploy-content-writer/skills/blog-post/SKILL.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/deploy-content-writer/skills/social-media/SKILL.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/deploy-content-writer/user/context.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/deploy-content-writer/user/preferences.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/skills/arxiv-search/SKILL.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/examples/skills/web-research/SKILL.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/images/cli.png +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/scripts/check_imports.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/scripts/debug_server.sh +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/scripts/install.sh +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/README.md +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/integration_tests/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/integration_tests/conftest.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/integration_tests/test_acp_mode.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/integration_tests/test_compact_resume.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/conftest.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/deploy/test_commands.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/skills/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/skills/test_commands.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/skills/test_load.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_agent.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_agent_friendly.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_approval.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_ask_user.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_ask_user_middleware.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_charset.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_compact_tool.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_config.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_configurable_model.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_debug.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_editor.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_end_to_end.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_env_vars.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_exception_handling.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_file_ops.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_history.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_hooks.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_imports.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_input_parsing.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_links.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_loading.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_local_context.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_main.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_main_args.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_mcp_tools.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_mcp_trust.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_mcp_viewer.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_media_utils.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_message_store.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_messages.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_model_config.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_model_selector.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_model_switch.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_non_interactive.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_output.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_remote_client.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_server.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_server_config.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_server_graph.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_server_helpers.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_server_manager.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_sessions.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_status.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_subagents.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_textual_adapter.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_theme.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_thread_selector.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_token_tracker.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_ui.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_unicode_security.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_version.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/test_welcome.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/tools/__init__.py +0 -0
- {deepagents_cli-0.0.38 → deepagents_cli-0.0.39}/tests/unit_tests/tools/test_fetch_url.py +0 -0
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.39](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.38...deepagents-cli==0.0.39) (2026-04-17)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **cli:** inline argument hints for slash commands ([#2181](https://github.com/langchain-ai/deepagents/issues/2181)) ([6b58e06](https://github.com/langchain-ai/deepagents/commit/6b58e06b06f6fb360d85c54eac31953d1e47dd7a))
|
|
9
|
+
* **cli:** subagents for `deepagents deploy` ([#2786](https://github.com/langchain-ai/deepagents/issues/2786)) ([7dd5565](https://github.com/langchain-ai/deepagents/commit/7dd5565e30ab91a2cd2ca10fcd227e590451f13c))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* **cli:** throttle update notification to once per day and fix teardown banner ([#2764](https://github.com/langchain-ai/deepagents/issues/2764)) ([ba31294](https://github.com/langchain-ai/deepagents/commit/ba31294b733d4ef542d18830eec6df30cfa0d23f))
|
|
15
|
+
|
|
3
16
|
## [0.0.38](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.37...deepagents-cli==0.0.38) (2026-04-15)
|
|
4
17
|
|
|
5
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.39
|
|
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/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Version information and lightweight constants for `deepagents-cli`."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.0.
|
|
3
|
+
__version__ = "0.0.39" # 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."""
|
|
@@ -1439,7 +1439,7 @@ class DeepAgentsApp(App):
|
|
|
1439
1439
|
)
|
|
1440
1440
|
|
|
1441
1441
|
available, latest = await asyncio.to_thread(is_update_available)
|
|
1442
|
-
if not available:
|
|
1442
|
+
if not available or latest is None:
|
|
1443
1443
|
return
|
|
1444
1444
|
|
|
1445
1445
|
self._update_available = (True, latest)
|
|
@@ -1447,7 +1447,7 @@ class DeepAgentsApp(App):
|
|
|
1447
1447
|
logger.debug("Background update check failed", exc_info=True)
|
|
1448
1448
|
return
|
|
1449
1449
|
|
|
1450
|
-
# Phase 2: auto-update or notify
|
|
1450
|
+
# Phase 2: auto-update or notify
|
|
1451
1451
|
try:
|
|
1452
1452
|
from deepagents_cli._version import __version__ as cli_version
|
|
1453
1453
|
|
|
@@ -1475,6 +1475,14 @@ class DeepAgentsApp(App):
|
|
|
1475
1475
|
markup=False,
|
|
1476
1476
|
)
|
|
1477
1477
|
else:
|
|
1478
|
+
from deepagents_cli.update_check import (
|
|
1479
|
+
mark_update_notified,
|
|
1480
|
+
should_notify_update,
|
|
1481
|
+
)
|
|
1482
|
+
|
|
1483
|
+
if not await asyncio.to_thread(should_notify_update, latest):
|
|
1484
|
+
return
|
|
1485
|
+
|
|
1478
1486
|
cmd = upgrade_command()
|
|
1479
1487
|
self.notify(
|
|
1480
1488
|
f"Update available: v{latest} (current: v{cli_version}). "
|
|
@@ -1484,13 +1492,15 @@ class DeepAgentsApp(App):
|
|
|
1484
1492
|
timeout=15,
|
|
1485
1493
|
markup=False,
|
|
1486
1494
|
)
|
|
1495
|
+
await asyncio.to_thread(mark_update_notified, latest)
|
|
1487
1496
|
except Exception:
|
|
1488
|
-
logger.warning("
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1497
|
+
logger.warning("Update check/notify failed unexpectedly", exc_info=True)
|
|
1498
|
+
if is_auto_update_enabled():
|
|
1499
|
+
self.notify(
|
|
1500
|
+
"Auto-update failed unexpectedly.",
|
|
1501
|
+
severity="warning",
|
|
1502
|
+
timeout=10,
|
|
1503
|
+
)
|
|
1494
1504
|
|
|
1495
1505
|
async def _show_whats_new(self) -> None:
|
|
1496
1506
|
"""Show a 'what's new' banner on the first launch after an upgrade."""
|
|
@@ -2763,6 +2773,15 @@ class DeepAgentsApp(App):
|
|
|
2763
2773
|
elif cmd == "/remember" or cmd.startswith("/remember "):
|
|
2764
2774
|
# Convenience alias for /skill:remember — shorter and discoverable
|
|
2765
2775
|
# before skill loading completes.
|
|
2776
|
+
if not await self._has_conversation_messages():
|
|
2777
|
+
await self._mount_message(UserMessage(command))
|
|
2778
|
+
await self._mount_message(
|
|
2779
|
+
AppMessage(
|
|
2780
|
+
"Nothing to remember yet. Start a conversation first,"
|
|
2781
|
+
" then use /remember to capture learnings."
|
|
2782
|
+
)
|
|
2783
|
+
)
|
|
2784
|
+
return
|
|
2766
2785
|
args = command.strip()[len("/remember") :].strip()
|
|
2767
2786
|
rewritten = f"/skill:remember {args}" if args else "/skill:remember"
|
|
2768
2787
|
await self._handle_skill_command(rewritten)
|
|
@@ -3043,6 +3062,35 @@ class DeepAgentsApp(App):
|
|
|
3043
3062
|
skill_name, args = parse_skill_command(command)
|
|
3044
3063
|
await self._invoke_skill(skill_name, args, command=command)
|
|
3045
3064
|
|
|
3065
|
+
async def _has_conversation_messages(self) -> bool:
|
|
3066
|
+
"""Check whether the current thread has at least one human message.
|
|
3067
|
+
|
|
3068
|
+
Returns:
|
|
3069
|
+
`True` if the conversation contains a `HumanMessage`, `False`
|
|
3070
|
+
otherwise. On transient errors (network, corrupt state) returns
|
|
3071
|
+
`True` so that `/remember` is not blocked with a misleading
|
|
3072
|
+
"nothing to remember" message.
|
|
3073
|
+
"""
|
|
3074
|
+
if not self._agent:
|
|
3075
|
+
return False
|
|
3076
|
+
try:
|
|
3077
|
+
from langchain_core.messages import HumanMessage
|
|
3078
|
+
|
|
3079
|
+
config: RunnableConfig = {
|
|
3080
|
+
"configurable": {"thread_id": self._lc_thread_id},
|
|
3081
|
+
}
|
|
3082
|
+
state = await self._agent.aget_state(config)
|
|
3083
|
+
if not state or not state.values:
|
|
3084
|
+
return False
|
|
3085
|
+
messages = state.values.get("messages", [])
|
|
3086
|
+
return any(isinstance(m, HumanMessage) for m in messages)
|
|
3087
|
+
except Exception:
|
|
3088
|
+
logger.warning(
|
|
3089
|
+
"Failed to check conversation messages; allowing /remember to proceed",
|
|
3090
|
+
exc_info=True,
|
|
3091
|
+
)
|
|
3092
|
+
return True
|
|
3093
|
+
|
|
3046
3094
|
async def _get_conversation_token_count(self) -> int | None:
|
|
3047
3095
|
"""Return the approximate conversation-only token count.
|
|
3048
3096
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Unified slash-command registry.
|
|
2
2
|
|
|
3
3
|
Every slash command is declared once as a `SlashCommand` entry in `COMMANDS`.
|
|
4
|
-
Bypass-tier frozensets and autocomplete
|
|
4
|
+
Bypass-tier frozensets and autocomplete entries are derived automatically — no
|
|
5
5
|
other file should hard-code command metadata.
|
|
6
6
|
"""
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
from dataclasses import dataclass
|
|
11
11
|
from enum import StrEnum
|
|
12
|
-
from typing import TYPE_CHECKING
|
|
12
|
+
from typing import TYPE_CHECKING, NamedTuple
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from deepagents_cli.skills.load import ExtendedSkillMetadata
|
|
@@ -50,9 +50,26 @@ class SlashCommand:
|
|
|
50
50
|
hidden_keywords: str = ""
|
|
51
51
|
"""Space-separated terms for fuzzy matching (never displayed)."""
|
|
52
52
|
|
|
53
|
+
argument_hint: str = ""
|
|
54
|
+
"""Placeholder text for autocomplete when the command accepts args."""
|
|
55
|
+
|
|
53
56
|
aliases: tuple[str, ...] = ()
|
|
54
57
|
"""Alternative names (e.g. `("/q",)` for `/quit`)."""
|
|
55
58
|
|
|
59
|
+
def to_entry(self) -> CommandEntry:
|
|
60
|
+
"""Project this command into a `CommandEntry` for autocomplete.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
A `CommandEntry` carrying only the fields the autocomplete
|
|
64
|
+
layer needs.
|
|
65
|
+
"""
|
|
66
|
+
return CommandEntry(
|
|
67
|
+
name=self.name,
|
|
68
|
+
description=self.description,
|
|
69
|
+
hidden_keywords=self.hidden_keywords,
|
|
70
|
+
argument_hint=self.argument_hint,
|
|
71
|
+
)
|
|
72
|
+
|
|
56
73
|
|
|
57
74
|
COMMANDS: tuple[SlashCommand, ...] = (
|
|
58
75
|
SlashCommand(
|
|
@@ -94,11 +111,13 @@ COMMANDS: tuple[SlashCommand, ...] = (
|
|
|
94
111
|
name="/remember",
|
|
95
112
|
description="Update memory and skills from conversation",
|
|
96
113
|
bypass_tier=BypassTier.QUEUED,
|
|
114
|
+
argument_hint="[context]",
|
|
97
115
|
),
|
|
98
116
|
SlashCommand( # Static alias; not auto-generated from skill discovery
|
|
99
117
|
name="/skill-creator",
|
|
100
118
|
description="Guide for creating effective agent skills",
|
|
101
119
|
bypass_tier=BypassTier.QUEUED,
|
|
120
|
+
argument_hint="[task]",
|
|
102
121
|
),
|
|
103
122
|
SlashCommand(
|
|
104
123
|
name="/threads",
|
|
@@ -228,13 +247,28 @@ ALL_CLASSIFIED: frozenset[str] = (
|
|
|
228
247
|
|
|
229
248
|
|
|
230
249
|
# ---------------------------------------------------------------------------
|
|
231
|
-
# Autocomplete
|
|
250
|
+
# Autocomplete entries
|
|
232
251
|
# ---------------------------------------------------------------------------
|
|
233
252
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
253
|
+
|
|
254
|
+
class CommandEntry(NamedTuple):
|
|
255
|
+
"""A single autocomplete entry for the slash-command controller."""
|
|
256
|
+
|
|
257
|
+
name: str
|
|
258
|
+
"""Canonical command name (e.g. `/quit`)."""
|
|
259
|
+
|
|
260
|
+
description: str
|
|
261
|
+
"""Short user-facing description."""
|
|
262
|
+
|
|
263
|
+
hidden_keywords: str
|
|
264
|
+
"""Space-separated terms for fuzzy matching (never displayed)."""
|
|
265
|
+
|
|
266
|
+
argument_hint: str
|
|
267
|
+
"""Placeholder text shown when the command accepts arguments (e.g. `[context]`)."""
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
SLASH_COMMANDS: list[CommandEntry] = [cmd.to_entry() for cmd in COMMANDS]
|
|
271
|
+
"""Autocomplete entries derived from `COMMANDS` for `SlashCommandController`."""
|
|
238
272
|
|
|
239
273
|
|
|
240
274
|
def parse_skill_command(command: str) -> tuple[str, str]:
|
|
@@ -271,8 +305,8 @@ appear as `/skill:model`).
|
|
|
271
305
|
|
|
272
306
|
def build_skill_commands(
|
|
273
307
|
skills: list[ExtendedSkillMetadata],
|
|
274
|
-
) -> list[
|
|
275
|
-
"""Build autocomplete
|
|
308
|
+
) -> list[CommandEntry]:
|
|
309
|
+
"""Build autocomplete entries for discovered skills.
|
|
276
310
|
|
|
277
311
|
Each skill becomes a `/skill:<name>` entry with its description
|
|
278
312
|
and the skill name as a hidden keyword for fuzzy matching.
|
|
@@ -285,10 +319,15 @@ def build_skill_commands(
|
|
|
285
319
|
skills: List of discovered skill metadata.
|
|
286
320
|
|
|
287
321
|
Returns:
|
|
288
|
-
List of `
|
|
322
|
+
List of `CommandEntry` instances.
|
|
289
323
|
"""
|
|
290
324
|
return [
|
|
291
|
-
(
|
|
325
|
+
CommandEntry(
|
|
326
|
+
name=f"/skill:{skill['name']}",
|
|
327
|
+
description=skill["description"],
|
|
328
|
+
hidden_keywords=skill["name"],
|
|
329
|
+
argument_hint="",
|
|
330
|
+
)
|
|
292
331
|
for skill in skills
|
|
293
332
|
if skill["name"] not in _STATIC_SKILL_ALIASES
|
|
294
333
|
]
|
|
@@ -27,6 +27,7 @@ import json
|
|
|
27
27
|
import logging
|
|
28
28
|
import shutil
|
|
29
29
|
from pathlib import Path
|
|
30
|
+
from typing import Any
|
|
30
31
|
|
|
31
32
|
from deepagents_cli.deploy.config import (
|
|
32
33
|
AGENTS_MD_FILENAME,
|
|
@@ -34,12 +35,15 @@ from deepagents_cli.deploy.config import (
|
|
|
34
35
|
SKILLS_DIRNAME,
|
|
35
36
|
USER_DIRNAME,
|
|
36
37
|
DeployConfig,
|
|
38
|
+
SubAgentProject,
|
|
39
|
+
load_subagents,
|
|
37
40
|
)
|
|
38
41
|
from deepagents_cli.deploy.templates import (
|
|
39
42
|
DEPLOY_GRAPH_TEMPLATE,
|
|
40
43
|
MCP_TOOLS_TEMPLATE,
|
|
41
44
|
PYPROJECT_TEMPLATE,
|
|
42
45
|
SANDBOX_BLOCKS,
|
|
46
|
+
SYNC_SUBAGENTS_TEMPLATE,
|
|
43
47
|
)
|
|
44
48
|
|
|
45
49
|
logger = logging.getLogger(__name__)
|
|
@@ -77,7 +81,7 @@ def bundle(
|
|
|
77
81
|
system_prompt = agents_md_path.read_text(encoding="utf-8")
|
|
78
82
|
|
|
79
83
|
# 2. Build and write the seed payload: memory (AGENTS.md) + skills/.
|
|
80
|
-
seed = _build_seed(
|
|
84
|
+
seed = _build_seed(project_root, system_prompt)
|
|
81
85
|
(build_dir / "_seed.json").write_text(
|
|
82
86
|
json.dumps(seed, indent=2, ensure_ascii=False),
|
|
83
87
|
encoding="utf-8",
|
|
@@ -104,35 +108,89 @@ def bundle(
|
|
|
104
108
|
shutil.copy2(env_src, build_dir / ".env")
|
|
105
109
|
logger.info("Copied %s → .env", env_src)
|
|
106
110
|
|
|
107
|
-
# 4.
|
|
111
|
+
# 4. Load subagents (needed for both deploy_graph.py and pyproject.toml).
|
|
112
|
+
sync_subagents = load_subagents(project_root)
|
|
113
|
+
|
|
114
|
+
# 5. Render deploy_graph.py.
|
|
108
115
|
has_user_memories = (project_root / USER_DIRNAME).is_dir()
|
|
116
|
+
has_sync_subagents = bool(sync_subagents)
|
|
109
117
|
(build_dir / "deploy_graph.py").write_text(
|
|
110
118
|
_render_deploy_graph(
|
|
111
119
|
config,
|
|
112
120
|
mcp_present=mcp_present,
|
|
113
121
|
has_user_memories=has_user_memories,
|
|
122
|
+
has_sync_subagents=has_sync_subagents,
|
|
114
123
|
),
|
|
115
124
|
encoding="utf-8",
|
|
116
125
|
)
|
|
117
126
|
logger.info("Generated deploy_graph.py")
|
|
118
127
|
|
|
119
|
-
#
|
|
128
|
+
# 6. Render langgraph.json.
|
|
120
129
|
(build_dir / "langgraph.json").write_text(
|
|
121
130
|
_render_langgraph_json(env_present=env_present),
|
|
122
131
|
encoding="utf-8",
|
|
123
132
|
)
|
|
124
133
|
|
|
125
|
-
#
|
|
134
|
+
# 7. Render pyproject.toml.
|
|
135
|
+
subagent_model_providers: list[str] = []
|
|
136
|
+
has_subagent_mcp = False
|
|
137
|
+
for sa in sync_subagents.values():
|
|
138
|
+
model = sa.config.agent.model
|
|
139
|
+
if ":" in model:
|
|
140
|
+
subagent_model_providers.append(model.split(":", 1)[0])
|
|
141
|
+
if (sa.root / MCP_FILENAME).is_file():
|
|
142
|
+
has_subagent_mcp = True
|
|
143
|
+
|
|
126
144
|
(build_dir / "pyproject.toml").write_text(
|
|
127
|
-
_render_pyproject(
|
|
145
|
+
_render_pyproject(
|
|
146
|
+
config,
|
|
147
|
+
mcp_present=mcp_present,
|
|
148
|
+
subagent_model_providers=subagent_model_providers,
|
|
149
|
+
has_subagent_mcp=has_subagent_mcp,
|
|
150
|
+
),
|
|
128
151
|
encoding="utf-8",
|
|
129
152
|
)
|
|
130
153
|
|
|
131
154
|
return build_dir
|
|
132
155
|
|
|
133
156
|
|
|
157
|
+
def _build_subagent_seed(subagent: SubAgentProject) -> dict:
|
|
158
|
+
"""Build the seed entry for a single sync subagent."""
|
|
159
|
+
sa_root = subagent.root
|
|
160
|
+
agent = subagent.config.agent
|
|
161
|
+
|
|
162
|
+
memories: dict[str, str] = {
|
|
163
|
+
f"/{AGENTS_MD_FILENAME}": (sa_root / AGENTS_MD_FILENAME).read_text(
|
|
164
|
+
encoding="utf-8"
|
|
165
|
+
),
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
skills: dict[str, str] = {}
|
|
169
|
+
skills_dir = sa_root / SKILLS_DIRNAME
|
|
170
|
+
if skills_dir.is_dir():
|
|
171
|
+
for f in sorted(skills_dir.rglob("*")):
|
|
172
|
+
if f.is_file() and not f.name.startswith("."):
|
|
173
|
+
rel = f.relative_to(skills_dir).as_posix()
|
|
174
|
+
skills[f"/{rel}"] = f.read_text(encoding="utf-8")
|
|
175
|
+
|
|
176
|
+
mcp_path = sa_root / MCP_FILENAME
|
|
177
|
+
mcp = None
|
|
178
|
+
if mcp_path.is_file():
|
|
179
|
+
mcp = json.loads(mcp_path.read_text(encoding="utf-8"))
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
"config": {
|
|
183
|
+
"name": agent.name,
|
|
184
|
+
"description": agent.description,
|
|
185
|
+
"model": agent.model,
|
|
186
|
+
},
|
|
187
|
+
"memories": memories,
|
|
188
|
+
"skills": skills,
|
|
189
|
+
"mcp": mcp,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
|
|
134
193
|
def _build_seed(
|
|
135
|
-
config: DeployConfig, # noqa: ARG001
|
|
136
194
|
project_root: Path,
|
|
137
195
|
system_prompt: str,
|
|
138
196
|
) -> dict:
|
|
@@ -172,18 +230,28 @@ def _build_seed(
|
|
|
172
230
|
)
|
|
173
231
|
user_memories[f"/{AGENTS_MD_FILENAME}"] = content
|
|
174
232
|
|
|
175
|
-
|
|
233
|
+
seed: dict = {
|
|
176
234
|
"memories": memories,
|
|
177
235
|
"skills": skills,
|
|
178
236
|
"user_memories": user_memories,
|
|
179
237
|
}
|
|
180
238
|
|
|
239
|
+
# Sync subagents.
|
|
240
|
+
sync_subagents = load_subagents(project_root)
|
|
241
|
+
if sync_subagents:
|
|
242
|
+
seed["subagents"] = {
|
|
243
|
+
name: _build_subagent_seed(sa) for name, sa in sync_subagents.items()
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return seed
|
|
247
|
+
|
|
181
248
|
|
|
182
249
|
def _render_deploy_graph(
|
|
183
250
|
config: DeployConfig,
|
|
184
251
|
*,
|
|
185
252
|
mcp_present: bool,
|
|
186
253
|
has_user_memories: bool = False,
|
|
254
|
+
has_sync_subagents: bool = False,
|
|
187
255
|
) -> str:
|
|
188
256
|
"""Render the generated `deploy_graph.py`."""
|
|
189
257
|
provider = config.sandbox.provider
|
|
@@ -199,6 +267,16 @@ def _render_deploy_graph(
|
|
|
199
267
|
mcp_tools_block = ""
|
|
200
268
|
mcp_tools_load_call = "pass # no MCP servers configured"
|
|
201
269
|
|
|
270
|
+
if has_sync_subagents:
|
|
271
|
+
sync_subagents_block = SYNC_SUBAGENTS_TEMPLATE
|
|
272
|
+
sync_subagents_load_call = (
|
|
273
|
+
"all_subagents.extend("
|
|
274
|
+
"await _build_sync_subagents(seed, store, assistant_id))"
|
|
275
|
+
)
|
|
276
|
+
else:
|
|
277
|
+
sync_subagents_block = ""
|
|
278
|
+
sync_subagents_load_call = "pass # no sync subagents"
|
|
279
|
+
|
|
202
280
|
return DEPLOY_GRAPH_TEMPLATE.format(
|
|
203
281
|
model=config.agent.model,
|
|
204
282
|
sandbox_template=config.sandbox.template,
|
|
@@ -209,6 +287,8 @@ def _render_deploy_graph(
|
|
|
209
287
|
mcp_tools_load_call=mcp_tools_load_call,
|
|
210
288
|
default_assistant_id=config.agent.name,
|
|
211
289
|
has_user_memories=has_user_memories,
|
|
290
|
+
sync_subagents_block=sync_subagents_block,
|
|
291
|
+
sync_subagents_load_call=sync_subagents_load_call,
|
|
212
292
|
)
|
|
213
293
|
|
|
214
294
|
|
|
@@ -224,7 +304,13 @@ def _render_langgraph_json(*, env_present: bool) -> str:
|
|
|
224
304
|
return json.dumps(data, indent=2) + "\n"
|
|
225
305
|
|
|
226
306
|
|
|
227
|
-
def _render_pyproject(
|
|
307
|
+
def _render_pyproject(
|
|
308
|
+
config: DeployConfig,
|
|
309
|
+
*,
|
|
310
|
+
mcp_present: bool,
|
|
311
|
+
subagent_model_providers: list[str] | None = None,
|
|
312
|
+
has_subagent_mcp: bool = False,
|
|
313
|
+
) -> str:
|
|
228
314
|
"""Render the deployment package's `pyproject.toml`.
|
|
229
315
|
|
|
230
316
|
Deps are inferred — the user never writes them. We add:
|
|
@@ -241,7 +327,13 @@ def _render_pyproject(config: DeployConfig, *, mcp_present: bool) -> str:
|
|
|
241
327
|
if provider_prefix and provider_prefix in _MODEL_PROVIDER_DEPS:
|
|
242
328
|
deps.append(_MODEL_PROVIDER_DEPS[provider_prefix])
|
|
243
329
|
|
|
244
|
-
|
|
330
|
+
# Add deps for subagent model providers.
|
|
331
|
+
for sp in subagent_model_providers or []:
|
|
332
|
+
dep = _MODEL_PROVIDER_DEPS.get(sp)
|
|
333
|
+
if dep and dep not in deps:
|
|
334
|
+
deps.append(dep)
|
|
335
|
+
|
|
336
|
+
if mcp_present or has_subagent_mcp:
|
|
245
337
|
deps.append("langchain-mcp-adapters")
|
|
246
338
|
|
|
247
339
|
_, partner_pkg = SANDBOX_BLOCKS.get(config.sandbox.provider, (None, None))
|
|
@@ -259,7 +351,7 @@ def _render_pyproject(config: DeployConfig, *, mcp_present: bool) -> str:
|
|
|
259
351
|
def print_bundle_summary(config: DeployConfig, build_dir: Path) -> None:
|
|
260
352
|
"""Print a human-readable summary of what was bundled."""
|
|
261
353
|
seed_path = build_dir / "_seed.json"
|
|
262
|
-
seed: dict[str,
|
|
354
|
+
seed: dict[str, Any] = {"memories": {}, "skills": {}}
|
|
263
355
|
if seed_path.exists():
|
|
264
356
|
try:
|
|
265
357
|
seed = json.loads(seed_path.read_text(encoding="utf-8"))
|
|
@@ -294,6 +386,14 @@ def print_bundle_summary(config: DeployConfig, build_dir: Path) -> None:
|
|
|
294
386
|
if (build_dir / "_mcp.json").exists():
|
|
295
387
|
print("\n MCP config: _mcp.json")
|
|
296
388
|
|
|
389
|
+
# Subagent summary.
|
|
390
|
+
sync_subagents = seed.get("subagents", {})
|
|
391
|
+
if sync_subagents:
|
|
392
|
+
print(f"\n Subagents ({len(sync_subagents)}):")
|
|
393
|
+
for name, sa_data in sync_subagents.items():
|
|
394
|
+
desc = sa_data.get("config", {}).get("description", "")
|
|
395
|
+
print(f" {name} \u2014 {desc}")
|
|
396
|
+
|
|
297
397
|
print(f"\n Sandbox: {config.sandbox.provider}")
|
|
298
398
|
print(f"\n Build directory: {build_dir}")
|
|
299
399
|
generated = sorted(f.name for f in build_dir.iterdir() if f.is_file())
|
|
@@ -6,6 +6,7 @@ Registered with the CLI via `setup_deploy_parsers` in `main.py`.
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import argparse
|
|
9
|
+
import os
|
|
9
10
|
import subprocess
|
|
10
11
|
import tempfile
|
|
11
12
|
from pathlib import Path
|
|
@@ -402,12 +403,14 @@ def _run_langgraph_deploy(build_dir: Path, *, name: str) -> None:
|
|
|
402
403
|
|
|
403
404
|
config_path = str(build_dir / "langgraph.json")
|
|
404
405
|
cmd = ["langgraph", "deploy", "-c", config_path, "--name", name, "--verbose"]
|
|
406
|
+
env = os.environ.copy()
|
|
407
|
+
env["LANGGRAPH_CLI_ANALYTICS_SOURCE"] = "deepagents"
|
|
405
408
|
|
|
406
409
|
print("Deploying to LangSmith Deployments...")
|
|
407
410
|
print(f"Running: {' '.join(cmd)}")
|
|
408
411
|
print()
|
|
409
412
|
|
|
410
|
-
result = subprocess.run(cmd, cwd=str(build_dir), check=False)
|
|
413
|
+
result = subprocess.run(cmd, cwd=str(build_dir), check=False, env=env)
|
|
411
414
|
|
|
412
415
|
if result.returncode != 0:
|
|
413
416
|
print(f"\nDeployment failed (exit code {result.returncode}).")
|