deepagents-cli 0.0.46__tar.gz → 0.0.48__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.46 → deepagents_cli-0.0.48}/CHANGELOG.md +16 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/Makefile +7 -1
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/PKG-INFO +5 -5
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/README.md +2 -2
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_version.py +1 -1
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/app.py +288 -22
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/config.py +10 -6
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/model_config.py +28 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/theme.py +69 -58
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/theme_selector.py +3 -3
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/welcome.py +15 -32
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/pyproject.toml +4 -4
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/scripts/install.sh +1 -1
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_app.py +9 -6
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_chat_input.py +13 -2
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_model_switch.py +283 -1
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_theme.py +22 -20
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_welcome.py +0 -15
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/uv.lock +26 -21
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/.gitignore +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/DEV.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/THREAT_MODEL.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/__main__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_ask_user_types.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_cli_context.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_debug.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_env_vars.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_git.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_server_config.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_session_stats.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_testing_models.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_textual_patches.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/agent.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/app.tcss +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/ask_user.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/remember/SKILL.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/clipboard.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/command_registry.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/configurable_model.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/default_agent_prompt.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/bundler.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/commands.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/config.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/anonymous-B9UzAXQd.js +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/clerk-5xHgyQyG.js +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/highlighted-body-OFNGDK62-rX-7qT8o.js +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/index-DM3gptpu.js +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/index-Ddy7F6KI.css +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/supabase-S6NACDgm.js +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/index.html +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/logo-dark.svg +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/logo-light.svg +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/templates.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/editor.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/extras_info.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/file_ops.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/formatting.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/hooks.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/input.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/integrations/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/integrations/sandbox_factory.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/integrations/sandbox_provider.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/local_context.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/main.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_auth.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_commands.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/_registry.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/base.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/github.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/slack.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_tools.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_trust.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/media_utils.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/non_interactive.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/notifications.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/offload.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/output.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/project_utils.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/py.typed +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/remote_client.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/server.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/server_graph.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/server_manager.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/sessions.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/skills/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/skills/commands.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/skills/invocation.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/skills/load.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/subagents.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/system_prompt.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/terminal_capabilities.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/textual_adapter.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/token_state.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/tool_display.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/tools.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/ui.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/unicode_security.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/update_check.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/_links.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/agent_selector.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/approval.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/ask_user.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/autocomplete.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/chat_input.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/diff.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/history.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/loading.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/mcp_viewer.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/message_store.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/messages.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/model_selector.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/notification_center.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/notification_detail.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/notification_settings.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/status.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/thread_selector.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/tool_renderers.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/tool_widgets.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/update_available.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/.env.example +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/skills/blog-post/SKILL.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/skills/social-media/SKILL.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/user/context.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/user/preferences.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/arxiv-search/SKILL.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/web-research/SKILL.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/.nvmrc +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/index.html +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/package-lock.json +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/package.json +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/postcss.config.js +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/public/logo-dark.svg +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/public/logo-light.svg +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/App.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/ThemeProvider.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/anonymous.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/clerk.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/loader.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/supabase.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/types.ts +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/AppHeader.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/FilePanels.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/MessageList.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/SubagentActivity.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/ThreadPicker.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/TodosPanel.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/ToolCallCard.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/FileToolCard.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/SearchCard.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/ThinkCard.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/TodosCard.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/index.ts +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/constants.ts +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/index.css +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/main.tsx +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/runtimeConfig.ts +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/types.ts +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/vite-env.d.ts +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/tsconfig.json +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/vite.config.ts +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/images/cli.png +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/scripts/check_imports.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/scripts/debug_server.sh +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/README.md +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/conftest.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/test_acp_mode.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/test_compact_resume.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/conftest.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_bundler.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_commands.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_config.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_frontend_bundle.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_frontend_config.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/skills/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/skills/test_commands.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/skills/test_load.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_agent.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_agent_friendly.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_agent_selector.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_approval.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_args.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_ask_user.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_ask_user_middleware.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_autocomplete.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_charset.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_command_registry.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_compact_tool.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_config.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_configurable_model.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_debug.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_editor.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_end_to_end.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_env_vars.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_exception_handling.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_extras_info.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_file_ops.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_formatting.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_git.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_history.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_hooks.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_imports.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_input_parsing.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_links.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_loading.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_local_context.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_main.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_main_args.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_auth.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_commands.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_tools.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_trust.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_viewer.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_media_utils.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_message_store.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_messages.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_model_config.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_model_selector.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_non_interactive.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_notification_center.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_notification_detail.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_notifications.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_offload.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_offload_dict_messages.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_output.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_reload.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_remote_client.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server_config.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server_graph.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server_helpers.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server_manager.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_session_stats.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_sessions.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_skill_invocation.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_status.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_subagents.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_terminal_capabilities.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_textual_adapter.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_textual_patches.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_thread_selector.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_token_tracker.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_tool_display.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_ui.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_unicode_security.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_update_available.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_update_check.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_version.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/tools/__init__.py +0 -0
- {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/tools/test_fetch_url.py +0 -0
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.48](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.47...deepagents-cli==0.0.48) (2026-05-01)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* Apply `--model-params` on `/model` re-select ([#3072](https://github.com/langchain-ai/deepagents/issues/3072)) ([50546dd](https://github.com/langchain-ai/deepagents/commit/50546dd3d368af297084929ee3aa91ccf8496fca))
|
|
8
|
+
|
|
9
|
+
## [0.0.47](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.46...deepagents-cli==0.0.47) (2026-05-01)
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* Auto-discover Textual built-in themes ([#3068](https://github.com/langchain-ai/deepagents/issues/3068)) ([27894e3](https://github.com/langchain-ai/deepagents/commit/27894e336f20f270fb4bb685bf979f24b9bea0bc))
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* Recover from failed server startup via `/model` ([#3056](https://github.com/langchain-ai/deepagents/issues/3056)) ([6ee375e](https://github.com/langchain-ai/deepagents/commit/6ee375e979b672cd1d172669f0e5a7a665431d7c))
|
|
18
|
+
|
|
3
19
|
## [0.0.46](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.45...deepagents-cli==0.0.46) (2026-04-30)
|
|
4
20
|
|
|
5
21
|
### Features
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.PHONY: format lint type typecheck test tests integration_test integration_tests test_watch benchmark help run lint_package lint_tests check_imports coverage
|
|
1
|
+
.PHONY: format lint type typecheck test tests integration_test integration_tests test_watch benchmark bench bench-memory help run lint_package lint_tests check_imports coverage
|
|
2
2
|
|
|
3
3
|
.DEFAULT_GOAL := help
|
|
4
4
|
|
|
@@ -38,6 +38,12 @@ test_watch: ## Run tests in watch mode
|
|
|
38
38
|
benchmark: ## Run benchmark tests
|
|
39
39
|
uv run --group test pytest ./tests -m benchmark
|
|
40
40
|
|
|
41
|
+
bench: ## Run benchmarks under CodSpeed instrumentation
|
|
42
|
+
uv run --group test pytest ./tests -m benchmark --codspeed
|
|
43
|
+
|
|
44
|
+
bench-memory: ## Run memory benchmarks under CodSpeed instrumentation
|
|
45
|
+
uv run --group test pytest ./tests -m memory_benchmark --codspeed
|
|
46
|
+
|
|
41
47
|
run: ## Reinstall and run package
|
|
42
48
|
uvx --no-cache --reinstall .
|
|
43
49
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.48
|
|
4
4
|
Summary: Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities.
|
|
5
5
|
Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
|
|
6
6
|
Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
|
|
@@ -27,7 +27,7 @@ Classifier: Topic :: Terminals
|
|
|
27
27
|
Requires-Python: <4.0,>=3.11
|
|
28
28
|
Requires-Dist: aiosqlite<1.0.0,>=0.19.0
|
|
29
29
|
Requires-Dist: deepagents-acp>=0.0.4
|
|
30
|
-
Requires-Dist: deepagents==0.5.
|
|
30
|
+
Requires-Dist: deepagents==0.5.6
|
|
31
31
|
Requires-Dist: httpx<1.0.0,>=0.28.1
|
|
32
32
|
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.2
|
|
33
33
|
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.2
|
|
@@ -51,7 +51,7 @@ Requires-Dist: rich<15.0.0,>=14.0.0
|
|
|
51
51
|
Requires-Dist: tavily-python<1.0.0,>=0.7.21
|
|
52
52
|
Requires-Dist: textual-autocomplete<5.0.0,>=3.0.0
|
|
53
53
|
Requires-Dist: textual-speedups<1.0.0,>=0.2.1
|
|
54
|
-
Requires-Dist: textual<9.0.0,>=8.
|
|
54
|
+
Requires-Dist: textual<9.0.0,>=8.2.5
|
|
55
55
|
Requires-Dist: tomli-w<2.0.0,>=1.0.0
|
|
56
56
|
Requires-Dist: uuid-utils<1.0.0,>=0.10.0
|
|
57
57
|
Provides-Extra: agentcore
|
|
@@ -141,13 +141,13 @@ Description-Content-Type: text/markdown
|
|
|
141
141
|
## Quick Install
|
|
142
142
|
|
|
143
143
|
```bash
|
|
144
|
-
curl -LsSf https://
|
|
144
|
+
curl -LsSf https://langch.in/gh-da-cli | bash
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
```bash
|
|
148
148
|
# With model provider extras
|
|
149
149
|
# OpenAI, Anthropic, and Gemini are included by default
|
|
150
|
-
DEEPAGENTS_EXTRAS="nvidia,ollama" curl -LsSf https://
|
|
150
|
+
DEEPAGENTS_EXTRAS="nvidia,ollama" curl -LsSf https://langch.in/gh-da-cli | bash
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
Or install directly with `uv`:
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
## Quick Install
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
curl -LsSf https://
|
|
15
|
+
curl -LsSf https://langch.in/gh-da-cli | bash
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
# With model provider extras
|
|
20
20
|
# OpenAI, Anthropic, and Gemini are included by default
|
|
21
|
-
DEEPAGENTS_EXTRAS="nvidia,ollama" curl -LsSf https://
|
|
21
|
+
DEEPAGENTS_EXTRAS="nvidia,ollama" curl -LsSf https://langch.in/gh-da-cli | bash
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
Or install directly with `uv`:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Version information and lightweight constants for `deepagents-cli`."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.0.
|
|
3
|
+
__version__ = "0.0.48" # 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."""
|
|
@@ -192,7 +192,10 @@ def _load_theme_preference() -> str:
|
|
|
192
192
|
return theme.DEFAULT_THEME
|
|
193
193
|
|
|
194
194
|
name = data.get("ui", {}).get("theme")
|
|
195
|
-
|
|
195
|
+
# Migrate legacy `textual-ansi` preference (pre-Textual 8.2.5) to `ansi-light`.
|
|
196
|
+
if name == "textual-ansi":
|
|
197
|
+
name = "ansi-light"
|
|
198
|
+
if isinstance(name, str) and name in theme.get_registry():
|
|
196
199
|
return name
|
|
197
200
|
if isinstance(name, str):
|
|
198
201
|
logger.warning(
|
|
@@ -211,7 +214,7 @@ def save_theme_preference(name: str) -> bool:
|
|
|
211
214
|
Returns:
|
|
212
215
|
`True` if the preference was saved, `False` if any error occurred.
|
|
213
216
|
"""
|
|
214
|
-
if name not in theme.
|
|
217
|
+
if name not in theme.get_registry():
|
|
215
218
|
logger.warning("Refusing to save unknown theme '%s'", name)
|
|
216
219
|
return False
|
|
217
220
|
|
|
@@ -344,6 +347,21 @@ def _extract_model_params_flag(raw_arg: str) -> tuple[str, dict[str, Any] | None
|
|
|
344
347
|
return remaining, params
|
|
345
348
|
|
|
346
349
|
|
|
350
|
+
def _format_model_params(extra_kwargs: dict[str, Any] | None) -> str:
|
|
351
|
+
"""Render `--model-params` as a stable, key-sorted JSON suffix.
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
extra_kwargs: The parsed `--model-params` payload, or `None`.
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
` with model params {json}` when `extra_kwargs` is non-empty;
|
|
358
|
+
otherwise an empty string so callers can unconditionally concatenate.
|
|
359
|
+
"""
|
|
360
|
+
if not extra_kwargs:
|
|
361
|
+
return ""
|
|
362
|
+
return f" with model params {json.dumps(extra_kwargs, sort_keys=True)}"
|
|
363
|
+
|
|
364
|
+
|
|
347
365
|
InputMode = Literal["normal", "shell", "command"]
|
|
348
366
|
|
|
349
367
|
_TYPING_IDLE_THRESHOLD_SECONDS: float = 2.0
|
|
@@ -428,6 +446,24 @@ def _truncate(text: str, *, limit: int) -> str:
|
|
|
428
446
|
return text[: limit - 1].rstrip() + "…"
|
|
429
447
|
|
|
430
448
|
|
|
449
|
+
def _log_task_exception(task: asyncio.Task[Any]) -> None:
|
|
450
|
+
"""Done-callback that surfaces unhandled exceptions from fire-and-forget tasks.
|
|
451
|
+
|
|
452
|
+
Default `asyncio` behavior is to log "Task exception was never retrieved"
|
|
453
|
+
only when the task is GC'd — easy to miss. This callback runs at task
|
|
454
|
+
completion and routes failures through `logger.warning` with `exc_info`,
|
|
455
|
+
matching the codebase pattern at `_finalize_git_branch_refresh`. Use
|
|
456
|
+
when scheduling a coroutine via `asyncio.create_task` whose result is
|
|
457
|
+
not awaited (e.g. event-handler cleanup, single-fire mounts).
|
|
458
|
+
"""
|
|
459
|
+
try:
|
|
460
|
+
task.result()
|
|
461
|
+
except asyncio.CancelledError:
|
|
462
|
+
pass
|
|
463
|
+
except Exception:
|
|
464
|
+
logger.warning("Background task failed unexpectedly", exc_info=True)
|
|
465
|
+
|
|
466
|
+
|
|
431
467
|
def _format_startup_error(error: BaseException) -> str:
|
|
432
468
|
"""Format a server-startup exception for the welcome banner.
|
|
433
469
|
|
|
@@ -905,6 +941,25 @@ class DeepAgentsApp(App):
|
|
|
905
941
|
Shown in place of the generic 'Agent not configured' message.
|
|
906
942
|
"""
|
|
907
943
|
|
|
944
|
+
self._server_startup_missing_credentials_provider: str | None = None
|
|
945
|
+
"""Set to the offending provider name when startup failed with
|
|
946
|
+
`MissingCredentialsError`; `None` otherwise. Gates the `/model`
|
|
947
|
+
recovery hint without string-matching on the formatted error.
|
|
948
|
+
"""
|
|
949
|
+
|
|
950
|
+
self._retry_status_widget: AppMessage | None = None
|
|
951
|
+
"""Transient "Retrying startup with X…" breadcrumb. Mounted via
|
|
952
|
+
`_mount_before_queued` (not `_mount_message`) because it is ephemeral
|
|
953
|
+
state and must not appear in scrollback or serialized history.
|
|
954
|
+
"""
|
|
955
|
+
|
|
956
|
+
self._startup_failure_widget: ErrorMessage | None = None
|
|
957
|
+
"""Transient chat surface for the most recent server-startup failure.
|
|
958
|
+
Mounted by `on_deep_agents_app_server_start_failed`; removed on
|
|
959
|
+
`ServerReady` so a successful `/model` retry doesn't leave the stale
|
|
960
|
+
error dangling in scrollback.
|
|
961
|
+
"""
|
|
962
|
+
|
|
908
963
|
self._quit_pending = False
|
|
909
964
|
"""True after a first `Ctrl+C` so a second press within the window quits."""
|
|
910
965
|
|
|
@@ -1181,6 +1236,14 @@ class DeepAgentsApp(App):
|
|
|
1181
1236
|
# Focus the input immediately so the cursor is visible on first paint
|
|
1182
1237
|
self._chat_input.focus_input()
|
|
1183
1238
|
|
|
1239
|
+
# Pre-import `html.entities` on the main thread before the worker
|
|
1240
|
+
# starts. Python 3.14 replaced the global import lock with per-module
|
|
1241
|
+
# locks; a worker importing `markdown_it` (which transitively pulls
|
|
1242
|
+
# `html.entities`) can race main-thread code looking up `html` *while
|
|
1243
|
+
# `html` itself is still being initialized*, raising `KeyError: 'html'`
|
|
1244
|
+
# from `_find_and_load_unlocked`.
|
|
1245
|
+
import html.entities # noqa: F401
|
|
1246
|
+
|
|
1184
1247
|
# Prewarm heavy imports in a thread while the first frame renders.
|
|
1185
1248
|
# The user can't type yet, so GIL contention is harmless. By the
|
|
1186
1249
|
# time _post_paint_init fires its inline imports are dict lookups.
|
|
@@ -1742,6 +1805,28 @@ class DeepAgentsApp(App):
|
|
|
1742
1805
|
self._agent = event.agent
|
|
1743
1806
|
self._server_proc = event.server_proc
|
|
1744
1807
|
self._mcp_server_info = event.mcp_server_info
|
|
1808
|
+
|
|
1809
|
+
# Drop transient failure-state widgets — banner state and the agent
|
|
1810
|
+
# response now convey "connected", so the prior error and breadcrumb
|
|
1811
|
+
# would just dangle in scrollback.
|
|
1812
|
+
for attr in ("_retry_status_widget", "_startup_failure_widget"):
|
|
1813
|
+
widget = getattr(self, attr)
|
|
1814
|
+
if widget is None:
|
|
1815
|
+
continue
|
|
1816
|
+
setattr(self, attr, None)
|
|
1817
|
+
|
|
1818
|
+
async def _drop(w: Widget = widget) -> None:
|
|
1819
|
+
# Mount may still be in flight when `ServerReady` arrives;
|
|
1820
|
+
# short-circuit on un-attached widgets instead of raising.
|
|
1821
|
+
# `NoMatches`/`ScreenStackError` cover later-stage detach
|
|
1822
|
+
# races (screen torn down mid-removal).
|
|
1823
|
+
if not w.is_attached:
|
|
1824
|
+
return
|
|
1825
|
+
with suppress(NoMatches, ScreenStackError):
|
|
1826
|
+
await w.remove()
|
|
1827
|
+
|
|
1828
|
+
task = asyncio.create_task(_drop())
|
|
1829
|
+
task.add_done_callback(_log_task_exception)
|
|
1745
1830
|
self._mcp_tool_count = sum(len(s.tools) for s in (event.mcp_server_info or []))
|
|
1746
1831
|
self._mcp_unauthenticated = sum(
|
|
1747
1832
|
1 for s in (event.mcp_server_info or []) if s.status == "unauthenticated"
|
|
@@ -1797,6 +1882,7 @@ class DeepAgentsApp(App):
|
|
|
1797
1882
|
def on_deep_agents_app_server_start_failed(self, event: ServerStartFailed) -> None:
|
|
1798
1883
|
"""Handle background server startup failure."""
|
|
1799
1884
|
from deepagents_cli.mcp_tools import MCPConfigError
|
|
1885
|
+
from deepagents_cli.model_config import MissingCredentialsError
|
|
1800
1886
|
|
|
1801
1887
|
self._connecting = False
|
|
1802
1888
|
if isinstance(event.error, MCPConfigError):
|
|
@@ -1804,22 +1890,68 @@ class DeepAgentsApp(App):
|
|
|
1804
1890
|
self._server_startup_error = str(event.error)
|
|
1805
1891
|
else:
|
|
1806
1892
|
self._server_startup_error = _format_startup_error(event.error)
|
|
1893
|
+
|
|
1894
|
+
# Stash the provider for the `/model` recovery hint. Reset on every
|
|
1895
|
+
# failure so a non-credentials retry-failure clears the prior flag.
|
|
1896
|
+
self._server_startup_missing_credentials_provider = (
|
|
1897
|
+
event.error.provider
|
|
1898
|
+
if isinstance(event.error, MissingCredentialsError)
|
|
1899
|
+
else None
|
|
1900
|
+
)
|
|
1807
1901
|
logger.error("Server startup failed: %s", event.error, exc_info=event.error)
|
|
1808
|
-
|
|
1902
|
+
|
|
1903
|
+
# Drop the banner's connecting spinner — chat surface owns the error.
|
|
1809
1904
|
try:
|
|
1810
1905
|
banner = self.query_one("#welcome-banner", WelcomeBanner)
|
|
1811
|
-
banner.
|
|
1906
|
+
banner.set_idle()
|
|
1812
1907
|
except NoMatches:
|
|
1813
1908
|
logger.warning("Welcome banner not found during server failure transition")
|
|
1814
1909
|
|
|
1815
|
-
#
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
self._queued_widgets.clear()
|
|
1910
|
+
# Keep any queued messages and widgets in place — `/model` retry can
|
|
1911
|
+
# bring the server up, at which point `_run_session_start_sequence`
|
|
1912
|
+
# drains them. Deferred actions (model/thread switches queued during
|
|
1913
|
+
# the initial connect) are dropped because the failure invalidates
|
|
1914
|
+
# their assumptions; the user can re-issue them after recovery.
|
|
1821
1915
|
self._deferred_actions.clear()
|
|
1822
1916
|
|
|
1917
|
+
# Failure surfaces only in chat — keeps recovery hint adjacent to the
|
|
1918
|
+
# input. Banner is set to idle above to drop the connecting spinner.
|
|
1919
|
+
text = f"Server failed to start: {self._server_startup_error}"
|
|
1920
|
+
if (
|
|
1921
|
+
self._server_startup_missing_credentials_provider is not None
|
|
1922
|
+
and self._server_kwargs is not None
|
|
1923
|
+
):
|
|
1924
|
+
text += (
|
|
1925
|
+
"\n\nHint: run `/model <provider>:<model>` to retry "
|
|
1926
|
+
"startup with a provider you have credentials for."
|
|
1927
|
+
)
|
|
1928
|
+
|
|
1929
|
+
async def _mount_failure() -> None:
|
|
1930
|
+
# Drop any prior failure widget (re-entrant on retry-then-fail).
|
|
1931
|
+
prior = self._startup_failure_widget
|
|
1932
|
+
self._startup_failure_widget = None
|
|
1933
|
+
if prior is not None and prior.is_attached:
|
|
1934
|
+
with suppress(NoMatches, ScreenStackError):
|
|
1935
|
+
await prior.remove()
|
|
1936
|
+
|
|
1937
|
+
try:
|
|
1938
|
+
messages = self.query_one("#messages", Container)
|
|
1939
|
+
except (NoMatches, ScreenStackError):
|
|
1940
|
+
return
|
|
1941
|
+
if not messages.is_attached:
|
|
1942
|
+
return
|
|
1943
|
+
|
|
1944
|
+
new_widget = ErrorMessage(text)
|
|
1945
|
+
# Mount before storing the reference so `ServerReady` racing this
|
|
1946
|
+
# await cannot observe a half-mounted widget.
|
|
1947
|
+
await self._mount_before_queued(messages, new_widget)
|
|
1948
|
+
self._startup_failure_widget = new_widget
|
|
1949
|
+
|
|
1950
|
+
# Fire-and-forget mount: this is the *only* failure surface, so log
|
|
1951
|
+
# any exception loudly via `_log_task_exception`.
|
|
1952
|
+
task = asyncio.create_task(_mount_failure())
|
|
1953
|
+
task.add_done_callback(_log_task_exception)
|
|
1954
|
+
|
|
1823
1955
|
async def _await_prewarm_imports(self) -> None:
|
|
1824
1956
|
"""Wait for prewarm imports before re-entering their module graph.
|
|
1825
1957
|
|
|
@@ -3065,14 +3197,17 @@ class DeepAgentsApp(App):
|
|
|
3065
3197
|
)
|
|
3066
3198
|
return
|
|
3067
3199
|
|
|
3068
|
-
# If the app is busy
|
|
3069
|
-
#
|
|
3070
|
-
#
|
|
3200
|
+
# If the app is busy, still sequencing startup work, or holding a
|
|
3201
|
+
# post-failure recovery state (server hasn't come up yet but `/model`
|
|
3202
|
+
# retry is still possible), enqueue instead of processing. Messages
|
|
3203
|
+
# queued in any of these states are drained once the session reaches
|
|
3204
|
+
# its first stable idle/running state.
|
|
3071
3205
|
if (
|
|
3072
3206
|
self._agent_running
|
|
3073
3207
|
or self._shell_running
|
|
3074
3208
|
or self._connecting
|
|
3075
3209
|
or self._startup_sequence_running
|
|
3210
|
+
or self._server_startup_error is not None
|
|
3076
3211
|
):
|
|
3077
3212
|
if mode == "command" and self._can_bypass_queue(value.lower().strip()):
|
|
3078
3213
|
await self._process_message(value, mode)
|
|
@@ -4120,11 +4255,10 @@ class DeepAgentsApp(App):
|
|
|
4120
4255
|
self._run_agent_task(message, message_kwargs=message_kwargs),
|
|
4121
4256
|
exclusive=False,
|
|
4122
4257
|
)
|
|
4123
|
-
elif self._server_startup_error:
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
else:
|
|
4258
|
+
elif not self._server_startup_error:
|
|
4259
|
+
# When a server-startup failure is in flight, the chat
|
|
4260
|
+
# `ErrorMessage` mounted by `on_deep_agents_app_server_start_failed`
|
|
4261
|
+
# is the single source of truth — don't duplicate it here.
|
|
4128
4262
|
await self._mount_message(
|
|
4129
4263
|
AppMessage("Agent not configured for this session.")
|
|
4130
4264
|
)
|
|
@@ -5367,7 +5501,7 @@ class DeepAgentsApp(App):
|
|
|
5367
5501
|
|
|
5368
5502
|
def _register_custom_themes(self) -> None:
|
|
5369
5503
|
"""Register all custom themes (built-in LC + user-defined) with Textual."""
|
|
5370
|
-
for name, entry in theme.
|
|
5504
|
+
for name, entry in theme.get_registry().items():
|
|
5371
5505
|
if entry.custom:
|
|
5372
5506
|
c = entry.colors
|
|
5373
5507
|
try:
|
|
@@ -6530,6 +6664,18 @@ class DeepAgentsApp(App):
|
|
|
6530
6664
|
timeout=3,
|
|
6531
6665
|
)
|
|
6532
6666
|
return
|
|
6667
|
+
# Recover from a failed startup (e.g., `MissingCredentialsError`).
|
|
6668
|
+
# The server never came up, so the only way out without
|
|
6669
|
+
# restarting the CLI is to retry startup with the new model.
|
|
6670
|
+
# Only valid for CLI-owned servers.
|
|
6671
|
+
if (
|
|
6672
|
+
self._server_startup_error is not None
|
|
6673
|
+
and self._server_kwargs is not None
|
|
6674
|
+
):
|
|
6675
|
+
await self._retry_startup_with_model(
|
|
6676
|
+
model_spec, extra_kwargs=extra_kwargs
|
|
6677
|
+
)
|
|
6678
|
+
return
|
|
6533
6679
|
await self._mount_message(
|
|
6534
6680
|
ErrorMessage("Model switching requires a server-backed session.")
|
|
6535
6681
|
)
|
|
@@ -6572,7 +6718,19 @@ class DeepAgentsApp(App):
|
|
|
6572
6718
|
not provider or provider == settings.model_provider
|
|
6573
6719
|
):
|
|
6574
6720
|
current = f"{settings.model_provider}:{settings.model_name}"
|
|
6575
|
-
|
|
6721
|
+
# Mirror the regular-switch path so `--model-params` semantics
|
|
6722
|
+
# are consistent across same-model and different-model cases:
|
|
6723
|
+
# passing params applies them, omitting params clears any
|
|
6724
|
+
# prior per-session override.
|
|
6725
|
+
self._model_override = current
|
|
6726
|
+
self._model_params_override = extra_kwargs
|
|
6727
|
+
params_suffix = _format_model_params(extra_kwargs)
|
|
6728
|
+
await self._mount_message(
|
|
6729
|
+
AppMessage(f"Already using {current}{params_suffix}")
|
|
6730
|
+
)
|
|
6731
|
+
logger.info(
|
|
6732
|
+
"Model unchanged (%s); model_params=%s", current, extra_kwargs
|
|
6733
|
+
)
|
|
6576
6734
|
return
|
|
6577
6735
|
|
|
6578
6736
|
# Build the provider:model spec for the configurable middleware.
|
|
@@ -6613,8 +6771,15 @@ class DeepAgentsApp(App):
|
|
|
6613
6771
|
)
|
|
6614
6772
|
)
|
|
6615
6773
|
else:
|
|
6616
|
-
|
|
6617
|
-
|
|
6774
|
+
params_suffix = _format_model_params(extra_kwargs)
|
|
6775
|
+
await self._mount_message(
|
|
6776
|
+
AppMessage(f"Switched to {display}{params_suffix}")
|
|
6777
|
+
)
|
|
6778
|
+
logger.info(
|
|
6779
|
+
"Model switched to %s (via configurable middleware); model_params=%s",
|
|
6780
|
+
display,
|
|
6781
|
+
extra_kwargs,
|
|
6782
|
+
)
|
|
6618
6783
|
|
|
6619
6784
|
# Anchor to bottom so the confirmation message is visible
|
|
6620
6785
|
with suppress(NoMatches, ScreenStackError):
|
|
@@ -6622,6 +6787,107 @@ class DeepAgentsApp(App):
|
|
|
6622
6787
|
finally:
|
|
6623
6788
|
self._model_switching = False
|
|
6624
6789
|
|
|
6790
|
+
async def _retry_startup_with_model(
|
|
6791
|
+
self,
|
|
6792
|
+
model_spec: str,
|
|
6793
|
+
*,
|
|
6794
|
+
extra_kwargs: dict[str, Any] | None = None,
|
|
6795
|
+
) -> None:
|
|
6796
|
+
"""Retry deferred server startup after a failed initial startup.
|
|
6797
|
+
|
|
6798
|
+
Exists because the server never came up (typically a
|
|
6799
|
+
`MissingCredentialsError`), so the only escape without restarting
|
|
6800
|
+
the CLI is re-running the deferred startup worker with a new spec.
|
|
6801
|
+
|
|
6802
|
+
Args:
|
|
6803
|
+
model_spec: The new model specification (`provider:model` or bare
|
|
6804
|
+
model name for auto-detection).
|
|
6805
|
+
extra_kwargs: Extra constructor kwargs from `--model-params`.
|
|
6806
|
+
"""
|
|
6807
|
+
from deepagents_cli.config import detect_provider
|
|
6808
|
+
from deepagents_cli.model_config import (
|
|
6809
|
+
ModelSpec,
|
|
6810
|
+
get_credential_env_var,
|
|
6811
|
+
has_provider_credentials,
|
|
6812
|
+
)
|
|
6813
|
+
|
|
6814
|
+
if self._server_kwargs is None:
|
|
6815
|
+
await self._mount_message(
|
|
6816
|
+
ErrorMessage("Cannot retry startup: server is not CLI-owned.")
|
|
6817
|
+
)
|
|
6818
|
+
return
|
|
6819
|
+
|
|
6820
|
+
parsed = ModelSpec.try_parse(model_spec)
|
|
6821
|
+
if parsed:
|
|
6822
|
+
provider: str | None = parsed.provider
|
|
6823
|
+
model_name = parsed.model
|
|
6824
|
+
else:
|
|
6825
|
+
model_name = model_spec
|
|
6826
|
+
provider = detect_provider(model_spec)
|
|
6827
|
+
|
|
6828
|
+
# Tri-state credentials check (`None` = unknown provider, treated as
|
|
6829
|
+
# proceed); bail early so retrying with still-missing creds doesn't
|
|
6830
|
+
# loop right back into the same `MissingCredentialsError`.
|
|
6831
|
+
has_creds = has_provider_credentials(provider) if provider else None
|
|
6832
|
+
if has_creds is False and provider is not None:
|
|
6833
|
+
env_var = get_credential_env_var(provider)
|
|
6834
|
+
detail = (
|
|
6835
|
+
f"{env_var} is not set or is empty"
|
|
6836
|
+
if env_var
|
|
6837
|
+
else (
|
|
6838
|
+
f"provider '{provider}' is not recognized. "
|
|
6839
|
+
"Add it to ~/.deepagents/config.toml with an "
|
|
6840
|
+
"api_key_env field"
|
|
6841
|
+
)
|
|
6842
|
+
)
|
|
6843
|
+
await self._mount_message(ErrorMessage(f"Missing credentials: {detail}"))
|
|
6844
|
+
return
|
|
6845
|
+
|
|
6846
|
+
display = model_spec
|
|
6847
|
+
if provider and not parsed:
|
|
6848
|
+
display = f"{provider}:{model_name}"
|
|
6849
|
+
|
|
6850
|
+
new_model_kwargs: dict[str, Any] = {
|
|
6851
|
+
"model_spec": display,
|
|
6852
|
+
"extra_kwargs": extra_kwargs,
|
|
6853
|
+
"profile_overrides": self._profile_override,
|
|
6854
|
+
}
|
|
6855
|
+
self._model_kwargs = new_model_kwargs
|
|
6856
|
+
self._server_kwargs["model_name"] = display
|
|
6857
|
+
if extra_kwargs is not None:
|
|
6858
|
+
self._server_kwargs["model_params"] = extra_kwargs
|
|
6859
|
+
|
|
6860
|
+
self._server_startup_error = None
|
|
6861
|
+
self._server_startup_missing_credentials_provider = None
|
|
6862
|
+
self._connecting = True
|
|
6863
|
+
try:
|
|
6864
|
+
banner = self.query_one("#welcome-banner", WelcomeBanner)
|
|
6865
|
+
banner.set_connecting()
|
|
6866
|
+
except (NoMatches, ScreenStackError):
|
|
6867
|
+
logger.debug("Welcome banner not found during startup retry", exc_info=True)
|
|
6868
|
+
|
|
6869
|
+
if self._retry_status_widget is not None:
|
|
6870
|
+
with suppress(NoMatches, ScreenStackError):
|
|
6871
|
+
await self._retry_status_widget.remove()
|
|
6872
|
+
self._retry_status_widget = None
|
|
6873
|
+
try:
|
|
6874
|
+
messages = self.query_one("#messages", Container)
|
|
6875
|
+
except (NoMatches, ScreenStackError):
|
|
6876
|
+
messages = None
|
|
6877
|
+
if messages is not None and messages.is_attached:
|
|
6878
|
+
new_widget = AppMessage(f"Retrying startup with {display}…")
|
|
6879
|
+
# Mount before storing the reference so `on_deep_agents_app_server_ready`
|
|
6880
|
+
# cannot observe a half-mounted widget if it races during this await.
|
|
6881
|
+
await self._mount_before_queued(messages, new_widget)
|
|
6882
|
+
self._retry_status_widget = new_widget
|
|
6883
|
+
logger.info("Retrying server startup with model %s", display)
|
|
6884
|
+
|
|
6885
|
+
self.run_worker(
|
|
6886
|
+
self._start_server_background,
|
|
6887
|
+
exclusive=True,
|
|
6888
|
+
group="server-startup",
|
|
6889
|
+
)
|
|
6890
|
+
|
|
6625
6891
|
async def _set_default_model(self, model_spec: str) -> None:
|
|
6626
6892
|
"""Set the default model in config without switching the current session.
|
|
6627
6893
|
|
|
@@ -2194,9 +2194,10 @@ def create_model(
|
|
|
2194
2194
|
A `ModelResult` containing the model and its metadata.
|
|
2195
2195
|
|
|
2196
2196
|
Raises:
|
|
2197
|
-
ModelConfigError: If provider cannot be determined from the model name
|
|
2198
|
-
required provider package is not installed
|
|
2199
|
-
|
|
2197
|
+
ModelConfigError: If provider cannot be determined from the model name
|
|
2198
|
+
or required provider package is not installed.
|
|
2199
|
+
MissingCredentialsError: If no credentials are configured for the
|
|
2200
|
+
resolved provider.
|
|
2200
2201
|
|
|
2201
2202
|
Examples:
|
|
2202
2203
|
>>> model = create_model("anthropic:claude-sonnet-4-5")
|
|
@@ -2248,12 +2249,15 @@ def create_model(
|
|
|
2248
2249
|
if provider and provider not in IMPLICIT_AUTH_PROVIDERS:
|
|
2249
2250
|
cred_status = has_provider_credentials(provider)
|
|
2250
2251
|
if cred_status is False:
|
|
2251
|
-
|
|
2252
|
+
from deepagents_cli.model_config import MissingCredentialsError
|
|
2253
|
+
|
|
2254
|
+
env_var = get_credential_env_var(provider)
|
|
2255
|
+
display_env = env_var or f"<{provider} API key>"
|
|
2252
2256
|
msg = (
|
|
2253
2257
|
f"No credentials found for provider '{provider}'. "
|
|
2254
|
-
f"Please set the {
|
|
2258
|
+
f"Please set the {display_env} environment variable."
|
|
2255
2259
|
)
|
|
2256
|
-
raise
|
|
2260
|
+
raise MissingCredentialsError(msg, provider=provider, env_var=env_var)
|
|
2257
2261
|
|
|
2258
2262
|
# Provider-specific kwargs (with per-model overrides)
|
|
2259
2263
|
kwargs = _get_provider_kwargs(provider, model_name=model_name)
|
|
@@ -72,6 +72,34 @@ class ModelConfigError(Exception):
|
|
|
72
72
|
"""Raised when model configuration or creation fails."""
|
|
73
73
|
|
|
74
74
|
|
|
75
|
+
class MissingCredentialsError(ModelConfigError):
|
|
76
|
+
"""Raised when a provider is selected but its API key env var is unset.
|
|
77
|
+
|
|
78
|
+
Subclasses `ModelConfigError` so existing `except ModelConfigError` blocks
|
|
79
|
+
keep working. Carries the `provider` name and the canonical `env_var` so
|
|
80
|
+
callers can render targeted recovery hints (e.g., "set OPENAI_API_KEY" or
|
|
81
|
+
"run `/model <other_provider>:<model>`") without string-matching on the
|
|
82
|
+
formatted exception message and without re-deriving the env-var name.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def __init__(
|
|
86
|
+
self, message: str, *, provider: str, env_var: str | None = None
|
|
87
|
+
) -> None:
|
|
88
|
+
"""Initialize the error.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
message: Human-readable message describing the missing credential.
|
|
92
|
+
provider: The provider whose credentials are missing
|
|
93
|
+
(e.g., `'openai'`).
|
|
94
|
+
env_var: The canonical env var name expected to hold the
|
|
95
|
+
credential (e.g., `'OPENAI_API_KEY'`). `None` when the
|
|
96
|
+
provider has no registered env-var mapping.
|
|
97
|
+
"""
|
|
98
|
+
super().__init__(message)
|
|
99
|
+
self.provider = provider
|
|
100
|
+
self.env_var = env_var
|
|
101
|
+
|
|
102
|
+
|
|
75
103
|
@dataclass(frozen=True)
|
|
76
104
|
class ModelSpec:
|
|
77
105
|
"""A model specification in `provider:model` format.
|