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,163 @@
1
+ """
2
+ tools/bash/sed_validation.py — BashRuntimeTool 模块2:sed 命令安全与工作流判定
3
+
4
+ 职责:
5
+ 将 `sed` 从普通 Bash 写命令里解耦出来,决定它应该走哪条执行路径:
6
+ 1. 普通非原地 `sed`:继续走原有 Bash 权限链
7
+ 2. 可稳定预览的 simple `sed -i`:进入 preview -> confirm -> apply
8
+ 3. 含危险语义或无法稳定预览的 `sed -i`:保守 ask
9
+
10
+ 核心判定点:
11
+ - 是否为 in-place edit(`-i` / `--in-place`)
12
+ - substitution flags 中是否包含 `e/E/w/W` 等危险能力
13
+ - 是否能够通过 `sed_edit_parser.py` 生成确定性 preview
14
+
15
+ 与 `tool.py` 的关系:
16
+ `tool.py` 负责编排工作流和暂存 preview 结果;
17
+ 本文件只回答“这个 sed 命令是否安全、是否可预览、是否必须人工审批”。
18
+
19
+ 与 CC 对照:
20
+ 对应 CC `sedValidation.ts` 的基础版能力,当前只覆盖模块 2 需要的高价值分支。
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import re
26
+ import shlex
27
+ from dataclasses import dataclass
28
+
29
+ from .sed_edit_parser import BashSedEditParser, SedEditInfo
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class BashSedCommandCheck:
34
+ is_sed: bool
35
+ is_in_place: bool
36
+ requires_manual_approval: bool
37
+ reason: str | None = None
38
+ edit_info: SedEditInfo | None = None
39
+
40
+
41
+ class BashSedCommandValidator:
42
+ """判断 sed 是否能走 preview/apply,或必须人工审批。"""
43
+
44
+ _DANGEROUS_SUBST_FLAGS = frozenset({"e", "E", "w", "W"})
45
+
46
+ def __init__(self, parser: BashSedEditParser | None = None) -> None:
47
+ self._parser = parser or BashSedEditParser()
48
+
49
+ def evaluate(self, command: str) -> BashSedCommandCheck:
50
+ tokens = self._split(command)
51
+ if not tokens or tokens[0] != "sed":
52
+ return BashSedCommandCheck(False, False, False)
53
+
54
+ in_place = self._has_in_place_flag(tokens[1:])
55
+ expressions = self._collect_inline_expressions(tokens[1:])
56
+ if self._contains_dangerous_expression(expressions):
57
+ return BashSedCommandCheck(
58
+ is_sed=True,
59
+ is_in_place=in_place,
60
+ requires_manual_approval=True,
61
+ reason=(
62
+ "sed command requires explicit approval because it contains potentially "
63
+ "dangerous write/execute operations."
64
+ ),
65
+ )
66
+
67
+ if not in_place:
68
+ return BashSedCommandCheck(
69
+ is_sed=True,
70
+ is_in_place=False,
71
+ requires_manual_approval=False,
72
+ )
73
+
74
+ edit_info = self._parser.parse(command)
75
+ if edit_info is None:
76
+ return BashSedCommandCheck(
77
+ is_sed=True,
78
+ is_in_place=True,
79
+ requires_manual_approval=True,
80
+ reason=(
81
+ "sed -i command requires explicit approval because a deterministic preview "
82
+ "cannot be generated safely."
83
+ ),
84
+ )
85
+ return BashSedCommandCheck(
86
+ is_sed=True,
87
+ is_in_place=True,
88
+ requires_manual_approval=False,
89
+ edit_info=edit_info,
90
+ )
91
+
92
+ @staticmethod
93
+ def _split(command: str) -> list[str]:
94
+ try:
95
+ return shlex.split(command)
96
+ except ValueError:
97
+ return command.split()
98
+
99
+ @staticmethod
100
+ def _has_in_place_flag(args: list[str]) -> bool:
101
+ return any(arg in {"-i", "--in-place"} or arg.startswith("-i") for arg in args)
102
+
103
+ def _collect_inline_expressions(self, args: list[str]) -> list[str]:
104
+ expressions: list[str] = []
105
+ i = 0
106
+ while i < len(args):
107
+ arg = args[i]
108
+ if arg in {"-e", "--expression"} and i + 1 < len(args):
109
+ expressions.append(args[i + 1])
110
+ i += 2
111
+ continue
112
+ if arg.startswith("--expression="):
113
+ expressions.append(arg.split("=", 1)[1])
114
+ i += 1
115
+ continue
116
+ if arg.startswith("-"):
117
+ i += 1
118
+ continue
119
+ if not expressions:
120
+ expressions.append(arg)
121
+ i += 1
122
+ return expressions
123
+
124
+ def _contains_dangerous_expression(self, expressions: list[str]) -> bool:
125
+ for expression in expressions:
126
+ parsed = self._parser.parse(f"sed -i {shlex.quote(expression)} dummy.txt")
127
+ if parsed is None:
128
+ dangerous_flags = self._extract_substitution_flags(expression)
129
+ if any(flag in self._DANGEROUS_SUBST_FLAGS for flag in dangerous_flags):
130
+ return True
131
+ if re.search(r"(^|[;\s])[weWE](?:[\s]|$)", expression):
132
+ return True
133
+ continue
134
+ if any(flag in self._DANGEROUS_SUBST_FLAGS for flag in parsed.flags):
135
+ return True
136
+ return False
137
+
138
+ @staticmethod
139
+ def _extract_substitution_flags(expression: str) -> str:
140
+ if not expression.startswith("s/"):
141
+ return ""
142
+ rest = expression[2:]
143
+ state = "pattern"
144
+ flags = ""
145
+ i = 0
146
+ while i < len(rest):
147
+ char = rest[i]
148
+ if char == "\\" and i + 1 < len(rest):
149
+ i += 2
150
+ continue
151
+ if char == "/":
152
+ if state == "pattern":
153
+ state = "replacement"
154
+ elif state == "replacement":
155
+ state = "flags"
156
+ else:
157
+ return flags
158
+ i += 1
159
+ continue
160
+ if state == "flags":
161
+ flags += char
162
+ i += 1
163
+ return flags if state == "flags" else ""
@@ -0,0 +1,111 @@
1
+ """
2
+ tools/bash/semantics.py — 命令退出码语义解析
3
+
4
+ 某些命令以非零退出码表达"正常信息"而非"错误",需要特殊解释,
5
+ 否则工具框架会将其包装为 error envelope,导致模型误认为命令失败。
6
+
7
+ 对应 CC commandSemantics.ts 的 interpretCommandResult()。
8
+
9
+ 规则定义格式:
10
+ (命令匹配正则, {退出码: 语义描述})
11
+ 语义描述为 None 表示该退出码视为成功(无 hint)
12
+ 语义描述为字符串表示非错误但需要说明(作为 hint 展示)
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import re
18
+ from dataclasses import dataclass
19
+
20
+ # ---------------------------------------------------------------------------
21
+ # 规则表(对应 CC commandSemantics.ts)
22
+ # ---------------------------------------------------------------------------
23
+
24
+ # (command_pattern, {exit_code: hint_message | None})
25
+ # hint_message=None → 视为成功,无需说明
26
+ # hint_message=str → 视为成功,present() 中以 hint 形式告知模型
27
+ _SEMANTIC_RULES: list[tuple[re.Pattern[str], dict[int, str | None]]] = [
28
+ # grep / rg / ag / ack:返回 1 = 无匹配(非错误)
29
+ (
30
+ re.compile(r"^(?:grep|rg|ag|ack|ugrep)\b"),
31
+ {1: "No matches found (exit code 1 is normal for grep when no lines match)"},
32
+ ),
33
+ # diff:返回 1 = 文件存在差异(非错误,是正常信息)
34
+ (
35
+ re.compile(r"^diff\b"),
36
+ {1: "Files differ (exit code 1 is normal for diff when files are different)"},
37
+ ),
38
+ # git diff / git log / git show:同 diff
39
+ (
40
+ re.compile(r"^git\s+(?:diff|log|show)\b"),
41
+ {1: "Files differ"},
42
+ ),
43
+ # test / [ ] / [[ ]]:返回 1 = 条件为假(正常行为)
44
+ # 注意:[ 和 [[ 不是字母字符,\b 在其后不生效,需要匹配后面的空格或行尾
45
+ (
46
+ re.compile(r"^(?:test(?:\s|$)|\[{1,2}(?:\s|$))"),
47
+ {1: "Condition is false (exit code 1 is normal for test/[ ] when condition is false)"},
48
+ ),
49
+ # cmp:返回 1 = 文件不同,返回 2 = 无法比较(错误)
50
+ (
51
+ re.compile(r"^cmp\b"),
52
+ {1: "Files are different (exit code 1 is normal for cmp when files differ)"},
53
+ ),
54
+ # ls:返回 2 = 无访问权限/不存在(真正错误,不覆盖)
55
+ # find:返回 1 = 无匹配或权限问题(某些 find 实现)
56
+ (
57
+ re.compile(r"^find\b"),
58
+ {1: None}, # 视为成功(find 无结果时返回 0 或 1 取决于实现)
59
+ ),
60
+ # git:某些子命令如 git fetch --dry-run 可能返回 1 表示有变更
61
+ (
62
+ re.compile(r"^git\s+fetch\b"),
63
+ {1: None},
64
+ ),
65
+ ]
66
+
67
+
68
+ @dataclass
69
+ class CommandResult:
70
+ """
71
+ 命令退出码语义解析结果。
72
+
73
+ is_error=True → 框架应将其视为错误(包装为 error envelope / 抛异常)
74
+ is_error=False → 视为成功,message 作为 hint 展示给模型
75
+ message → 语义说明(非空时注入 present() 的 hints)
76
+ """
77
+
78
+ is_error: bool
79
+ message: str | None = None
80
+
81
+
82
+ def interpret_command_result(
83
+ command: str,
84
+ exit_code: int,
85
+ stdout: str, # noqa: ARG001 保留参数供将来内容感知判断使用
86
+ ) -> CommandResult:
87
+ """
88
+ 解析命令退出码,判断是否为真正错误。
89
+
90
+ 返回:
91
+ CommandResult.is_error=False → 非错误,可能包含 hint 说明
92
+ CommandResult.is_error=True → 真正的执行错误
93
+
94
+ 对应 CC commandSemantics.ts::interpretCommandResult()。
95
+ """
96
+ if exit_code == 0:
97
+ return CommandResult(is_error=False)
98
+
99
+ # 提取命令基础部分(去掉参数)用于正则匹配
100
+ cmd_stripped = command.strip()
101
+
102
+ for pattern, code_map in _SEMANTIC_RULES:
103
+ if pattern.match(cmd_stripped):
104
+ if exit_code in code_map:
105
+ hint = code_map[exit_code]
106
+ return CommandResult(is_error=False, message=hint)
107
+ # 命令匹配但退出码不在规则表 → 视为错误
108
+ return CommandResult(is_error=True)
109
+
110
+ # 未命中任何规则 → 非零退出码视为错误
111
+ return CommandResult(is_error=True)
@@ -0,0 +1,205 @@
1
+ """
2
+ tools/bash/session_manager.py — BashRuntimeTool v3:会话管理器
3
+
4
+ 职责:
5
+ 管理多个 `BashSessionRuntime` 的创建、复用与销毁,保证:
6
+ 1. 同一 session_key 复用同一长期 shell
7
+ 2. 多会话之间状态隔离
8
+ 3. 空闲会话按 TTL 清理
9
+
10
+ 与 CC 对照:
11
+ 对应 CC 长期 shell 任务管理模型的 Python 化基础设施。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import os
17
+ import threading
18
+ import time
19
+ from dataclasses import dataclass
20
+
21
+ from .session_runtime import BashSessionRuntime
22
+
23
+
24
+ @dataclass
25
+ class _SessionEntry:
26
+ runtime: BashSessionRuntime
27
+ last_used_ts: float
28
+ created_ts: float
29
+ command_count: int = 0
30
+ recycled_count: int = 0
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ class BashSessionAuditRecord:
35
+ session_key: str
36
+ event: str
37
+ ts: float
38
+ details: dict[str, str]
39
+
40
+
41
+ class BashSessionManager:
42
+ """Bash 长期会话管理器。"""
43
+
44
+ def __init__(
45
+ self,
46
+ *,
47
+ idle_ttl_sec: int = 900,
48
+ max_sessions: int = 16,
49
+ max_commands_per_session: int = 200,
50
+ ) -> None:
51
+ self._idle_ttl_sec = max(60, idle_ttl_sec)
52
+ self._max_sessions = max(1, max_sessions)
53
+ # 允许小阈值以便测试与细粒度回收(最小为 1)
54
+ self._max_commands_per_session = max(1, max_commands_per_session)
55
+ self._sessions: dict[str, _SessionEntry] = {}
56
+ self._audit_log: list[BashSessionAuditRecord] = []
57
+ self._lock = threading.Lock()
58
+
59
+ def get_or_create(
60
+ self,
61
+ *,
62
+ session_key: str,
63
+ cwd: str | None,
64
+ env: dict[str, str],
65
+ ) -> BashSessionRuntime:
66
+ now = time.time()
67
+ with self._lock:
68
+ self._cleanup_expired_locked(now)
69
+ self._enforce_max_sessions_locked(now)
70
+ entry = self._sessions.get(session_key)
71
+ if entry is None:
72
+ runtime = BashSessionRuntime(
73
+ initial_cwd=cwd,
74
+ base_env=env,
75
+ )
76
+ entry = _SessionEntry(runtime=runtime, last_used_ts=now, created_ts=now)
77
+ self._sessions[session_key] = entry
78
+ self._append_audit_locked(
79
+ session_key=session_key,
80
+ event="created",
81
+ details={"cwd": cwd or "", "env_size": str(len(env))},
82
+ )
83
+ else:
84
+ entry.last_used_ts = now
85
+ if entry.command_count >= self._max_commands_per_session:
86
+ entry.runtime.close()
87
+ entry.runtime = BashSessionRuntime(initial_cwd=cwd, base_env=env)
88
+ entry.command_count = 0
89
+ entry.recycled_count += 1
90
+ self._append_audit_locked(
91
+ session_key=session_key,
92
+ event="recycled_command_limit",
93
+ details={"recycled_count": str(entry.recycled_count)},
94
+ )
95
+ entry.command_count += 1
96
+ return entry.runtime
97
+
98
+ def reset_session(self, session_key: str, *, cwd: str | None = None, env: dict[str, str] | None = None) -> None:
99
+ with self._lock:
100
+ old = self._sessions.pop(session_key, None)
101
+ if old is not None:
102
+ old.runtime.close()
103
+ runtime = BashSessionRuntime(initial_cwd=cwd, base_env=(env or os.environ.copy()))
104
+ now = time.time()
105
+ self._sessions[session_key] = _SessionEntry(
106
+ runtime=runtime,
107
+ last_used_ts=now,
108
+ created_ts=now,
109
+ command_count=0,
110
+ recycled_count=0,
111
+ )
112
+ self._append_audit_locked(
113
+ session_key=session_key,
114
+ event="reset",
115
+ details={"cwd": cwd or "", "env_size": str(len(env or {}))},
116
+ )
117
+
118
+ def close_session(self, session_key: str) -> None:
119
+ with self._lock:
120
+ entry = self._sessions.pop(session_key, None)
121
+ if entry is not None:
122
+ entry.runtime.close()
123
+ with self._lock:
124
+ self._append_audit_locked(
125
+ session_key=session_key,
126
+ event="closed",
127
+ details={},
128
+ )
129
+
130
+ def close_all(self) -> None:
131
+ with self._lock:
132
+ entries = list(self._sessions.values())
133
+ self._sessions.clear()
134
+ for entry in entries:
135
+ entry.runtime.close()
136
+
137
+ def _cleanup_expired_locked(self, now_ts: float) -> None:
138
+ expired_keys = [
139
+ key
140
+ for key, entry in self._sessions.items()
141
+ if (now_ts - entry.last_used_ts) > self._idle_ttl_sec
142
+ ]
143
+ for key in expired_keys:
144
+ entry = self._sessions.pop(key, None)
145
+ if entry is not None:
146
+ entry.runtime.close()
147
+ self._append_audit_locked(
148
+ session_key=key,
149
+ event="expired",
150
+ details={"idle_ttl_sec": str(self._idle_ttl_sec)},
151
+ )
152
+
153
+ def _enforce_max_sessions_locked(self, now_ts: float) -> None:
154
+ if len(self._sessions) < self._max_sessions:
155
+ return
156
+ oldest_key = min(
157
+ self._sessions.keys(),
158
+ key=lambda k: self._sessions[k].last_used_ts,
159
+ )
160
+ oldest = self._sessions.pop(oldest_key, None)
161
+ if oldest is not None:
162
+ oldest.runtime.close()
163
+ self._append_audit_locked(
164
+ session_key=oldest_key,
165
+ event="evicted_max_sessions",
166
+ details={"max_sessions": str(self._max_sessions), "ts": str(now_ts)},
167
+ )
168
+
169
+ def get_audit_log(self, *, tail: int = 200) -> list[BashSessionAuditRecord]:
170
+ with self._lock:
171
+ if tail <= 0:
172
+ return []
173
+ return list(self._audit_log[-tail:])
174
+
175
+ def _append_audit_locked(self, *, session_key: str, event: str, details: dict[str, str]) -> None:
176
+ self._audit_log.append(
177
+ BashSessionAuditRecord(
178
+ session_key=session_key,
179
+ event=event,
180
+ ts=time.time(),
181
+ details=details,
182
+ )
183
+ )
184
+ if len(self._audit_log) > 2000:
185
+ self._audit_log = self._audit_log[-1000:]
186
+
187
+
188
+ _GLOBAL_SESSION_MANAGER: BashSessionManager | None = None
189
+ _GLOBAL_SESSION_MANAGER_LOCK = threading.Lock()
190
+
191
+
192
+ def get_global_bash_session_manager() -> BashSessionManager:
193
+ """获取全局会话管理器(延迟初始化)。"""
194
+ global _GLOBAL_SESSION_MANAGER
195
+ with _GLOBAL_SESSION_MANAGER_LOCK:
196
+ if _GLOBAL_SESSION_MANAGER is None:
197
+ ttl = int(os.getenv("AGENTX_BASH_SESSION_IDLE_TTL_SEC", "900"))
198
+ max_sessions = int(os.getenv("AGENTX_BASH_MAX_SESSIONS", "16"))
199
+ max_commands = int(os.getenv("AGENTX_BASH_MAX_COMMANDS_PER_SESSION", "200"))
200
+ _GLOBAL_SESSION_MANAGER = BashSessionManager(
201
+ idle_ttl_sec=ttl,
202
+ max_sessions=max_sessions,
203
+ max_commands_per_session=max_commands,
204
+ )
205
+ return _GLOBAL_SESSION_MANAGER