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,68 @@
1
+ """
2
+ loop/runtime/subagent_execution_paths.py — 子 Agent 工作目录与 worktree 单点准备
3
+
4
+ 职责:
5
+ 计算子会话的 ``effective_cwd``(供 ``run_with_cwd_override`` / ``AgentLoopConfig.cwd`` /
6
+ ``SubagentContext.cwd`` 同源),并在 ``isolation=worktree`` 时创建唯一临时目录。
7
+ 链路位置:
8
+ ``SubagentOrchestrator._derive_runtime_context`` → ``prepare`` → ``RuntimeContextFactory.derive``;
9
+ ``create_subagent_context(..., path_prep=...)`` 消费本结构,避免重复 ``mkdir``。
10
+ 当前裁剪范围:
11
+ 仅 ``none`` / ``worktree``;不处理 CC ``remote`` isolation。路径展开 / 权限校验留在 Phase 2。
12
+ CC 对照:
13
+ ``AgentTool.tsx`` 中 ``cwdOverridePath = cwd ?? worktreeInfo?.worktreePath``。
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import os
19
+ import uuid
20
+ from dataclasses import dataclass
21
+ from typing import Any
22
+
23
+ from langchain_agentx.loop.runtime.context import SubagentContextOverrides
24
+ from langchain_agentx.workspace import resolve_agent_workspace_config
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class PreparedSubagentPaths:
29
+ """``SubagentExecutionPaths.prepare`` 的输出:最终 cwd 与可选 worktree 目录。"""
30
+
31
+ effective_cwd: str
32
+ worktree_dir: str | None = None
33
+
34
+
35
+ class SubagentExecutionPaths:
36
+ """子 Agent 路径准备(OOP 单点,禁止在 orchestrator 内堆叠 mkdir 逻辑)。"""
37
+
38
+ @staticmethod
39
+ def prepare(
40
+ *,
41
+ parent_ctx: Any,
42
+ overrides: "SubagentContextOverrides",
43
+ ) -> PreparedSubagentPaths:
44
+ """解析 ``effective_cwd``,并在 worktree 模式下创建临时目录。
45
+
46
+ 顺序对齐 CC:**显式 ``overrides.cwd`` 优先于 worktree 目录**(``cwd ?? worktreePath``)。
47
+ """
48
+ parent_cwd = getattr(parent_ctx, "cwd", None)
49
+ parent_workspace_root = getattr(parent_ctx, "workspace_root", None) or os.getcwd()
50
+ parent_agent_home = getattr(parent_ctx, "agent_home", ".langchain_agentx")
51
+ raw = overrides.cwd
52
+ override_cwd = raw.strip() if isinstance(raw, str) and raw.strip() else None
53
+
54
+ if overrides.isolation == "worktree":
55
+ workspace_cfg = resolve_agent_workspace_config(
56
+ workspace_root=parent_workspace_root,
57
+ agent_home=parent_agent_home,
58
+ )
59
+ workspace_cfg.worktrees_dir.mkdir(parents=True, exist_ok=True)
60
+ worktree_dir = str(
61
+ workspace_cfg.worktrees_dir / f"agentx-worktree-{uuid.uuid4().hex[:12]}"
62
+ )
63
+ os.makedirs(worktree_dir, exist_ok=False)
64
+ effective = override_cwd or worktree_dir
65
+ return PreparedSubagentPaths(effective_cwd=effective, worktree_dir=worktree_dir)
66
+
67
+ base = override_cwd or parent_cwd or os.getcwd()
68
+ return PreparedSubagentPaths(effective_cwd=base, worktree_dir=None)
@@ -0,0 +1,53 @@
1
+ """Loop Subagent 框架
2
+
3
+ 职责:子 Agent 执行框架的公共接口导出
4
+ 在整体链路中的位置:被 tools/agent/tool.py 调用
5
+ CC 对照:src/agent/subagent/ 目录
6
+ 当前裁剪范围:v1 同步执行路径,stub runner
7
+ """
8
+
9
+ from langchain_agentx.loop.subagent.context import (
10
+ SubagentContext,
11
+ SubagentResult,
12
+ cleanup_subagent_context,
13
+ create_subagent_context,
14
+ )
15
+ from langchain_agentx.loop.subagent.async_runner import (
16
+ BackgroundAgentHandle,
17
+ get_background_agent_handle,
18
+ register_background_agent,
19
+ run_async_agent_lifecycle,
20
+ )
21
+ from langchain_agentx.loop.subagent.progress import SubagentProgressEvent
22
+ from langchain_agentx.loop.subagent.runner import (
23
+ BackgroundLaunchedResult,
24
+ _run_coroutine_sync,
25
+ run_subagent,
26
+ run_subagent_with_background_signal,
27
+ )
28
+ from langchain_agentx.loop.subagent.transcript import (
29
+ JsonlTranscriptStore,
30
+ SubagentTranscriptManager,
31
+ SubagentTranscriptStore,
32
+ )
33
+ from langchain_agentx.loop.subagent.graph import create_subagent_graph
34
+
35
+ __all__ = [
36
+ "SubagentContext",
37
+ "SubagentResult",
38
+ "create_subagent_context",
39
+ "cleanup_subagent_context",
40
+ "SubagentProgressEvent",
41
+ "run_subagent",
42
+ "run_subagent_with_background_signal",
43
+ "BackgroundLaunchedResult",
44
+ "_run_coroutine_sync",
45
+ "register_background_agent",
46
+ "get_background_agent_handle",
47
+ "BackgroundAgentHandle",
48
+ "run_async_agent_lifecycle",
49
+ "JsonlTranscriptStore",
50
+ "SubagentTranscriptManager",
51
+ "SubagentTranscriptStore",
52
+ "create_subagent_graph",
53
+ ]
@@ -0,0 +1,215 @@
1
+ """
2
+ loop/subagent/async_runner.py — 子 Agent 异步生命周期管理
3
+
4
+ 职责:
5
+ - register_background_agent():threading 后台启动子 Agent(旧接口,供 v1 兼容)
6
+ - run_async_agent_lifecycle():coordinate 模式纯 async 生命周期(计划接口,供 AgentRuntimeTool 调用)
7
+ 在整体链路中的位置:AgentRuntimeTool.invoke(is_async=True) → run_async_agent_lifecycle()
8
+ CC 对照:agentToolUtils.ts runAsyncAgentLifecycle();LocalAgentTask enqueueAgentNotification()
9
+ 当前裁剪范围:v1 基础版;完整 worktree 清理 / output_file 管理为 v2
10
+
11
+ 执行流程(run_async_agent_lifecycle):
12
+ 1. 构造 output_file 路径,确保父目录存在
13
+ 2. task_runtime.update(task_id, {status: running})
14
+ 3. 临时置 ctx.is_async=False,调用 run_subagent() 执行子图
15
+ 4. 写 output_file(result.content)
16
+ 5. task_runtime.mark_terminal(completed/failed)
17
+ 异常分支:
18
+ CancelledError → 写 "cancelled",mark_terminal(failed, terminal_reason="cancelled"),re-raise
19
+ 其他 Exception → 写错误信息,mark_terminal(failed)
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import asyncio
25
+ import os
26
+ import threading
27
+ import uuid
28
+ from dataclasses import dataclass
29
+ from typing import Any, Callable
30
+
31
+ from langchain_agentx.task_runtime.core.types import TaskScope, TaskSpec, TaskStatus, TaskType
32
+
33
+ from .context import SubagentContext
34
+ from .runner import run_subagent
35
+
36
+
37
+ @dataclass
38
+ class BackgroundAgentHandle:
39
+ task_id: str
40
+ agent_id: str
41
+ output_file: str
42
+ thread: threading.Thread
43
+
44
+
45
+ _BACKGROUND_HANDLES: dict[str, BackgroundAgentHandle] = {}
46
+
47
+
48
+ def _ensure_parent(path: str) -> None:
49
+ os.makedirs(os.path.dirname(path), exist_ok=True)
50
+
51
+
52
+ def _resolve_task_runtime(ctx: Any) -> Any | None:
53
+ runtime = getattr(ctx, "task_runtime", None)
54
+ if runtime is not None:
55
+ return runtime
56
+ state = getattr(ctx, "state", {})
57
+ if isinstance(state, dict):
58
+ return state.get("task_runtime")
59
+ return None
60
+
61
+
62
+ def _spawn_task_record(task_runtime: Any, ctx: SubagentContext, description: str) -> str:
63
+ if task_runtime is None:
64
+ return str(uuid.uuid4())
65
+ spec = TaskSpec(
66
+ task_type=TaskType.LOCAL_AGENT,
67
+ description=description,
68
+ input={"prompt": description, "agent_label": ctx.subagent_type},
69
+ scope=TaskScope(agent_id=ctx.parent_agent_id),
70
+ )
71
+ return task_runtime.spawn(spec)
72
+
73
+
74
+ def register_background_agent(
75
+ *,
76
+ ctx: SubagentContext,
77
+ loader: Any,
78
+ model: Any | None,
79
+ output_dir: str,
80
+ description: str,
81
+ on_progress: Callable[[Any], None] | None = None,
82
+ parent_ctx: Any | None = None,
83
+ ) -> BackgroundAgentHandle:
84
+ """注册并启动后台子 Agent。"""
85
+ task_runtime = _resolve_task_runtime(parent_ctx)
86
+ task_id = _spawn_task_record(task_runtime, ctx, description)
87
+ output_file = os.path.join(output_dir, task_id, "output.txt")
88
+ _ensure_parent(output_file)
89
+
90
+ def _run() -> None:
91
+ async def _lifecycle() -> None:
92
+ try:
93
+ result = await run_subagent(
94
+ ctx=ctx,
95
+ loader=loader,
96
+ model=model,
97
+ on_progress=on_progress,
98
+ )
99
+ with open(output_file, "w", encoding="utf-8") as fp:
100
+ fp.write(result.content)
101
+ if task_runtime is not None:
102
+ status = TaskStatus.COMPLETED if result.status == "completed" else TaskStatus.FAILED
103
+ task_runtime.mark_terminal(
104
+ task_id,
105
+ status,
106
+ result.content[:500] if result.content else (result.error_message or "subagent completed"),
107
+ output_file=output_file,
108
+ terminal_reason=result.terminal_reason or None,
109
+ )
110
+ except Exception as exc:
111
+ with open(output_file, "w", encoding="utf-8") as fp:
112
+ fp.write(str(exc))
113
+ if task_runtime is not None:
114
+ task_runtime.mark_terminal(
115
+ task_id,
116
+ TaskStatus.FAILED,
117
+ f"Subagent background lifecycle failed: {exc}",
118
+ output_file=output_file,
119
+ terminal_reason="error",
120
+ )
121
+
122
+ asyncio.run(_lifecycle())
123
+
124
+ thread = threading.Thread(target=_run, daemon=True, name=f"agentx-subagent-{task_id}")
125
+ thread.start()
126
+ handle = BackgroundAgentHandle(
127
+ task_id=task_id,
128
+ agent_id=ctx.agent_id,
129
+ output_file=output_file,
130
+ thread=thread,
131
+ )
132
+ _BACKGROUND_HANDLES[task_id] = handle
133
+ return handle
134
+
135
+
136
+ def get_background_agent_handle(task_id: str) -> BackgroundAgentHandle | None:
137
+ return _BACKGROUND_HANDLES.get(task_id)
138
+
139
+
140
+ async def run_async_agent_lifecycle(
141
+ task_id: str,
142
+ ctx: SubagentContext,
143
+ loader: Any,
144
+ task_runtime: Any,
145
+ output_dir: str,
146
+ ) -> None:
147
+ """coordinate 模式异步生命周期:后台执行子 Agent,完成后通过 task_runtime 写通知。
148
+
149
+ Args:
150
+ task_id: 已由调用方在 task_runtime 中注册的任务 ID
151
+ ctx: 子 Agent 执行上下文(is_async 应为 True)
152
+ tools: 工具列表
153
+ task_runtime: TaskRuntime 实例,用于写终态通知
154
+ output_dir: 输出文件根目录
155
+
156
+ 执行流程:
157
+ 1. mark_terminal(running)
158
+ 2. run_subagent()
159
+ 3. 写 output_file
160
+ 4. mark_terminal(completed/failed)
161
+
162
+ CancelledError 单独捕获,写 cancelled 状态后 re-raise。
163
+ """
164
+ output_file = os.path.join(output_dir, task_id, "output.txt")
165
+ _ensure_parent(output_file)
166
+
167
+ if task_runtime is not None:
168
+ try:
169
+ task_runtime.update(task_id, {"status": TaskStatus.RUNNING.value})
170
+ except Exception:
171
+ pass
172
+
173
+ try:
174
+ # 子会话 is_async=True 时 run_subagent 会抛 RuntimeError,
175
+ # 此处临时置 False 走真实执行路径(lifecycle 本身已是异步上下文)
176
+ ctx.is_async = False
177
+ result = await run_subagent(ctx=ctx, loader=loader, model=None)
178
+
179
+ with open(output_file, "w", encoding="utf-8") as fp:
180
+ fp.write(result.content)
181
+
182
+ if task_runtime is not None:
183
+ status = TaskStatus.COMPLETED if result.status == "completed" else TaskStatus.FAILED
184
+ task_runtime.mark_terminal(
185
+ task_id,
186
+ status,
187
+ result.content[:500] if result.content else (result.error_message or "done"),
188
+ output_file=output_file,
189
+ terminal_reason=result.terminal_reason or None,
190
+ )
191
+
192
+ except asyncio.CancelledError:
193
+ with open(output_file, "w", encoding="utf-8") as fp:
194
+ fp.write("cancelled")
195
+ if task_runtime is not None:
196
+ try:
197
+ task_runtime.mark_terminal(
198
+ task_id, TaskStatus.FAILED, "subagent cancelled",
199
+ output_file=output_file, terminal_reason="cancelled",
200
+ )
201
+ except Exception:
202
+ pass
203
+ raise
204
+
205
+ except Exception as exc:
206
+ with open(output_file, "w", encoding="utf-8") as fp:
207
+ fp.write(str(exc))
208
+ if task_runtime is not None:
209
+ task_runtime.mark_terminal(
210
+ task_id,
211
+ TaskStatus.FAILED,
212
+ f"subagent failed: {exc}",
213
+ output_file=output_file,
214
+ terminal_reason="error",
215
+ )
@@ -0,0 +1,209 @@
1
+ """Subagent Context 与 Result 数据结构
2
+
3
+ 职责:封装子会话的独立状态与继承自父会话的共享引用
4
+ 在整体链路中的位置:create_subagent_context() 构造 → run_subagent() 消费
5
+ CC 对照:src/agent/subagent/context.ts SubagentContext 接口
6
+ 当前裁剪范围:v1 全量;system_prompt / is_async 字段驱动执行路径选择;
7
+ ``path_prep`` 与遗留 ``cwd``/worktree 自建二选一(编排层须传 ``path_prep``);
8
+ fork + worktree 时可选注入 CC 等价 ``buildWorktreeNotice`` user 消息(见 ``fork_worktree_notice``)。
9
+ """
10
+
11
+ import os
12
+ import shutil
13
+ import uuid
14
+ from dataclasses import dataclass, field
15
+ from typing import Any
16
+
17
+ from langchain_agentx.loop.runtime.subagent_execution_paths import PreparedSubagentPaths
18
+ from langchain_agentx.loop.subagent.fork_worktree_notice import build_worktree_notice
19
+ from langchain_agentx.workspace import resolve_agent_workspace_config
20
+
21
+
22
+ @dataclass
23
+ class SubagentContext:
24
+ """子 Agent 执行上下文
25
+
26
+ 独立字段:agent_id / initial_messages / max_steps / subagent_type / agent_depth
27
+ system_prompt / is_async / fork_from_parent
28
+ 共享字段:session_store / tool_registry(从父会话继承)
29
+ 执行路径:fork_from_parent 决定消息构造;is_async 决定同步/异步路径路由
30
+ """
31
+ # 独立字段
32
+ agent_id: str
33
+ initial_messages: list[dict[str, Any]]
34
+ max_steps: int | None
35
+ subagent_type: str
36
+ model: Any | None = None
37
+ agent_depth: int = 0
38
+
39
+ # 执行路径字段(由外部注入,驱动 runner 路由决策)
40
+ system_prompt: str = "" # 由 SubagentConfig.system_prompt_factory() 注入
41
+ fork_from_parent: bool = False # True = fork 模式,initial_messages 含父会话历史
42
+ is_async: bool = False # True = 走异步路径(coordinate/fork-async)
43
+
44
+ # 共享字段(从父会话继承)
45
+ session_store: Any = None # SessionStore
46
+ tool_registry: Any = None # ToolRegistry
47
+ tool_loader: Any = None # ToolRuntimeLoader
48
+
49
+ # 可选字段
50
+ parent_agent_id: str | None = None
51
+ parent_run_id: str | None = None # 父 Agent 的 trace run_id,供 TraceLifecycleCollector/Collector 建立父子链接
52
+ parent_tool_call_id: str | None = None # 触发本子 Agent 的 tool_call_id
53
+ parent_conversation_session_id: str | None = None
54
+ enable_trace: bool = True
55
+ isolation: str = "none"
56
+ worktree_dir: str | None = None
57
+ workspace_root: str = ""
58
+ agent_home: str = ".langchain_agentx"
59
+ cwd: str | None = None
60
+ _file_read_state: dict[str, Any] = field(default_factory=dict)
61
+
62
+
63
+ @dataclass
64
+ class SubagentResult:
65
+ """子 Agent 执行结果"""
66
+ agent_id: str
67
+ content: str
68
+ status: str # "completed" | "error" | "interrupted"
69
+ terminal_reason: str = ""
70
+ total_steps: int = 0
71
+ error_message: str = ""
72
+ output_file: str | None = None
73
+ child_run_id: str | None = None # 子会话的 trace session_id,供父 run 追溯
74
+
75
+
76
+ def create_subagent_context(
77
+ parent_ctx: Any,
78
+ task: str,
79
+ subagent_type: str,
80
+ system_prompt: str = "",
81
+ max_steps: int | None = None,
82
+ model: Any | None = None,
83
+ agent_depth: int = 0,
84
+ isolation: str = "none",
85
+ cwd: str | None = None,
86
+ fork_from_parent: bool = False,
87
+ is_async: bool = False,
88
+ *,
89
+ path_prep: PreparedSubagentPaths | None = None,
90
+ inject_fork_worktree_notice: bool = False,
91
+ fork_worktree_parent_cwd: str | None = None,
92
+ fork_worktree_path: str | None = None,
93
+ ) -> SubagentContext:
94
+ """工厂函数:从父上下文创建子 Agent 上下文
95
+
96
+ Args:
97
+ parent_ctx: 父会话上下文(需有 session_store / tool_registry)
98
+ task: 子任务描述
99
+ subagent_type: 子 Agent 类型("general-purpose" / "explore" / "plan")
100
+ system_prompt: 系统提示词(由 SubagentConfig.system_prompt_factory() 提供)
101
+ max_steps: 最大步数
102
+ model: 子 Agent 使用模型(None 时由调用方在 runner 阶段继续继承)
103
+ agent_depth: Agent 嵌套深度
104
+ isolation: 隔离模式("none" / "worktree")
105
+ cwd: 工作目录覆盖(与 ``path_prep`` 二选一;``path_prep`` 非空时忽略本参数的路径语义)
106
+ fork_from_parent: True = fork 模式,initial_messages 继承父会话历史
107
+ is_async: True = 走异步执行路径(coordinate/fork-async)
108
+ path_prep: 由 ``SubagentExecutionPaths.prepare`` 提供时,使用其 ``effective_cwd`` /
109
+ ``worktree_dir``,且不再在本函数内创建 worktree 目录。
110
+ inject_fork_worktree_notice: 为 True 且 ``fork_from_parent`` 且 ``fork_worktree_path`` 非空时,
111
+ 在最终任务 user 消息前插入 CC 等价 worktree 提示(父 cwd 由 ``fork_worktree_parent_cwd`` 提供)。
112
+ fork_worktree_parent_cwd: 父 Agent 工作目录(须在 ``run_with_cwd_override`` 子 cwd 生效前由编排层捕获)。
113
+ fork_worktree_path: 子 Agent 的 worktree 根路径(通常即 ``path_prep.worktree_dir``)。
114
+
115
+ Returns:
116
+ SubagentContext 实例
117
+ """
118
+ agent_id = str(uuid.uuid4())
119
+ parent_run_id_raw = getattr(parent_ctx, "run_id", None)
120
+ if not isinstance(parent_run_id_raw, str) or not parent_run_id_raw:
121
+ parent_run_id_raw = getattr(parent_ctx, "session_id", None)
122
+ if not isinstance(parent_run_id_raw, str) or not parent_run_id_raw:
123
+ parent_run_id_raw = None
124
+ parent_conversation_id = getattr(parent_ctx, "conversation_session_id", None)
125
+ if not isinstance(parent_conversation_id, str) or not parent_conversation_id:
126
+ parent_conversation_id = parent_run_id_raw
127
+ parent_tool_call_id = getattr(parent_ctx, "tool_call_id", None)
128
+ if not isinstance(parent_tool_call_id, str) or not parent_tool_call_id:
129
+ anchor = parent_run_id_raw or "unknown-run"
130
+ parent_tool_call_id = f"synthetic-agent-call:{anchor}:{agent_id[:8]}"
131
+
132
+ parent_cwd = getattr(parent_ctx, "cwd", None)
133
+
134
+ initial_messages = [{"role": "user", "content": task}]
135
+ if fork_from_parent:
136
+ parent_messages = getattr(parent_ctx, "state", {}).get("messages", [])
137
+ if isinstance(parent_messages, list):
138
+ initial_messages = []
139
+ for msg in parent_messages:
140
+ if isinstance(msg, dict):
141
+ initial_messages.append(dict(msg))
142
+ notice_parent = fork_worktree_parent_cwd or parent_cwd or os.getcwd()
143
+ if (
144
+ inject_fork_worktree_notice
145
+ and fork_worktree_path
146
+ and isinstance(notice_parent, str)
147
+ and notice_parent.strip()
148
+ ):
149
+ initial_messages.append(
150
+ {
151
+ "role": "user",
152
+ "content": build_worktree_notice(
153
+ notice_parent.strip(),
154
+ fork_worktree_path,
155
+ ),
156
+ }
157
+ )
158
+ initial_messages.append({"role": "user", "content": task})
159
+
160
+ parent_workspace_root = getattr(parent_ctx, "workspace_root", None) or os.getcwd()
161
+ parent_agent_home = getattr(parent_ctx, "agent_home", ".langchain_agentx")
162
+ worktree_dir: str | None = None
163
+ if path_prep is not None:
164
+ effective_cwd = path_prep.effective_cwd
165
+ worktree_dir = path_prep.worktree_dir
166
+ else:
167
+ effective_cwd = cwd or parent_cwd or os.getcwd()
168
+ if isolation == "worktree":
169
+ workspace_cfg = resolve_agent_workspace_config(
170
+ workspace_root=parent_workspace_root,
171
+ agent_home=parent_agent_home,
172
+ )
173
+ workspace_cfg.worktrees_dir.mkdir(parents=True, exist_ok=True)
174
+ worktree_dir = str(
175
+ workspace_cfg.worktrees_dir / f"agentx-worktree-{uuid.uuid4().hex[:12]}"
176
+ )
177
+ os.makedirs(worktree_dir, exist_ok=False)
178
+ effective_cwd = (cwd.strip() if isinstance(cwd, str) and cwd.strip() else None) or worktree_dir
179
+
180
+ return SubagentContext(
181
+ agent_id=agent_id,
182
+ initial_messages=initial_messages,
183
+ max_steps=max_steps,
184
+ model=model,
185
+ subagent_type=subagent_type,
186
+ agent_depth=agent_depth,
187
+ system_prompt=system_prompt,
188
+ fork_from_parent=fork_from_parent,
189
+ is_async=is_async,
190
+ session_store=getattr(parent_ctx, "session_store", None),
191
+ tool_registry=getattr(parent_ctx, "tool_registry", None),
192
+ tool_loader=getattr(parent_ctx, "tool_loader", None),
193
+ parent_agent_id=getattr(parent_ctx, "agent_id", None),
194
+ parent_run_id=parent_run_id_raw,
195
+ parent_tool_call_id=parent_tool_call_id,
196
+ parent_conversation_session_id=parent_conversation_id,
197
+ enable_trace=bool(getattr(parent_ctx, "trace_enabled", True)),
198
+ isolation=isolation,
199
+ worktree_dir=worktree_dir,
200
+ workspace_root=str(parent_workspace_root),
201
+ agent_home=str(parent_agent_home),
202
+ cwd=effective_cwd,
203
+ )
204
+
205
+
206
+ def cleanup_subagent_context(ctx: SubagentContext) -> None:
207
+ """清理 subagent 临时资源(如 worktree 目录)。"""
208
+ if ctx.isolation == "worktree" and ctx.worktree_dir:
209
+ shutil.rmtree(ctx.worktree_dir, ignore_errors=True)
@@ -0,0 +1,25 @@
1
+ """
2
+ loop/subagent/fork_worktree_notice.py — Fork 子 Agent 的 worktree 路径提示文案
3
+
4
+ 职责:
5
+ 生成与 Claude Code ``buildWorktreeNotice`` 等价的 user 消息正文,提示子 Agent
6
+ 将继承消息中的路径从父工作目录映射到隔离 worktree。
7
+ 链路位置:
8
+ ``create_subagent_context`` 在 ``fork_from_parent`` 且存在 worktree 目录时追加一条 user 消息。
9
+ 当前裁剪范围:
10
+ 仅英文固定模板(与 CC 原文一致);不承载 i18n。
11
+ CC 对照:
12
+ ``src/tools/AgentTool/forkSubagent.ts`` ``buildWorktreeNotice(parentCwd, worktreeCwd)``。
13
+ """
14
+
15
+
16
+ def build_worktree_notice(parent_cwd: str, worktree_path: str) -> str:
17
+ """与 CC ``buildWorktreeNotice`` 原文一致(参数为父 cwd 与 worktree 根路径)。"""
18
+ return (
19
+ f"You've inherited the conversation context above from a parent agent working in {parent_cwd}. "
20
+ f"You are operating in an isolated git worktree at {worktree_path} — same repository, "
21
+ "same relative file structure, separate working copy. Paths in the inherited context refer "
22
+ "to the parent's working directory; translate them to your worktree root. Re-read files before "
23
+ "editing if the parent may have modified them since they appear in the context. Your changes stay "
24
+ "in this worktree and will not affect the parent's files."
25
+ )
@@ -0,0 +1,72 @@
1
+ """
2
+ loop/subagent/graph.py — 子 Agent 图创建
3
+
4
+ 职责:create_subagent_graph(),基于 SubagentContext 创建独立子 Loop 图
5
+ 在整体链路中的位置:run_subagent() → create_subagent_graph() → subagent_graph.astream_events()
6
+ CC 对照:runAgent.ts 中 queryLoop() 调用(子会话复用主引擎)
7
+ 当前裁剪范围:v1 复用 create_loop_agent;通过 tools 参数注入子代理工具,并传入
8
+ parent_run_id/parent_tool_call_id 与父 run 关联。
9
+
10
+ 执行流程(create_subagent_graph):
11
+ 1. 从 ctx 读取 system_prompt / session_store / max_steps
12
+ 2. 调用 create_loop_agent(is_subagent=True, loader=..., parent_run_id=..., parent_tool_call_id=...)
13
+ 创建子图
14
+ 3. 返回编译后的 CompiledStateGraph,由 run_subagent() 调用 astream_events()
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import TYPE_CHECKING, Any
20
+
21
+ if TYPE_CHECKING:
22
+ from langchain_core.language_models.chat_models import BaseChatModel
23
+ from langchain_core.tools import BaseTool
24
+ from langgraph.graph.state import CompiledStateGraph
25
+
26
+ from .context import SubagentContext
27
+
28
+
29
+ def create_subagent_graph(
30
+ ctx: SubagentContext,
31
+ loader: Any,
32
+ model: str | BaseChatModel | None = None,
33
+ ) -> CompiledStateGraph:
34
+ """创建子 Agent 的 LangGraph 图。
35
+
36
+ 复用 create_loop_agent(..., is_subagent=True)。
37
+
38
+ Args:
39
+ ctx: 子 Agent 执行上下文(SubagentContext)
40
+ loader: 子会话 ToolRuntimeLoader(已完成工具过滤与运行时装配)
41
+ model: 语言模型(str 或 BaseChatModel),None 时由调用方保证已在 ctx 外部传入
42
+
43
+ Returns:
44
+ 编译后的 CompiledStateGraph,可直接调用 astream_events()
45
+ """
46
+ from langchain_agentx.loop.graph.factory import create_loop_agent
47
+
48
+ if model is None:
49
+ raise ValueError("model is required for create_subagent_graph")
50
+
51
+ # 显式 session_id:避免子图构图时生成 ephemeral id 刷屏日志,并与 ctx.agent_id 对齐便于追溯
52
+ session_id = f"subagent:{ctx.subagent_type}:{ctx.agent_id}"
53
+
54
+ return create_loop_agent(
55
+ model=model,
56
+ loader=loader,
57
+ system_prompt=ctx.system_prompt or None,
58
+ session_id=session_id,
59
+ session_store=ctx.session_store,
60
+ max_steps=ctx.max_steps,
61
+ is_subagent=True,
62
+ name=f"subagent:{ctx.subagent_type}:{ctx.agent_id[:8]}",
63
+ parent_run_id=ctx.parent_run_id,
64
+ parent_tool_call_id=ctx.parent_tool_call_id,
65
+ parent_conversation_session_id=ctx.parent_conversation_session_id,
66
+ enable_trace=ctx.enable_trace,
67
+ # 背景子代理默认隐藏;前台子代理沿用默认可见性。
68
+ trace_visibility="hidden" if ctx.is_async else "default",
69
+ workspace_root=ctx.workspace_root or None,
70
+ agent_home=ctx.agent_home,
71
+ subagent_type=ctx.subagent_type,
72
+ )