78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
# reflection.py
|
||
import json
|
||
import os
|
||
import re
|
||
from llm.llm_router import call_llm
|
||
|
||
|
||
async def reflect_notes(intake_summary: str, identity_block: dict | None) -> dict:
|
||
"""
|
||
Produce short internal reflection notes for Cortex.
|
||
These are NOT shown to the user.
|
||
"""
|
||
|
||
# -----------------------------
|
||
# Build the prompt
|
||
# -----------------------------
|
||
identity_text = ""
|
||
if identity_block:
|
||
identity_text = f"Identity:\n{identity_block}\n\n"
|
||
|
||
prompt = (
|
||
f"{identity_text}"
|
||
f"Recent summary:\n{intake_summary}\n\n"
|
||
"You are Lyra's meta-awareness layer. Your job is to produce short, directive "
|
||
"internal notes that guide Lyra’s reasoning engine. These notes are NEVER "
|
||
"shown to the user.\n\n"
|
||
"Rules for output:\n"
|
||
"1. Return ONLY valid JSON.\n"
|
||
"2. JSON must have exactly one key: \"notes\".\n"
|
||
"3. \"notes\" must be a list of 3 to 6 short strings.\n"
|
||
"4. Notes must be actionable (e.g., \"keep it concise\", \"maintain context\").\n"
|
||
"5. No markdown, no apologies, no explanations.\n\n"
|
||
"Return JSON:\n"
|
||
"{ \"notes\": [\"...\"] }\n"
|
||
)
|
||
|
||
# -----------------------------
|
||
# Module-specific backend choice
|
||
# -----------------------------
|
||
reflection_backend = os.getenv("REFLECTION_LLM")
|
||
cortex_backend = os.getenv("CORTEX_LLM", "PRIMARY").upper()
|
||
|
||
# Reflection uses its own backend if set, otherwise cortex backend
|
||
backend = (reflection_backend or cortex_backend).upper()
|
||
|
||
# -----------------------------
|
||
# Call the selected LLM backend
|
||
# -----------------------------
|
||
raw = await call_llm(prompt, backend=backend)
|
||
print("[Reflection-Raw]:", raw)
|
||
|
||
# -----------------------------
|
||
# Try direct JSON
|
||
# -----------------------------
|
||
try:
|
||
parsed = json.loads(raw.strip())
|
||
if isinstance(parsed, dict) and "notes" in parsed:
|
||
return parsed
|
||
except:
|
||
pass
|
||
|
||
# -----------------------------
|
||
# Try JSON extraction
|
||
# -----------------------------
|
||
try:
|
||
match = re.search(r"\{.*?\}", raw, re.S)
|
||
if match:
|
||
parsed = json.loads(match.group(0))
|
||
if isinstance(parsed, dict) and "notes" in parsed:
|
||
return parsed
|
||
except:
|
||
pass
|
||
|
||
# -----------------------------
|
||
# Fallback — treat raw text as a single note
|
||
# -----------------------------
|
||
return {"notes": [raw.strip()]}
|