deepagents-cli 0.0.46__tar.gz → 0.0.47__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.47}/CHANGELOG.md +10 -0
  2. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/PKG-INFO +4 -4
  3. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/README.md +2 -2
  4. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_version.py +1 -1
  5. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/app.py +251 -19
  6. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/config.py +10 -6
  7. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/model_config.py +28 -0
  8. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/theme.py +69 -58
  9. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/theme_selector.py +3 -3
  10. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/welcome.py +15 -32
  11. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/pyproject.toml +2 -2
  12. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/scripts/install.sh +1 -1
  13. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_app.py +9 -6
  14. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_chat_input.py +13 -2
  15. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_model_switch.py +137 -0
  16. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_theme.py +22 -20
  17. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_welcome.py +0 -15
  18. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/uv.lock +5 -5
  19. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/.gitignore +0 -0
  20. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/DEV.md +0 -0
  21. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/Makefile +0 -0
  22. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/THREAT_MODEL.md +0 -0
  23. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/__init__.py +0 -0
  24. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/__main__.py +0 -0
  25. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_ask_user_types.py +0 -0
  26. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_cli_context.py +0 -0
  27. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_debug.py +0 -0
  28. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_env_vars.py +0 -0
  29. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_git.py +0 -0
  30. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_server_config.py +0 -0
  31. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_session_stats.py +0 -0
  32. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_testing_models.py +0 -0
  33. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/_textual_patches.py +0 -0
  34. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/agent.py +0 -0
  35. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/app.tcss +0 -0
  36. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/ask_user.py +0 -0
  37. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/built_in_skills/__init__.py +0 -0
  38. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/built_in_skills/remember/SKILL.md +0 -0
  39. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
  40. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
  41. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
  42. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/clipboard.py +0 -0
  43. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/command_registry.py +0 -0
  44. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/configurable_model.py +0 -0
  45. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/default_agent_prompt.md +0 -0
  46. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/__init__.py +0 -0
  47. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/bundler.py +0 -0
  48. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/commands.py +0 -0
  49. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/config.py +0 -0
  50. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/frontend_dist/assets/anonymous-B9UzAXQd.js +0 -0
  51. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/frontend_dist/assets/clerk-5xHgyQyG.js +0 -0
  52. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/frontend_dist/assets/highlighted-body-OFNGDK62-rX-7qT8o.js +0 -0
  53. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/frontend_dist/assets/index-DM3gptpu.js +0 -0
  54. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/frontend_dist/assets/index-Ddy7F6KI.css +0 -0
  55. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/frontend_dist/assets/supabase-S6NACDgm.js +0 -0
  56. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/frontend_dist/index.html +0 -0
  57. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/frontend_dist/logo-dark.svg +0 -0
  58. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/frontend_dist/logo-light.svg +0 -0
  59. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/deploy/templates.py +0 -0
  60. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/editor.py +0 -0
  61. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/extras_info.py +0 -0
  62. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/file_ops.py +0 -0
  63. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/formatting.py +0 -0
  64. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/hooks.py +0 -0
  65. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/input.py +0 -0
  66. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/integrations/__init__.py +0 -0
  67. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/integrations/sandbox_factory.py +0 -0
  68. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/integrations/sandbox_provider.py +0 -0
  69. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/local_context.py +0 -0
  70. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/main.py +0 -0
  71. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/mcp_auth.py +0 -0
  72. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/mcp_commands.py +0 -0
  73. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/mcp_providers/__init__.py +0 -0
  74. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/mcp_providers/_registry.py +0 -0
  75. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/mcp_providers/base.py +0 -0
  76. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/mcp_providers/github.py +0 -0
  77. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/mcp_providers/slack.py +0 -0
  78. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/mcp_tools.py +0 -0
  79. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/mcp_trust.py +0 -0
  80. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/media_utils.py +0 -0
  81. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/non_interactive.py +0 -0
  82. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/notifications.py +0 -0
  83. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/offload.py +0 -0
  84. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/output.py +0 -0
  85. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/project_utils.py +0 -0
  86. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/py.typed +0 -0
  87. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/remote_client.py +0 -0
  88. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/server.py +0 -0
  89. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/server_graph.py +0 -0
  90. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/server_manager.py +0 -0
  91. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/sessions.py +0 -0
  92. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/skills/__init__.py +0 -0
  93. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/skills/commands.py +0 -0
  94. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/skills/invocation.py +0 -0
  95. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/skills/load.py +0 -0
  96. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/subagents.py +0 -0
  97. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/system_prompt.md +0 -0
  98. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/terminal_capabilities.py +0 -0
  99. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/textual_adapter.py +0 -0
  100. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/token_state.py +0 -0
  101. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/tool_display.py +0 -0
  102. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/tools.py +0 -0
  103. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/ui.py +0 -0
  104. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/unicode_security.py +0 -0
  105. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/update_check.py +0 -0
  106. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/__init__.py +0 -0
  107. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/_links.py +0 -0
  108. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/agent_selector.py +0 -0
  109. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/approval.py +0 -0
  110. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/ask_user.py +0 -0
  111. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/autocomplete.py +0 -0
  112. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/chat_input.py +0 -0
  113. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/diff.py +0 -0
  114. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/history.py +0 -0
  115. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/loading.py +0 -0
  116. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/mcp_viewer.py +0 -0
  117. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/message_store.py +0 -0
  118. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/messages.py +0 -0
  119. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/model_selector.py +0 -0
  120. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/notification_center.py +0 -0
  121. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/notification_detail.py +0 -0
  122. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/notification_settings.py +0 -0
  123. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/status.py +0 -0
  124. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/thread_selector.py +0 -0
  125. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/tool_renderers.py +0 -0
  126. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/tool_widgets.py +0 -0
  127. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/deepagents_cli/widgets/update_available.py +0 -0
  128. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/deploy-content-writer/.env.example +0 -0
  129. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/deploy-content-writer/skills/blog-post/SKILL.md +0 -0
  130. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/deploy-content-writer/skills/social-media/SKILL.md +0 -0
  131. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/deploy-content-writer/user/context.md +0 -0
  132. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/deploy-content-writer/user/preferences.md +0 -0
  133. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/skills/arxiv-search/SKILL.md +0 -0
  134. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/skills/arxiv-search/arxiv_search.py +0 -0
  135. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/skills/langgraph-docs/SKILL.md +0 -0
  136. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/skills/skill-creator/SKILL.md +0 -0
  137. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
  138. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
  139. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/examples/skills/web-research/SKILL.md +0 -0
  140. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/.nvmrc +0 -0
  141. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/index.html +0 -0
  142. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/package-lock.json +0 -0
  143. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/package.json +0 -0
  144. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/postcss.config.js +0 -0
  145. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/public/logo-dark.svg +0 -0
  146. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/public/logo-light.svg +0 -0
  147. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/App.tsx +0 -0
  148. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/ThemeProvider.tsx +0 -0
  149. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/auth/anonymous.tsx +0 -0
  150. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/auth/clerk.tsx +0 -0
  151. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/auth/loader.tsx +0 -0
  152. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/auth/supabase.tsx +0 -0
  153. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/auth/types.ts +0 -0
  154. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/AppHeader.tsx +0 -0
  155. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/FilePanels.tsx +0 -0
  156. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/MessageList.tsx +0 -0
  157. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/SubagentActivity.tsx +0 -0
  158. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/ThreadPicker.tsx +0 -0
  159. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/TodosPanel.tsx +0 -0
  160. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/ToolCallCard.tsx +0 -0
  161. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/toolcalls/FileToolCard.tsx +0 -0
  162. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/toolcalls/SearchCard.tsx +0 -0
  163. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/toolcalls/ThinkCard.tsx +0 -0
  164. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/toolcalls/TodosCard.tsx +0 -0
  165. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/components/toolcalls/index.ts +0 -0
  166. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/constants.ts +0 -0
  167. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/index.css +0 -0
  168. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/main.tsx +0 -0
  169. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/runtimeConfig.ts +0 -0
  170. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/types.ts +0 -0
  171. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/src/vite-env.d.ts +0 -0
  172. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/tsconfig.json +0 -0
  173. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/frontend/vite.config.ts +0 -0
  174. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/images/cli.png +0 -0
  175. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/scripts/check_imports.py +0 -0
  176. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/scripts/debug_server.sh +0 -0
  177. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/README.md +0 -0
  178. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/integration_tests/__init__.py +0 -0
  179. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/integration_tests/benchmarks/__init__.py +0 -0
  180. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
  181. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
  182. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/integration_tests/conftest.py +0 -0
  183. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/integration_tests/test_acp_mode.py +0 -0
  184. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/integration_tests/test_compact_resume.py +0 -0
  185. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/integration_tests/test_sandbox_factory.py +0 -0
  186. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/integration_tests/test_sandbox_operations.py +0 -0
  187. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/__init__.py +0 -0
  188. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/conftest.py +0 -0
  189. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/deploy/__init__.py +0 -0
  190. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/deploy/test_bundler.py +0 -0
  191. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/deploy/test_commands.py +0 -0
  192. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/deploy/test_config.py +0 -0
  193. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/deploy/test_frontend_bundle.py +0 -0
  194. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/deploy/test_frontend_config.py +0 -0
  195. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/skills/__init__.py +0 -0
  196. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/skills/test_commands.py +0 -0
  197. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/skills/test_load.py +0 -0
  198. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/skills/test_skills_json.py +0 -0
  199. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_agent.py +0 -0
  200. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_agent_friendly.py +0 -0
  201. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_agent_selector.py +0 -0
  202. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_approval.py +0 -0
  203. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_args.py +0 -0
  204. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_ask_user.py +0 -0
  205. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_ask_user_middleware.py +0 -0
  206. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_autocomplete.py +0 -0
  207. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_charset.py +0 -0
  208. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_command_registry.py +0 -0
  209. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_compact_tool.py +0 -0
  210. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_config.py +0 -0
  211. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_configurable_model.py +0 -0
  212. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_debug.py +0 -0
  213. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_editor.py +0 -0
  214. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_end_to_end.py +0 -0
  215. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_env_vars.py +0 -0
  216. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_exception_handling.py +0 -0
  217. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_extras_info.py +0 -0
  218. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_file_ops.py +0 -0
  219. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_formatting.py +0 -0
  220. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_git.py +0 -0
  221. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_history.py +0 -0
  222. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_hooks.py +0 -0
  223. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_imports.py +0 -0
  224. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_input_parsing.py +0 -0
  225. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_links.py +0 -0
  226. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_loading.py +0 -0
  227. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_local_context.py +0 -0
  228. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_main.py +0 -0
  229. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_main_acp_mode.py +0 -0
  230. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_main_args.py +0 -0
  231. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_mcp_auth.py +0 -0
  232. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_mcp_commands.py +0 -0
  233. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_mcp_tools.py +0 -0
  234. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_mcp_trust.py +0 -0
  235. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_mcp_viewer.py +0 -0
  236. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_media_utils.py +0 -0
  237. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_message_store.py +0 -0
  238. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_messages.py +0 -0
  239. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_model_config.py +0 -0
  240. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_model_selector.py +0 -0
  241. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_non_interactive.py +0 -0
  242. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_notification_center.py +0 -0
  243. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_notification_detail.py +0 -0
  244. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_notifications.py +0 -0
  245. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_offload.py +0 -0
  246. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_offload_dict_messages.py +0 -0
  247. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_output.py +0 -0
  248. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_reload.py +0 -0
  249. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_remote_client.py +0 -0
  250. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_sandbox_factory.py +0 -0
  251. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_server.py +0 -0
  252. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_server_config.py +0 -0
  253. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_server_graph.py +0 -0
  254. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_server_helpers.py +0 -0
  255. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_server_manager.py +0 -0
  256. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_session_stats.py +0 -0
  257. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_sessions.py +0 -0
  258. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_shell_allow_list.py +0 -0
  259. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_skill_invocation.py +0 -0
  260. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_status.py +0 -0
  261. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_subagents.py +0 -0
  262. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_terminal_capabilities.py +0 -0
  263. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_textual_adapter.py +0 -0
  264. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_textual_patches.py +0 -0
  265. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_thread_selector.py +0 -0
  266. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_token_tracker.py +0 -0
  267. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_tool_display.py +0 -0
  268. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_ui.py +0 -0
  269. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_unicode_security.py +0 -0
  270. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_update_available.py +0 -0
  271. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_update_check.py +0 -0
  272. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/test_version.py +0 -0
  273. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/tools/__init__.py +0 -0
  274. {deepagents_cli-0.0.46 → deepagents_cli-0.0.47}/tests/unit_tests/tools/test_fetch_url.py +0 -0
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.47](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.46...deepagents-cli==0.0.47) (2026-05-01)
4
+
5
+ ### Features
6
+
7
+ * Auto-discover Textual built-in themes ([#3068](https://github.com/langchain-ai/deepagents/issues/3068)) ([27894e3](https://github.com/langchain-ai/deepagents/commit/27894e336f20f270fb4bb685bf979f24b9bea0bc))
8
+
9
+ ### Bug Fixes
10
+
11
+ * 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))
12
+
3
13
  ## [0.0.46](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.45...deepagents-cli==0.0.46) (2026-04-30)
