refactor(models): route tasks to chat vs worker per new architecture

Chat and background model roles effectively swapped during the
conversation+curator pivot, but call sites still used OLD routing.
This commit re-routes each call to the model whose new role fits.

Moved to background_model (worker — heavy, deliberate):
- services/journal_prep.py: daily prep generation.
- services/user_profile.py: observation consolidation.

Moved to default_model (chat — small, fast):
- services/chat.py save_response_as_note: note title generation.
- services/tag_suggestions.py: tag suggestions.

Already routed correctly (unchanged): curator, closeout, consolidation,
project summaries, history summarization.

SettingsView.vue: help text rewritten for both model fields to
describe new roles. Background Model UI label renamed to Worker
Model so the heavier role is visible from the picker. Warning copy
updated to recommend OLLAMA_MAX_LOADED_MODELS=2+ so chat and worker
can stay loaded simultaneously.

Schema names default_model and background_model unchanged on purpose
(renaming requires migration + touches ~50 call sites for UX-only gain).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-23 11:00:47 -04:00
parent 48b99b62be
commit 85b212fbf2
5 changed files with 46 additions and 11 deletions
+9 -2
View File
@@ -243,8 +243,15 @@ async def save_response_as_note(user_id: int, message_id: int) -> dict:
},
{"role": "user", "content": msg.content[:2000]},
]
bg_model = await get_setting(user_id, "background_model", Config.OLLAMA_BACKGROUND_MODEL)
title = await generate_completion(prompt_messages, bg_model)
# 3-8 word title generation is the kind of trivial small-input
# / small-output task the chat model (default_model) handles in
# ~1s. Routing here so the worker (background_model) isn't
# interrupted from heavier curator / prep / closeout passes.
chat_model = (
await get_setting(user_id, "default_model", "")
or Config.OLLAMA_MODEL
)
title = await generate_completion(prompt_messages, chat_model)
title = title.strip().strip('"\'').strip()[:100]
except Exception:
logger.warning("Failed to generate note title, using fallback", exc_info=True)
+10 -1
View File
@@ -446,7 +446,16 @@ async def _generate_prep_prose(
"""Ask the LLM for a direct conversational journal opener built from the sections."""
from fabledassistant.services.llm import generate_completion
model = (await get_setting(user_id, "default_model", "")) or Config.OLLAMA_MODEL
# Daily prep is a deliberate, multi-section generation — runs once a day,
# latency-tolerant, benefits from a smarter model. Route to the worker
# (background_model) rather than the chat model. The chat model in the
# conversation+curator architecture is small/fast/no-tools; prep needs
# the heavier reasoning the worker provides.
model = (
await get_setting(user_id, "background_model", "")
or Config.OLLAMA_BACKGROUND_MODEL
or Config.OLLAMA_MODEL
)
if not model:
logger.warning("No LLM model configured for daily prep — using fallback text")
return _fallback_prep_text(day_date)
@@ -22,7 +22,14 @@ async def suggest_tags(user_id: int, title: str, body: str, current_tags: list[s
return []
existing_tags = await get_all_tags(user_id)
model = await get_setting(user_id, "background_model", Config.OLLAMA_BACKGROUND_MODEL)
# Tag suggestion is a tiny single-shot task (3-5 tags from a note's
# title + body) — route to the chat model (small/fast) rather than
# tying up the worker on a trivial call. The chat model handles this
# in well under a second.
model = (
await get_setting(user_id, "default_model", "")
or Config.OLLAMA_MODEL
)
existing_list = ", ".join(f"#{t}" for t in existing_tags) if existing_tags else "(none yet)"
+9 -1
View File
@@ -144,7 +144,15 @@ async def _consolidate_observations(user_id: int) -> str:
user_prompt += f"Existing summary:\n{existing_summary}\n\n"
user_prompt += f"New observations:\n{obs_text}"
model = await get_setting(user_id, "default_model", Config.OLLAMA_MODEL)
# Profile observation consolidation reasons over multiple documents to
# produce a coherent summary — closer to curator-shaped work than chat.
# Route to worker (background_model). Falls back to OLLAMA_MODEL only if
# neither setting nor BACKGROUND default is available.
model = (
await get_setting(user_id, "background_model", "")
or Config.OLLAMA_BACKGROUND_MODEL
or Config.OLLAMA_MODEL
)
try:
new_summary = (await generate_completion(
[