deepagents-code 0.1.7__tar.gz → 0.1.8__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_code-0.1.7 → deepagents_code-0.1.8}/CHANGELOG.md +23 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/PKG-INFO +2 -2
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_version.py +1 -1
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/agent.py +5 -2
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/app.py +183 -51
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/ask_user.py +5 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/command_registry.py +17 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/extras_info.py +70 -0
- deepagents_code-0.1.8/deepagents_code/filesystem_empty_result.py +88 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/local_context.py +3 -12
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/main.py +7 -7
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_auth.py +250 -12
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_tools.py +11 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/unicode_security.py +47 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/update_check.py +62 -13
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/mcp_login.py +123 -30
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/mcp_viewer.py +166 -37
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/model_selector.py +16 -3
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/welcome.py +2 -1
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/pyproject.toml +2 -2
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/scripts/install.sh +22 -7
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_app.py +175 -14
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_command_registry.py +12 -0
- deepagents_code-0.1.8/tests/unit_tests/test_cursor_blink.py +59 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_extras_info.py +34 -0
- deepagents_code-0.1.8/tests/unit_tests/test_filesystem_empty_result.py +160 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_install_command.py +12 -4
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_main_args.py +57 -2
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_auth.py +405 -1
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_login_modal.py +103 -1
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_viewer.py +181 -43
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_model_selector.py +35 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_skill_invocation.py +3 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_unicode_security.py +69 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_update_check.py +129 -3
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_welcome.py +2 -2
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/uv.lock +17 -14
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/.gitignore +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/AGENTS.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/COMMANDS.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/DEV.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/Makefile +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/README.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/THREAT_MODEL.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/__main__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_ask_user_types.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_cli_context.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_constants.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_debug.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_env_vars.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_git.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_server_config.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_session_stats.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_startup_error.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_testing_models.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/_textual_patches.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/app.tcss +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/auth_store.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/built_in_skills/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/built_in_skills/remember/SKILL.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/built_in_skills/skill-creator/SKILL.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/clipboard.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/config.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/configurable_model.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/default_agent_prompt.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/editor.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/event_bus.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/file_ops.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/formatting.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/hooks.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/input.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/integrations/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/integrations/sandbox_factory.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/integrations/sandbox_provider.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/iterm_cursor_guide.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_commands.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_disabled.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_login_service.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_oauth_ui.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_providers/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_providers/_registry.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_providers/base.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_providers/github.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_providers/slack.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/mcp_trust.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/media_utils.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/model_config.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/non_interactive.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/notifications.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/offload.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/onboarding.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/output.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/project_utils.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/py.typed +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/remote_client.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/resume_state.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/server.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/server_graph.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/server_manager.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/sessions.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/skills/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/skills/commands.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/skills/invocation.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/skills/load.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/state_migration.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/subagents.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/system_prompt.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/terminal_capabilities.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/terminal_escape.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/textual_adapter.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/theme.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/tool_display.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/tools.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/ui.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/_links.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/agent_selector.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/approval.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/ask_user.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/auth.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/autocomplete.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/chat_input.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/diff.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/history.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/launch_init.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/loading.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/mcp_reconnect.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/message_store.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/messages.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/notification_center.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/notification_detail.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/notification_settings.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/status.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/theme_selector.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/thread_selector.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/tool_renderers.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/tool_widgets.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/update_available.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/deepagents_code/widgets/update_progress.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/examples/skills/arxiv-search/SKILL.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/examples/skills/skill-creator/SKILL.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/examples/skills/web-research/SKILL.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/images/tui.png +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/scripts/check_imports.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/scripts/debug_server.sh +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/scripts/generate_commands_catalog.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/README.md +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/integration_tests/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/integration_tests/conftest.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/integration_tests/test_acp_mode.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/integration_tests/test_compact_resume.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/conftest.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/skills/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/skills/test_commands.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/skills/test_load.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_agent.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_agent_friendly.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_agent_selector.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_approval.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_args.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_ask_user.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_ask_user_middleware.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_auth_store.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_auth_widgets.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_autocomplete.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_charset.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_chat_input.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_clipboard.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_compact_tool.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_config.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_configurable_model.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_debug.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_editor.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_end_to_end.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_env_vars.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_event_bus.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_exception_handling.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_file_ops.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_formatting.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_git.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_history.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_hooks.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_imports.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_input_parsing.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_iterm_cursor_guide.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_launch_init.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_links.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_loading.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_local_context.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_main.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_commands.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_disabled.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_login_service.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_oauth_ui.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_reconnect.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_tools.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_mcp_trust.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_media_utils.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_message_store.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_messages.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_model_config.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_model_switch.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_non_interactive.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_notification_center.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_notification_detail.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_notifications.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_offload.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_offload_dict_messages.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_onboarding.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_output.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_reload.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_remote_client.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_resume_state.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_server.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_server_config.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_server_graph.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_server_helpers.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_server_manager.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_session_stats.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_sessions.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_startup_fast_paths.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_state_migration.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_status.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_subagents.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_terminal_capabilities.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_terminal_escape.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_textual_adapter.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_textual_patches.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_theme.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_thread_selector.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_tool_display.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_ui.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_update_available.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_update_progress.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/test_version.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/tools/__init__.py +0 -0
- {deepagents_code-0.1.7 → deepagents_code-0.1.8}/tests/unit_tests/tools/test_fetch_url.py +0 -0
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
# Deep Agents Code Changelog
|
|
4
4
|
|
|
5
|
+
## [0.1.8](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.7...deepagents-code==0.1.8) (2026-06-02)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* List valid extras when `/install` has no argument ([#3695](https://github.com/langchain-ai/deepagents/issues/3695)) ([c7d529c](https://github.com/langchain-ai/deepagents/commit/c7d529ca0fc478dec9060ea04bcc8589f9b1cd3a))
|
|
10
|
+
* Add MCP error detail modal ([#3687](https://github.com/langchain-ai/deepagents/issues/3687)) ([4ae4754](https://github.com/langchain-ai/deepagents/commit/4ae475453ce0df6d6b057b7e163396aa27d55143))
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* Allow recovery commands when startup fails ([#3706](https://github.com/langchain-ai/deepagents/issues/3706)) ([727d022](https://github.com/langchain-ai/deepagents/commit/727d022cd1526836c3d1de997c1f036e870881f7))
|
|
15
|
+
* Preserve extras during install ([#3707](https://github.com/langchain-ai/deepagents/issues/3707)) ([e636ce9](https://github.com/langchain-ai/deepagents/commit/e636ce9e979fd1c30335ec340acdabbd0a5ae79e))
|
|
16
|
+
* Normalize empty file list tool output ([#3697](https://github.com/langchain-ai/deepagents/issues/3697)) ([b67aead](https://github.com/langchain-ai/deepagents/commit/b67aead2b86e04aaee8f2dbfba7b263e3e23597d))
|
|
17
|
+
* Point MCP re-enable guidance at `Ctrl+R` ([#3688](https://github.com/langchain-ai/deepagents/issues/3688)) ([15ca302](https://github.com/langchain-ai/deepagents/commit/15ca3029f18fa38c1592859febc2a6d0469bff2d))
|
|
18
|
+
* Preserve MCP token refresh when metadata discovery fails ([#3685](https://github.com/langchain-ai/deepagents/issues/3685)) ([afafeeb](https://github.com/langchain-ai/deepagents/commit/afafeeb471c4008d4eb4263ec478cf868833fe0b))
|
|
19
|
+
* Reduce OAuth login modal noise ([#3693](https://github.com/langchain-ai/deepagents/issues/3693)) ([0e8a780](https://github.com/langchain-ai/deepagents/commit/0e8a780e2dfea2e22ac44545a16279dbe30eb8ee))
|
|
20
|
+
* Repair MCP OAuth login redirect and stale client registration ([#3692](https://github.com/langchain-ai/deepagents/issues/3692)) ([f741293](https://github.com/langchain-ai/deepagents/commit/f741293524f7d47eb8a16a3cd4def336c3c3c13f))
|
|
21
|
+
* Search all models from `/model` filter ([#3690](https://github.com/langchain-ai/deepagents/issues/3690)) ([5fcb877](https://github.com/langchain-ai/deepagents/commit/5fcb877d094c4504f671bb7aeb52efa7bf3a5b48))
|
|
22
|
+
* Serialize `QueuedUserMessage` as user input ([#3708](https://github.com/langchain-ai/deepagents/issues/3708)) ([307d598](https://github.com/langchain-ai/deepagents/commit/307d59826da9b1ddcbcdab8dccef6d18ecf16d10))
|
|
23
|
+
* Serialize cold SDK imports ([#3712](https://github.com/langchain-ai/deepagents/issues/3712)) ([fb2adc0](https://github.com/langchain-ai/deepagents/commit/fb2adc0585e978b12646602ba922e252abf41f81))
|
|
24
|
+
* Pluralize singular MCP login splash text ([#3689](https://github.com/langchain-ai/deepagents/issues/3689)) ([492b0fc](https://github.com/langchain-ai/deepagents/commit/492b0fc9209e13cd7004a255ef67b31b7e78e95e))
|
|
25
|
+
|
|
5
26
|
## [0.1.7](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.6...deepagents-code==0.1.7) (2026-05-30)
|
|
6
27
|
|
|
7
28
|
### Features
|
|
@@ -102,5 +123,7 @@ Hello world! Ported from `libs/cli`.
|
|
|
102
123
|
|
|
103
124
|
---
|
|
104
125
|
|
|
126
|
+
## Prior Releases
|
|
127
|
+
|
|
105
128
|
`deepagents-code` was forked from `deepagents-cli` at v0.1.0 (2026-05-12).
|
|
106
129
|
For history prior to the fork, see [the `deepagents-cli` changelog](https://github.com/langchain-ai/deepagents/blob/main/libs/cli/CHANGELOG.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-code
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
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/
|
|
@@ -33,7 +33,7 @@ Requires-Dist: langchain-anthropic<2.0.0,>=1.4.3
|
|
|
33
33
|
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.2
|
|
34
34
|
Requires-Dist: langchain-mcp-adapters<1.0.0,>=0.2.2
|
|
35
35
|
Requires-Dist: langchain-openai<2.0.0,>=1.2.1
|
|
36
|
-
Requires-Dist: langchain<2.0.0,>=1.3.
|
|
36
|
+
Requires-Dist: langchain<2.0.0,>=1.3.4
|
|
37
37
|
Requires-Dist: langgraph-checkpoint-sqlite<4.0.0,>=3.1.0
|
|
38
38
|
Requires-Dist: langgraph-cli[inmem]<1.0.0,>=0.4.24
|
|
39
39
|
Requires-Dist: langgraph-runtime-inmem<1.0.0,>=0.28.1
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Keep the `x-release-please-version` annotation — release-please uses it to
|
|
4
4
|
# bump `__version__` in sync with `pyproject.toml` on every release PR.
|
|
5
|
-
__version__ = "0.1.
|
|
5
|
+
__version__ = "0.1.8" # x-release-please-version
|
|
6
6
|
|
|
7
7
|
DOCS_URL = "https://docs.langchain.com/oss/python/deepagents/code"
|
|
8
8
|
"""URL for `deepagents-code` documentation."""
|
|
@@ -62,6 +62,7 @@ from deepagents_code.config import (
|
|
|
62
62
|
settings,
|
|
63
63
|
)
|
|
64
64
|
from deepagents_code.configurable_model import ConfigurableModelMiddleware
|
|
65
|
+
from deepagents_code.filesystem_empty_result import _FilesystemEmptyResultMiddleware
|
|
65
66
|
from deepagents_code.integrations.sandbox_factory import get_default_working_dir
|
|
66
67
|
from deepagents_code.local_context import (
|
|
67
68
|
LocalContextMiddleware,
|
|
@@ -1240,8 +1241,10 @@ def create_cli_agent(
|
|
|
1240
1241
|
custom_subagents.append(general_purpose_subagent)
|
|
1241
1242
|
|
|
1242
1243
|
# Build middleware stack based on enabled features
|
|
1243
|
-
agent_middleware = [
|
|
1244
|
-
|
|
1244
|
+
agent_middleware = [
|
|
1245
|
+
ConfigurableModelMiddleware(),
|
|
1246
|
+
_FilesystemEmptyResultMiddleware(),
|
|
1247
|
+
]
|
|
1245
1248
|
|
|
1246
1249
|
# Resume state: declares the `_context_tokens` and `_model_spec` channels
|
|
1247
1250
|
# and writes them from `after_model` (token count from the latest
|
|
@@ -103,6 +103,14 @@ _DEFERRED_START_NOTICE = (
|
|
|
103
103
|
# read the same pre-mutation state and then clobber the other's keys.
|
|
104
104
|
_CONFIG_WRITE_LOCK = threading.Lock()
|
|
105
105
|
|
|
106
|
+
_DEEPAGENTS_IMPORT_LOCK = threading.RLock()
|
|
107
|
+
"""Serializes process-local cold imports into the Deep Agents SDK graph.
|
|
108
|
+
|
|
109
|
+
The SDK currently has a package-to-backend circular import that is safe when a
|
|
110
|
+
single thread imports it re-entrantly, but can trip CPython's per-module import
|
|
111
|
+
deadlock detector when two threads cold-import overlapping modules.
|
|
112
|
+
"""
|
|
113
|
+
|
|
106
114
|
_MESSAGE_TIMESTAMP_FOOTER_CLASS = "message-timestamp-footer"
|
|
107
115
|
|
|
108
116
|
_TIMESTAMP_FOOTER_EXCLUDED_TYPES: frozenset[MessageType] = frozenset(
|
|
@@ -127,6 +135,32 @@ def _is_message_timestamp_footer(widget: Widget) -> bool:
|
|
|
127
135
|
return widget.has_class(_MESSAGE_TIMESTAMP_FOOTER_CLASS)
|
|
128
136
|
|
|
129
137
|
|
|
138
|
+
def _create_model_with_deepagents_import_lock(
|
|
139
|
+
model_spec: str | None = None,
|
|
140
|
+
*,
|
|
141
|
+
extra_kwargs: dict[str, Any] | None = None,
|
|
142
|
+
profile_overrides: dict[str, Any] | None = None,
|
|
143
|
+
) -> ModelResult:
|
|
144
|
+
"""Create a model while serializing Deep Agents SDK import entry.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
model_spec: Model specification in `provider:model` format.
|
|
148
|
+
extra_kwargs: Extra model constructor kwargs.
|
|
149
|
+
profile_overrides: Model profile metadata overrides.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Created model and resolved metadata.
|
|
153
|
+
"""
|
|
154
|
+
with _DEEPAGENTS_IMPORT_LOCK:
|
|
155
|
+
from deepagents_code.config import create_model
|
|
156
|
+
|
|
157
|
+
return create_model(
|
|
158
|
+
model_spec,
|
|
159
|
+
extra_kwargs=extra_kwargs,
|
|
160
|
+
profile_overrides=profile_overrides,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
130
164
|
@dataclass(frozen=True)
|
|
131
165
|
class _ConfigWriteResult:
|
|
132
166
|
"""Result of a config write with TUI-facing failure context."""
|
|
@@ -156,6 +190,7 @@ if TYPE_CHECKING:
|
|
|
156
190
|
from textual.worker import Worker
|
|
157
191
|
|
|
158
192
|
from deepagents_code._ask_user_types import AskUserWidgetResult, Question
|
|
193
|
+
from deepagents_code.config import ModelResult
|
|
159
194
|
from deepagents_code.event_bus import EventSource, ExternalEvent
|
|
160
195
|
from deepagents_code.mcp_tools import MCPServerInfo
|
|
161
196
|
from deepagents_code.model_config import MissingProviderPackageError
|
|
@@ -525,6 +560,49 @@ def save_theme_preference(name: str) -> bool:
|
|
|
525
560
|
return _save_theme_preference_result(name).ok
|
|
526
561
|
|
|
527
562
|
|
|
563
|
+
def _load_cursor_blink_preference() -> bool:
|
|
564
|
+
"""Load the saved cursor-blink preference from `~/.deepagents/config.toml`.
|
|
565
|
+
|
|
566
|
+
The chat input cursor blink can be turned off by setting
|
|
567
|
+
`[ui].cursor_blink = false` in the config file. There is no in-app command
|
|
568
|
+
for this; the file is edited manually.
|
|
569
|
+
|
|
570
|
+
Returns:
|
|
571
|
+
The saved `[ui].cursor_blink` value, or `True` (blink on) when unset,
|
|
572
|
+
unreadable, or malformed.
|
|
573
|
+
"""
|
|
574
|
+
import tomllib
|
|
575
|
+
|
|
576
|
+
from deepagents_code.model_config import DEFAULT_CONFIG_PATH
|
|
577
|
+
|
|
578
|
+
if not DEFAULT_CONFIG_PATH.exists():
|
|
579
|
+
return True
|
|
580
|
+
try:
|
|
581
|
+
with DEFAULT_CONFIG_PATH.open("rb") as f:
|
|
582
|
+
data = tomllib.load(f)
|
|
583
|
+
except (tomllib.TOMLDecodeError, PermissionError, OSError) as exc:
|
|
584
|
+
logger.warning("Could not read config for cursor blink preference: %s", exc)
|
|
585
|
+
return True
|
|
586
|
+
|
|
587
|
+
ui = data.get("ui", {})
|
|
588
|
+
if not isinstance(ui, dict):
|
|
589
|
+
logger.warning(
|
|
590
|
+
"[ui] should be a table; got %s while loading cursor blink preference",
|
|
591
|
+
type(ui).__name__,
|
|
592
|
+
)
|
|
593
|
+
return True
|
|
594
|
+
|
|
595
|
+
value = ui.get("cursor_blink")
|
|
596
|
+
if isinstance(value, bool):
|
|
597
|
+
return value
|
|
598
|
+
if value is not None:
|
|
599
|
+
logger.warning(
|
|
600
|
+
"[ui].cursor_blink should be a boolean; got %s",
|
|
601
|
+
type(value).__name__,
|
|
602
|
+
)
|
|
603
|
+
return True
|
|
604
|
+
|
|
605
|
+
|
|
528
606
|
def _save_terminal_theme_mapping_result(
|
|
529
607
|
term_program: str,
|
|
530
608
|
name: str,
|
|
@@ -1328,6 +1406,10 @@ class DeepAgentsApp(App):
|
|
|
1328
1406
|
Loaded from the user's saved preference (or the default) so the app
|
|
1329
1407
|
boots with consistent colors before `/theme` runs.
|
|
1330
1408
|
"""
|
|
1409
|
+
|
|
1410
|
+
self._cursor_blink_enabled = _load_cursor_blink_preference()
|
|
1411
|
+
"""Whether the chat input cursor should blink (user preference)."""
|
|
1412
|
+
|
|
1331
1413
|
self.sync_terminal_background()
|
|
1332
1414
|
|
|
1333
1415
|
# Injected session config
|
|
@@ -1612,14 +1694,6 @@ class DeepAgentsApp(App):
|
|
|
1612
1694
|
loop re-enters the same module graph (see that method for why).
|
|
1613
1695
|
"""
|
|
1614
1696
|
|
|
1615
|
-
self._deepagents_import_lock = asyncio.Lock()
|
|
1616
|
-
"""Serializes cold imports into the Deep Agents graph after prewarm.
|
|
1617
|
-
|
|
1618
|
-
Startup model creation and skill discovery can both be triggered during
|
|
1619
|
-
first paint. If prewarm failed or did not cover a transitive module,
|
|
1620
|
-
both paths may cold-import overlapping modules at the same time.
|
|
1621
|
-
"""
|
|
1622
|
-
|
|
1623
1697
|
# Lifecycle flags & re-entry guards
|
|
1624
1698
|
self._connecting = (
|
|
1625
1699
|
server_kwargs is not None and not self._server_startup_deferred
|
|
@@ -1963,6 +2037,7 @@ class DeepAgentsApp(App):
|
|
|
1963
2037
|
|
|
1964
2038
|
self._status_bar = self.query_one("#status-bar", StatusBar)
|
|
1965
2039
|
self._chat_input = self.query_one("#input-area", ChatInput)
|
|
2040
|
+
self._chat_input.set_cursor_blink(blink=self._cursor_blink_enabled)
|
|
1966
2041
|
|
|
1967
2042
|
# Apply any skill commands discovered before the widget was mounted
|
|
1968
2043
|
if self._discovered_skills:
|
|
@@ -2406,8 +2481,9 @@ class DeepAgentsApp(App):
|
|
|
2406
2481
|
# graph in separate workers. Let prewarm finish first so CPython's
|
|
2407
2482
|
# per-module import locks cannot form a cycle.
|
|
2408
2483
|
await self._await_prewarm_imports()
|
|
2409
|
-
|
|
2410
|
-
|
|
2484
|
+
skills, roots = await asyncio.to_thread(
|
|
2485
|
+
self._discover_skills_and_roots_with_import_lock,
|
|
2486
|
+
)
|
|
2411
2487
|
except OSError:
|
|
2412
2488
|
logger.warning(
|
|
2413
2489
|
"Filesystem error during skill discovery",
|
|
@@ -2465,6 +2541,17 @@ class DeepAgentsApp(App):
|
|
|
2465
2541
|
assistant_id = self._assistant_id or DEFAULT_ASSISTANT_ID
|
|
2466
2542
|
return discover_skills_and_roots(assistant_id)
|
|
2467
2543
|
|
|
2544
|
+
def _discover_skills_and_roots_with_import_lock(
|
|
2545
|
+
self,
|
|
2546
|
+
) -> tuple[list[ExtendedSkillMetadata], list[Path]]:
|
|
2547
|
+
"""Discover skills while serializing Deep Agents SDK import entry.
|
|
2548
|
+
|
|
2549
|
+
Returns:
|
|
2550
|
+
Tuple of `(skill metadata list, pre-resolved containment roots)`.
|
|
2551
|
+
"""
|
|
2552
|
+
with _DEEPAGENTS_IMPORT_LOCK:
|
|
2553
|
+
return self._discover_skills_and_roots()
|
|
2554
|
+
|
|
2468
2555
|
async def _resolve_resume_thread(self) -> None:
|
|
2469
2556
|
"""Resolve a `-r` resume intent into a concrete thread ID.
|
|
2470
2557
|
|
|
@@ -2595,7 +2682,6 @@ class DeepAgentsApp(App):
|
|
|
2595
2682
|
# `_await_prewarm_imports` for the deadlock rationale.
|
|
2596
2683
|
await self._await_prewarm_imports()
|
|
2597
2684
|
|
|
2598
|
-
from deepagents_code.config import create_model
|
|
2599
2685
|
from deepagents_code.model_config import (
|
|
2600
2686
|
ModelConfigError,
|
|
2601
2687
|
save_recent_model,
|
|
@@ -2603,8 +2689,10 @@ class DeepAgentsApp(App):
|
|
|
2603
2689
|
)
|
|
2604
2690
|
|
|
2605
2691
|
try:
|
|
2606
|
-
|
|
2607
|
-
|
|
2692
|
+
result = await asyncio.to_thread(
|
|
2693
|
+
_create_model_with_deepagents_import_lock,
|
|
2694
|
+
**self._model_kwargs,
|
|
2695
|
+
)
|
|
2608
2696
|
except ModelConfigError as exc:
|
|
2609
2697
|
self.post_message(self.ServerStartFailed(error=exc))
|
|
2610
2698
|
return
|
|
@@ -2958,12 +3046,13 @@ class DeepAgentsApp(App):
|
|
|
2958
3046
|
# tool_display — hit on first message send and first tool
|
|
2959
3047
|
# approval. Best-effort: missing optional deps should not block the
|
|
2960
3048
|
# TUI from rendering.
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
3049
|
+
with _DEEPAGENTS_IMPORT_LOCK:
|
|
3050
|
+
from deepagents.backends import DEFAULT_EXECUTE_TIMEOUT # noqa: F401
|
|
3051
|
+
from langchain.agents.middleware.human_in_the_loop import ( # noqa: F401
|
|
3052
|
+
ApproveDecision,
|
|
3053
|
+
)
|
|
3054
|
+
from langchain_core.messages import AIMessage # noqa: F401
|
|
3055
|
+
from langgraph.types import Command # noqa: F401
|
|
2967
3056
|
except Exception:
|
|
2968
3057
|
logger.warning("Could not prewarm third-party imports", exc_info=True)
|
|
2969
3058
|
|
|
@@ -3349,9 +3438,13 @@ class DeepAgentsApp(App):
|
|
|
3349
3438
|
force = "--force" in parts[1:]
|
|
3350
3439
|
extras = [p for p in parts[1:] if not p.startswith("-")]
|
|
3351
3440
|
if not extras:
|
|
3441
|
+
from deepagents_code.extras_info import format_known_extras
|
|
3442
|
+
|
|
3352
3443
|
await self._mount_message(
|
|
3353
3444
|
AppMessage(
|
|
3354
|
-
"Usage: /install <extra> [--force]\
|
|
3445
|
+
"Usage: /install <extra> [--force]\n"
|
|
3446
|
+
"Example: /install quickjs\n\n"
|
|
3447
|
+
f"{format_known_extras()}",
|
|
3355
3448
|
),
|
|
3356
3449
|
)
|
|
3357
3450
|
return
|
|
@@ -3372,6 +3465,7 @@ class DeepAgentsApp(App):
|
|
|
3372
3465
|
KNOWN_EXTRAS,
|
|
3373
3466
|
MODEL_PROVIDER_EXTRAS,
|
|
3374
3467
|
SANDBOX_EXTRAS,
|
|
3468
|
+
ExtrasIntrospectionError,
|
|
3375
3469
|
)
|
|
3376
3470
|
from deepagents_code.update_check import (
|
|
3377
3471
|
create_update_log_path,
|
|
@@ -3406,12 +3500,20 @@ class DeepAgentsApp(App):
|
|
|
3406
3500
|
return
|
|
3407
3501
|
|
|
3408
3502
|
if extra not in KNOWN_EXTRAS and not force:
|
|
3503
|
+
try:
|
|
3504
|
+
manual_cmd = await asyncio.to_thread(install_extra_command, extra)
|
|
3505
|
+
except (ExtrasIntrospectionError, ValueError) as exc:
|
|
3506
|
+
logger.warning("/install command failed", exc_info=True)
|
|
3507
|
+
await self._mount_message(
|
|
3508
|
+
ErrorMessage(f"Install failed: {type(exc).__name__}: {exc}"),
|
|
3509
|
+
)
|
|
3510
|
+
return
|
|
3409
3511
|
known = ", ".join(sorted(KNOWN_EXTRAS))
|
|
3410
3512
|
await self._mount_message(
|
|
3411
3513
|
AppMessage(
|
|
3412
3514
|
f"'{extra}' is not a known extra.\n"
|
|
3413
3515
|
f"Known extras: {known}\n\n"
|
|
3414
|
-
f"This would run: `{
|
|
3516
|
+
f"This would run: `{manual_cmd}`\n"
|
|
3415
3517
|
f"Re-run with `--force` to install anyway: "
|
|
3416
3518
|
f"`/install {extra} --force`",
|
|
3417
3519
|
),
|
|
@@ -3422,7 +3524,16 @@ class DeepAgentsApp(App):
|
|
|
3422
3524
|
await self._mount_message(
|
|
3423
3525
|
AppMessage(f"Installing extra '{extra}'..."),
|
|
3424
3526
|
)
|
|
3425
|
-
|
|
3527
|
+
try:
|
|
3528
|
+
manual_cmd = await asyncio.to_thread(install_extra_command, extra)
|
|
3529
|
+
except (ExtrasIntrospectionError, ValueError) as exc:
|
|
3530
|
+
logger.warning("/install command failed", exc_info=True)
|
|
3531
|
+
await self._mount_message(
|
|
3532
|
+
ErrorMessage(
|
|
3533
|
+
f"Install failed: {type(exc).__name__}: {exc}\nLog: {log_path}",
|
|
3534
|
+
),
|
|
3535
|
+
)
|
|
3536
|
+
return
|
|
3426
3537
|
try:
|
|
3427
3538
|
success, output = await perform_install_extra(extra, log_path=log_path)
|
|
3428
3539
|
except (OSError, asyncio.CancelledError) as exc:
|
|
@@ -4843,9 +4954,21 @@ class DeepAgentsApp(App):
|
|
|
4843
4954
|
BYPASS_WHEN_CONNECTING,
|
|
4844
4955
|
IMMEDIATE_UI,
|
|
4845
4956
|
SIDE_EFFECT_FREE,
|
|
4957
|
+
STARTUP_RECOVERY_COMMANDS,
|
|
4846
4958
|
)
|
|
4847
4959
|
|
|
4848
4960
|
cmd = value.split(maxsplit=1)[0] if value else ""
|
|
4961
|
+
# Recovery escape hatch: when startup failed (`_server_startup_error`
|
|
4962
|
+
# set) and nothing is running, the commands that repair the session
|
|
4963
|
+
# must run instead of being parked behind the failure they fix — e.g.
|
|
4964
|
+
# `/install <pkg>` for a missing provider package. Gated on no active
|
|
4965
|
+
# work so a reinstall never swaps the running binary mid-turn.
|
|
4966
|
+
if (
|
|
4967
|
+
cmd in STARTUP_RECOVERY_COMMANDS
|
|
4968
|
+
and self._server_startup_error is not None
|
|
4969
|
+
and not (self._agent_running or self._shell_running)
|
|
4970
|
+
):
|
|
4971
|
+
return True
|
|
4849
4972
|
if cmd in BYPASS_WHEN_CONNECTING:
|
|
4850
4973
|
return self._connecting and not (self._agent_running or self._shell_running)
|
|
4851
4974
|
if cmd in IMMEDIATE_UI:
|
|
@@ -5841,7 +5964,7 @@ class DeepAgentsApp(App):
|
|
|
5841
5964
|
if cached is None:
|
|
5842
5965
|
try:
|
|
5843
5966
|
skills, allowed_roots = await asyncio.to_thread(
|
|
5844
|
-
self.
|
|
5967
|
+
self._discover_skills_and_roots_with_import_lock,
|
|
5845
5968
|
)
|
|
5846
5969
|
# Backfill cache so subsequent invocations are fast
|
|
5847
5970
|
self._discovered_skills = skills
|
|
@@ -6010,31 +6133,33 @@ class DeepAgentsApp(App):
|
|
|
6010
6133
|
"""Resolve the offload retention budget as a human-readable string.
|
|
6011
6134
|
|
|
6012
6135
|
Instantiates a model and computes summarization defaults, so this is
|
|
6013
|
-
not a trivial accessor.
|
|
6136
|
+
not a trivial accessor. Call only from a worker thread; cold imports
|
|
6137
|
+
and model construction run under the process-wide import lock.
|
|
6014
6138
|
|
|
6015
6139
|
Returns:
|
|
6016
6140
|
A string like `"20.0K (10% of 200.0K)"` or
|
|
6017
6141
|
`"last 6 messages"`, or `None` if the budget cannot be determined.
|
|
6018
6142
|
"""
|
|
6019
|
-
from deepagents_code.config import
|
|
6143
|
+
from deepagents_code.config import settings
|
|
6020
6144
|
|
|
6021
6145
|
try:
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6146
|
+
with _DEEPAGENTS_IMPORT_LOCK:
|
|
6147
|
+
from deepagents.middleware.summarization import (
|
|
6148
|
+
compute_summarization_defaults,
|
|
6149
|
+
)
|
|
6025
6150
|
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6151
|
+
model_spec = f"{settings.model_provider}:{settings.model_name}"
|
|
6152
|
+
result = _create_model_with_deepagents_import_lock(
|
|
6153
|
+
model_spec,
|
|
6154
|
+
profile_overrides=self._profile_override,
|
|
6155
|
+
)
|
|
6156
|
+
defaults = compute_summarization_defaults(result.model)
|
|
6157
|
+
from deepagents_code.offload import format_offload_limit
|
|
6033
6158
|
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6159
|
+
return format_offload_limit(
|
|
6160
|
+
defaults["keep"],
|
|
6161
|
+
settings.model_context_limit,
|
|
6162
|
+
)
|
|
6038
6163
|
except Exception: # best-effort for /tokens display
|
|
6039
6164
|
logger.debug("Failed to compute offload budget string", exc_info=True)
|
|
6040
6165
|
return None
|
|
@@ -6918,6 +7043,17 @@ class DeepAgentsApp(App):
|
|
|
6918
7043
|
if not messages.is_attached:
|
|
6919
7044
|
return
|
|
6920
7045
|
|
|
7046
|
+
if isinstance(widget, QueuedUserMessage):
|
|
7047
|
+
# Queued placeholders mount at the bottom and stay out of the
|
|
7048
|
+
# message store; drain remounts them as real UserMessage widgets.
|
|
7049
|
+
await messages.mount(widget)
|
|
7050
|
+
try:
|
|
7051
|
+
input_container = self.query_one("#bottom-app-container", Container)
|
|
7052
|
+
input_container.scroll_visible()
|
|
7053
|
+
except NoMatches:
|
|
7054
|
+
pass
|
|
7055
|
+
return
|
|
7056
|
+
|
|
6921
7057
|
# Store message data for virtualization
|
|
6922
7058
|
message_data = MessageData.from_widget(widget)
|
|
6923
7059
|
if not widget.id:
|
|
@@ -6927,14 +7063,9 @@ class DeepAgentsApp(App):
|
|
|
6927
7063
|
self._message_store.append(message_data)
|
|
6928
7064
|
footer = self._build_message_timestamp_footer(message_data)
|
|
6929
7065
|
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
await messages.mount(widget)
|
|
6934
|
-
else:
|
|
6935
|
-
await self._mount_before_queued(messages, widget)
|
|
6936
|
-
if footer is not None:
|
|
6937
|
-
await self._mount_before_queued(messages, footer)
|
|
7066
|
+
await self._mount_before_queued(messages, widget)
|
|
7067
|
+
if footer is not None:
|
|
7068
|
+
await self._mount_before_queued(messages, footer)
|
|
6938
7069
|
|
|
6939
7070
|
# Prune old widgets if window exceeded
|
|
6940
7071
|
await self._prune_old_messages()
|
|
@@ -7622,7 +7753,7 @@ class DeepAgentsApp(App):
|
|
|
7622
7753
|
"""
|
|
7623
7754
|
if self._chat_input is None:
|
|
7624
7755
|
return
|
|
7625
|
-
self._chat_input.set_cursor_blink(blink=
|
|
7756
|
+
self._chat_input.set_cursor_blink(blink=self._cursor_blink_enabled)
|
|
7626
7757
|
if isinstance(self.screen, ModalScreen):
|
|
7627
7758
|
return
|
|
7628
7759
|
if self._pending_approval_widget or self._pending_ask_user_widget:
|
|
@@ -9198,7 +9329,7 @@ class DeepAgentsApp(App):
|
|
|
9198
9329
|
name=entry.name,
|
|
9199
9330
|
transport=entry.transport,
|
|
9200
9331
|
status="disabled",
|
|
9201
|
-
error="Re-enabled —
|
|
9332
|
+
error="Re-enabled — press Ctrl+R to load.",
|
|
9202
9333
|
),
|
|
9203
9334
|
)
|
|
9204
9335
|
self._mcp_server_info = updated
|
|
@@ -9995,7 +10126,7 @@ class DeepAgentsApp(App):
|
|
|
9995
10126
|
messaging (which model couldn't be restored and what the session
|
|
9996
10127
|
is falling back to) rather than the interactive `/model` errors.
|
|
9997
10128
|
"""
|
|
9998
|
-
from deepagents_code.config import
|
|
10129
|
+
from deepagents_code.config import detect_provider, settings
|
|
9999
10130
|
from deepagents_code.model_config import (
|
|
10000
10131
|
ModelSpec,
|
|
10001
10132
|
ProviderAuthState,
|
|
@@ -10121,7 +10252,8 @@ class DeepAgentsApp(App):
|
|
|
10121
10252
|
display = f"{provider}:{model_name}"
|
|
10122
10253
|
|
|
10123
10254
|
try:
|
|
10124
|
-
result =
|
|
10255
|
+
result = await asyncio.to_thread(
|
|
10256
|
+
_create_model_with_deepagents_import_lock,
|
|
10125
10257
|
display,
|
|
10126
10258
|
extra_kwargs=extra_kwargs,
|
|
10127
10259
|
profile_overrides=self._profile_override,
|
|
@@ -248,6 +248,11 @@ class AskUserMiddleware(AgentMiddleware[Any, ContextT, ResponseT]):
|
|
|
248
248
|
questions=questions,
|
|
249
249
|
tool_call_id=tool_call_id,
|
|
250
250
|
)
|
|
251
|
+
# interrupt() raises GraphInterrupt from INSIDE tool execution,
|
|
252
|
+
# within ToolNode's wrap_tool_call chain. Any
|
|
253
|
+
# wrap_tool_call middleware that catches exceptions MUST re-raise
|
|
254
|
+
# GraphBubbleUp — a broad `except Exception` (e.g. ToolRetryMiddleware)
|
|
255
|
+
# would swallow this interrupt and silently break ask_user.
|
|
251
256
|
response = interrupt(ask_request)
|
|
252
257
|
return _parse_answers(response, questions, tool_call_id)
|
|
253
258
|
|
|
@@ -282,6 +282,23 @@ Includes both debug helpers (`/debug-error`) and recovery escape hatches
|
|
|
282
282
|
(`/restart` — hot-respawn the app-owned LangGraph server).
|
|
283
283
|
"""
|
|
284
284
|
|
|
285
|
+
STARTUP_RECOVERY_COMMANDS: frozenset[str] = frozenset(
|
|
286
|
+
{"/install", "/reload", "/update"}
|
|
287
|
+
)
|
|
288
|
+
"""`QUEUED`-tier commands that must still run when startup has failed.
|
|
289
|
+
|
|
290
|
+
When the configured model can't be built (e.g. its provider package is
|
|
291
|
+
missing) the server never starts and the app holds a `_server_startup_error`
|
|
292
|
+
state that parks queued messages. These are the recovery escape hatches for
|
|
293
|
+
that state — install the missing package, reload config/env, or upgrade the
|
|
294
|
+
tool — so they must bypass the queue rather than sit behind the very failure
|
|
295
|
+
they repair. `/model` and `/auth` already escape via `IMMEDIATE_UI` (which
|
|
296
|
+
opens a modal and defers the real work); the commands here instead perform
|
|
297
|
+
their repair work directly, so they stay `QUEUED` and rely on this exemption.
|
|
298
|
+
The bypass itself is gated in `_can_bypass_queue`. Every entry is also
|
|
299
|
+
`QUEUE_BOUND` — the recovery exemption is orthogonal to the normal queue.
|
|
300
|
+
"""
|
|
301
|
+
|
|
285
302
|
ALL_CLASSIFIED: frozenset[str] = (
|
|
286
303
|
ALWAYS_IMMEDIATE
|
|
287
304
|
| BYPASS_WHEN_CONNECTING
|
|
@@ -24,6 +24,11 @@ logger = logging.getLogger(__name__)
|
|
|
24
24
|
|
|
25
25
|
_EXTRA_MARKER_RE = re.compile(r"""extra\s*==\s*["']([^"']+)["']""")
|
|
26
26
|
|
|
27
|
+
|
|
28
|
+
class ExtrasIntrospectionError(RuntimeError):
|
|
29
|
+
"""Raised when installed extras cannot be determined safely."""
|
|
30
|
+
|
|
31
|
+
|
|
27
32
|
_COMPOSITE_EXTRAS: frozenset[str] = frozenset({"all-providers", "all-sandboxes"})
|
|
28
33
|
"""Extras whose package set is already covered by other, more specific extras.
|
|
29
34
|
|
|
@@ -84,6 +89,31 @@ model-provider-drift checks; new extras must be added to the corresponding
|
|
|
84
89
|
category frozenset above.
|
|
85
90
|
"""
|
|
86
91
|
|
|
92
|
+
|
|
93
|
+
def format_known_extras() -> str:
|
|
94
|
+
"""Render the installable extras grouped by category as plain text.
|
|
95
|
+
|
|
96
|
+
Drives the no-argument `/install` slash-command help so users can
|
|
97
|
+
discover valid extras without consulting `pyproject.toml`. Sourced from
|
|
98
|
+
the category frozensets above, so it stays in sync with `KNOWN_EXTRAS`
|
|
99
|
+
automatically.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Multi-line string with one labeled line per category, each listing
|
|
103
|
+
its extras alphabetically.
|
|
104
|
+
"""
|
|
105
|
+
groups: tuple[tuple[str, frozenset[str]], ...] = (
|
|
106
|
+
("Model providers", MODEL_PROVIDER_EXTRAS),
|
|
107
|
+
("Sandboxes", SANDBOX_EXTRAS),
|
|
108
|
+
("Other", STANDALONE_EXTRAS),
|
|
109
|
+
)
|
|
110
|
+
lines = ["Available extras:"]
|
|
111
|
+
lines.extend(
|
|
112
|
+
f" {label}: {', '.join(sorted(extras))}" for label, extras in groups if extras
|
|
113
|
+
)
|
|
114
|
+
return "\n".join(lines)
|
|
115
|
+
|
|
116
|
+
|
|
87
117
|
ExtrasStatus = dict[str, list[tuple[str, str]]]
|
|
88
118
|
"""Mapping from extra name to `(package, installed_version)` tuples.
|
|
89
119
|
|
|
@@ -155,21 +185,55 @@ def get_extras_status(
|
|
|
155
185
|
return result
|
|
156
186
|
|
|
157
187
|
|
|
188
|
+
def installed_extra_names(
|
|
189
|
+
distribution_name: str = "deepagents-code",
|
|
190
|
+
*,
|
|
191
|
+
strict: bool = False,
|
|
192
|
+
) -> set[str]:
|
|
193
|
+
"""Return extras with at least one installed dependency.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
distribution_name: Name of the installed distribution to inspect.
|
|
197
|
+
strict: Raise when the distribution metadata cannot be read or parsed
|
|
198
|
+
reliably.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Set of extra names whose optional dependency metadata has at least one
|
|
202
|
+
installed package. Composite extras are excluded.
|
|
203
|
+
"""
|
|
204
|
+
statuses = get_optional_dependency_status(distribution_name, strict=strict)
|
|
205
|
+
return {extra.name for extra in statuses if extra.installed}
|
|
206
|
+
|
|
207
|
+
|
|
158
208
|
def get_optional_dependency_status(
|
|
159
209
|
distribution_name: str = "deepagents-code",
|
|
210
|
+
*,
|
|
211
|
+
strict: bool = False,
|
|
160
212
|
) -> tuple[ExtraDependencyStatus, ...]:
|
|
161
213
|
"""Return installed and missing optional dependencies grouped by extra.
|
|
162
214
|
|
|
163
215
|
Args:
|
|
164
216
|
distribution_name: Name of the installed distribution to inspect.
|
|
217
|
+
strict: Raise when the distribution metadata cannot be read or parsed
|
|
218
|
+
reliably.
|
|
165
219
|
|
|
166
220
|
Returns:
|
|
167
221
|
Sorted tuple of optional extra statuses. An empty tuple is returned
|
|
168
222
|
when the distribution itself is not found.
|
|
223
|
+
|
|
224
|
+
Raises:
|
|
225
|
+
ExtrasIntrospectionError: If `strict` is `True` and metadata
|
|
226
|
+
introspection fails.
|
|
169
227
|
"""
|
|
170
228
|
try:
|
|
171
229
|
dist = distribution(distribution_name)
|
|
172
230
|
except PackageNotFoundError:
|
|
231
|
+
if strict:
|
|
232
|
+
msg = (
|
|
233
|
+
f"Distribution {distribution_name!r} not found; cannot preserve "
|
|
234
|
+
"already-installed extras safely"
|
|
235
|
+
)
|
|
236
|
+
raise ExtrasIntrospectionError(msg) from None
|
|
173
237
|
# Editable installs renamed by the user, dev checkouts without metadata,
|
|
174
238
|
# or vendored copies all hit this path. The dependency screen otherwise
|
|
175
239
|
# silently renders "none detected" twice; warn so the cause is visible.
|
|
@@ -186,6 +250,12 @@ def get_optional_dependency_status(
|
|
|
186
250
|
try:
|
|
187
251
|
req = Requirement(raw)
|
|
188
252
|
except InvalidRequirement:
|
|
253
|
+
if strict:
|
|
254
|
+
msg = (
|
|
255
|
+
"Could not parse optional-dependency metadata; cannot "
|
|
256
|
+
f"preserve already-installed extras safely: {raw}"
|
|
257
|
+
)
|
|
258
|
+
raise ExtrasIntrospectionError(msg) from None
|
|
189
259
|
logger.warning("Could not parse Requires-Dist entry: %s", raw)
|
|
190
260
|
continue
|
|
191
261
|
if not req.marker:
|