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.
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/PKG-INFO +2 -2
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/__init__.py +1 -1
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/app.py +18 -1
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/bridge/session_bridge.py +12 -9
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/cli.py +21 -4
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/commands/builtin/compact.py +74 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/session_factory.py +32 -10
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tools/registry.py +1 -2
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/__init__.py +1 -3
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/base.py +2 -1
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/bash.py +35 -2
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/message_list.py +17 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/permission_inline.py +25 -27
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/permission_keybindings.py +6 -16
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/agent/widget.py +18 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/base.py +45 -12
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/bash/widget.py +11 -4
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/batch_edit/widget.py +11 -6
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/edit/widget.py +4 -3
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/glob/widget.py +5 -4
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/grep/widget.py +5 -4
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/helpers.py +12 -3
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/read/widget.py +7 -4
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/skill/widget.py +11 -8
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/webfetch/widget.py +6 -5
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/websearch/widget.py +7 -6
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/write/widget.py +5 -4
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/PKG-INFO +2 -2
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/SOURCES.txt +0 -1
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/requires.txt +1 -1
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/pyproject.toml +2 -2
- langchain_agentx_cli-0.3.0/langchain_agentx_cli/commands/builtin/compact.py +0 -44
- langchain_agentx_cli-0.3.0/langchain_agentx_cli/tui/permissions/inject.py +0 -57
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/LICENSE +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/README.md +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/__main__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/bootstrap.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/bridge/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/clear.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/help.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/model.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/quit.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/builtin/theme.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/parser.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/providers/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/providers/sdk_commands.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/commands/registry.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/completion/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/completion/base.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/completion/command_source.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/completion/history_source.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/config.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/history/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/history/store.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/keybindings/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/keybindings/bindings.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/llm_config.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/observation/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/observation/config.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/observation/observer.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/permissions/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/permissions/factory.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/permissions/policy.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/prompts/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/prompts/assembler.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/prompts/sections.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/prompts/system_prompt.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/screens/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/screens/repl.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/session_options.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/state/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/state/task_store.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/colors.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/detection.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/manager.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/settings.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/system_theme.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/themes.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/theme/watcher.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tools/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/clipboard.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/message_selection.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/cache.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/component_manager.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/config.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/consumer.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/dialog.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/models.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/fallback.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/presenters/file.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/permissions/queue.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tui/safe_screen.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/welcome.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/compact_progress.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/completion_overlay.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/input_area.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/message_events.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/assistant_message.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/error_message.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/hook_message.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/rendering.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/stop_hook_summary.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/messages/thinking_message.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/pending_permission.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/spinner.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/task_panel.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/agent/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/ask_user_question/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/ask_user_question/widget.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/bash/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/batch_edit/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/edit/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/glob/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/grep/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/read/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/skill/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/user_message/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/user_message/widget.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/webfetch/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/websearch/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/widgets/tools/write/__init__.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/dependency_links.txt +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/entry_points.txt +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/not-zip-safe +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli.egg-info/top_level.txt +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/setup.cfg +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_app_interrupt.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_llm_config_chain.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_repl_commands.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_repl_submit_flow.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_repl_ui.py +0 -0
- {langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/tests/test_smoke.py +0 -0
- {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.
|
|
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.
|
|
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
|
|
@@ -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
|
-
|
|
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__(
|
|
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
|
-
#
|
|
100
|
-
self._permission_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 =
|
|
104
|
-
|
|
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(
|
|
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,
|
|
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(
|
|
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
|
+
)
|
{langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/session_factory.py
RENAMED
|
@@ -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
|
-
**
|
|
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:
|
{langchain_agentx_cli-0.3.0 → langchain_agentx_cli-0.3.2}/langchain_agentx_cli/tools/registry.py
RENAMED
|
@@ -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
|
|
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
|
-
|
|
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
|
]
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
95
|
-
|
|
96
|
-
lines.append(f"[bold {color}]{escape(p.title)}[/]")
|
|
85
|
+
# 对齐 CC:标题使用加粗,但不高亮颜色
|
|
86
|
+
lines.append(f"[bold]{escape(p.title)}[/]")
|
|
97
87
|
|
|
98
|
-
#
|
|
99
|
-
lines.append(
|
|
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
|
-
#
|
|
102
|
-
|
|
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
|
-
#
|
|
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"
|
|
108
|
+
lines.append(f" ❯ {num}. {label}")
|
|
111
109
|
else:
|
|
112
|
-
lines.append(f"
|
|
110
|
+
lines.append(f" {num}. {label}")
|
|
113
111
|
|
|
114
|
-
#
|
|
112
|
+
# 对齐 CC:底部快捷键提示
|
|
115
113
|
lines.append("")
|
|
116
114
|
help_text = self._keybindings.get_help_text()
|
|
117
|
-
lines.append(f"[dim]
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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,
|