4
14
 
5
15
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepagents-cli
3
- Version: 0.0.46
3
+ Version: 0.0.47
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/
@@ -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.47" # 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
 
@@ -428,6 +431,24 @@ def _truncate(text: str, *, limit: int) -> str:
428
431
  return text[: limit - 1].rstrip() + "…"
429
432
 
430
433
 
434
+ def _log_task_exception(task: asyncio.Task[Any]) -> None:
435
+ """Done-callback that surfaces unhandled exceptions from fire-and-forget tasks.
436
+
437
+ Default `asyncio` behavior is to log "Task exception was never retrieved"
438
+ only when the task is GC'd — easy to miss. This callback runs at task
439
+ completion and routes failures through `logger.warning` with `exc_info`,
440
+ matching the codebase pattern at `_finalize_git_branch_refresh`. Use
441
+ when scheduling a coroutine via `asyncio.create_task` whose result is
442
+ not awaited (e.g. event-handler cleanup, single-fire mounts).
443
+ """
444
+ try:
445
+ task.result()
446
+ except asyncio.CancelledError:
447
+ pass
448
+ except Exception:
449
+ logger.warning("Background task failed unexpectedly", exc_info=True)
450
+
451
+
431
452
  def _format_startup_error(error: BaseException) -> str:
432
453
  """Format a server-startup exception for the welcome banner.
433
454
 
@@ -905,6 +926,25 @@ class DeepAgentsApp(App):
905
926
  Shown in place of the generic 'Agent not configured' message.
906
927
  """
