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.
- langchain_agentx/__init__.py +46 -0
- langchain_agentx/command/__init__.py +28 -0
- langchain_agentx/command/builtin/__init__.py +25 -0
- langchain_agentx/command/builtin/clear.py +33 -0
- langchain_agentx/command/builtin/compact.py +33 -0
- langchain_agentx/command/builtin/memory.py +37 -0
- langchain_agentx/command/builtin/reload_plugins.py +42 -0
- langchain_agentx/command/context.py +30 -0
- langchain_agentx/command/dispatcher.py +183 -0
- langchain_agentx/command/registry.py +110 -0
- langchain_agentx/command/result.py +25 -0
- langchain_agentx/command/types.py +41 -0
- langchain_agentx/config/__init__.py +14 -0
- langchain_agentx/loop/__init__.py +47 -0
- langchain_agentx/loop/config/__init__.py +20 -0
- langchain_agentx/loop/config/agent_config.py +66 -0
- langchain_agentx/loop/config/agent_loop_config.py +72 -0
- langchain_agentx/loop/config/model_context_resolver.py +105 -0
- langchain_agentx/loop/config/runtime_settings.py +50 -0
- langchain_agentx/loop/config/token_estimator.py +133 -0
- langchain_agentx/loop/context/__init__.py +66 -0
- langchain_agentx/loop/context/blocking_guard.py +97 -0
- langchain_agentx/loop/context/compaction_service.py +60 -0
- langchain_agentx/loop/context/message_utils.py +56 -0
- langchain_agentx/loop/context/pipeline.py +127 -0
- langchain_agentx/loop/context/settings.py +103 -0
- langchain_agentx/loop/context/stages/__init__.py +29 -0
- langchain_agentx/loop/context/stages/autocompact.py +140 -0
- langchain_agentx/loop/context/stages/base.py +32 -0
- langchain_agentx/loop/context/stages/collapse.py +76 -0
- langchain_agentx/loop/context/stages/microcompact.py +76 -0
- langchain_agentx/loop/context/stages/noop.py +33 -0
- langchain_agentx/loop/context/stages/snip.py +71 -0
- langchain_agentx/loop/context/stages/tool_result_budget.py +69 -0
- langchain_agentx/loop/context/types.py +79 -0
- langchain_agentx/loop/exit/__init__.py +1 -0
- langchain_agentx/loop/exit/exit_logic.py +320 -0
- langchain_agentx/loop/exit/reason_codes.py +39 -0
- langchain_agentx/loop/graph/__init__.py +5 -0
- langchain_agentx/loop/graph/builtin_loop_control.py +197 -0
- langchain_agentx/loop/graph/factory.py +1409 -0
- langchain_agentx/loop/graph/graph_edges.py +820 -0
- langchain_agentx/loop/hook/__init__.py +48 -0
- langchain_agentx/loop/hook/async_hook_runner.py +62 -0
- langchain_agentx/loop/hook/config.py +280 -0
- langchain_agentx/loop/hook/engine.py +321 -0
- langchain_agentx/loop/hook/executors/__init__.py +9 -0
- langchain_agentx/loop/hook/executors/agent.py +107 -0
- langchain_agentx/loop/hook/executors/command.py +230 -0
- langchain_agentx/loop/hook/executors/http.py +114 -0
- langchain_agentx/loop/hook/executors/prompt.py +92 -0
- langchain_agentx/loop/hook/graph_wiring.py +134 -0
- langchain_agentx/loop/hook/registry.py +262 -0
- langchain_agentx/loop/hook/trust.py +43 -0
- langchain_agentx/loop/hook/types.py +110 -0
- langchain_agentx/loop/injection/__init__.py +13 -0
- langchain_agentx/loop/injection/dedup.py +74 -0
- langchain_agentx/loop/loop_abort.py +36 -0
- langchain_agentx/loop/model/__init__.py +1 -0
- langchain_agentx/loop/model/model_node.py +648 -0
- langchain_agentx/loop/model/model_nodes.py +661 -0
- langchain_agentx/loop/model/orphan_tool_results.py +38 -0
- langchain_agentx/loop/model/retrier.py +307 -0
- langchain_agentx/loop/model/retry_bridge.py +58 -0
- langchain_agentx/loop/model/retry_events.py +35 -0
- langchain_agentx/loop/model/retry_policy.py +56 -0
- langchain_agentx/loop/model/schema_and_format.py +153 -0
- langchain_agentx/loop/model/tool_and_model_binding.py +227 -0
- langchain_agentx/loop/model/tool_call_degradation_corrector.py +443 -0
- langchain_agentx/loop/model/tool_transcript_guard.py +225 -0
- langchain_agentx/loop/prompt/__init__.py +95 -0
- langchain_agentx/loop/prompt/builder.py +61 -0
- langchain_agentx/loop/prompt/builtin.py +218 -0
- langchain_agentx/loop/prompt/compact.py +408 -0
- langchain_agentx/loop/prompt/sections.py +120 -0
- langchain_agentx/loop/runtime/__init__.py +19 -0
- langchain_agentx/loop/runtime/context.py +34 -0
- langchain_agentx/loop/runtime/context_factory.py +107 -0
- langchain_agentx/loop/runtime/subagent_execution_paths.py +68 -0
- langchain_agentx/loop/subagent/__init__.py +53 -0
- langchain_agentx/loop/subagent/async_runner.py +215 -0
- langchain_agentx/loop/subagent/context.py +209 -0
- langchain_agentx/loop/subagent/fork_worktree_notice.py +25 -0
- langchain_agentx/loop/subagent/graph.py +72 -0
- langchain_agentx/loop/subagent/orchestrator.py +391 -0
- langchain_agentx/loop/subagent/progress.py +30 -0
- langchain_agentx/loop/subagent/prompt.py +52 -0
- langchain_agentx/loop/subagent/runner.py +504 -0
- langchain_agentx/loop/subagent/transcript.py +172 -0
- langchain_agentx/memory/__init__.py +2 -0
- langchain_agentx/memory/instruction/__init__.py +12 -0
- langchain_agentx/memory/instruction/loader.py +325 -0
- langchain_agentx/memory/instruction/resolver.py +24 -0
- langchain_agentx/memory/instruction/runtime.py +83 -0
- langchain_agentx/memory/instruction/sections.py +83 -0
- langchain_agentx/memory/instruction/types.py +59 -0
- langchain_agentx/memory/memdir/__init__.py +77 -0
- langchain_agentx/memory/memdir/age.py +36 -0
- langchain_agentx/memory/memdir/agent_memory.py +380 -0
- langchain_agentx/memory/memdir/extractor.py +309 -0
- langchain_agentx/memory/memdir/loader.py +187 -0
- langchain_agentx/memory/memdir/paths.py +63 -0
- langchain_agentx/memory/memdir/recall.py +45 -0
- langchain_agentx/memory/memdir/runtime.py +43 -0
- langchain_agentx/memory/memdir/scan.py +135 -0
- langchain_agentx/memory/memdir/types.py +104 -0
- langchain_agentx/memory/session/__init__.py +76 -0
- langchain_agentx/memory/session/compact_bridge.py +208 -0
- langchain_agentx/memory/session/prompts.py +172 -0
- langchain_agentx/memory/session/session_memory.py +282 -0
- langchain_agentx/observability/__init__.py +67 -0
- langchain_agentx/observability/evaluation/__init__.py +17 -0
- langchain_agentx/observability/evaluation/checkers/__init__.py +18 -0
- langchain_agentx/observability/evaluation/checkers/base.py +34 -0
- langchain_agentx/observability/evaluation/checkers/compaction.py +38 -0
- langchain_agentx/observability/evaluation/checkers/degradation.py +50 -0
- langchain_agentx/observability/evaluation/checkers/exit_quality.py +42 -0
- langchain_agentx/observability/evaluation/checkers/session_memory.py +45 -0
- langchain_agentx/observability/evaluation/checkers/tool_behavior.py +53 -0
- langchain_agentx/observability/evaluation/retention_scheduler.py +67 -0
- langchain_agentx/observability/evaluation/service.py +102 -0
- langchain_agentx/observability/evaluation/state.py +32 -0
- langchain_agentx/observability/evaluation/store.py +258 -0
- langchain_agentx/observability/events/__init__.py +15 -0
- langchain_agentx/observability/events/langchain_agentx_event_adapter.py +832 -0
- langchain_agentx/observability/logging/__init__.py +15 -0
- langchain_agentx/observability/logging/debug_burst.py +95 -0
- langchain_agentx/observability/logging/logging_config.py +178 -0
- langchain_agentx/observability/logging/logging_contract.py +65 -0
- langchain_agentx/observability/replay/__init__.py +35 -0
- langchain_agentx/observability/replay/cli.py +91 -0
- langchain_agentx/observability/replay/service.py +83 -0
- langchain_agentx/observability/replay/store.py +278 -0
- langchain_agentx/observability/replay/ui.py +47 -0
- langchain_agentx/observability/trace/__init__.py +25 -0
- langchain_agentx/observability/trace/collector.py +560 -0
- langchain_agentx/observability/trace/event_emitter.py +183 -0
- langchain_agentx/observability/trace/hook_event_emitter.py +49 -0
- langchain_agentx/observability/trace/models.py +144 -0
- langchain_agentx/observability/trace/sqlite_store.py +873 -0
- langchain_agentx/observability/trace/trace_callback.py +295 -0
- langchain_agentx/observability/trace/trace_lifecycle_collector.py +114 -0
- langchain_agentx/plugin/__init__.py +26 -0
- langchain_agentx/plugin/builtin.py +53 -0
- langchain_agentx/plugin/config.py +113 -0
- langchain_agentx/plugin/loader.py +386 -0
- langchain_agentx/plugin/manifest.py +154 -0
- langchain_agentx/plugin/registries.py +211 -0
- langchain_agentx/plugin/types.py +142 -0
- langchain_agentx/provider/__init__.py +27 -0
- langchain_agentx/provider/anthropic.py +121 -0
- langchain_agentx/provider/compatible_chat_openai.py +86 -0
- langchain_agentx/provider/env.py +45 -0
- langchain_agentx/provider/model_profile.py +156 -0
- langchain_agentx/provider/openai.py +89 -0
- langchain_agentx/session/__init__.py +17 -0
- langchain_agentx/session/agent_session.py +320 -0
- langchain_agentx/session/conversation_factory.py +87 -0
- langchain_agentx/session/conversation_recovery.py +156 -0
- langchain_agentx/session/conversation_session.py +198 -0
- langchain_agentx/session/factory.py +143 -0
- langchain_agentx/session/protocol.py +25 -0
- langchain_agentx/task_runtime/__init__.py +113 -0
- langchain_agentx/task_runtime/core/__init__.py +51 -0
- langchain_agentx/task_runtime/core/ids.py +33 -0
- langchain_agentx/task_runtime/core/interfaces.py +115 -0
- langchain_agentx/task_runtime/core/notification_priority.py +19 -0
- langchain_agentx/task_runtime/core/types.py +136 -0
- langchain_agentx/task_runtime/integrations/__init__.py +33 -0
- langchain_agentx/task_runtime/integrations/loop_adapter.py +91 -0
- langchain_agentx/task_runtime/integrations/loop_integration.py +61 -0
- langchain_agentx/task_runtime/integrations/prefetch_providers.py +108 -0
- langchain_agentx/task_runtime/integrations/provider_factory.py +103 -0
- langchain_agentx/task_runtime/integrations/queued_command_provider.py +184 -0
- langchain_agentx/task_runtime/integrations/sqlite_queued_command_provider.py +338 -0
- langchain_agentx/task_runtime/integrations/tool_use_summary_provider.py +254 -0
- langchain_agentx/task_runtime/orchestrator/__init__.py +5 -0
- langchain_agentx/task_runtime/orchestrator/runtime.py +386 -0
- langchain_agentx/task_runtime/output/__init__.py +5 -0
- langchain_agentx/task_runtime/output/sink.py +64 -0
- langchain_agentx/task_runtime/policy/__init__.py +11 -0
- langchain_agentx/task_runtime/policy/withhold_visibility.py +32 -0
- langchain_agentx/task_runtime/queue/__init__.py +5 -0
- langchain_agentx/task_runtime/queue/in_memory.py +55 -0
- langchain_agentx/task_runtime/skill_prefetch/__init__.py +4 -0
- langchain_agentx/task_runtime/skill_prefetch/attachments.py +46 -0
- langchain_agentx/task_runtime/skill_prefetch/models.py +37 -0
- langchain_agentx/task_runtime/skill_prefetch/provider.py +344 -0
- langchain_agentx/task_runtime/store/__init__.py +6 -0
- langchain_agentx/task_runtime/store/in_memory.py +81 -0
- langchain_agentx/task_runtime/store/sqlite_store.py +281 -0
- langchain_agentx/task_runtime/tasks/__init__.py +76 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/__init__.py +15 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/base.py +41 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/evaluation.py +67 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/registry.py +36 -0
- langchain_agentx/task_runtime/tasks/ai_analysis/scheduler.py +70 -0
- langchain_agentx/task_runtime/tasks/base/__init__.py +6 -0
- langchain_agentx/task_runtime/tasks/base/contracts.py +24 -0
- langchain_agentx/task_runtime/tasks/custom/__init__.py +7 -0
- langchain_agentx/task_runtime/tasks/custom/executor.py +60 -0
- langchain_agentx/task_runtime/tasks/custom/notification.py +7 -0
- langchain_agentx/task_runtime/tasks/custom/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/custom/spec.py +33 -0
- langchain_agentx/task_runtime/tasks/dream_task/__init__.py +15 -0
- langchain_agentx/task_runtime/tasks/dream_task/executor.py +61 -0
- langchain_agentx/task_runtime/tasks/dream_task/notification.py +19 -0
- langchain_agentx/task_runtime/tasks/dream_task/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/dream_task/spec.py +35 -0
- langchain_agentx/task_runtime/tasks/dream_task/state.py +17 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/__init__.py +12 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/executor.py +36 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/notification.py +25 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/in_process_teammate/spec.py +63 -0
- langchain_agentx/task_runtime/tasks/local_agent/__init__.py +14 -0
- langchain_agentx/task_runtime/tasks/local_agent/executor.py +33 -0
- langchain_agentx/task_runtime/tasks/local_agent/notification.py +21 -0
- langchain_agentx/task_runtime/tasks/local_agent/runner.py +43 -0
- langchain_agentx/task_runtime/tasks/local_agent/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/local_agent/spec.py +31 -0
- langchain_agentx/task_runtime/tasks/local_bash/__init__.py +13 -0
- langchain_agentx/task_runtime/tasks/local_bash/executor.py +95 -0
- langchain_agentx/task_runtime/tasks/local_bash/notification.py +22 -0
- langchain_agentx/task_runtime/tasks/local_bash/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/local_bash/spec.py +55 -0
- langchain_agentx/task_runtime/tasks/remote_agent/__init__.py +19 -0
- langchain_agentx/task_runtime/tasks/remote_agent/backend.py +76 -0
- langchain_agentx/task_runtime/tasks/remote_agent/executor.py +37 -0
- langchain_agentx/task_runtime/tasks/remote_agent/notification.py +22 -0
- langchain_agentx/task_runtime/tasks/remote_agent/semantics.py +13 -0
- langchain_agentx/task_runtime/tasks/remote_agent/spec.py +34 -0
- langchain_agentx/task_runtime/tasks/trace_cleanup/__init__.py +19 -0
- langchain_agentx/task_runtime/tasks/trace_cleanup/bootstrap.py +95 -0
- langchain_agentx/task_runtime/tasks/trace_cleanup/executor.py +66 -0
- langchain_agentx/task_runtime/tasks/trace_cleanup/scheduler.py +169 -0
- langchain_agentx/tool_runtime/__init__.py +90 -0
- langchain_agentx/tool_runtime/adapter.py +365 -0
- langchain_agentx/tool_runtime/base.py +319 -0
- langchain_agentx/tool_runtime/errors.py +190 -0
- langchain_agentx/tool_runtime/identical_call_cache.py +110 -0
- langchain_agentx/tool_runtime/loader.py +195 -0
- langchain_agentx/tool_runtime/models.py +260 -0
- langchain_agentx/tool_runtime/permission_context.py +78 -0
- langchain_agentx/tool_runtime/pipeline.py +621 -0
- langchain_agentx/tool_runtime/policy.py +447 -0
- langchain_agentx/tool_runtime/registry.py +81 -0
- langchain_agentx/tool_runtime/resolvers/__init__.py +27 -0
- langchain_agentx/tool_runtime/resolvers/agent_session.py +125 -0
- langchain_agentx/tool_runtime/resolvers/background.py +32 -0
- langchain_agentx/tool_runtime/resolvers/base.py +20 -0
- langchain_agentx/tool_runtime/resolvers/conversation.py +22 -0
- langchain_agentx/tool_runtime/resolvers/workflow.py +73 -0
- langchain_agentx/tool_runtime/session_store.py +132 -0
- langchain_agentx/tool_runtime/smoke_test_runtime.py +294 -0
- langchain_agentx/tool_runtime/state_bridge.py +164 -0
- langchain_agentx/tools/__init__.py +26 -0
- langchain_agentx/tools/agent/__init__.py +9 -0
- langchain_agentx/tools/agent/backend.py +53 -0
- langchain_agentx/tools/agent/built_in/__init__.py +19 -0
- langchain_agentx/tools/agent/built_in/agentx_guide.py +65 -0
- langchain_agentx/tools/agent/built_in/explore.py +80 -0
- langchain_agentx/tools/agent/built_in/general.py +57 -0
- langchain_agentx/tools/agent/built_in/plan.py +89 -0
- langchain_agentx/tools/agent/built_in/statusline_setup.py +64 -0
- langchain_agentx/tools/agent/built_in/verification.py +120 -0
- langchain_agentx/tools/agent/builtin_subagent_loader.py +89 -0
- langchain_agentx/tools/agent/cwd_resolution.py +119 -0
- langchain_agentx/tools/agent/limits.py +26 -0
- langchain_agentx/tools/agent/loader.py +270 -0
- langchain_agentx/tools/agent/models.py +85 -0
- langchain_agentx/tools/agent/prompt.py +120 -0
- langchain_agentx/tools/agent/registry/__init__.py +18 -0
- langchain_agentx/tools/agent/registry/config.py +29 -0
- langchain_agentx/tools/agent/registry/registry.py +47 -0
- langchain_agentx/tools/agent/scope.py +137 -0
- langchain_agentx/tools/agent/tool.py +256 -0
- langchain_agentx/tools/bash/__init__.py +9 -0
- langchain_agentx/tools/bash/ast_security.py +571 -0
- langchain_agentx/tools/bash/backend.py +1447 -0
- langchain_agentx/tools/bash/bash_hardening.py +734 -0
- langchain_agentx/tools/bash/bash_runtime_contract.py +41 -0
- langchain_agentx/tools/bash/cwd_reporter.py +95 -0
- langchain_agentx/tools/bash/limits.py +71 -0
- langchain_agentx/tools/bash/mode_validation.py +282 -0
- langchain_agentx/tools/bash/models.py +131 -0
- langchain_agentx/tools/bash/observability.py +148 -0
- langchain_agentx/tools/bash/output_utils.py +200 -0
- langchain_agentx/tools/bash/path_security.py +2429 -0
- langchain_agentx/tools/bash/prompt.py +68 -0
- langchain_agentx/tools/bash/read_only_validation.py +589 -0
- langchain_agentx/tools/bash/result_presenter.py +324 -0
- langchain_agentx/tools/bash/sandbox_decision.py +133 -0
- langchain_agentx/tools/bash/security.py +311 -0
- langchain_agentx/tools/bash/sed_edit_parser.py +243 -0
- langchain_agentx/tools/bash/sed_validation.py +163 -0
- langchain_agentx/tools/bash/semantics.py +111 -0
- langchain_agentx/tools/bash/session_manager.py +205 -0
- langchain_agentx/tools/bash/session_runtime.py +290 -0
- langchain_agentx/tools/bash/shell_locator.py +191 -0
- langchain_agentx/tools/bash/task_runtime.py +91 -0
- langchain_agentx/tools/bash/tool.py +939 -0
- langchain_agentx/tools/bash/windows_shell_quoting.py +45 -0
- langchain_agentx/tools/glob/__init__.py +9 -0
- langchain_agentx/tools/glob/models.py +57 -0
- langchain_agentx/tools/glob/pagination.py +30 -0
- langchain_agentx/tools/glob/prompt.py +24 -0
- langchain_agentx/tools/glob/rg_list_backend.py +139 -0
- langchain_agentx/tools/glob/rg_pattern.py +44 -0
- langchain_agentx/tools/glob/tool.py +327 -0
- langchain_agentx/tools/grep/__init__.py +7 -0
- langchain_agentx/tools/grep/backend.py +375 -0
- langchain_agentx/tools/grep/models.py +127 -0
- langchain_agentx/tools/grep/prompt.py +30 -0
- langchain_agentx/tools/grep/rg_subprocess_controller.py +114 -0
- langchain_agentx/tools/grep/tool.py +475 -0
- langchain_agentx/tools/read/__init__.py +9 -0
- langchain_agentx/tools/read/backend.py +415 -0
- langchain_agentx/tools/read/limits.py +67 -0
- langchain_agentx/tools/read/models.py +156 -0
- langchain_agentx/tools/read/prompt.py +73 -0
- langchain_agentx/tools/read/tool.py +494 -0
- langchain_agentx/tools/ripgrep_plugin_exclusions.py +137 -0
- langchain_agentx/tools/skill/__init__.py +4 -0
- langchain_agentx/tools/skill/argument_substitution.py +80 -0
- langchain_agentx/tools/skill/loader.py +196 -0
- langchain_agentx/tools/skill/models.py +88 -0
- langchain_agentx/tools/skill/policy.py +80 -0
- langchain_agentx/tools/skill/prompt.py +35 -0
- langchain_agentx/tools/skill/tool.py +222 -0
- langchain_agentx/utils/__init__.py +0 -0
- langchain_agentx/utils/cwd.py +124 -0
- langchain_agentx/utils/host_platform.py +112 -0
- langchain_agentx/utils/path_hierarchy.py +48 -0
- langchain_agentx/utils/path_user_input.py +66 -0
- langchain_agentx/utils/rg_executable.py +18 -0
- langchain_agentx/utils/subprocess_text.py +101 -0
- langchain_agentx/utils/temp_paths.py +77 -0
- langchain_agentx/utils/unc_path.py +25 -0
- langchain_agentx/utils/win_reserved_paths.py +51 -0
- langchain_agentx/workflow/__init__.py +7 -0
- langchain_agentx/workflow/base.py +97 -0
- langchain_agentx/workflow/batch.py +55 -0
- langchain_agentx/workflow/dag.py +54 -0
- langchain_agentx/workspace/__init__.py +13 -0
- langchain_agentx/workspace/config.py +140 -0
- langchain_agentx/workspace/path_key_normalizer.py +30 -0
- langchain_agentx/workspace/resolver.py +74 -0
- langchain_agentx/workspace/validators.py +41 -0
- langchain_agentx_python-0.1.dist-info/LICENSE +201 -0
- langchain_agentx_python-0.1.dist-info/METADATA +513 -0
- langchain_agentx_python-0.1.dist-info/RECORD +354 -0
- langchain_agentx_python-0.1.dist-info/WHEEL +5 -0
- langchain_agentx_python-0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
memory/memdir/loader.py — Layer 2 prompt 加载编排。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
负责 MEMORY.md 入口读取、截断保护与 auto_memory section 文本组装。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
Loop 启动时通过 section("auto_memory") 调用 load_memory_prompt() 注入 system prompt。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
Phase 2 仅实现全量注入(行为说明 + MEMORY.md 正文),不含相关性召回。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from langchain_agentx.workspace import AgentWorkspaceConfig
|
|
20
|
+
|
|
21
|
+
from .paths import is_memory_enabled
|
|
22
|
+
from .types import (
|
|
23
|
+
DIR_EXISTS_GUIDANCE,
|
|
24
|
+
HOW_TO_SAVE_SECTION,
|
|
25
|
+
MEMORY_AND_PERSISTENCE_SECTION,
|
|
26
|
+
TRUSTING_RECALL_SECTION,
|
|
27
|
+
TYPES_SECTION_INDIVIDUAL,
|
|
28
|
+
WHAT_NOT_TO_SAVE_SECTION,
|
|
29
|
+
WHEN_TO_ACCESS_SECTION,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
MAX_ENTRYPOINT_LINES = 200
|
|
33
|
+
MAX_ENTRYPOINT_BYTES = 25_000
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(frozen=True)
|
|
37
|
+
class EntrypointTruncation:
|
|
38
|
+
content: str
|
|
39
|
+
was_line_truncated: bool
|
|
40
|
+
was_byte_truncated: bool
|
|
41
|
+
warning: str | None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class MemoryPromptLoader:
|
|
45
|
+
def __init__(self, workspace_cfg: AgentWorkspaceConfig) -> None:
|
|
46
|
+
self._cfg = workspace_cfg
|
|
47
|
+
|
|
48
|
+
def _ensure_memory_dir(self) -> None:
|
|
49
|
+
self._cfg.memory_dir.mkdir(parents=True, exist_ok=True)
|
|
50
|
+
|
|
51
|
+
def truncate_entrypoint_content(self, raw: str) -> EntrypointTruncation:
|
|
52
|
+
return _truncate_entrypoint_content(raw)
|
|
53
|
+
|
|
54
|
+
def build_memory_lines(self, entrypoint_text: str) -> list[str]:
|
|
55
|
+
return _build_memory_lines(memory_dir=self._cfg.memory_dir, entrypoint_text=entrypoint_text)
|
|
56
|
+
|
|
57
|
+
def load_memory_prompt(self) -> str | None:
|
|
58
|
+
self._ensure_memory_dir()
|
|
59
|
+
if not is_memory_enabled(self._cfg):
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
entrypoint = self._cfg.memory_entrypoint
|
|
63
|
+
if entrypoint.exists():
|
|
64
|
+
raw = entrypoint.read_text(encoding="utf-8")
|
|
65
|
+
else:
|
|
66
|
+
raw = ""
|
|
67
|
+
truncated = self.truncate_entrypoint_content(raw)
|
|
68
|
+
lines = self.build_memory_lines(truncated.content)
|
|
69
|
+
if truncated.warning:
|
|
70
|
+
lines.extend(["", truncated.warning])
|
|
71
|
+
return "\n".join(lines)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _build_warning(
|
|
75
|
+
*,
|
|
76
|
+
line_count: int,
|
|
77
|
+
original_bytes_len: int,
|
|
78
|
+
line_truncated: bool,
|
|
79
|
+
byte_truncated: bool,
|
|
80
|
+
) -> str | None:
|
|
81
|
+
if not line_truncated and not byte_truncated:
|
|
82
|
+
return None
|
|
83
|
+
bytes_text = f"{round(original_bytes_len / 1000)} KB"
|
|
84
|
+
if line_truncated and byte_truncated:
|
|
85
|
+
reason = f"{line_count} lines and {bytes_text}"
|
|
86
|
+
elif line_truncated:
|
|
87
|
+
reason = f"{line_count} lines (limit: {MAX_ENTRYPOINT_LINES})"
|
|
88
|
+
else:
|
|
89
|
+
reason = (
|
|
90
|
+
f"{bytes_text} (limit: {MAX_ENTRYPOINT_BYTES // 1000} KB) "
|
|
91
|
+
"— index entries are too long"
|
|
92
|
+
)
|
|
93
|
+
return (
|
|
94
|
+
f"> WARNING: MEMORY.md is {reason}. Only part of it was loaded.\n"
|
|
95
|
+
"> Keep index entries to one line under ~200 chars; move detail into topic files."
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _truncate_entrypoint_content(raw: str) -> EntrypointTruncation:
|
|
100
|
+
lines = raw.splitlines()
|
|
101
|
+
line_truncated = len(lines) > MAX_ENTRYPOINT_LINES
|
|
102
|
+
if line_truncated:
|
|
103
|
+
truncated_lines = lines[:MAX_ENTRYPOINT_LINES]
|
|
104
|
+
working = "\n".join(truncated_lines)
|
|
105
|
+
else:
|
|
106
|
+
working = raw
|
|
107
|
+
|
|
108
|
+
original_bytes_len = len(raw.encode("utf-8"))
|
|
109
|
+
working_bytes = working.encode("utf-8")
|
|
110
|
+
byte_truncated = original_bytes_len > MAX_ENTRYPOINT_BYTES
|
|
111
|
+
if byte_truncated:
|
|
112
|
+
working = working_bytes[:MAX_ENTRYPOINT_BYTES].decode("utf-8", errors="ignore")
|
|
113
|
+
|
|
114
|
+
warning = _build_warning(
|
|
115
|
+
line_count=len(lines),
|
|
116
|
+
original_bytes_len=original_bytes_len,
|
|
117
|
+
line_truncated=line_truncated,
|
|
118
|
+
byte_truncated=byte_truncated,
|
|
119
|
+
)
|
|
120
|
+
return EntrypointTruncation(
|
|
121
|
+
content=working.strip(),
|
|
122
|
+
was_line_truncated=line_truncated,
|
|
123
|
+
was_byte_truncated=byte_truncated,
|
|
124
|
+
warning=warning,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _build_memory_lines(*, memory_dir: Path, entrypoint_text: str) -> list[str]:
|
|
129
|
+
header = [
|
|
130
|
+
"# auto memory",
|
|
131
|
+
"",
|
|
132
|
+
f"You have a persistent, file-based memory system at `{memory_dir}`.",
|
|
133
|
+
DIR_EXISTS_GUIDANCE,
|
|
134
|
+
"",
|
|
135
|
+
"You should build up this memory system over time so that future conversations",
|
|
136
|
+
"can have a complete picture of who the user is, how they'd like to collaborate",
|
|
137
|
+
"with you, what behaviors to avoid or repeat, and the context behind the work",
|
|
138
|
+
"the user gives you.",
|
|
139
|
+
"",
|
|
140
|
+
"If the user explicitly asks you to remember something, save it immediately as",
|
|
141
|
+
"whichever type fits best. If they ask you to forget something, find and remove",
|
|
142
|
+
"the relevant entry.",
|
|
143
|
+
"",
|
|
144
|
+
TYPES_SECTION_INDIVIDUAL,
|
|
145
|
+
"",
|
|
146
|
+
WHAT_NOT_TO_SAVE_SECTION,
|
|
147
|
+
"",
|
|
148
|
+
HOW_TO_SAVE_SECTION,
|
|
149
|
+
"",
|
|
150
|
+
WHEN_TO_ACCESS_SECTION,
|
|
151
|
+
"",
|
|
152
|
+
TRUSTING_RECALL_SECTION,
|
|
153
|
+
"",
|
|
154
|
+
MEMORY_AND_PERSISTENCE_SECTION,
|
|
155
|
+
"",
|
|
156
|
+
"## MEMORY.md",
|
|
157
|
+
"",
|
|
158
|
+
]
|
|
159
|
+
body = (
|
|
160
|
+
entrypoint_text.strip()
|
|
161
|
+
if entrypoint_text.strip()
|
|
162
|
+
else "Your MEMORY.md is currently empty. When you save new memories, they will appear here."
|
|
163
|
+
)
|
|
164
|
+
return [*header, body]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def truncate_entrypoint_content(raw: str) -> EntrypointTruncation:
|
|
168
|
+
return _truncate_entrypoint_content(raw)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def build_memory_lines(*, entrypoint_text: str, workspace_cfg: AgentWorkspaceConfig) -> list[str]:
|
|
172
|
+
return MemoryPromptLoader(workspace_cfg).build_memory_lines(entrypoint_text)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def load_memory_prompt(workspace_cfg: AgentWorkspaceConfig) -> str | None:
|
|
176
|
+
return MemoryPromptLoader(workspace_cfg).load_memory_prompt()
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
__all__ = [
|
|
180
|
+
"EntrypointTruncation",
|
|
181
|
+
"MAX_ENTRYPOINT_BYTES",
|
|
182
|
+
"MAX_ENTRYPOINT_LINES",
|
|
183
|
+
"MemoryPromptLoader",
|
|
184
|
+
"build_memory_lines",
|
|
185
|
+
"load_memory_prompt",
|
|
186
|
+
"truncate_entrypoint_content",
|
|
187
|
+
]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
memory/memdir/paths.py — Layer 2 路径与启用门禁。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
提供 memdir 启用判断与路径安全校验,作为 Layer 2 的统一入口。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
loader/extractor 调用本模块判断是否启用与路径是否在 memory_dir 内。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
仅覆盖本地路径语义与环境变量门禁,不包含远端 feature flag。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from langchain_agentx.workspace import AgentWorkspaceConfig
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MemoryPathResolver:
|
|
23
|
+
"""Layer 2 路径解析与安全校验协作者。"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, workspace_cfg: AgentWorkspaceConfig) -> None:
|
|
26
|
+
self._cfg = workspace_cfg
|
|
27
|
+
self._memory_dir = self._cfg.memory_dir.resolve()
|
|
28
|
+
|
|
29
|
+
def get_memory_dir(self) -> Path:
|
|
30
|
+
return self._memory_dir
|
|
31
|
+
|
|
32
|
+
def is_memory_path(self, candidate: str | Path) -> bool:
|
|
33
|
+
try:
|
|
34
|
+
resolved = Path(candidate).resolve()
|
|
35
|
+
except (TypeError, OSError, RuntimeError):
|
|
36
|
+
return False
|
|
37
|
+
try:
|
|
38
|
+
resolved.relative_to(self._memory_dir)
|
|
39
|
+
return True
|
|
40
|
+
except ValueError:
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def is_memory_enabled(workspace_cfg: AgentWorkspaceConfig) -> bool:
|
|
45
|
+
"""Layer 2 是否启用:环境变量优先,默认启用。"""
|
|
46
|
+
del workspace_cfg
|
|
47
|
+
return os.environ.get("LANGCHAIN_AGENTX_DISABLE_MEMORY") != "1"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_memory_dir(workspace_cfg: AgentWorkspaceConfig) -> Path:
|
|
51
|
+
return MemoryPathResolver(workspace_cfg).get_memory_dir()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def is_memory_path(candidate: str | Path, workspace_cfg: AgentWorkspaceConfig) -> bool:
|
|
55
|
+
return MemoryPathResolver(workspace_cfg).is_memory_path(candidate)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
__all__ = [
|
|
59
|
+
"MemoryPathResolver",
|
|
60
|
+
"get_memory_dir",
|
|
61
|
+
"is_memory_enabled",
|
|
62
|
+
"is_memory_path",
|
|
63
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
memory/memdir/recall.py — Layer 2 相关性召回接口空桩。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
提供 Phase 5 的稳定异步接口签名,供后续 side-query 召回实现复用。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
query 前召回路径将调用本模块(Phase 5 先空桩,不接入主链)。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
仅返回空结果,确保默认配置下行为不变。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def find_relevant_memories(
|
|
21
|
+
*,
|
|
22
|
+
query: str,
|
|
23
|
+
memory_dir: Path,
|
|
24
|
+
limit: int = 5,
|
|
25
|
+
max_scan: int = 200,
|
|
26
|
+
recent_tools: list[str] | None = None,
|
|
27
|
+
) -> list[dict[str, Any]]:
|
|
28
|
+
del query, memory_dir, limit, max_scan, recent_tools
|
|
29
|
+
return []
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async def select_relevant_memories(
|
|
33
|
+
*,
|
|
34
|
+
query: str,
|
|
35
|
+
manifest_text: str,
|
|
36
|
+
limit: int = 5,
|
|
37
|
+
) -> list[str]:
|
|
38
|
+
del query, manifest_text, limit
|
|
39
|
+
return []
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"find_relevant_memories",
|
|
44
|
+
"select_relevant_memories",
|
|
45
|
+
]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
memory/memdir/runtime.py — Layer 2 在 loop 侧的注入协作者。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
将 MemoryPromptLoader 适配为 `section("auto_memory")`,统一供 loop 工厂接线。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
LoopGraphBuilder._prepare_compile_context() -> MemoryPromptBootstrap.build_sections()。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
仅提供 Phase 2 的 prompt 注入,不包含 extractor/recall 链路。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import TYPE_CHECKING
|
|
18
|
+
|
|
19
|
+
from langchain_agentx.workspace import resolve_agent_workspace_config
|
|
20
|
+
|
|
21
|
+
from .loader import MemoryPromptLoader
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from langchain_agentx.loop.prompt.sections import SystemPromptSection
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MemoryPromptBootstrap:
|
|
28
|
+
def __init__(self, *, workspace_root: str | Path, agent_home: str) -> None:
|
|
29
|
+
self._workspace_root = workspace_root
|
|
30
|
+
self._agent_home = agent_home
|
|
31
|
+
|
|
32
|
+
def build_sections(self) -> list["SystemPromptSection"]:
|
|
33
|
+
from langchain_agentx.loop.prompt.sections import section
|
|
34
|
+
|
|
35
|
+
workspace_cfg = resolve_agent_workspace_config(
|
|
36
|
+
workspace_root=self._workspace_root,
|
|
37
|
+
agent_home=self._agent_home,
|
|
38
|
+
)
|
|
39
|
+
loader = MemoryPromptLoader(workspace_cfg)
|
|
40
|
+
return [section("auto_memory", loader.load_memory_prompt)]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
__all__ = ["MemoryPromptBootstrap"]
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
memory/memdir/scan.py — Layer 2 memory 文件扫描器。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
扫描 memory 目录下的 markdown 文件,解析 frontmatter 的 type 字段,输出可组装清单。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
memdir runtime 读取 MEMORY.md 或 fallback 扫描时使用。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
Phase 1 仅实现基础扫描与轻量 frontmatter 解析,不做异步缓存。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
import logging
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
from .age import memory_freshness_text
|
|
21
|
+
from .types import parse_memory_type
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
MAX_SCAN_FILES = 200
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class MemoryFileHeader:
|
|
30
|
+
path: Path
|
|
31
|
+
rel_path: str
|
|
32
|
+
title: str
|
|
33
|
+
memory_type: str | None
|
|
34
|
+
freshness: str
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class FrontmatterParseError(ValueError):
|
|
38
|
+
"""frontmatter 结构损坏。"""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class MemoryScanner:
|
|
42
|
+
def __init__(self, *, memory_dir: Path, max_scan: int = MAX_SCAN_FILES) -> None:
|
|
43
|
+
self._memory_dir = memory_dir
|
|
44
|
+
self._max_scan = max_scan
|
|
45
|
+
|
|
46
|
+
def scan_memory_files(self) -> list[MemoryFileHeader]:
|
|
47
|
+
if not self._memory_dir.exists() or not self._memory_dir.is_dir():
|
|
48
|
+
return []
|
|
49
|
+
|
|
50
|
+
candidates = self._iter_candidates()
|
|
51
|
+
headers: list[MemoryFileHeader] = []
|
|
52
|
+
for path in candidates:
|
|
53
|
+
try:
|
|
54
|
+
content = path.read_text(encoding="utf-8")
|
|
55
|
+
except OSError:
|
|
56
|
+
continue
|
|
57
|
+
try:
|
|
58
|
+
memory_type = self._parse_frontmatter_type(content)
|
|
59
|
+
except FrontmatterParseError as exc:
|
|
60
|
+
logger.warning("skip memory file with malformed frontmatter: %s (%s)", path, exc)
|
|
61
|
+
continue
|
|
62
|
+
headers.append(
|
|
63
|
+
MemoryFileHeader(
|
|
64
|
+
path=path,
|
|
65
|
+
rel_path=path.relative_to(self._memory_dir).as_posix(),
|
|
66
|
+
title=self._first_heading(content, fallback=path.stem),
|
|
67
|
+
memory_type=memory_type,
|
|
68
|
+
freshness=memory_freshness_text(path),
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
return headers
|
|
72
|
+
|
|
73
|
+
def _iter_candidates(self) -> list[Path]:
|
|
74
|
+
all_md = [path for path in self._memory_dir.rglob("*.md") if path.name != "MEMORY.md"]
|
|
75
|
+
all_md.sort(key=lambda p: p.stat().st_mtime, reverse=True)
|
|
76
|
+
return all_md[: self._max_scan]
|
|
77
|
+
|
|
78
|
+
def _parse_frontmatter_type(self, content: str) -> str | None:
|
|
79
|
+
lines = content.splitlines()
|
|
80
|
+
if not lines:
|
|
81
|
+
return None
|
|
82
|
+
if lines[0].strip() != "---":
|
|
83
|
+
return None
|
|
84
|
+
end_index: int | None = None
|
|
85
|
+
for idx in range(1, len(lines)):
|
|
86
|
+
if lines[idx].strip() == "---":
|
|
87
|
+
end_index = idx
|
|
88
|
+
break
|
|
89
|
+
if end_index is None:
|
|
90
|
+
raise FrontmatterParseError("missing closing ---")
|
|
91
|
+
for raw in lines[1:end_index]:
|
|
92
|
+
line = raw.strip()
|
|
93
|
+
if not line:
|
|
94
|
+
continue
|
|
95
|
+
if ":" not in line:
|
|
96
|
+
raise FrontmatterParseError(f"invalid frontmatter line: {line}")
|
|
97
|
+
key, value = line.split(":", 1)
|
|
98
|
+
if key.strip() != "type":
|
|
99
|
+
continue
|
|
100
|
+
normalized = value.strip().strip('"').strip("'")
|
|
101
|
+
parsed = parse_memory_type(normalized)
|
|
102
|
+
return parsed.value if parsed else None
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
@staticmethod
|
|
106
|
+
def _first_heading(content: str, fallback: str) -> str:
|
|
107
|
+
for line in content.splitlines():
|
|
108
|
+
if line.startswith("# "):
|
|
109
|
+
title = line[2:].strip()
|
|
110
|
+
if title:
|
|
111
|
+
return title
|
|
112
|
+
return fallback
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def scan_memory_files(memory_dir: Path) -> list[MemoryFileHeader]:
|
|
116
|
+
return MemoryScanner(memory_dir=memory_dir).scan_memory_files()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def format_memory_manifest(headers: list[MemoryFileHeader]) -> str:
|
|
120
|
+
if not headers:
|
|
121
|
+
return ""
|
|
122
|
+
lines = [
|
|
123
|
+
f"- [{h.rel_path}] type={h.memory_type or 'unknown'} ({h.freshness})"
|
|
124
|
+
for h in headers
|
|
125
|
+
]
|
|
126
|
+
return "\n".join(lines)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
__all__ = [
|
|
130
|
+
"MAX_SCAN_FILES",
|
|
131
|
+
"MemoryScanner",
|
|
132
|
+
"MemoryFileHeader",
|
|
133
|
+
"format_memory_manifest",
|
|
134
|
+
"scan_memory_files",
|
|
135
|
+
]
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
memory/memdir/types.py — Layer 2 类型与提示词常量。
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
定义记忆类型闭集与通用提示词片段,供 loader/extractor 复用。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
build_memory_lines() 与 build_extract_prompt() 从本模块读取同源常量。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
仅定义静态契约,不包含 IO 或业务编排逻辑。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from enum import Enum
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MemoryType(str, Enum):
|
|
20
|
+
USER = "user"
|
|
21
|
+
FEEDBACK = "feedback"
|
|
22
|
+
PROJECT = "project"
|
|
23
|
+
REFERENCE = "reference"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
MEMORY_TYPES: tuple[str, ...] = (
|
|
27
|
+
MemoryType.USER.value,
|
|
28
|
+
MemoryType.FEEDBACK.value,
|
|
29
|
+
MemoryType.PROJECT.value,
|
|
30
|
+
MemoryType.REFERENCE.value,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
TYPES_SECTION_INDIVIDUAL = """
|
|
34
|
+
## Memory types
|
|
35
|
+
|
|
36
|
+
- user: User profile, preferences, and collaboration style.
|
|
37
|
+
- feedback: Corrections and explicit preferences from the user.
|
|
38
|
+
- project: Non-code project context and constraints.
|
|
39
|
+
- reference: Pointers to external systems and resources.
|
|
40
|
+
""".strip()
|
|
41
|
+
|
|
42
|
+
WHAT_NOT_TO_SAVE_SECTION = """
|
|
43
|
+
## What not to save
|
|
44
|
+
|
|
45
|
+
- Anything that can be derived from code or git history.
|
|
46
|
+
- Task-local TODOs that belong to the current run only.
|
|
47
|
+
- Anything already documented in instruction files (e.g. CLAUDE.md / AGENT.md / .cursorrules).
|
|
48
|
+
""".strip()
|
|
49
|
+
|
|
50
|
+
HOW_TO_SAVE_SECTION = """
|
|
51
|
+
## How to save
|
|
52
|
+
|
|
53
|
+
1. Create or update a topic file under memory/.
|
|
54
|
+
2. Keep MEMORY.md as an index line list pointing to topic files.
|
|
55
|
+
""".strip()
|
|
56
|
+
|
|
57
|
+
WHEN_TO_ACCESS_SECTION = """
|
|
58
|
+
## When to access memory
|
|
59
|
+
|
|
60
|
+
- At session start to recover long-term context.
|
|
61
|
+
- Before making personalized recommendations.
|
|
62
|
+
- If the user asks to ignore memory, proceed as if MEMORY.md were empty.
|
|
63
|
+
""".strip()
|
|
64
|
+
|
|
65
|
+
TRUSTING_RECALL_SECTION = """
|
|
66
|
+
## Before recommending from memory
|
|
67
|
+
|
|
68
|
+
A memory is a historical claim, not a guarantee of current truth.
|
|
69
|
+
Verify code/file/function claims against the current workspace before recommending actions.
|
|
70
|
+
""".strip()
|
|
71
|
+
|
|
72
|
+
DIR_EXISTS_GUIDANCE = """
|
|
73
|
+
This directory already exists — write to it directly with the Write tool
|
|
74
|
+
(do not run mkdir or check for its existence).
|
|
75
|
+
""".strip()
|
|
76
|
+
|
|
77
|
+
MEMORY_AND_PERSISTENCE_SECTION = """
|
|
78
|
+
## Memory vs task state
|
|
79
|
+
|
|
80
|
+
Use memory for durable facts that should survive across sessions.
|
|
81
|
+
Use task/session state for temporary execution details.
|
|
82
|
+
""".strip()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def parse_memory_type(raw: str) -> MemoryType | None:
|
|
86
|
+
normalized = str(raw or "").strip().lower()
|
|
87
|
+
for item in MemoryType:
|
|
88
|
+
if item.value == normalized:
|
|
89
|
+
return item
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
__all__ = [
|
|
94
|
+
"DIR_EXISTS_GUIDANCE",
|
|
95
|
+
"HOW_TO_SAVE_SECTION",
|
|
96
|
+
"MEMORY_TYPES",
|
|
97
|
+
"MEMORY_AND_PERSISTENCE_SECTION",
|
|
98
|
+
"MemoryType",
|
|
99
|
+
"TRUSTING_RECALL_SECTION",
|
|
100
|
+
"TYPES_SECTION_INDIVIDUAL",
|
|
101
|
+
"WHAT_NOT_TO_SAVE_SECTION",
|
|
102
|
+
"WHEN_TO_ACCESS_SECTION",
|
|
103
|
+
"parse_memory_type",
|
|
104
|
+
]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
memory/session/__init__.py — Session Memory 包入口
|
|
3
|
+
|
|
4
|
+
职责:
|
|
5
|
+
暴露 Layer 3 Session Memory 的 prompt 构建能力。
|
|
6
|
+
|
|
7
|
+
链路位置:
|
|
8
|
+
被 loop/session memory 实现层导入,用于生成提取提示词与模板内容。
|
|
9
|
+
|
|
10
|
+
当前裁剪范围:
|
|
11
|
+
本阶段仅实现 Phase 1(prompts),不包含提取调度与 compact bridge。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .prompts import (
|
|
15
|
+
DEFAULT_SESSION_MEMORY_TEMPLATE,
|
|
16
|
+
EXTRACT_SESSION_MEMORY_PROMPT,
|
|
17
|
+
MAX_SECTION_LENGTH,
|
|
18
|
+
analyze_section_sizes,
|
|
19
|
+
build_session_memory_update_prompt,
|
|
20
|
+
generate_section_reminders,
|
|
21
|
+
load_session_memory_prompt,
|
|
22
|
+
load_session_memory_template,
|
|
23
|
+
substitute_variables,
|
|
24
|
+
)
|
|
25
|
+
from .session_memory import (
|
|
26
|
+
SESSION_MEMORY_INIT_TOKEN_THRESHOLD,
|
|
27
|
+
SESSION_MEMORY_TOOL_CALL_THRESHOLD,
|
|
28
|
+
SESSION_MEMORY_UPDATE_TOKEN_THRESHOLD,
|
|
29
|
+
SessionMemoryExtractionState,
|
|
30
|
+
SessionMemoryManager,
|
|
31
|
+
create_memory_file_can_use_tool,
|
|
32
|
+
make_session_memory_section,
|
|
33
|
+
should_extract_session_memory,
|
|
34
|
+
)
|
|
35
|
+
from .compact_bridge import (
|
|
36
|
+
EXTRACTION_STALE_THRESHOLD_SECONDS,
|
|
37
|
+
EXTRACTION_WAIT_TIMEOUT_SECONDS,
|
|
38
|
+
MAX_SECTION_CHARS,
|
|
39
|
+
TRUNCATION_MARKER,
|
|
40
|
+
SessionMemoryCompactBridge,
|
|
41
|
+
adjust_index_to_preserve_api_invariants,
|
|
42
|
+
is_session_memory_empty,
|
|
43
|
+
truncate_session_memory_for_compact,
|
|
44
|
+
try_session_memory_compaction,
|
|
45
|
+
wait_for_session_memory_extraction,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"MAX_SECTION_LENGTH",
|
|
50
|
+
"DEFAULT_SESSION_MEMORY_TEMPLATE",
|
|
51
|
+
"EXTRACT_SESSION_MEMORY_PROMPT",
|
|
52
|
+
"substitute_variables",
|
|
53
|
+
"analyze_section_sizes",
|
|
54
|
+
"generate_section_reminders",
|
|
55
|
+
"build_session_memory_update_prompt",
|
|
56
|
+
"load_session_memory_template",
|
|
57
|
+
"load_session_memory_prompt",
|
|
58
|
+
"SESSION_MEMORY_INIT_TOKEN_THRESHOLD",
|
|
59
|
+
"SESSION_MEMORY_UPDATE_TOKEN_THRESHOLD",
|
|
60
|
+
"SESSION_MEMORY_TOOL_CALL_THRESHOLD",
|
|
61
|
+
"SessionMemoryExtractionState",
|
|
62
|
+
"SessionMemoryManager",
|
|
63
|
+
"should_extract_session_memory",
|
|
64
|
+
"create_memory_file_can_use_tool",
|
|
65
|
+
"make_session_memory_section",
|
|
66
|
+
"EXTRACTION_WAIT_TIMEOUT_SECONDS",
|
|
67
|
+
"EXTRACTION_STALE_THRESHOLD_SECONDS",
|
|
68
|
+
"MAX_SECTION_CHARS",
|
|
69
|
+
"TRUNCATION_MARKER",
|
|
70
|
+
"wait_for_session_memory_extraction",
|
|
71
|
+
"is_session_memory_empty",
|
|
72
|
+
"truncate_session_memory_for_compact",
|
|
73
|
+
"adjust_index_to_preserve_api_invariants",
|
|
74
|
+
"try_session_memory_compaction",
|
|
75
|
+
"SessionMemoryCompactBridge",
|
|
76
|
+
]
|