deepagents-cli 0.0.41__tar.gz → 0.0.42__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.41 → deepagents_cli-0.0.42}/CHANGELOG.md +20 -11
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/PKG-INFO +5 -5
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/_env_vars.py +3 -0
- deepagents_cli-0.0.42/deepagents_cli/_textual_patches.py +66 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/_version.py +1 -1
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/agent.py +34 -7
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/app.py +23 -1
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/config.py +82 -35
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/local_context.py +21 -7
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/system_prompt.md +1 -1
- deepagents_cli-0.0.42/deepagents_cli/terminal_capabilities.py +115 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/model_selector.py +23 -2
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/pyproject.toml +7 -4
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/conftest.py +15 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_agent.py +110 -6
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_config.py +372 -45
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_local_context.py +39 -10
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_model_switch.py +80 -0
- deepagents_cli-0.0.42/tests/unit_tests/test_terminal_capabilities.py +203 -0
- deepagents_cli-0.0.42/tests/unit_tests/test_textual_patches.py +92 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_version.py +11 -1
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/uv.lock +34 -21
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/.gitignore +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/DEV.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/Makefile +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/README.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/THREAT_MODEL.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/__main__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/_ask_user_types.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/_cli_context.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/_debug.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/_git.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/_server_config.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/_session_stats.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/_testing_models.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/app.tcss +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/ask_user.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/built_in_skills/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/built_in_skills/remember/SKILL.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/clipboard.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/command_registry.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/configurable_model.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/default_agent_prompt.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/deploy/bundler.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/deploy/commands.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/deploy/config.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/deploy/templates.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/editor.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/extras_info.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/file_ops.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/formatting.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/hooks.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/input.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/integrations/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/integrations/sandbox_factory.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/integrations/sandbox_provider.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/main.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/mcp_tools.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/mcp_trust.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/media_utils.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/model_config.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/non_interactive.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/notifications.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/offload.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/output.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/project_utils.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/py.typed +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/remote_client.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/server.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/server_graph.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/server_manager.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/sessions.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/skills/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/skills/commands.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/skills/invocation.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/skills/load.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/subagents.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/textual_adapter.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/theme.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/token_state.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/tool_display.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/tools.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/ui.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/unicode_security.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/update_check.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/_links.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/agent_selector.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/approval.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/ask_user.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/autocomplete.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/chat_input.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/diff.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/history.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/loading.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/mcp_viewer.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/message_store.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/messages.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/notification_center.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/notification_detail.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/notification_settings.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/status.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/theme_selector.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/thread_selector.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/tool_renderers.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/tool_widgets.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/update_available.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/deepagents_cli/widgets/welcome.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/deploy-content-writer/.env.example +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/deploy-content-writer/skills/blog-post/SKILL.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/deploy-content-writer/skills/social-media/SKILL.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/deploy-content-writer/user/context.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/deploy-content-writer/user/preferences.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/skills/arxiv-search/SKILL.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/examples/skills/web-research/SKILL.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/images/cli.png +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/scripts/check_imports.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/scripts/debug_server.sh +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/scripts/install.sh +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/README.md +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/integration_tests/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/integration_tests/conftest.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/integration_tests/test_acp_mode.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/integration_tests/test_compact_resume.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/deploy/test_bundler.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/deploy/test_commands.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/deploy/test_config.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/skills/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/skills/test_commands.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/skills/test_load.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_agent_friendly.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_agent_selector.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_app.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_approval.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_args.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_ask_user.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_ask_user_middleware.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_autocomplete.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_charset.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_chat_input.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_command_registry.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_compact_tool.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_configurable_model.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_debug.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_editor.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_end_to_end.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_env_vars.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_exception_handling.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_extras_info.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_file_ops.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_formatting.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_git.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_history.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_hooks.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_imports.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_input_parsing.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_links.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_loading.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_main.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_main_args.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_mcp_tools.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_mcp_trust.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_mcp_viewer.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_media_utils.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_message_store.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_messages.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_model_config.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_model_selector.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_non_interactive.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_notification_center.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_notification_detail.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_notifications.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_offload.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_offload_dict_messages.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_output.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_reload.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_remote_client.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_server.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_server_config.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_server_graph.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_server_helpers.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_server_manager.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_session_stats.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_sessions.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_skill_invocation.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_status.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_subagents.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_textual_adapter.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_theme.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_thread_selector.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_token_tracker.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_tool_display.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_ui.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_unicode_security.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_update_available.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_update_check.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/test_welcome.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/tools/__init__.py +0 -0
- {deepagents_cli-0.0.41 → deepagents_cli-0.0.42}/tests/unit_tests/tools/test_fetch_url.py +0 -0
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.0.
|
|
4
|
-
|
|
3
|
+
## [0.0.42](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.41...deepagents-cli==0.0.42) (2026-04-29)
|
|
5
4
|
|
|
6
5
|
### Features
|
|
7
6
|
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
* `shift+enter` newline on kitty-capable terminals ([#2869](https://github.com/langchain-ai/deepagents/issues/2869)) ([34e6614](https://github.com/langchain-ai/deepagents/commit/34e6614a2c6e6a7e33f763ac5b527c13b324a690))
|
|
8
|
+
* Hint `Enter` behavior in `/model` empty state ([#2933](https://github.com/langchain-ai/deepagents/issues/2933)) ([7cffa16](https://github.com/langchain-ai/deepagents/commit/7cffa16a072bc77def78e4cda09c2e5a2cf8ca39))
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* Queue `/model` switches during server startup ([#2895](https://github.com/langchain-ai/deepagents/issues/2895)) ([6ed7b65](https://github.com/langchain-ai/deepagents/commit/6ed7b65a40ac5bd926e94edd944bd552e8d6b5b4))
|
|
13
|
+
|
|
14
|
+
## [0.0.41](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.40...deepagents-cli==0.0.41) (2026-04-21)
|
|
15
|
+
|
|
16
|
+
### Features
|
|
13
17
|
|
|
18
|
+
* `--startup-cmd` flag ([#2841](https://github.com/langchain-ai/deepagents/issues/2841)) ([8adcc2c](https://github.com/langchain-ai/deepagents/commit/8adcc2c2e612346c263d02d1ec5c33e0d63da5a3))
|
|
19
|
+
* Actionable notifications, update modal ([#2855](https://github.com/langchain-ai/deepagents/issues/2855)) ([5fcd368](https://github.com/langchain-ai/deepagents/commit/5fcd368088079a84f151e0a3f5e4b9ac29c360c1))
|
|
20
|
+
* Custom auth via `[auth]` in `deepagents deploy` ([#2734](https://github.com/langchain-ai/deepagents/issues/2734)) ([417ddaa](https://github.com/langchain-ai/deepagents/commit/417ddaab4804a54a8f83721bb8577d65cfa3659f))
|
|
21
|
+
* Refresh footer git branch after shell commands ([#2851](https://github.com/langchain-ai/deepagents/issues/2851)) ([ee4fddd](https://github.com/langchain-ai/deepagents/commit/ee4fddde9454ee8f7ede98ee9a346da6c5ccd3d9))
|
|
22
|
+
* Rework `/version`, add release-age and editable-install guard ([#2854](https://github.com/langchain-ai/deepagents/issues/2854)) ([1ae053f](https://github.com/langchain-ai/deepagents/commit/1ae053f347679e58562d2b81eb6d6e6e9bbf0b07))
|
|
14
23
|
|
|
15
24
|
### Bug Fixes
|
|
16
25
|
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
26
|
+
* Gate agent-swap resume hint on server checkpoint ([#2862](https://github.com/langchain-ai/deepagents/issues/2862)) ([f14b9cd](https://github.com/langchain-ai/deepagents/commit/f14b9cd3cc41f92ddb089d4294cba8496d517807))
|
|
27
|
+
* Keep thinking spinner visible during text streaming ([#2849](https://github.com/langchain-ai/deepagents/issues/2849)) ([2cb2244](https://github.com/langchain-ai/deepagents/commit/2cb22446bc1351d20e8bbfa9f23b5d668947351f))
|
|
28
|
+
* Re-show thinking spinner on hitl/`ask_user` resume ([#2847](https://github.com/langchain-ai/deepagents/issues/2847)) ([34a6167](https://github.com/langchain-ai/deepagents/commit/34a6167b0c275c7e4da067ef276a837f60da2f8a))
|
|
29
|
+
* Restore `ctrl+j` newline keybinding ([#2827](https://github.com/langchain-ai/deepagents/issues/2827)) ([2e1a3f4](https://github.com/langchain-ai/deepagents/commit/2e1a3f45a9ff56390e294ea5b0f6a837200874ec))
|
|
21
30
|
|
|
22
31
|
## [0.0.40](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.39...deepagents-cli==0.0.40) (2026-04-20)
|
|
23
32
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.42
|
|
4
4
|
Summary: Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities.
|
|
5
5
|
Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
|
|
6
6
|
Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
|
|
@@ -27,9 +27,9 @@ Classifier: Topic :: Terminals
|
|
|
27
27
|
Requires-Python: <4.0,>=3.11
|
|
28
28
|
Requires-Dist: aiosqlite<1.0.0,>=0.19.0
|
|
29
29
|
Requires-Dist: deepagents-acp>=0.0.4
|
|
30
|
-
Requires-Dist: deepagents==0.5.
|
|
30
|
+
Requires-Dist: deepagents==0.5.4
|
|
31
31
|
Requires-Dist: httpx<1.0.0,>=0.28.1
|
|
32
|
-
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.
|
|
32
|
+
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.2
|
|
33
33
|
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.1
|
|
34
34
|
Requires-Dist: langchain-mcp-adapters<1.0.0,>=0.2.0
|
|
35
35
|
Requires-Dist: langchain-openai<2.0.0,>=1.1.12
|
|
@@ -57,7 +57,7 @@ Requires-Dist: uuid-utils<1.0.0,>=0.10.0
|
|
|
57
57
|
Provides-Extra: agentcore
|
|
58
58
|
Requires-Dist: langchain-agentcore-codeinterpreter>=0.0.1; extra == 'agentcore'
|
|
59
59
|
Provides-Extra: all-providers
|
|
60
|
-
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.
|
|
60
|
+
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.2; extra == 'all-providers'
|
|
61
61
|
Requires-Dist: langchain-aws<2.0.0,>=1.0.0; extra == 'all-providers'
|
|
62
62
|
Requires-Dist: langchain-baseten<1.0.0,>=0.1.9; extra == 'all-providers'
|
|
63
63
|
Requires-Dist: langchain-cohere<1.0.0,>=0.5.0; extra == 'all-providers'
|
|
@@ -82,7 +82,7 @@ Requires-Dist: langchain-daytona>=0.0.4; extra == 'all-sandboxes'
|
|
|
82
82
|
Requires-Dist: langchain-modal>=0.0.2; extra == 'all-sandboxes'
|
|
83
83
|
Requires-Dist: langchain-runloop>=0.0.3; extra == 'all-sandboxes'
|
|
84
84
|
Provides-Extra: anthropic
|
|
85
|
-
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.
|
|
85
|
+
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.2; extra == 'anthropic'
|
|
86
86
|
Provides-Extra: baseten
|
|
87
87
|
Requires-Dist: langchain-baseten<1.0.0,>=0.1.9; extra == 'baseten'
|
|
88
88
|
Provides-Extra: bedrock
|
|
@@ -52,6 +52,9 @@ real PyPI release. Any non-empty value enables the flag (including `"0"` or
|
|
|
52
52
|
EXTRA_SKILLS_DIRS = "DEEPAGENTS_CLI_EXTRA_SKILLS_DIRS"
|
|
53
53
|
"""Colon-separated paths added to the skill containment allowlist."""
|
|
54
54
|
|
|
55
|
+
KITTY_KEYBOARD = "DEEPAGENTS_CLI_KITTY_KEYBOARD"
|
|
56
|
+
"""Override kitty-keyboard detection (`1` forces on, `0` forces off)."""
|
|
57
|
+
|
|
55
58
|
LANGSMITH_PROJECT = "DEEPAGENTS_CLI_LANGSMITH_PROJECT"
|
|
56
59
|
"""Override LangSmith project name for agent traces."""
|
|
57
60
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
r"""Preserve the `alt` modifier on legacy `ESC + <byte>` sequences.
|
|
2
|
+
|
|
3
|
+
Upstream `XTermParser._sequence_to_key_events` drops the `alt` flag on
|
|
4
|
+
the tuple-branch fast path, so VSCode's `sendSequence` shift+enter
|
|
5
|
+
binding (which writes `\x1b\r` to the PTY) arrives as bare `enter`
|
|
6
|
+
instead of `alt+enter`. Tracked in Textualize/textual#6378. Remove this
|
|
7
|
+
file and the Textual pin comment in `pyproject.toml` when that lands.
|
|
8
|
+
|
|
9
|
+
Imported for side effect from `app.py` before any `App()` is created.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from collections.abc import Iterable
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
_ESC_PREFIX_LEN = 2
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
from textual import events
|
|
26
|
+
from textual._ansi_sequences import (
|
|
27
|
+
ANSI_SEQUENCES_KEYS, # noqa: PLC2701
|
|
28
|
+
IGNORE_SEQUENCE, # noqa: PLC2701
|
|
29
|
+
)
|
|
30
|
+
from textual._xterm_parser import XTermParser # noqa: PLC2701
|
|
31
|
+
|
|
32
|
+
_original = XTermParser._sequence_to_key_events
|
|
33
|
+
except (ImportError, AttributeError) as exc: # pragma: no cover - defensive
|
|
34
|
+
logger.warning("Textual keyboard parser patch skipped: %s", exc)
|
|
35
|
+
else:
|
|
36
|
+
|
|
37
|
+
def _emit_alt(keys: tuple, character: str | None) -> Iterable[events.Key]:
|
|
38
|
+
for key in keys:
|
|
39
|
+
yield events.Key(f"alt+{key.value}", character)
|
|
40
|
+
|
|
41
|
+
def _sequence_to_key_events_with_alt(
|
|
42
|
+
self: XTermParser, sequence: str, alt: bool = False
|
|
43
|
+
) -> Iterable[events.Key]:
|
|
44
|
+
# Fast path: \x1b<byte> on first pass. Short-circuits the ~100 ms
|
|
45
|
+
# escape-delay wait when both bytes arrive together. Semantic side
|
|
46
|
+
# effect: \x1b\x1b dispatches as `alt+escape` with no delay, matching
|
|
47
|
+
# crossterm and Node TTY.
|
|
48
|
+
if not alt and len(sequence) == _ESC_PREFIX_LEN and sequence[0] == "\x1b":
|
|
49
|
+
inner = ANSI_SEQUENCES_KEYS.get(sequence[1])
|
|
50
|
+
if inner is not IGNORE_SEQUENCE and isinstance(inner, tuple):
|
|
51
|
+
yield from _emit_alt(inner, None)
|
|
52
|
+
return
|
|
53
|
+
# Correctness fix (Textualize/textual#6378): preserve `alt` on the
|
|
54
|
+
# reissue path for single-byte tuple mappings.
|
|
55
|
+
if alt:
|
|
56
|
+
keys = ANSI_SEQUENCES_KEYS.get(sequence)
|
|
57
|
+
if keys is not IGNORE_SEQUENCE and isinstance(keys, tuple):
|
|
58
|
+
character = sequence if len(sequence) == 1 else None
|
|
59
|
+
yield from _emit_alt(keys, character)
|
|
60
|
+
return
|
|
61
|
+
yield from _original(self, sequence, alt=alt)
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
XTermParser._sequence_to_key_events = _sequence_to_key_events_with_alt # ty: ignore[invalid-assignment]
|
|
65
|
+
except (AttributeError, TypeError) as exc: # pragma: no cover - defensive
|
|
66
|
+
logger.warning("Textual keyboard parser patch assignment rejected: %s", exc)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Version information and lightweight constants for `deepagents-cli`."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.0.
|
|
3
|
+
__version__ = "0.0.42" # 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."""
|
|
@@ -16,6 +16,18 @@ from deepagents.backends import CompositeBackend, LocalShellBackend
|
|
|
16
16
|
from deepagents.backends.filesystem import FilesystemBackend
|
|
17
17
|
from deepagents.middleware import MemoryMiddleware, SkillsMiddleware
|
|
18
18
|
|
|
19
|
+
# Backwards-compat flag: SDKs before 0.5.4 accept only `list[str]` for
|
|
20
|
+
# `SkillsMiddleware.sources`; newer SDKs expose the `SkillSource` alias
|
|
21
|
+
# that permits `(path, label)` tuples. The `skills` module is already
|
|
22
|
+
# loaded by the `SkillsMiddleware` import above, so the extra lookup
|
|
23
|
+
# here adds no startup cost.
|
|
24
|
+
try:
|
|
25
|
+
from deepagents.middleware.skills import SkillSource as _SkillSource # noqa: F401
|
|
26
|
+
except ImportError:
|
|
27
|
+
_SUPPORTS_SKILL_SOURCE_TUPLES = False
|
|
28
|
+
else:
|
|
29
|
+
_SUPPORTS_SKILL_SOURCE_TUPLES = True
|
|
30
|
+
|
|
19
31
|
if TYPE_CHECKING:
|
|
20
32
|
from collections.abc import Awaitable, Callable, Sequence
|
|
21
33
|
|
|
@@ -1116,25 +1128,40 @@ def create_cli_agent(
|
|
|
1116
1128
|
# built-in -> user .deepagents -> user .agents
|
|
1117
1129
|
# -> project .deepagents -> project .agents
|
|
1118
1130
|
# -> user .claude (experimental) -> project .claude (experimental)
|
|
1119
|
-
sources
|
|
1120
|
-
|
|
1131
|
+
# Labels disambiguate user- vs project-scoped sources that share a
|
|
1132
|
+
# `.../skills` leaf; the middleware would otherwise derive identical
|
|
1133
|
+
# labels from the parent directory name.
|
|
1134
|
+
sources: list[tuple[str, str]] = [
|
|
1135
|
+
(str(settings.get_built_in_skills_dir()), "Built-in"),
|
|
1136
|
+
(str(skills_dir), "User Deepagents"),
|
|
1137
|
+
(str(user_agent_skills_dir), "User Agents"),
|
|
1138
|
+
]
|
|
1121
1139
|
if project_skills_dir:
|
|
1122
|
-
sources.append(str(project_skills_dir))
|
|
1140
|
+
sources.append((str(project_skills_dir), "Project Deepagents"))
|
|
1123
1141
|
if project_agent_skills_dir:
|
|
1124
|
-
sources.append(str(project_agent_skills_dir))
|
|
1142
|
+
sources.append((str(project_agent_skills_dir), "Project Agents"))
|
|
1125
1143
|
|
|
1126
1144
|
# Experimental: Claude Code skill directories
|
|
1127
1145
|
user_claude_skills_dir = settings.get_user_claude_skills_dir()
|
|
1128
1146
|
if user_claude_skills_dir.exists():
|
|
1129
|
-
sources.append(str(user_claude_skills_dir))
|
|
1147
|
+
sources.append((str(user_claude_skills_dir), "User Claude"))
|
|
1130
1148
|
project_claude_skills_dir = settings.get_project_claude_skills_dir()
|
|
1131
1149
|
if project_claude_skills_dir:
|
|
1132
|
-
sources.append(str(project_claude_skills_dir))
|
|
1150
|
+
sources.append((str(project_claude_skills_dir), "Project Claude"))
|
|
1151
|
+
|
|
1152
|
+
# Backwards-compat: strip labels when the installed SDK is too old
|
|
1153
|
+
# to accept `(path, label)` tuples. Label-based disambiguation
|
|
1154
|
+
# regresses to the pre-alias behavior (user- and project-scoped
|
|
1155
|
+
# `.claude/skills` collapse to the same label), but functionality
|
|
1156
|
+
# is preserved.
|
|
1157
|
+
middleware_sources: Sequence[str | tuple[str, str]] = (
|
|
1158
|
+
sources if _SUPPORTS_SKILL_SOURCE_TUPLES else [path for path, _ in sources]
|
|
1159
|
+
)
|
|
1133
1160
|
|
|
1134
1161
|
agent_middleware.append(
|
|
1135
1162
|
SkillsMiddleware(
|
|
1136
1163
|
backend=FilesystemBackend(),
|
|
1137
|
-
sources=
|
|
1164
|
+
sources=middleware_sources,
|
|
1138
1165
|
)
|
|
1139
1166
|
)
|
|
1140
1167
|
|
|
@@ -33,7 +33,11 @@ from textual.widgets._toast import (
|
|
|
33
33
|
Toast as _Toast, # noqa: PLC2701 # for Toast click routing
|
|
34
34
|
)
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
# Applied as an import-time side effect; must come before any App is created.
|
|
37
|
+
from deepagents_cli import (
|
|
38
|
+
_textual_patches, # noqa: F401
|
|
39
|
+
theme,
|
|
40
|
+
)
|
|
37
41
|
from deepagents_cli._cli_context import CLIContext
|
|
38
42
|
from deepagents_cli._git import (
|
|
39
43
|
read_git_branch_from_filesystem,
|
|
@@ -6370,6 +6374,24 @@ class DeepAgentsApp(App):
|
|
|
6370
6374
|
model_spec = model_spec.removeprefix(":")
|
|
6371
6375
|
|
|
6372
6376
|
if not self._remote_agent():
|
|
6377
|
+
if self._connecting:
|
|
6378
|
+
from functools import partial
|
|
6379
|
+
|
|
6380
|
+
self._defer_action(
|
|
6381
|
+
DeferredAction(
|
|
6382
|
+
kind="model_switch",
|
|
6383
|
+
execute=partial(
|
|
6384
|
+
self._switch_model,
|
|
6385
|
+
model_spec,
|
|
6386
|
+
extra_kwargs=extra_kwargs,
|
|
6387
|
+
),
|
|
6388
|
+
)
|
|
6389
|
+
)
|
|
6390
|
+
self.notify(
|
|
6391
|
+
"Model will switch once the session is ready.",
|
|
6392
|
+
timeout=3,
|
|
6393
|
+
)
|
|
6394
|
+
return
|
|
6373
6395
|
await self._mount_message(
|
|
6374
6396
|
ErrorMessage("Model switching requires a server-backed session.")
|
|
6375
6397
|
)
|
|
@@ -496,14 +496,22 @@ def is_ascii_mode() -> bool:
|
|
|
496
496
|
|
|
497
497
|
|
|
498
498
|
def newline_shortcut() -> str:
|
|
499
|
-
"""Return the
|
|
499
|
+
"""Return the terminal-appropriate label for the newline keyboard shortcut.
|
|
500
500
|
|
|
501
|
-
|
|
502
|
-
|
|
501
|
+
Prefers `Shift+Enter` when the terminal is known to support the kitty
|
|
502
|
+
keyboard protocol, either via conservative terminal-identity heuristics
|
|
503
|
+
or the `DEEPAGENTS_CLI_KITTY_KEYBOARD` override. Falls back to
|
|
504
|
+
`Option+Enter` on macOS and `Ctrl+J` elsewhere — both survive legacy
|
|
505
|
+
terminals that strip the shift modifier from `Enter`.
|
|
503
506
|
|
|
504
507
|
Returns:
|
|
505
|
-
A human-readable shortcut string,
|
|
508
|
+
A human-readable shortcut string,
|
|
509
|
+
e.g. `'Shift+Enter'`, `'Option+Enter'`, or `'Ctrl+J'`.
|
|
506
510
|
"""
|
|
511
|
+
from deepagents_cli.terminal_capabilities import supports_kitty_keyboard_protocol
|
|
512
|
+
|
|
513
|
+
if supports_kitty_keyboard_protocol():
|
|
514
|
+
return "Shift+Enter"
|
|
507
515
|
return "Option+Enter" if sys.platform == "darwin" else "Ctrl+J"
|
|
508
516
|
|
|
509
517
|
|
|
@@ -1854,36 +1862,52 @@ _OPENROUTER_APP_TITLE = "Deep Agents CLI"
|
|
|
1854
1862
|
_OPENROUTER_APP_CATEGORIES: list[str] = ["cli-agent"]
|
|
1855
1863
|
"""Default `app_categories` (maps to `X-OpenRouter-Categories`) for OpenRouter."""
|
|
1856
1864
|
|
|
1865
|
+
_cli_openrouter_profile_registered = False
|
|
1866
|
+
"""Process-wide guard so the CLI OpenRouter profile is registered exactly once."""
|
|
1857
1867
|
|
|
1858
|
-
def _apply_openrouter_defaults(kwargs: dict[str, Any]) -> None:
|
|
1859
|
-
"""Inject default OpenRouter attribution kwargs.
|
|
1860
1868
|
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
`HTTP-Referer`, `X-Title`, and `X-OpenRouter-Categories` headers that
|
|
1864
|
-
`ChatOpenRouter` sends for app attribution
|
|
1865
|
-
(see https://openrouter.ai/docs/app-attribution).
|
|
1869
|
+
def _cli_openrouter_attribution_kwargs() -> dict[str, Any]:
|
|
1870
|
+
"""CLI-specific OpenRouter attribution kwargs.
|
|
1866
1871
|
|
|
1867
|
-
|
|
1868
|
-
|
|
1872
|
+
Layered on top of the SDK's built-in factory via profile stacking; these
|
|
1873
|
+
values override the SDK defaults but still sit beneath any caller-supplied
|
|
1874
|
+
`kwargs` (i.e. `config.toml`-resolved values), preserving the precedence
|
|
1875
|
+
documented on `apply_provider_profile`.
|
|
1869
1876
|
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1877
|
+
Returns:
|
|
1878
|
+
Mapping of `app_url` and `app_title` to spread into `init_chat_model`.
|
|
1879
|
+
"""
|
|
1880
|
+
return {
|
|
1881
|
+
"app_url": _OPENROUTER_APP_URL,
|
|
1882
|
+
"app_title": _OPENROUTER_APP_TITLE,
|
|
1883
|
+
}
|
|
1875
1884
|
|
|
1876
|
-
# Per-model (shallow-merges on top of provider-wide)
|
|
1877
|
-
[models.providers.openrouter.params."openai/gpt-oss-120b"]
|
|
1878
|
-
app_title = "My App (GPT)"
|
|
1879
|
-
```
|
|
1880
1885
|
|
|
1881
|
-
|
|
1882
|
-
|
|
1886
|
+
def _ensure_cli_openrouter_profile_registered() -> None:
|
|
1887
|
+
"""Stack the CLI OpenRouter attribution onto the SDK's built-in profile.
|
|
1888
|
+
|
|
1889
|
+
Stacking (vs. duplicating the inline `_get_provider_kwargs` path) means the
|
|
1890
|
+
SDK's `pre_init` version check fires exactly once and the CLI's app-
|
|
1891
|
+
attribution defaults are composed via the same `apply_provider_profile`
|
|
1892
|
+
path used for every other provider. `register_provider_profile` merges on
|
|
1893
|
+
top of the existing built-in registration: the CLI's `init_kwargs` and
|
|
1894
|
+
factory output win on shared keys, while the built-in's `pre_init` and
|
|
1895
|
+
factory still chain.
|
|
1883
1896
|
"""
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1897
|
+
global _cli_openrouter_profile_registered # noqa: PLW0603
|
|
1898
|
+
if _cli_openrouter_profile_registered:
|
|
1899
|
+
return
|
|
1900
|
+
|
|
1901
|
+
from deepagents.profiles.provider import ProviderProfile, register_provider_profile
|
|
1902
|
+
|
|
1903
|
+
register_provider_profile(
|
|
1904
|
+
"openrouter",
|
|
1905
|
+
ProviderProfile(
|
|
1906
|
+
init_kwargs={"app_categories": _OPENROUTER_APP_CATEGORIES},
|
|
1907
|
+
init_kwargs_factory=_cli_openrouter_attribution_kwargs,
|
|
1908
|
+
),
|
|
1909
|
+
)
|
|
1910
|
+
_cli_openrouter_profile_registered = True
|
|
1887
1911
|
|
|
1888
1912
|
|
|
1889
1913
|
def _get_provider_kwargs(
|
|
@@ -1927,14 +1951,6 @@ def _get_provider_kwargs(
|
|
|
1927
1951
|
if api_key:
|
|
1928
1952
|
result["api_key"] = api_key
|
|
1929
1953
|
|
|
1930
|
-
if provider == "openrouter":
|
|
1931
|
-
from deepagents.profiles._openrouter import (
|
|
1932
|
-
check_openrouter_version, # noqa: PLC2701
|
|
1933
|
-
)
|
|
1934
|
-
|
|
1935
|
-
check_openrouter_version()
|
|
1936
|
-
_apply_openrouter_defaults(result)
|
|
1937
|
-
|
|
1938
1954
|
return result
|
|
1939
1955
|
|
|
1940
1956
|
|
|
@@ -2242,6 +2258,37 @@ def create_model(
|
|
|
2242
2258
|
# Provider-specific kwargs (with per-model overrides)
|
|
2243
2259
|
kwargs = _get_provider_kwargs(provider, model_name=model_name)
|
|
2244
2260
|
|
|
2261
|
+
# Compose under existing kwargs: profile < config.toml < --model-params
|
|
2262
|
+
# (applied below). The CLI's OpenRouter profile is stacked on top of the
|
|
2263
|
+
# built-in SDK profile so its `pre_init` (version check) and factory
|
|
2264
|
+
# (app attribution) compose into a single `apply_provider_profile` call.
|
|
2265
|
+
if provider:
|
|
2266
|
+
from deepagents.profiles.provider import apply_provider_profile
|
|
2267
|
+
|
|
2268
|
+
if provider == "openrouter":
|
|
2269
|
+
_ensure_cli_openrouter_profile_registered()
|
|
2270
|
+
|
|
2271
|
+
spec = f"{provider}:{model_name}" if model_name else provider
|
|
2272
|
+
try:
|
|
2273
|
+
kwargs = apply_provider_profile(spec, kwargs)
|
|
2274
|
+
except ModelConfigError:
|
|
2275
|
+
raise
|
|
2276
|
+
except Exception as exc:
|
|
2277
|
+
# `pre_init` and `init_kwargs_factory` callables registered on a
|
|
2278
|
+
# `ProviderProfile` may raise arbitrary exceptions (e.g. an
|
|
2279
|
+
# `ImportError` from the OpenRouter min-version check). Surface
|
|
2280
|
+
# them as `ModelConfigError` so the CLI's error path renders an
|
|
2281
|
+
# actionable message instead of a raw stack trace.
|
|
2282
|
+
logger.debug(
|
|
2283
|
+
"ProviderProfile resolution for %r failed.", spec, exc_info=True
|
|
2284
|
+
)
|
|
2285
|
+
msg = (
|
|
2286
|
+
f"Failed to apply provider profile for '{spec}': {exc}. "
|
|
2287
|
+
f"Check that the provider package is installed and up to date, "
|
|
2288
|
+
f"or set explicit kwargs via `--model-params`."
|
|
2289
|
+
)
|
|
2290
|
+
raise ModelConfigError(msg) from exc
|
|
2291
|
+
|
|
2245
2292
|
# CLI --model-params take highest priority
|
|
2246
2293
|
if extra_kwargs:
|
|
2247
2294
|
kwargs.update(extra_kwargs)
|
|
@@ -224,7 +224,7 @@ if command -v node >/dev/null 2>&1; then
|
|
|
224
224
|
NV="$(node --version 2>/dev/null | sed 's/^v//')"
|
|
225
225
|
[ -n "$NV" ] && RT="${RT:+${RT}, }Node ${NV}"
|
|
226
226
|
fi
|
|
227
|
-
[ -n "$RT" ] && echo "**Runtimes**: ${RT}" && echo ""
|
|
227
|
+
[ -n "$RT" ] && echo "**Detected Runtimes**: ${RT}" && echo ""
|
|
228
228
|
"""
|
|
229
229
|
|
|
230
230
|
|
|
@@ -246,7 +246,7 @@ if $IN_GIT; then
|
|
|
246
246
|
master) MAINS="${MAINS:+${MAINS}, }\`master\`" ;;
|
|
247
247
|
esac
|
|
248
248
|
done
|
|
249
|
-
[ -n "$MAINS" ] && GT="${GT},
|
|
249
|
+
[ -n "$MAINS" ] && GT="${GT}, ${MAINS} available"
|
|
250
250
|
|
|
251
251
|
DC=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
|
252
252
|
if [ "$DC" -gt 0 ]; then
|
|
@@ -301,13 +301,18 @@ if [ -n "$FILES" ]; then
|
|
|
301
301
|
TOTAL=$(echo "$FILES" | wc -l | tr -d ' ')
|
|
302
302
|
SHOWN_FILES=$(echo "$FILES" | head -20)
|
|
303
303
|
SHOWN=$(echo "$SHOWN_FILES" | wc -l | tr -d ' ')
|
|
304
|
-
|
|
304
|
+
TOTAL=${TOTAL:-0}
|
|
305
|
+
SHOWN=${SHOWN:-0}
|
|
306
|
+
if [ "$SHOWN" -lt "$TOTAL" ]; then
|
|
307
|
+
echo "**Files** (showing ${SHOWN} of ${TOTAL}):"
|
|
308
|
+
else
|
|
309
|
+
echo "**Files** (${TOTAL}):"
|
|
310
|
+
fi
|
|
305
311
|
echo "$SHOWN_FILES" | while IFS= read -r f; do
|
|
306
312
|
if [ -d "$f" ]; then echo "- ${f}/"
|
|
307
313
|
else echo "- ${f}"
|
|
308
314
|
fi
|
|
309
315
|
done
|
|
310
|
-
[ "$SHOWN" -lt "$TOTAL" ] && echo "... ($((TOTAL - SHOWN)) more files)"
|
|
311
316
|
echo ""
|
|
312
317
|
fi"""
|
|
313
318
|
|
|
@@ -323,12 +328,21 @@ if command -v tree >/dev/null 2>&1; then
|
|
|
323
328
|
TREE_EXCL='node_modules|.venv|__pycache__|.pytest_cache'
|
|
324
329
|
TREE_EXCL="${TREE_EXCL}|.git|.mypy_cache|.ruff_cache"
|
|
325
330
|
TREE_EXCL="${TREE_EXCL}|.tox|.coverage|.eggs|dist|build"
|
|
326
|
-
|
|
327
|
-
-I "$TREE_EXCL" 2>/dev/null |
|
|
328
|
-
if [ -n "$
|
|
331
|
+
T_PREVIEW=$(tree -L 3 --noreport --dirsfirst \
|
|
332
|
+
-I "$TREE_EXCL" 2>/dev/null | sed -n '1,22p;23{p;q;}')
|
|
333
|
+
if [ -n "$T_PREVIEW" ]; then
|
|
334
|
+
PREVIEW_LINES=$(echo "$T_PREVIEW" | wc -l | tr -d ' ')
|
|
335
|
+
PREVIEW_LINES=${PREVIEW_LINES:-0}
|
|
336
|
+
T="$T_PREVIEW"
|
|
337
|
+
TREE_TRUNCATED=false
|
|
338
|
+
if [ "$PREVIEW_LINES" -gt 22 ]; then
|
|
339
|
+
T=$(echo "$T_PREVIEW" | head -22)
|
|
340
|
+
TREE_TRUNCATED=true
|
|
341
|
+
fi
|
|
329
342
|
echo "**Tree** (3 levels):"
|
|
330
343
|
echo '```text'
|
|
331
344
|
echo "$T"
|
|
345
|
+
$TREE_TRUNCATED && echo "... (more lines truncated)"
|
|
332
346
|
echo '```'
|
|
333
347
|
echo ""
|
|
334
348
|
fi
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Deep Agents CLI
|
|
2
2
|
|
|
3
|
-
You are a
|
|
3
|
+
You are a deep agent, an AI assistant running in {mode_description}. You help with tasks like coding, debugging, research, analysis, and more.
|
|
4
4
|
|
|
5
5
|
{interactive_preamble}
|
|
6
6
|
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Terminal capability detection.
|
|
2
|
+
|
|
3
|
+
Detect optional terminal features without reading from `stdin`.
|
|
4
|
+
|
|
5
|
+
The CLI only uses kitty-keyboard-protocol support to choose a user-facing
|
|
6
|
+
newline shortcut label. To keep startup safe on remote or high-latency PTYs,
|
|
7
|
+
detection is conservative and relies on side-effect-free terminal identity
|
|
8
|
+
signals plus an explicit environment-variable override.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
from functools import cache
|
|
17
|
+
from typing import TYPE_CHECKING
|
|
18
|
+
|
|
19
|
+
from deepagents_cli._env_vars import KITTY_KEYBOARD
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from collections.abc import Mapping
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
_TRUE_VALUES = frozenset({"1", "true", "yes", "on"})
|
|
27
|
+
_FALSE_VALUES = frozenset({"0", "false", "no", "off"})
|
|
28
|
+
_KNOWN_KITTY_KEYBOARD_TERMS = frozenset({"xterm-ghostty", "xterm-kitty"})
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _override_supports_kitty_keyboard_protocol(
|
|
32
|
+
env: Mapping[str, str],
|
|
33
|
+
) -> bool | None:
|
|
34
|
+
"""Return an explicit kitty-keyboard override from `env`, if present.
|
|
35
|
+
|
|
36
|
+
Accepted truthy values are `'1'`, `'true'`, `'yes'`, and `'on'`.
|
|
37
|
+
Accepted falsy values are `'0'`, `'false'`, `'no'`, and `'off'`.
|
|
38
|
+
`'auto'`, the empty string, and invalid values fall back to heuristic
|
|
39
|
+
detection.
|
|
40
|
+
"""
|
|
41
|
+
raw = env.get(KITTY_KEYBOARD)
|
|
42
|
+
if raw is None:
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
normalized = raw.strip().lower()
|
|
46
|
+
if normalized in {"", "auto"}:
|
|
47
|
+
return None
|
|
48
|
+
if normalized in _TRUE_VALUES:
|
|
49
|
+
return True
|
|
50
|
+
if normalized in _FALSE_VALUES:
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
logger.warning(
|
|
54
|
+
"%s=%r ignored; expected one of: %s, or 'auto' to defer to detection.",
|
|
55
|
+
KITTY_KEYBOARD,
|
|
56
|
+
raw,
|
|
57
|
+
", ".join(sorted(_TRUE_VALUES | _FALSE_VALUES)),
|
|
58
|
+
)
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _terminal_identity_supports_kitty_keyboard_protocol(
|
|
63
|
+
env: Mapping[str, str],
|
|
64
|
+
) -> bool:
|
|
65
|
+
"""Return whether `env` identifies a terminal with built-in kitty support.
|
|
66
|
+
|
|
67
|
+
This intentionally only recognizes terminals whose environment markers
|
|
68
|
+
imply kitty-keyboard support is part of the terminal's default identity.
|
|
69
|
+
Configurable terminals such as iTerm2 and WezTerm are intentionally not
|
|
70
|
+
auto-detected because protocol support can be disabled in user settings.
|
|
71
|
+
"""
|
|
72
|
+
if env.get("KITTY_WINDOW_ID"):
|
|
73
|
+
return True
|
|
74
|
+
|
|
75
|
+
term = env.get("TERM", "")
|
|
76
|
+
return term in _KNOWN_KITTY_KEYBOARD_TERMS
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@cache
|
|
80
|
+
def supports_kitty_keyboard_protocol() -> bool:
|
|
81
|
+
"""Return whether the attached terminal should be treated as kitty-aware.
|
|
82
|
+
|
|
83
|
+
Detection is side-effect free: it never writes escape sequences or reads
|
|
84
|
+
queued input bytes. That means it may under-detect some configurable
|
|
85
|
+
terminals, but it will not interfere with Textual's input stream.
|
|
86
|
+
|
|
87
|
+
Set `DEEPAGENTS_CLI_KITTY_KEYBOARD` to an accepted truthy value (`1`,
|
|
88
|
+
`true`, `yes`, `on`) to force-enable the label, a falsy value (`0`,
|
|
89
|
+
`false`, `no`, `off`) to force-disable it, or `auto`/unset to use
|
|
90
|
+
heuristic detection.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
`True` when the terminal is known to support the kitty keyboard
|
|
94
|
+
protocol, `False` otherwise.
|
|
95
|
+
"""
|
|
96
|
+
if sys.platform == "win32":
|
|
97
|
+
logger.debug("kitty kbd detection: False (win32 unsupported)")
|
|
98
|
+
return False
|
|
99
|
+
if not (sys.stdin.isatty() and sys.stdout.isatty()):
|
|
100
|
+
logger.debug("kitty kbd detection: False (stdin/stdout not a tty)")
|
|
101
|
+
return False
|
|
102
|
+
|
|
103
|
+
override = _override_supports_kitty_keyboard_protocol(os.environ)
|
|
104
|
+
if override is not None:
|
|
105
|
+
logger.debug("kitty kbd detection: %s (explicit override)", override)
|
|
106
|
+
return override
|
|
107
|
+
|
|
108
|
+
detected = _terminal_identity_supports_kitty_keyboard_protocol(os.environ)
|
|
109
|
+
logger.debug(
|
|
110
|
+
"kitty kbd detection: %s (terminal identity TERM=%r KITTY_WINDOW_ID=%r)",
|
|
111
|
+
detected,
|
|
112
|
+
os.environ.get("TERM", ""),
|
|
113
|
+
os.environ.get("KITTY_WINDOW_ID"),
|
|
114
|
+
)
|
|
115
|
+
return detected
|
|
@@ -471,8 +471,29 @@ class ModelSelectorScreen(ModalScreen[tuple[str, str] | None]):
|
|
|
471
471
|
self._option_widgets = []
|
|
472
472
|
|
|
473
473
|
if not self._filtered_models:
|
|
474
|
-
|
|
475
|
-
|
|
474
|
+
if not self._loaded:
|
|
475
|
+
empty_content: Content = Content.styled("Loading models…", "dim")
|
|
476
|
+
else:
|
|
477
|
+
typed = self._filter_text.strip()
|
|
478
|
+
if typed and ":" in typed:
|
|
479
|
+
empty_content = Content.assemble(
|
|
480
|
+
("No matching models — press ", "dim"),
|
|
481
|
+
("Enter", "bold"),
|
|
482
|
+
(" to use ", "dim"),
|
|
483
|
+
(typed, "bold"),
|
|
484
|
+
(" as a custom provider:model spec", "dim"),
|
|
485
|
+
)
|
|
486
|
+
elif typed:
|
|
487
|
+
empty_content = Content.assemble(
|
|
488
|
+
("No matching models — press ", "dim"),
|
|
489
|
+
("Enter", "bold"),
|
|
490
|
+
(" to use ", "dim"),
|
|
491
|
+
(typed, "bold"),
|
|
492
|
+
(" as a custom model spec (no provider prefix)", "dim"),
|
|
493
|
+
)
|
|
494
|
+
else:
|
|
495
|
+
empty_content = Content.styled("No matching models", "dim")
|
|
496
|
+
await self._options_container.mount(Static(empty_content))
|
|
476
497
|
self._update_footer()
|
|
477
498
|
return
|
|
478
499
|
|