langchain-agentx-python 0.1__py3-none-any.whl

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 (354) hide show
  1. langchain_agentx/__init__.py +46 -0
  2. langchain_agentx/command/__init__.py +28 -0
  3. langchain_agentx/command/builtin/__init__.py +25 -0
  4. langchain_agentx/command/builtin/clear.py +33 -0
  5. langchain_agentx/command/builtin/compact.py +33 -0
  6. langchain_agentx/command/builtin/memory.py +37 -0
  7. langchain_agentx/command/builtin/reload_plugins.py +42 -0
  8. langchain_agentx/command/context.py +30 -0
  9. langchain_agentx/command/dispatcher.py +183 -0
  10. langchain_agentx/command/registry.py +110 -0
  11. langchain_agentx/command/result.py +25 -0
  12. langchain_agentx/command/types.py +41 -0
  13. langchain_agentx/config/__init__.py +14 -0
  14. langchain_agentx/loop/__init__.py +47 -0
  15. langchain_agentx/loop/config/__init__.py +20 -0
  16. langchain_agentx/loop/config/agent_config.py +66 -0
  17. langchain_agentx/loop/config/agent_loop_config.py +72 -0
  18. langchain_agentx/loop/config/model_context_resolver.py +105 -0
  19. langchain_agentx/loop/config/runtime_settings.py +50 -0
  20. langchain_agentx/loop/config/token_estimator.py +133 -0
  21. langchain_agentx/loop/context/__init__.py +66 -0
  22. langchain_agentx/loop/context/blocking_guard.py +97 -0
  23. langchain_agentx/loop/context/compaction_service.py +60 -0
  24. langchain_agentx/loop/context/message_utils.py +56 -0
  25. langchain_agentx/loop/context/pipeline.py +127 -0
  26. langchain_agentx/loop/context/settings.py +103 -0
  27. langchain_agentx/loop/context/stages/__init__.py +29 -0
  28. langchain_agentx/loop/context/stages/autocompact.py +140 -0
  29. langchain_agentx/loop/context/stages/base.py +32 -0
  30. langchain_agentx/loop/context/stages/collapse.py +76 -0
  31. langchain_agentx/loop/context/stages/microcompact.py +76 -0
  32. langchain_agentx/loop/context/stages/noop.py +33 -0
  33. langchain_agentx/loop/context/stages/snip.py +71 -0
  34. langchain_agentx/loop/context/stages/tool_result_budget.py +69 -0
  35. langchain_agentx/loop/context/types.py +79 -0
  36. langchain_agentx/loop/exit/__init__.py +1 -0
  37. langchain_agentx/loop/exit/exit_logic.py +320 -0
  38. langchain_agentx/loop/exit/reason_codes.py +39 -0
  39. langchain_agentx/loop/graph/__init__.py +5 -0
  40. langchain_agentx/loop/graph/builtin_loop_control.py +197 -0
  41. langchain_agentx/loop/graph/factory.py +1409 -0
  42. langchain_agentx/loop/graph/graph_edges.py +820 -0
  43. langchain_agentx/loop/hook/__init__.py +48 -0
  44. langchain_agentx/loop/hook/async_hook_runner.py +62 -0
  45. langchain_agentx/loop/hook/config.py +280 -0
  46. langchain_agentx/loop/hook/engine.py +321 -0
  47. langchain_agentx/loop/hook/executors/__init__.py +9 -0
  48. langchain_agentx/loop/hook/executors/agent.py +107 -0
  49. langchain_agentx/loop/hook/executors/command.py +230 -0
  50. langchain_agentx/loop/hook/executors/http.py +114 -0
  51. langchain_agentx/loop/hook/executors/prompt.py +92 -0
  52. langchain_agentx/loop/hook/graph_wiring.py +134 -0
  53. langchain_agentx/loop/hook/registry.py +262 -0
  54. langchain_agentx/loop/hook/trust.py +43 -0
  55. langchain_agentx/loop/hook/types.py +110 -0
  56. langchain_agentx/loop/injection/__init__.py +13 -0
  57. langchain_agentx/loop/injection/dedup.py +74 -0
  58. langchain_agentx/loop/loop_abort.py +36 -0
  59. langchain_agentx/loop/model/__init__.py +1 -0
  60. langchain_agentx/loop/model/model_node.py +648 -0
  61. langchain_agentx/loop/model/model_nodes.py +661 -0
  62. langchain_agentx/loop/model/orphan_tool_results.py +38 -0
  63. langchain_agentx/loop/model/retrier.py +307 -0
  64. langchain_agentx/loop/model/retry_bridge.py +58 -0
  65. langchain_agentx/loop/model/retry_events.py +35 -0
  66. langchain_agentx/loop/model/retry_policy.py +56 -0
  67. langchain_agentx/loop/model/schema_and_format.py +153 -0
  68. langchain_agentx/loop/model/tool_and_model_binding.py +227 -0
  69. langchain_agentx/loop/model/tool_call_degradation_corrector.py +443 -0
  70. langchain_agentx/loop/model/tool_transcript_guard.py +225 -0
  71. langchain_agentx/loop/prompt/__init__.py +95 -0
  72. langchain_agentx/loop/prompt/builder.py +61 -0
  73. langchain_agentx/loop/prompt/builtin.py +218 -0
  74. langchain_agentx/loop/prompt/compact.py +408 -0
  75. langchain_agentx/loop/prompt/sections.py +120 -0
  76. langchain_agentx/loop/runtime/__init__.py +19 -0
  77. langchain_agentx/loop/runtime/context.py +34 -0
  78. langchain_agentx/loop/runtime/context_factory.py +107 -0
  79. langchain_agentx/loop/runtime/subagent_execution_paths.py +68 -0
  80. langchain_agentx/loop/subagent/__init__.py +53 -0
  81. langchain_agentx/loop/subagent/async_runner.py +215 -0
  82. langchain_agentx/loop/subagent/context.py +209 -0
  83. langchain_agentx/loop/subagent/fork_worktree_notice.py +25 -0
  84. langchain_agentx/loop/subagent/graph.py +72 -0
  85. langchain_agentx/loop/subagent/orchestrator.py +391 -0
  86. langchain_agentx/loop/subagent/progress.py +30 -0
  87. langchain_agentx/loop/subagent/prompt.py +52 -0
  88. langchain_agentx/loop/subagent/runner.py +504 -0
  89. langchain_agentx/loop/subagent/transcript.py +172 -0
  90. langchain_agentx/memory/__init__.py +2 -0
  91. langchain_agentx/memory/instruction/__init__.py +12 -0
  92. langchain_agentx/memory/instruction/loader.py +325 -0
  93. langchain_agentx/memory/instruction/resolver.py +24 -0
  94. langchain_agentx/memory/instruction/runtime.py +83 -0
  95. langchain_agentx/memory/instruction/sections.py +83 -0
  96. langchain_agentx/memory/instruction/types.py +59 -0
  97. langchain_agentx/memory/memdir/__init__.py +77 -0
  98. langchain_agentx/memory/memdir/age.py +36 -0
  99. langchain_agentx/memory/memdir/agent_memory.py +380 -0
  100. langchain_agentx/memory/memdir/extractor.py +309 -0
  101. langchain_agentx/memory/memdir/loader.py +187 -0
  102. langchain_agentx/memory/memdir/paths.py +63 -0
  103. langchain_agentx/memory/memdir/recall.py +45 -0
  104. langchain_agentx/memory/memdir/runtime.py +43 -0
  105. langchain_agentx/memory/memdir/scan.py +135 -0
  106. langchain_agentx/memory/memdir/types.py +104 -0
  107. langchain_agentx/memory/session/__init__.py +76 -0
  108. langchain_agentx/memory/session/compact_bridge.py +208 -0
  109. langchain_agentx/memory/session/prompts.py +172 -0
  110. langchain_agentx/memory/session/session_memory.py +282 -0
  111. langchain_agentx/observability/__init__.py +67 -0
  112. langchain_agentx/observability/evaluation/__init__.py +17 -0
  113. langchain_agentx/observability/evaluation/checkers/__init__.py +18 -0
  114. langchain_agentx/observability/evaluation/checkers/base.py +34 -0
  115. langchain_agentx/observability/evaluation/checkers/compaction.py +38 -0
  116. langchain_agentx/observability/evaluation/checkers/degradation.py +50 -0
  117. langchain_agentx/observability/evaluation/checkers/exit_quality.py +42 -0
  118. langchain_agentx/observability/evaluation/checkers/session_memory.py +45 -0
  119. langchain_agentx/observability/evaluation/checkers/tool_behavior.py +53 -0
  120. langchain_agentx/observability/evaluation/retention_scheduler.py +67 -0
  121. langchain_agentx/observability/evaluation/service.py +102 -0
  122. langchain_agentx/observability/evaluation/state.py +32 -0
  123. langchain_agentx/observability/evaluation/store.py +258 -0
  124. langchain_agentx/observability/events/__init__.py +15 -0
  125. langchain_agentx/observability/events/langchain_agentx_event_adapter.py +832 -0
  126. langchain_agentx/observability/logging/__init__.py +15 -0
  127. langchain_agentx/observability/logging/debug_burst.py +95 -0
  128. langchain_agentx/observability/logging/logging_config.py +178 -0
  129. langchain_agentx/observability/logging/logging_contract.py +65 -0
  130. langchain_agentx/observability/replay/__init__.py +35 -0
  131. langchain_agentx/observability/replay/cli.py +91 -0
  132. langchain_agentx/observability/replay/service.py +83 -0
  133. langchain_agentx/observability/replay/store.py +278 -0
  134. langchain_agentx/observability/replay/ui.py +47 -0
  135. langchain_agentx/observability/trace/__init__.py +25 -0
  136. langchain_agentx/observability/trace/collector.py +560 -0
  137. langchain_agentx/observability/trace/event_emitter.py +183 -0
  138. langchain_agentx/observability/trace/hook_event_emitter.py +49 -0
  139. langchain_agentx/observability/trace/models.py +144 -0
  140. langchain_agentx/observability/trace/sqlite_store.py +873 -0
  141. langchain_agentx/observability/trace/trace_callback.py +295 -0
  142. langchain_agentx/observability/trace/trace_lifecycle_collector.py +114 -0
  143. langchain_agentx/plugin/__init__.py +26 -0
  144. langchain_agentx/plugin/builtin.py +53 -0
  145. langchain_agentx/plugin/config.py +113 -0
  146. langchain_agentx/plugin/loader.py +386 -0
  147. langchain_agentx/plugin/manifest.py +154 -0
  148. langchain_agentx/plugin/registries.py +211 -0
  149. langchain_agentx/plugin/types.py +142 -0
  150. langchain_agentx/provider/__init__.py +27 -0
  151. langchain_agentx/provider/anthropic.py +121 -0
  152. langchain_agentx/provider/compatible_chat_openai.py +86 -0
  153. langchain_agentx/provider/env.py +45 -0
  154. langchain_agentx/provider/model_profile.py +156 -0
  155. langchain_agentx/provider/openai.py +89 -0
  156. langchain_agentx/session/__init__.py +17 -0
  157. langchain_agentx/session/agent_session.py +320 -0
  158. langchain_agentx/session/conversation_factory.py +87 -0
  159. langchain_agentx/session/conversation_recovery.py +156 -0
  160. langchain_agentx/session/conversation_session.py +198 -0
  161. langchain_agentx/session/factory.py +143 -0
  162. langchain_agentx/session/protocol.py +25 -0
  163. langchain_agentx/task_runtime/__init__.py +113 -0
  164. langchain_agentx/task_runtime/core/__init__.py +51 -0
  165. langchain_agentx/task_runtime/core/ids.py +33 -0
  166. langchain_agentx/task_runtime/core/interfaces.py +115 -0
  167. langchain_agentx/task_runtime/core/notification_priority.py +19 -0
  168. langchain_agentx/task_runtime/core/types.py +136 -0
  169. langchain_agentx/task_runtime/integrations/__init__.py +33 -0
  170. langchain_agentx/task_runtime/integrations/loop_adapter.py +91 -0
  171. langchain_agentx/task_runtime/integrations/loop_integration.py +61 -0
  172. langchain_agentx/task_runtime/integrations/prefetch_providers.py +108 -0
  173. langchain_agentx/task_runtime/integrations/provider_factory.py +103 -0
  174. langchain_agentx/task_runtime/integrations/queued_command_provider.py +184 -0
  175. langchain_agentx/task_runtime/integrations/sqlite_queued_command_provider.py +338 -0
  176. langchain_agentx/task_runtime/integrations/tool_use_summary_provider.py +254 -0
  177. langchain_agentx/task_runtime/orchestrator/__init__.py +5 -0
  178. langchain_agentx/task_runtime/orchestrator/runtime.py +386 -0
  179. langchain_agentx/task_runtime/output/__init__.py +5 -0
  180. langchain_agentx/task_runtime/output/sink.py +64 -0
  181. langchain_agentx/task_runtime/policy/__init__.py +11 -0
  182. langchain_agentx/task_runtime/policy/withhold_visibility.py +32 -0
  183. langchain_agentx/task_runtime/queue/__init__.py +5 -0
  184. langchain_agentx/task_runtime/queue/in_memory.py +55 -0
  185. langchain_agentx/task_runtime/skill_prefetch/__init__.py +4 -0
  186. langchain_agentx/task_runtime/skill_prefetch/attachments.py +46 -0
  187. langchain_agentx/task_runtime/skill_prefetch/models.py +37 -0
  188. langchain_agentx/task_runtime/skill_prefetch/provider.py +344 -0
  189. langchain_agentx/task_runtime/store/__init__.py +6 -0
  190. langchain_agentx/task_runtime/store/in_memory.py +81 -0
  191. langchain_agentx/task_runtime/store/sqlite_store.py +281 -0
  192. langchain_agentx/task_runtime/tasks/__init__.py +76 -0
  193. langchain_agentx/task_runtime/tasks/ai_analysis/__init__.py +15 -0
  194. langchain_agentx/task_runtime/tasks/ai_analysis/base.py +41 -0
  195. langchain_agentx/task_runtime/tasks/ai_analysis/evaluation.py +67 -0
  196. langchain_agentx/task_runtime/tasks/ai_analysis/registry.py +36 -0
  197. langchain_agentx/task_runtime/tasks/ai_analysis/scheduler.py +70 -0
  198. langchain_agentx/task_runtime/tasks/base/__init__.py +6 -0
  199. langchain_agentx/task_runtime/tasks/base/contracts.py +24 -0
  200. langchain_agentx/task_runtime/tasks/custom/__init__.py +7 -0
  201. langchain_agentx/task_runtime/tasks/custom/executor.py +60 -0
  202. langchain_agentx/task_runtime/tasks/custom/notification.py +7 -0
  203. langchain_agentx/task_runtime/tasks/custom/semantics.py +13 -0
  204. langchain_agentx/task_runtime/tasks/custom/spec.py +33 -0
  205. langchain_agentx/task_runtime/tasks/dream_task/__init__.py +15 -0
  206. langchain_agentx/task_runtime/tasks/dream_task/executor.py +61 -0
  207. langchain_agentx/task_runtime/tasks/dream_task/notification.py +19 -0
  208. langchain_agentx/task_runtime/tasks/dream_task/semantics.py +13 -0
  209. langchain_agentx/task_runtime/tasks/dream_task/spec.py +35 -0
  210. langchain_agentx/task_runtime/tasks/dream_task/state.py +17 -0
  211. langchain_agentx/task_runtime/tasks/in_process_teammate/__init__.py +12 -0
  212. langchain_agentx/task_runtime/tasks/in_process_teammate/executor.py +36 -0
  213. langchain_agentx/task_runtime/tasks/in_process_teammate/notification.py +25 -0
  214. langchain_agentx/task_runtime/tasks/in_process_teammate/semantics.py +13 -0
  215. langchain_agentx/task_runtime/tasks/in_process_teammate/spec.py +63 -0
  216. langchain_agentx/task_runtime/tasks/local_agent/__init__.py +14 -0
  217. langchain_agentx/task_runtime/tasks/local_agent/executor.py +33 -0
  218. langchain_agentx/task_runtime/tasks/local_agent/notification.py +21 -0
  219. langchain_agentx/task_runtime/tasks/local_agent/runner.py +43 -0
  220. langchain_agentx/task_runtime/tasks/local_agent/semantics.py +13 -0
  221. langchain_agentx/task_runtime/tasks/local_agent/spec.py +31 -0
  222. langchain_agentx/task_runtime/tasks/local_bash/__init__.py +13 -0
  223. langchain_agentx/task_runtime/tasks/local_bash/executor.py +95 -0
  224. langchain_agentx/task_runtime/tasks/local_bash/notification.py +22 -0
  225. langchain_agentx/task_runtime/tasks/local_bash/semantics.py +13 -0
  226. langchain_agentx/task_runtime/tasks/local_bash/spec.py +55 -0
  227. langchain_agentx/task_runtime/tasks/remote_agent/__init__.py +19 -0
  228. langchain_agentx/task_runtime/tasks/remote_agent/backend.py +76 -0
  229. langchain_agentx/task_runtime/tasks/remote_agent/executor.py +37 -0
  230. langchain_agentx/task_runtime/tasks/remote_agent/notification.py +22 -0
  231. langchain_agentx/task_runtime/tasks/remote_agent/semantics.py +13 -0
  232. langchain_agentx/task_runtime/tasks/remote_agent/spec.py +34 -0
  233. langchain_agentx/task_runtime/tasks/trace_cleanup/__init__.py +19 -0
  234. langchain_agentx/task_runtime/tasks/trace_cleanup/bootstrap.py +95 -0
  235. langchain_agentx/task_runtime/tasks/trace_cleanup/executor.py +66 -0
  236. langchain_agentx/task_runtime/tasks/trace_cleanup/scheduler.py +169 -0
  237. langchain_agentx/tool_runtime/__init__.py +90 -0
  238. langchain_agentx/tool_runtime/adapter.py +365 -0
  239. langchain_agentx/tool_runtime/base.py +319 -0
  240. langchain_agentx/tool_runtime/errors.py +190 -0
  241. langchain_agentx/tool_runtime/identical_call_cache.py +110 -0
  242. langchain_agentx/tool_runtime/loader.py +195 -0
  243. langchain_agentx/tool_runtime/models.py +260 -0
  244. langchain_agentx/tool_runtime/permission_context.py +78 -0
  245. langchain_agentx/tool_runtime/pipeline.py +621 -0
  246. langchain_agentx/tool_runtime/policy.py +447 -0
  247. langchain_agentx/tool_runtime/registry.py +81 -0
  248. langchain_agentx/tool_runtime/resolvers/__init__.py +27 -0
  249. langchain_agentx/tool_runtime/resolvers/agent_session.py +125 -0
  250. langchain_agentx/tool_runtime/resolvers/background.py +32 -0
  251. langchain_agentx/tool_runtime/resolvers/base.py +20 -0
  252. langchain_agentx/tool_runtime/resolvers/conversation.py +22 -0
  253. langchain_agentx/tool_runtime/resolvers/workflow.py +73 -0
  254. langchain_agentx/tool_runtime/session_store.py +132 -0
  255. langchain_agentx/tool_runtime/smoke_test_runtime.py +294 -0
  256. langchain_agentx/tool_runtime/state_bridge.py +164 -0
  257. langchain_agentx/tools/__init__.py +26 -0
  258. langchain_agentx/tools/agent/__init__.py +9 -0
  259. langchain_agentx/tools/agent/backend.py +53 -0
  260. langchain_agentx/tools/agent/built_in/__init__.py +19 -0
  261. langchain_agentx/tools/agent/built_in/agentx_guide.py +65 -0
  262. langchain_agentx/tools/agent/built_in/explore.py +80 -0
  263. langchain_agentx/tools/agent/built_in/general.py +57 -0
  264. langchain_agentx/tools/agent/built_in/plan.py +89 -0
  265. langchain_agentx/tools/agent/built_in/statusline_setup.py +64 -0
  266. langchain_agentx/tools/agent/built_in/verification.py +120 -0
  267. langchain_agentx/tools/agent/builtin_subagent_loader.py +89 -0
  268. langchain_agentx/tools/agent/cwd_resolution.py +119 -0
  269. langchain_agentx/tools/agent/limits.py +26 -0
  270. langchain_agentx/tools/agent/loader.py +270 -0
  271. langchain_agentx/tools/agent/models.py +85 -0
  272. langchain_agentx/tools/agent/prompt.py +120 -0
  273. langchain_agentx/tools/agent/registry/__init__.py +18 -0
  274. langchain_agentx/tools/agent/registry/config.py +29 -0
  275. langchain_agentx/tools/agent/registry/registry.py +47 -0
  276. langchain_agentx/tools/agent/scope.py +137 -0
  277. langchain_agentx/tools/agent/tool.py +256 -0
  278. langchain_agentx/tools/bash/__init__.py +9 -0
  279. langchain_agentx/tools/bash/ast_security.py +571 -0
  280. langchain_agentx/tools/bash/backend.py +1447 -0
  281. langchain_agentx/tools/bash/bash_hardening.py +734 -0
  282. langchain_agentx/tools/bash/bash_runtime_contract.py +41 -0
  283. langchain_agentx/tools/bash/cwd_reporter.py +95 -0
  284. langchain_agentx/tools/bash/limits.py +71 -0
  285. langchain_agentx/tools/bash/mode_validation.py +282 -0
  286. langchain_agentx/tools/bash/models.py +131 -0
  287. langchain_agentx/tools/bash/observability.py +148 -0
  288. langchain_agentx/tools/bash/output_utils.py +200 -0
  289. langchain_agentx/tools/bash/path_security.py +2429 -0
  290. langchain_agentx/tools/bash/prompt.py +68 -0
  291. langchain_agentx/tools/bash/read_only_validation.py +589 -0
  292. langchain_agentx/tools/bash/result_presenter.py +324 -0
  293. langchain_agentx/tools/bash/sandbox_decision.py +133 -0
  294. langchain_agentx/tools/bash/security.py +311 -0
  295. langchain_agentx/tools/bash/sed_edit_parser.py +243 -0
  296. langchain_agentx/tools/bash/sed_validation.py +163 -0
  297. langchain_agentx/tools/bash/semantics.py +111 -0
  298. langchain_agentx/tools/bash/session_manager.py +205 -0
  299. langchain_agentx/tools/bash/session_runtime.py +290 -0
  300. langchain_agentx/tools/bash/shell_locator.py +191 -0
  301. langchain_agentx/tools/bash/task_runtime.py +91 -0
  302. langchain_agentx/tools/bash/tool.py +939 -0
  303. langchain_agentx/tools/bash/windows_shell_quoting.py +45 -0
  304. langchain_agentx/tools/glob/__init__.py +9 -0
  305. langchain_agentx/tools/glob/models.py +57 -0
  306. langchain_agentx/tools/glob/pagination.py +30 -0
  307. langchain_agentx/tools/glob/prompt.py +24 -0
  308. langchain_agentx/tools/glob/rg_list_backend.py +139 -0
  309. langchain_agentx/tools/glob/rg_pattern.py +44 -0
  310. langchain_agentx/tools/glob/tool.py +327 -0
  311. langchain_agentx/tools/grep/__init__.py +7 -0
  312. langchain_agentx/tools/grep/backend.py +375 -0
  313. langchain_agentx/tools/grep/models.py +127 -0
  314. langchain_agentx/tools/grep/prompt.py +30 -0
  315. langchain_agentx/tools/grep/rg_subprocess_controller.py +114 -0
  316. langchain_agentx/tools/grep/tool.py +475 -0
  317. langchain_agentx/tools/read/__init__.py +9 -0
  318. langchain_agentx/tools/read/backend.py +415 -0
  319. langchain_agentx/tools/read/limits.py +67 -0
  320. langchain_agentx/tools/read/models.py +156 -0
  321. langchain_agentx/tools/read/prompt.py +73 -0
  322. langchain_agentx/tools/read/tool.py +494 -0
  323. langchain_agentx/tools/ripgrep_plugin_exclusions.py +137 -0
  324. langchain_agentx/tools/skill/__init__.py +4 -0
  325. langchain_agentx/tools/skill/argument_substitution.py +80 -0
  326. langchain_agentx/tools/skill/loader.py +196 -0
  327. langchain_agentx/tools/skill/models.py +88 -0
  328. langchain_agentx/tools/skill/policy.py +80 -0
  329. langchain_agentx/tools/skill/prompt.py +35 -0
  330. langchain_agentx/tools/skill/tool.py +222 -0
  331. langchain_agentx/utils/__init__.py +0 -0
  332. langchain_agentx/utils/cwd.py +124 -0
  333. langchain_agentx/utils/host_platform.py +112 -0
  334. langchain_agentx/utils/path_hierarchy.py +48 -0
  335. langchain_agentx/utils/path_user_input.py +66 -0
  336. langchain_agentx/utils/rg_executable.py +18 -0
  337. langchain_agentx/utils/subprocess_text.py +101 -0
  338. langchain_agentx/utils/temp_paths.py +77 -0
  339. langchain_agentx/utils/unc_path.py +25 -0
  340. langchain_agentx/utils/win_reserved_paths.py +51 -0
  341. langchain_agentx/workflow/__init__.py +7 -0
  342. langchain_agentx/workflow/base.py +97 -0
  343. langchain_agentx/workflow/batch.py +55 -0
  344. langchain_agentx/workflow/dag.py +54 -0
  345. langchain_agentx/workspace/__init__.py +13 -0
  346. langchain_agentx/workspace/config.py +140 -0
  347. langchain_agentx/workspace/path_key_normalizer.py +30 -0
  348. langchain_agentx/workspace/resolver.py +74 -0
  349. langchain_agentx/workspace/validators.py +41 -0
  350. langchain_agentx_python-0.1.dist-info/LICENSE +201 -0
  351. langchain_agentx_python-0.1.dist-info/METADATA +513 -0
  352. langchain_agentx_python-0.1.dist-info/RECORD +354 -0
  353. langchain_agentx_python-0.1.dist-info/WHEEL +5 -0
  354. langchain_agentx_python-0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,76 @@
