feat(persona): decision agent over the persona memory layer (algorithmic retrieval + LLM pass)#77
Conversation
Adds `memory::persona::retrieve` — a purely lexical, no-LLM retriever over the persona observation leaves persisted by the reduce step. Loads every `owner="persona"` Document chunk per facet, splits each rendered `- <obs> (…) [tN]` line into an indexed observation, and ranks against a query with BM25 scaled by evidence-tier weight (mirrors reduce::tier_score). Deterministic, network-free; the LLM final pass filters what this surfaces, never selects it. 10 unit + integration tests (parsing, tokenizer, BM25 ranking, facet filter, tier weighting, real-workspace load roundtrip).
…ols) Adds `examples/persona_agent.rs` — a two-stage decision agent over the persona memory layer: - Stage 1: algorithmic BM25 retrieval (PersonaRetriever, no LLM). - Stage 2: a tinyagents AgentHarness backed by the OpenRouter model (DeepSeek v4 Flash) with three read-only tools — search_persona, list_directives, persona_overview — that filters/synthesises the retrieved evidence into a decision in the developer's own voice, citing tiers. Registered as a `persona`-gated example.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 33 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d63fa57c8d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "[{facet} | {tier} | score {score:.2}] {text}{quote}", | ||
| facet = h.facet.as_str(), | ||
| tier = h.tier.as_str(), | ||
| score = h.score, | ||
| text = h.text, | ||
| ) |
There was a problem hiding this comment.
Include timestamps in persona evidence output
When retrieved observations conflict, the system prompt tells the LLM to prefer the more recent evidence, but this formatter drops h.timestamp before the hit reaches the model. In same-tier conflicts or across multiple search_persona calls, the model only sees facet/tier/score/text/quote and cannot apply the recency rule, so it can choose stale preferences even though the retriever already carries timestamps.
Useful? React with 👍 / 👎.
| source_kind: Some(SourceKind::Document), | ||
| source_id: Some(facet.tree_scope()), | ||
| owner: Some(PERSONA_OWNER.to_string()), | ||
| limit: Some(10_000), |
There was a problem hiding this comment.
Page through all persona chunks
For large persona workspaces with more than 10,000 chunks in a facet, this single list_chunks call only indexes the first page: ListChunksQuery is paginated and normalized_limit in src/memory/chunks/store_list.rs clamps requests to 10,000 while ordering newest-first. That violates the retriever's "load every observation" contract and silently makes older evidence unretrievable; loop with offset until the final short page instead.
Useful? React with 👍 / 👎.
Summary
Turns the persona memory layer (doc 06, #75) into an answer surface: a purely algorithmic retriever plus a
tinyagentsagent harness that answers hard coding decisions as this person would, grounded in their distilled coding persona. Demonstrates both goals from #76's parent milestone follow-on — one full memory-engine run, and user-like intelligence surfaced from it.Two new pieces alongside the existing
personasurface (allpersona-gated; default build unaffected):memory::persona::retrieve— algorithmic retrieval (no LLM)PersonaRetriever::load(&config)reads everyowner="persona"observation leaf the reduce step persists (one Document chunk per facet), splits each rendered- <obs> ("<quote>") [tN]line into an indexed doc, and ranks against a query with:Deterministic, network-free, ties broken by recency. No per-observation vectors exist on disk (pipeline seals with
embedder: None), and embedding the query would make retrieval itself model-dependent — so retrieval stays lexical and the LLM enters only at the final pass.examples/persona_agent.rs— the decision agent (LLM final pass)AgentHarness<PersonaState>backed by the OpenRouter reference model (DeepSeek v4 Flash) with three read-only tools over the retriever:search_persona(BM25, optional facet filter),list_directives(verbatim T0 rules),persona_overview(facet coverage). Stage 1 selects candidates algorithmically; the LLM only filters, resolves tier/recency conflicts, and writes a decisive answer in the person's voice — citing the evidence it used.Live verification
One full backfill over this machine (Claude Code + Codex +
CLAUDE.md/AGENTS.md+ git), capped 80 sessions:PERSONA.md, $0.0848, no fabrication.fix/branch + failing-test-first + babysit-CI flow; sibling*_tests.rs+ ≤500-line + export-onlymod.rs).Full numbers and reproduce steps in
docs/plan/06-persona-agent-demo.md.Tests
cargo fmtclean.Notes
memory::persona::retrieve); the example only wires it to the harness.🤖 Generated with Claude Code