feat(memory): agent-scope two-phase trajectory/experience memory pipeline#1880
Merged
chenjw merged 19 commits intovolcengine:mainfrom May 8, 2026
Merged
feat(memory): agent-scope two-phase trajectory/experience memory pipeline#1880chenjw merged 19 commits intovolcengine:mainfrom
chenjw merged 19 commits intovolcengine:mainfrom
Conversation
Add a two-phase agent memory pipeline with schema-driven trajectory and experience extraction, plus system-managed source trajectory tracking. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enable the agent memory pipeline behind config and invoke trajectory/experience extraction during session memory processing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ce merge, concurrent extraction - Trajectory filenames now include a timestamp suffix (via _stamp_trajectory_names in compressor_v2 before apply_operations), so trajectory_name in both the filename and MEMORY_FIELDS carries the full timestamped name - Experience extraction: add merge operation (write generalized + delete_uris), fix delete lock conflict (pass lock_handle to viking_fs.rm), and inherit source_trajectories from deleted experiences before merge - Near-duplicate trajectory dedup removed from memory_updater; delete moved before write to avoid AGFS sibling lock contention - session.py: restore user memory extraction and run user + agent memory concurrently via asyncio.gather (agent memory gated by agent_memory_enabled) - directories.py: trajectories and experiences directories added to agent memory preset with abstract/overview; cases and patterns removed - Simplify trajectory/experience YAML descriptions and instructions - extract_loop: skip refetch for add_only schemas; add logging for URI resolution and operation dispatch to aid diagnosis of duplicate experience writes - demo_agent_memory.py: replace three-round demo with two same-domain rounds to specifically test the experience edit path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ing trajectory/experience - Add `agent_only: true` to trajectory.yaml and experience.yaml schemas - Add `agent_only` field to `MemoryTypeSchema` dataclass - Parse `agent_only` from YAML in `MemoryTypeRegistry._parse_memory_type` - Filter out agent_only schemas in both `prefetch` and `get_memory_schemas` in `SessionExtractContextProvider`, so trajectory/experience are only processed by the agent memory extraction pipeline Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eline - test_trajectory_and_experience_extraction: runs two same-domain sessions, asserts Round 1 creates the experience and Round 2 edits it (no duplicate), and verifies all trajectory filenames carry a timestamp suffix - test_no_agent_only_schemas_in_user_memory: unit-level check that trajectory/experience schemas are filtered out of SessionExtractContextProvider Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ce extraction Phase 1 (trajectory): extract execution summaries from conversation, one per business domain. Phase 2 (experience): prefetch top-5 candidate experiences + source trajectories, single no-tool LLM call to Update/Replace/Create/Skip. Key changes: - AgentExperienceContextProvider: rewrite as prefetch-all + single no-tool call; top-3 candidates include source_trajectories for grounding; prefetched_uris tracked to skip refetch check - AgentTrajectoryContextProvider: remove read tool (was causing hallucination); tighten instruction - ExtractLoop: fix prefetch URI tracking (old format was broken); guard tool_choice on empty tools - compressor_v2: deserialize trajectory content before passing to experience phase; restore user/agent memory concurrent execution in session.py - memory_updater: downgrade diff_match_patch ImportError from tracer.error to tracer.info - volcengine_vlm: trace tool calls and response content separately - experience/trajectory yaml: refine field descriptions and Reflect section wording - e2e test: add skipif guard, tracer init, two-iteration loop, persistent demo dir Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolve extract_loop prefetch tracking conflict by keeping both provider-declared prefetched_uris support and upstream's legacy tool_call_name JSON compatibility. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop the unused get_source_trajectories memory tool after phase-2 moved to prefetch-only context, and replace source_trajectory debug prints with tracer logs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allow LocalClient to accept an explicit UserIdentifier and add an integration test covering user+agent agent-memory isolation in embedded mode. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolved conflicts in 8 files, preserving agent-memory features (extract_agent_memories, two-phase pipeline, agent_memory_enabled config) while integrating upstream changes (overview_template, extraction_enabled, eager_prefetch, isolation_handler refactor, _build_memory_diff, bind_telemetry_stage, get_event_content). Key merge decisions: - dataclass.py: kept both agent_only and overview_template fields - memory_config.py: kept all fields from both branches - extract_loop.py: kept prefetch URI tracking; adopted upstream bind_telemetry_stage - memory_updater.py: adopted upstream apply_operations/apply_upsert refactor; kept get_timestamp_from_ranges alongside upstream get_event_content - uri.py: adopted upstream supplement_operation_uris with isolation_handler - session.py: merged concurrent user+agent extraction into upstream structure with extraction_enabled check and archive_uri param - compressor_v2.py: kept extract_agent_memories + helpers; added _build_memory_diff; updated _run_extract_phase to use new data model and isolation_handler Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… + cap source_trajectories - AgentExperienceContextProvider.prefetch now populates _read_file_contents for each candidate experience, fixing two issues on the Replace path: 1. resolve_operations could never find delete_file_contents → old file was never deleted 2. inherited_traj_uris was always empty → source_trajectories not inherited On the Update path this also eliminates the extra _check_unread_existing_files LLM round-trip that was previously triggered for every edit. - Move deserialize_content/deserialize_metadata imports from inline to module top. - AgentTrajectoryContextProvider.prefetch signature simplified (no unused args). - _append_trajectories_to_experiences: cap source_trajectories at 5 most recent URIs to prevent unbounded growth over many sessions (MAX_SOURCE_TRAJECTORIES = 5). - e2e test cleaned up: single focused test, remove redundant Replace-path tests, filter .abstract.md in _list_non_overview_entries. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ompts - experience.yaml: restructure content format from 4-section to 3-section (Situation / Approach / Reflect), rewrite rules to emphasize machine readability, mutual exclusivity between Approach and Reflect, and abstraction mandate for generalization. - trajectory.yaml: extend content format with explicit Trajectory steps (intent + actions + progress) and Fail reason field; add exhaustive tracking and tool-call formatting rules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- session.py: use gather(return_exceptions=True) so user and agent memory tasks fail independently; each side logs its own error and falls back to [] instead of losing the other side's results - compressor_v2: remove redundant rm before write_file in _append_trajectories_to_experiences — agfs PUT is atomic overwrite, so the prior delete only added a data-loss window; also drop the duplicate ExtractContext/MemoryIsolationHandler construction in _run_extract_phase and fix its outdated docstring - extract_loop: remove stray blank line after prefetch tracking block - memory_updater: remove extra blank line inside class body - experience.yaml / trajectory.yaml: add missing trailing newlines Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨No code suggestions found for the PR. |
chenjw
approved these changes
May 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Introduces an agent-scope memory pipeline that runs alongside the existing user memory extraction. After each session is committed, two sequential phases extract and consolidate execution knowledge specific to the agent identity.
Architecture
Two-phase pipeline
Phase 1 — Trajectory extraction
Reads the full conversation and writes one (or rarely more)
trajectorymemory per business domain. Each trajectory is an immutable execution trace: goal, step-by-step actions with tool calls, result, and failure analysis. Filenames are timestamped to guarantee uniqueness (<name>_YYYYMMDDHHMMSS.md).Phase 2 — Experience consolidation
For each newly written trajectory, retrieves the top-K most relevant existing
experiencememories (via vector search with directory-listing fallback), then lets the LLM choose one of four strategies:Each experience file stores a
source_trajectoriesmetadata list (capped at 5 entries) so Phase 2 can ground its decision in concrete past executions.Isolation from user memory
New
agent_only: trueflag onMemoryTypeSchema. Schemas markedagent_only(trajectory,experience) are filtered out ofSessionExtractContextProviderso they never appear in user-scope extraction. User memory and agent memory run concurrently viaasyncio.gather.Changes
memory/experience.yamlcases.yamlmemory/trajectory.yamlpatterns.yamlcore/directories.pycases→trajectories,patterns→experiencescompressor_v2.pyextract_agent_memories(),_run_extract_phase(),_append_trajectories_to_experiences()agent_trajectory_context_provider.pyagent_experience_context_provider.pysession.pymemory_config.pyagent_memory_enabledflag (defaultfalse)client/local.pyUserIdentifierfor embedded/test useextract_loop.py_read_files; guard empty tool schemaConfiguration
Enable via
~/.openviking/ov.conf:{ "memory": { "version": "v2", "agent_memory_enabled": true } }Testing
End-to-end integration test in
tests/integration/test_agent_memory_e2e.py:source_trajectoriesmetadata links back to extracted trajectoriesRun: