Files
FabledScribe/alembic/versions/0038_add_rss_item_full_content.py
T
bvandeusen 8205590f8d feat(briefing): cache + map-reduce article context for rich discuss chats
The Discuss button on news cards was producing one-shot replies because
the model got the whole trafilatura blob dropped into history with a
canned "summarize and discuss this article" prompt — no length guard, no
prep, no invitation to converse. Large articles got silently truncated by
Ollama; small articles got a tepid reply.

This reworks discuss_article around a three-layer cache:

  context_prepared  →  content_full  →  fresh trafilatura fetch

First click on a small article fetches once, writes through to both
caches, and passes the body straight into the synthetic read_article
tool-result. First click on a large article additionally runs a parallel
map step (services/article_context.py) that chunks the body on paragraph
boundaries, summarizes each ~8k chunk to ~300 words of dense factual
prose via the background model, and concatenates the summaries under
section headers — all pinned to num_ctx=16384 so the map step doesn't
itself fall victim to silent truncation. Repeat clicks on either path
skip straight to the chat turn.

The canned summary prompt is replaced with a conversational seed that
invites the user into an actual discussion rather than a one-shot
synopsis, matching the goal of "have a conversation about an article,
not just read it."

discuss_topic is intentionally left untouched — it's the multi-article
aggregation path and needs a separate rework. Follow-up task will decide
whether to retire it or rework it on the cached-context approach.

Closes task #106.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 20:52:00 -04:00

35 lines
819 B
Python

"""Add content_full and context_prepared caches to rss_items.
Revision ID: 0038
Revises: 0037
Create Date: 2026-04-13
"""
from __future__ import annotations
import sqlalchemy as sa
from alembic import op
revision = "0038"
down_revision = "0037"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column("rss_items", sa.Column("content_full", sa.Text(), nullable=True))
op.add_column(
"rss_items",
sa.Column("context_prepared", sa.Text(), nullable=True),
)
op.add_column(
"rss_items",
sa.Column("content_fetched_at", sa.DateTime(timezone=True), nullable=True),
)
def downgrade() -> None:
op.drop_column("rss_items", "content_fetched_at")
op.drop_column("rss_items", "context_prepared")
op.drop_column("rss_items", "content_full")