1
+ """
2
+ Microcompact 阶段:对 `ToolMessage` 做轻量规范化(对齐 CC microcompact「块级收紧」的低成本子集)。
3
+
4
+ 与 Claude Code 对齐:
5
+ - 对应 `query.ts` 传入 `deps.microcompact` 的意图:在 snip 之后进一步去掉 tool 输出中的冗余空白,降低无效 token;
6
+ - `ctx.query_source in microcompact_skip_query_sources` 时跳过,避免递归压缩路径(如 `compact`)死循环。
7
+
8
+ 设计要点:
9
+ - 不调用 LLM;仅 `ToolMessage` 参与,避免改写 `AIMessage` 中 JSON tool_calls 结构;
10
+ - 使用 `model_copy` 保持 LangChain 消息字段完整。
11
+
12
+ 注意:
13
+ - 不依赖 LangGraph;不修改 `should_end` / `finish_reason`。
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import re
19
+ from typing import Any
20
+
21
+ from langchain_core.messages import ToolMessage
22
+
23
+ from ..message_utils import estimate_tokens_from_chars, stringify_content
24
+ from ..settings import CompactionSettings, get_active_compaction_settings
25
+ from ..types import ContextCompactionContext, StageResult
26
+ from .base import CompactionStage
27
+
28
+
29
+ _BLANK_RUN = re.compile(r"\n{3,}")
30
+
31
+
32
+ def _normalize_tool_text(text: str) -> str:
33
+ lines = [ln.rstrip() for ln in text.splitlines()]
34
+ joined = "\n".join(lines)
35
+ return _BLANK_RUN.sub("\n\n", joined)
36
+
37
+
38
+ class MicrocompactStage(CompactionStage):
39
+ """CC 阶段 ③:microcompact(轻量规范化)。"""
40
+
41
+ def __init__(self, settings: CompactionSettings | None = None) -> None:
42
+ self._settings_override = settings
43
+
44
+ def _effective_settings(self) -> CompactionSettings:
45
+ return self._settings_override or get_active_compaction_settings()
46
+
47
+ @property
48
+ def name(self) -> str:
49
+ return "microcompact"
50
+
51
+ def run(self, messages: list[Any], ctx: ContextCompactionContext) -> StageResult:
52
+ s = self._effective_settings()
53
+ if ctx.query_source in s.microcompact_skip_query_sources:
54
+ return StageResult(messages=messages, tokens_freed=0)
55
+ changed = False
56
+ out: list[Any] = []
57
+ freed_chars = 0
58
+ for m in messages:
59
+ if not isinstance(m, ToolMessage):
60
+ out.append(m)
61
+ continue
62
+ text = stringify_content(m.content)
63
+ new_text = _normalize_tool_text(text)
64
+ if new_text == text:
65
+ out.append(m)
66
+ continue
67
+ freed_chars += len(text) - len(new_text)
68
+ out.append(m.model_copy(update={"content": new_text}))
69
+ changed = True
70
+ if not changed:
71
+ return StageResult(messages=messages, tokens_freed=0)
72
+ return StageResult(
73
+ messages=out,
74
+ tokens_freed=estimate_tokens_from_chars(freed_chars, s.num_chars_per_token),
75
+ extra={"microcompact_normalized": True},
76
+ )
@@ -0,0 +1,33 @@
1
+ """
2
+ 泛型占位阶段:无操作,仅透传 messages。
3
+
4
+ 与 Claude Code 对齐:
5
+ - 不对应单一 TS 步骤;用于单测或临时将某一槽位替换为恒等映射,而不引入真实 `ToolResultBudgetStage` 等实现。
6
+
7
+ 设计要点:
8
+ - 通过构造参数 `name` 区分阶段名,便于日志;**默认 CC 五段请使用 `stages/*.py` 中独立类**,而非本泛型类。
9
+
10
+ 注意:
11
+ - 生产默认流水线见 `DefaultCompactionStages.build()` / `ContextPipeline.with_default_stages()`(五段具名类)。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Any
17
+
18
+ from ..types import ContextCompactionContext, StageResult
19
+ from .base import CompactionStage
20
+
21
+
22
+ class NoOpCompactionStage(CompactionStage):
23
+ """透传消息列表,不修改内容。"""
24
+
25
+ def __init__(self, name: str) -> None:
26
+ self._name = name
27
+
28
+ @property
29
+ def name(self) -> str:
30
+ return self._name
31
+
32
+ def run(self, messages: list[Any], ctx: ContextCompactionContext) -> StageResult:
33
+ return StageResult(messages=messages, tokens_freed=0)
@@ -0,0 +1,71 @@
1
+ """
2
+ Snip 紧凑化阶段:对「非尾部」窗口内的超大 `ToolMessage` 截断(对齐 CC `snipCompactIfNeeded` 意图)。
3
+
4
+ 与 Claude Code 对齐:
5
+ - 对应 `snipCompactIfNeeded` / `services/compact/snipCompact.ts`:优先裁剪历史中早期 tool 大块,保留尾部对话连贯性;
6
+ - `StageResult.tokens_freed` 供 `ContextPipeline` 累加到 `ctx.snip_tokens_freed_carry`,与 CC `snipTokensFreed` 传入 autocompact 同向。
7
+
8
+ 设计要点:
9
+ - 仅截断索引 `< len(messages) - snip_preserve_tail_messages` 的 `ToolMessage`;
10
+ - 截断后内容 + `snip_suffix`,仍保留同一条 `ToolMessage`(不删消息条数,避免破坏 tool_calls 对齐)。
11
+
12
+ 注意:
13
+ - 不依赖 LangGraph;不修改 exit 相关 state 字段。
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Any
19
+
20
+ from langchain_core.messages import ToolMessage
21
+
22
+ from ..message_utils import estimate_tokens_from_chars, stringify_content
23
+ from ..settings import CompactionSettings, get_active_compaction_settings
24
+ from ..types import ContextCompactionContext, StageResult
25
+ from .base import CompactionStage
26
+
27
+
28
+ class SnipCompactStage(CompactionStage):
29
+ """CC 阶段 ②:历史侧 tool 内容 snip。"""
30
+
31
+ def __init__(self, settings: CompactionSettings | None = None) -> None:
32
+ self._settings_override = settings
33
+
34
+ def _effective_settings(self) -> CompactionSettings:
35
+ return self._settings_override or get_active_compaction_settings()
36
+
37
+ @property
38
+ def name(self) -> str:
39
+ return "snip_compact"
40
+
41
+ def run(self, messages: list[Any], ctx: ContextCompactionContext) -> StageResult:
42
+ _ = ctx
43
+ s = self._effective_settings()
44
+ if not messages:
45
+ return StageResult(messages=messages, tokens_freed=0)
46
+ n = len(messages)
47
+ preserve = min(max(0, s.snip_preserve_tail_messages), n)
48
+ cutoff = n - preserve
49
+ changed = False
50
+ out: list[Any] = []
51
+ freed_chars = 0
52
+ for i, m in enumerate(messages):
53
+ if i >= cutoff or not isinstance(m, ToolMessage):
54
+ out.append(m)
55
+ continue
56
+ text = stringify_content(m.content)
57
+ cap = s.snip_max_tool_content_chars
58
+ if len(text) <= cap:
59
+ out.append(m)
60
+ continue
61
+ new_text = text[:cap] + s.snip_suffix
62
+ freed_chars += len(text) - len(new_text)
63
+ out.append(m.model_copy(update={"content": new_text}))
64
+ changed = True
65
+ if not changed:
66
+ return StageResult(messages=messages, tokens_freed=0)
67
+ return StageResult(
68
+ messages=out,
69
+ tokens_freed=estimate_tokens_from_chars(freed_chars, s.num_chars_per_token),
70
+ extra={"snip_compact_applied": True},
71
+ )
@@ -0,0 +1,69 @@
1
+ """
2
+ 工具结果预算阶段:对单条 `ToolMessage` 做软字符上限(对齐 CC `applyToolResultBudget` 意图)。
3
+
4
+ 与 Claude Code 对齐:
5
+ - 对应 `query.ts` 中 `messagesForQuery` 链上的 `applyToolResultBudget`:在会话级流水线入口收紧超大 tool 输出,避免单条结果撑爆窗口。
6
+
7
+ 设计要点:
8
+ - 仅处理 `langchain_core.messages.ToolMessage`;`name` 落在 `CompactionSettings.prune_protected_tools` 的不截断(如 CC 侧 skill 类结果);
9
+ - 使用 `model_copy(update={"content": ...})` 保持 `tool_call_id` / `name` 与 LangChain 消息契约一致。
10
+
11
+ 注意:
12
+ - 与 `tool_runtime` 单条落盘截断分工见设计文档;此处是会话 `messages` 级预算。
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import Any
18
+
19
+ from langchain_core.messages import ToolMessage
20
+
21
+ from ..message_utils import estimate_tokens_from_chars, stringify_content
22
+ from ..settings import CompactionSettings, get_active_compaction_settings
23
+ from ..types import ContextCompactionContext, StageResult
24
+ from .base import CompactionStage
25
+
26
+
27
+ class ToolResultBudgetStage(CompactionStage):
28
+ """CC 阶段 ①:tool result 软上限。"""
29
+
30
+ def __init__(self, settings: CompactionSettings | None = None) -> None:
31
+ self._settings_override = settings
32
+
33
+ def _effective_settings(self) -> CompactionSettings:
34
+ return self._settings_override or get_active_compaction_settings()
35
+
36
+ @property
37
+ def name(self) -> str:
38
+ return "tool_result_budget"
39
+
40
+ def run(self, messages: list[Any], ctx: ContextCompactionContext) -> StageResult:
41
+ _ = ctx
42
+ s = self._effective_settings()
43
+ changed = False
44
+ out: list[Any] = []
45
+ freed_chars = 0
46
+ for m in messages:
47
+ if not isinstance(m, ToolMessage):
48
+ out.append(m)
49
+ continue
50
+ tool_name = (m.name or "").strip()
51
+ if tool_name in s.prune_protected_tools:
52
+ out.append(m)
53
+ continue
54
+ text = stringify_content(m.content)
55
+ cap = s.tool_result_max_chars_per_message
56
+ if len(text) <= cap:
57
+ out.append(m)
58
+ continue
59
+ new_text = text[:cap] + s.tool_result_budget_suffix
60
+ freed_chars += len(text) - len(new_text)
61
+ out.append(m.model_copy(update={"content": new_text}))
62
+ changed = True
63
+ if not changed:
64
+ return StageResult(messages=messages, tokens_freed=0)
65
+ return StageResult(
66
+ messages=out,
67
+ tokens_freed=estimate_tokens_from_chars(freed_chars, s.num_chars_per_token),
68
+ extra={"tool_result_budget_truncated": True},
69
+ )
@@ -0,0 +1,79 @@
1
+ """
2
+ 上下文压缩流水线的共享类型(ContextCompactionContext、StageResult 等)。
3
+
4
+ 与 Claude Code 对齐:
5
+ - `ContextCompactionContext` 承载 `query.ts` 中传入 `deps.microcompact` / `deps.autocompact` 的
6
+ 同类信息(model、snip 释放 token 累计、query_source 递归防护等),随阶段演进补齐。
7
+
8
+ 设计要点:
9
+ - 使用 dataclass,避免裸 dict 魔法键;
10
+ - 不依赖 LangGraph;不修改 should_end / finish_reason。
11
+
12
+ 注意:
13
+ - `TokenWarningState` 供 `blocking_guard` 与 `compaction_pipeline_meta` 观测对齐 CC token 告警语义。
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from dataclasses import dataclass, field
19
+ from typing import Any, Literal, Mapping
20
+
21
+ TokenWarningLevel = Literal["ok", "warn", "block_compact_llm", "block_main_model"]
22
+
23
+
24
+ @dataclass
25
+ class CompactionConfig:
26
+ """各阶段阈值与开关占位;后续与环境变量 / feature flag 对齐 CC。"""
27
+
28
+ # 预留:如 AUTOCOMPACT_BUFFER_TOKENS 等价项
29
+ pass
30
+
31
+
32
+ @dataclass
33
+ class ContextCompactionContext:
34
+ """单轮 `prune_and_compress` 节点执行时的流水线上下文。"""
35
+
36
+ model: Any | None = None
37
+ snip_tokens_freed_carry: int = 0
38
+ query_source: str | None = None
39
+ config: CompactionConfig = field(default_factory=CompactionConfig)
40
+
41
+ @classmethod
42
+ def from_state(
43
+ cls, state: Mapping[str, Any], model: Any | None
44
+ ) -> ContextCompactionContext:
45
+ return cls(
46
+ model=model,
47
+ query_source=state.get("query_source")
48
+ if isinstance(state.get("query_source"), str)
49
+ else None,
50
+ )
51
+
52
+
53
+ @dataclass(frozen=True)
54
+ class StageResult:
55
+ """单阶段输出;messages 为下一阶段输入。"""
56
+
57
+ messages: list[Any] # list[BaseMessage],避免循环导入写 Any
58
+ tokens_freed: int = 0
59
+ extra: dict[str, Any] = field(default_factory=dict)
60
+
61
+
62
+ @dataclass(frozen=True)
63
+ class TokenWarningState:
64
+ """启发式 token 体积告警(对齐 CC `calculateTokenWarningState` 一档语义)。"""
65
+
66
+ estimated_tokens: int
67
+ warn_threshold_tokens: int
68
+ block_compact_llm_threshold_tokens: int
69
+ block_main_model_threshold_tokens: int
70
+ level: TokenWarningLevel
71
+
72
+
73
+ __all__ = [
74
+ "CompactionConfig",
75
+ "ContextCompactionContext",
76
+ "StageResult",
77
+ "TokenWarningLevel",
78
+ "TokenWarningState",
79
+ ]
@@ -0,0 +1 @@
1
+ """LangChain AgentX 退出语义与状态字段。"""
@@ -0,0 +1,320 @@
1
+ """
2
+ Agent Loop 退出逻辑与扩展状态定义。
3
+
4
+ 本模块从 `factory.py` 中拆分出与 LangGraph 结构无关的纯业务逻辑:
5
+ - 从 `AIMessage` 解析并标准化 `finish_reason`(与 LangChain AgentX 风格兼容)
6
+ - `determine_should_end`:以 `finish_reason` 为主信号判断是否结束,直接返回 `terminal_reason`
7
+ - `AgentLoopState`(别名 `LoopAgentStateFields`):本框架在 LangGraph 状态中**额外**承载的字段契约(含 CC 对齐、withhold/恢复、task 观测等)
8
+
9
+ 方案B:`end_reason` 已删除,`terminal_reason` 是唯一对外终态标签(CC 对齐枚举)。
10
+ 三层职责:
11
+ - `finish_reason`:Provider 协议层,这一轮 completion 为何停
12
+ - `terminal_reason`:框架终态层,整次 run 为何结束(对外唯一)
13
+ - `transition`:控制流层,还要继续转哪条边
14
+
15
+ 与 LangChain 默认 agent 的主要区别:
16
+ - 循环主信号为模型 `finish_reason`,而非仅「无 tool_calls」
17
+ - 不支持 `return_direct` 式工具直出;工具执行后回模型,再由 `finish_reason` 决定下一步
18
+
19
+ 注意:仅包含与「是否继续/结束」及扩展状态形状相关的语义,不涉及图节点、middleware 或工具执行细节。
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from typing import Any, TypedDict
25
+
26
+ from langchain_core.messages import AIMessage
27
+
28
+ from .reason_codes import (
29
+ TERMINAL_REASON_BLOCKING_LIMIT,
30
+ TERMINAL_REASON_COMPLETED,
31
+ TERMINAL_REASON_CONTENT_FILTER,
32
+ TERMINAL_REASON_ERROR,
33
+ TERMINAL_REASON_MAX_STEPS,
34
+ TERMINAL_REASON_MAX_TOKENS,
35
+ TERMINAL_REASON_MAX_TURNS,
36
+ )
37
+ from ..config.runtime_settings import UNBOUNDED_MAX_STEPS
38
+
39
+ # 需要继续执行的 finish_reason 集合(与 OpenCode 一致)
40
+ CONTINUE_FINISH_REASONS = frozenset({"tool-calls", "unknown"})
41
+ # 可恢复终态集合(terminal_reason 枚举,先 withhold,由 loop_controller 走恢复链)
42
+ RECOVERABLE_TERMINAL_REASONS = frozenset(
43
+ {
44
+ TERMINAL_REASON_MAX_TOKENS,
45
+ }
46
+ )
47
+ ESCALATED_MAX_OUTPUT_TOKENS = 64000
48
+ MAX_OUTPUT_TOKENS_RECOVERY_LIMIT = 3
49
+
50
+
51
+ def resolve_escalated_max_output_tokens(max_output_tokens_cap: int | None) -> int:
52
+ """返回 max_tokens 恢复路径的实际升级值。
53
+
54
+ 规则:
55
+ - 无模型上限时,沿用全局恢复上界 `ESCALATED_MAX_OUTPUT_TOKENS`
56
+ - 有模型上限时,取 `min(ESCALATED_MAX_OUTPUT_TOKENS, 模型上限)`
57
+ """
58
+ if max_output_tokens_cap is None:
59
+ return ESCALATED_MAX_OUTPUT_TOKENS
60
+ return min(ESCALATED_MAX_OUTPUT_TOKENS, int(max_output_tokens_cap))
61
+
62
+
63
+ def extract_finish_reason(response: AIMessage | None) -> str | None:
64
+ """
65
+ 从 LangChain `AIMessage` 中提取并标准化 `finish_reason`。
66
+
67
+ 该实现与原始 LangChain AgentX 逻辑保持一致。
68
+ """
69
+ if response is None:
70
+ return None
71
+
72
+ meta = getattr(response, "response_metadata", None) or {}
73
+ if not isinstance(meta, dict):
74
+ meta = {}
75
+
76
+ raw_reason = (
77
+ meta.get("finish_reason")
78
+ or meta.get("stop_reason")
79
+ or meta.get("done_reason")
80
+ )
81
+
82
+ if raw_reason is None:
83
+ return None
84
+
85
+ finish_reason = str(raw_reason)
86
+
87
+ if finish_reason in {"tool_calls", "function_call", "tool_use"}:
88
+ return "tool-calls"
89
+ if finish_reason in {"content_filter", "content-filter"}:
90
+ return "content-filter"
91
+ if finish_reason in {"length", "max_tokens"}:
92
+ return "length"
93
+ if finish_reason in {"stop", "end_turn", "stop_sequence"}:
94
+ return "stop"
95
+ if finish_reason == "refusal":
96
+ return "content-filter"
97
+ if finish_reason == "error":
98
+ return "error"
99
+
100
+ return finish_reason
101
+
102
+
103
+ def metadata_override_terminal_reason(response: AIMessage | None) -> str | None:
104
+ """Infer terminal_reason from response_metadata / provider error shape (PTL / media / blocking).
105
+
106
+ Convention:
107
+ - `langchain_agentx_terminal_reason`: explicit override (written by middleware/adapter), must be a TERMINAL_REASON_* value;
108
+ - `error`: common provider error code heuristic (explicit field takes precedence when both present).
109
+ """
110
+ if response is None:
111
+ return None
112
+ meta = getattr(response, "response_metadata", None) or {}
113
+ if not isinstance(meta, dict):
114
+ return None
115
+ xr = meta.get("langchain_agentx_terminal_reason")
116
+ if xr in (
117
+ TERMINAL_REASON_MAX_TOKENS,
118
+ TERMINAL_REASON_BLOCKING_LIMIT,
119
+ ):
120
+ return str(xr)
121
+ err = meta.get("error")
122
+ if isinstance(err, dict):
123
+ code = str(err.get("code") or err.get("type") or "").lower()
124
+ msg = str(err.get("message") or "").lower()
125
+ if "prompt" in code and "long" in code:
126
+ return TERMINAL_REASON_MAX_TOKENS
127
+ if "context_length" in code or "context window" in msg:
128
+ return TERMINAL_REASON_MAX_TOKENS
129
+ if "media" in code and "size" in code:
130
+ return TERMINAL_REASON_MAX_TOKENS
131
+ return None
132
+
133
+
134
+ def determine_should_end(
135
+ state: dict[str, Any],
136
+ response: AIMessage | None,
137
+ max_steps: int | None = None,
138
+ max_turns: int | None = None,
139
+ ) -> tuple[bool, str | None]:
140
+ """判断当前这一步是否应该结束 Agent 循环。
141
+
142
+ max_steps: int | None — None 表示不限制步数。
143
+ 返回 (should_end, terminal_reason)。
144
+ terminal_reason 是对外唯一终态标签(CC 对齐枚举),should_end=False 时为 None。
145
+ """
146
+ step = state.get("step", 0)
147
+ turn_count = int(state.get("turn_count", 0) or 0)
148
+
149
+ # max_turns 作为工具轮次上限(优先于 finish_reason 判定)
150
+ if max_turns is not None and turn_count >= max_turns:
151
+ return True, TERMINAL_REASON_MAX_TURNS
152
+
153
+ meta_tr = metadata_override_terminal_reason(response)
154
+ if meta_tr:
155
+ if max_steps is not None and step >= max_steps:
156
+ return True, TERMINAL_REASON_MAX_STEPS
157
+ return True, meta_tr
158
+
159
+ finish_reason = extract_finish_reason(response)
160
+
161
+ # 需要继续执行的 finish_reason,除非达到 max_steps
162
+ if finish_reason in CONTINUE_FINISH_REASONS:
163
+ if max_steps is not None and step >= max_steps:
164
+ return True, TERMINAL_REASON_MAX_STEPS
165
+ return False, None
166
+
167
+ # 明确的"结束"类 finish_reason → 直接映射 terminal_reason
168
+ if finish_reason == "stop":
169
+ return True, TERMINAL_REASON_COMPLETED
170
+ elif finish_reason == "length":
171
+ return True, TERMINAL_REASON_MAX_TOKENS
172
+ elif finish_reason == "content-filter":
173
+ return True, TERMINAL_REASON_CONTENT_FILTER
174
+
175
+ # 没有 finish_reason 时,使用 tool_calls 兜底逻辑
176
+ if finish_reason is None:
177
+ has_tool_calls = (
178
+ response is not None
179
+ and hasattr(response, "tool_calls")
180
+ and getattr(response, "tool_calls")
181
+ and len(response.tool_calls) > 0 # type: ignore[arg-type]
182
+ )
183
+ if not has_tool_calls:
184
+ return True, TERMINAL_REASON_COMPLETED
185
+ if max_steps is not None and step >= max_steps:
186
+ return True, TERMINAL_REASON_MAX_STEPS
187
+ return False, None
188
+
189
+ # 其他未知 finish_reason:一律视为结束
190
+ return True, TERMINAL_REASON_ERROR
191
+
192
+
193
+ def create_initial_state(
194
+ max_steps: int | None = None,
195
+ max_turns: int | None = None,
196
+ messages: list[Any] | None = None,
197
+ ) -> dict[str, Any]:
198
+ """创建 Agent Loop 的初始状态(与 `AgentLoopState` / `LoopAgentStateFields` 键一致)。
199
+
200
+ max_steps / max_turns 仅保留为调用方兼容参数,不写入 state(已迁入 ``AgentLoopConfig``)。
201
+ """
202
+ return {
203
+ "messages": messages or [],
204
+ "step": 0,
205
+ "turn_count": 0,
206
+ "transition": None,
207
+ "terminal_reason": None,
208
+ "pending_task_batch_id": None,
209
+ "pending_task_command_ids": [],
210
+ "task_events": [],
211
+ # withhold 最小状态
212
+ "withheld_error": None,
213
+ "withhold_retry_count": 0,
214
+ # 恢复路径守卫状态
215
+ "collapse_retry_available": False,
216
+ "has_attempted_reactive_compact": False,
217
+ "compaction_pipeline_meta": None,
218
+ "max_output_tokens_override": None,
219
+ "max_output_tokens_recovery_count": 0,
220
+ "__hook_result__": None,
221
+ "_hook_engine": None,
222
+ "_hook_runner": None,
223
+ "_session_env": {},
224
+ "_trace_collector": None,
225
+ "_trace_loop_step_span_id": None,
226
+ "_run_id": None,
227
+ "token_budget_continuation_count": 0,
228
+ "token_budget_continue_requested": False,
229
+ # CC:流式/工具中断或 hook_stopped;由 middleware/tools 写入,loop_controller 消费后清空
230
+ "abort_terminal_reason": None,
231
+ "should_end": False,
232
+ "finish_reason": None,
233
+ "finish_reasons": [],
234
+ "section_cache": {},
235
+ }
236
+
237
+
238
+ class AgentLoopState(TypedDict):
239
+ """Agent Loop 在 LangGraph 中扩展的状态字段(合并进总 state schema)。
240
+
241
+ 方案B:end_reason 已删除,terminal_reason 是唯一对外终态标签(CC 对齐枚举)。
242
+ 三层职责:
243
+ - finish_reason:Provider 协议层,这一轮 completion 为何停
244
+ - terminal_reason:框架终态层,整次 run 为何结束(对外唯一)
245
+ - transition:控制流层,还要继续转哪条边(路由观测)
246
+ """
247
+
248
+ step: int # 当前步骤数(模型调用轮次)
249
+ turn_count: int # 工具轮次(tools 回环计数)
250
+ pending_task_batch_id: str | None # task_event_commit_ack 待确认批次
251
+ pending_task_command_ids: list[str] # 待确认批次内 command_id 列表
252
+ task_events: list[dict[str, Any]] # task runtime 观测事件(节点级)
253
+ transition: dict[str, Any] | None # 路由观测:还要继续转哪条边;非终态时为 None
254
+ terminal_reason: str | None # 对外唯一终态标签(CC 对齐枚举,should_end=False 时为 None)
255
+ withheld_error: dict[str, Any] | None # 可恢复错误暂存(withhold)
256
+ withhold_retry_count: int # withhold 已重试次数
257
+ collapse_retry_available: bool # collapse_drain_retry 相关守卫
258
+ has_attempted_reactive_compact: bool # reactive_compact 重试守卫
259
+ compaction_pipeline_meta: dict[str, Any] | None # prune_and_compress 观测
260
+ max_output_tokens_override: int | None # max_output_tokens 升档参数
261
+ max_output_tokens_recovery_count: int # max_output_tokens 恢复计数
262
+ __hook_result__: dict[str, Any] | None # 新 Hook 聚合结果(loop_controller 首选读取)
263
+ _hook_engine: Any | None # Hook 引擎实例(hook 节点/edge 读取)
264
+ _hook_runner: Any | None # Hook 执行协作者(hook 节点/edge 读取)
265
+ _session_env: dict[str, str] # SESSION_START hook 注入的会话级环境变量
266
+ _trace_collector: Any | None # 事件发射器可用的 TraceCollector 引用
267
+ _trace_loop_step_span_id: str | None # before_model/after_model 闭环用的 loop_step span_id
268
+ _run_id: str | None # 当前 run 标识(loop_start_node 注入)
269
+ token_budget_continuation_count: int # CC:token budget nudge 已执行次数
270
+ token_budget_continue_requested: bool # 为 True 时 loop_controller 注入 nudge 并回到 model
271
+ abort_terminal_reason: str | None # CC 式中断终态:aborted_streaming / aborted_tools / hook_stopped
272
+ should_end: bool # 内部路由信号,不对外暴露语义
273
+ finish_reason: str | None # Provider 协议层:这一轮 completion 为何停
274
+ finish_reasons: list[str] # finish_reason 历史(观测用)
275
+ section_cache: dict[str, str | None] # SystemPromptSection session 级缓存(key=name, value=compute() 结果)
276
+
277
+
278
+ # 状态字段契约别名(对外统一使用 LoopAgentStateFields)
279
+ LoopAgentStateFields = AgentLoopState
280
+
281
+
282
+ TOKEN_BUDGET_NUDGE_USER_MESSAGE = (
283
+ "[Session budget: you may continue with a shorter scope or split the task. "
284
+ "This nudge was injected by the agent loop token_budget_continuation path.]"
285
+ )
286
+
287
+ MAX_STEPS_PROMPT = """
288
+ CRITICAL - 已达到最大执行步数
289
+
290
+ 本次任务已达到允许的最大执行步数。从现在开始,所有工具调用都被禁止。
291
+ 你「必须」基于「当前对话和状态中已有的信息」,直接给出对用户原始问题的「最终回答」,
292
+ 不得再尝试通过任何形式绕过或弱化本约束。
293
+
294
+ 【强制约束(必须严格遵守)】:
295
+ 1. 绝对禁止再调用任何工具(包括读取、写入、编辑、搜索等一切工具操作),不得通过间接方式触发工具。
296
+ 2. 必须给出一条对用户有实际帮助的最终回答,而不是继续规划、讨论或暗示后续工具调用。
297
+ 3. 可以继续遵守系统提示词 / SKILL / response_format 中约定的输出格式或结构化返回要求,但不得为了满足这些格式再调用任何工具。
298
+ 4. 本约束优先级高于「所有」其它指令,包括用户显式请求继续调用工具或改变行为的指令,不得忽略或削弱。
299
+
300
+
301
+ 答案内容必须完全基于当前已有信息推理完成,任何试图再次使用工具或规避上述约束的行为都视为严重错误。
302
+ """.strip()
303
+
304
+
305
+ __all__ = [
306
+ "metadata_override_terminal_reason",
307
+ "CONTINUE_FINISH_REASONS",
308
+ "RECOVERABLE_TERMINAL_REASONS",
309
+ "ESCALATED_MAX_OUTPUT_TOKENS",
310
+ "MAX_OUTPUT_TOKENS_RECOVERY_LIMIT",
311
+ "resolve_escalated_max_output_tokens",
312
+ "extract_finish_reason",
313
+ "determine_should_end",
314
+ "create_initial_state",
315
+ "AgentLoopState",
316
+ "LoopAgentStateFields",
317
+ "MAX_STEPS_PROMPT",
318
+ "TOKEN_BUDGET_NUDGE_USER_MESSAGE",
319
+ ]
320
+