langchain-agentx-cli 0.3.0__tar.gz → 0.3.2__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 (141) hide show
  1. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/PKG-INFO +2 -2
  2. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/__init__.py +1 -1
  3. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/app.py +18 -1
  4. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/bridge/session_bridge.py +12 -9
  5. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/cli.py +21 -4
  6. langchain_agentx_cli-0.3.2/langchain_agentx_cli/commands/builtin/compact.py +74 -0
  7. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/session_factory.py +32 -10
  8. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tools/registry.py +1 -2
  9. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/__init__.py +1 -3
  10. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/base.py +2 -1
  11. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/bash.py +35 -2
  12. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/message_list.py +17 -0
  13. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/permission_inline.py +25 -27
  14. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/permission_keybindings.py +6 -16
  15. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/agent/widget.py +18 -0
  16. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/base.py +45 -12
  17. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/bash/widget.py +11 -4
  18. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/batch_edit/widget.py +11 -6
  19. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/edit/widget.py +4 -3
  20. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/glob/widget.py +5 -4
  21. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/grep/widget.py +5 -4
  22. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/helpers.py +12 -3
  23. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/read/widget.py +7 -4
  24. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/skill/widget.py +11 -8
  25. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/webfetch/widget.py +6 -5
  26. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/websearch/widget.py +7 -6
  27. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/write/widget.py +5 -4
  28. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/PKG-INFO +2 -2
  29. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/SOURCES.txt +0 -1
  30. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/requires.txt +1 -1
  31. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/pyproject.toml +2 -2
  32. langchain_agentx_cli-0.3.0/langchain_agentx_cli/commands/builtin/compact.py +0 -44
  33. langchain_agentx_cli-0.3.0/langchain_agentx_cli/tui/permissions/inject.py +0 -57
  34. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/LICENSE +0 -0
  35. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/README.md +0 -0
  36. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/__main__.py +0 -0
  37. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/bootstrap.py +0 -0
  38. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/bridge/__init__.py +0 -0
  39. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/__init__.py +0 -0
  40. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/__init__.py +0 -0
  41. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/clear.py +0 -0
  42. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/help.py +0 -0
  43. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/model.py +0 -0
  44. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/quit.py +0 -0
  45. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/theme.py +0 -0
  46. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/parser.py +0 -0
  47. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/providers/__init__.py +0 -0
  48. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/providers/sdk_commands.py +0 -0
  49. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/registry.py +0 -0
  50. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/completion/__init__.py +0 -0
  51. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/completion/base.py +0 -0
  52. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/completion/command_source.py +0 -0
  53. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/completion/history_source.py +0 -0
  54. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/config.py +0 -0
  55. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/history/__init__.py +0 -0
  56. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/history/store.py +0 -0
  57. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/keybindings/__init__.py +0 -0
  58. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/keybindings/bindings.py +0 -0
  59. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/llm_config.py +0 -0
  60. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/observation/__init__.py +0 -0
  61. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/observation/config.py +0 -0
  62. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/observation/observer.py +0 -0
  63. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/permissions/__init__.py +0 -0
  64. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/permissions/factory.py +0 -0
  65. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/permissions/policy.py +0 -0
  66. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/prompts/__init__.py +0 -0
  67. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/prompts/assembler.py +0 -0
  68. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/prompts/sections.py +0 -0
  69. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/prompts/system_prompt.py +0 -0
  70. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/screens/__init__.py +0 -0
  71. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/screens/repl.py +0 -0
  72. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/session_options.py +0 -0
  73. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/state/__init__.py +0 -0
  74. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/state/task_store.py +0 -0
  75. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/__init__.py +0 -0
  76. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/colors.py +0 -0
  77. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/detection.py +0 -0
  78. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/manager.py +0 -0
  79. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/settings.py +0 -0
  80. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/system_theme.py +0 -0
  81. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/themes.py +0 -0
  82. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/watcher.py +0 -0
  83. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tools/__init__.py +0 -0
  84. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/__init__.py +0 -0
  85. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/clipboard.py +0 -0
  86. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/message_selection.py +0 -0
  87. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/cache.py +0 -0
  88. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/component_manager.py +0 -0
  89. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/config.py +0 -0
  90. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/consumer.py +0 -0
  91. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/dialog.py +0 -0
  92. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/models.py +0 -0
  93. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/__init__.py +0 -0
  94. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/fallback.py +0 -0
  95. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/file.py +0 -0
  96. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/queue.py +0 -0
  97. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/safe_screen.py +0 -0
  98. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/welcome.py +0 -0
  99. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/__init__.py +0 -0
  100. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/compact_progress.py +0 -0
  101. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/completion_overlay.py +0 -0
  102. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/input_area.py +0 -0
  103. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/message_events.py +0 -0
  104. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/__init__.py +0 -0
  105. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/assistant_message.py +0 -0
  106. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/error_message.py +0 -0
  107. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/hook_message.py +0 -0
  108. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/rendering.py +0 -0
  109. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/stop_hook_summary.py +0 -0
  110. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/thinking_message.py +0 -0
  111. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/pending_permission.py +0 -0
  112. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/spinner.py +0 -0
  113. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/task_panel.py +0 -0
  114. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/__init__.py +0 -0
  115. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/agent/__init__.py +0 -0
  116. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/ask_user_question/__init__.py +0 -0
  117. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/ask_user_question/widget.py +0 -0
  118. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/bash/__init__.py +0 -0
  119. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/batch_edit/__init__.py +0 -0
  120. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/edit/__init__.py +0 -0
  121. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/glob/__init__.py +0 -0
  122. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/grep/__init__.py +0 -0
  123. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/read/__init__.py +0 -0
  124. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/skill/__init__.py +0 -0
  125. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/user_message/__init__.py +0 -0
  126. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/user_message/widget.py +0 -0
  127. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/webfetch/__init__.py +0 -0
  128. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/websearch/__init__.py +0 -0
  129. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/write/__init__.py +0 -0
  130. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/dependency_links.txt +0 -0
  131. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/entry_points.txt +0 -0
  132. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/not-zip-safe +0 -0
  133. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/top_level.txt +0 -0
  134. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/setup.cfg +0 -0
  135. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_app_interrupt.py +0 -0
  136. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_llm_config_chain.py +0 -0
  137. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_repl_commands.py +0 -0
  138. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_repl_submit_flow.py +0 -0
  139. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_repl_ui.py +0 -0
  140. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_smoke.py +0 -0
  141. {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_welcome.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langchain-agentx-cli
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Terminal CLI/TUI for AgentX: migrate Claude Code Ink UI, backed by langchain-agentx-python SDK.
5
5
  Author: GoodMood2008
6
6
  License: Apache-2.0
@@ -22,7 +22,7 @@ Classifier: Topic :: Software Development
22
22
  Requires-Python: >=3.11
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
- Requires-Dist: langchain-agentx-python<0.6.0,>=0.4.3
25
+ Requires-Dist: langchain-agentx-python<0.6.0,>=0.4.5
26
26
  Requires-Dist: click>=8.1
27
27
  Requires-Dist: textual>=0.79.0
28
28
  Provides-Extra: dev
@@ -1,3 +1,3 @@
1
1
  """langchain_agentx_cli:依托 langchain_agentx_python SDK 的终端 CLI/TUI(CC Ink 迁移)。"""
2
2
 
3
- __version__ = "0.2.2"
3
+ __version__ = "0.3.2"
@@ -10,6 +10,7 @@ app.py — Textual ReplApp 容器。
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
+ import asyncio
13
14
  from pathlib import Path
14
15
  from typing import TYPE_CHECKING
15
16
 
@@ -36,6 +37,10 @@ from langchain_agentx_cli.widgets.messages import UserMessage
36
37
 
37
38
  if TYPE_CHECKING:
38
39
  from langchain_agentx import AgentSession
40
+ from langchain_agentx.tool_runtime.resolvers import (
41
+ AgentSessionPermissionResolver,
42
+ PermissionRequest,
43
+ )
39
44
 
40
45
  _CANCEL_HINT = "已取消当前生成。再次按 Ctrl+C 退出。"
41
46
  _EXIT_HINT = "再次按 Ctrl+C 退出。"
@@ -64,11 +69,15 @@ class ReplApp(App[None]):
64
69
  self,
65
70
  launch_config: ReplLaunchConfig,
66
71
  session: AgentSession | None = None,
72
+ permission_queue: asyncio.Queue[PermissionRequest] | None = None,
73
+ permission_resolver: AgentSessionPermissionResolver | None = None,
67
74
  debug: bool = False,
68
75
  ) -> None:
