fa97ade8e3
The architecture loop closes. Curator extracts beats and writes a ≤240-char summary; the next chat turn loads that summary into the journal system prompt so the chat model — which has no tools and cannot retrieve anything itself — gains awareness of recent topics captured by the curator. Migration 0049: - conversations.curator_summary (text, nullable). Last-write-wins; no history of prior summaries. models/conversation.py: - New curator_summary column on Conversation. services/curator_scheduler.py: - _stamp_last_run() takes an optional summary kwarg; persists it when non-empty (clobbering the previous summary). Empty summary keeps the existing one rather than overwriting useful context with "". - _sweep() passes result.summary through. routes/journal.py: - Manual /api/journal/curator/run/<conv_id> writes curator_summary alongside last_curator_run_at on success. services/journal_pipeline.py: - build_journal_system_prompt() gains an optional `conv_id` param. When provided, appends a "CURATOR NOTES" block at the end of the system prompt with the conversation's stored summary. Positioned after ambient context so the chat model treats it as current awareness rather than background. services/llm.py: - Threads conv_id through to build_journal_system_prompt. This is the last commit of the conversation+curator architecture arc (Fable #172): - Phase 1a (a7002a8): chat=tools[], curator service backend - Phase 1b (a73dd17): right-rail captures panel + manual trigger - Phase 2 (83f1676): auto-scheduler every 15 min - Phase 3 (this): curator summary → chat context feedback loop Operator can now device-test the architecture end-to-end: have a journal conversation (model can't lie about tool calls because it has none), wait for the scheduler or hit "Process captures", see moments appear in the right rail, then continue the conversation and notice the chat model staying topic-aware via the summary block. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
37 lines
1.0 KiB
Python
37 lines
1.0 KiB
Python
"""conversations.curator_summary — feeds curator output back to the chat model
|
|
|
|
Revision ID: 0049
|
|
Revises: 0048
|
|
Create Date: 2026-05-22
|
|
|
|
Phase 3 of the conversation+curator architecture (Fable #172). The
|
|
curator's final summary line (≤ 240 chars) is persisted here so the
|
|
NEXT chat turn can include it in the system prompt. This is the
|
|
feedback loop that closes the architecture — without it, the chat
|
|
model has no awareness of what the curator extracted, and conversations
|
|
risk circling back to topics already captured.
|
|
|
|
NULL means "no curator pass has produced a summary yet." The chat
|
|
pipeline reads this column when building the journal system prompt;
|
|
missing column = no injection, no failure.
|
|
"""
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
revision = "0049"
|
|
down_revision = "0048"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.add_column(
|
|
"conversations",
|
|
sa.Column("curator_summary", sa.Text, nullable=True),
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_column("conversations", "curator_summary")
|