907
928
 
929
+ self._server_startup_missing_credentials_provider: str | None = None
930
+ """Set to the offending provider name when startup failed with
931
+ `MissingCredentialsError`; `None` otherwise. Gates the `/model`
932
+ recovery hint without string-matching on the formatted error.
933
+ """
934
+
935
+ self._retry_status_widget: AppMessage | None = None
936
+ """Transient "Retrying startup with X…" breadcrumb. Mounted via
937
+ `_mount_before_queued` (not `_mount_message`) because it is ephemeral
938
+ state and must not appear in scrollback or serialized history.
939
+ """
940
+
941
+ self._startup_failure_widget: ErrorMessage | None = None
942
+ """Transient chat surface for the most recent server-startup failure.
943
+ Mounted by `on_deep_agents_app_server_start_failed`; removed on
944
+ `ServerReady` so a successful `/model` retry doesn't leave the stale
945
+ error dangling in scrollback.
946
+ """
947
+
908
948
  self._quit_pending = False
909
949
  """True after a first `Ctrl+C` so a second press within the window quits."""
910
950
 
@@ -1181,6 +1221,14 @@ class DeepAgentsApp(App):
1181
1221
  # Focus the input immediately so the cursor is visible on first paint
1182
1222
  self._chat_input.focus_input()