69
76
  super().__init__()
70
77
  self._launch_config = launch_config
71
78
  self._session = session
79
+ self._permission_queue = permission_queue
80
+ self._permission_resolver = permission_resolver
72
81
  self._bridge: SessionBridge | None = None
73
82
  self._exit_armed = False
74
83
  self.command_registry = CommandRegistry()
@@ -109,7 +118,15 @@ class ReplApp(App[None]):
109
118
  self.theme_manager = ThemeManager(self)
110
119
  self.theme_manager.setup(initial=initial_setting)
111
120
  if self._session is not None:
112
- self._bridge = SessionBridge(self, self._session)
121
+ # 方案 A: 传入预先创建的 permission_queue 和 permission_resolver
122
+ if self._permission_queue is None or self._permission_resolver is None:
123
+ raise RuntimeError("permission_queue 和 permission_resolver 必须由 open_agent_session 提供")
124
+ self._bridge = SessionBridge(
125
+ self,
126
+ self._session,
127
+ permission_queue=self._permission_queue,
128
+ permission_resolver=self._permission_resolver,
129
+ )
113
130
  register_sdk_commands(self.command_registry, self._session)
114
131
  self._bridge.permission_consumer.start()
115
132
  self.push_screen(ReplScreen())
@@ -29,7 +29,6 @@ from langchain_agentx_cli.observation import debug, info
29
29
  from langchain_agentx_cli.tui.permissions import (
30
30
  PermissionQueueConsumer,
31
31
  SessionPermissionCache,
32
- inject_permission_resolver,
33
32
  )
