langchain-agentx-cli 0.3.2__tar.gz → 0.3.7__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.2 → langchain-agentx-cli-0.3.7}/PKG-INFO +3 -9
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/__init__.py +1 -1
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/app.py +119 -14
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/auto_mode_config.py +108 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/bootstrap.py +2 -2
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/__init__.py +6 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/auto_mode_config_apply.py +83 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/auto_mode_messages.py +39 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/auto_mode_sink.py +60 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/auto_mode_status.py +49 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/boundary_inspector.py +150 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/cli_l3_user_ui_queue.py +114 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/deny_override.py +352 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/hook_constants.py +34 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/hook_payload.py +66 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/permission_mode_apply.py +73 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/permission_response_builder.py +73 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/permission_user_ui.py +25 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/bridge/session_bridge.py +193 -35
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/cli.py +146 -1
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/__init__.py +14 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/auto_mode.py +345 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/doctor.py +74 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/grant.py +122 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/grants.py +54 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/permissions.py +95 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/revoke.py +44 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/roots.py +47 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/config.py +39 -5
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/health_report.py +389 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/keybindings/bindings.py +2 -2
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/launch_config_validator.py +65 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/audit_subscriber.py +175 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/config.py +103 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/failure_counts.py +38 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/failure_observation.py +64 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/log_rotator.py +107 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/observation/observer.py +41 -3
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/session_context.py +55 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/permissions/__init__.py +11 -5
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/permissions/factory.py +129 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/permissions/mode.py +96 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/permissions/policy.py +76 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/permissions/session_mode.py +45 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/prompts/__init__.py +6 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/prompts/assembler.py +6 -1
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/prompts/sections.py +56 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/screens/repl.py +101 -7
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/session_factory.py +251 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/session_headless.py +21 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/session_options.py +5 -1
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/bootstrap.py +49 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/memory_paths.py +284 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/__init__.py +4 -2
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/consumer.py +323 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/dialog.py +145 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/models.py +1 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/persistent_rules.py +255 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/__init__.py +56 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/base.py +15 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/bash.py +17 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/fallback.py +8 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/file.py +11 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/__init__.py +76 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/auto_mode_deny.py +69 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/base.py +98 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/boundary/__init__.py +19 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/boundary/extract.py +90 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/boundary/request.py +147 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/fallback/__init__.py +6 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/fallback/request.py +26 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/__init__.py +7 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/_base.py +69 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/diff.py +187 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/edit/__init__.py +6 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/edit/request.py +26 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/filesystem/__init__.py +6 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/filesystem/request.py +35 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/paths.py +58 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/write/__init__.py +6 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/write/request.py +26 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/plan_mode/__init__.py +8 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/plan_mode/request.py +53 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/__init__.py +11 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/bash/__init__.py +6 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/bash/request.py +78 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/extract.py +66 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/helpers.py +192 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/skill/__init__.py +7 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/skill/request.py +29 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/webfetch/__init__.py +7 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/webfetch/request.py +124 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/router.py +158 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/widgets/health_view.py +95 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/workspace_trust.py +47 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/welcome.py +8 -1
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/footer.py +57 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/input_area.py +132 -6
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/message_events.py +127 -3
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/message_list.py +494 -58
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/__init__.py +6 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/assistant_message.py +29 -11
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/messages/auto_mode_chip.py +67 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/messages/hook_message.py +130 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/thinking_message.py +11 -2
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/messages/tool_result.py +42 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/permission_inline.py +317 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/__init__.py +65 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/expand_hint.py +45 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/full_output.py +25 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/message_layout.py +104 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/shell_output.py +102 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/view_mode.py +44 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/status_bar.py +46 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/task_panel.py +2 -4
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/__init__.py +34 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/base.py +87 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/blocked_view.py +84 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/error_view.py +137 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/success_view.py +50 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/__init__.py +7 -1
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/agent/widget.py +2 -2
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/ask_user_question/widget.py +1 -1
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tools/base.py +573 -0
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tools/bash/widget.py +301 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/batch_edit/widget.py +2 -2
- langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tools/helpers.py +600 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/skill/widget.py +1 -1
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/webfetch/widget.py +2 -2
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/websearch/widget.py +2 -2
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/write/widget.py +22 -4
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/PKG-INFO +3 -9
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/SOURCES.txt +81 -8
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/requires.txt +1 -1
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/pyproject.toml +14 -3
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/bridge/__init__.py +0 -5
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/observation/config.py +0 -35
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/permissions/factory.py +0 -93
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/permissions/policy.py +0 -119
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/session_factory.py +0 -132
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/consumer.py +0 -188
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/dialog.py +0 -132
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/__init__.py +0 -63
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/base.py +0 -69
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/bash.py +0 -124
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/fallback.py +0 -25
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/file.py +0 -87
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/messages/hook_message.py +0 -72
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/permission_inline.py +0 -145
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/tools/base.py +0 -286
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/tools/bash/widget.py +0 -110
- langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/tools/helpers.py +0 -309
- langchain_agentx_cli-0.3.2/tests/test_app_interrupt.py +0 -98
- langchain_agentx_cli-0.3.2/tests/test_llm_config_chain.py +0 -182
- langchain_agentx_cli-0.3.2/tests/test_repl_commands.py +0 -84
- langchain_agentx_cli-0.3.2/tests/test_repl_submit_flow.py +0 -69
- langchain_agentx_cli-0.3.2/tests/test_repl_ui.py +0 -90
- langchain_agentx_cli-0.3.2/tests/test_smoke.py +0 -124
- langchain_agentx_cli-0.3.2/tests/test_welcome.py +0 -59
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/LICENSE +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/README.md +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/__main__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/clear.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/compact.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/help.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/model.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/quit.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/theme.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/parser.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/providers/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/providers/sdk_commands.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/registry.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/completion/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/completion/base.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/completion/command_source.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/completion/history_source.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/history/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/history/store.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/keybindings/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/llm_config.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/observation/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/prompts/system_prompt.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/screens/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/state/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/state/task_store.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/colors.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/detection.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/manager.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/settings.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/system_theme.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/themes.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/watcher.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tools/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tools/registry.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/clipboard.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/message_selection.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/cache.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/component_manager.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/config.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/queue.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/safe_screen.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/compact_progress.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/completion_overlay.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/error_message.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/rendering.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/stop_hook_summary.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/pending_permission.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/permission_keybindings.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/spinner.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/agent/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/ask_user_question/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/bash/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/batch_edit/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/edit/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/edit/widget.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/glob/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/glob/widget.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/grep/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/grep/widget.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/read/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/read/widget.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/skill/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/user_message/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/user_message/widget.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/webfetch/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/websearch/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/write/__init__.py +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/dependency_links.txt +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/entry_points.txt +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/not-zip-safe +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/top_level.txt +0 -0
- {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: langchain-agentx-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
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
|
|
@@ -21,14 +21,8 @@ Classifier: Environment :: Console
|
|
|
21
21
|
Classifier: Topic :: Software Development
|
|
22
22
|
Requires-Python: >=3.11
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
|
-
License-File: LICENSE
|
|
25
|
-
Requires-Dist: langchain-agentx-python<0.6.0,>=0.4.5
|
|
26
|
-
Requires-Dist: click>=8.1
|
|
27
|
-
Requires-Dist: textual>=0.79.0
|
|
28
24
|
Provides-Extra: dev
|
|
29
|
-
|
|
30
|
-
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
|
|
31
|
-
Dynamic: license-file
|
|
25
|
+
License-File: LICENSE
|
|
32
26
|
|
|
33
27
|
# langchain-agentx-cli
|
|
34
28
|
|
|
@@ -2,17 +2,22 @@
|
|
|
2
2
|
app.py — Textual ReplApp 容器。
|
|
3
3
|
|
|
4
4
|
职责:
|
|
5
|
-
应用生命周期、SessionBridge
|
|
5
|
+
应用生命周期、SessionBridge、命令注册表、历史、三键语义模型(对齐 CC)。
|
|
6
6
|
|
|
7
7
|
链路位置:
|
|
8
8
|
CliEntry._run_tui() 实例化并 run();session 关闭由 CliEntry finally 负责。
|
|
9
|
+
|
|
10
|
+
三键语义模型(对齐 CC):
|
|
11
|
+
Esc (chat:cancel) → 仅中断当前活动,永不退出
|
|
12
|
+
Ctrl+C (app:interrupt) → 中断 + 双击退出
|
|
13
|
+
Ctrl+D (app:exit) → 输入为空时双击退出(Unix EOF 惯例)
|
|
9
14
|
"""
|
|
10
15
|
|
|
11
16
|
from __future__ import annotations
|
|
12
17
|
|
|
13
18
|
import asyncio
|
|
14
19
|
from pathlib import Path
|
|
15
|
-
from typing import TYPE_CHECKING
|
|
20
|
+
from typing import TYPE_CHECKING, Literal
|
|
16
21
|
|
|
17
22
|
from textual import on
|
|
18
23
|
from textual.app import App
|
|
@@ -33,6 +38,11 @@ from langchain_agentx_cli.screens import ReplScreen
|
|
|
33
38
|
from langchain_agentx_cli.tui.message_selection import try_copy_message_selection
|
|
34
39
|
from langchain_agentx_cli.tui.safe_screen import ReplScreenMessenger
|
|
35
40
|
from langchain_agentx_cli.widgets.permission_inline import InlinePermissionWidget
|
|
41
|
+
from langchain_agentx_cli.bridge.permission_mode_apply import apply_permission_mode
|
|
42
|
+
from langchain_agentx_cli.permissions.mode import (
|
|
43
|
+
get_next_permission_mode,
|
|
44
|
+
normalize_permission_mode,
|
|
45
|
+
)
|
|
36
46
|
from langchain_agentx_cli.widgets.messages import UserMessage
|
|
37
47
|
|
|
38
48
|
if TYPE_CHECKING:
|
|
@@ -42,8 +52,7 @@ if TYPE_CHECKING:
|
|
|
42
52
|
PermissionRequest,
|
|
43
53
|
)
|
|
44
54
|
|
|
45
|
-
|
|
46
|
-
_EXIT_HINT = "再次按 Ctrl+C 退出。"
|
|
55
|
+
from langchain_agentx_cli.bridge.auto_mode_sink import AutoModeEventSink
|
|
47
56
|
|
|
48
57
|
|
|
49
58
|
class ReplApp(App[None]):
|
|
@@ -52,7 +61,9 @@ class ReplApp(App[None]):
|
|
|
52
61
|
TITLE = "langchain-agentx-cli"
|
|
53
62
|
BINDINGS = [
|
|
54
63
|
("q", "quit", "Quit"),
|
|
55
|
-
|
|
64
|
+
# 对齐 CC 三键语义模型
|
|
65
|
+
("escape", "cancel_stream", "Cancel"), # chat:cancel — 仅中断,永不退出
|
|
66
|
+
("ctrl+c", "interrupt", "Interrupt / Quit"), # app:interrupt — 中断 + 双击退出
|
|
56
67
|
Binding("ctrl+l", "clear_screen", "Clear", show=False, priority=True),
|
|
57
68
|
Binding(
|
|
58
69
|
"ctrl+shift+l",
|
|
@@ -71,6 +82,7 @@ class ReplApp(App[None]):
|
|
|
71
82
|
session: AgentSession | None = None,
|
|
72
83
|
permission_queue: asyncio.Queue[PermissionRequest] | None = None,
|
|
73
84
|
permission_resolver: AgentSessionPermissionResolver | None = None,
|
|
85
|
+
auto_mode_sink: AutoModeEventSink | None = None,
|
|
74
86
|
debug: bool = False,
|
|
75
87
|
) -> None:
|
|
76
88
|
super().__init__()
|
|
@@ -78,8 +90,11 @@ class ReplApp(App[None]):
|
|
|
78
90
|
self._session = session
|
|
79
91
|
self._permission_queue = permission_queue
|
|
80
92
|
self._permission_resolver = permission_resolver
|
|
93
|
+
self._auto_mode_sink = auto_mode_sink
|
|
81
94
|
self._bridge: SessionBridge | None = None
|
|
82
|
-
|
|
95
|
+
# 对齐 CC useDoublePress:独立的双击状态(按键名 + 800ms timer)
|
|
96
|
+
self._exit_armed_key: Literal["ctrl+c", "ctrl+d"] | None = None
|
|
97
|
+
self._exit_armed_timer = None # textual.timer.Timer | None
|
|
83
98
|
self.command_registry = CommandRegistry()
|
|
84
99
|
register_builtin_commands(self.command_registry)
|
|
85
100
|
self.history_store = HistoryStore()
|
|
@@ -87,6 +102,10 @@ class ReplApp(App[None]):
|
|
|
87
102
|
self._screen_messenger = ReplScreenMessenger(self)
|
|
88
103
|
# Phase 3: 加载用户偏好(供 MessageListWidget 和工具 Widget 使用)
|
|
89
104
|
self.preferences: AppUserPreferences = AppPreferencesStore().load()
|
|
105
|
+
self._permission_mode = normalize_permission_mode(
|
|
106
|
+
launch_config.permission_mode
|
|
107
|
+
)
|
|
108
|
+
self._prefs_store = AppPreferencesStore()
|
|
90
109
|
self._debug = debug
|
|
91
110
|
|
|
92
111
|
@property
|
|
@@ -105,6 +124,47 @@ class ReplApp(App[None]):
|
|
|
105
124
|
def bridge(self) -> SessionBridge | None:
|
|
106
125
|
return self._bridge
|
|
107
126
|
|
|
127
|
+
@property
|
|
128
|
+
def permission_mode(self) -> str:
|
|
129
|
+
return self._permission_mode
|
|
130
|
+
|
|
131
|
+
def set_permission_mode(self, mode: str) -> str:
|
|
132
|
+
"""设置权限模式并同步 Auto Mode enabled + graph(对齐 CC transitionPermissionMode)。"""
|
|
133
|
+
resolved = apply_permission_mode(
|
|
134
|
+
bridge=self._bridge,
|
|
135
|
+
session=self._session,
|
|
136
|
+
mode=mode,
|
|
137
|
+
store=self._prefs_store,
|
|
138
|
+
prefs=self.preferences,
|
|
139
|
+
)
|
|
140
|
+
self._permission_mode = resolved
|
|
141
|
+
self.preferences = self._prefs_store.load()
|
|
142
|
+
self._refresh_permission_mode_footer()
|
|
143
|
+
from langchain_agentx_cli.permissions.mode import permission_mode_short_title
|
|
144
|
+
|
|
145
|
+
return permission_mode_short_title(resolved)
|
|
146
|
+
|
|
147
|
+
def cycle_permission_mode(self) -> str | None:
|
|
148
|
+
"""Shift+Tab:循环权限模式;无 session 时返回 None。"""
|
|
149
|
+
if self._session is None:
|
|
150
|
+
return None
|
|
151
|
+
next_mode = get_next_permission_mode(
|
|
152
|
+
self._permission_mode,
|
|
153
|
+
bypass_available=self._launch_config.skip_permissions,
|
|
154
|
+
)
|
|
155
|
+
return self.set_permission_mode(next_mode)
|
|
156
|
+
|
|
157
|
+
def _refresh_permission_mode_footer(self) -> None:
|
|
158
|
+
screen = self.screen
|
|
159
|
+
if not isinstance(screen, ReplScreen):
|
|
160
|
+
return
|
|
161
|
+
try:
|
|
162
|
+
from langchain_agentx_cli.widgets.input_area import InputAreaWidget
|
|
163
|
+
|
|
164
|
+
screen.query_one(InputAreaWidget).refresh_auto_status_footer()
|
|
165
|
+
except Exception:
|
|
166
|
+
pass
|
|
167
|
+
|
|
108
168
|
def on_mount(self) -> None:
|
|
109
169
|
# DEBUG: 启用观测日志
|
|
110
170
|
if self._debug:
|
|
@@ -127,6 +187,8 @@ class ReplApp(App[None]):
|
|
|
127
187
|
permission_queue=self._permission_queue,
|
|
128
188
|
permission_resolver=self._permission_resolver,
|
|
129
189
|
)
|
|
190
|
+
if self._auto_mode_sink is not None:
|
|
191
|
+
self._bridge.attach_auto_mode(self._auto_mode_sink)
|
|
130
192
|
register_sdk_commands(self.command_registry, self._session)
|
|
131
193
|
self._bridge.permission_consumer.start()
|
|
132
194
|
self.push_screen(ReplScreen())
|
|
@@ -147,16 +209,34 @@ class ReplApp(App[None]):
|
|
|
147
209
|
self.clear_messages()
|
|
148
210
|
self.notify("消息已清空", severity="information", timeout=2)
|
|
149
211
|
|
|
212
|
+
# 对齐 CC useDoublePress:800ms 双击窗口
|
|
213
|
+
_DOUBLE_PRESS_TIMEOUT = 0.8 # CC DOUBLE_PRESS_TIMEOUT_MS=800
|
|
214
|
+
|
|
215
|
+
def _arm_exit(self, key: Literal["ctrl+c", "ctrl+d"], hint: str) -> None:
|
|
216
|
+
"""对齐 CC useDoublePress:800ms 内再次按同一键则退出。"""
|
|
217
|
+
self._exit_armed_key = key
|
|
218
|
+
if self._exit_armed_timer is not None:
|
|
219
|
+
self._exit_armed_timer.stop()
|
|
220
|
+
self._exit_armed_timer = self.set_timer(
|
|
221
|
+
self._DOUBLE_PRESS_TIMEOUT,
|
|
222
|
+
self._disarm_exit,
|
|
223
|
+
)
|
|
224
|
+
self.notify(hint, severity="information", timeout=2)
|
|
225
|
+
|
|
226
|
+
def _disarm_exit(self) -> None:
|
|
227
|
+
"""清除双击退出状态。"""
|
|
228
|
+
self._exit_armed_key = None
|
|
229
|
+
self._exit_armed_timer = None
|
|
230
|
+
|
|
150
231
|
@on(UserMessage)
|
|
151
232
|
def _on_user_message_reset_exit_arm(self, _event: UserMessage) -> None:
|
|
152
|
-
self.
|
|
233
|
+
self._disarm_exit()
|
|
153
234
|
|
|
154
235
|
def action_cancel_stream(self) -> None:
|
|
236
|
+
"""Esc → chat:cancel:仅中断当前活动,永不退出(对齐 CC)。"""
|
|
155
237
|
result = try_copy_message_selection(self)
|
|
156
238
|
if result is not None:
|
|
157
|
-
# 有选区被复制(无论成功与否),不执行后续操作
|
|
158
239
|
return
|
|
159
|
-
# Dismiss inline permission widget if active
|
|
160
240
|
try:
|
|
161
241
|
widget = self.screen.query_one(InlinePermissionWidget)
|
|
162
242
|
widget.dismiss_externally()
|
|
@@ -165,14 +245,39 @@ class ReplApp(App[None]):
|
|
|
165
245
|
pass
|
|
166
246
|
if self._bridge is not None and self._bridge.is_streaming():
|
|
167
247
|
self._bridge.cancel_stream()
|
|
168
|
-
self.
|
|
169
|
-
self.notify(_CANCEL_HINT, severity="warning", timeout=4)
|
|
248
|
+
self.notify("已取消当前生成", severity="warning", timeout=2)
|
|
170
249
|
return
|
|
171
|
-
|
|
250
|
+
# 空闲时 no-op(对齐 CC isEscapeActive=false)
|
|
251
|
+
|
|
252
|
+
def action_interrupt(self) -> None:
|
|
253
|
+
"""Ctrl+C → app:interrupt + 双击退出(对齐 CC)。"""
|
|
254
|
+
result = try_copy_message_selection(self)
|
|
255
|
+
if result is not None:
|
|
256
|
+
return
|
|
257
|
+
try:
|
|
258
|
+
widget = self.screen.query_one(InlinePermissionWidget)
|
|
259
|
+
widget.dismiss_externally()
|
|
260
|
+
return
|
|
261
|
+
except Exception:
|
|
262
|
+
pass
|
|
263
|
+
if self._bridge is not None and self._bridge.is_streaming():
|
|
264
|
+
self._bridge.cancel_stream()
|
|
265
|
+
# 关键:取消流不 arm 退出(对齐 CC,取消流和 arm 退出是独立动作)
|
|
266
|
+
self._disarm_exit()
|
|
267
|
+
self.notify("已取消当前生成", severity="warning", timeout=2)
|
|
268
|
+
return
|
|
269
|
+
# 空闲:双击退出逻辑(对齐 CC useExitOnCtrlCD)
|
|
270
|
+
if self._exit_armed_key == "ctrl+c":
|
|
271
|
+
self.action_quit()
|
|
272
|
+
return
|
|
273
|
+
self._arm_exit("ctrl+c", "再次按 Ctrl+C 退出")
|
|
274
|
+
|
|
275
|
+
def action_exit(self) -> None:
|
|
276
|
+
"""Ctrl+D → app:exit:纯双击退出,输入为空时生效(对齐 CC + Unix EOF)。"""
|
|
277
|
+
if self._exit_armed_key == "ctrl+d":
|
|
172
278
|
self.action_quit()
|
|
173
279
|
return
|
|
174
|
-
self.
|
|
175
|
-
self.notify(_EXIT_HINT, severity="information", timeout=4)
|
|
280
|
+
self._arm_exit("ctrl+d", "再次按 Ctrl+D 退出")
|
|
176
281
|
|
|
177
282
|
def action_quit(self) -> None:
|
|
178
283
|
if self._bridge is not None:
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""
|
|
2
|
+
auto_mode_config.py — Auto Mode 用户配置 ↔ SDK AutoModeConfig 转换。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
从 AppUserPreferences.auto_mode(camelCase dict)加载;
|
|
6
|
+
合并字段、序列化回持久化 dict。
|
|
7
|
+
|
|
8
|
+
链路位置:
|
|
9
|
+
session_factory / CliPolicyConfigBuilder → load_auto_mode_config;
|
|
10
|
+
/auto-mode 命令 → merge_auto_mode_fields → persist。
|
|
11
|
+
|
|
12
|
+
当前裁剪范围:
|
|
13
|
+
set 白名单:useClassifier / classifierTimeoutS / transcriptMaxTurns;
|
|
14
|
+
enabled 由 permission mode(auto)驱动,勿用 /auto-mode set enabled。
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from dataclasses import replace
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from langchain_agentx.tool_runtime.auto_mode import AutoModeConfig
|
|
23
|
+
|
|
24
|
+
SETTABLE_KEYS: dict[str, str] = {
|
|
25
|
+
"enabled": "enabled",
|
|
26
|
+
"useClassifier": "use_classifier",
|
|
27
|
+
"use_classifier": "use_classifier",
|
|
28
|
+
"classifierTimeoutS": "classifier_timeout_s",
|
|
29
|
+
"classifier_timeout_s": "classifier_timeout_s",
|
|
30
|
+
"transcriptMaxTurns": "transcript_max_turns",
|
|
31
|
+
"transcript_max_turns": "transcript_max_turns",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def load_auto_mode_config(data: dict[str, Any] | None) -> AutoModeConfig:
|
|
36
|
+
"""camelCase / snake_case dict → AutoModeConfig(默认值填充)。"""
|
|
37
|
+
if not data:
|
|
38
|
+
return AutoModeConfig()
|
|
39
|
+
return AutoModeConfig.from_dict(data)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def auto_mode_prefs_from_config(cfg: AutoModeConfig) -> dict[str, Any]:
|
|
43
|
+
"""AutoModeConfig → camelCase 持久化字段(set 白名单子集)。"""
|
|
44
|
+
return {
|
|
45
|
+
"enabled": cfg.enabled,
|
|
46
|
+
"useClassifier": cfg.use_classifier,
|
|
47
|
+
"classifierTimeoutS": cfg.classifier_timeout_s,
|
|
48
|
+
"transcriptMaxTurns": cfg.transcript_max_turns,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def merge_auto_mode_fields(
|
|
53
|
+
current: AutoModeConfig | None,
|
|
54
|
+
*,
|
|
55
|
+
enabled: bool | None = None,
|
|
56
|
+
use_classifier: bool | None = None,
|
|
57
|
+
classifier_timeout_s: float | None = None,
|
|
58
|
+
transcript_max_turns: int | None = None,
|
|
59
|
+
) -> AutoModeConfig:
|
|
60
|
+
"""合并可热更新字段(dataclass replace)。"""
|
|
61
|
+
base = current if current is not None else AutoModeConfig()
|
|
62
|
+
fields: dict[str, Any] = {}
|
|
63
|
+
if enabled is not None:
|
|
64
|
+
fields["enabled"] = enabled
|
|
65
|
+
if use_classifier is not None:
|
|
66
|
+
fields["use_classifier"] = use_classifier
|
|
67
|
+
if classifier_timeout_s is not None:
|
|
68
|
+
fields["classifier_timeout_s"] = classifier_timeout_s
|
|
69
|
+
if transcript_max_turns is not None:
|
|
70
|
+
fields["transcript_max_turns"] = transcript_max_turns
|
|
71
|
+
if not fields:
|
|
72
|
+
return base
|
|
73
|
+
return replace(base, **fields)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def parse_bool(value: str) -> bool | None:
|
|
77
|
+
key = value.strip().lower()
|
|
78
|
+
if key in ("true", "1", "on", "yes"):
|
|
79
|
+
return True
|
|
80
|
+
if key in ("false", "0", "off", "no"):
|
|
81
|
+
return False
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def parse_set_value(key: str, raw: str) -> Any:
|
|
86
|
+
"""解析 /auto-mode set 的值;失败时抛 ValueError。"""
|
|
87
|
+
field = SETTABLE_KEYS.get(key)
|
|
88
|
+
if field is None:
|
|
89
|
+
raise ValueError(f"不可通过 set 修改的字段:{key}")
|
|
90
|
+
if field == "enabled" or field == "use_classifier":
|
|
91
|
+
parsed = parse_bool(raw)
|
|
92
|
+
if parsed is None:
|
|
93
|
+
raise ValueError(f"{key} 需要 true/false")
|
|
94
|
+
return parsed
|
|
95
|
+
if field == "classifier_timeout_s":
|
|
96
|
+
try:
|
|
97
|
+
return float(raw.strip())
|
|
98
|
+
except ValueError as exc:
|
|
99
|
+
raise ValueError(f"{key} 需要数字(秒)") from exc
|
|
100
|
+
if field == "transcript_max_turns":
|
|
101
|
+
try:
|
|
102
|
+
n = int(raw.strip())
|
|
103
|
+
except ValueError as exc:
|
|
104
|
+
raise ValueError(f"{key} 需要整数") from exc
|
|
105
|
+
if n < 1:
|
|
106
|
+
raise ValueError(f"{key} 必须 >= 1")
|
|
107
|
+
return n
|
|
108
|
+
raise ValueError(f"未知字段:{key}")
|
|
@@ -8,7 +8,7 @@ bootstrap.py — CLI 启动前环境检查。
|
|
|
8
8
|
CliEntry.run() 在创建 ReplApp 之前调用。
|
|
9
9
|
|
|
10
10
|
当前裁剪范围:
|
|
11
|
-
不校验 API Key
|
|
11
|
+
不校验 API Key;启动期 quick health 见 tui/bootstrap.py。
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
from __future__ import annotations
|
|
@@ -30,7 +30,7 @@ class EnvironmentChecker:
|
|
|
30
30
|
except ImportError as exc:
|
|
31
31
|
raise CliEnvironmentError(
|
|
32
32
|
"无法导入 langchain_agentx。请安装 SDK:\n"
|
|
33
|
-
' pip install "langchain-agentx-python>=0.
|
|
33
|
+
' pip install "langchain-agentx-python>=0.7.0,<0.8.0"\n'
|
|
34
34
|
"或 editable:pip install -e <langchain_agentx_python 路径>"
|
|
35
35
|
) from exc
|
|
36
36
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
bridge/auto_mode_config_apply.py — 运行中 Auto Mode 配置热更新薄壳。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
单点调用 SDK apply_auto_mode_config_to_engine,隔离 engine 私有字段访问。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
/auto-mode on|off|set|classifier → apply_to_running_session。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
仅 DefaultPolicyEngine + ToolRuntimeLoader 路径。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import TYPE_CHECKING, Any
|
|
17
|
+
|
|
18
|
+
from langchain_agentx.tool_runtime.auto_mode import AutoModeConfig
|
|
19
|
+
from langchain_agentx.tool_runtime.auto_mode.config_update import (
|
|
20
|
+
apply_auto_mode_config_to_engine,
|
|
21
|
+
)
|
|
22
|
+
from langchain_agentx.tool_runtime.policy import DefaultPolicyEngine
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from langchain_agentx_cli.bridge.session_bridge import SessionBridge
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def policy_engine_from_bridge(bridge: SessionBridge | None) -> DefaultPolicyEngine | None:
|
|
29
|
+
if bridge is None:
|
|
30
|
+
return None
|
|
31
|
+
loader = bridge.tool_loader
|
|
32
|
+
if loader is None:
|
|
33
|
+
return None
|
|
34
|
+
policy = loader.policy
|
|
35
|
+
return policy if isinstance(policy, DefaultPolicyEngine) else None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def current_auto_mode_config(bridge: SessionBridge | None) -> AutoModeConfig:
|
|
39
|
+
engine = policy_engine_from_bridge(bridge)
|
|
40
|
+
if engine is None:
|
|
41
|
+
return AutoModeConfig()
|
|
42
|
+
cfg = getattr(engine._config, "auto_mode", None)
|
|
43
|
+
return cfg if isinstance(cfg, AutoModeConfig) else AutoModeConfig()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def apply_to_running_session(bridge: SessionBridge | None, new_cfg: AutoModeConfig) -> bool:
|
|
47
|
+
"""将配置写入运行中 session;无 engine 时返回 False。"""
|
|
48
|
+
loader = bridge.tool_loader if bridge is not None else None
|
|
49
|
+
if loader is not None and hasattr(loader, "update_auto_mode_config"):
|
|
50
|
+
loader.update_auto_mode_config(auto_mode_config=new_cfg)
|
|
51
|
+
return True
|
|
52
|
+
engine = policy_engine_from_bridge(bridge)
|
|
53
|
+
if engine is None:
|
|
54
|
+
return False
|
|
55
|
+
apply_auto_mode_config_to_engine(engine, new_cfg)
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def format_config_dump(cfg: AutoModeConfig) -> str:
|
|
60
|
+
"""YAML 风格 dump(标量字段)。"""
|
|
61
|
+
lines = [
|
|
62
|
+
f"enabled: {cfg.enabled}",
|
|
63
|
+
f"useClassifier: {cfg.use_classifier}",
|
|
64
|
+
f"classifierModel: {cfg.classifier_model!r}",
|
|
65
|
+
f"classifierTimeoutS: {cfg.classifier_timeout_s}",
|
|
66
|
+
f"transcriptMaxTurns: {cfg.transcript_max_turns}",
|
|
67
|
+
f"stripDangerousRules: {cfg.strip_dangerous_rules}",
|
|
68
|
+
f"emitDecisionEvents: {cfg.emit_decision_events}",
|
|
69
|
+
]
|
|
70
|
+
return "\n".join(lines)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def refresh_auto_mode_footer(app: Any) -> None:
|
|
74
|
+
"""命令改配置后刷新 InputArea footer。"""
|
|
75
|
+
try:
|
|
76
|
+
screen = app.screen
|
|
77
|
+
from langchain_agentx_cli.screens.repl import ReplScreen
|
|
78
|
+
from langchain_agentx_cli.widgets.input_area import InputAreaWidget
|
|
79
|
+
|
|
80
|
+
if isinstance(screen, ReplScreen):
|
|
81
|
+
screen.query_one(InputAreaWidget).refresh_auto_status_footer()
|
|
82
|
+
except Exception:
|
|
83
|
+
pass
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
bridge/auto_mode_messages.py — SDK AutoModeDecisionEvent → UI Message 转换。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
从 event_bus 事件构造 AutoModeDecisionMessage;过滤无 tool_use_id 的事件。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
SessionBridge._on_auto_mode_event → _post_ui(AutoModeDecisionMessage)。
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from langchain_agentx_cli.widgets.message_events import AutoModeDecisionMessage
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def auto_mode_message_from_event(event: Any) -> AutoModeDecisionMessage | None:
|
|
19
|
+
"""将 SDK 决策事件转为 Textual Message;无 tool_use_id 时返回 None。"""
|
|
20
|
+
tool_use_id = getattr(event, "tool_use_id", None)
|
|
21
|
+
if not tool_use_id:
|
|
22
|
+
return None
|
|
23
|
+
decision = getattr(event, "decision", None) or {}
|
|
24
|
+
if not isinstance(decision, dict):
|
|
25
|
+
decision = {}
|
|
26
|
+
return AutoModeDecisionMessage(
|
|
27
|
+
raw_event=event,
|
|
28
|
+
tool_use_id=str(tool_use_id),
|
|
29
|
+
tool_name=getattr(event, "tool_name", None),
|
|
30
|
+
behavior=str(decision.get("behavior", "")),
|
|
31
|
+
layer=str(decision.get("layer", "")),
|
|
32
|
+
reason=str(decision.get("reason", "")),
|
|
33
|
+
explanation=str(decision.get("explanation", "")),
|
|
34
|
+
confidence=str(decision.get("confidence", "")),
|
|
35
|
+
classifier_thinking=decision.get("classifier_thinking"),
|
|
36
|
+
elapsed_ms=float(decision.get("elapsed_ms", 0.0)),
|
|
37
|
+
matched_pattern=decision.get("matched_pattern"),
|
|
38
|
+
timestamp=str(getattr(event, "timestamp", "")),
|
|
39
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
bridge/auto_mode_sink.py — Auto Mode 决策事件 Sink(SDK event_bus 适配)。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
在 UI 就绪前缓冲决策事件;UI attach 后切换 live 回调并 flush pending。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
open_agent_session 创建 → build_auto_mode_hook(event_bus=sink) → SessionBridge.attach_auto_mode。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
duck-typed event_bus(仅需 emit);不持锁、不跨线程。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
from collections import deque
|
|
18
|
+
from collections.abc import Callable
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
_PENDING_MAXLEN = 200
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AutoModeEventSink:
|
|
27
|
+
"""SDK AutoModeAuthHook 的 event_bus 薄适配。"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
on_event: Callable[[Any], None] | None = None,
|
|
32
|
+
*,
|
|
33
|
+
pending_maxlen: int = _PENDING_MAXLEN,
|
|
34
|
+
) -> None:
|
|
35
|
+
self._pending: deque[Any] = deque(maxlen=pending_maxlen)
|
|
36
|
+
self._live_callback: Callable[[Any], None] | None = on_event
|
|
37
|
+
|
|
38
|
+
def emit(self, event: Any) -> None:
|
|
39
|
+
"""SDK 调用;任何异常不得影响主 agent 流程。"""
|
|
40
|
+
try:
|
|
41
|
+
if self._live_callback is not None:
|
|
42
|
+
self._live_callback(event)
|
|
43
|
+
else:
|
|
44
|
+
self._pending.append(event)
|
|
45
|
+
except Exception:
|
|
46
|
+
logger.debug("AutoModeEventSink.emit failed", exc_info=True)
|
|
47
|
+
|
|
48
|
+
def replace_callback(self, on_event: Callable[[Any], None]) -> None:
|
|
49
|
+
"""切换 live 回调;不 flush、不补发历史事件。"""
|
|
50
|
+
self._live_callback = on_event
|
|
51
|
+
|
|
52
|
+
def drain_pending(self) -> list[Any]:
|
|
53
|
+
"""取出并清空 pending 缓冲(attach 时由 bridge flush)。"""
|
|
54
|
+
items = list(self._pending)
|
|
55
|
+
self._pending.clear()
|
|
56
|
+
return items
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def pending_count(self) -> int:
|
|
60
|
+
return len(self._pending)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
bridge/auto_mode_status.py — footer auto mode 状态段。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
根据运行中 PolicyEngine / AutoModeConfig 生成 status line 片段。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
InputAreaWidget._update_status_line → format_status_line。
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def format_auto_mode_segment(*, enabled: bool, use_classifier: bool) -> str:
|
|
17
|
+
"""返回 Rich markup 片段,如 `` · [green]auto: classifier-on[/]``。"""
|
|
18
|
+
if not enabled:
|
|
19
|
+
return " · [dim]auto: off[/]"
|
|
20
|
+
if use_classifier:
|
|
21
|
+
return " · [green]auto: classifier-on[/]"
|
|
22
|
+
return " · [blue]auto: fast-only[/]"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def auto_mode_segment_from_loader(loader: Any) -> str:
|
|
26
|
+
"""从 ToolRuntimeLoader 读取 AutoModeConfig。"""
|
|
27
|
+
policy = getattr(loader, "_policy", None)
|
|
28
|
+
cfg = getattr(policy, "_config", None) if policy is not None else None
|
|
29
|
+
auto_cfg = getattr(cfg, "auto_mode", None) if cfg is not None else None
|
|
30
|
+
if auto_cfg is None:
|
|
31
|
+
return format_auto_mode_segment(enabled=False, use_classifier=False)
|
|
32
|
+
return format_auto_mode_segment(
|
|
33
|
+
enabled=bool(getattr(auto_cfg, "enabled", False)),
|
|
34
|
+
use_classifier=bool(getattr(auto_cfg, "use_classifier", True)),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def pending_deny_dot(session_store: Any | None) -> str:
|
|
39
|
+
"""pending deny override 红点。"""
|
|
40
|
+
if session_store is None:
|
|
41
|
+
return ""
|
|
42
|
+
summary = getattr(session_store, "summary", None)
|
|
43
|
+
if not callable(summary):
|
|
44
|
+
return ""
|
|
45
|
+
try:
|
|
46
|
+
pending = int(summary().get("pending_deny_overrides", 0))
|
|
47
|
+
except Exception:
|
|
48
|
+
return ""
|
|
49
|
+
return " [red]●[/]" if pending > 0 else ""
|