1183
1223
 
1224
+ # Pre-import `html.entities` on the main thread before the worker
1225
+ # starts. Python 3.14 replaced the global import lock with per-module
1226
+ # locks; a worker importing `markdown_it` (which transitively pulls
1227
+ # `html.entities`) can race main-thread code looking up `html` *while
1228
+ # `html` itself is still being initialized*, raising `KeyError: 'html'`
1229
+ # from `_find_and_load_unlocked`.
1230
+ import html.entities # noqa: F401
1231
+
1184
1232
  # Prewarm heavy imports in a thread while the first frame renders.
1185
1233
  # The user can't type yet, so GIL contention is harmless. By the
1186
1234
  # time _post_paint_init fires its inline imports are dict lookups.
@@ -1742,6 +1790,28 @@ class DeepAgentsApp(App):
1742
1790
  self._agent = event.agent
1743
1791
  self._server_proc = event.server_proc
1744
1792
  self._mcp_server_info = event.mcp_server_info
1793
+
1794
+ # Drop transient failure-state widgets — banner state and the agent
1795
+ # response now convey "connected", so the prior error and breadcrumb
1796
+ # would just dangle in scrollback.
1797
+ for attr in ("_retry_status_widget", "_startup_failure_widget"):
1798
+ widget = getattr(self, attr)
1799
+ if widget is None:
1800
+ continue
1801
+ setattr(self, attr, None)
1802
+
1803
+ async def _drop(w: Widget = widget) -> None:
1804
+ # Mount may still be in flight when `ServerReady` arrives;
1805
+ # short-circuit on un-attached widgets instead of raising.
1806
+ # `NoMatches`/`ScreenStackError` cover later-stage detach
1807
+ # races (screen torn down mid-removal).
1808
+ if not w.is_attached:
1809
+ return
1810
+ with suppress(NoMatches, ScreenStackError):
1811
+ await w.remove()
1812
+
1813
+ task = asyncio.create_task(_drop())
1814
+ task.add_done_callback(_log_task_exception)
1745
1815
  self._mcp_tool_count = sum(len(s.tools) for s in (event.mcp_server_info or []))
