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,114 @@
1
+ """
2
+ http.py — HttpExecutor(P2)。
3
+
4
+ 职责:
5
+ 执行 http 类型 hook,负责请求构建、响应解析与错误收敛。
6
+
7
+ 链路位置:
8
+ HookEngine._run_one() 在 executor_type=="http" 时调用本执行器。
9
+
10
+ 当前裁剪范围:
11
+ 实现 HTTP POST 主路径与 JSON 协议解析;并行调度由 F6 统一处理。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import os
18
+ from dataclasses import dataclass
19
+ from typing import Any
20
+
21
+ import httpx
22
+
23
+ from ..config import HookCandidate
24
+ from ..types import HookContext, HookResult
25
+
26
+
27
+ @dataclass
28
+ class HttpExecutor:
29
+ """http 类型 hook 执行器。"""
30
+
31
+ async def run(self, candidate: HookCandidate, ctx: HookContext) -> HookResult:
32
+ config = candidate.spec.config
33
+ url = str(config.get("url") or "").strip()
34
+ if not url:
35
+ return HookResult(
36
+ outcome="non_blocking_error",
37
+ blocking_errors=["http hook missing 'url'"],
38
+ )
39
+
40
+ timeout = candidate.spec.timeout
41
+ body = {
42
+ "event": ctx.event.value,
43
+ "session_id": ctx.session_id,
44
+ "tool_name": ctx.tool_name,
45
+ "tool_input": ctx.tool_input,
46
+ "hook_stable_key": candidate.stable_key,
47
+ }
48
+ headers = self._build_headers(config)
49
+
50
+ try:
51
+ async with httpx.AsyncClient(timeout=timeout) as client:
52
+ response = await client.post(url, json=body, headers=headers)
53
+ except Exception as exc:
54
+ return HookResult(
55
+ outcome="non_blocking_error",
56
+ blocking_errors=[f"http hook request failed: {exc}"],
57
+ )
58
+
59
+ if response.status_code != 200:
60
+ return HookResult(
61
+ outcome="non_blocking_error",
62
+ blocking_errors=[f"http hook status {response.status_code}"],
63
+ )
64
+
65
+ payload = self._parse_json(response)
66
+ result = HookResult(outcome="success")
67
+ if isinstance(payload, dict):
68
+ self._apply_json_result(result, payload)
69
+ return result
70
+
71
+ @staticmethod
72
+ def _build_headers(config: dict[str, Any]) -> dict[str, str]:
73
+ headers_raw = config.get("headers")
74
+ headers: dict[str, str] = {}
75
+ if isinstance(headers_raw, dict):
76
+ headers = {str(k): str(v) for k, v in headers_raw.items()}
77
+
78
+ allowed_raw = config.get("allowedEnvVars")
79
+ allowed_env = allowed_raw if isinstance(allowed_raw, list) else []
80
+ env_values = {name: os.environ.get(name, "") for name in allowed_env if isinstance(name, str)}
81
+ for key, value in list(headers.items()):
82
+ rendered = value
83
+ for env_name, env_val in env_values.items():
84
+ rendered = rendered.replace(f"${env_name}", env_val)
85
+ headers[key] = rendered
86
+ return headers
87
+
88
+ @staticmethod
89
+ def _parse_json(response: httpx.Response) -> dict[str, Any] | None:
90
+ try:
91
+ data = response.json()
92
+ except json.JSONDecodeError:
93
+ return None
94
+ except Exception:
95
+ return None
96
+ return data if isinstance(data, dict) else None
97
+
98
+ @staticmethod
99
+ def _apply_json_result(result: HookResult, payload: dict[str, Any]) -> None:
100
+ if payload.get("continue") is False:
101
+ result.prevent_continuation = True
102
+ stop_reason = payload.get("stopReason")
103
+ if isinstance(stop_reason, str) and stop_reason.strip():
104
+ result.blocking_errors.append(stop_reason.strip())
105
+ decision = payload.get("decision")
106
+ if decision in {"allow", "ask", "deny"}:
107
+ result.permission_behavior = decision
108
+ reason = payload.get("reason")
109
+ if isinstance(reason, str) and reason.strip():
110
+ result.hook_permission_decision_reason = reason.strip()
111
+ updated_input = payload.get("updatedInput")
112
+ if isinstance(updated_input, dict):
113
+ result.updated_input = dict(updated_input)
114
+
@@ -0,0 +1,92 @@
1
+ """
2
+ prompt.py — PromptExecutor(P2)。
3
+
4
+ 职责:
5
+ 执行 prompt 类型 hook,负责 `$ARGUMENTS` 替换与 decision 解析。
6
+
7
+ 链路位置:
8
+ HookEngine._run_one() 在 executor_type=="prompt" 时调用本执行器。
9
+
10
+ 当前裁剪范围:
11
+ 通过配置注入可调用对象执行模型推理;并行调度在 F6 统一处理。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import inspect
17
+ import json
18
+ from dataclasses import dataclass
19
+ from typing import Any, Callable
20
+
21
+ from ..config import HookCandidate
22
+ from ..types import HookContext, HookResult
23
+
24
+
25
+ @dataclass
26
+ class PromptExecutor:
27
+ """prompt 类型 hook 执行器。"""
28
+
29
+ async def run(self, candidate: HookCandidate, ctx: HookContext) -> HookResult:
30
+ config = candidate.spec.config
31
+ template = str(config.get("prompt") or "").strip()
32
+ if not template:
33
+ return HookResult(
34
+ outcome="non_blocking_error",
35
+ blocking_errors=["prompt hook missing 'prompt'"],
36
+ )
37
+
38
+ runner = self._resolve_runner(config)
39
+ if runner is None:
40
+ return HookResult(
41
+ outcome="non_blocking_error",
42
+ blocking_errors=["prompt hook missing callable runner"],
43
+ )
44
+
45
+ arguments = json.dumps(ctx.tool_input or {}, ensure_ascii=False)
46
+ rendered_prompt = template.replace("$ARGUMENTS", arguments)
47
+ output_text = await self._call_runner(runner, rendered_prompt, config, ctx)
48
+ return self._parse_decision(output_text)
49
+
50
+ @staticmethod
51
+ def _resolve_runner(config: dict[str, Any]) -> Callable[..., Any] | None:
52
+ runner = config.get("runner") or config.get("llm") or config.get("model_runner")
53
+ return runner if callable(runner) else None
54
+
55
+ @staticmethod
56
+ async def _call_runner(
57
+ runner: Callable[..., Any],
58
+ rendered_prompt: str,
59
+ config: dict[str, Any],
60
+ ctx: HookContext,
61
+ ) -> str:
62
+ output = runner(rendered_prompt, config.get("model"), ctx)
63
+ if inspect.isawaitable(output):
64
+ output = await output
65
+ return str(output or "")
66
+
67
+ @staticmethod
68
+ def _parse_decision(text: str) -> HookResult:
69
+ lowered = text.lower()
70
+ if "deny" in lowered:
71
+ return HookResult(
72
+ outcome="success",
73
+ permission_behavior="deny",
74
+ hook_permission_decision_reason=text.strip() or None,
75
+ )
76
+ if "ask" in lowered:
77
+ return HookResult(
78
+ outcome="success",
79
+ permission_behavior="ask",
80
+ hook_permission_decision_reason=text.strip() or None,
81
+ )
82
+ if "allow" in lowered:
83
+ return HookResult(
84
+ outcome="success",
85
+ permission_behavior="allow",
86
+ hook_permission_decision_reason=text.strip() or None,
87
+ )
88
+ return HookResult(
89
+ outcome="non_blocking_error",
90
+ blocking_errors=["prompt hook cannot parse decision"],
91
+ )
92
+
@@ -0,0 +1,134 @@
1
+ """
2
+ graph_wiring.py — Hook 与 Loop 图装配协作者(Phase 2)。
3
+
4
+ 职责:
5
+ 封装 Hook 节点工厂与最小接线路径,避免 factory.py 继续膨胀。
6
+
7
+ 链路位置:
8
+ 由 loop/graph/factory.py 在构图阶段调用,产出 loop_start / stop_hooks 节点。
9
+
10
+ 当前裁剪范围:
11
+ Phase 2 仅接入 `loop_start` 与 `stop_hooks` 主路径;before/after/loop_end 节点先提供工厂占位。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass, field
17
+ from typing import Any
18
+ from uuid import uuid4
19
+
20
+ from .async_hook_runner import AsyncHookRunner
21
+ from .engine import HookEngine
22
+ from .types import AggregatedHookResult, HookContext, HookEvent
23
+
24
+
25
+ def _to_hook_result_dict(result: AggregatedHookResult) -> dict[str, Any]:
26
+ return {
27
+ "prevent_continuation": result.prevent_continuation,
28
+ "blocking_errors": list(result.blocking_errors) or None,
29
+ "permission_behavior": result.permission_behavior,
30
+ "hook_permission_decision_reason": result.hook_permission_decision_reason,
31
+ "additional_contexts": list(result.additional_contexts),
32
+ "updated_input": result.updated_input,
33
+ "state_patch": dict(result.state_patch),
34
+ }
35
+
36
+
37
+ @dataclass
38
+ class HookGraphWiring:
39
+ """Hook 图装配器。"""
40
+
41
+ hook_engine: HookEngine
42
+ trace_lifecycle_collector: Any | None = None
43
+ session_memory: Any | None = None
44
+ memory_extractor: Any | None = None
45
+ agent_memory_extractor: Any | None = None
46
+ workspace_cfg: Any | None = None
47
+ session_id: str | None = None
48
+ container_type: str = "interactive"
49
+ subagent_type: str | None = None
50
+ hook_runner: AsyncHookRunner = field(default_factory=AsyncHookRunner)
51
+
52
+ def loop_start_node(self, state: dict[str, Any], runtime: Any) -> dict[str, Any]:
53
+ run_id = state.get("_run_id")
54
+ if not isinstance(run_id, str) or not run_id:
55
+ preferred = getattr(self.trace_lifecycle_collector, "default_run_id", None)
56
+ run_id = preferred if isinstance(preferred, str) and preferred else uuid4().hex
57
+ state_with_run_id = dict(state)
58
+ state_with_run_id["_run_id"] = run_id
59
+ patch: dict[str, Any] = {"_run_id": run_id}
60
+ patch["_hook_engine"] = self.hook_engine
61
+ patch["_hook_runner"] = self.hook_runner
62
+ if self.trace_lifecycle_collector is not None:
63
+ patch.update(self.trace_lifecycle_collector.loop_start_node(state_with_run_id))
64
+ result = self._execute_sync(HookEvent.LOOP_START, state_with_run_id)
65
+ if result is not None:
66
+ patch["__hook_result__"] = _to_hook_result_dict(result)
67
+ if result.state_patch:
68
+ patch.update(dict(result.state_patch))
69
+ return patch
70
+
71
+ def before_model_node(self, state: dict[str, Any], runtime: Any) -> dict[str, Any]:
72
+ result = self._execute_sync(HookEvent.BEFORE_MODEL, state)
73
+ patch = {"__hook_result__": _to_hook_result_dict(result)} if result is not None else {}
74
+ if result is not None and result.state_patch:
75
+ patch.update(dict(result.state_patch))
76
+ if self.trace_lifecycle_collector is not None:
77
+ patch.update(self.trace_lifecycle_collector.before_model_node(state))
78
+ return patch
79
+
80
+ def after_model_node(self, state: dict[str, Any], runtime: Any) -> dict[str, Any]:
81
+ result = self._execute_sync(HookEvent.AFTER_MODEL, state)
82
+ patch = {"__hook_result__": _to_hook_result_dict(result)} if result is not None else {}
83
+ if result is not None and result.state_patch:
84
+ patch.update(dict(result.state_patch))
85
+ if self.session_memory is not None:
86
+ self.session_memory.maybe_trigger(state)
87
+ if self.trace_lifecycle_collector is not None:
88
+ patch.update(self.trace_lifecycle_collector.after_model_node(state))
89
+ return patch
90
+
91
+ def stop_hooks_node(self, state: dict[str, Any], runtime: Any) -> dict[str, Any]:
92
+ # 仅在 loop_controller 会读取的时机执行 stop,避免每轮额外开销。
93
+ if not bool(state.get("should_end")):
94
+ return {}
95
+ if self.memory_extractor is not None and self.workspace_cfg is not None:
96
+ self.memory_extractor.trigger_from_state(
97
+ state=state,
98
+ workspace_cfg=self.workspace_cfg,
99
+ session_id=self.session_id or str(state.get("_session_id") or ""),
100
+ container_type=self.container_type,
101
+ )
102
+ if self.agent_memory_extractor is not None and self.workspace_cfg is not None:
103
+ self.agent_memory_extractor.trigger_from_state(
104
+ state=state,
105
+ workspace_cfg=self.workspace_cfg,
106
+ session_id=self.session_id or str(state.get("_session_id") or ""),
107
+ container_type=self.container_type,
108
+ agent_type=self.subagent_type,
109
+ )
110
+ result = self._execute_sync(HookEvent.STOP, state)
111
+ if result is None:
112
+ return {}
113
+ patch = {"__hook_result__": _to_hook_result_dict(result)}
114
+ if result.state_patch:
115
+ patch.update(dict(result.state_patch))
116
+ return patch
117
+
118
+ def loop_end_node(self, state: dict[str, Any], runtime: Any) -> dict[str, Any]:
119
+ result = self._execute_sync(HookEvent.LOOP_END, state)
120
+ patch = {"__hook_result__": _to_hook_result_dict(result)} if result is not None else {}
121
+ if result is not None and result.state_patch:
122
+ patch.update(dict(result.state_patch))
123
+ if self.trace_lifecycle_collector is not None:
124
+ patch.update(self.trace_lifecycle_collector.loop_end_node(state))
125
+ return patch
126
+
127
+ def _execute_sync(
128
+ self, event: HookEvent, state: dict[str, Any]
129
+ ) -> AggregatedHookResult | None:
130
+ ctx = HookContext(event=event, state=state, session_id=state.get("_run_id"))
131
+ return self.hook_runner.run(self.hook_engine, ctx)
132
+
133
+
134
+ __all__ = ["HookGraphWiring"]
@@ -0,0 +1,262 @@
1
+ """
2
+ registry.py — HookRegistry 用户侧入口。
3
+
4
+ 职责:
5
+ 提供类型安全的 Hook 注册 API(装饰器 / 命令式),通过 build_snapshot() 桥接到
6
+ HooksConfigSnapshot,对用户隐藏 HookSpec 内部结构。
7
+
8
+ 链路位置:
9
+ 用户构造 HookRegistry 后传入 create_loop_agent(hooks=registry);
10
+ LoopGraphBuilder._prepare_compile_context() 调用 build_snapshot() 获取快照。
11
+
12
+ 当前裁剪范围:
13
+ 已支持 P1/P2 执行器注册(function/callback/command/http/prompt/agent)。
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Any, Callable
19
+
20
+ from .config import HookSpec, HooksConfigSnapshot
21
+ from .types import HookEvent
22
+
23
+
24
+ class HookRegistry:
25
+ """用户侧 Hook 注册入口。
26
+
27
+ 隐藏 HookSpec 内部结构,通过 build_snapshot() 桥接到 HooksConfigSnapshot。
28
+ """
29
+
30
+ def __init__(self) -> None:
31
+ self._specs: list[HookSpec] = []
32
+ self._snapshots: list[HooksConfigSnapshot] = []
33
+
34
+ # ── 装饰器 API(P1)──
35
+
36
+ def on(
37
+ self,
38
+ event: HookEvent,
39
+ *,
40
+ matcher: str = "*",
41
+ timeout: float = 30.0,
42
+ managed: bool = False,
43
+ once: bool = False,
44
+ ) -> Callable:
45
+ """注册 function hook(装饰器用法)。"""
46
+ def decorator(fn: Callable) -> Callable:
47
+ self._specs.append(self._make_spec(
48
+ event=event,
49
+ executor_type="function",
50
+ config={"fn": fn},
51
+ matcher=matcher,
52
+ timeout=timeout,
53
+ managed=managed,
54
+ source="session",
55
+ once=once,
56
+ ))
57
+ return fn
58
+ return decorator
59
+
60
+ def add_callback(
61
+ self,
62
+ event: HookEvent,
63
+ callback: Callable,
64
+ *,
65
+ matcher: str = "*",
66
+ timeout: float = 30.0,
67
+ managed: bool = False,
68
+ once: bool = False,
69
+ ) -> str:
70
+ """注册 callback hook,返回 hook_id 供撤销。"""
71
+ spec = self._make_spec(
72
+ event=event,
73
+ executor_type="callback",
74
+ config={"fn": callback},
75
+ matcher=matcher,
76
+ timeout=timeout,
77
+ managed=managed,
78
+ source="session",
79
+ once=once,
80
+ )
81
+ self._specs.append(spec)
82
+ return spec.hook_id
83
+
84
+ def remove(self, hook_id: str) -> None:
85
+ """撤销已注册的 hook。"""
86
+ self._specs = [s for s in self._specs if s.hook_id != hook_id]
87
+ for snapshot in self._snapshots:
88
+ snapshot.unregister_session_hook(hook_id)
89
+
90
+ # ── P2 注册 API ──
91
+
92
+ def add_command(
93
+ self,
94
+ event: HookEvent,
95
+ command: str,
96
+ *,
97
+ matcher: str = "*",
98
+ timeout: float = 60.0,
99
+ shell: str = "bash",
100
+ condition: str | None = None,
101
+ once: bool = False,
102
+ async_: bool = False,
103
+ async_rewake: bool = False,
104
+ ) -> str:
105
+ """注册 command hook。"""
106
+ spec = self._make_spec(
107
+ event=event,
108
+ executor_type="command",
109
+ config={
110
+ "command": command,
111
+ "shell": shell,
112
+ "if": condition,
113
+ "once": once,
114
+ "async": async_,
115
+ "asyncRewake": async_rewake,
116
+ },
117
+ matcher=matcher,
118
+ timeout=timeout,
119
+ source="session",
120
+ once=once,
121
+ )
122
+ self._specs.append(spec)
123
+ return spec.hook_id
124
+
125
+ def add_http(
126
+ self,
127
+ event: HookEvent,
128
+ url: str,
129
+ *,
130
+ matcher: str = "*",
131
+ timeout: float = 30.0,
132
+ headers: dict[str, str] | None = None,
133
+ allowed_env_vars: list[str] | None = None,
134
+ condition: str | None = None,
135
+ once: bool = False,
136
+ ) -> str:
137
+ """注册 http hook。"""
138
+ spec = self._make_spec(
139
+ event=event,
140
+ executor_type="http",
141
+ config={
142
+ "url": url,
143
+ "headers": headers or {},
144
+ "allowedEnvVars": allowed_env_vars or [],
145
+ "if": condition,
146
+ "once": once,
147
+ },
148
+ matcher=matcher,
149
+ timeout=timeout,
150
+ source="session",
151
+ once=once,
152
+ )
153
+ self._specs.append(spec)
154
+ return spec.hook_id
155
+
156
+ def add_prompt(
157
+ self,
158
+ event: HookEvent,
159
+ prompt: str,
160
+ runner: Callable,
161
+ *,
162
+ matcher: str = "*",
163
+ timeout: float = 30.0,
164
+ model: str | None = None,
165
+ condition: str | None = None,
166
+ once: bool = False,
167
+ ) -> str:
168
+ """注册 prompt hook。"""
169
+ config: dict[str, Any] = {
170
+ "prompt": prompt,
171
+ "runner": runner,
172
+ "if": condition,
173
+ "once": once,
174
+ }
175
+ if model is not None:
176
+ config["model"] = model
177
+ spec = self._make_spec(
178
+ event=event,
179
+ executor_type="prompt",
180
+ config=config,
181
+ matcher=matcher,
182
+ timeout=timeout,
183
+ source="session",
184
+ once=once,
185
+ )
186
+ self._specs.append(spec)
187
+ return spec.hook_id
188
+
189
+ def add_agent(
190
+ self,
191
+ event: HookEvent,
192
+ prompt: str,
193
+ runner: Callable,
194
+ *,
195
+ matcher: str = "*",
196
+ timeout: float = 60.0,
197
+ model: str | None = None,
198
+ condition: str | None = None,
199
+ once: bool = False,
200
+ ) -> str:
201
+ """注册 agent hook。"""
202
+ config: dict[str, Any] = {
203
+ "prompt": prompt,
204
+ "runner": runner,
205
+ "if": condition,
206
+ "once": once,
207
+ }
208
+ if model is not None:
209
+ config["model"] = model
210
+ spec = self._make_spec(
211
+ event=event,
212
+ executor_type="agent",
213
+ config=config,
214
+ matcher=matcher,
215
+ timeout=timeout,
216
+ source="session",
217
+ once=once,
218
+ )
219
+ self._specs.append(spec)
220
+ return spec.hook_id
221
+
222
+ # ── 桥接到引擎层 ──
223
+
224
+ def build_snapshot(self) -> HooksConfigSnapshot:
225
+ """将注册的所有 spec 构建为 HooksConfigSnapshot,供 HookEngine 消费。"""
226
+ snapshot = HooksConfigSnapshot()
227
+ for spec in self._specs:
228
+ snapshot.add_spec(spec)
229
+ self._snapshots.append(snapshot)
230
+ return snapshot
231
+
232
+ def __len__(self) -> int:
233
+ return len(self._specs)
234
+
235
+ def _make_spec(
236
+ self,
237
+ *,
238
+ event: HookEvent,
239
+ executor_type: str,
240
+ config: dict[str, Any],
241
+ matcher: str,
242
+ timeout: float,
243
+ source: str,
244
+ managed: bool = False,
245
+ once: bool = False,
246
+ ) -> HookSpec:
247
+ spec = HookSpec(
248
+ event=event,
249
+ executor_type=executor_type,
250
+ config=config,
251
+ matcher=matcher,
252
+ timeout=timeout,
253
+ managed=managed,
254
+ source=source,
255
+ once=once,
256
+ )
257
+ if once:
258
+ spec.on_success = lambda hook_id=spec.hook_id: self.remove(hook_id)
259
+ return spec
260
+
261
+
262
+ __all__ = ["HookRegistry"]
@@ -0,0 +1,43 @@
1
+ """
2
+ trust.py — Hook 执行信任闸门。
3
+
4
+ 职责:
5
+ 在 HookEngine 执行前判断当前工作区信任状态,决定是否跳过高风险执行器。
6
+
7
+ 链路位置:
8
+ HookEngine.execute() 入口处调用,集中拦截 command/http/agent。
9
+
10
+ 当前裁剪范围:
11
+ 仅提供 should_skip/skip_reason 判断,不负责 trust 交互与持久化。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ HIGH_RISK_EXECUTORS = frozenset({"command", "http", "agent"})
17
+
18
+
19
+ class WorkspaceTrustChecker:
20
+ """Hook 执行前的工作区信任检查器。"""
21
+
22
+ def __init__(
23
+ self,
24
+ *,
25
+ headless: bool = False,
26
+ workspace_trust_accepted: bool = False,
27
+ ) -> None:
28
+ self._headless = headless
29
+ self._workspace_trust_accepted = workspace_trust_accepted
30
+
31
+ def should_skip(self, executor_type: str) -> bool:
32
+ if executor_type not in HIGH_RISK_EXECUTORS:
33
+ return False
34
+ return not self._workspace_trust_accepted
35
+
36
+ def skip_reason(self, executor_type: str) -> str:
37
+ return (
38
+ "workspace trust not accepted; "
39
+ f"executor type '{executor_type}' requires trusted workspace"
40
+ )
41
+
42
+
43
+ __all__ = ["HIGH_RISK_EXECUTORS", "WorkspaceTrustChecker"]