Commit Graph

6 Commits

Author SHA1 Message Date
bvandeusen b11a92f32d Fix writing assist: disable thinking mode, drop stuck-buffer 409
- stream_chat: add think=False parameter passed through to Ollama payload.
  qwen3 models have thinking enabled by default; without this flag the model
  spends minutes generating internal thinking tokens that stream_chat silently
  discards, leaving the frontend spinner blank until the SSE connection times
  out and the widget disappears.

- create_assist_buffer: orphan (overwrite) a still-running buffer instead of
  raising. The old asyncio task holds a direct reference and completes
  harmlessly against the stale buffer. New requests always win.

- assist_route: remove the 409 guard that blocked new requests when a previous
  generation got stuck. create_assist_buffer now handles this transparently.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 13:28:59 -05:00
bvandeusen e119331645 Phase 21: Intent-first pipeline, visible ack, KV-stable system prompt
Pipeline changes (generation_task.py, intent.py):
- Remove optimistic streaming queue/race (_drain_queue deleted)
- Remove _generate_acknowledgment — ack now embedded in intent JSON
- Round 0: await intent (~400ms), stream ack immediately as TTFT,
  then execute tool sequentially; chat-only streams directly
- IntentResult.ack: one-sentence acknowledgment, intent max_tokens 200→350
- _parse_intent extracts and trims ack field

KV cache stability (llm.py, generation_buffer.py, generation_task.py):
- build_context: replace cached_note_ids with include_note_ids
- Auto-found notes populate context_meta["auto_notes"] for sidebar but
  are NOT injected into system prompt (--- Related Notes --- removed)
- Explicitly included notes injected as --- Included Notes ---
- _conv_note_cache dict + get/set/clear functions removed from generation_buffer.py
- All clear_conv_note_cache() calls removed

Cold model retry (llm.py):
- generate_completion (used by classify_intent) retries on HTTP 500:
  3 attempts with 3s/6s delays — prevents intent failure during cold load

API + frontend (routes/chat.py, stores/chat.ts, views/ChatView.vue, components/ChatPanel.vue):
- exclude_note_ids → include_note_ids throughout
- ChatView sidebar: Suggested (auto-found, + to include) + In Context (× to remove)
- ChatPanel: remove exclude button from context pills; no IDs passed to sendMessage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 22:34:54 -05:00
bvandeusen d6f4a6dbb6 Add semantic note search (nomic-embed-text) and per-conversation note cache
- New NoteEmbedding model + migration 0014 stores float embeddings (JSONB)
- services/embeddings.py: get_embedding, upsert_note_embedding,
  semantic_search_notes (cosine similarity), backfill_note_embeddings
- build_context() now tries semantic search first, falls back to keyword search;
  accepts cached_note_ids to reuse last-turn notes and stabilise the system
  prompt prefix for Ollama's KV cache
- generation_buffer.py: per-conversation note ID cache (get/set/clear)
- generation_task.py: passes cached IDs into build_context, updates cache
  after each turn, and invalidates it after create_note/update_note/create_task
- app.py: pulls nomic-embed-text at startup and launches a background backfill
  to embed all existing notes (30 s delay so Ollama has time to load the model)
- routes/notes.py + services/tools.py: fire-and-forget embedding update on
  every note create or update via the API or LLM tool calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 21:44:58 -05:00
bvandeusen 815eed2574 Add tool confirmation UI with Accept/Decline for write operations
Before executing any write tool (create/update/delete), the backend now
pauses with an asyncio.Future and emits a tool_pending SSE event. The
frontend displays a ToolConfirmCard with Accept and Decline buttons.
Clicking Accept resolves the Future and proceeds; Decline records a
declined tool_call chip and falls through to regular streaming. Typing
single-word yes/no responses (e.g. "yes", "cancel") also works as
confirmation. 120s timeout auto-declines if no response.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 20:43:47 -05:00
bvandeusen a89d25f5d6 Refactor AI Assist to background-task + buffer architecture
The assist flow previously tied the entire LLM generation to a single
POST request with no keepalives, causing NS_ERROR_NET_PARTIAL_TRANSFER
in Firefox when Hypercorn closed the connection during gaps between
chunks. This refactor decouples generation into a background task with
a buffer and a separate SSE stream — the same pattern used by chat.

- generation_buffer.py: Widen _buffers to support string keys, add
  create/get/remove_assist_buffer() using "assist:{user_id}" keys,
  fix cleanup log format for string keys
- generation_task.py: Add run_assist_generation() — lightweight
  background task with no DB persistence or title generation
- notes.py: Replace single POST SSE route with POST /api/notes/assist
  (returns 202) + GET /api/notes/assist/stream (SSE with 15s keepalives
  and Last-Event-ID reconnection); 409 if already running
- useAssist.ts: Switch from apiStreamPost to apiPost + apiSSEStream
  two-step pattern with named event mapping and stream handle cleanup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 00:27:21 -05:00
bvandeusen cbfdf5289e Add multi-user auth, background generation, and chat UX improvements
Phase 5: Multi-user authentication with session cookies, bcrypt passwords,
first-user-is-admin pattern, per-user data isolation, backup/restore,
Docker Swarm production stack with secrets and network isolation.

Phase 5.1: Chat UX improvements:
- Background generation architecture (GenerationBuffer + asyncio task)
  with SSE fan-out, reconnect support, and periodic DB flushes
- LLM-generated conversation titles (first exchange + every 10th message)
- Stop generation button with cancel_event and partial content preservation
- Relative timestamps in sidebar (5m ago, 3h ago, then dates)
- Empty chat auto-cleanup on navigation away
- Save-as-note uses LLM for title generation, tags notes with "chat"
- Summarize-as-note also tags with "chat"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:36:30 -05:00