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>
This commit is contained in:
@@ -74,6 +74,27 @@ class GenerationBuffer:
|
||||
|
||||
# Module-level singleton registry
|
||||
_buffers: dict[int | str, GenerationBuffer] = {}
|
||||
|
||||
# Per-conversation note context cache — maps conv_id → sorted list of note IDs.
|
||||
# Stores the note IDs that were last included in the system prompt so that
|
||||
# subsequent turns in the same conversation can reuse them, stabilizing the
|
||||
# system prompt prefix and improving Ollama's KV cache hit rate.
|
||||
_conv_note_cache: dict[int, list[int]] = {}
|
||||
|
||||
|
||||
def get_conv_note_cache(conv_id: int) -> list[int]:
|
||||
"""Return cached note IDs for a conversation (empty list if none)."""
|
||||
return list(_conv_note_cache.get(conv_id, []))
|
||||
|
||||
|
||||
def set_conv_note_cache(conv_id: int, note_ids: list[int]) -> None:
|
||||
"""Store note IDs to reuse on the next turn of this conversation."""
|
||||
_conv_note_cache[conv_id] = list(note_ids)
|
||||
|
||||
|
||||
def clear_conv_note_cache(conv_id: int) -> None:
|
||||
"""Invalidate the note cache for a conversation (e.g. after a note write)."""
|
||||
_conv_note_cache.pop(conv_id, None)
|
||||
_cleanup_task: asyncio.Task | None = None
|
||||
_GRACE_PERIOD = 60.0 # seconds to keep completed buffers
|
||||
|
||||
|
||||
Reference in New Issue
Block a user