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,325 @@
1
+ """instruction/loader.py — Layer 1 规则加载编排。
2
+
3
+ 职责:
4
+ 负责规则文件加载、@path 展开、frontmatter 路径解析与条件规则筛选。
5
+
6
+ 链路位置:
7
+ Loop 初始化 -> load_rule_set(...) -> LoadedRuleSet -> sections 组装。
8
+
9
+ 当前裁剪范围:
10
+ 仅处理 Layer 1 文本加载与匹配,不解析规则业务语义。
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import re
16
+ from pathlib import Path
17
+
18
+ from wcmatch import glob as wcglob
19
+
20
+ from langchain_agentx.utils.path_hierarchy import is_filesystem_root
21
+
22
+ from .resolver import resolve_rules_file_name
23
+ from .types import ConditionalRule, InstructionMemoryConfig, LoadedRuleSet, RuleFile, RuleLayer
24
+
25
+ _AT_PATH_RE = re.compile(r"(?:^|\s)@((?:[^\s\\]|\\ )+)")
26
+ _HTML_COMMENT_RE = re.compile(r"<!--.*?-->", re.DOTALL)
27
+
28
+
29
+ class ProjectRuleCollector:
30
+ """Project 规则文件收集器(workspace_root 向上遍历)。"""
31
+
32
+ def collect(self, *, workspace_root: Path, agent_home: str, rules_file: str) -> list[Path]:
33
+ found: list[Path] = []
34
+ current = workspace_root.resolve()
35
+ while True:
36
+ candidate = current / agent_home / rules_file
37
+ if candidate.exists():
38
+ found.append(candidate)
39
+ if is_filesystem_root(current):
40
+ break
41
+ current = current.parent
42
+ found.reverse()
43
+ return found
44
+
45
+
46
+ class AtPathResolver:
47
+ """`@path` 路径解析器(支持 ~/、绝对路径、fragment、转义空格)。"""
48
+
49
+ def resolve(self, *, raw: str, current_file: Path) -> Path:
50
+ normalized = raw.replace(r"\ ", " ")
51
+ normalized = normalized.split("#")[0]
52
+ p = Path(normalized)
53
+ if p.is_absolute():
54
+ return p.resolve()
55
+ if normalized.startswith("~/"):
56
+ return (Path.home() / normalized[2:]).resolve()
57
+ return (current_file.parent / p).resolve()
58
+
59
+
60
+ class AtPathProcessor:
61
+ """`@path` 行内展开器(代码块内跳过,循环/缺失文件保留原文)。"""
62
+
63
+ def __init__(self, *, depth_limit: int, resolver: AtPathResolver | None = None) -> None:
64
+ self._depth_limit = depth_limit
65
+ self._resolver = resolver or AtPathResolver()
66
+
67
+ def process(
68
+ self,
69
+ *,
70
+ current_path: Path,
71
+ content: str,
72
+ visited: frozenset[Path],
73
+ depth: int,
74
+ ) -> str:
75
+ if depth > self._depth_limit:
76
+ return content
77
+
78
+ lines: list[str] = []
79
+ in_code_block = False
80
+ for line in content.splitlines(keepends=True):
81
+ stripped = line.rstrip("\n\r")
82
+ if stripped.startswith("```") or stripped.startswith("~~~"):
83
+ in_code_block = not in_code_block
84
+ lines.append(line)
85
+ continue
86
+ if in_code_block:
87
+ lines.append(line)
88
+ continue
89
+ matches = _AT_PATH_RE.findall(stripped)
90
+ if not matches:
91
+ lines.append(line)
92
+ continue
93
+ result_line = line
94
+ for raw in matches:
95
+ resolved = self._resolver.resolve(raw=raw, current_file=current_path)
96
+ if resolved in visited:
97
+ continue
98
+ if not resolved.exists():
99
+ continue
100
+ included = resolved.read_text(encoding="utf-8")
101
+ expanded = self.process(
102
+ current_path=resolved,
103
+ content=included,
104
+ visited=visited | {resolved},
105
+ depth=depth + 1,
106
+ )
107
+ result_line = result_line.replace(f"@{raw}", expanded, 1)
108
+ lines.append(result_line)
109
+ return "".join(lines)
110
+
111
+
112
+ def strip_html_comments(content: str) -> str:
113
+ return _HTML_COMMENT_RE.sub('', content)
114
+
115
+
116
+ class FrontmatterPathsParser:
117
+ def parse(self, raw: str) -> tuple[str, list[str]]:
118
+ """解析 frontmatter,返回 (去除 frontmatter 的正文, paths 列表)。"""
119
+ lines = raw.splitlines(keepends=True)
120
+ if len(lines) < 3 or lines[0].strip() != "---":
121
+ return raw, []
122
+ end_idx = None
123
+ for i in range(1, len(lines)):
124
+ if lines[i].strip() == "---":
125
+ end_idx = i
126
+ break
127
+ if end_idx is None:
128
+ return raw, []
129
+
130
+ fm_block = "".join(lines[1:end_idx])
131
+ content = "".join(lines[end_idx + 1:])
132
+ patterns = self._parse_paths_block(fm_block)
133
+ return content, patterns
134
+
135
+ def parse_paths(self, raw: str) -> list[str]:
136
+ _, patterns = self.parse(raw)
137
+ return patterns
138
+
139
+ def _parse_paths_block(self, fm_block: str) -> list[str]:
140
+ fm_lines = fm_block.splitlines()
141
+ in_paths = False
142
+ patterns: list[str] = []
143
+ for line in fm_lines:
144
+ stripped = line.strip()
145
+ if not stripped:
146
+ continue
147
+ if stripped.startswith("paths:"):
148
+ direct = stripped[len("paths:"):].strip()
149
+ if direct:
150
+ patterns.extend(self._split_inline_paths(direct))
151
+ in_paths = True
152
+ continue
153
+ if in_paths:
154
+ if stripped.startswith("- "):
155
+ val = stripped[2:].strip().strip("'").strip('"')
156
+ if val:
157
+ patterns.append(val)
158
+ else:
159
+ in_paths = False
160
+ return patterns
161
+
162
+ @staticmethod
163
+ def _split_inline_paths(raw: str) -> list[str]:
164
+ # 支持 paths: "a,b" 或 paths: a,b;逗号分隔时忽略空白项。
165
+ normalized = raw.strip().strip("'").strip('"')
166
+ if not normalized:
167
+ return []
168
+ return [part.strip() for part in normalized.split(",") if part.strip()]
169
+
170
+
171
+ def _path_matches_pattern(file_path: str, pattern: str) -> bool:
172
+ return wcglob.globmatch(file_path, pattern, flags=wcglob.GLOBSTAR)
173
+
174
+
175
+ def _parse_paths_from_frontmatter(raw: str) -> list[str]:
176
+ return FrontmatterPathsParser().parse_paths(raw)
177
+
178
+
179
+ def get_active_conditional_rules(
180
+ conditional_rules: list[ConditionalRule],
181
+ active_files: list[str],
182
+ ) -> list[ConditionalRule]:
183
+ result: list[ConditionalRule] = []
184
+ for rule in conditional_rules:
185
+ if not rule.paths_patterns:
186
+ result.append(rule)
187
+ continue
188
+ if any(
189
+ _path_matches_pattern(f, pattern)
190
+ for f in active_files
191
+ for pattern in rule.paths_patterns
192
+ ):
193
+ result.append(rule)
194
+ return result
195
+
196
+
197
+ class InstructionRuleLoader:
198
+ def __init__(
199
+ self,
200
+ *,
201
+ cfg: InstructionMemoryConfig,
202
+ frontmatter_parser: FrontmatterPathsParser | None = None,
203
+ project_collector: ProjectRuleCollector | None = None,
204
+ at_path_processor: AtPathProcessor | None = None,
205
+ ) -> None:
206
+ self._cfg = cfg
207
+ self._frontmatter_parser = frontmatter_parser or FrontmatterPathsParser()
208
+ self._project_collector = project_collector or ProjectRuleCollector()
209
+ self._at_path_processor = at_path_processor or AtPathProcessor(
210
+ depth_limit=cfg.include_depth_limit
211
+ )
212
+
213
+ def load(self) -> LoadedRuleSet:
214
+ ws = self._cfg.workspace_cfg
215
+ rules_file, local_file, rules_dir_name = resolve_rules_file_name(ws.agent_home)
216
+
217
+ user_rf: RuleFile | None = None
218
+ if self._cfg.load_user_layer:
219
+ user_path = Path.home() / ws.agent_home / rules_file
220
+ if user_path.exists():
221
+ user_rf = self._load_file(user_path, RuleLayer.USER)
222
+
223
+ project_paths = self._project_collector.collect(
224
+ workspace_root=ws.workspace_root,
225
+ agent_home=ws.agent_home,
226
+ rules_file=rules_file,
227
+ )
228
+ project_files = [
229
+ self._load_file(p, RuleLayer.PROJECT) for p in project_paths
230
+ ]
231
+
232
+ local_path = ws.agent_home_dir / local_file
233
+ local_rf = self._load_file(local_path, RuleLayer.LOCAL) if local_path.exists() else None
234
+
235
+ rules_dir = ws.agent_home_dir / rules_dir_name
236
+ conditional = self._load_conditional_rules(rules_dir)
237
+
238
+ return LoadedRuleSet(
239
+ managed=self._cfg.managed_rules,
240
+ user=user_rf,
241
+ project_files=project_files,
242
+ local=local_rf,
243
+ conditional_rules=conditional,
244
+ )
245
+
246
+ def _load_file(self, path: Path, layer: RuleLayer) -> RuleFile:
247
+ raw = path.read_text(encoding="utf-8")
248
+ content_wo_frontmatter, _ = self._frontmatter_parser.parse(raw)
249
+ content = self._at_path_processor.process(
250
+ current_path=path,
251
+ content=content_wo_frontmatter,
252
+ visited=frozenset([path.resolve()]),
253
+ depth=0,
254
+ )
255
+ return RuleFile(path=path, content=content, source_layer=layer)
256
+
257
+ def _load_conditional_rules(self, rules_dir: Path) -> list[ConditionalRule]:
258
+ if not rules_dir.exists() or not rules_dir.is_dir():
259
+ return []
260
+ result: list[ConditionalRule] = []
261
+ for file_path in sorted(rules_dir.glob("*.md"), key=lambda p: p.name):
262
+ raw = file_path.read_text(encoding="utf-8")
263
+ content_wo_frontmatter, patterns = self._frontmatter_parser.parse(raw)
264
+ content = self._at_path_processor.process(
265
+ current_path=file_path,
266
+ content=content_wo_frontmatter,
267
+ visited=frozenset([file_path.resolve()]),
268
+ depth=0,
269
+ )
270
+ result.append(ConditionalRule(path=file_path, content=content, paths_patterns=patterns))
271
+ return result
272
+
273
+
274
+ def load_rule_set(cfg: InstructionMemoryConfig) -> LoadedRuleSet:
275
+ return InstructionRuleLoader(cfg=cfg).load()
276
+
277
+
278
+ def load_conditional_rules(rules_dir: Path, depth_limit: int) -> list[ConditionalRule]:
279
+ if not rules_dir.exists() or not rules_dir.is_dir():
280
+ return []
281
+ parser = FrontmatterPathsParser()
282
+ processor = AtPathProcessor(depth_limit=depth_limit)
283
+ result: list[ConditionalRule] = []
284
+ for file_path in sorted(rules_dir.glob("*.md"), key=lambda p: p.name):
285
+ raw = file_path.read_text(encoding="utf-8")
286
+ content_wo_frontmatter, patterns = parser.parse(raw)
287
+ content = processor.process(
288
+ current_path=file_path,
289
+ content=content_wo_frontmatter,
290
+ visited=frozenset([file_path.resolve()]),
291
+ depth=0,
292
+ )
293
+ result.append(ConditionalRule(path=file_path, content=content, paths_patterns=patterns))
294
+ return result
295
+
296
+
297
+ def collect_project_rule_files(
298
+ workspace_root: Path,
299
+ agent_home: str,
300
+ rules_file: str,
301
+ ) -> list[Path]:
302
+ return ProjectRuleCollector().collect(
303
+ workspace_root=workspace_root,
304
+ agent_home=agent_home,
305
+ rules_file=rules_file,
306
+ )
307
+
308
+
309
+ def _resolve_at_path(raw: str, current_file: Path) -> Path:
310
+ return AtPathResolver().resolve(raw=raw, current_file=current_file)
311
+
312
+
313
+ def process_at_paths(
314
+ current_path: Path,
315
+ content: str,
316
+ visited: frozenset[Path],
317
+ depth: int,
318
+ depth_limit: int,
319
+ ) -> str:
320
+ return AtPathProcessor(depth_limit=depth_limit).process(
321
+ current_path=current_path,
322
+ content=content,
323
+ visited=visited,
324
+ depth=depth,
325
+ )
@@ -0,0 +1,24 @@
1
+ """instruction/resolver.py — Layer 1 规则文件名解析器。
2
+
3
+ 职责:
4
+ 基于 agent_home 返回主规则文件、本地规则文件、rules 目录名映射。
5
+
6
+ 链路位置:
7
+ InstructionRuleLoader.load() -> resolve_rules_file_name(...)。
8
+
9
+ 当前裁剪范围:
10
+ 仅做名称映射,不执行目录扫描与存在性回退。
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ _AGENT_HOME_MAP: dict[str, tuple[str, str, str]] = {
16
+ ".claude": ("CLAUDE.md", "CLAUDE.local.md", "rules"),
17
+ ".cursor": (".cursorrules", ".cursorrules.local", "rules"),
18
+ }
19
+ _DEFAULT = ("AGENT.md", "AGENT.local.md", "rules")
20
+
21
+
22
+ def resolve_rules_file_name(agent_home: str) -> tuple[str, str, str]:
23
+ return _AGENT_HOME_MAP.get(agent_home, _DEFAULT)
24
+
@@ -0,0 +1,83 @@
1
+ """instruction/runtime.py — Layer 1 在 loop 侧的接线协作者。
2
+
3
+ 职责:
4
+ 封装 Instruction Memory 在运行时的配置解析与 section 构建,避免工厂内联拼装。
5
+
6
+ 链路位置:
7
+ LoopGraphBuilder.__init__ -> InstructionMemoryBootstrap.build_sections()。
8
+
9
+ 当前裁剪范围:
10
+ 提供默认 active_files 提供器(空列表),具体会话采集策略由上层注入。
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from collections.abc import Callable
16
+ from pathlib import Path
17
+
18
+ from langchain_agentx.loop.prompt import SystemPromptSection
19
+ from langchain_agentx.workspace import resolve_agent_workspace_config
20
+
21
+ from .loader import load_rule_set
22
+ from .sections import make_instruction_sections
23
+ from .types import InstructionMemoryConfig
24
+
25
+
26
+ class InstructionMemoryBootstrap:
27
+ def __init__(
28
+ self,
29
+ *,
30
+ workspace_root: str | Path,
31
+ agent_home: str,
32
+ managed_rules: str | None,
33
+ include_depth_limit: int = 5,
34
+ active_files_provider: "ActiveFilesProvider | None" = None,
35
+ ) -> None:
36
+ self._workspace_root = workspace_root
37
+ self._agent_home = agent_home
38
+ self._managed_rules = managed_rules
39
+ self._include_depth_limit = include_depth_limit
40
+ self._active_files_provider = active_files_provider or NullActiveFilesProvider()
41
+
42
+ def build_sections(self) -> list[SystemPromptSection]:
43
+ workspace_cfg = resolve_agent_workspace_config(
44
+ workspace_root=self._workspace_root,
45
+ agent_home=self._agent_home,
46
+ )
47
+ loaded_rules = load_rule_set(
48
+ InstructionMemoryConfig(
49
+ workspace_cfg=workspace_cfg,
50
+ managed_rules=self._managed_rules,
51
+ load_user_layer=True,
52
+ include_depth_limit=self._include_depth_limit,
53
+ )
54
+ )
55
+ return make_instruction_sections(
56
+ loaded_rules,
57
+ active_files_getter=self._active_files_provider.get_active_files,
58
+ )
59
+
60
+
61
+ class ActiveFilesProvider:
62
+ """active_files 提供器接口。"""
63
+
64
+ def get_active_files(self) -> list[str]:
65
+ raise NotImplementedError()
66
+
67
+
68
+ class NullActiveFilesProvider(ActiveFilesProvider):
69
+ """默认 provider:无会话文件上下文时返回空列表。"""
70
+
71
+ def get_active_files(self) -> list[str]:
72
+ return []
73
+
74
+
75
+ class CallbackActiveFilesProvider(ActiveFilesProvider):
76
+ """通过回调函数桥接外部会话上下文。"""
77
+
78
+ def __init__(self, getter: Callable[[], list[str]]) -> None:
79
+ self._getter = getter
80
+
81
+ def get_active_files(self) -> list[str]:
82
+ return list(self._getter() or [])
83
+
@@ -0,0 +1,83 @@
1
+ """instruction/sections.py — Layer 1 规则段装配器。
2
+
3
+ 职责:
4
+ 将 LoadedRuleSet 按静态/动态规则拆分为可缓存的 prompt sections。
5
+
6
+ 链路位置:
7
+ load_rule_set(...) -> make_instruction_sections(...) -> build_effective_system_prompt(...)。
8
+
9
+ 当前裁剪范围:
10
+ 仅负责文本组装,不负责文件加载与 active_files 维护。
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from collections.abc import Callable
16
+
17
+ from langchain_agentx.loop.prompt import SystemPromptSection, section, volatile_section
18
+
19
+ from .loader import get_active_conditional_rules, strip_html_comments
20
+ from .types import LoadedRuleSet
21
+
22
+
23
+ class InstructionSectionBuilder:
24
+ def __init__(
25
+ self,
26
+ *,
27
+ rule_set: LoadedRuleSet,
28
+ active_files_getter: Callable[[], list[str]],
29
+ ) -> None:
30
+ self._rule_set = rule_set
31
+ self._active_files_getter = active_files_getter
32
+
33
+ def build_static_rules(self) -> str | None:
34
+ parts: list[str] = []
35
+ if self._rule_set.managed:
36
+ parts.append(strip_html_comments(self._rule_set.managed))
37
+ if self._rule_set.user:
38
+ parts.append(strip_html_comments(self._rule_set.user.content))
39
+ for rf in self._rule_set.project_files:
40
+ parts.append(strip_html_comments(rf.content))
41
+ if self._rule_set.local:
42
+ parts.append(strip_html_comments(self._rule_set.local.content))
43
+ for rule in self._rule_set.conditional_rules:
44
+ if not rule.paths_patterns:
45
+ parts.append(strip_html_comments(rule.content))
46
+ return "".join(parts) if parts else None
47
+
48
+ def build_conditional_rules(self) -> str | None:
49
+ dynamic_rules = [
50
+ r
51
+ for r in get_active_conditional_rules(
52
+ self._rule_set.conditional_rules,
53
+ self._active_files_getter(),
54
+ )
55
+ if r.paths_patterns
56
+ ]
57
+ if not dynamic_rules:
58
+ return None
59
+ return "".join(strip_html_comments(r.content) for r in dynamic_rules)
60
+
61
+ def build_sections(self) -> list[SystemPromptSection]:
62
+ return [
63
+ section(
64
+ name="agent_rules_static",
65
+ compute=self.build_static_rules,
66
+ ),
67
+ volatile_section(
68
+ name="agent_rules_conditional",
69
+ compute=self.build_conditional_rules,
70
+ reason="active_files changes as session progresses; paths matching must re-evaluate each turn",
71
+ ),
72
+ ]
73
+
74
+
75
+ def make_instruction_sections(
76
+ rule_set: LoadedRuleSet,
77
+ active_files_getter: Callable[[], list[str]],
78
+ ) -> list[SystemPromptSection]:
79
+ return InstructionSectionBuilder(
80
+ rule_set=rule_set,
81
+ active_files_getter=active_files_getter,
82
+ ).build_sections()
83
+
@@ -0,0 +1,59 @@
1
+ """instruction/types.py — Layer 1 指令规则核心数据模型。
2
+
3
+ 职责:
4
+ 定义规则来源层、单文件结果、条件规则、完整加载结果与配置入口。
5
+
6
+ 链路位置:
7
+ resolver/loader/sections 之间共享的契约层。
8
+
9
+ 当前裁剪范围:
10
+ 仅数据建模,不包含任何 IO 或匹配逻辑。
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from dataclasses import dataclass
16
+ from enum import Enum
17
+ from pathlib import Path
18
+
19
+ from langchain_agentx.workspace import AgentWorkspaceConfig
20
+
21
+
22
+ class RuleLayer(str, Enum):
23
+ MANAGED = "managed"
24
+ USER = "user"
25
+ PROJECT = "project"
26
+ RULES = "rules"
27
+ LOCAL = "local"
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class RuleFile:
32
+ path: Path | None
33
+ content: str
34
+ source_layer: RuleLayer
35
+
36
+
37
+ @dataclass(frozen=True)
38
+ class ConditionalRule:
39
+ path: Path
40
+ content: str
41
+ paths_patterns: list[str]
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class LoadedRuleSet:
46
+ managed: str | None
47
+ user: RuleFile | None
48
+ project_files: list[RuleFile] # root → workspace_root order; workspace_root has highest priority
49
+ local: RuleFile | None
50
+ conditional_rules: list[ConditionalRule]
51
+
52
+
53
+ @dataclass(frozen=True)
54
+ class InstructionMemoryConfig:
55
+ workspace_cfg: AgentWorkspaceConfig
56
+ managed_rules: str | None = None
57
+ load_user_layer: bool = True
58
+ include_depth_limit: int = 5
59
+
@@ -0,0 +1,77 @@
1
+ """memdir — Layer 2 跨会话事实记忆能力入口。"""
2
+
3
+ from .age import memory_age_days, memory_freshness_text
4
+ from .agent_memory import (
5
+ AgentMemoryExtractionContext,
6
+ AgentMemoryExtractionCoordinator,
7
+ AgentMemoryPromptBootstrap,
8
+ AgentMemoryPromptService,
9
+ AgentMemoryPathPolicy,
10
+ drain_pending_agent_memory_extraction,
11
+ get_default_agent_memory_extraction_coordinator,
12
+ is_agent_memory_path,
13
+ is_agent_memory_path_for_type,
14
+ load_agent_memory_prompt,
15
+ sanitize_agent_type,
16
+ )
17
+ from .extractor import (
18
+ MemoryExtractionContext,
19
+ MemoryExtractionCoordinator,
20
+ build_extract_prompt,
21
+ create_auto_mem_can_use_tool,
22
+ drain_pending_extraction,
23
+ execute_extract_memories,
24
+ )
25
+ from .loader import (
26
+ EntrypointTruncation,
27
+ MemoryPromptLoader,
28
+ build_memory_lines,
29
+ load_memory_prompt,
30
+ truncate_entrypoint_content,
31
+ )
32
+ from .paths import get_memory_dir, is_memory_enabled, is_memory_path
33
+ from .runtime import MemoryPromptBootstrap
34
+ from .scan import MAX_SCAN_FILES, MemoryFileHeader, MemoryScanner, format_memory_manifest, scan_memory_files
35
+ from .recall import find_relevant_memories, select_relevant_memories
36
+ from .types import MEMORY_TYPES, MemoryType, parse_memory_type
37
+
38
+ __all__ = [
39
+ "EntrypointTruncation",
40
+ "AgentMemoryPathPolicy",
41
+ "AgentMemoryExtractionContext",
42
+ "AgentMemoryExtractionCoordinator",
43
+ "AgentMemoryPromptBootstrap",
44
+ "AgentMemoryPromptService",
45
+ "get_default_agent_memory_extraction_coordinator",
46
+ "MEMORY_TYPES",
47
+ "MAX_SCAN_FILES",
48
+ "MemoryExtractionContext",
49
+ "MemoryExtractionCoordinator",
50
+ "MemoryFileHeader",
51
+ "build_extract_prompt",
52
+ "create_auto_mem_can_use_tool",
53
+ "drain_pending_extraction",
54
+ "execute_extract_memories",
55
+ "MemoryScanner",
56
+ "MemoryType",
57
+ "MemoryPromptBootstrap",
58
+ "MemoryPromptLoader",
59
+ "build_memory_lines",
60
+ "format_memory_manifest",
61
+ "get_memory_dir",
62
+ "is_memory_enabled",
63
+ "is_memory_path",
64
+ "is_agent_memory_path",
65
+ "is_agent_memory_path_for_type",
66
+ "load_agent_memory_prompt",
67
+ "drain_pending_agent_memory_extraction",
68
+ "load_memory_prompt",
69
+ "memory_age_days",
70
+ "memory_freshness_text",
71
+ "parse_memory_type",
72
+ "sanitize_agent_type",
73
+ "find_relevant_memories",
74
+ "scan_memory_files",
75
+ "select_relevant_memories",
76
+ "truncate_entrypoint_content",
77
+ ]
@@ -0,0 +1,36 @@
1
+ """
2
+ memory/memdir/age.py — Layer 2 记忆新鲜度文本。
3
+
4
+ 职责:
5
+ 基于文件更新时间计算 age 文本,为 memory manifest 提供可读提示。
6
+
7
+ 链路位置:
8
+ scan/build_memory_lines 在组装输出时读取本模块结果。
9
+
10
+ 当前裁剪范围:
11
+ 仅基于 mtime,不引入时区数据库或复杂本地化。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from datetime import datetime
17
+ from pathlib import Path
18
+
19
+
20
+ def memory_age_days(path: Path, now: datetime | None = None) -> int:
21
+ snapshot = now or datetime.now()
22
+ mtime = datetime.fromtimestamp(path.stat().st_mtime)
23
+ delta = snapshot - mtime
24
+ return max(0, delta.days)
25
+
26
+
27
+ def memory_freshness_text(path: Path, now: datetime | None = None) -> str:
28
+ days = memory_age_days(path, now=now)
29
+ if days <= 0:
30
+ return "updated today"
31
+ if days == 1:
32
+ return "updated yesterday"
33
+ return f"updated {days} days ago"
34
+
35
+
36
+ __all__ = ["memory_age_days", "memory_freshness_text"]