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,386 @@
1
+ """
2
+ plugin/loader.py — Plugin Discovery/Load/Register 主编排。
3
+
4
+ 职责:
5
+ 协调插件发现、manifest 解析、能力注册与 hook 原子切换。
6
+
7
+ 链路位置:
8
+ 由容器 on_start/on_end 调用,连接 workspace 配置、HookEngine 与各 Registry。
9
+
10
+ 当前裁剪范围:
11
+ 覆盖本地+内置插件;不包含远程插件下载与 MCP 连接管理。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import logging
18
+ from pathlib import Path
19
+ from typing import Any
20
+
21
+ from langchain_agentx.loop.hook.config import HookSpec, HooksConfigSnapshot
22
+ from langchain_agentx.loop.hook.types import HookEvent
23
+ from langchain_agentx.workspace.config import AgentWorkspaceConfig
24
+
25
+ from .builtin import BuiltinPluginRegistry
26
+ from .config import PluginConfigLoader
27
+ from .manifest import MinimalManifest, PluginManifestSchema, ValidationError
28
+ from .registries import AgentRegistry, CommandRegistry, SkillRegistry
29
+ from .types import (
30
+ GenericPluginError,
31
+ HookLoadFailedError,
32
+ LoadedPlugin,
33
+ ManifestParseError,
34
+ ManifestValidationError,
35
+ PluginError,
36
+ PluginLoadResult,
37
+ )
38
+
39
+ logger = logging.getLogger(__name__)
40
+
41
+
42
+ class PluginLoader:
43
+ def __init__(
44
+ self,
45
+ workspace_config: AgentWorkspaceConfig,
46
+ hook_engine: Any,
47
+ skill_registry: SkillRegistry,
48
+ command_registry: CommandRegistry,
49
+ agent_registry: AgentRegistry,
50
+ mcp_manager: Any | None = None,
51
+ builtin_registry: BuiltinPluginRegistry | None = None,
52
+ ) -> None:
53
+ self._cfg = workspace_config
54
+ self._hook_engine = hook_engine
55
+ self._skill_registry = skill_registry
56
+ self._command_registry = command_registry
57
+ self._agent_registry = agent_registry
58
+ self._mcp_manager = mcp_manager
59
+ self._builtin_registry = builtin_registry or BuiltinPluginRegistry.global_instance()
60
+ self._loaded: list[LoadedPlugin] = []
61
+
62
+ async def load_all(self, container_type: str | None = None) -> PluginLoadResult:
63
+ errors: list[PluginError] = []
64
+ candidates = await self._discover(errors)
65
+ if container_type:
66
+ candidates = [
67
+ plugin
68
+ for plugin in candidates
69
+ if not plugin.applicable_containers
70
+ or container_type in plugin.applicable_containers
71
+ ]
72
+
73
+ candidates = [plugin for plugin in candidates if plugin.enabled]
74
+
75
+ errors.extend(await self._register_skills(candidates))
76
+ errors.extend(await self._register_commands(candidates))
77
+ errors.extend(await self._register_agents(candidates))
78
+ errors.extend(await self._register_hooks_atomic(candidates))
79
+
80
+ self._loaded = candidates
81
+ return PluginLoadResult(enabled=candidates, errors=errors)
82
+
83
+ async def unload_all(self) -> None:
84
+ for plugin in self._loaded:
85
+ try:
86
+ self._skill_registry.unregister_plugin(plugin.source)
87
+ self._command_registry.unregister_plugin(plugin.source)
88
+ self._agent_registry.unregister_plugin(plugin.source)
89
+ except Exception as exc:
90
+ logger.error(
91
+ "plugin unload failed for %s: %s", plugin.source, exc, exc_info=True
92
+ )
93
+ snapshot = self._get_snapshot()
94
+ if snapshot is not None:
95
+ try:
96
+ snapshot.replace_plugin_hooks_atomic([])
97
+ except Exception as exc:
98
+ logger.error("plugin hook cleanup failed: %s", exc, exc_info=True)
99
+ self._loaded = []
100
+
101
+ async def reload(self, container_type: str | None = None) -> PluginLoadResult:
102
+ errors: list[PluginError] = []
103
+ candidates = await self._discover(errors)
104
+ if container_type:
105
+ candidates = [
106
+ plugin
107
+ for plugin in candidates
108
+ if not plugin.applicable_containers
109
+ or container_type in plugin.applicable_containers
110
+ ]
111
+ candidates = [plugin for plugin in candidates if plugin.enabled]
112
+
113
+ for plugin in self._loaded:
114
+ self._skill_registry.unregister_plugin(plugin.source)
115
+ self._command_registry.unregister_plugin(plugin.source)
116
+ self._agent_registry.unregister_plugin(plugin.source)
117
+
118
+ errors.extend(await self._register_skills(candidates))
119
+ errors.extend(await self._register_commands(candidates))
120
+ errors.extend(await self._register_agents(candidates))
121
+ errors.extend(await self._register_hooks_atomic(candidates))
122
+ self._loaded = candidates
123
+ return PluginLoadResult(enabled=candidates, errors=errors)
124
+
125
+ async def disable_plugin(self, plugin_source: str) -> None:
126
+ self._skill_registry.unregister_plugin(plugin_source)
127
+ self._command_registry.unregister_plugin(plugin_source)
128
+ self._agent_registry.unregister_plugin(plugin_source)
129
+ snapshot = self._get_snapshot()
130
+ if snapshot is not None:
131
+ snapshot.remove_plugin_hooks(plugin_source)
132
+ self._loaded = [plugin for plugin in self._loaded if plugin.source != plugin_source]
133
+
134
+ async def _discover(self, errors: list[PluginError]) -> list[LoadedPlugin]:
135
+ plugins: list[LoadedPlugin] = []
136
+ plugins.extend(self._discover_builtin())
137
+ local_plugins, local_errors = await self._discover_local()
138
+ plugins.extend(local_plugins)
139
+ errors.extend(local_errors)
140
+ return plugins
141
+
142
+ def _discover_builtin(self) -> list[LoadedPlugin]:
143
+ plugin_config = PluginConfigLoader.load(self._cfg)
144
+ loaded: list[LoadedPlugin] = []
145
+ for definition in self._builtin_registry.all():
146
+ plugin_id = f"{definition.name}@builtin"
147
+ enabled = plugin_config.is_enabled(plugin_id, default=definition.default_enabled)
148
+ if definition.is_available and not definition.is_available():
149
+ continue
150
+ loaded.append(
151
+ LoadedPlugin(
152
+ name=definition.name,
153
+ description=definition.description,
154
+ version=definition.version,
155
+ path="builtin",
156
+ source=plugin_id,
157
+ enabled=enabled,
158
+ is_builtin=True,
159
+ hooks_config=definition.hooks,
160
+ mcp_servers=definition.mcp_servers or {},
161
+ applicable_containers=definition.applicable_containers,
162
+ )
163
+ )
164
+ return loaded
165
+
166
+ async def _discover_local(self) -> tuple[list[LoadedPlugin], list[PluginError]]:
167
+ plugins_dir = self._cfg.plugins_dir
168
+ if not plugins_dir.exists():
169
+ return [], []
170
+
171
+ plugin_config = PluginConfigLoader.load(self._cfg)
172
+ plugins: list[LoadedPlugin] = []
173
+ errors: list[PluginError] = []
174
+ for plugin_dir in sorted(plugins_dir.iterdir()):
175
+ if not plugin_dir.is_dir():
176
+ continue
177
+ plugin_id = f"{plugin_dir.name}@local"
178
+ if not plugin_config.is_enabled(plugin_id, default=True):
179
+ continue
180
+ loaded, error = await self._load_local_plugin(plugin_dir, plugin_id)
181
+ if loaded is not None:
182
+ plugins.append(loaded)
183
+ if error is not None:
184
+ errors.append(error)
185
+ return plugins, errors
186
+
187
+ async def _load_local_plugin(
188
+ self, plugin_dir: Path, plugin_id: str
189
+ ) -> tuple[LoadedPlugin | None, PluginError | None]:
190
+ manifest_path = plugin_dir / "plugin.json"
191
+ if manifest_path.exists():
192
+ try:
193
+ raw = json.loads(manifest_path.read_text(encoding="utf-8"))
194
+ manifest = PluginManifestSchema.validate(raw)
195
+ except json.JSONDecodeError as exc:
196
+ return (
197
+ None,
198
+ ManifestParseError(
199
+ source=plugin_id,
200
+ manifest_path=str(manifest_path),
201
+ parse_error=str(exc),
202
+ ),
203
+ )
204
+ except ValidationError as exc:
205
+ return (
206
+ None,
207
+ ManifestValidationError(
208
+ source=plugin_id,
209
+ manifest_path=str(manifest_path),
210
+ validation_errors=exc.messages,
211
+ ),
212
+ )
213
+ except OSError as exc:
214
+ return (
215
+ None,
216
+ GenericPluginError(
217
+ source=plugin_id,
218
+ plugin=plugin_dir.name,
219
+ error=str(exc),
220
+ ),
221
+ )
222
+ else:
223
+ manifest = MinimalManifest(name=plugin_dir.name)
224
+
225
+ skills_dir = plugin_dir / manifest.skills_path
226
+ commands_dir = plugin_dir / manifest.commands_path
227
+ agents_dir = plugin_dir / manifest.agents_path
228
+ loaded = LoadedPlugin(
229
+ name=manifest.name,
230
+ description=manifest.description,
231
+ version=manifest.version,
232
+ path=str(plugin_dir),
233
+ source=plugin_id,
234
+ enabled=True,
235
+ is_builtin=False,
236
+ skills_dir=skills_dir if skills_dir.exists() else None,
237
+ commands_dir=commands_dir if commands_dir.exists() else None,
238
+ agents_dir=agents_dir if agents_dir.exists() else None,
239
+ hooks_config=manifest.hooks,
240
+ mcp_servers=manifest.mcp_servers,
241
+ dependencies=manifest.dependencies,
242
+ applicable_containers=manifest.applicable_containers,
243
+ )
244
+ return loaded, None
245
+
246
+ async def _register_skills(self, plugins: list[LoadedPlugin]) -> list[PluginError]:
247
+ errors: list[PluginError] = []
248
+ for plugin in plugins:
249
+ errors.extend(self._skill_registry.register(plugin))
250
+ return errors
251
+
252
+ async def _register_commands(self, plugins: list[LoadedPlugin]) -> list[PluginError]:
253
+ errors: list[PluginError] = []
254
+ for plugin in plugins:
255
+ errors.extend(self._command_registry.register(plugin))
256
+ return errors
257
+
258
+ async def _register_agents(self, plugins: list[LoadedPlugin]) -> list[PluginError]:
259
+ errors: list[PluginError] = []
260
+ for plugin in plugins:
261
+ errors.extend(self._agent_registry.register(plugin))
262
+ return errors
263
+
264
+ async def _register_hooks_atomic(self, plugins: list[LoadedPlugin]) -> list[PluginError]:
265
+ snapshot = self._get_snapshot()
266
+ if snapshot is None:
267
+ return [
268
+ GenericPluginError(
269
+ source="plugin-loader",
270
+ plugin="hook_engine",
271
+ error="hook engine snapshot is unavailable",
272
+ )
273
+ ]
274
+
275
+ errors: list[PluginError] = []
276
+ specs: list[HookSpec] = []
277
+ for plugin in plugins:
278
+ if plugin.is_builtin:
279
+ continue
280
+ if not plugin.hooks_config:
281
+ continue
282
+ built_specs, built_errors = self._convert_hooks_to_specs(plugin)
283
+ specs.extend(built_specs)
284
+ errors.extend(built_errors)
285
+
286
+ snapshot.replace_plugin_hooks_atomic(specs)
287
+ return errors
288
+
289
+ def _convert_hooks_to_specs(
290
+ self, plugin: LoadedPlugin
291
+ ) -> tuple[list[HookSpec], list[PluginError]]:
292
+ specs: list[HookSpec] = []
293
+ errors: list[PluginError] = []
294
+ hooks_config = plugin.hooks_config or {}
295
+ if not isinstance(hooks_config, dict):
296
+ return specs, errors
297
+
298
+ event_map = {event.name: event for event in HookEvent}
299
+ for event_name, matchers in hooks_config.items():
300
+ if event_name not in event_map:
301
+ logger.warning(
302
+ "plugin %s has unknown hook event %r, skipping",
303
+ plugin.source,
304
+ event_name,
305
+ )
306
+ continue
307
+ event = event_map[event_name]
308
+ if not isinstance(matchers, list):
309
+ continue
310
+ for matcher_entry in matchers:
311
+ if not isinstance(matcher_entry, dict):
312
+ continue
313
+ matcher = self._extract_matcher(matcher_entry.get("matcher", {}))
314
+ for hook_entry in matcher_entry.get("hooks", []):
315
+ spec_or_error = self._build_spec(plugin, event, matcher, hook_entry)
316
+ if isinstance(spec_or_error, HookSpec):
317
+ specs.append(spec_or_error)
318
+ else:
319
+ errors.append(spec_or_error)
320
+ return specs, errors
321
+
322
+ def _build_spec(
323
+ self,
324
+ plugin: LoadedPlugin,
325
+ event: HookEvent,
326
+ matcher: str,
327
+ hook_entry: Any,
328
+ ) -> HookSpec | HookLoadFailedError:
329
+ if not isinstance(hook_entry, dict):
330
+ return HookLoadFailedError(
331
+ source=plugin.source,
332
+ plugin=plugin.name,
333
+ hook_path=f"plugin.json/hooks/{event.name}",
334
+ reason="hook entry must be object",
335
+ )
336
+ executor_type = hook_entry.get("type")
337
+ if executor_type not in ("command", "http", "prompt", "agent"):
338
+ return HookLoadFailedError(
339
+ source=plugin.source,
340
+ plugin=plugin.name,
341
+ hook_path=f"plugin.json/hooks/{event.name}",
342
+ reason=f"unsupported executor type in manifest: {executor_type!r}",
343
+ )
344
+ if executor_type == "http" and event == HookEvent.SESSION_START:
345
+ return HookLoadFailedError(
346
+ source=plugin.source,
347
+ plugin=plugin.name,
348
+ hook_path=f"plugin.json/hooks/{event.name}",
349
+ reason="http hooks cannot be used with SessionStart event",
350
+ )
351
+ timeout = hook_entry.get("timeout", self._default_timeout(executor_type))
352
+ return HookSpec(
353
+ event=event,
354
+ executor_type=executor_type,
355
+ config=dict(hook_entry),
356
+ matcher=matcher,
357
+ timeout=float(timeout),
358
+ source="plugin",
359
+ plugin_source=plugin.source,
360
+ once=bool(hook_entry.get("once", False)),
361
+ )
362
+
363
+ @staticmethod
364
+ def _extract_matcher(matcher: Any) -> str:
365
+ if isinstance(matcher, dict):
366
+ tool_name = matcher.get("tool_name")
367
+ if isinstance(tool_name, str) and tool_name.strip():
368
+ return tool_name.strip()
369
+ return "*"
370
+
371
+ @staticmethod
372
+ def _default_timeout(executor_type: str) -> float:
373
+ if executor_type == "http":
374
+ return 30.0
375
+ return 60.0
376
+
377
+ def _get_snapshot(self) -> HooksConfigSnapshot | None:
378
+ snapshot = getattr(self._hook_engine, "snapshot", None)
379
+ if snapshot is None:
380
+ snapshot = getattr(self._hook_engine, "_snapshot", None)
381
+ if isinstance(snapshot, HooksConfigSnapshot):
382
+ return snapshot
383
+ return None
384
+
385
+
386
+ __all__ = ["PluginLoader"]
@@ -0,0 +1,154 @@
1
+ """
2
+ plugin/manifest.py — plugin.json 解析与校验。
3
+
4
+ 职责:
5
+ 定义 PluginManifest/MinimalManifest,并提供 PluginManifestSchema.validate()。
6
+
7
+ 链路位置:
8
+ PluginLoader._load_local_plugin() 在构建 LoadedPlugin 前调用本模块。
9
+
10
+ 当前裁剪范围:
11
+ 仅覆盖 P0/P1 校验规则,不包含 mcp_servers 深度校验与依赖拓扑解析。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass, field
17
+ import re
18
+ from typing import Any
19
+
20
+ from langchain_agentx.loop.hook.types import HookEvent
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class PluginManifest:
25
+ name: str
26
+ description: str = ""
27
+ version: str = "0.1.0"
28
+ applicable_containers: list[str] = field(default_factory=list)
29
+ dependencies: list[str] = field(default_factory=list)
30
+ skills_path: str = "skills"
31
+ commands_path: str = "commands"
32
+ agents_path: str = "agents"
33
+ hooks: dict[str, Any] | None = None
34
+ mcp_servers: dict[str, dict[str, Any]] = field(default_factory=dict)
35
+
36
+
37
+ @dataclass(frozen=True)
38
+ class MinimalManifest(PluginManifest):
39
+ pass
40
+
41
+
42
+ class ValidationError(Exception):
43
+ """manifest 校验错误。"""
44
+
45
+ def __init__(self, messages: list[str]) -> None:
46
+ super().__init__("; ".join(messages))
47
+ self.messages = messages
48
+
49
+
50
+ class PluginManifestSchema:
51
+ """plugin.json 校验器。"""
52
+
53
+ _name_pattern = re.compile(r"^[a-z0-9][a-z0-9-]{0,63}$")
54
+ _semver_pattern = re.compile(r"^\d+\.\d+\.\d+$")
55
+ _allowed_hook_types = {"command", "http", "prompt", "agent"}
56
+ _http_disallowed_events = {"SessionStart"}
57
+
58
+ @classmethod
59
+ def validate(cls, raw: dict[str, Any]) -> PluginManifest:
60
+ if not isinstance(raw, dict):
61
+ raise ValidationError(["manifest root must be object"])
62
+
63
+ errors: list[str] = []
64
+ name = raw.get("name")
65
+ if not isinstance(name, str) or not cls._name_pattern.fullmatch(name):
66
+ errors.append("name must match ^[a-z0-9][a-z0-9-]{0,63}$")
67
+
68
+ description = raw.get("description", "")
69
+ if description is not None and not isinstance(description, str):
70
+ errors.append("description must be string")
71
+ description = description if isinstance(description, str) else ""
72
+
73
+ version = raw.get("version", "0.1.0")
74
+ if not isinstance(version, str) or not cls._semver_pattern.fullmatch(version):
75
+ errors.append("version must be semver x.y.z")
76
+
77
+ applicable = raw.get("applicable_containers", [])
78
+ if not isinstance(applicable, list) or not all(isinstance(v, str) for v in applicable):
79
+ errors.append("applicable_containers must be list[str]")
80
+ applicable = []
81
+
82
+ dependencies = raw.get("dependencies", [])
83
+ if not isinstance(dependencies, list) or not all(isinstance(v, str) for v in dependencies):
84
+ errors.append("dependencies must be list[str]")
85
+ dependencies = []
86
+
87
+ skills_path = raw.get("skills_path", "skills")
88
+ commands_path = raw.get("commands_path", "commands")
89
+ agents_path = raw.get("agents_path", "agents")
90
+ for field_name, value in (
91
+ ("skills_path", skills_path),
92
+ ("commands_path", commands_path),
93
+ ("agents_path", agents_path),
94
+ ):
95
+ if not isinstance(value, str) or not value.strip():
96
+ errors.append(f"{field_name} must be non-empty string")
97
+
98
+ hooks = raw.get("hooks")
99
+ if hooks is not None:
100
+ cls._validate_hooks(hooks, errors)
101
+
102
+ mcp_servers = raw.get("mcp_servers", {})
103
+ if not isinstance(mcp_servers, dict):
104
+ errors.append("mcp_servers must be object")
105
+ mcp_servers = {}
106
+
107
+ if errors:
108
+ raise ValidationError(errors)
109
+
110
+ return PluginManifest(
111
+ name=name,
112
+ description=description,
113
+ version=version,
114
+ applicable_containers=applicable,
115
+ dependencies=dependencies,
116
+ skills_path=skills_path,
117
+ commands_path=commands_path,
118
+ agents_path=agents_path,
119
+ hooks=hooks if isinstance(hooks, dict) else None,
120
+ mcp_servers=mcp_servers,
121
+ )
122
+
123
+ @classmethod
124
+ def _validate_hooks(cls, hooks: Any, errors: list[str]) -> None:
125
+ if not isinstance(hooks, dict):
126
+ errors.append("hooks must be object")
127
+ return
128
+ valid_event_names = {event.name for event in HookEvent}
129
+ for event_name, matchers in hooks.items():
130
+ if not isinstance(event_name, str):
131
+ errors.append("hook event key must be string")
132
+ continue
133
+ if event_name not in valid_event_names:
134
+ # 未知事件只告警级别,忽略该 key,不阻断整个 manifest
135
+ continue
136
+ if not isinstance(matchers, list):
137
+ errors.append(f"hooks.{event_name} must be list")
138
+ continue
139
+ for matcher in matchers:
140
+ if not isinstance(matcher, dict):
141
+ errors.append(f"hooks.{event_name} matcher must be object")
142
+ continue
143
+ hook_items = matcher.get("hooks", [])
144
+ if not isinstance(hook_items, list):
145
+ errors.append(f"hooks.{event_name}.hooks must be list")
146
+ continue
147
+ for hook in hook_items:
148
+ if not isinstance(hook, dict):
149
+ errors.append(f"hooks.{event_name}.hooks[] must be object")
150
+ # hook type/http+SessionStart 语义校验由 loader._build_spec 负责,
151
+ # 此处只做结构性检查,不整体拒绝 manifest。
152
+
153
+
154
+ __all__ = ["MinimalManifest", "PluginManifest", "PluginManifestSchema", "ValidationError"]