Skip to content

fix: stop pointing the agent at an empty episodic log under a memory backend#216

Open
AmirF194 wants to merge 1 commit into
EverMind-AI:mainfrom
AmirF194:fix/122-episodic-memory-backend-blind
Open

fix: stop pointing the agent at an empty episodic log under a memory backend#216
AmirF194 wants to merge 1 commit into
EverMind-AI:mainfrom
AmirF194:fix/122-episodic-memory-backend-blind

Conversation

@AmirF194

Copy link
Copy Markdown

Summary

The Workspace section of the system prompt always advertises {workspace}/user_memory/episodic/episodes.md as the episodic log to grep, in both render.py's identity_text (the live per-turn prompt) and builder.py's hand-duplicated copy (token-size estimation only). That file is written only by the host's legacy MemoryConsolidator. When a MemoryBackend plugin is wired (e.g. EverOS), episodes live in the plugin's own store instead and are surfaced through per-turn recall into the # Memory section (MemorySegmentBuilder), so the workspace file stays empty and the guidance sends the agent to grep nothing, exactly as the issue's own evidence shows (0-byte episodes.md next to 8 populated EverOS episode files).

identity_text now takes a has_memory_backend flag. IdentitySegmentBuilder and build_context_engine already receive backend, so wiring it through is one added parameter on each. With a backend, the Episodic log line is replaced with guidance pointing at the automatic # Memory recall instead of a file path that stays empty; without one (the default), the rendered text is unchanged. ContextBuilder._get_identity now delegates to the shared render.identity_text instead of keeping its own copy of the same text, which is the "unify" half of the issue: the two had already drifted once (builder.py was missing the language directive render.py has).

Type

  • Fix

Verification

Commands run (this container, python:3.12-slim + uv sync --frozen --extra dev --dev):

  • uv run --extra dev pytest tests/test_segments.py tests/test_context_invariants.py tests/test_default_context_engine.py tests/test_security_untrusted_context.py -v -> 42 passed.
  • New regression tests (test_identity_with_backend_omits_stale_episodic_path, test_identity_with_backend_matches_legacy_builder in tests/test_segments.py) fail on main with TypeError: IdentitySegmentBuilder.__init__() takes 2 positional arguments but 3 were given (confirmed by reverting only the source files and re-running against the new tests) and pass on this branch.
  • Broader regression sweep: every test file that constructs ContextBuilder/AgentLoop/build_context_engine (29 files, git grep list), minus tests/integration/ and the messaging-channel adapter tests that fail to import for missing optional deps unrelated to this change (dingtalk_stream, lark_oapi, nh3, botpy, slackify_markdown, python-telegram-bot, wecom_aibot_sdk, none installed by --extra dev) -> 402 passed, 22 failed. All 22 failures are in tests/test_runtime_checkpoint_bug2*.py and are pre-existing environment gaps (FileNotFoundError: [Errno 2] No such file or directory: 'git', the python:3.12-slim image has no git binary), unrelated to this diff.
  • uv run --extra dev ruff check / ruff format --check on every changed file: clean.
  • uv run --extra dev pre-commit run --files <changed files>: all hooks pass (ruff, ruff-format, trailing-whitespace, end-of-file-fixer, large-files, merge-conflict, private-key).

Not verified: an end-to-end run against a live EverOS instance (the issue's own repro environment). The fix is scoped to the prompt-text guidance the issue describes and is covered by the unit tests above; I did not stand up EverOS to confirm the rendered prompt reaches a running agent unchanged elsewhere.

Risk

  • Security impact considered: none, prompt text only.
  • Backward compatibility considered: has_memory_backend defaults to False and the new backend parameters default to None, so every existing call site (all of which construct without a backend) renders byte-identical text to before.
  • Rollback path is clear for risky changes: revert the single commit.

Related Issues

Fixes #122

…backend

The Workspace section of the system prompt always advertises
{workspace}/user_memory/episodic/episodes.md as the episodic log to
grep, in both render.py's identity_text (the live per-turn prompt) and
builder.py's hand-duplicated copy (token-size estimation only). That
file is written only by the host's legacy MemoryConsolidator. When a
MemoryBackend plugin is wired (e.g. EverOS), episodes live in the
plugin's own store instead and are surfaced through per-turn recall
into the # Memory section (MemorySegmentBuilder), so the workspace
file stays empty and the guidance sends the agent to grep nothing.

Thread whether a backend is wired into identity_text via a new
has_memory_backend flag. IdentitySegmentBuilder and
build_context_engine already receive backend, so this is one added
parameter on each; ContextBuilder gains the same parameter, passed in
from AgentLoop.__init__ where backend is already available. With a
backend, the Episodic log line is replaced with guidance pointing at
the automatic # Memory recall instead of a file path that stays
empty. Without one (the default), the rendered text is unchanged.

Also fold ContextBuilder._get_identity into a call to the shared
render.identity_text instead of keeping a second hand-maintained copy
of the same prompt text: the two had already drifted once (builder.py
was missing the language directive render.py has), and a duplicated
literal is how this bug's own guidance line went stale in only one of
the two places to begin with.

Co-authored-by: Claude (claude-sonnet-5) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Episodic memory path is hardcoded and backend-blind (empty under EverOS)

1 participant