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.
Files changed (274) hide show
  1. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/CHANGELOG.md +16 -0
  2. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/Makefile +7 -1
  3. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/PKG-INFO +5 -5
  4. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/README.md +2 -2
  5. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_version.py +1 -1
  6. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/app.py +288 -22
  7. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/config.py +10 -6
  8. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/model_config.py +28 -0
  9. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/theme.py +69 -58
  10. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/theme_selector.py +3 -3
  11. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/welcome.py +15 -32
  12. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/pyproject.toml +4 -4
  13. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/scripts/install.sh +1 -1
  14. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_app.py +9 -6
  15. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_chat_input.py +13 -2
  16. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_model_switch.py +283 -1
  17. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_theme.py +22 -20
  18. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_welcome.py +0 -15
  19. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/uv.lock +26 -21
  20. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/.gitignore +0 -0
  21. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/DEV.md +0 -0
  22. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/THREAT_MODEL.md +0 -0
  23. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/__init__.py +0 -0
  24. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/__main__.py +0 -0
  25. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_ask_user_types.py +0 -0
  26. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_cli_context.py +0 -0
  27. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_debug.py +0 -0
  28. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_env_vars.py +0 -0
  29. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_git.py +0 -0
  30. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_server_config.py +0 -0
  31. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_session_stats.py +0 -0
  32. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_testing_models.py +0 -0
  33. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/_textual_patches.py +0 -0
  34. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/agent.py +0 -0
  35. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/app.tcss +0 -0
  36. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/ask_user.py +0 -0
  37. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/__init__.py +0 -0
  38. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/remember/SKILL.md +0 -0
  39. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
  40. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
  41. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
  42. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/clipboard.py +0 -0
  43. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/command_registry.py +0 -0
  44. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/configurable_model.py +0 -0
  45. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/default_agent_prompt.md +0 -0
  46. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/__init__.py +0 -0
  47. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/bundler.py +0 -0
  48. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/commands.py +0 -0
  49. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/config.py +0 -0
  50. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/anonymous-B9UzAXQd.js +0 -0
  51. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/clerk-5xHgyQyG.js +0 -0
  52. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/highlighted-body-OFNGDK62-rX-7qT8o.js +0 -0
  53. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/index-DM3gptpu.js +0 -0
  54. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/index-Ddy7F6KI.css +0 -0
  55. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/assets/supabase-S6NACDgm.js +0 -0
  56. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/index.html +0 -0
  57. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/logo-dark.svg +0 -0
  58. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/frontend_dist/logo-light.svg +0 -0
  59. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/deploy/templates.py +0 -0
  60. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/editor.py +0 -0
  61. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/extras_info.py +0 -0
  62. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/file_ops.py +0 -0
  63. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/formatting.py +0 -0
  64. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/hooks.py +0 -0
  65. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/input.py +0 -0
  66. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/integrations/__init__.py +0 -0
  67. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/integrations/sandbox_factory.py +0 -0
  68. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/integrations/sandbox_provider.py +0 -0
  69. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/local_context.py +0 -0
  70. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/main.py +0 -0
  71. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_auth.py +0 -0
  72. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_commands.py +0 -0
  73. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/__init__.py +0 -0
  74. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/_registry.py +0 -0
  75. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/base.py +0 -0
  76. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/github.py +0 -0
  77. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_providers/slack.py +0 -0
  78. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_tools.py +0 -0
  79. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/mcp_trust.py +0 -0
  80. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/media_utils.py +0 -0
  81. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/non_interactive.py +0 -0
  82. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/notifications.py +0 -0
  83. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/offload.py +0 -0
  84. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/output.py +0 -0
  85. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/project_utils.py +0 -0
  86. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/py.typed +0 -0
  87. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/remote_client.py +0 -0
  88. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/server.py +0 -0
  89. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/server_graph.py +0 -0
  90. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/server_manager.py +0 -0
  91. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/sessions.py +0 -0
  92. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/skills/__init__.py +0 -0
  93. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/skills/commands.py +0 -0
  94. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/skills/invocation.py +0 -0
  95. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/skills/load.py +0 -0
  96. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/subagents.py +0 -0
  97. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/system_prompt.md +0 -0
  98. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/terminal_capabilities.py +0 -0
  99. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/textual_adapter.py +0 -0
  100. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/token_state.py +0 -0
  101. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/tool_display.py +0 -0
  102. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/tools.py +0 -0
  103. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/ui.py +0 -0
  104. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/unicode_security.py +0 -0
  105. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/update_check.py +0 -0
  106. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/__init__.py +0 -0
  107. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/_links.py +0 -0
  108. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/agent_selector.py +0 -0
  109. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/approval.py +0 -0
  110. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/ask_user.py +0 -0
  111. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/autocomplete.py +0 -0
  112. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/chat_input.py +0 -0
  113. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/diff.py +0 -0
  114. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/history.py +0 -0
  115. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/loading.py +0 -0
  116. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/mcp_viewer.py +0 -0
  117. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/message_store.py +0 -0
  118. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/messages.py +0 -0
  119. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/model_selector.py +0 -0
  120. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/notification_center.py +0 -0
  121. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/notification_detail.py +0 -0
  122. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/notification_settings.py +0 -0
  123. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/status.py +0 -0
  124. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/thread_selector.py +0 -0
  125. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/tool_renderers.py +0 -0
  126. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/tool_widgets.py +0 -0
  127. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/deepagents_cli/widgets/update_available.py +0 -0
  128. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/.env.example +0 -0
  129. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/skills/blog-post/SKILL.md +0 -0
  130. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/skills/social-media/SKILL.md +0 -0
  131. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/user/context.md +0 -0
  132. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/deploy-content-writer/user/preferences.md +0 -0
  133. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/arxiv-search/SKILL.md +0 -0
  134. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/arxiv-search/arxiv_search.py +0 -0
  135. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/langgraph-docs/SKILL.md +0 -0
  136. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/skill-creator/SKILL.md +0 -0
  137. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
  138. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
  139. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/examples/skills/web-research/SKILL.md +0 -0
  140. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/.nvmrc +0 -0
  141. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/index.html +0 -0
  142. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/package-lock.json +0 -0
  143. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/package.json +0 -0
  144. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/postcss.config.js +0 -0
  145. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/public/logo-dark.svg +0 -0
  146. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/public/logo-light.svg +0 -0
  147. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/App.tsx +0 -0
  148. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/ThemeProvider.tsx +0 -0
  149. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/anonymous.tsx +0 -0
  150. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/clerk.tsx +0 -0
  151. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/loader.tsx +0 -0
  152. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/supabase.tsx +0 -0
  153. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/auth/types.ts +0 -0
  154. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/AppHeader.tsx +0 -0
  155. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/FilePanels.tsx +0 -0
  156. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/MessageList.tsx +0 -0
  157. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/SubagentActivity.tsx +0 -0
  158. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/ThreadPicker.tsx +0 -0
  159. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/TodosPanel.tsx +0 -0
  160. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/ToolCallCard.tsx +0 -0
  161. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/FileToolCard.tsx +0 -0
  162. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/SearchCard.tsx +0 -0
  163. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/ThinkCard.tsx +0 -0
  164. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/TodosCard.tsx +0 -0
  165. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/components/toolcalls/index.ts +0 -0
  166. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/constants.ts +0 -0
  167. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/index.css +0 -0
  168. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/main.tsx +0 -0
  169. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/runtimeConfig.ts +0 -0
  170. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/types.ts +0 -0
  171. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/src/vite-env.d.ts +0 -0
  172. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/tsconfig.json +0 -0
  173. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/frontend/vite.config.ts +0 -0
  174. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/images/cli.png +0 -0
  175. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/scripts/check_imports.py +0 -0
  176. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/scripts/debug_server.sh +0 -0
  177. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/README.md +0 -0
  178. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/__init__.py +0 -0
  179. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/benchmarks/__init__.py +0 -0
  180. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
  181. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
  182. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/conftest.py +0 -0
  183. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/test_acp_mode.py +0 -0
  184. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/test_compact_resume.py +0 -0
  185. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/test_sandbox_factory.py +0 -0
  186. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/integration_tests/test_sandbox_operations.py +0 -0
  187. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/__init__.py +0 -0
  188. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/conftest.py +0 -0
  189. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/__init__.py +0 -0
  190. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_bundler.py +0 -0
  191. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_commands.py +0 -0
  192. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_config.py +0 -0
  193. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_frontend_bundle.py +0 -0
  194. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/deploy/test_frontend_config.py +0 -0
  195. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/skills/__init__.py +0 -0
  196. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/skills/test_commands.py +0 -0
  197. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/skills/test_load.py +0 -0
  198. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/skills/test_skills_json.py +0 -0
  199. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_agent.py +0 -0
  200. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_agent_friendly.py +0 -0
  201. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_agent_selector.py +0 -0
  202. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_approval.py +0 -0
  203. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_args.py +0 -0
  204. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_ask_user.py +0 -0
  205. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_ask_user_middleware.py +0 -0
  206. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_autocomplete.py +0 -0
  207. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_charset.py +0 -0
  208. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_command_registry.py +0 -0
  209. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_compact_tool.py +0 -0
  210. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_config.py +0 -0
  211. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_configurable_model.py +0 -0
  212. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_debug.py +0 -0
  213. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_editor.py +0 -0
  214. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_end_to_end.py +0 -0
  215. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_env_vars.py +0 -0
  216. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_exception_handling.py +0 -0
  217. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_extras_info.py +0 -0
  218. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_file_ops.py +0 -0
  219. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_formatting.py +0 -0
  220. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_git.py +0 -0
  221. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_history.py +0 -0
  222. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_hooks.py +0 -0
  223. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_imports.py +0 -0
  224. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_input_parsing.py +0 -0
  225. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_links.py +0 -0
  226. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_loading.py +0 -0
  227. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_local_context.py +0 -0
  228. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_main.py +0 -0
  229. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_main_acp_mode.py +0 -0
  230. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_main_args.py +0 -0
  231. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_auth.py +0 -0
  232. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_commands.py +0 -0
  233. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_tools.py +0 -0
  234. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_trust.py +0 -0
  235. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_mcp_viewer.py +0 -0
  236. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_media_utils.py +0 -0
  237. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_message_store.py +0 -0
  238. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_messages.py +0 -0
  239. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_model_config.py +0 -0
  240. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_model_selector.py +0 -0
  241. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_non_interactive.py +0 -0
  242. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_notification_center.py +0 -0
  243. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_notification_detail.py +0 -0
  244. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_notifications.py +0 -0
  245. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_offload.py +0 -0
  246. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_offload_dict_messages.py +0 -0
  247. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_output.py +0 -0
  248. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_reload.py +0 -0
  249. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_remote_client.py +0 -0
  250. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_sandbox_factory.py +0 -0
  251. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server.py +0 -0
  252. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server_config.py +0 -0
  253. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server_graph.py +0 -0
  254. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server_helpers.py +0 -0
  255. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_server_manager.py +0 -0
  256. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_session_stats.py +0 -0
  257. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_sessions.py +0 -0
  258. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_shell_allow_list.py +0 -0
  259. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_skill_invocation.py +0 -0
  260. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_status.py +0 -0
  261. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_subagents.py +0 -0
  262. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_terminal_capabilities.py +0 -0
  263. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_textual_adapter.py +0 -0
  264. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_textual_patches.py +0 -0
  265. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_thread_selector.py +0 -0
  266. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_token_tracker.py +0 -0
  267. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_tool_display.py +0 -0
  268. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_ui.py +0 -0
  269. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_unicode_security.py +0 -0
  270. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_update_available.py +0 -0
  271. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_update_check.py +0 -0
  272. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/test_version.py +0 -0
  273. {deepagents_cli-0.0.46 → deepagents_cli-0.0.48}/tests/unit_tests/tools/__init__.py +0 -0
  274. {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.46
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.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.0.0
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://raw.githubusercontent.com/langchain-ai/deepagents/main/libs/cli/scripts/install.sh | bash
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://raw.githubusercontent.com/langchain-ai/deepagents/main/libs/cli/scripts/install.sh | bash
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://raw.githubusercontent.com/langchain-ai/deepagents/main/libs/cli/scripts/install.sh | bash
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://raw.githubusercontent.com/langchain-ai/deepagents/main/libs/cli/scripts/install.sh | bash
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.46" # x-release-please-version
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
- if isinstance(name, str) and name in theme.ThemeEntry.REGISTRY:
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.ThemeEntry.REGISTRY:
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
- # Update banner to show persistent failure state
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.set_failed(self._server_startup_error)
1906
+ banner.set_idle()
1812
1907
  except NoMatches:
1813
1908
  logger.warning("Welcome banner not found during server failure transition")
1814
1909
 
1815
- # Discard any messages queued while the server was starting
1816
- if self._pending_messages:
1817
- self._pending_messages.clear()
1818
- for w in self._queued_widgets:
1819
- w.remove()
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 or still sequencing startup work, enqueue instead
3069
- # of processing. Messages queued during startup are drained once the
3070
- # session reaches its first stable idle/running state.
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
- await self._mount_message(
4125
- ErrorMessage(f"Server failed to start: {self._server_startup_error}")
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.ThemeEntry.REGISTRY.items():
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
- await self._mount_message(AppMessage(f"Already using {current}"))
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
- await self._mount_message(AppMessage(f"Switched to {display}"))
6617
- logger.info("Model switched to %s (via configurable middleware)", display)
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, or no credentials are
2199
- configured.
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
- env_var = get_credential_env_var(provider) or f"<{provider} API key>"
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 {env_var} environment variable."
2258
+ f"Please set the {display_env} environment variable."
2255
2259
  )
2256
- raise ModelConfigError(msg)
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.