Skip to content

feat: retrieval-utility logging + history-based deletion (Closes #1480) - #1483

Merged
Lexus2016 merged 2 commits into
mainfrom
evolution/issue-1480-retrieval-utility-2
Jul 28, 2026
Merged

feat: retrieval-utility logging + history-based deletion (Closes #1480)#1483
Lexus2016 merged 2 commits into
mainfrom
evolution/issue-1480-retrieval-utility-2

Conversation

@Lexus2016

Copy link
Copy Markdown
Owner

Automated evolution PR for issue #1480 (child of #1270).

Summary

Add structured retrieval-utility logging on the existing memory retrieval infrastructure and a history-based deletion function that removes records retrieved ≥n times with average downstream utility below a threshold. The ACL 2026 memory-management paper proves selective addition + history-based deletion beats add-all by 22-25 points.

Changes

  • agent/retrieval_utility.py (new): Sidecar JSON log module with:

    • record_retrieval() — log when memory/skill context is retrieved
    • record_outcome() — log downstream outcome (helpful/neutral/harmful) derived from friction signals
    • compute_utility() — aggregate avg downstream utility per record
    • delete_low_utility_records() — identify records eligible for history-based deletion (retrieved ≥n times, avg utility < floor)
    • Atomic writes, cross-process file locking, cap at 5000 entries
  • agent/memory_manager.py: Wire retrieval logging into existing infrastructure:

    • prefetch_all() calls _record_retrieval_utility() when a provider returns context
    • sync_all() calls _record_retrieval_outcomes() after scoring friction signals
    • Per-turn tracking via _pending_retrievals list
  • hermes_cli/config.py: Add memory.retrieval_utility config section (enabled, min_retrievals, utility_floor)

  • Tests: 25 unit tests + 7 MemoryManager integration tests (all passing)

Design notes

  • Sidecar pattern mirrors tools/skill_usage.py — operational telemetry stays out of user-authored content
  • Best-effort: failures log at DEBUG and return silently; broken sidecar never breaks memory
  • Profile-aware via get_hermes_home()
  • No prompt caching impact: logging is a side effect in the background worker path, not in the system prompt

Closes #1480

Add structured retrieval-utility logging on the existing memory retrieval
infrastructure and a history-based deletion function that removes records
retrieved >=n times with average downstream utility below a threshold.

- agent/retrieval_utility.py: sidecar JSON log with record_retrieval(),
  record_outcome(), compute_utility(), delete_low_utility_records()
- agent/memory_manager.py: wire prefetch_all → record_retrieval,
  sync_all → record_outcome (uses existing friction signals)
- hermes_cli/config.py: memory.retrieval_utility config section
- Tests: 25 unit tests + 7 integration tests

Closes #1480

Co-Authored-By: Hermes Evolution <evolution@hermes.ai>
@github-actions github-actions Bot added the bug Something isn't working label Jul 28, 2026
Two privacy issues found reviewing this PR. Both are small, and neither costs
the feature anything.

1. record_retrieval persisted retrieval_context[:500] — up to 500 characters of
   the user's query, on disk, per retrieval. It was WRITE-ONLY: compute_utility
   scores outcomes alone and never reads it, so the text served no downstream
   purpose. Now accepted but not stored; the parameter stays in the signature so
   callers need no change and a future consumer can opt into a redacted form
   deliberately rather than by default.

2. retrieval_utility.enabled defaulted True, so every memory/skill hit in every
   ordinary session wrote a record to disk unasked. Now False, matching the
   opt-in HERMES_EVOLUTION_CAPTURE precedent from #1363 — where the same
   question came up and was settled the same way.

The existing test asserted the stored context, so it is updated to pin the new
behaviour, plus a test that the query text does not appear anywhere in the
persisted entry.

26 passing in test_retrieval_utility.py, 31 with the memory-manager suite.
Ruff clean.
@Lexus2016

Copy link
Copy Markdown
Owner Author

Reviewed and pushed two privacy fixes to this branch (8b8409ea8). Both are small, and neither costs the feature anything.

1. record_retrieval persisted retrieval_context[:500] — up to 500 characters of the user's query, on disk, per retrieval.

It was write-only: compute_utility scores outcomes alone and never reads it, so the text served no downstream purpose at all. Now accepted but not stored. The parameter stays in the signature so callers need no change, and a future consumer can opt into a redacted form deliberately rather than by default.

2. retrieval_utility.enabled defaulted True — every memory/skill hit in every ordinary session wrote a record to disk unasked. Now False, matching the HERMES_EVOLUTION_CAPTURE precedent from #1363, where the same question came up and was settled the same way.

The existing test asserted the stored context, so it now pins the new behaviour, plus a test that the query text appears nowhere in the persisted entry.


On the other PR

#1482 closes the same issue with a different approach — it logs retrieval utility for ERL heuristics (scripts/evolution_retrieval_utility.py, plus backfill through the funnel), where this one covers memory/skill records in the runtime.

#1480 asks for memory/skill retrieval specifically, so this PR is the one that matches. Merging both would create two parallel utility stores — one under agent/, one under scripts/ — recording the same kind of signal for different subsystems, with no shared identity or schema.

Merging this one; closing #1482 with the suggestion that if heuristic-retrieval utility is wanted, it should write to this store rather than a second one.

26 passing in test_retrieval_utility.py, 31 with the memory-manager suite. Ruff clean.

@Lexus2016
Lexus2016 merged commit de04d93 into main Jul 28, 2026
36 checks passed
@Lexus2016
Lexus2016 deleted the evolution/issue-1480-retrieval-utility-2 branch July 28, 2026 17:04
Lexus2016 added a commit that referenced this pull request Jul 29, 2026
The memory.retrieval_utility.enabled config flag defaults to False
(opt-in), but _record_retrieval_utility and _record_retrieval_outcomes
in MemoryManager ran unconditionally — writing a per-retrieval record
to disk on every memory hit in every session despite the user never
opting in.

This adds a _retrieval_utility_enabled() check that reads the config
flag via load_config_readonly() and gates both methods. When disabled
(the default), no sidecar file is written and no pending retrievals
accumulate.

Identified in PR #1483 code review. Issue #1480 was closed as completed
but the privacy gate fix was never landed — PR #1485 is stuck in a
conflicting state. This is the minimal standalone fix.

Co-authored-by: Hermes Evolution <evolution@hermes.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[INCREMENT] Retrieval-utility logging + history-based deletion for memory/skill records (Child A of #1270)

1 participant