Commit graph

4 commits

Author SHA1 Message Date
chopratejas
2208121e12 test(memory): live tests for delete-via-[id] + dedup-hint mechanism
Three live tests now cover the model-as-judge memory loop end-to-end
against the real Anthropic API:

1. memory_update via [id] (already existed) — model extracts ID from
   the auto-tail block, calls memory_update with the exact seeded ID.

2. memory_delete via [id] (new) — same handle, destructive verb.
   Proves the [id] prefix is verb-agnostic. Prompt explicitly tells
   the model to skip memory_search / memory_list so the test targets
   the direct-from-tail path.

3. memory_save → dedup-hint mechanism (new) — when the model fires
   memory_save on near-duplicate content, the proxy's _execute_save
   must return a "Similar memory exists" note carrying the existing
   memory's exact ID. Without this hint, parallel duplicates would
   silently accumulate, polluting the cache prefix.

The dedup test asserts the MECHANISM (hint contains seeded ID),
not the model's downstream behaviour. The hint text intentionally
ends with "or ignore if these are distinct facts", so the model is
free to decline consolidation. Whether it consolidates depends on a
judgement call about whether two phrasings name the same fact —
intentionally outside this test's contract.

Refactor: extract _seed_memory and _install_tool_call_recorder
module-level helpers so all three live tests read as their intent.
Recorder also captures the tool result now (needed to inspect the
JSON-encoded dedup hint).
2026-05-19 22:18:15 -05:00
chopratejas
c62d45eea8 fix(memory): expose memory IDs in auto-tail + memory_list tool + ID-usage guidance
Pre-this-PR the auto-injected memory block rendered rows as `1. <content>`
with no addressable handle. To UPDATE or DELETE a row the model first had
to call memory_search to discover its ID — two round trips, against the
model-as-judge architecture.

This PR adds three tightly-coupled affordances so the model can act on
memory directly:

1. Auto-tail rows now carry the memory ID:
     `1. [mem_alpha_001] User prefers Python`
   The bracketed token is the canonical ID — same identifier accepted by
   memory_update and memory_delete.

2. New `memory_list` tool — chronological browse (vs `memory_search`'s
   semantic lookup). Returns recent memories with their IDs. Backend
   dispatches to `Backend.list_memories` if available, else falls back
   to an empty-query `search_memories`. Caps at 100 entries.

3. ID-usage guidance text appended to the auto-tail block. Tells the
   model that bracketed IDs can go straight to memory_update /
   memory_delete with no intervening search. The guidance lives in the
   user-message tail (never system) — preserves cache-prefix byte
   stability (invariant I2).

`memory_update` and `memory_delete` tool descriptions also point at the
[id] block as a valid ID source — keeps tool docs consistent with the
new affordance.

Verification:
- 10/10 tests pass in tests/test_memory_auto_tail.py (incl. 2 new
  guidance tests + 2 new ID-format tests)
- 31/31 tests pass in tests/test_memory_handler_native_ops.py (incl. 4
  new memory_list dispatch tests + existing assertions updated for the
  [id] format change)
- Golden fixtures regenerated for the tool-description copy changes
  (tests/fixtures/memory_tool_definitions/{anthropic,openai}.json)
- Live end-to-end test against real Anthropic API
  (tests/test_proxy_memory_integration.py::TestMemoryIdAutoTailAndUpdate):
  seeded memory → auto-tail → Claude → memory_update with exact ID.
  PASSED.
2026-05-19 22:10:42 -05:00
Tejas Chopra
787f925204 fix: correct cost calculation for cache tokens and simplify memory DevEx
- Fix Anthropic cache token cost formula: input_tokens, cache_read, and
  cache_write are all separate (not overlapping), so don't subtract
  cache_write from input_tokens
- Default memory user ID to "default" when x-headroom-user-id header is
  not provided, removing the need for client configuration
- Update CLI help text and tests to reflect new default behavior
2026-01-26 22:49:31 -08:00
chopratejas
da74341858 Add hierarchical memory system with graph + vector storage
Implement comprehensive memory system supporting:
- Local backend (SQLite + FTS5 + HNSW) for zero-dependency operation
- Mem0 backends (Neo4j + Qdrant) for production graph memory
- DirectMem0Adapter for optimized pre-extracted data (bypasses LLM)
- Memory extraction with facts, entities, and relationships
- Proxy integration with --memory flag for automatic memory injection

Key components:
- headroom/memory/backends/: LocalBackend, Mem0Backend, DirectMem0Adapter
- headroom/memory/system.py: MemorySystem with tool-based interface
- headroom/memory/extraction.py: Entity and relationship extraction
- headroom/proxy/memory_handler.py: Proxy integration layer
- headroom/prediction/feature_extractor.py: Content analysis features

Testing:
- 217 new memory system tests covering all backends
- LoCoMo evaluation framework for memory quality assessment
- Integration tests for proxy memory functionality

Also removes deprecated example files in favor of focused test coverage.
2026-01-26 21:58:47 -08:00