deepagents-cli 0.0.31__tar.gz → 0.0.32__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 (145) hide show
  1. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/CHANGELOG.md +11 -0
  2. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/PKG-INFO +4 -4
  3. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/README.md +2 -2
  4. deepagents_cli-0.0.32/deepagents_cli/_version.py +3 -0
  5. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/agent.py +62 -14
  6. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/app.py +69 -36
  7. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/main.py +21 -4
  8. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/non_interactive.py +4 -2
  9. deepagents_cli-0.0.32/deepagents_cli/output.py +69 -0
  10. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/sessions.py +31 -6
  11. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/skills/commands.py +145 -37
  12. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/ui.py +60 -52
  13. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/chat_input.py +18 -0
  14. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/welcome.py +22 -11
  15. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/pyproject.toml +2 -2
  16. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/scripts/install.sh +1 -1
  17. deepagents_cli-0.0.32/tests/unit_tests/skills/test_skills_json.py +154 -0
  18. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_agent.py +94 -0
  19. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_args.py +47 -0
  20. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_chat_input.py +41 -0
  21. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_compact.py +1 -4
  22. deepagents_cli-0.0.32/tests/unit_tests/test_output.py +62 -0
  23. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_sessions.py +112 -0
  24. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_version.py +0 -2
  25. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_welcome.py +105 -1
  26. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/uv.lock +20 -20
  27. deepagents_cli-0.0.31/deepagents_cli/_version.py +0 -3
  28. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/.gitignore +0 -0
  29. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/Makefile +0 -0
  30. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/__init__.py +0 -0
  31. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/__main__.py +0 -0
  32. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/app.tcss +0 -0
  33. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/ask_user.py +0 -0
  34. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/built_in_skills/__init__.py +0 -0
  35. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
  36. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
  37. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
  38. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/clipboard.py +0 -0
  39. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/config.py +0 -0
  40. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/default_agent_prompt.md +0 -0
  41. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/file_ops.py +0 -0
  42. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/hooks.py +0 -0
  43. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/input.py +0 -0
  44. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/integrations/__init__.py +0 -0
  45. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/integrations/daytona.py +0 -0
  46. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/integrations/langsmith.py +0 -0
  47. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/integrations/modal.py +0 -0
  48. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/integrations/runloop.py +0 -0
  49. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/integrations/sandbox_factory.py +0 -0
  50. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/integrations/sandbox_provider.py +0 -0
  51. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/local_context.py +0 -0
  52. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/mcp_tools.py +0 -0
  53. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/mcp_trust.py +0 -0
  54. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/media_utils.py +0 -0
  55. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/model_config.py +0 -0
  56. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/project_utils.py +0 -0
  57. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/py.typed +0 -0
  58. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/skills/__init__.py +0 -0
  59. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/skills/load.py +0 -0
  60. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/subagents.py +0 -0
  61. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/system_prompt.md +0 -0
  62. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/textual_adapter.py +0 -0
  63. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/tool_display.py +0 -0
  64. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/tools.py +0 -0
  65. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/unicode_security.py +0 -0
  66. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/update_check.py +0 -0
  67. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/__init__.py +0 -0
  68. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/_links.py +0 -0
  69. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/approval.py +0 -0
  70. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/ask_user.py +0 -0
  71. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/autocomplete.py +0 -0
  72. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/diff.py +0 -0
  73. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/history.py +0 -0
  74. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/loading.py +0 -0
  75. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/mcp_viewer.py +0 -0
  76. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/message_store.py +0 -0
  77. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/messages.py +0 -0
  78. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/model_selector.py +0 -0
  79. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/status.py +0 -0
  80. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/thread_selector.py +0 -0
  81. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/tool_renderers.py +0 -0
  82. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/deepagents_cli/widgets/tool_widgets.py +0 -0
  83. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/examples/skills/arxiv-search/SKILL.md +0 -0
  84. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/examples/skills/arxiv-search/arxiv_search.py +0 -0
  85. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/examples/skills/langgraph-docs/SKILL.md +0 -0
  86. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/examples/skills/skill-creator/SKILL.md +0 -0
  87. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
  88. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
  89. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/examples/skills/web-research/SKILL.md +0 -0
  90. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/images/cli.png +0 -0
  91. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/scripts/check_imports.py +0 -0
  92. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/README.md +0 -0
  93. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/integration_tests/__init__.py +0 -0
  94. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/integration_tests/benchmarks/__init__.py +0 -0
  95. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
  96. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/integration_tests/conftest.py +0 -0
  97. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/integration_tests/test_acp_mode.py +0 -0
  98. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/integration_tests/test_sandbox_factory.py +0 -0
  99. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/integration_tests/test_sandbox_operations.py +0 -0
  100. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/__init__.py +0 -0
  101. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/conftest.py +0 -0
  102. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/skills/__init__.py +0 -0
  103. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/skills/test_commands.py +0 -0
  104. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/skills/test_load.py +0 -0
  105. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_app.py +0 -0
  106. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_approval.py +0 -0
  107. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_ask_user.py +0 -0
  108. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_ask_user_middleware.py +0 -0
  109. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_autocomplete.py +0 -0
  110. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_charset.py +0 -0
  111. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_compact_tool.py +0 -0
  112. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_config.py +0 -0
  113. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_end_to_end.py +0 -0
  114. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_exception_handling.py +0 -0
  115. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_file_ops.py +0 -0
  116. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_history.py +0 -0
  117. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_hooks.py +0 -0
  118. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_imports.py +0 -0
  119. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_input_parsing.py +0 -0
  120. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_local_context.py +0 -0
  121. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_main.py +0 -0
  122. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_main_acp_mode.py +0 -0
  123. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_main_args.py +0 -0
  124. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_mcp_tools.py +0 -0
  125. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_mcp_trust.py +0 -0
  126. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_mcp_viewer.py +0 -0
  127. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_media_utils.py +0 -0
  128. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_message_store.py +0 -0
  129. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_messages.py +0 -0
  130. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_model_config.py +0 -0
  131. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_model_selector.py +0 -0
  132. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_model_switch.py +0 -0
  133. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_non_interactive.py +0 -0
  134. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_reload.py +0 -0
  135. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_shell_allow_list.py +0 -0
  136. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_status.py +0 -0
  137. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_subagents.py +0 -0
  138. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_textual_adapter.py +0 -0
  139. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_thread_selector.py +0 -0
  140. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_token_tracker.py +0 -0
  141. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_ui.py +0 -0
  142. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_unicode_security.py +0 -0
  143. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/test_update_check.py +0 -0
  144. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/tools/__init__.py +0 -0
  145. {deepagents_cli-0.0.31 → deepagents_cli-0.0.32}/tests/unit_tests/tools/test_fetch_url.py +0 -0
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.32](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.31...deepagents-cli==0.0.32) (2026-03-11)
4
+
5
+ ### Features
6
+
7
+ * Add token breakdown to `/tokens` and simplify `/compact` messages ([#1782](https://github.com/langchain-ai/deepagents/issues/1782)) ([2f37bff](https://github.com/langchain-ai/deepagents/commit/2f37bffa9d7a9ced6945abe4ab6bc3409bfb97b1))
8
+ * `--json` flag for machine-readable output ([#1768](https://github.com/langchain-ai/deepagents/issues/1768)) ([6f62496](https://github.com/langchain-ai/deepagents/commit/6f62496bb699dfa6086ee1850b83f38d3b1242fa))
9
+
10
+ ### Bug Fixes
11
+
12
+ * Work around VS Code 1.110 space key regression ([#1748](https://github.com/langchain-ai/deepagents/issues/1748)) ([f5fe431](https://github.com/langchain-ai/deepagents/commit/f5fe4315143bf5b636cf42fc98cbfe3d99918cfc))
13
+
3
14
  ## [0.0.31](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.30...deepagents-cli==0.0.31) (2026-03-09)
4
15
 
5
16
  ### Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepagents-cli
3
- Version: 0.0.31
3
+ Version: 0.0.32
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 @@ Requires-Python: <4.0,>=3.11
26
26
  Requires-Dist: aiosqlite<1.0.0,>=0.19.0
27
27
  Requires-Dist: daytona<1.0.0,>=0.113.0
28
28
  Requires-Dist: deepagents-acp>=0.0.4
29
- Requires-Dist: deepagents==0.4.7
29
+ Requires-Dist: deepagents==0.4.10
30
30
  Requires-Dist: langchain-mcp-adapters<1.0.0,>=0.2.0
31
31
  Requires-Dist: langchain-openai<2.0.0,>=1.1.8
32
32
  Requires-Dist: langchain<2.0.0,>=1.2.10
@@ -114,12 +114,12 @@ Description-Content-Type: text/markdown
114
114
  ## Quick Install
115
115
 
116
116
  ```bash
117
- curl -LsSf https://raw.githubusercontent.com/langchain-ai/deepagents/main/scripts/install.sh | bash
117
+ curl -LsSf https://raw.githubusercontent.com/langchain-ai/deepagents/main/libs/cli/scripts/install.sh | bash
118
118
  ```
119
119
 
120
120
  ```bash
121
121
  # With model provider extras (OpenAI is included by default)
122
- DEEPAGENTS_EXTRAS="anthropic,groq" curl -LsSf https://raw.githubusercontent.com/langchain-ai/deepagents/main/scripts/install.sh | bash
122
+ DEEPAGENTS_EXTRAS="anthropic,groq" curl -LsSf https://raw.githubusercontent.com/langchain-ai/deepagents/main/libs/cli/scripts/install.sh | bash
123
123
  ```
124
124
 
125
125
  Or install directly with `uv`:
@@ -12,12 +12,12 @@
12
12
  ## Quick Install
13
13
 
14
14
  ```bash
15
- curl -LsSf https://raw.githubusercontent.com/langchain-ai/deepagents/main/scripts/install.sh | bash
15
+ curl -LsSf https://raw.githubusercontent.com/langchain-ai/deepagents/main/libs/cli/scripts/install.sh | bash
16
16
  ```
17
17
 
18
18
  ```bash
19
19
  # With model provider extras (OpenAI is included by default)
20
- DEEPAGENTS_EXTRAS="anthropic,groq" curl -LsSf https://raw.githubusercontent.com/langchain-ai/deepagents/main/scripts/install.sh | bash
20
+ DEEPAGENTS_EXTRAS="anthropic,groq" curl -LsSf https://raw.githubusercontent.com/langchain-ai/deepagents/main/libs/cli/scripts/install.sh | bash
21
21
  ```
22
22
 
23
23
  Or install directly with `uv`:
@@ -0,0 +1,3 @@
1
+ """Version information for `deepagents-cli`."""
2
+
3
+ __version__ = "0.0.32" # x-release-please-version
@@ -31,6 +31,7 @@ if TYPE_CHECKING:
31
31
  from langgraph.runtime import Runtime
32
32
 
33
33
  from deepagents_cli.mcp_tools import MCPServerInfo
34
+ from deepagents_cli.output import OutputFormat
34
35
 
35
36
  from deepagents_cli.config import (
36
37
  COLORS,
@@ -61,11 +62,20 @@ REQUIRE_COMPACT_TOOL_APPROVAL: bool = True
61
62
  """When `True`, `compact_conversation` requires HITL approval like other gated tools."""
62
63
 
63
64
 
64
- def list_agents() -> None:
65
- """List all available agents."""
65
+ def list_agents(*, output_format: OutputFormat = "text") -> None:
66
+ """List all available agents.
67
+
68
+ Args:
69
+ output_format: Output format — `'text'` (Rich) or `'json'`.
70
+ """
66
71
  agents_dir = settings.user_deepagents_dir
67
72
 
68
73
  if not agents_dir.exists() or not any(agents_dir.iterdir()):
74
+ if output_format == "json":
75
+ from deepagents_cli.output import write_json
76
+
77
+ write_json("list", [])
78
+ return
69
79
  console.print("[yellow]No agents found.[/yellow]")
70
80
  console.print(
71
81
  "[dim]Agents will be created in ~/.deepagents/ "
@@ -74,6 +84,24 @@ def list_agents() -> None:
74
84
  )
75
85
  return
76
86
 
87
+ if output_format == "json":
88
+ from deepagents_cli.output import write_json
89
+
90
+ agents = []
91
+ for agent_path in sorted(agents_dir.iterdir()):
92
+ if agent_path.is_dir():
93
+ agent_name = agent_path.name
94
+ agents.append(
95
+ {
96
+ "name": agent_name,
97
+ "path": str(agent_path),
98
+ "has_agents_md": (agent_path / "AGENTS.md").exists(),
99
+ "is_default": agent_name == DEFAULT_AGENT_NAME,
100
+ }
101
+ )
102
+ write_json("list", agents)
103
+ return
104
+
77
105
  console.print("\n[bold]Available Agents:[/bold]\n", style=COLORS["primary"])
78
106
 
79
107
  for agent_path in sorted(agents_dir.iterdir()):
@@ -101,8 +129,19 @@ def list_agents() -> None:
101
129
  console.print()
102
130
 
103
131
 
104
- def reset_agent(agent_name: str, source_agent: str | None = None) -> None:
105
- """Reset an agent to default or copy from another agent."""
132
+ def reset_agent(
133
+ agent_name: str,
134
+ source_agent: str | None = None,
135
+ *,
136
+ output_format: OutputFormat = "text",
137
+ ) -> None:
138
+ """Reset an agent to default or copy from another agent.
139
+
140
+ Args:
141
+ agent_name: Name of the agent to reset.
142
+ source_agent: Copy AGENTS.md from this agent instead of default.
143
+ output_format: Output format — `'text'` (Rich) or `'json'`.
144
+ """
106
145
  agents_dir = settings.user_deepagents_dir
107
146
  agent_dir = agents_dir / agent_name
108
147
 
@@ -125,14 +164,28 @@ def reset_agent(agent_name: str, source_agent: str | None = None) -> None:
125
164
 
126
165
  if agent_dir.exists():
127
166
  shutil.rmtree(agent_dir)
128
- console.print(
129
- f"Removed existing agent directory: {agent_dir}", style=COLORS["tool"]
130
- )
167
+ if output_format != "json":
168
+ console.print(
169
+ f"Removed existing agent directory: {agent_dir}", style=COLORS["tool"]
170
+ )
131
171
 
132
172
  agent_dir.mkdir(parents=True, exist_ok=True)
133
173
  agent_md = agent_dir / "AGENTS.md"
134
174
  agent_md.write_text(source_content)
135
175
 
176
+ if output_format == "json":
177
+ from deepagents_cli.output import write_json
178
+
179
+ write_json(
180
+ "reset",
181
+ {
182
+ "agent": agent_name,
183
+ "reset_to": source_agent or "default",
184
+ "path": str(agent_dir),
185
+ },
186
+ )
187
+ return
188
+
136
189
  console.print(
137
190
  f"{get_glyphs().checkmark} Agent '{agent_name}' reset to {action_desc}",
138
191
  style=COLORS["primary"],
@@ -713,15 +766,10 @@ def create_cli_agent(
713
766
 
714
767
  model = resolve_model(model)
715
768
 
716
- from deepagents.middleware.summarization import (
717
- SummarizationToolMiddleware,
718
- create_summarization_middleware,
719
- )
769
+ from deepagents.middleware.summarization import create_summarization_tool_middleware
720
770
 
721
771
  agent_middleware.append(
722
- SummarizationToolMiddleware(
723
- create_summarization_middleware(model, composite_backend)
724
- )
772
+ create_summarization_tool_middleware(model, composite_backend)
725
773
  )
726
774
 
727
775
  # Create the agent
@@ -148,10 +148,7 @@ def _format_compact_limit(
148
148
  percent = float(keep_value) * 100
149
149
  if context_limit is not None:
150
150
  token_limit = max(1, int(context_limit * float(keep_value)))
151
- return (
152
- f"{format_token_count(token_limit)} tokens "
153
- f"({percent:.0f}% of {format_token_count(context_limit)})"
154
- )
151
+ return f"{format_token_count(token_limit)} tokens"
155
152
  return f"{percent:.0f}% of context window"
156
153
 
157
154
  return "current retention threshold"
@@ -1588,19 +1585,25 @@ class DeepAgentsApp(App):
1588
1585
  if context_limit is not None:
1589
1586
  limit_str = format_token_count(context_limit)
1590
1587
  pct = count / context_limit * 100
1591
- usage = (
1592
- f"{formatted} / {limit_str} tokens "
1593
- f"({pct:.0f}%, includes system prompt + tools)"
1594
- )
1588
+ usage = f"{formatted} / {limit_str} tokens ({pct:.0f}%)"
1595
1589
  else:
1596
- usage = f"{formatted} tokens used (includes system prompt + tools)"
1590
+ usage = f"{formatted} tokens used"
1591
+
1592
+ msg = f"{usage} \u00b7 {model_name}" if model_name else usage
1597
1593
 
1598
- msg = f"{usage} · {model_name}" if model_name else usage
1594
+ conv_tokens = await self._get_conversation_token_count()
1595
+ if conv_tokens is not None:
1596
+ overhead = max(0, count - conv_tokens)
1597
+ overhead_str = format_token_count(overhead)
1598
+ conv_str = format_token_count(conv_tokens)
1599
1599
 
1600
- # Append conversation-only token count when available
1601
- conv_line = await self._get_conversation_token_line()
1602
- if conv_line:
1603
- msg = f"{msg}\n{conv_line}"
1600
+ overhead_unit = " tokens" if overhead < 1000 else "" # noqa: PLR2004 # not bothersome, cosmetic
1601
+ conv_unit = " tokens" if conv_tokens < 1000 else "" # noqa: PLR2004 # not bothersome, cosmetic
1602
+
1603
+ msg += (
1604
+ f"\n\u251c System prompt + tools: ~{overhead_str}{overhead_unit} (fixed)" # noqa: E501
1605
+ f"\n\u2514 Conversation: ~{conv_str}{conv_unit}"
1606
+ )
1604
1607
 
1605
1608
  await self._mount_message(AppMessage(msg))
1606
1609
  else:
@@ -1610,7 +1613,7 @@ class DeepAgentsApp(App):
1610
1613
  parts: list[str] = ["No token usage yet"]
1611
1614
  if context_limit is not None:
1612
1615
  limit_str = format_token_count(context_limit)
1613
- parts.append(f"{limit_str} context window")
1616
+ parts.append(f"{limit_str} token context window")
1614
1617
  if model_name:
1615
1618
  parts.append(model_name)
1616
1619
 
@@ -1723,12 +1726,11 @@ class DeepAgentsApp(App):
1723
1726
 
1724
1727
  self.call_after_refresh(_scroll_after_command)
1725
1728
 
1726
- async def _get_conversation_token_line(self) -> str | None:
1727
- """Return a short string with the conversation-only token count.
1729
+ async def _get_conversation_token_count(self) -> int | None:
1730
+ """Return the approximate conversation-only token count.
1728
1731
 
1729
1732
  Returns:
1730
- Formatted line like `"Conversation only: ~18 tokens"`, or
1731
- `None` if state is unavailable.
1733
+ Token count as an integer, or `None` if state is unavailable.
1732
1734
  """
1733
1735
  if not self._agent:
1734
1736
  return None
@@ -1746,9 +1748,38 @@ class DeepAgentsApp(App):
1746
1748
  messages = state.values.get("messages", [])
1747
1749
  if not messages:
1748
1750
  return None
1749
- conv_tokens = count_tokens_approximately(messages)
1750
- return f"Conversation only: ~{format_token_count(conv_tokens)} tokens"
1751
- except Exception: # noqa: BLE001
1751
+ return count_tokens_approximately(messages)
1752
+ except Exception: # best-effort for /tokens display
1753
+ logger.debug("Failed to retrieve conversation token count", exc_info=True)
1754
+ return None
1755
+
1756
+ def _resolve_compact_budget_str(self) -> str | None:
1757
+ """Resolve the compaction retention budget as a human-readable string.
1758
+
1759
+ Instantiates a model and computes summarization defaults, so this is
1760
+ not a trivial accessor.
1761
+
1762
+ Returns:
1763
+ A string like `"20.0K (10% of 200.0K)"` or
1764
+ `"last 6 messages"`, or `None` if the budget cannot be determined.
1765
+ """
1766
+ try:
1767
+ from deepagents.middleware.summarization import (
1768
+ compute_summarization_defaults,
1769
+ )
1770
+
1771
+ model_spec = f"{settings.model_provider}:{settings.model_name}"
1772
+ result = create_model(
1773
+ model_spec,
1774
+ profile_overrides=self._profile_override,
1775
+ )
1776
+ defaults = compute_summarization_defaults(result.model)
1777
+ return _format_compact_limit(
1778
+ defaults["keep"],
1779
+ settings.model_context_limit,
1780
+ )
1781
+ except Exception: # best-effort for /tokens display
1782
+ logger.debug("Failed to compute compaction budget string", exc_info=True)
1752
1783
  return None
1753
1784
 
1754
1785
  async def _handle_compact(self) -> None:
@@ -1760,9 +1791,9 @@ class DeepAgentsApp(App):
1760
1791
  instead of the full history.
1761
1792
 
1762
1793
  Compaction is a no-op when the conversation's total token count is
1763
- within the `keep` budget (by default 10% of the model's
1764
- `max_input_tokens`). Until that threshold is exceeded the user sees
1765
- "Nothing to compact yet" plus the active compact limit.
1794
+ within the `keep` budget. Until that threshold is exceeded the user
1795
+ sees "Nothing to compact" with the retention budget and a pointer to
1796
+ `/tokens` for a full breakdown.
1766
1797
  """
1767
1798
  if not self._agent or not self._lc_thread_id or not self._backend:
1768
1799
  await self._mount_message(
@@ -1876,27 +1907,29 @@ class DeepAgentsApp(App):
1876
1907
  and context_limit is not None
1877
1908
  and total_context > context_limit
1878
1909
  ):
1879
- # Case A: overhead-dominated — total context exceeds
1880
- # limit but conversation itself is small
1910
+ # Case A: total context exceeds model limit but
1911
+ # conversation is within keep budget — excess is
1912
+ # system prompt + tool overhead that compaction
1913
+ # cannot reduce
1881
1914
  total_str = format_token_count(total_context)
1882
1915
  await self._mount_message(
1883
1916
  AppMessage(
1884
1917
  f"Nothing to compact \u2014 conversation is only "
1885
- f"~{conv_str} tokens.\n"
1886
- f"Total context ({total_str}) is mostly system "
1887
- f"prompt and tool overhead, which compaction "
1888
- f"cannot reduce.\n"
1889
- f"Retention budget: {compact_limit}"
1918
+ f"~{conv_str} tokens.\n\n"
1919
+ f"Total context ({total_str} tokens) is mostly "
1920
+ f"system prompt and tool overhead, which "
1921
+ f"compaction cannot reduce.\n\n"
1922
+ f"Use /tokens for a full breakdown."
1890
1923
  )
1891
1924
  )
1892
1925
  else:
1893
1926
  # Case B: genuinely within budget
1894
1927
  await self._mount_message(
1895
1928
  AppMessage(
1896
- "Nothing to compact yet \u2014 conversation is "
1897
- "within the retention budget.\n"
1898
- f"Conversation: ~{conv_str} tokens \u00b7 "
1899
- f"Retention budget: {compact_limit}"
1929
+ f"Nothing to compact \u2014 conversation "
1930
+ f"(~{conv_str} tokens) is within the "
1931
+ f"retention budget ({compact_limit}).\n\n"
1932
+ f"Use /tokens for a full breakdown."
1900
1933
  )
1901
1934
  )
1902
1935
  return
@@ -141,6 +141,7 @@ def parse_args() -> argparse.Namespace:
141
141
  Returns:
142
142
  Parsed arguments namespace.
143
143
  """
144
+ from deepagents_cli.output import add_json_output_arg
144
145
  from deepagents_cli.skills import setup_skills_parser
145
146
  from deepagents_cli.ui import (
146
147
  build_help_parent,
@@ -226,6 +227,7 @@ def parse_args() -> argparse.Namespace:
226
227
  add_help=False,
227
228
  parents=help_parent(show_list_help),
228
229
  )
230
+ add_json_output_arg(subparsers.choices["list"])
229
231
 
230
232
  reset_parser = subparsers.add_parser(
231
233
  "reset",
@@ -233,12 +235,17 @@ def parse_args() -> argparse.Namespace:
233
235
  add_help=False,
234
236
  parents=help_parent(show_reset_help),
235
237
  )
238
+ add_json_output_arg(reset_parser)
236
239
  reset_parser.add_argument("--agent", required=True, help="Name of agent to reset")
237
240
  reset_parser.add_argument(
238
241
  "--target", dest="source_agent", help="Copy prompt from another agent"
239
242
  )
240
243
 
241
- setup_skills_parser(subparsers, make_help_action=_make_help_action)
244
+ setup_skills_parser(
245
+ subparsers,
246
+ make_help_action=_make_help_action,
247
+ add_output_args=add_json_output_arg,
248
+ )
242
249
 
243
250
  threads_parser = subparsers.add_parser(
244
251
  "threads",
@@ -246,6 +253,7 @@ def parse_args() -> argparse.Namespace:
246
253
  add_help=False,
247
254
  parents=help_parent(show_threads_help),
248
255
  )
256
+ add_json_output_arg(threads_parser)
249
257
  threads_sub = threads_parser.add_subparsers(dest="threads_command")
250
258
 
251
259
  threads_list = threads_sub.add_parser(
@@ -255,6 +263,7 @@ def parse_args() -> argparse.Namespace:
255
263
  add_help=False,
256
264
  parents=help_parent(show_threads_list_help),
257
265
  )
266
+ add_json_output_arg(threads_list)
258
267
  threads_list.add_argument(
259
268
  "--agent", default=None, help="Filter by agent name (default: show all)"
260
269
  )
@@ -296,6 +305,7 @@ def parse_args() -> argparse.Namespace:
296
305
  add_help=False,
297
306
  parents=help_parent(show_threads_delete_help),
298
307
  )
308
+ add_json_output_arg(threads_delete)
299
309
  threads_delete.add_argument("thread_id", help="Thread ID to delete")
300
310
 
301
311
  # Default interactive mode — argument order here determines the
@@ -395,6 +405,8 @@ def parse_args() -> argparse.Namespace:
395
405
  "instead of streaming token-by-token. Requires -n or piped stdin.",
396
406
  )
397
407
 
408
+ add_json_output_arg(parser, default="text")
409
+
398
410
  parser.add_argument(
399
411
  "--auto-approve",
400
412
  action="store_true",
@@ -1204,6 +1216,8 @@ def cli_main() -> None:
1204
1216
  sys.exit(1)
1205
1217
  sys.exit(0)
1206
1218
 
1219
+ output_format = getattr(args, "output_format", "text")
1220
+
1207
1221
  if args.command == "help":
1208
1222
  from deepagents_cli.ui import show_help
1209
1223
 
@@ -1211,11 +1225,11 @@ def cli_main() -> None:
1211
1225
  elif args.command == "list":
1212
1226
  from deepagents_cli.agent import list_agents
1213
1227
 
1214
- list_agents()
1228
+ list_agents(output_format=output_format)
1215
1229
  elif args.command == "reset":
1216
1230
  from deepagents_cli.agent import reset_agent
1217
1231
 
1218
- reset_agent(args.agent, args.source_agent)
1232
+ reset_agent(args.agent, args.source_agent, output_format=output_format)
1219
1233
  elif args.command == "skills":
1220
1234
  from deepagents_cli.skills import execute_skills_command
1221
1235
 
@@ -1238,10 +1252,13 @@ def cli_main() -> None:
1238
1252
  branch=getattr(args, "branch", None),
1239
1253
  verbose=getattr(args, "verbose", False),
1240
1254
  relative=getattr(args, "relative", None),
1255
+ output_format=output_format,
1241
1256
  )
1242
1257
  )
1243
1258
  elif args.threads_command == "delete":
1244
- asyncio.run(delete_thread_command(args.thread_id))
1259
+ asyncio.run(
1260
+ delete_thread_command(args.thread_id, output_format=output_format)
1261
+ )
1245
1262
  else:
1246
1263
  # No subcommand provided, show threads help screen
1247
1264
  show_threads_help()
@@ -773,10 +773,9 @@ async def run_non_interactive(
773
773
  thread_url_lookup: ThreadUrlLookupState | None = None
774
774
  if not quiet:
775
775
  thread_url_lookup = _start_langsmith_thread_url_lookup(thread_id)
776
- console.print("[dim]Running task non-interactively...[/dim]")
776
+ console.print("[dim]Running task non-interactively...[/dim]", highlight=False)
777
777
  header = _build_non_interactive_header(assistant_id, thread_id)
778
778
  console.print(header)
779
- console.print()
780
779
 
781
780
  sandbox_backend = None
782
781
  exit_stack = contextlib.ExitStack()
@@ -869,6 +868,9 @@ async def run_non_interactive(
869
868
  assistant_id=assistant_id, backend=composite_backend
870
869
  )
871
870
 
871
+ if not quiet:
872
+ console.print()
873
+
872
874
  await _run_agent_loop(
873
875
  agent,
874
876
  message,
@@ -0,0 +1,69 @@
1
+ """Machine-readable JSON output helpers for CLI subcommands.
2
+
3
+ This module deliberately stays stdlib-only so it can be imported from CLI
4
+ startup paths without pulling in unnecessary dependency trees.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import argparse
10
+ import json
11
+ import sys
12
+ from typing import Literal
13
+
14
+ OutputFormat = Literal["text", "json"]
15
+ """Accepted internal output modes for CLI subcommands."""
16
+
17
+
18
+ def add_json_output_arg(
19
+ parser: argparse.ArgumentParser, *, default: OutputFormat | None = None
20
+ ) -> None:
21
+ """Add a `--json` flag to an argparse parser.
22
+
23
+ Args:
24
+ parser: Parser to update.
25
+ default: Default output format for this parser.
26
+
27
+ Pass `None` for subparsers so parent parser values are preserved.
28
+ """
29
+ if default is None:
30
+ parser.add_argument(
31
+ "--json",
32
+ dest="output_format",
33
+ action="store_const",
34
+ const="json",
35
+ default=argparse.SUPPRESS,
36
+ help="Emit machine-readable JSON for this command",
37
+ )
38
+ else:
39
+ parser.add_argument(
40
+ "--json",
41
+ dest="output_format",
42
+ action="store_const",
43
+ const="json",
44
+ default=default,
45
+ help="Emit machine-readable JSON for this command",
46
+ )
47
+
48
+
49
+ def write_json(command: str, data: list | dict) -> None:
50
+ """Write a JSON envelope to stdout and flush.
51
+
52
+ The envelope is a single-line JSON object with a stable schema:
53
+
54
+ ```json
55
+ {"schema_version": 1, "command": "...", "data": ...}
56
+ ```
57
+
58
+ Args:
59
+ command: Self-documenting command name (e.g. `'list'`,
60
+ `'threads list'`).
61
+ data: Payload — typically a list for listing commands or a dict
62
+ for action/info commands.
63
+
64
+ `default=str` is used so that `Path` and `datetime` objects
65
+ serialize without error.
66
+ """
67
+ envelope = {"schema_version": 1, "command": command, "data": data}
68
+ sys.stdout.write(json.dumps(envelope, default=str) + "\n")
69
+ sys.stdout.flush()
@@ -18,6 +18,8 @@ if TYPE_CHECKING:
18
18
  from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
19
19
  from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
20
20
 
21
+ from deepagents_cli.output import OutputFormat
22
+
21
23
  logger = logging.getLogger(__name__)
22
24
 
23
25
  _aiosqlite_patched = False
@@ -964,6 +966,8 @@ async def list_threads_command(
964
966
  branch: str | None = None,
965
967
  verbose: bool = False,
966
968
  relative: bool | None = None,
969
+ *,
970
+ output_format: OutputFormat = "text",
967
971
  ) -> None:
968
972
  """CLI handler for `deepagents threads list`.
969
973
 
@@ -986,10 +990,8 @@ async def list_threads_command(
986
990
  relative: Show timestamps as relative time (e.g., '5m ago').
987
991
 
988
992
  When `None`, reads from config (`~/.deepagents/config.toml`).
993
+ output_format: Output format — `'text'` (Rich) or `'json'`.
989
994
  """
990
- from rich.table import Table
991
-
992
- from deepagents_cli.config import COLORS, console
993
995
  from deepagents_cli.model_config import (
994
996
  load_thread_relative_time,
995
997
  load_thread_sort_order,
@@ -1018,6 +1020,16 @@ async def list_threads_command(
1018
1020
  threads, include_message_count=False, include_initial_prompt=True
1019
1021
  )
1020
1022
 
1023
+ if output_format == "json":
1024
+ from deepagents_cli.output import write_json
1025
+
1026
+ write_json("threads list", list(threads))
1027
+ return
1028
+
1029
+ from rich.table import Table
1030
+
1031
+ from deepagents_cli.config import COLORS, console
1032
+
1021
1033
  if not threads:
1022
1034
  filters = []
1023
1035
  if agent_name:
@@ -1090,12 +1102,25 @@ async def list_threads_command(
1090
1102
  console.print()
1091
1103
 
1092
1104
 
1093
- async def delete_thread_command(thread_id: str) -> None:
1094
- """CLI handler for: deepagents threads delete."""
1095
- from deepagents_cli.config import console
1105
+ async def delete_thread_command(
1106
+ thread_id: str, *, output_format: OutputFormat = "text"
1107
+ ) -> None:
1108
+ """CLI handler for: deepagents threads delete.
1096
1109
 
1110
+ Args:
1111
+ thread_id: ID of the thread to delete.
1112
+ output_format: Output format — `'text'` (Rich) or `'json'`.
1113
+ """
1097
1114
  deleted = await delete_thread(thread_id)
1098
1115
 
1116
+ if output_format == "json":
1117
+ from deepagents_cli.output import write_json
1118
+
1119
+ write_json("threads delete", {"thread_id": thread_id, "deleted": deleted})
1120
+ return
1121
+
1122
+ from deepagents_cli.config import console
1123
+
1099
1124
  if deleted:
1100
1125
  console.print(f"[green]Thread '{thread_id}' deleted.[/green]")
1101
1126
  else: