Skip to content

feat(memory): say when a turn used stored memory, and which - #417

Merged
sulthannauval merged 2 commits into
mainfrom
feat/memory-recall-visibility
Aug 6, 2026
Merged

feat(memory): say when a turn used stored memory, and which#417
sulthannauval merged 2 commits into
mainfrom
feat/memory-recall-visibility

Conversation

@sulthannauval

Copy link
Copy Markdown
Member

Problem

Recalled memory was prepended to every prompt with nothing on any surface
saying so
. An answer shaped by a remembered fact read as if the model simply
knew it, and an operator had no way to tell the difference — or to find the
entry responsible. This was raised as the one gap left open by the memory
UI/UX sweep (#414, #415, claw-ui #50).

Change

  • build_memory_context returns MemoryContext { block, keys }. The keys are
    carried rather than parsed back out of the block: the block's shape is a
    prompt-formatting decision, and a reader deriving keys from it would break
    the next time that shape changed.
  • The agent emits AgentEvent::MemoryRecalled { keys } before the first chunk,
    and only when something was injected — an empty recall stays silent.
  • TUI renders ↺ recalled N memories: ….
  • Gateway forwards it as memory_recalled on the chat stream (consumed by
    claw-ui, separate PR).
  • Channels take .block only: a remote transport has no event stream to
    surface it on.

Auto-saved turns are counted, not named. Their keys are user_msg_<uuid>,
and the first version of this line filled the terminal width with hex while
saying less than "3 from this conversation" does — the same defect the console's
memory panel had with generated keys.

Validation

  • cargo test --lib memory:: / tui::app / agent:: / gateway::api_v1 and
    --test agent_e2e — 629 passed across the affected areas.
  • Mutation-tested both directions: removing the emit fails the test, and
    emitting unconditionally fails its control.
  • Strict delta gate — clean.
  • Driven live in the TUI against a real store, with a stub provider so the turn
    completes:
You: when is the deployment window?
System: ↺ recalled 5 memories: 5 from this conversation
Assistant: Deployments happen Friday afternoons only.

Two things this surfaced

The first version rendered nowhere. It pushed to scrollback_queue, which
— along with commit_message_to_scrollback — nothing in src/ reads any more.
Only driving the binary caught it. Both are left in place rather than removed
here: dead code is worth a separate, deliberate change.

What actually gets injected is conversation echo. In the run above, all
five recalled entries were auto-saved turns; the curated deploy_window fact
never reached the prompt, although a direct memory recall ranks it at 100%.
recall_layered puts conversation-scoped hits first and they fill the entry
budget. That is pre-existing behaviour and changing it changes what every turn
sends to the model, so it is not touched here — but it is worth deciding on,
and it was invisible until this landed.

Risk / rollback

Medium: one new event variant, one changed return type with three call sites.
No config or schema change. Revert the commits.

Recalled memory was prepended to every prompt with nothing on any surface
saying so. An answer shaped by a remembered fact read as if the model simply
knew it, and an operator had no way to tell the difference — or to find the
entry responsible.

- `build_memory_context` returns a `MemoryContext { block, keys }`. The keys
  are carried rather than parsed back out of the block: the block's shape is a
  prompt-formatting decision, and a reader deriving keys from it would break
  the next time that shape changed.
- The agent emits `AgentEvent::MemoryRecalled { keys }` before the first chunk,
  and only when something was injected — an empty recall stays silent.
- TUI renders it as a muted tool-log line: memory is background activity, not
  something to act on.
- Gateway forwards it as `memory_recalled` on the chat stream.
- Channels take `.block` only: a remote transport has no event stream to
  surface it on.

Both directions are covered: removing the emit fails the test, and emitting
unconditionally fails its control.
Driving the new line showed it filling the width with
`user_msg_23f4b294-…` — five uuids that identify nothing to the reader.
Same defect the console's memory panel had with generated keys.

Auto-saved turns are now counted ("3 from this conversation"); memories a
person named are still named. Adds `memory::is_autosave_key` for the test.

Also switches the notice onto `append_system_message`: `scrollback_queue`
and `commit_message_to_scrollback` still exist but nothing reads them any
more, so the first version rendered nowhere at all.
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

PR intake checks found warnings (non-blocking)

Fast safe checks found advisory issues. CI lint/test/build gates still enforce merge quality.

  • Missing required PR template sections: ## Summary, ## Validation Evidence (required), ## Security Impact (required), ## Privacy and Data Hygiene (required), ## Rollback Plan (required)
  • Incomplete required PR template fields: summary problem, summary why it matters, summary what changed, validation commands, security risk/mitigation, privacy status, rollback plan

Action items:

  1. Complete required PR template sections/fields.
  2. Remove tabs, trailing whitespace, and merge conflict markers from added lines.
  3. Re-run local checks before pushing:
    • ./scripts/ci/rust_quality_gate.sh
    • ./scripts/ci/rust_strict_delta_gate.sh
    • ./scripts/ci/docs_quality_gate.sh

Run logs: https://github.com/RantAI-dev/RantAIClaw/actions/runs/31082831161

Detected blocking line issues (sample):

  • none

Detected advisory line issues (sample):

  • none

@github-actions github-actions Bot added agent Auto scope: src/agent/** changed. channel Auto scope: src/channels/** changed. gateway Auto scope: src/gateway/** changed. memory Auto scope: src/memory/** changed. tests Auto scope: tests/** changed. size: M Auto size: 251-500 non-doc changed lines. risk: high Auto risk: security/runtime/gateway/tools/workflows. distinguished contributor Contributor with 50+ merged PRs. gateway: api_v1 Auto module: gateway/api_v1 changed. channel: core Auto module: channel core files changed. memory: context Auto module: memory/context changed. and removed channel Auto scope: src/channels/** changed. gateway Auto scope: src/gateway/** changed. memory Auto scope: src/memory/** changed. labels Aug 6, 2026
@sulthannauval
sulthannauval merged commit 64b48b5 into main Aug 6, 2026
17 checks passed
@sulthannauval
sulthannauval deleted the feat/memory-recall-visibility branch August 6, 2026 08:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Auto scope: src/agent/** changed. channel: core Auto module: channel core files changed. distinguished contributor Contributor with 50+ merged PRs. gateway: api_v1 Auto module: gateway/api_v1 changed. memory: context Auto module: memory/context changed. risk: high Auto risk: security/runtime/gateway/tools/workflows. size: M Auto size: 251-500 non-doc changed lines. tests Auto scope: tests/** changed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant