feat: make the two-step reflection observable (draft -> revised -> critique)
You couldn't see her actually correct herself — /self showed only the result. Now: - reflect() logs the draft, the revised/committed version, and the self-critique to the live log as an expandable "view details" block - POST /self/reflect runs a reflection in the web process so it lands in /logs live (reflections normally run in the dream process, whose logs only go to journald); "↻ Reflect now" button on /self triggers it, with a logs ↗ link - log viewers relabel the expander "view full prompt" -> "view details" (it now carries prompts and reflection diffs) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+27
-4
@@ -150,6 +150,20 @@ def _safe_json(s: str) -> dict | None:
|
||||
return None
|
||||
|
||||
|
||||
def _fmt_reflection(label: str, d: dict | None) -> str:
|
||||
"""Readable block of a reflection's key fields, for the live-log inspector."""
|
||||
if not d:
|
||||
return f"{label}:\n (none)"
|
||||
keys = ("mood", "valence", "energy", "confidence", "curiosity",
|
||||
"self_narrative", "relationship", "new_reflections")
|
||||
lines = [f"{label}:"]
|
||||
for k in keys:
|
||||
if k in d and d[k] not in (None, "", []):
|
||||
v = " | ".join(d[k]) if isinstance(d[k], list) else d[k]
|
||||
lines.append(f" {k}: {v}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def reflect(backend: Backend | None = None, session_id: str | None = None) -> dict:
|
||||
"""Reflect on recent activity and update the self-state. Returns new state.
|
||||
|
||||
@@ -189,7 +203,7 @@ def reflect(backend: Backend | None = None, session_id: str | None = None) -> di
|
||||
))
|
||||
|
||||
# Step 2 — examine her own draft and revise it into a more honest version.
|
||||
update, critique = draft, None
|
||||
update, critique, revised = draft, None, None
|
||||
if draft:
|
||||
examine_body = body + "\n\nYOUR DRAFT REFLECTION:\n" + json.dumps(draft, indent=2)
|
||||
revised = _safe_json(llm.complete(
|
||||
@@ -217,9 +231,18 @@ def reflect(backend: Backend | None = None, session_id: str | None = None) -> di
|
||||
|
||||
state["interaction_count"] = state.get("interaction_count", 0) + 1
|
||||
memory.set_self_state(state)
|
||||
logbus.log("info", "self-state updated", mood=state.get("mood"),
|
||||
interactions=state["interaction_count"], parsed=bool(update),
|
||||
critiqued=bool(critique))
|
||||
|
||||
# Surface the actual self-correction (draft -> revised -> critique) to the live
|
||||
# log as an expandable block, so the two-step reflection is observable.
|
||||
detail = (
|
||||
_fmt_reflection("DRAFT (first pass)", draft) + "\n\n"
|
||||
+ _fmt_reflection("REVISED (committed)",
|
||||
revised if revised else None)
|
||||
+ ("" if revised else "\n (examine step didn't parse — kept the draft)")
|
||||
+ "\n\nSELF-CRITIQUE:\n " + (critique or "(none recorded this pass)")
|
||||
)
|
||||
logbus.log("info", "reflection", mood=state.get("mood"),
|
||||
critiqued=bool(critique), detail=detail)
|
||||
return state
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user