feat: per-POV summary and edge summary update on scene close

This commit is contained in:
Joseph Doherty
2026-04-26 13:53:12 -04:00
parent 0997562e75
commit b5175aefaa
6 changed files with 601 additions and 12 deletions
+22 -5
View File
@@ -32,11 +32,13 @@ from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from chat.eventlog.log import append_and_apply
from chat.services.scene_summarize import apply_scene_close_summary
from chat.state.edges import get_edge
from chat.state.entities import get_bot, get_you
from chat.state.memory import get_pinned
from chat.state.world import active_scene, get_activity, get_chat, get_container
from chat.web.bots import get_conn
from chat.web.kickoff import get_llm_client
TEMPLATES = Jinja2Templates(
directory=str(Path(__file__).resolve().parent.parent / "templates")
@@ -143,13 +145,17 @@ async def close_scene_manual(
chat_id: str,
request: Request,
conn=Depends(get_conn),
client=Depends(get_llm_client),
):
"""Manual scene close from the drawer button.
Always available when there's an active scene; mirrors the auto-close
path in the turn flow but bypasses the classifier. Returns the refreshed
drawer partial so HTMX swaps it in. ``400`` when no scene is active —
the button is hidden in that state but a stale tab might still POST.
path in the turn flow but bypasses the hard-signal classifier. After
emitting ``scene_closed`` we run the T27 per-POV summary pipeline
(one classifier call) so the manual path produces the same memory /
edge updates as the auto path. Returns the refreshed drawer partial
so HTMX swaps it in. ``400`` when no scene is active — the button is
hidden in that state but a stale tab might still POST.
"""
chat = get_chat(conn, chat_id)
if chat is None:
@@ -167,11 +173,22 @@ async def close_scene_manual(
payload={
"scene_id": scene["id"],
"ended_at": chat.get("time"),
# T27 will set this from the per-POV summary pass; for T26 we
# default to 0 so the projector update has a value to write.
# Significance defaults to 0; T22's significance worker
# operates on memories, not scenes.
"significance": 0,
},
)
settings = request.app.state.settings
await apply_scene_close_summary(
conn,
client,
classifier_model=settings.classifier_model,
chat_id=chat_id,
scene_id=scene["id"],
host_bot_id=chat["host_bot_id"],
timeout_s=settings.classifier_timeout_s,
)
return await drawer(chat_id, request, conn)