34
33
  from langchain_agentx_cli.tui.permissions.config import DEFAULT_PERMISSION_TIMEOUT_SECONDS
35
34
  from langchain_agentx_cli.tui.permissions.dialog import DialogPermissionDecisionPort
@@ -89,22 +88,26 @@ class _TurnSegmentState:
89
88
  class SessionBridge:
90
89
  """TUI 与 SDK 之间的桥接层(消费 LangchainAgentEvent)。"""
91
90
 
92
- def __init__(self, app: ReplApp, session: AgentSession) -> None:
91
+ def __init__(
92
+ self,
93
+ app: ReplApp,
94
+ session: AgentSession,
95
+ *,
96
+ permission_queue: asyncio.Queue[PermissionRequest],
97
+ permission_resolver: AgentSessionPermissionResolver,
98
+ ) -> None:
93
99
  self._app = app
94
100
  self._screen_messenger = app.screen_messenger
95
101
  self._session = session
96
102
  self._adapter = LangGraphToLangchainAgentEventAdapter(config=dict(MVP_ADAPTER_CONFIG))
97
103
  self._current_worker: Any = None
98
104
  self._seg = _TurnSegmentState()
99
- # 对齐 CC: 集中式权限队列状态管理
100
- self._permission_queue: asyncio.Queue[PermissionRequest] = asyncio.Queue()
105
+ # 方案 A: 接收预先创建的 queue 和 resolver(由 open_agent_session 传入)
106
+ self._permission_queue = permission_queue
101
107
  self._permission_cache = SessionPermissionCache()
102
108
  self._confirm_queue = ConfirmQueue(max_size=10) # 对齐 CC confirmQueue