1746
1816
  self._mcp_unauthenticated = sum(
1747
1817
  1 for s in (event.mcp_server_info or []) if s.status == "unauthenticated"
@@ -1797,6 +1867,7 @@ class DeepAgentsApp(App):
1797
1867
  def on_deep_agents_app_server_start_failed(self, event: ServerStartFailed) -> None:
1798
1868
  """Handle background server startup failure."""
1799
1869
  from deepagents_cli.mcp_tools import MCPConfigError
1870
+ from deepagents_cli.model_config import MissingCredentialsError
1800
1871
 
1801
1872
  self._connecting = False
1802
1873
  if isinstance(event.error, MCPConfigError):
@@ -1804,22 +1875,68 @@ class DeepAgentsApp(App):
1804
1875
  self._server_startup_error = str(event.error)
1805
1876
  else:
1806
1877
  self._server_startup_error = _format_startup_error(event.error)
1878
+
1879
+ # Stash the provider for the `/model` recovery hint. Reset on every
1880
+ # failure so a non-credentials retry-failure clears the prior flag.
1881
+ self._server_startup_missing_credentials_provider = (
1882
+ event.error.provider
1883
+ if isinstance(event.error, MissingCredentialsError)
1884
+ else None
1885
+ )
1807
1886
  logger.error("Server startup failed: %s", event.error, exc_info=event.error)
1808
- # Update banner to show persistent failure state
1887
+
1888
+ # Drop the banner's connecting spinner — chat surface owns the error.
1809
1889
  try:
1810
1890
  banner = self.query_one("#welcome-banner", WelcomeBanner)
1811
- banner.set_failed(self._server_startup_error)
1891
+ banner.set_idle()
1812
1892
  except NoMatches:
1813
1893
  logger.warning("Welcome banner not found during server failure transition")
1814
1894
 
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()
1895
+ # Keep any queued messages and widgets in place `/model` retry can
1896
+ # bring the server up, at which point `_run_session_start_sequence`
1897
+ # drains them. Deferred actions (model/thread switches queued during
1898
+ # the initial connect) are dropped because the failure invalidates
1899
+ # their assumptions; the user can re-issue them after recovery.
1821
1900
  self._deferred_actions.clear()
1822
1901
 
1902
+ # Failure surfaces only in chat — keeps recovery hint adjacent to the
1903
+ # input. Banner is set to idle above to drop the connecting spinner.
1904
+ text = f"Server failed to start: {self._server_startup_error}"
1905
+ if (
1906
+ self._server_startup_missing_credentials_provider is not None
1907
+ and self._server_kwargs is not None
1908
+ ):
1909
+ text += (
1910
+ "\n\nHint: run `/model <provider>:<model>` to retry "
1911
+ "startup with a provider you have credentials for."
1912
+ )
1913
+
1914
+ async def _mount_failure() -> None:
1915
+ # Drop any prior failure widget (re-entrant on retry-then-fail).
1916
+ prior = self._startup_failure_widget
1917
+ self._startup_failure_widget = None
1918
+ if prior is not None and prior.is_attached:
1919
+ with suppress(NoMatches, ScreenStackError):
1920
+ await prior.remove()
1921
+
1922
+ try:
1923
+ messages = self.query_one("#messages", Container)
1924
+ except (NoMatches, ScreenStackError):
1925
+ return
1926
+ if not messages.is_attached:
1927
+ return
1928
+
1929
+ new_widget = ErrorMessage(text)
1930
+ # Mount before storing the reference so `ServerReady` racing this
1931
+ # await cannot observe a half-mounted widget.
1932
+ await self._mount_before_queued(messages, new_widget)
1933
+ self._startup_failure_widget = new_widget
1934
+
1935
+ # Fire-and-forget mount: this is the *only* failure surface, so log
1936
+ # any exception loudly via `_log_task_exception`.
1937
+ task = asyncio.create_task(_mount_failure())
1938
+ task.add_done_callback(_log_task_exception)
1939
+
1823
1940
  async def _await_prewarm_imports(self) -> None:
1824
1941
  """Wait for prewarm imports before re-entering their module graph.
1825
1942
 
@@ -3065,14 +3182,17 @@ class DeepAgentsApp(App):
3065
3182
  )
3066
3183
  return
3067
3184
 
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.
3185
+ # If the app is busy, still sequencing startup work, or holding a
3186
+ # post-failure recovery state (server hasn't come up yet but `/model`
3187
+ # retry is still possible), enqueue instead of processing. Messages
3188
+ # queued in any of these states are drained once the session reaches
3189
+ # its first stable idle/running state.
3071
3190
  if (
3072
3191
  self._agent_running
3073
3192
  or self._shell_running
3074
3193
  or self._connecting
3075
3194
  or self._startup_sequence_running
3195
+ or self._server_startup_error is not None
3076
3196
  ):
3077
3197
  if mode == "command" and self._can_bypass_queue(value.lower().strip()):
3078
3198
  await self._process_message(value, mode)
@@ -4120,11 +4240,10 @@ class DeepAgentsApp(App):
4120
4240
  self._run_agent_task(message, message_kwargs=message_kwargs),
4121
4241
  exclusive=False,
4122
4242
  )
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:
4243
+ elif not self._server_startup_error:
4244
+ # When a server-startup failure is in flight, the chat
4245
+ # `ErrorMessage` mounted by `on_deep_agents_app_server_start_failed`
4246
+ # is the single source of truth — don't duplicate it here.
4128
4247
  await self._mount_message(
4129
4248
  AppMessage("Agent not configured for this session.")
4130
4249
  )
@@ -5367,7 +5486,7 @@ class DeepAgentsApp(App):
5367
5486
 
5368
5487
  def _register_custom_themes(self) -> None:
5369
5488
  """Register all custom themes (built-in LC + user-defined) with Textual."""
5370
- for name, entry in theme.ThemeEntry.REGISTRY.items():
5489
+ for name, entry in theme.get_registry().items():
5371
5490
  if entry.custom:
5372
5491
  c = entry.colors
5373
5492
  try:
@@ -6530,6 +6649,18 @@ class DeepAgentsApp(App):
6530
6649
  timeout=3,
6531
6650
  )
6532
6651
  return
6652
+ # Recover from a failed startup (e.g., `MissingCredentialsError`).
6653
+ # The server never came up, so the only way out without
6654
+ # restarting the CLI is to retry startup with the new model.
6655
+ # Only valid for CLI-owned servers.
6656
+ if (
6657
+ self._server_startup_error is not None
6658
+ and self._server_kwargs is not None
6659
+ ):
6660
+ await self._retry_startup_with_model(
6661
+ model_spec, extra_kwargs=extra_kwargs
6662
+ )
6663
+ return
6533
6664
  await self._mount_message(
6534
6665
  ErrorMessage("Model switching requires a server-backed session.")
6535
6666
  )
@@ -6622,6 +6753,107 @@ class DeepAgentsApp(App):
6622
6753
  finally:
6623
6754
  self._model_switching = False
6624
6755
 
6756
+ async def _retry_startup_with_model(
6757
+ self,
6758
+ model_spec: str,
6759
+ *,
6760
+ extra_kwargs: dict[str, Any] | None = None,
6761
+ ) -> None:
6762
+ """Retry deferred server startup after a failed initial startup.
6763
+
6764
+ Exists because the server never came up (typically a
6765
+ `MissingCredentialsError`), so the only escape without restarting
6766
+ the CLI is re-running the deferred startup worker with a new spec.
6767
+
6768
+ Args:
6769
+ model_spec: The new model specification (`provider:model` or bare
6770
+ model name for auto-detection).
6771
+ extra_kwargs: Extra constructor kwargs from `--model-params`.
6772
+ """
6773
+ from deepagents_cli.config import detect_provider
6774
+ from deepagents_cli.model_config import (
6775
+ ModelSpec,
6776
+ get_credential_env_var,
6777
+ has_provider_credentials,
6778
+ )
6779
+
6780
+ if self._server_kwargs is None:
6781
+ await self._mount_message(
6782
+ ErrorMessage("Cannot retry startup: server is not CLI-owned.")
6783
+ )
6784
+ return
6785
+
6786
+ parsed = ModelSpec.try_parse(model_spec)
6787
+ if parsed:
6788
+ provider: str | None = parsed.provider
6789
+ model_name = parsed.model
6790
+ else:
6791
+ model_name = model_spec
6792
+ provider = detect_provider(model_spec)
6793
+
6794
+ # Tri-state credentials check (`None` = unknown provider, treated as
6795
+ # proceed); bail early so retrying with still-missing creds doesn't
6796
+ # loop right back into the same `MissingCredentialsError`.
6797
+ has_creds = has_provider_credentials(provider) if provider else None
6798
+ if has_creds is False and provider is not None:
6799
+ env_var = get_credential_env_var(provider)
6800
+ detail = (
6801
+ f"{env_var} is not set or is empty"
6802
+ if env_var
6803
+ else (
6804
+ f"provider '{provider}' is not recognized. "
6805
+ "Add it to ~/.deepagents/config.toml with an "
6806
+ "api_key_env field"
6807
+ )
6808
+ )
6809
+ await self._mount_message(ErrorMessage(f"Missing credentials: {detail}"))
6810
+ return
6811
+
6812
+ display = model_spec
6813
+ if provider and not parsed:
6814
+ display = f"{provider}:{model_name}"
6815
+
6816
+ new_model_kwargs: dict[str, Any] = {
6817
+ "model_spec": display,
6818
+ "extra_kwargs": extra_kwargs,
6819
+ "profile_overrides": self._profile_override,
6820
+ }
6821
+ self._model_kwargs = new_model_kwargs
6822
+ self._server_kwargs["model_name"] = display
6823
+ if extra_kwargs is not None:
6824
+ self._server_kwargs["model_params"] = extra_kwargs
6825
+
6826
+ self._server_startup_error = None
6827
+ self._server_startup_missing_credentials_provider = None
6828
+ self._connecting = True
6829
+ try:
6830
+ banner = self.query_one("#welcome-banner", WelcomeBanner)
6831
+ banner.set_connecting()
6832
+ except (NoMatches, ScreenStackError):
6833
+ logger.debug("Welcome banner not found during startup retry", exc_info=True)
6834
+
6835
+ if self._retry_status_widget is not None:
6836
+ with suppress(NoMatches, ScreenStackError):
6837
+ await self._retry_status_widget.remove()
6838
+ self._retry_status_widget = None
6839
+ try:
6840
+ messages = self.query_one("#messages", Container)
6841
+ except (NoMatches, ScreenStackError):
6842
+ messages = None
6843
+ if messages is not None and messages.is_attached:
6844
+ new_widget = AppMessage(f"Retrying startup with {display}…")
6845
+ # Mount before storing the reference so `on_deep_agents_app_server_ready`
6846
+ # cannot observe a half-mounted widget if it races during this await.
6847
+ await self._mount_before_queued(messages, new_widget)
6848
+ self._retry_status_widget = new_widget
6849
+ logger.info("Retrying server startup with model %s", display)
6850
+
6851
+ self.run_worker(
6852
+ self._start_server_background,
6853
+ exclusive=True,
6854
+ group="server-startup",
6855
+ )
6856
+
6625
6857
  async def _set_default_model(self, model_spec: str) -> None:
6626
6858
  """Set the default model in config without switching the current session.
6627
6859
 
@@ -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.