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.
Files changed (236) hide show
  1. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/PKG-INFO +3 -9
  2. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/__init__.py +1 -1
  3. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/app.py +119 -14
  4. langchain-agentx-cli-0.3.7/langchain_agentx_cli/auto_mode_config.py +108 -0
  5. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/bootstrap.py +2 -2
  6. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/__init__.py +6 -0
  7. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/auto_mode_config_apply.py +83 -0
  8. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/auto_mode_messages.py +39 -0
  9. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/auto_mode_sink.py +60 -0
  10. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/auto_mode_status.py +49 -0
  11. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/boundary_inspector.py +150 -0
  12. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/cli_l3_user_ui_queue.py +114 -0
  13. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/deny_override.py +352 -0
  14. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/hook_constants.py +34 -0
  15. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/hook_payload.py +66 -0
  16. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/permission_mode_apply.py +73 -0
  17. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/permission_response_builder.py +73 -0
  18. langchain-agentx-cli-0.3.7/langchain_agentx_cli/bridge/permission_user_ui.py +25 -0
  19. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/bridge/session_bridge.py +193 -35
  20. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/cli.py +146 -1
  21. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/__init__.py +14 -0
  22. langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/auto_mode.py +345 -0
  23. langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/doctor.py +74 -0
  24. langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/grant.py +122 -0
  25. langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/grants.py +54 -0
  26. langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/permissions.py +95 -0
  27. langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/revoke.py +44 -0
  28. langchain-agentx-cli-0.3.7/langchain_agentx_cli/commands/builtin/roots.py +47 -0
  29. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/config.py +39 -5
  30. langchain-agentx-cli-0.3.7/langchain_agentx_cli/health_report.py +389 -0
  31. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/keybindings/bindings.py +2 -2
  32. langchain-agentx-cli-0.3.7/langchain_agentx_cli/launch_config_validator.py +65 -0
  33. langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/audit_subscriber.py +175 -0
  34. langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/config.py +103 -0
  35. langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/failure_counts.py +38 -0
  36. langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/failure_observation.py +64 -0
  37. langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/log_rotator.py +107 -0
  38. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/observation/observer.py +41 -3
  39. langchain-agentx-cli-0.3.7/langchain_agentx_cli/observation/session_context.py +55 -0
  40. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/permissions/__init__.py +11 -5
  41. langchain-agentx-cli-0.3.7/langchain_agentx_cli/permissions/factory.py +129 -0
  42. langchain-agentx-cli-0.3.7/langchain_agentx_cli/permissions/mode.py +96 -0
  43. langchain-agentx-cli-0.3.7/langchain_agentx_cli/permissions/policy.py +76 -0
  44. langchain-agentx-cli-0.3.7/langchain_agentx_cli/permissions/session_mode.py +45 -0
  45. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/prompts/__init__.py +6 -0
  46. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/prompts/assembler.py +6 -1
  47. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/prompts/sections.py +56 -0
  48. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/screens/repl.py +101 -7
  49. langchain-agentx-cli-0.3.7/langchain_agentx_cli/session_factory.py +251 -0
  50. langchain-agentx-cli-0.3.7/langchain_agentx_cli/session_headless.py +21 -0
  51. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/session_options.py +5 -1
  52. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/bootstrap.py +49 -0
  53. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/memory_paths.py +284 -0
  54. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/__init__.py +4 -2
  55. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/consumer.py +323 -0
  56. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/dialog.py +145 -0
  57. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/models.py +1 -0
  58. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/persistent_rules.py +255 -0
  59. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/__init__.py +56 -0
  60. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/base.py +15 -0
  61. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/bash.py +17 -0
  62. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/fallback.py +8 -0
  63. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/presenters/file.py +11 -0
  64. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/__init__.py +76 -0
  65. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/auto_mode_deny.py +69 -0
  66. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/base.py +98 -0
  67. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/boundary/__init__.py +19 -0
  68. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/boundary/extract.py +90 -0
  69. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/boundary/request.py +147 -0
  70. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/fallback/__init__.py +6 -0
  71. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/fallback/request.py +26 -0
  72. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/__init__.py +7 -0
  73. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/_base.py +69 -0
  74. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/diff.py +187 -0
  75. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/edit/__init__.py +6 -0
  76. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/edit/request.py +26 -0
  77. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/filesystem/__init__.py +6 -0
  78. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/filesystem/request.py +35 -0
  79. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/paths.py +58 -0
  80. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/write/__init__.py +6 -0
  81. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/file/write/request.py +26 -0
  82. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/plan_mode/__init__.py +8 -0
  83. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/plan_mode/request.py +53 -0
  84. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/__init__.py +11 -0
  85. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/bash/__init__.py +6 -0
  86. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/bash/request.py +78 -0
  87. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/extract.py +66 -0
  88. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/shell/helpers.py +192 -0
  89. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/skill/__init__.py +7 -0
  90. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/skill/request.py +29 -0
  91. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/webfetch/__init__.py +7 -0
  92. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/requests/webfetch/request.py +124 -0
  93. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/permissions/router.py +158 -0
  94. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/widgets/health_view.py +95 -0
  95. langchain-agentx-cli-0.3.7/langchain_agentx_cli/tui/workspace_trust.py +47 -0
  96. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/welcome.py +8 -1
  97. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/footer.py +57 -0
  98. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/input_area.py +132 -6
  99. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/message_events.py +127 -3
  100. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/message_list.py +494 -58
  101. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/__init__.py +6 -0
  102. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/assistant_message.py +29 -11
  103. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/messages/auto_mode_chip.py +67 -0
  104. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/messages/hook_message.py +130 -0
  105. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/thinking_message.py +11 -2
  106. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/messages/tool_result.py +42 -0
  107. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/permission_inline.py +317 -0
  108. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/__init__.py +65 -0
  109. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/expand_hint.py +45 -0
  110. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/full_output.py +25 -0
  111. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/message_layout.py +104 -0
  112. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/shell_output.py +102 -0
  113. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/presentation/view_mode.py +44 -0
  114. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/status_bar.py +46 -0
  115. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/task_panel.py +2 -4
  116. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/__init__.py +34 -0
  117. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/base.py +87 -0
  118. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/blocked_view.py +84 -0
  119. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/error_view.py +137 -0
  120. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tool_result/success_view.py +50 -0
  121. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/__init__.py +7 -1
  122. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/agent/widget.py +2 -2
  123. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/ask_user_question/widget.py +1 -1
  124. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tools/base.py +573 -0
  125. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tools/bash/widget.py +301 -0
  126. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/batch_edit/widget.py +2 -2
  127. langchain-agentx-cli-0.3.7/langchain_agentx_cli/widgets/tools/helpers.py +600 -0
  128. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/skill/widget.py +1 -1
  129. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/webfetch/widget.py +2 -2
  130. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/websearch/widget.py +2 -2
  131. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/write/widget.py +22 -4
  132. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/PKG-INFO +3 -9
  133. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/SOURCES.txt +81 -8
  134. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/requires.txt +1 -1
  135. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/pyproject.toml +14 -3
  136. langchain_agentx_cli-0.3.2/langchain_agentx_cli/bridge/__init__.py +0 -5
  137. langchain_agentx_cli-0.3.2/langchain_agentx_cli/observation/config.py +0 -35
  138. langchain_agentx_cli-0.3.2/langchain_agentx_cli/permissions/factory.py +0 -93
  139. langchain_agentx_cli-0.3.2/langchain_agentx_cli/permissions/policy.py +0 -119
  140. langchain_agentx_cli-0.3.2/langchain_agentx_cli/session_factory.py +0 -132
  141. langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/consumer.py +0 -188
  142. langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/dialog.py +0 -132
  143. langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/__init__.py +0 -63
  144. langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/base.py +0 -69
  145. langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/bash.py +0 -124
  146. langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/fallback.py +0 -25
  147. langchain_agentx_cli-0.3.2/langchain_agentx_cli/tui/permissions/presenters/file.py +0 -87
  148. langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/messages/hook_message.py +0 -72
  149. langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/permission_inline.py +0 -145
  150. langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/tools/base.py +0 -286
  151. langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/tools/bash/widget.py +0 -110
  152. langchain_agentx_cli-0.3.2/langchain_agentx_cli/widgets/tools/helpers.py +0 -309
  153. langchain_agentx_cli-0.3.2/tests/test_app_interrupt.py +0 -98
  154. langchain_agentx_cli-0.3.2/tests/test_llm_config_chain.py +0 -182
  155. langchain_agentx_cli-0.3.2/tests/test_repl_commands.py +0 -84
  156. langchain_agentx_cli-0.3.2/tests/test_repl_submit_flow.py +0 -69
  157. langchain_agentx_cli-0.3.2/tests/test_repl_ui.py +0 -90
  158. langchain_agentx_cli-0.3.2/tests/test_smoke.py +0 -124
  159. langchain_agentx_cli-0.3.2/tests/test_welcome.py +0 -59
  160. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/LICENSE +0 -0
  161. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/README.md +0 -0
  162. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/__main__.py +0 -0
  163. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/__init__.py +0 -0
  164. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/clear.py +0 -0
  165. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/compact.py +0 -0
  166. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/help.py +0 -0
  167. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/model.py +0 -0
  168. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/quit.py +0 -0
  169. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/builtin/theme.py +0 -0
  170. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/parser.py +0 -0
  171. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/providers/__init__.py +0 -0
  172. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/providers/sdk_commands.py +0 -0
  173. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/commands/registry.py +0 -0
  174. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/completion/__init__.py +0 -0
  175. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/completion/base.py +0 -0
  176. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/completion/command_source.py +0 -0
  177. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/completion/history_source.py +0 -0
  178. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/history/__init__.py +0 -0
  179. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/history/store.py +0 -0
  180. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/keybindings/__init__.py +0 -0
  181. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/llm_config.py +0 -0
  182. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/observation/__init__.py +0 -0
  183. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/prompts/system_prompt.py +0 -0
  184. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/screens/__init__.py +0 -0
  185. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/state/__init__.py +0 -0
  186. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/state/task_store.py +0 -0
  187. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/__init__.py +0 -0
  188. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/colors.py +0 -0
  189. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/detection.py +0 -0
  190. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/manager.py +0 -0
  191. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/settings.py +0 -0
  192. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/system_theme.py +0 -0
  193. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/themes.py +0 -0
  194. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/theme/watcher.py +0 -0
  195. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tools/__init__.py +0 -0
  196. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tools/registry.py +0 -0
  197. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/__init__.py +0 -0
  198. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/clipboard.py +0 -0
  199. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/message_selection.py +0 -0
  200. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/cache.py +0 -0
  201. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/component_manager.py +0 -0
  202. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/config.py +0 -0
  203. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/permissions/queue.py +0 -0
  204. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/tui/safe_screen.py +0 -0
  205. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/__init__.py +0 -0
  206. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/compact_progress.py +0 -0
  207. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/completion_overlay.py +0 -0
  208. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/error_message.py +0 -0
  209. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/rendering.py +0 -0
  210. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/messages/stop_hook_summary.py +0 -0
  211. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/pending_permission.py +0 -0
  212. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/permission_keybindings.py +0 -0
  213. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/spinner.py +0 -0
  214. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/agent/__init__.py +0 -0
  215. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/ask_user_question/__init__.py +0 -0
  216. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/bash/__init__.py +0 -0
  217. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/batch_edit/__init__.py +0 -0
  218. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/edit/__init__.py +0 -0
  219. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/edit/widget.py +0 -0
  220. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/glob/__init__.py +0 -0
  221. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/glob/widget.py +0 -0
  222. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/grep/__init__.py +0 -0
  223. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/grep/widget.py +0 -0
  224. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/read/__init__.py +0 -0
  225. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/read/widget.py +0 -0
  226. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/skill/__init__.py +0 -0
  227. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/user_message/__init__.py +0 -0
  228. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/user_message/widget.py +0 -0
  229. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/webfetch/__init__.py +0 -0
  230. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/websearch/__init__.py +0 -0
  231. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli/widgets/tools/write/__init__.py +0 -0
  232. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/dependency_links.txt +0 -0
  233. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/entry_points.txt +0 -0
  234. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/not-zip-safe +0 -0
  235. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/langchain_agentx_cli.egg-info/top_level.txt +0 -0
  236. {langchain_agentx_cli-0.3.2 → langchain-agentx-cli-0.3.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.1
2
2
  Name: langchain-agentx-cli
3
- Version: 0.3.2
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
- Requires-Dist: pytest>=8; extra == "dev"
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
 
@@ -1,3 +1,3 @@
1
1
  """langchain_agentx_cli:依托 langchain_agentx_python SDK 的终端 CLI/TUI(CC Ink 迁移)。"""
2
2
 
3
- __version__ = "0.3.2"
3
+ __version__ = "0.3.7"
@@ -2,17 +2,22 @@
2
2
  app.py — Textual ReplApp 容器。
3
3
 
4
4
  职责:
5
- 应用生命周期、SessionBridge、命令注册表、历史、双次 Ctrl+C 退出。
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
- _CANCEL_HINT = "已取消当前生成。再次按 Ctrl+C 退出。"
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
- ("ctrl+c", "cancel_stream", "Cancel / Quit"),
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
- self._exit_armed = False
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._exit_armed = False
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._exit_armed = True
169
- self.notify(_CANCEL_HINT, severity="warning", timeout=4)
248
+ self.notify("已取消当前生成", severity="warning", timeout=2)
170
249
  return
171
- if self._exit_armed:
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._exit_armed = True
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;AgentSession 创建失败由 session_factory 抛出 CliEnvironmentError
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.2.3"\n'
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,6 @@
1
+ """TUI 与 SDK 桥接层。"""
2
+
3
+ from .auto_mode_sink import AutoModeEventSink
4
+ from .session_bridge import MVP_ADAPTER_CONFIG, SessionBridge
5
+
6
+ __all__ = ["AutoModeEventSink", "MVP_ADAPTER_CONFIG", "SessionBridge"]
@@ -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 ""