103
- self._permission_resolver = AgentSessionPermissionResolver(
104
- request_queue=self._permission_queue,
105
- timeout=DEFAULT_PERMISSION_TIMEOUT_SECONDS,
106
- )
107
- inject_permission_resolver(session, self._permission_resolver)
109
+ self._permission_resolver = permission_resolver
110
+ # 不再需要 inject_permission_resolver,SDK 在编译时已使用传入的 resolver
108
111
  self._permission_consumer = PermissionQueueConsumer(
109
112
  queue=self._permission_queue,
110
113
  cache=self._permission_cache,
@@ -76,7 +76,7 @@ class CliEntry:
76
76
  return 0
77
77
 
78
78
  try:
79
- session = asyncio.run(
79
+ session, permission_queue, permission_resolver = asyncio.run(
80
80
  open_agent_session(
81
81
  launch_config,
82
82
  cli_provider=provider,
@@ -89,7 +89,13 @@ class CliEntry:
89
89
  return 2
90
90
 
91
91
  try:
92
- return self._run_tui(launch_config, session, debug=debug)
92
+ return self._run_tui(
93
+ launch_config,
94
+ session,
95
+ permission_queue=permission_queue,
96
+ permission_resolver=permission_resolver,
97
+ debug=debug,
98
+ )
93
99
  finally:
94
100
  asyncio.run(close_agent_session(session))
95
101
 
@@ -140,9 +146,20 @@ class CliEntry:
140
146
  return mode_map.get(mode.lower(), ".langchain_agentx")
141
147
 
142
148
  def _run_tui(
143
- self, launch_config: ReplLaunchConfig, session, debug: bool = False # noqa: ANN001
149
+ self,
150
+ launch_config: ReplLaunchConfig,
151
+ session, # noqa: ANN001
152
+ permission_queue, # noqa: ANN001
153
+ permission_resolver, # noqa: ANN001
154
+ debug: bool = False,
144
155
  ) -> int:
145
- app = ReplApp(launch_config=launch_config, session=session, debug=debug)
156
+ app = ReplApp(
157
+ launch_config=launch_config,
158
+ session=session,
159
+ permission_queue=permission_queue,
160
+ permission_resolver=permission_resolver,
161
+ debug=debug,
162
+ )
146
163
  app.run()
147
164
  return 0
148
165
 
@@ -0,0 +1,74 @@
1
+ """builtin/compact.py — /compact 命令(调用 SDK compact_context)。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from langchain_agentx_cli.commands.registry import Command, CommandContext
6
+ from langchain_agentx_cli.widgets.message_events import (
7
+ CompactFinished,
8
+ CompactProgressUpdate,
9
+ CompactStarted,
10
+ )
11
+
12
+ _SESSION_REQUIRED = "错误:会话未建立,无法压缩上下文"
13
+
14
+
15
+ async def handle_compact(ctx: CommandContext) -> str:
16
+ if ctx.bridge is None or not ctx.bridge.is_session_ready():
17
+ return _SESSION_REQUIRED
18
+
19
+ # 对齐 CC:支持可选的自定义总结指令参数
20
+ custom_instructions = ctx.args.strip() if ctx.args else None
21
+
22
+ # 通知 TUI 开始 compact(mount 进度条 widget)
23
+ ctx.app.post_message(CompactStarted())
24
+
25
+ def on_progress(p) -> None: # noqa: ANN001
26
+ """SDK 回调:向 TUI 发送进度更新。"""
27
+ ctx.app.post_message(
28
+ CompactProgressUpdate(percent=p.percent, detail=p.detail)
29
+ )
30
+
31
+ # 如果有自定义指令,设置到 CompactionSettings
32
+ if custom_instructions:
33
+ from langchain_agentx.loop.context.settings import (
34
+ CompactionSettings,
35
+ set_active_compaction_settings,
36
+ get_active_compaction_settings,
37
+ )
38
+ current = get_active_compaction_settings()
39
+ # 创建新的 settings,只替换 compact_custom_instructions
40
+ updated = CompactionSettings(
41
+ **{**current.__dict__, 'compact_custom_instructions': custom_instructions}
42
+ )
43
+ set_active_compaction_settings(updated)
44
+
45
+ try:
46
+ before, after = await ctx.bridge.session.compact_context(
47
+ progress_callback=on_progress
48
+ )
49
+ finally:
50
+ # 恢复原始设置(即使出错也要恢复)
51
+ if custom_instructions:
52
+ from langchain_agentx.loop.context.settings import set_active_compaction_settings, get_active_compaction_settings
53
+ current = get_active_compaction_settings()
54
+ updated = CompactionSettings(
55
+ **{**current.__dict__, 'compact_custom_instructions': None}
56
+ )
57
+ set_active_compaction_settings(updated)
58
+
59
+ # 通知 TUI 结束(移除进度条,显示结果)
60
+ ctx.app.post_message(CompactFinished(before=before, after=after))
61
+
62
+ pct = int(round(after / before * 100)) if before > 0 else 0
63
+ result = f"[信息] 已压缩:{before} tokens → {after} tokens ({pct}%)"
64
+ if custom_instructions:
65
+ result += f"\n[使用自定义指令: {custom_instructions}]"
66
+ return result
67
+
68
+
69
+ def make_compact_command() -> Command:
70
+ return Command(
71
+ name="compact",
72
+ description="压缩当前会话上下文。可选: /compact [自定义总结指令]",
73
+ handler=handle_compact,
74
+ )
@@ -13,6 +13,7 @@ session_factory.py — AgentSession 创建与生命周期。
13
13
 
14
14
  from __future__ import annotations
15
15
 
16
+ import asyncio
16
17
  from typing import TYPE_CHECKING
17
18
 
18
19
  from langchain_agentx_cli.bootstrap import CliEnvironmentError
@@ -27,6 +28,10 @@ if TYPE_CHECKING:
27
28
  from langchain_core.language_models.chat_models import BaseChatModel
28
29
 
29
30
  from langchain_agentx import AgentSession
31
+ from langchain_agentx.tool_runtime.resolvers import (
32
+ AgentSessionPermissionResolver,
33
+ PermissionRequest,
34
+ )
30
35
 
31
36
  from langchain_agentx_cli.config import ReplLaunchConfig
32
37
 
@@ -64,9 +69,15 @@ async def open_agent_session(
64
69
  cli_model: str | None = None,
65
70
  enable_git_snapshot: bool | None = None,
66
71
  include_default_session_context: bool = True,
67
- ) -> AgentSession:
68
- """创建并进入 AgentSession(构建 graph、SESSION_START hook)。"""
72
+ ) -> tuple[AgentSession, asyncio.Queue[PermissionRequest], AgentSessionPermissionResolver]:
73
+ """创建并进入 AgentSession(构建 graph、SESSION_START hook)。
74
+
75
+ 返回: (session, permission_queue, permission_resolver)
76
+ permission_queue 和 permission_resolver 由调用方传递给 SessionBridge。
77
+ """
69
78
  from langchain_agentx import create_agent_session
79
+ from langchain_agentx.tool_runtime.resolvers import AgentSessionPermissionResolver
80
+ from langchain_agentx_cli.tui.permissions.config import DEFAULT_PERMISSION_TIMEOUT_SECONDS
70
81
 
71
82
  cfg = resolve_llm_config(cli_provider=cli_provider, cli_model=cli_model)
72
83
  llm = build_chat_model(cfg)
@@ -82,18 +93,29 @@ async def open_agent_session(
82
93
  skip_permissions=launch_config.skip_permissions,
83
94
  )
84
95
 
96
+ # 方案 A: 在 session 创建前创建 permission_resolver,通过 loop_kwargs 传入
97
+ permission_queue: asyncio.Queue[PermissionRequest] = asyncio.Queue()
98
+ permission_resolver = AgentSessionPermissionResolver(
99
+ request_queue=permission_queue,
100
+ timeout=DEFAULT_PERMISSION_TIMEOUT_SECONDS,
101
+ )
102
+
103
+ loop_kwargs = build_session_loop_kwargs(
104
+ workspace_root=launch_config.workspace_root,
105
+ model=cfg.model,
106
+ provider=cfg.provider,
107
+ enable_git_snapshot=enable_git_snapshot,
108
+ include_default_session_context=include_default_session_context,
109
+ )
110
+ # 注入 permission_resolver 到 loop_kwargs
111
+ loop_kwargs["permission_resolver"] = permission_resolver
112
+
85
113
  session = create_agent_session(
86
114
  llm,
87
115
  workspace_root=launch_config.workspace_root,
88
116
  agent_home=launch_config.agent_home,
89
117
  loader=loader,
90
- **build_session_loop_kwargs(
91
- workspace_root=launch_config.workspace_root,
92
- model=cfg.model,
93
- provider=cfg.provider,
94
- enable_git_snapshot=enable_git_snapshot,
95
- include_default_session_context=include_default_session_context,
96
- ),
118
+ **loop_kwargs,
97
119
  )
98
120
  try:
99
121
  await session.__aenter__()
@@ -103,7 +125,7 @@ async def open_agent_session(
103
125
  raise CliEnvironmentError(
104
126
  f"无法创建 AgentSession(provider={cfg.provider!r}, model={cfg.model!r}):{exc}"
105
127
  ) from exc
106
- return session
128
+ return session, permission_queue, permission_resolver
107
129
 
108
130
 
109
131
  async def close_agent_session(session: AgentSession) -> None:
@@ -20,7 +20,7 @@ from langchain_agentx.tool_runtime.state_bridge import ToolStateBridge
20
20
  from langchain_agentx.tools.agent import AgentRuntimeTool
21
21
  from langchain_agentx.tools.ask_user_question import AskUserQuestionTool
22
22
  from langchain_agentx.tools.bash import BashRuntimeTool
23
- from langchain_agentx.tools.edit import BatchEditRuntimeTool, EditRuntimeTool
23
+ from langchain_agentx.tools.edit import EditRuntimeTool
24
24
  from langchain_agentx.tools.glob import GlobRuntimeTool
25
25
  from langchain_agentx.tools.grep import GrepRuntimeTool
26
26
  from langchain_agentx.tools.read import ReadRuntimeTool
@@ -87,7 +87,6 @@ class CliToolRegistry:
87
87
  self._loader.register(ReadRuntimeTool(state_bridge=bridge))
88
88
  self._loader.register(WriteRuntimeTool(state_bridge=bridge))
89
89
  self._loader.register(EditRuntimeTool(state_bridge=bridge))
90
- self._loader.register(BatchEditRuntimeTool(state_bridge=bridge))
91
90
  self._loader.register(BashRuntimeTool(state_bridge=bridge))
92
91
 
93
92
  def _register_search_tools(self) -> None:
@@ -6,7 +6,7 @@ tui/permissions — 权限确认子系统(Queue + Future)。
6
6
  集成 ConfirmQueue 状态管理(对齐 CC)。
7
7
 
8
8
  链路位置:
9
- SessionBridge 创建 Queue/Resolver → PermissionQueueConsumer → SDK Future。
9
+ open_agent_session 创建 Queue/Resolver → SessionBridge → PermissionQueueConsumer → SDK Future。
10
10
  """
11
11
 
12
12
  from langchain_agentx_cli.tui.permissions.cache import SessionPermissionCache
@@ -19,7 +19,6 @@ from langchain_agentx_cli.tui.permissions.consumer import (
19
19
  from langchain_agentx_cli.tui.permissions.dialog import (
20
20
  DialogPermissionDecisionPort,
21
21
  )
22
- from langchain_agentx_cli.tui.permissions.inject import inject_permission_resolver
23
22
  from langchain_agentx_cli.tui.permissions.models import PermissionDecision
24
23
  from langchain_agentx_cli.tui.permissions.presenters import (
25
24
  PermissionPresentation,
@@ -38,6 +37,5 @@ __all__ = [
38
37
  "PermissionQueueConsumer",
39
38
  "QueuedPermission",
40
39
  "SessionPermissionCache",
41
- "inject_permission_resolver",
42
40
  "permission_presenter_for_tool",
43
41
  ]
@@ -65,4 +65,5 @@ class PermissionPresenter:
65
65
  return None
66
66
 
67
67
  def _default_prompt(self) -> str:
68
- return "Do you want to proceed?"
68
+ # 对齐 CC:默认 prompt 为空,由 InlinePermissionWidget 添加 "Do you want to proceed?"
69
+ return ""
@@ -63,13 +63,46 @@ class BashPermissionPresenter(PermissionPresenter):
63
63
  self._command = extract_bash_command(self._prompt) or self._prompt
64
64
 
65
65
  def title(self) -> str:
66
- return "权限确认: Bash 命令"
66
+ # 对齐 CC:PermissionDialog title="Bash command"
67
+ return "Bash command"
67
68
 
68
69
  def format_body(self) -> str:
70
+ # 对齐 CC:命令 + 描述分行显示(带缩进)
69
71
  command = self._command
70
72
  if not command:
71
73
  return super().format_body()
72
- return f"Do you want to run the following command?\n\n $ {command}"
74
+
75
+ # 从 prompt 提取描述(如果有)
76
+ description = self._extract_description()
77
+
78
+ # 对齐 CC:命令显示在中间,带缩进
79
+ lines = [f" {command}"]
80
+ if description:
81
+ lines.append(f" {description}")
82
+ return "\n".join(lines)
83
+
84
+ def _extract_description(self) -> str | None:
85
+ """从 prompt 提取描述(如果有)。
86
+
87
+ 对齐 CC:bash 工具的 description 来自命令用途说明,
88
+ 如 "Search for langchain_agentx_python directory"。
89
+ """
90
+ prompt = self._prompt.strip()
91
+ if not prompt:
92
+ return None
93
+
94
+ # 尝试提取描述(prompt 中除去命令外的部分)
95
+ command = self._command
96
+ if command and command in prompt:
97
+ # 移除命令部分,获取剩余描述
98
+ remaining = prompt.replace(command, "", 1).strip()
99
+ # 移除常见的 prompt 前缀
100
+ for prefix in ["command:", "cmd:", "bash:", "$", ">"]:
101
+ if remaining.lower().startswith(prefix.lower()):
102
+ remaining = remaining[len(prefix):].strip()
103
+ if remaining and len(remaining) < 200:
104
+ return remaining
105
+ return None
73
106
 
74
107
  def warning_message(self) -> str | None:
75
108
  if not self.is_risky():
@@ -376,10 +376,18 @@ class MessageListWidget(ScrollableContainer):
376
376
 
377
377
  修复:使用 call_after_refresh 确保Widget完全mount后再转移焦点,
378
378
  避免与Textual渲染循环的竞态条件。
379
+ 对齐 CC:设置工具进度消息为 "Waiting for permission…"
379
380
  """
380
381
  # 先清理旧的 pending widget(使用引用,不依赖 ID)
381
382
  self.hide_permission_pending()
382
383
 
384
+ # 对齐 CC:在最近启动的工具上显示 "Waiting for permission…"
385
+ if self._active_tools:
386
+ # 获取最近启动的工具(最后一个添加的)
387
+ latest_tool = next(reversed(self._active_tools.values()), None)
388
+ if latest_tool and hasattr(latest_tool, "set_progress_text"):
389
+ latest_tool.set_progress_text("Waiting for permission…")
390
+
383
391
  self.mount(widget)
384
392
  self._pending_permission = widget
385
393
  self._scroll_to_end(force=True)
@@ -400,6 +408,12 @@ class MessageListWidget(ScrollableContainer):
400
408
  self._pending_permission.remove()
401
409
  self._pending_permission = None
402
410
 
411
+ # 对齐 CC:清除工具进度消息(权限处理后继续运行或完成)
412
+ if self._active_tools:
413
+ for tool in self._active_tools.values():
414
+ if hasattr(tool, "set_progress_text"):
415
+ tool.set_progress_text(None)
416
+
403
417
  def handle_assistant_chunk(self, chunk: AssistantMessageChunk) -> None:
404
418
  # DEBUG: 追踪消息块处理
405
419
  info(
@@ -522,6 +536,9 @@ class MessageListWidget(ScrollableContainer):
522
536
  verbose=self._verbose,
523
537
  parent_tool_use_id=event.parent_tool_use_id,
524
538
  )
539
+ # 对齐 CC:显示 "Running…" 进度消息
540
+ if hasattr(widget, "set_progress_text"):
541
+ widget.set_progress_text("Running…")
525
542
  self._mount_keeping_spinner_below(widget)
526
543
  # 跟踪运行中的工具(支持同名工具多次调用,追加后缀)
527
544
  key = event.tool_name
@@ -34,10 +34,11 @@ class _DecisionMade(Message):
34
34
  super().__init__()
35
35
 
36
36
 
37
+ # 对齐 CC:编号选项标签
37
38
  _OPTIONS = [
38
- (PermissionDecision.ALLOW_ONCE, "Yes"),
39
- (PermissionDecision.ALLOW_SESSION, "Yes, don't ask again this session"),
40
- (PermissionDecision.DENY, "No"),
39
+ (PermissionDecision.ALLOW_ONCE, "Yes"), # 1. Yes
40
+ (PermissionDecision.ALLOW_SESSION, "Yes, and don't ask again this session"), # 2. Yes, and don't ask again...
41
+ (PermissionDecision.DENY, "No"), # 3. No
41
42
  ]
42
43
 
43
44
 
@@ -48,6 +49,7 @@ class InlinePermissionWidget(Widget):
48
49
  - 使用 PermissionKeybindings 处理键盘事件
49
50
  - autoFocus 行为
50
51
  - 视觉反馈(focus 样式)
52
+ - 无边框设计(CC 不使用边框包裹权限对话框)
51
53
  """
52
54
 
53
55
  can_focus = True
@@ -60,17 +62,6 @@ class InlinePermissionWidget(Widget):
60
62
  height: auto;
61
63
  margin: 1 0;
62
64
  padding: 1 2;
63
- border: round $warning;
64
- background: $surface;
65
- }
66
- InlinePermissionWidget.-risky {
67
- border: round $error;
68
- }
69
- InlinePermissionWidget:focus {
70
- border: round $accent;
71
- }
72
- InlinePermissionWidget.-risky:focus {
73
- border: round $error;
74
65
  }
75
66
  """
76
67
 
@@ -91,30 +82,37 @@ class InlinePermissionWidget(Widget):
91
82
  p = self._presentation
92
83
  lines: list[str] = []
93
84
 
94
- # Title
95
- color = "$error" if p.is_risky else "$accent"
96
- lines.append(f"[bold {color}]{escape(p.title)}[/]")
85
+ # 对齐 CC:标题使用加粗,但不高亮颜色
86
+ lines.append(f"[bold]{escape(p.title)}[/]")
97
87
 
98
- # Body
99
- lines.append(f" {escape(p.body)}")
88
+ # 对齐 CC:空行分隔
89
+ lines.append("")
90
+
91
+ # Body - 对齐 CC:命令和描述已由 presenter 格式化
92
+ if p.body:
93
+ lines.append(f"{escape(p.body)}")
94
+
95
+ # 对齐 CC:空行分隔
96
+ lines.append("")
100
97
 
101
- # Warning
102
- if p.warning:
103
- lines.append(f" [bold $error]⚠ {escape(p.warning)}[/]")
98
+ # 对齐 CC:"Do you want to proceed?" 问题
99
+ lines.append(" Do you want to proceed?")
104
100
 
101
+ # 对齐 CC:空行分隔
105
102
  lines.append("")
106
103
 
107
- # Options
104
+ # 对齐 CC:编号选项(1. Yes, 2. Yes..., 3. No)
108
105
  for i, (_, label) in enumerate(_OPTIONS):
106
+ num = i + 1
109
107
  if i == self.selected_index:
110
- lines.append(f" [bold]> {label}[/]")
108
+ lines.append(f" {num}. {label}")
111
109
  else:
112
- lines.append(f" {label}")
110
+ lines.append(f" {num}. {label}")
113
111
 
114
- # Hint - 使用 keybindings 的帮助文本(对齐 CC
112
+ # 对齐 CC:底部快捷键提示
115
113
  lines.append("")
116
114
  help_text = self._keybindings.get_help_text()
117
- lines.append(f"[dim] {help_text}[/]")
115
+ lines.append(f"[dim] {help_text}[/]")
118
116
 
119
117
  return "\n".join(lines)
120
118
 
@@ -151,22 +151,12 @@ class PermissionKeybindings:
151
151
  return [b for b in self._bindings.values() if b.visible]
152
152
 
153
153
  def get_help_text(self) -> str:
154
- """获取帮助文本(对齐 CC 快捷键提示)。"""
155
- visible = self.get_visible_bindings()
156
- parts = []
157
- for binding in visible:
158
- if binding.key == "enter":
159
- parts.append("Enter confirm")
160
- elif binding.key == "up":
161
- parts.append("↑↓ select")
162
- elif binding.decision is PermissionDecision.ALLOW_ONCE:
163
- parts.append("Y allow")
164
- elif binding.decision is PermissionDecision.ALLOW_SESSION:
165
- parts.append("S session")
166
- elif binding.decision is PermissionDecision.DENY:
167
- if binding.key == "escape":
168
- parts.append("N/Esc deny")
169
- return " · ".join(parts)
154
+ """获取帮助文本(对齐 CC 快捷键提示)。
155
+
156
+ CC 格式: "Esc to cancel · Tab to amend · ctrl+e to explain"
157
+ """
158
+ # 对齐 CC:简化的快捷键提示
159
+ return "Esc to cancel · Enter to confirm"
170
160
 
171
161
 
172
162
  def setup_permission_keybindings(widget: InlinePermissionWidget) -> PermissionKeybindings:
@@ -46,6 +46,8 @@ class AgentToolWidget(BaseToolWidget):
46
46
  display: dict[str, Any] | None = None,
47
47
  **kwargs: Any,
48
48
  ) -> None:
49
+ # 对齐 CC:Agent 工具启动时显示 "In progress…" 进度消息
50
+ self._agent_started = False
49
51
  super().__init__(
50
52
  tool_name,
51
53
  tool_input,
@@ -56,6 +58,22 @@ class AgentToolWidget(BaseToolWidget):
56
58
  display=display,
57
59
  **kwargs,
58
60
  )
61
+ # 对齐 CC:设置 Agent 专属进度消息
62
+ if self._is_running:
63
+ self._update_agent_progress()
64
+
65
+ def _update_agent_progress(self) -> None:
66
+ """更新 Agent 运行时进度消息(对齐 CC)。"""
67
+ d = self._display
68
+ tool_count = d.get("total_steps")
69
+ if tool_count is not None:
70
+ # 对齐 CC:In progress… · N tool uses
71
+ suffix = "use" if tool_count == 1 else "uses"
72
+ progress = f"In progress… · {tool_count} tool {suffix}"
73
+ self.set_progress_text(progress)
74
+ else:
75
+ # 默认进度消息
76
+ self.set_progress_text("In progress…")
59
77
 
60
78
  def format_title(
61
79
  self,