Skip to content

PR4 v0.4.0 - FileMemory adapter unblocks the learning loop - #4

Open
bettercallzaal wants to merge 1 commit into
feat/pr3-interventionfrom
feat/pr4-file-memory
Open

PR4 v0.4.0 - FileMemory adapter unblocks the learning loop#4
bettercallzaal wants to merge 1 commit into
feat/pr3-interventionfrom
feat/pr4-file-memory

Conversation

@bettercallzaal

Copy link
Copy Markdown
Owner

Stacked on PR #3. Rebase target switches to main after PR3 merges.

What this PR teaches

PR1-3 wired the learner end to end - Learner wrapper, MemoryAdapter interface, hermes-bug-fix few-shot injection - but the only shipped adapter (BonfireMemory) returns [] until the Bonfire admin labeling step unlocks. The loop was wired but dormant.

PR4 adds FileMemory: a local JSONL-backed MemoryAdapter. Each OrchestratorEvent is one line. retrieve() joins classified + completed events by taskId, filters to the requested pattern, returns recency-sorted MemoryHits. No embeddings, no network - just append + read.

End-to-end loop now provable

This is the PR where you can actually demonstrate the learning behaviour without depending on Bonfires.

  • Run 1: orchestrate('fix the type error in foo.ts') -> FileMemory records classified + spawned + completed events.

  • Run 2: orchestrate('fix the type error in bar.ts') -> learner.retrieve returns run 1 -> hermesBugFix.prepare injects this block into the systemPrompt of the second Hermes session:

    Past similar tasks (most relevant first):
    1. Past task: "fix the type error in src/foo.ts"
       Outcome: changed foo.ts:42 from string to number, ran the type check, clean
       Cost: $0.120  Interventions: 0
    

The tests/learning-loop.test.ts integration test runs this and asserts the second session's systemPrompt contains the actual outcome text from the first.

What ships

File Purpose
src/adapters/file-memory.ts JSONL append + per-task join + recency sort + ENOENT graceful first-run
src/index.ts + package.json exports Re-exports FileMemory + adds ./adapters/file-memory subpath
tests/file-memory.test.ts 5 unit tests - missing file, JSONL format, retrieve by pattern, limit, malformed lines
tests/learning-loop.test.ts 2 integration tests - second-run-sees-first-run, queryable accumulator

Adapter matrix (after PR4)

Adapter Use when Hits today
FileMemory self-host, no graph dep YES (recency + pattern filter)
BonfireMemory knowledge-graph backed, multi-corpus dormant (returns [] until Bonfire admin labeling unlocks)

Both implement the same MemoryAdapter interface. Swap them by changing one line of orchestrator wiring.

Verification

typecheck   clean
tests       33 passed / 0 failed
            (autonomy 7, router 3, supervisor 8, orchestrator 8, file-memory 5, learning-loop 2)
build       clean dist/

Limits left for later PRs

  • Similarity ranking (PR5) - retrieve is recency + pattern filter only. PR5 adds naive keyword-overlap scoring to FileMemory as a midpoint until embeddings show up. BonfireMemory uses vector search the moment its graph is labeled.
  • Adaptive supervisor (PR5) - the data to drop loopThreshold to 2 for patterns that historically loop is recorded today; PR5 wires the supervisor to read it.

Lands on merge

  • Auto-tag v0.4.0 after PR3 -> PR4 cascade
  • FileMemory becomes the documented default for self-hosters

🤖 Generated with Claude Code

PR1-3 had a Learner wrapper, a MemoryAdapter interface, and a
hermes-bug-fix pattern that few-shot injects retrieved hits into its
systemPrompt - but the only adapter (BonfireMemory) returns [] until
Bonfire admin labeling unlocks. The loop was wired but dormant.

PR4 adds FileMemory: a local JSONL-backed MemoryAdapter. Each
OrchestratorEvent is one line. retrieve() joins classified+completed
events by taskId, filters to the requested pattern, returns recency-
sorted MemoryHits. No embeddings, no network - just append + read.

End-to-end loop now provable:
- Run 1: orchestrate('fix type error in foo.ts') -> FileMemory records
  classified + spawned + completed events -> file gets a row.
- Run 2: orchestrate('fix type error in bar.ts') -> learner.retrieve
  finds run 1 -> hermesBugFix.prepare injects:
    "Past similar tasks (most relevant first):
     1. Past task: fix type error in foo.ts
        Outcome: changed foo.ts:42 from string to number..."
  into the systemPrompt of the second Hermes session.

This is also the obvious default adapter for self-hosters who don't want
to depend on Bonfires for the v1 case.

What ships:
- src/adapters/file-memory.ts - JSONL append + per-task join + recency sort
- src/index.ts + package.json exports - FileMemory + ./adapters/file-memory
- tests/file-memory.test.ts - 5 unit tests (missing file, JSONL format,
  retrieve by pattern, limit, malformed lines)
- tests/learning-loop.test.ts - 2 integration tests proving run 2 sees
  run 1's outcome in its systemPrompt
- Bumped to 0.4.0

BonfireMemory remains shipped + supported - FileMemory is the default
for self-hosters, Bonfire is the default for graph-backed setups.

Known limits (PR5+):
- No similarity ranking yet - retrieve is recency + pattern filter only.
  When Bonfire labeling unlocks, BonfireMemory uses vector search and
  this becomes a non-issue. PR5 may add naive keyword overlap to
  FileMemory as a midpoint.
- Adaptive supervisor (drop loopThreshold to 2 if past runs of this
  pattern looped) lands in PR5 - the data is already being recorded.

Tests: 33/33 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <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.

1 participant