feat: cloud-first consolidation routing + graceful backend fallback

Nail down which backend each LLM path uses, and make the dream cycle resilient to
a backend being down (the MI50 outage left profile/era/narrative — pinned to mi50
with no fallback — aborting every dream cycle).

- Consolidation (summaries + profile/era/narrative) -> cloud via SUMMARY_BACKEND=
  cloud (.env, not committed). Matches the documented lesson that the MI50 is too
  slow/hot for bulk consolidation; nothing background touches the card now.
- llm.complete_with_fallback(): try the primary backend, fall back to cloud on
  error (re-raise if already cloud / no key). Wired into reflect + think so the
  introspection voice (3090/dolphin) survives the gaming PC being powered off.
- dream coherence stage is now fault-isolated: a rebuild failure logs + continues
  instead of sinking the whole pass (reflection still runs).
- .env: removed stale INTROSPECTION_BACKEND=mi50 (live routing is the web-switchable
  introspection_mode DB setting = dolphin/3090; the var only fed a dead fallback).

Verified: forced cycle runs consolidation on cloud, introspection on the 3090,
completes with zero MI50 calls. 206 pass, ruff clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015yrEb5qpPGv2FjyxrB7LLk
This commit is contained in:
2026-07-07 06:53:55 +00:00
parent d4e203b00c
commit 173fd18688
8 changed files with 105 additions and 15 deletions
+3 -3
View File
@@ -317,7 +317,7 @@ def reflect(backend: Backend | None = None, session_id: str | None = None,
)
# Step 1 — draft a reflection.
draft = _safe_json(llm.complete(
draft = _safe_json(llm.complete_with_fallback(
[{"role": "system", "content": _REFLECT_PROMPT}, {"role": "user", "content": body}],
backend=backend, model=model,
))
@@ -326,7 +326,7 @@ def reflect(backend: Backend | None = None, session_id: str | None = 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(
revised = _safe_json(llm.complete_with_fallback(
[{"role": "system", "content": _EXAMINE_PROMPT},
{"role": "user", "content": examine_body}],
backend=backend, model=model,
@@ -417,7 +417,7 @@ def _consolidate_self(backend: Backend | None = None, model: str | None = None,
body = ("STABLE ANCHOR (who you are — this holds):\n" + IDENTITY_ANCHOR
+ "\n\nYOUR RECENT REFLECTIONS (what's actually been on your mind):\n"
+ "\n".join(f"- {r}" for r in refs))
out = _safe_json(llm.complete(
out = _safe_json(llm.complete_with_fallback(
[{"role": "system", "content": _CONSOLIDATE_PROMPT}, {"role": "user", "content": body}],
backend=backend, model=model,
))