Skip to content

feat(recall): top-3 with body excerpts, per-session dedup, freshness …#6

Merged
nickroci merged 1 commit into
mainfrom
feat/recall
May 27, 2026
Merged

feat(recall): top-3 with body excerpts, per-session dedup, freshness …#6
nickroci merged 1 commit into
mainfrom
feat/recall

Conversation

@nickroci

Copy link
Copy Markdown
Owner

…+ kind markers

Acts on the agent's feedback after the rerank upgrade landed:

  • Top-3 instead of top-5. Fewer, higher-quality matches. The cross- encoder rerank already trimmed noise — surfacing fewer entries with more substance beats surfacing more entries with thinner signal.

  • Body excerpts on each surfaced entry. ~250-char first-paragraph excerpt under each bullet. The agent reported reinventing weaker versions of rules it had been told via wikilink — titles alone aren't enough. Note: this revises the older [[projects/agent-mem/concepts/priming-surfaces-wikilinks-not-bodies]] preference based on direct evidence from the agent's session.

  • Per-session sent-wikilink dedup. Bounded LRU on the daemon (64 sessions × 200 wikilinks) tracks what's been surfaced per session_id. Entries already shown to a session don't re-surface — they're in the agent's context. When every top-3 candidate is a repeat, the daemon returns empty markdown rather than recycling. session_id is now a fifth field on the priming RPC; the hook threads it through from the hook payload.

  • Freshness marker (★) on bullets whose frontmatter updated (or created) falls inside a 7-day window. Recent thinking is usually most load-bearing for current work.

  • Kind markers [C]/[P]/[F]/[W] derived from path segment + severity: frontmatter. Lets the agent triage convention vs preference vs finding vs warning in a glance rather than parsing each title. Best-effort heuristic; falls back to no marker.

  • Cross-project scope penalty. Flipped cross-project entries from 0 bonus to -0.010. Other-project lessons now only surface when no scoped entry beats them on relevance.

  • HTTP wire-log noise silenced (claude-agent-sdk, mcp, asyncio, plus the earlier batch). Real signals from agent_mem_daemon.* no longer drowned by debug spam at -v.

Tests: 464 daemon + 174 search + 68 hooks pass (25 new tests covering body extraction, freshness, kind classification, scope penalty, dedup filter, and the per-session sent-cache LRU mechanics).

…+ kind markers

Acts on the agent's feedback after the rerank upgrade landed:

- **Top-3 instead of top-5.** Fewer, higher-quality matches. The cross-
  encoder rerank already trimmed noise — surfacing fewer entries with
  more substance beats surfacing more entries with thinner signal.

- **Body excerpts on each surfaced entry.** ~250-char first-paragraph
  excerpt under each bullet. The agent reported reinventing weaker
  versions of rules it had been told via wikilink — titles alone aren't
  enough. Note: this revises the older
  ``[[projects/agent-mem/concepts/priming-surfaces-wikilinks-not-bodies]]``
  preference based on direct evidence from the agent's session.

- **Per-session sent-wikilink dedup.** Bounded LRU on the daemon
  (64 sessions × 200 wikilinks) tracks what's been surfaced per
  ``session_id``. Entries already shown to a session don't re-surface —
  they're in the agent's context. When every top-3 candidate is a
  repeat, the daemon returns empty markdown rather than recycling.
  ``session_id`` is now a fifth field on the priming RPC; the hook
  threads it through from the hook payload.

- **Freshness marker (★)** on bullets whose frontmatter ``updated``
  (or ``created``) falls inside a 7-day window. Recent thinking is
  usually most load-bearing for current work.

- **Kind markers** ``[C]/[P]/[F]/[W]`` derived from path segment +
  ``severity:`` frontmatter. Lets the agent triage convention vs
  preference vs finding vs warning in a glance rather than parsing
  each title. Best-effort heuristic; falls back to no marker.

- **Cross-project scope penalty.** Flipped cross-project entries from
  0 bonus to -0.010. Other-project lessons now only surface when no
  scoped entry beats them on relevance.

- **HTTP wire-log noise** silenced (claude-agent-sdk, mcp, asyncio,
  plus the earlier batch). Real signals from ``agent_mem_daemon.*``
  no longer drowned by debug spam at ``-v``.

Tests: 464 daemon + 174 search + 68 hooks pass (25 new tests covering
body extraction, freshness, kind classification, scope penalty, dedup
filter, and the per-session sent-cache LRU mechanics).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nickroci nickroci merged commit 02e7de8 into main May 27, 2026
3 checks passed
nickroci added a commit that referenced this pull request May 27, 2026
…pdates them

Footer addition surfaces on every priming render:

  *Entries are living — the curator updates them on new info.
   You may cite the current text; no need to maintain them yourself.*

Addresses a real gap the agent could hit: an entry it consulted
last turn may have a slightly different framing this turn because
the Librarian/Scholar updated it from the conversation buffer.
Without this note, the agent might (a) think it mis-cited, (b)
distrust the entry, or (c) try to edit memory directly to "fix"
the drift — the last of which would violate the existing
``no-manual-memory-writes-by-agents`` convention. The new line
preempts (c) and gently licenses (a) — past versions were correct
at their time; cite the current text.

Wording is permissive on user's correction (``You may cite``
rather than ``Cite``) — the previous header's ``cite or follow
when applicable`` already opted for that tone.

Same string lands in both renderers (daemon
``priming.py::_FOOTER`` and the hook-side fallback
``_priming_client.py::_FOOTER``) so the agent sees the same
framing regardless of which path served the request.

Tests:
- ``test_refresh_respects_char_budget`` and
  ``test_priming_char_budget_trims_bullets`` use deliberately-tight
  budgets (~400-500 chars) to exercise trim behaviour. The new
  footer added ~140 chars to the unconditional framing, so both
  budgets bumped (500→700, 400→600) to leave room for the trim
  test's seeded content. Production budget (1500) is unaffected.
- ``test_send_request_returns_none_when_socket_missing`` had a
  pre-existing pyright complaint (partial ``PrimingRequest`` dict
  after ``session_id`` was added to the TypedDict in PR #6); fixed
  properly by constructing a fully-typed request rather than
  suppressing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nickroci nickroci deleted the feat/recall branch May 27, 2026 13:02
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.

1 participant