deepagents-code 0.1.9__tar.gz → 0.1.11__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 (260) hide show
  1. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/AGENTS.md +16 -6
  2. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/CHANGELOG.md +23 -0
  3. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/PKG-INFO +4 -4
  4. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/THREAT_MODEL.md +1 -1
  5. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_env_vars.py +10 -0
  6. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_server_config.py +3 -3
  7. deepagents_code-0.1.11/deepagents_code/_textual_patches.py +287 -0
  8. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_version.py +1 -1
  9. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/agent.py +35 -22
  10. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/app.py +256 -110
  11. deepagents_code-0.1.11/deepagents_code/auth_display.py +137 -0
  12. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/auth_store.py +53 -4
  13. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/clipboard.py +0 -3
  14. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/config.py +13 -1
  15. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/input.py +67 -6
  16. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/integrations/sandbox_factory.py +34 -46
  17. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/main.py +265 -13
  18. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_disabled.py +4 -4
  19. deepagents_code-0.1.11/deepagents_code/mcp_trust.py +207 -0
  20. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/model_config.py +310 -7
  21. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/non_interactive.py +1 -2
  22. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/server_manager.py +2 -4
  23. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/ui.py +7 -3
  24. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/update_check.py +228 -19
  25. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/auth.py +70 -24
  26. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/loading.py +23 -4
  27. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/model_selector.py +3 -20
  28. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/pyproject.toml +3 -9
  29. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/conftest.py +36 -0
  30. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_agent.py +259 -0
  31. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_app.py +189 -4
  32. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_args.py +20 -3
  33. deepagents_code-0.1.11/tests/unit_tests/test_auth_display.py +187 -0
  34. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_auth_store.py +57 -0
  35. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_auth_widgets.py +149 -13
  36. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_clipboard.py +34 -0
  37. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_config.py +140 -0
  38. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_input_parsing.py +68 -0
  39. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_install_command.py +110 -0
  40. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_loading.py +78 -0
  41. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_main.py +345 -0
  42. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_main_args.py +151 -0
  43. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_mcp_disabled.py +1 -1
  44. deepagents_code-0.1.11/tests/unit_tests/test_mcp_trust.py +158 -0
  45. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_model_config.py +493 -0
  46. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_sandbox_factory.py +139 -4
  47. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_server_config.py +1 -1
  48. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_textual_patches.py +54 -0
  49. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_update_check.py +284 -4
  50. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/uv.lock +167 -154
  51. deepagents_code-0.1.9/deepagents_code/_textual_patches.py +0 -66
  52. deepagents_code-0.1.9/deepagents_code/mcp_trust.py +0 -167
  53. deepagents_code-0.1.9/tests/unit_tests/test_mcp_trust.py +0 -112
  54. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/.gitignore +0 -0
  55. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/COMMANDS.md +0 -0
  56. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/DEV.md +0 -0
  57. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/Makefile +0 -0
  58. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/README.md +0 -0
  59. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/__init__.py +0 -0
  60. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/__main__.py +0 -0
  61. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_ask_user_types.py +0 -0
  62. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_cli_context.py +0 -0
  63. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_constants.py +0 -0
  64. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_debug.py +0 -0
  65. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_git.py +0 -0
  66. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_session_stats.py +0 -0
  67. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_startup_error.py +0 -0
  68. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/_testing_models.py +0 -0
  69. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/app.tcss +0 -0
  70. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/ask_user.py +0 -0
  71. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/built_in_skills/__init__.py +0 -0
  72. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/built_in_skills/remember/SKILL.md +0 -0
  73. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/built_in_skills/skill-creator/SKILL.md +0 -0
  74. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
  75. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
  76. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/command_registry.py +0 -0
  77. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/configurable_model.py +0 -0
  78. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/default_agent_prompt.md +0 -0
  79. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/editor.py +0 -0
  80. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/event_bus.py +0 -0
  81. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/extras_info.py +0 -0
  82. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/file_ops.py +0 -0
  83. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/filesystem_empty_result.py +0 -0
  84. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/formatting.py +0 -0
  85. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/hooks.py +0 -0
  86. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/integrations/__init__.py +0 -0
  87. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/integrations/sandbox_provider.py +0 -0
  88. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/iterm_cursor_guide.py +0 -0
  89. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/local_context.py +0 -0
  90. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_auth.py +0 -0
  91. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_commands.py +0 -0
  92. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_login_service.py +0 -0
  93. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_oauth_ui.py +0 -0
  94. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_providers/__init__.py +0 -0
  95. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_providers/_registry.py +0 -0
  96. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_providers/base.py +0 -0
  97. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_providers/github.py +0 -0
  98. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_providers/slack.py +0 -0
  99. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/mcp_tools.py +0 -0
  100. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/media_utils.py +0 -0
  101. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/notifications.py +0 -0
  102. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/offload.py +0 -0
  103. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/onboarding.py +0 -0
  104. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/output.py +0 -0
  105. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/project_utils.py +0 -0
  106. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/py.typed +0 -0
  107. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/remote_client.py +0 -0
  108. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/resume_state.py +0 -0
  109. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/server.py +0 -0
  110. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/server_graph.py +0 -0
  111. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/sessions.py +0 -0
  112. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/skills/__init__.py +0 -0
  113. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/skills/commands.py +0 -0
  114. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/skills/invocation.py +0 -0
  115. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/skills/load.py +0 -0
  116. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/state_migration.py +0 -0
  117. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/subagents.py +0 -0
  118. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/system_prompt.md +0 -0
  119. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/terminal_capabilities.py +0 -0
  120. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/terminal_escape.py +0 -0
  121. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/textual_adapter.py +0 -0
  122. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/theme.py +0 -0
  123. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/tool_display.py +0 -0
  124. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/tools.py +0 -0
  125. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/unicode_security.py +0 -0
  126. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/__init__.py +0 -0
  127. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/_links.py +0 -0
  128. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/agent_selector.py +0 -0
  129. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/approval.py +0 -0
  130. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/ask_user.py +0 -0
  131. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/autocomplete.py +0 -0
  132. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/chat_input.py +0 -0
  133. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/diff.py +0 -0
  134. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/history.py +0 -0
  135. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/launch_init.py +0 -0
  136. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/mcp_login.py +0 -0
  137. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/mcp_reconnect.py +0 -0
  138. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/mcp_viewer.py +0 -0
  139. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/message_store.py +0 -0
  140. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/messages.py +0 -0
  141. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/notification_center.py +0 -0
  142. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/notification_detail.py +0 -0
  143. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/notification_settings.py +0 -0
  144. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/status.py +0 -0
  145. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/theme_selector.py +0 -0
  146. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/thread_selector.py +0 -0
  147. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/tool_renderers.py +0 -0
  148. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/tool_widgets.py +0 -0
  149. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/update_available.py +0 -0
  150. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/update_progress.py +0 -0
  151. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/deepagents_code/widgets/welcome.py +0 -0
  152. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/examples/skills/arxiv-search/SKILL.md +0 -0
  153. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/examples/skills/arxiv-search/arxiv_search.py +0 -0
  154. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/examples/skills/langgraph-docs/SKILL.md +0 -0
  155. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/examples/skills/skill-creator/SKILL.md +0 -0
  156. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
  157. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
  158. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/examples/skills/web-research/SKILL.md +0 -0
  159. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/images/tui.png +0 -0
  160. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/scripts/check_imports.py +0 -0
  161. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/scripts/debug_server.sh +0 -0
  162. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/scripts/generate_commands_catalog.py +0 -0
  163. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/scripts/install.sh +0 -0
  164. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/README.md +0 -0
  165. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/integration_tests/__init__.py +0 -0
  166. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/integration_tests/benchmarks/__init__.py +0 -0
  167. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
  168. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
  169. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/integration_tests/conftest.py +0 -0
  170. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/integration_tests/test_acp_mode.py +0 -0
  171. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/integration_tests/test_compact_resume.py +0 -0
  172. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/integration_tests/test_sandbox_factory.py +0 -0
  173. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/integration_tests/test_sandbox_operations.py +0 -0
  174. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/__init__.py +0 -0
  175. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/skills/__init__.py +0 -0
  176. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/skills/test_commands.py +0 -0
  177. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/skills/test_load.py +0 -0
  178. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/skills/test_skills_json.py +0 -0
  179. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_agent_friendly.py +0 -0
  180. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_agent_selector.py +0 -0
  181. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_approval.py +0 -0
  182. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_ask_user.py +0 -0
  183. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_ask_user_middleware.py +0 -0
  184. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_autocomplete.py +0 -0
  185. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_charset.py +0 -0
  186. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_chat_input.py +0 -0
  187. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_command_registry.py +0 -0
  188. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_compact_tool.py +0 -0
  189. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_configurable_model.py +0 -0
  190. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_cursor_blink.py +0 -0
  191. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_debug.py +0 -0
  192. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_editor.py +0 -0
  193. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_end_to_end.py +0 -0
  194. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_env_vars.py +0 -0
  195. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_event_bus.py +0 -0
  196. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_exception_handling.py +0 -0
  197. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_extras_info.py +0 -0
  198. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_file_ops.py +0 -0
  199. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_filesystem_empty_result.py +0 -0
  200. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_formatting.py +0 -0
  201. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_git.py +0 -0
  202. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_history.py +0 -0
  203. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_hooks.py +0 -0
  204. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_imports.py +0 -0
  205. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_iterm_cursor_guide.py +0 -0
  206. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_launch_init.py +0 -0
  207. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_links.py +0 -0
  208. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_local_context.py +0 -0
  209. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_main_acp_mode.py +0 -0
  210. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_mcp_auth.py +0 -0
  211. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_mcp_commands.py +0 -0
  212. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_mcp_login_modal.py +0 -0
  213. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_mcp_login_service.py +0 -0
  214. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_mcp_oauth_ui.py +0 -0
  215. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_mcp_reconnect.py +0 -0
  216. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_mcp_tools.py +0 -0
  217. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_mcp_viewer.py +0 -0
  218. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_media_utils.py +0 -0
  219. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_message_store.py +0 -0
  220. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_messages.py +0 -0
  221. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_model_selector.py +0 -0
  222. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_model_switch.py +0 -0
  223. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_non_interactive.py +0 -0
  224. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_notification_center.py +0 -0
  225. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_notification_detail.py +0 -0
  226. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_notifications.py +0 -0
  227. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_offload.py +0 -0
  228. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_offload_dict_messages.py +0 -0
  229. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_onboarding.py +0 -0
  230. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_output.py +0 -0
  231. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_reload.py +0 -0
  232. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_remote_client.py +0 -0
  233. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_resume_state.py +0 -0
  234. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_server.py +0 -0
  235. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_server_graph.py +0 -0
  236. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_server_helpers.py +0 -0
  237. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_server_manager.py +0 -0
  238. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_session_stats.py +0 -0
  239. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_sessions.py +0 -0
  240. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_shell_allow_list.py +0 -0
  241. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_skill_invocation.py +0 -0
  242. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_startup_fast_paths.py +0 -0
  243. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_state_migration.py +0 -0
  244. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_status.py +0 -0
  245. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_subagents.py +0 -0
  246. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_terminal_capabilities.py +0 -0
  247. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_terminal_escape.py +0 -0
  248. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_terminal_progress_preference.py +0 -0
  249. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_textual_adapter.py +0 -0
  250. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_theme.py +0 -0
  251. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_thread_selector.py +0 -0
  252. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_tool_display.py +0 -0
  253. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_ui.py +0 -0
  254. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_unicode_security.py +0 -0
  255. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_update_available.py +0 -0
  256. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_update_progress.py +0 -0
  257. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_version.py +0 -0
  258. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/test_welcome.py +0 -0
  259. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/tools/__init__.py +0 -0
  260. {deepagents_code-0.1.9 → deepagents_code-0.1.11}/tests/unit_tests/tools/test_fetch_url.py +0 -0
