Improve model status indicators and tune timeouts

Green/red emoji circles replace Unicode symbols for at-a-glance model
readiness. Increase connect timeouts (10→30s) for cold model loading,
warm timeout (120→300s) for large models, and pull timeout (600→1800s)
to match route-level limit. Show error toast on SSE reconnection failure
instead of silently recovering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 23:01:59 -05:00
parent 953eaf2feb
commit f089b16080
5 changed files with 13 additions and 7 deletions
+1 -1
View File
@@ -49,7 +49,7 @@ onMounted(async () => {
:key="m.name"
:value="m.name"
>
{{ isHot(m.name) ? "\u2B24 " : "\u25CB " }}{{ m.name }}
{{ isHot(m.name) ? "🟢 " : "🔴 " }}{{ m.name }}
</option>
</select>
</template>
+4
View File
@@ -239,6 +239,10 @@ export const useChatStore = defineStore("chat", () => {
// Recovery fallback: re-fetch conversation from DB
if (!gotDone && currentConversation.value?.id === convId) {
useToastStore().show(
"Connection lost — response may be incomplete",
"error",
);
try {
await fetchConversation(convId);
} catch {
+1 -1
View File
@@ -269,7 +269,7 @@ async def warm_model_route():
async def _warm():
try:
async with httpx.AsyncClient(timeout=120.0) as client:
async with httpx.AsyncClient(timeout=300.0) as client:
await client.post(
f"{Config.OLLAMA_URL}/api/generate",
json={"model": model, "prompt": "", "keep_alive": "30m"},
+3 -3
View File
@@ -54,7 +54,7 @@ async def ensure_model(model: str) -> None:
logger.info("Pulling model '%s' from Ollama...", model)
try:
async with httpx.AsyncClient(timeout=600.0) as client:
async with httpx.AsyncClient(timeout=1800.0) as client:
async with client.stream(
"POST",
f"{Config.OLLAMA_URL}/api/pull",
@@ -80,7 +80,7 @@ async def stream_chat(
payload: dict = {"model": model, "messages": messages, "stream": True}
if options:
payload["options"] = options
async with httpx.AsyncClient(timeout=httpx.Timeout(1800.0, connect=10.0, read=300.0)) as client:
async with httpx.AsyncClient(timeout=httpx.Timeout(1800.0, connect=30.0, read=300.0)) as client:
async with client.stream(
"POST",
f"{Config.OLLAMA_URL}/api/chat",
@@ -100,7 +100,7 @@ async def stream_chat(
async def generate_completion(messages: list[dict], model: str) -> str:
"""Non-streaming chat completion, returns full response text."""
async with httpx.AsyncClient(timeout=httpx.Timeout(1800.0, connect=10.0, read=300.0)) as client:
async with httpx.AsyncClient(timeout=httpx.Timeout(1800.0, connect=30.0, read=300.0)) as client:
resp = await client.post(
f"{Config.OLLAMA_URL}/api/chat",
json={"model": model, "messages": messages, "stream": False},
+4 -2
View File
@@ -12,7 +12,7 @@
> Include file-level details in the commit body when the change is non-trivial.
## Last Updated
2026-02-14 — Phase 6.0: Model selection, dashboard chat input, model warming
2026-02-14 — Phase 6.1: Model status colors, timeout tuning, SSE error feedback
## Project Overview
Fabled Assistant is a self-hosted note-taking and task-tracking application with
@@ -527,8 +527,10 @@ When adding a new migration, follow these conventions:
- Per-conversation model selection via ModelSelector dropdown in chat header (persisted via PATCH)
- Dashboard inline chat input: model selector + note picker + textarea; creates conversation and navigates
- Model warming: default model pre-loaded into Ollama on dashboard mount via fire-and-forget POST
- Hot/cold model indicators: `/api/chat/ps` proxies Ollama `/api/ps`; ModelSelector shows filled/empty circles
- Hot/cold model indicators: `/api/chat/ps` proxies Ollama `/api/ps`; ModelSelector shows green/red emoji circles
- Ollama configured with `OLLAMA_MAX_LOADED_MODELS=2` and `OLLAMA_KEEP_ALIVE=30m`
- Timeout tuning: connect timeout 30s (cold model loading), warm timeout 300s, pull timeout 1800s
- SSE reconnection failure shows error toast instead of silently recovering
### Authentication & User Management
- Session cookie auth with bcrypt, first-user-is-admin, orphaned data claiming