ecf0b852f9
Derive a standing profile of the user from session gists and inject it into
every prompt, so identity/abstract questions ("what kind of player am I",
"what are my leaks") are answered from distilled knowledge instead of noisy
single-vector recall (which finds passages, not patterns).
- memory: profile table + get/set_profile, list_summaries
- lyra/profile.py: rebuild_profile map-reduces all gists (batch -> extract
durable facts -> fold-merge) into one profile doc; `lyra-profile` CLI
- chat.build_messages injects "What you know about Brian" after the persona
Run after lyra-summarize (needs gists). Verified (stubbed): map-reduce, storage,
and prompt injection.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
85 lines
3.2 KiB
Python
85 lines
3.2 KiB
Python
"""Profile derivation: distill standing facts about the user (semantic memory).
|
|
|
|
This is consolidation step 2. It reads every session gist and map-reduces them
|
|
into one profile document — who Brian is as a player and person — which is then
|
|
injected into every prompt. This is what answers identity/abstract questions
|
|
("what kind of player am I", "what are my leaks") that raw recall handles badly,
|
|
because those are patterns across many sessions, not facts in any single message.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
|
|
from lyra import config, llm, logbus, memory
|
|
from lyra.llm import Backend, Message
|
|
|
|
BATCH_CHARS = 18000
|
|
|
|
_MAP_PROMPT = """From these session summaries, extract durable facts about Brian \
|
|
— things that are stably true, not one-off events. Cover, where present: poker \
|
|
games/formats/stakes he plays, his playing style and strengths, recurring leaks \
|
|
and tendencies, mental-game patterns (tilt triggers, scared money, fatigue), \
|
|
relevant personal context, and how he likes to be coached. Terse bullet points. \
|
|
Omit anything not supported by the summaries."""
|
|
|
|
_REDUCE_PROMPT = """Merge these fact lists into one deduplicated profile of Brian. \
|
|
Organize under these headings: Poker Style, Leaks & Tendencies, Mental Game, \
|
|
Personal Context, Working With Brian. Keep it tight — bullets, no fluff, no \
|
|
repetition. Resolve contradictions toward the more recent/frequent signal."""
|
|
|
|
|
|
def _batch_texts(texts: list[str], budget: int) -> list[str]:
|
|
"""Group texts into joined blocks under `budget` chars."""
|
|
blocks, buf, size = [], [], 0
|
|
for t in texts:
|
|
if size + len(t) > budget and buf:
|
|
blocks.append("\n\n".join(buf))
|
|
buf, size = [], 0
|
|
buf.append(t)
|
|
size += len(t)
|
|
if buf:
|
|
blocks.append("\n\n".join(buf))
|
|
return blocks
|
|
|
|
|
|
def _call(prompt: str, body: str, backend: Backend) -> str:
|
|
messages: list[Message] = [
|
|
{"role": "system", "content": prompt},
|
|
{"role": "user", "content": body},
|
|
]
|
|
return llm.complete(messages, backend=backend)
|
|
|
|
|
|
def rebuild_profile(backend: Backend | None = None) -> str | None:
|
|
"""Re-derive the profile from all current session gists and store it."""
|
|
backend = backend or config.load().summary_backend
|
|
summaries = memory.list_summaries()
|
|
if not summaries:
|
|
return None
|
|
|
|
# MAP: extract facts from batches of gists.
|
|
blocks = _batch_texts([s.content for s in summaries], BATCH_CHARS)
|
|
partials = [_call(_MAP_PROMPT, b, backend) for b in blocks]
|
|
logbus.log("info", "profile map done", batches=len(partials), sessions=len(summaries))
|
|
|
|
# REDUCE: fold partials together until one remains.
|
|
while len(partials) > 1:
|
|
partials = [_call(_REDUCE_PROMPT, g, backend) for g in _batch_texts(partials, BATCH_CHARS)]
|
|
profile = partials[0]
|
|
|
|
memory.set_profile(profile, len(summaries))
|
|
logbus.log("info", "profile rebuilt", sessions=len(summaries), chars=len(profile))
|
|
return profile
|
|
|
|
|
|
def main() -> int:
|
|
profile = rebuild_profile()
|
|
if profile is None:
|
|
print("No summaries yet — run lyra-summarize first.")
|
|
return 1
|
|
print(profile)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|