@@ -10,10 +10,10 @@ For monorepo-wide conventions (commit titles, lint, testing, docs, CI, benchmark
10
10
 
11
11
  **Key Textual resources:**
12
12
 
13
- - **Guide:** https://textual.textualize.io/guide/
14
- - **Widget gallery:** https://textual.textualize.io/widget_gallery/
15
- - **CSS reference:** https://textual.textualize.io/styles/
16
- - **API reference:** https://textual.textualize.io/api/
13
+ - **Guide:** <https://textual.textualize.io/guide/>
14
+ - **Widget gallery:** <https://textual.textualize.io/widget_gallery/>
15
+ - **CSS reference:** <https://textual.textualize.io/styles/>
16
+ - **API reference:** <https://textual.textualize.io/api/>
17
17
 
18
18
  ### Styled text in widgets
19
19
 
@@ -92,8 +92,18 @@ To add a new slash command: (1) add a `SlashCommand` entry to `COMMANDS`, (2) se
92
92
  `deepagents-code` supports LangChain-based chat model providers as optional dependencies. To add a new provider, update these files (all entries alphabetically sorted):
93
93
 
94
94
  1. `deepagents_code/model_config.py` — add `"provider_name": "ENV_VAR_NAME"` to `PROVIDER_API_KEY_ENV`
95
- 2. `pyproject.toml` — add `provider = ["langchain-provider>=X.Y.Z,<N.0.0"]` to `[project.optional-dependencies]` and include it in the `all-providers` composite extra
96
- 3. `tests/unit_tests/test_model_config.py` — add `assert PROVIDER_API_KEY_ENV["provider_name"] == "ENV_VAR_NAME"` to `TestProviderApiKeyEnv.test_contains_major_providers`
95
+ 2. `deepagents_code/model_config.py` — if the provider reads a *dedicated* endpoint env var, add `"provider_name": ("CANONICAL_BASE_URL", "ALTERNATE", ...)` to `PROVIDER_BASE_URL_ENV` (see guidelines below); omit the provider entirely when it has no provider-specific endpoint variable
96
+ 3. `pyproject.toml` — add `provider = ["langchain-provider>=X.Y.Z,<N.0.0"]` to `[project.optional-dependencies]` and include it in the `all-providers` composite extra
97
+ 4. `tests/unit_tests/test_model_config.py` — add `assert PROVIDER_API_KEY_ENV["provider_name"] == "ENV_VAR_NAME"` to `TestProviderApiKeyEnv.test_contains_major_providers`, and pin any `PROVIDER_BASE_URL_ENV` entry with a matching assertion
98
+
99
+ ### `PROVIDER_BASE_URL_ENV` guidelines
100
+
101
+ `PROVIDER_BASE_URL_ENV` pairs a provider with the endpoint env var(s) its LangChain integration and SDK read, so a stored `/auth` endpoint resolves and an inherited gateway URL cannot leak. Before adding an entry:
102
+
103
+ - **Verify against source — never infer from naming.** Read both the `langchain-<provider>` chat model (look for `from_env` / `get_from_dict_or_env` / `secret_from_env`, or a `Field` default on the `base_url`/`endpoint` alias) and the underlying vendor SDK, and record the exact env var name each reads. The integration and the SDK often read different names (e.g. `GROQ_API_BASE` vs `GROQ_BASE_URL`).
104
+ - **Canonical name first.** Element `[0]` is written by `apply_stored_credentials` and read by `get_base_url`; every other name the integration or SDK may read goes in the tuple so it is cleared too. By convention the SDK's `*_BASE_URL`-style name is canonical and the integration's `*_API_BASE`/`*_API_URL` name is the alternate.
105
+ - **Never list another provider's shared var.** OpenAI-compatible providers (e.g. `deepseek`, `openrouter`, `together`, `xai`, `baseten`) sit on the `openai` SDK, whose only endpoint var is the shared `OPENAI_BASE_URL`. Listing it under those providers would clobber the user's real OpenAI endpoint when their credential is written or cleared — list only the provider's own var (e.g. `DEEPSEEK_API_BASE`), or nothing.
106
+ - **Omit providers with no dedicated var.** When the endpoint is a hardcoded default plus a constructor arg (`baseten`), an `api_base` arg resolved per-provider inside the library (`litellm`), or derived from the region (`google_vertexai`), leave the provider out. A `/auth` endpoint still resolves through `get_base_url`'s stored-credential step and reaches the model as the `base_url` kwarg.
97
107
 
98
108
  **Not required** unless the provider's models have a distinctive name prefix (like `gpt-*`, `claude*`, `gemini*`):
99
109
 
@@ -2,6 +2,29 @@
2
2
 
3
3
  # Deep Agents Code Changelog
4
4
 
5
+ ## [0.1.11](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.10...deepagents-code==0.1.11) (2026-06-07)
6
+
7
+ ### Bug Fixes
8
+
9
+ * Pause loading timer during approvals ([#3782](https://github.com/langchain-ai/deepagents/issues/3782)) ([f98fb0c](https://github.com/langchain-ai/deepagents/commit/f98fb0c80d08e408a018ea33a8aa7144180f4e93))
10
+ * Run auto-update before startup ([#3784](https://github.com/langchain-ai/deepagents/issues/3784)) ([c160ea3](https://github.com/langchain-ai/deepagents/commit/c160ea3eeda1d0ba707bb524cfd0ce087a854e08))
11
+ * Skip update prompts for editable installs ([#3781](https://github.com/langchain-ai/deepagents/issues/3781)) ([ae2874e](https://github.com/langchain-ai/deepagents/commit/ae2874e8ece96c04233c1a88a9da1bd7b9ee2bb2))
12
+
13
+ ## [0.1.10](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.9...deepagents-code==0.1.10) (2026-06-05)
14
+
15
+ ### Features
16
+
17
+ * Pair model API keys with their endpoints ([#3770](https://github.com/langchain-ai/deepagents/issues/3770)) ([cf98030](https://github.com/langchain-ai/deepagents/commit/cf9803072dc0fdc1d5850c9fd2fc4eb6893ed8c9))
18
+ * Word-level double-click selection ([#3740](https://github.com/langchain-ai/deepagents/issues/3740)) ([4bb4286](https://github.com/langchain-ai/deepagents/commit/4bb4286a26c9c9bc69a36f2714d9eb0e3e5e4d40))
19
+ * Blueprint bootstrapping for Runloop sandboxes ([#3556](https://github.com/langchain-ai/deepagents/issues/3556)) ([13dafd8](https://github.com/langchain-ai/deepagents/commit/13dafd8823c4b530c8e096012733ad74cd501b59))
20
+
21
+ ### Bug Fixes
22
+
23
+ * Propagate runtime model switches to subagents ([#3771](https://github.com/langchain-ai/deepagents/issues/3771)) ([f577182](https://github.com/langchain-ai/deepagents/commit/f577182c84746e625b65c3c2fda95f8ca21164cf))
24
+ * Guard pasted-path probes against `OSError` ([#3745](https://github.com/langchain-ai/deepagents/issues/3745)) ([c9617d3](https://github.com/langchain-ai/deepagents/commit/c9617d3594ab1448c4f3ee2212cdc66cbf138b77))
25
+ * Keep startup import prewarm from crashing the TUI mid-upgrade ([#3756](https://github.com/langchain-ai/deepagents/issues/3756)) ([867a2e5](https://github.com/langchain-ai/deepagents/commit/867a2e5c341bd9dfa70b47c7fafc194ac51d7469))
26
+ * Move MCP trust state out of user config ([#3742](https://github.com/langchain-ai/deepagents/issues/3742)) ([a97f2fd](https://github.com/langchain-ai/deepagents/commit/a97f2fd394e6b0b943225a0195b0901188bd368c))
27
+
5
28
  ## [0.1.9](https://github.com/langchain-ai/deepagents/compare/deepagents-code==0.1.8...deepagents-code==0.1.9) (2026-06-03)
6
29
 
7
30
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepagents-code
3
- Version: 0.1.9
3
+ Version: 0.1.11
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/
@@ -26,7 +26,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
26
  Classifier: Topic :: Terminals
27
27
  Requires-Python: <4.0,>=3.11
28
28
  Requires-Dist: aiosqlite<1.0.0,>=0.22.1
29
- Requires-Dist: deepagents-acp<1.0.0,>=0.0.7
29
+ Requires-Dist: deepagents-acp<1.0.0,>=0.0.8
30
30
  Requires-Dist: deepagents==0.6.8
31
31
  Requires-Dist: httpx<1.0.0,>=0.28.1
32
32
  Requires-Dist: langchain-anthropic<2.0.0,>=1.4.4
@@ -81,7 +81,7 @@ Provides-Extra: all-sandboxes
81
81
  Requires-Dist: langchain-agentcore-codeinterpreter<1.0.0,>=0.0.3; extra == 'all-sandboxes'
82
82
  Requires-Dist: langchain-daytona>=0.0.6; extra == 'all-sandboxes'
83
83
  Requires-Dist: langchain-modal>=0.0.4; extra == 'all-sandboxes'
84
- Requires-Dist: langchain-runloop>=0.0.5; extra == 'all-sandboxes'
84
+ Requires-Dist: langchain-runloop>=0.0.6; extra == 'all-sandboxes'
85
85
  Provides-Extra: anthropic
86
86
  Requires-Dist: langchain-anthropic<2.0.0,>=1.4.4; extra == 'anthropic'
87
87
  Provides-Extra: baseten
@@ -123,7 +123,7 @@ Requires-Dist: langchain-perplexity<2.0.0,>=1.3.1; extra == 'perplexity'
123
123
  Provides-Extra: quickjs
124
124
  Requires-Dist: langchain-quickjs<0.2.0,>=0.1.3; extra == 'quickjs'
125
125
  Provides-Extra: runloop
126
- Requires-Dist: langchain-runloop>=0.0.5; extra == 'runloop'
126
+ Requires-Dist: langchain-runloop>=0.0.6; extra == 'runloop'
127
127
  Provides-Extra: together
128
128
  Requires-Dist: langchain-together<2.0.0,>=0.4.0; extra == 'together'
129
129
  Provides-Extra: vertex
@@ -156,7 +156,7 @@
156
156
  | DC1 | API Keys / Credentials | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `TAVILY_API_KEY`, `LANGSMITH_API_KEY`, `LANGGRAPH_API_KEY` | Critical | Process environment only; never written to disk by CLI code | N/A (in-memory) | Process lifetime | All — breach trigger |
157
157
  | DC2 | Conversation Messages | User prompts, LLM responses, tool args/results | High | SQLite (`~/.deepagents/*.db`) via LangGraph checkpointer | No (local file, unencrypted) | Unbounded (session files persist) | GDPR if personal data is discussed |
158
158
  | DC3 | System Prompt Content | `DA_SERVER_SYSTEM_PROMPT` env var; custom AGENTS.md contents | Medium | Process environment (transient); `~/.deepagents/{agent}/AGENTS.md` on disk | No | Config lifetime | None direct |
159
- | DC4 | MCP Trust Fingerprints | `mcp_trust.projects.*` in `config.toml` | Low | `~/.deepagents/config.toml` | No | Until revoked | None |
159
+ | DC4 | MCP Trust Fingerprints | `projects.*` in `mcp_trust.json` | Low | `~/.deepagents/.state/mcp_trust.json` | No | Until revoked | None |
160
160
  | DC5 | Offloaded Conversation History | Summarized + raw conversation messages written to sandbox backend | High | Sandbox filesystem at `/conversation_history/{thread_id}.md` | Depends on sandbox provider | Sandbox session lifetime | GDPR if personal data is discussed |
161
161
 
162
162
  ### Data Classification Details
@@ -134,6 +134,16 @@ and `/api/show`. See `_ollama_discovery_enabled` for accepted truthy/falsy
134
134
  values.
135
135
  """
136
136
 
137
+ RESTARTED_AFTER_UPDATE = "DEEPAGENTS_CODE_RESTARTED_AFTER_UPDATE"
138
+ """Internal sentinel recording the target version immediately before the
139
+ startup auto-update re-execs the process.
140
+
141
+ Not user-facing. The re-exec'd process consumes it and, if that same version
142
+ still reports as available (a no-op upgrade that did not change the running
143
+ version), skips auto-updating to break out of an otherwise endless
144
+ upgrade/restart loop. Set and read internally across `os.execv`.
145
+ """
146
+
137
147
  SERVER_ENV_PREFIX = "DEEPAGENTS_CODE_SERVER_"
138
148
  """Environment variable prefix used to pass CLI config to the server subprocess."""
139
149
 
@@ -180,7 +180,7 @@ class ServerConfig:
180
180
  """Existing sandbox ID to attach to; `None` creates a fresh sandbox."""
181
181
 
182
182
  sandbox_snapshot_name: str | None = None
183
- """Sandbox snapshot name to use or create. LangSmith-only; must be `None`
183
+ """Sandbox snapshot (langsmith) or blueprint (runloop) name; must be `None`
184
184
  when `sandbox_id` is set."""
185
185
 
186
186
  sandbox_setup: str | None = None
@@ -365,8 +365,8 @@ class ServerConfig:
365
365
  server subprocess for `ShellAllowListMiddleware`.
366
366
  sandbox_type: Sandbox type.
367
367
  sandbox_id: Existing sandbox ID to reuse.
368
- sandbox_snapshot_name: Sandbox snapshot name to use or create
369
- (langsmith only).
368
+ sandbox_snapshot_name: Snapshot (langsmith) or blueprint (runloop)
369
+ name to use or create.
370
370
  sandbox_setup: Path to setup script for the sandbox.
371
371
  enable_shell: Enable shell execution tools.
372
372
  enable_ask_user: Enable ask_user tool.
@@ -0,0 +1,287 @@
1
+ r"""Runtime patches over Textual internals, imported for side effect.
2
+
3
+ This module hosts two independent best-effort patches over private Textual
4
+ APIs. Each guards its own import/assignment and degrades to stock Textual
5
+ behavior (logging a warning) if the targeted internals move, so they have
6
+ separate lifecycles — do not delete the whole file when only one lands
7
+ upstream.
8
+
9
+ 1. Alt-modifier preservation on legacy `ESC + <byte>` sequences. Upstream
10
+ `XTermParser._sequence_to_key_events` drops the `alt` flag on the
11
+ tuple-branch fast path, so VSCode's `sendSequence` shift+enter binding
12
+ (which writes `\x1b\r` to the PTY) arrives as bare `enter` instead of
13
+ `alt+enter`. Tracked in Textualize/textual#6378. Remove this patch and
14
+ the Textual pin comment in `pyproject.toml` when that lands.
15
+
16
+ 2. Double-click word selection. Stock Textual selects the entire widget on
17
+ a click chain; these patches narrow a double-click (and double-click
18
+ drag) to word boundaries. No upstream issue tracks this yet, so it has
19
+ no removal criterion — it stays until Textual grows native word select.
20
+
21
+ Imported for side effect from `app.py` before any `App()` is created.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import logging
27
+ from inspect import isawaitable
28
+ from typing import TYPE_CHECKING
29
+
30
+ from rich.text import Text
31
+ from textual import __version__ as _textual_version
32
+ from textual.content import Content
33
+ from textual.geometry import Offset
34
+ from textual.selection import Selection
35
+
36
+ if TYPE_CHECKING:
37
+ from collections.abc import Iterable
38
+
39
+ from textual.events import Click, Event
40
+ from textual.screen import Screen
41
+ from textual.selection import SelectState
42
+ from textual.widget import Widget
43
+
44
+ logger = logging.getLogger(__name__)
45
+
46
+ _ESC_PREFIX_LEN = 2
47
+ _DOUBLE_CLICK_CHAIN = 2
48
+ _TRIPLE_CLICK_CHAIN = 3
49
+ _DEEPAGENTS_WORD_SELECT_ACTIVE = "_deepagents_word_select_active"
50
+
51
+ try:
52
+ from textual import events
53
+ from textual._ansi_sequences import (
54
+ ANSI_SEQUENCES_KEYS, # noqa: PLC2701
55
+ IGNORE_SEQUENCE, # noqa: PLC2701
56
+ )
57
+ from textual._xterm_parser import XTermParser # noqa: PLC2701
58
+
59
+ _original = XTermParser._sequence_to_key_events
60
+ except (ImportError, AttributeError) as exc: # pragma: no cover - defensive
61
+ logger.warning("Textual keyboard parser patch skipped: %s", exc)
62
+ else:
63
+
64
+ def _emit_alt(keys: tuple, character: str | None) -> Iterable[events.Key]:
65
+ for key in keys:
66
+ yield events.Key(f"alt+{key.value}", character)
67
+
68
+ def _sequence_to_key_events_with_alt(
69
+ self: XTermParser, sequence: str, alt: bool = False
70
+ ) -> Iterable[events.Key]:
71
+ # Fast path: \x1b<byte> on first pass. Short-circuits the ~100 ms
72
+ # escape-delay wait when both bytes arrive together. Semantic side
73
+ # effect: \x1b\x1b dispatches as `alt+escape` with no delay, matching
74
+ # crossterm and Node TTY.
75
+ if not alt and len(sequence) == _ESC_PREFIX_LEN and sequence[0] == "\x1b":
76
+ inner = ANSI_SEQUENCES_KEYS.get(sequence[1])
77
+ if inner is not IGNORE_SEQUENCE and isinstance(inner, tuple):
78
+ yield from _emit_alt(inner, None)
79
+ return
80
+ # Correctness fix (Textualize/textual#6378): preserve `alt` on the
81
+ # reissue path for single-byte tuple mappings.
82
+ if alt:
83
+ keys = ANSI_SEQUENCES_KEYS.get(sequence)
84
+ if keys is not IGNORE_SEQUENCE and isinstance(keys, tuple):
85
+ character = sequence if len(sequence) == 1 else None
86
+ yield from _emit_alt(keys, character)
87
+ return
88
+ yield from _original(self, sequence, alt=alt)
89
+
90
+ try:
91
+ XTermParser._sequence_to_key_events = _sequence_to_key_events_with_alt # ty: ignore[invalid-assignment]
92
+ except (AttributeError, TypeError) as exc: # pragma: no cover - defensive
93
+ logger.warning("Textual keyboard parser patch assignment rejected: %s", exc)
94
+
95
+
96
+ def _rendered_text(widget: Widget) -> str | None:
97
+ visual = widget._render() # match Textual's get_selection path
98
+ if isinstance(visual, (Content, Text)):
99
+ return str(visual)
100
+ return None
101
+
102
+
103
+ def _word_bounds(text: str, offset: Offset) -> tuple[Offset, Offset] | None:
104
+ lines = text.splitlines()
105
+ if not lines:
106
+ return None
107
+
108
+ y = min(max(offset.y, 0), len(lines) - 1)
109
+ line = lines[y]
110
+ if not line:
111
+ return None
112
+
113
+ x = min(max(offset.x, 0), len(line))
114
+ index = min(x, len(line) - 1)
115
+ if line[index].isspace():
116
+ # A click just past the final character (x == len(line)) lands on the
117
+ # virtual end-of-line position; snap back onto the trailing word so
118
+ # double-clicking after a word still selects it. Genuine whitespace
119
+ # clicks fall through and select nothing.
120
+ if x == len(line) and x > 0 and not line[x - 1].isspace():
121
+ index = x - 1
122
+ else:
123
+ return None
124
+
125
+ start = index
126
+ while start > 0 and not line[start - 1].isspace():
127
+ start -= 1
128
+
129
+ end = index + 1
130
+ while end < len(line) and not line[end].isspace():
131
+ end += 1
132
+
133
+ return Offset(start, y), Offset(end, y)
134
+
135
+
136
+ def _word_selection(widget: Widget, selection: Selection) -> Selection | None:
137
+ if selection.start is None or selection.end is None:
138
+ return None
139
+
140
+ text = _rendered_text(widget)
141
+ if text is None:
142
+ return None
143
+
144
+ start, end = selection.start, selection.end
145
+ # `Offset.transpose` is (y, x) — Textual's reading-order key. A backward
146
+ # drag leaves end before start in reading order; normalize so the word
147
+ # bounds below extend outward from the correct endpoints.
148
+ if end.transpose < start.transpose:
149
+ start, end = end, start
150
+
151
+ start_bounds = _word_bounds(text, start)
152
+ end_bounds = _word_bounds(text, end)
153
+ if start_bounds is None and end_bounds is None:
154
+ return None
155
+
156
+ return Selection(
157
+ start_bounds[0] if start_bounds is not None else start,
158
+ end_bounds[1] if end_bounds is not None else end,
159
+ )
160
+
161
+
162
+ def _select_word_at_click(widget: Widget, event: Click) -> bool:
163
+ offset = event.get_content_offset(widget)
164
+ if offset is None:
165
+ return False
166
+
167
+ text = _rendered_text(widget)
168
+ if text is None:
169
+ return False
170
+
171
+ bounds = _word_bounds(text, offset)
172
+ if bounds is None:
173
+ widget.screen.clear_selection()
174
+ return True
175
+
176
+ widget.screen.selections = {widget: Selection(*bounds)}
177
+ return True
178
+
179
+
180
+ try:
181
+ from textual import events as _events
182
+ from textual.screen import Screen as _Screen
183
+ from textual.widget import Widget as _Widget
184
+
185
+ _original_forward_event = _Screen._forward_event
186
+ _original_watch_select_state = _Screen._watch__select_state
187
+ _original_widget_on_click = _Widget._on_click
188
+ except (ImportError, AttributeError) as exc: # pragma: no cover - defensive
189
+ logger.warning(
190
+ "Textual word-selection patch skipped (textual %s): %s",
191
+ _textual_version,
192
+ exc,
193
+ )
194
+ else:
195
+
196
+ def _is_word_select_start(screen: Screen, event: Event) -> bool:
197
+ # Mirrors Textual's own click-chain detection (App._on_mouse_down),
198
+ # reading its private `_click_chain_last_*` bookkeeping to recognize
199
+ # the second press of a double-click before Textual increments the
200
+ # chain count. Re-verify these attribute names on every Textual bump.
201
+ if not isinstance(event, _events.MouseDown) or screen.app.mouse_captured:
202
+ return False
203
+
204
+ last_offset = getattr(screen.app, "_click_chain_last_offset", None)
205
+ last_time = getattr(screen.app, "_click_chain_last_time", None)
206
+ if last_offset != event.screen_offset or last_time is None:
207
+ return False
208
+
209
+ if event.time - last_time > screen.app.CLICK_CHAIN_TIME_THRESHOLD:
210
+ return False
211
+
212
+ select_widget, select_offset = screen.get_widget_and_offset_at(event.x, event.y)
213
+ return (
214
+ select_widget is not None
215
+ and select_widget.allow_select
216
+ and screen.allow_select
217
+ and screen.app.ALLOW_SELECT
218
+ and select_offset is not None
219
+ )
220
+
221
+ def _forward_event_with_word_select(self: Screen, event: Event) -> None:
222
+ if isinstance(event, _events.MouseDown):
223
+ setattr(
224
+ self,
225
+ _DEEPAGENTS_WORD_SELECT_ACTIVE,
226
+ _is_word_select_start(self, event),
227
+ )
228
+ try:
229
+ _original_forward_event(self, event)
230
+ finally:
231
+ if isinstance(event, _events.MouseUp):
232
+ setattr(self, _DEEPAGENTS_WORD_SELECT_ACTIVE, False)
233
+
234
+ async def _watch_select_state_with_word_select(
235
+ self: Screen,
236
+ select_state: SelectState | None,
237
+ ) -> None:
238
+ result = _original_watch_select_state(self, select_state)
239
+ # `_watch__select_state` is synchronous in the pinned Textual; the
240
+ # isawaitable guard tolerates a future release making it a coroutine
241
+ # without forcing a same-day patch update.
242
+ if isawaitable(result):
243
+ await result
244
+ if not getattr(self, _DEEPAGENTS_WORD_SELECT_ACTIVE, False):
245
+ return
246
+
247
+ selections = dict(self.selections)
248
+ changed = False
249
+ for widget, selection in selections.items():
250
+ word_selection = _word_selection(widget, selection)
251
+ if word_selection is None or word_selection == selection:
252
+ continue
253
+ selections[widget] = word_selection
254
+ changed = True
255
+
256
+ if changed:
257
+ self.selections = selections
258
+
259
+ async def _on_click_with_word_select(self: Widget, event: Click) -> None:
260
+ if (
261
+ event.widget is self
262
+ and self.allow_select
263
+ and self.screen.allow_select
264
+ and self.app.ALLOW_SELECT
265
+ ):
266
+ if event.chain == _DOUBLE_CLICK_CHAIN and _select_word_at_click(
267
+ self, event
268
+ ):
269
+ await self.broker_event("click", event)
270
+ return
271
+ if event.chain == _TRIPLE_CLICK_CHAIN:
272
+ self.text_select_all()
273
+ await self.broker_event("click", event)
274
+ return
275
+
276
+ await _original_widget_on_click(self, event)
277
+
278
+ try:
279
+ _Screen._forward_event = _forward_event_with_word_select # ty: ignore[invalid-assignment]
280
+ _Screen._watch__select_state = _watch_select_state_with_word_select # ty: ignore[invalid-assignment]
281
+ _Widget._on_click = _on_click_with_word_select # ty: ignore[invalid-assignment]
282
+ except (AttributeError, TypeError) as exc: # pragma: no cover - defensive
283
+ logger.warning(
284
+ "Textual word-selection patch assignment rejected (textual %s): %s",
285
+ _textual_version,
286
+ exc,
287
+ )
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Keep the `x-release-please-version` annotation — release-please uses it to
4
4
  # bump `__version__` in sync with `pyproject.toml` on every release PR.
5
- __version__ = "0.1.9" # x-release-please-version
5
+ __version__ = "0.1.11" # x-release-please-version
6
6
 
7
7
  DOCS_URL = "https://docs.langchain.com/oss/python/deepagents/code"
8
8
  """URL for `deepagents-code` documentation."""
@@ -1205,40 +1205,53 @@ def create_cli_agent(
1205
1205
  else settings.get_project_agents_dir()
1206
1206
  )
1207
1207
 
1208
+ def _subagent_cli_middleware(*, has_explicit_model: bool) -> list[AgentMiddleware]:
1209
+ middleware: list[AgentMiddleware] = []
1210
+ if not has_explicit_model:
1211
+ middleware.append(ConfigurableModelMiddleware())
1212
+ if restrictive_shell_allow_list is not None:
1213
+ middleware.append(ShellAllowListMiddleware(restrictive_shell_allow_list))
1214
+ return middleware
1215
+
1208
1216
  for subagent_meta in list_subagents(
1209
1217
  user_agents_dir=user_agents_dir,
1210
1218
  project_agents_dir=project_agents_dir,
1211
1219
  ):
1220
+ # Treat a falsy spec (`None` or `""`) as "no explicit model" so an empty
1221
+ # `model:` in subagent frontmatter inherits the runtime model rather than
1222
+ # being forwarded verbatim to `resolve_model("")`.
1223
+ model_spec = subagent_meta["model"]
1224
+ has_explicit_model = bool(model_spec)
1212
1225
  subagent: SubAgent = {
1213
1226
  "name": subagent_meta["name"],
1214
1227
  "description": subagent_meta["description"],
1215
1228
  "system_prompt": subagent_meta["system_prompt"],
1216
1229
  }
1217
- if subagent_meta["model"]:
1218
- subagent["model"] = subagent_meta["model"]
1219
- if restrictive_shell_allow_list is not None:
1220
- subagent["middleware"] = [
1221
- ShellAllowListMiddleware(restrictive_shell_allow_list)
1222
- ]
1230
+ if model_spec:
1231
+ subagent["model"] = model_spec
1232
+ subagent_middleware = _subagent_cli_middleware(
1233
+ has_explicit_model=has_explicit_model
1234
+ )
1235
+ if subagent_middleware:
1236
+ subagent["middleware"] = subagent_middleware
1223
1237
  custom_subagents.append(subagent)
1224
1238
 
1225
- if restrictive_shell_allow_list is not None:
1226
- from deepagents.middleware.subagents import (
1227
- GENERAL_PURPOSE_SUBAGENT,
1228
- SubAgent as RuntimeSubAgent,
1229
- )
1239
+ from deepagents.middleware.subagents import (
1240
+ GENERAL_PURPOSE_SUBAGENT,
1241
+ SubAgent as RuntimeSubAgent,
1242
+ )
1230
1243
 
1231
- if not any(
1232
- subagent["name"] == GENERAL_PURPOSE_SUBAGENT["name"]
1233
- for subagent in custom_subagents
1234
- ):
1235
- general_purpose_subagent: RuntimeSubAgent = {
1236
- "name": GENERAL_PURPOSE_SUBAGENT["name"],
1237
- "description": GENERAL_PURPOSE_SUBAGENT["description"],
1238
- "system_prompt": GENERAL_PURPOSE_SUBAGENT["system_prompt"],
1239
- "middleware": [ShellAllowListMiddleware(restrictive_shell_allow_list)],
1240
- }
1241
- custom_subagents.append(general_purpose_subagent)
1244
+ if not any(
1245
+ subagent["name"] == GENERAL_PURPOSE_SUBAGENT["name"]
1246
+ for subagent in custom_subagents
1247
+ ):
1248
+ general_purpose_subagent: RuntimeSubAgent = {
1249
+ "name": GENERAL_PURPOSE_SUBAGENT["name"],
1250
+ "description": GENERAL_PURPOSE_SUBAGENT["description"],
1251
+ "system_prompt": GENERAL_PURPOSE_SUBAGENT["system_prompt"],
1252
+ "middleware": _subagent_cli_middleware(has_explicit_model=False),
1253
+ }
1254
+ custom_subagents.append(general_purpose_subagent)
1242
1255
 
1243
1256
  # Build middleware stack based on enabled features
1244
1257
  agent_middleware = [