v0.17.2: auto-fact detection with conflict-alert flow
- auto_detect_facts() scans chat turns for factual content (IPs, paths, services, config changes, hardware refs) using pattern matching - check_fact_conflicts() cross-references detected facts against stored FTS5 memories — when a contradiction exists (same topic, diff value) the system surfaces a rag_update_suggestion in the done SSE payload - Frontend shows a floating notification banner comparing old vs new fact with Update/Dismiss buttons - confirm_fact_update() replaces the memory + re-embeds/re-indexes the Qdraft entry on user confirmation - Silent auto-ingest (memories + Qdrant) when no conflict exists - Frontend: msg-toolbar opacity 0→0.35 for visibility
This commit is contained in:
+22
-4
@@ -1,4 +1,5 @@
|
||||
"""JarvisChat routers - /api/chat streaming endpoint."""
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import uuid
|
||||
@@ -10,8 +11,8 @@ from fastapi.responses import StreamingResponse
|
||||
|
||||
from config import DEFAULT_MODEL, LLAMA_SERVER_BASE
|
||||
from db import get_db, get_upload_context
|
||||
from memory import process_remember_command
|
||||
from rag import build_system_prompt
|
||||
from memory import process_remember_command, auto_detect_facts, check_fact_conflicts
|
||||
from rag import build_system_prompt, ingest_auto_fact
|
||||
from search import (calculate_perplexity, is_uncertain, is_refusal,
|
||||
clean_hedging, format_search_results, format_direct_answer,
|
||||
extract_search_query, query_searxng)
|
||||
@@ -127,6 +128,7 @@ async def chat(request: Request):
|
||||
tokens_per_sec = 0.0
|
||||
completion_tokens = 0
|
||||
prompt_tokens = 0
|
||||
rag_update = None
|
||||
|
||||
if remember_response:
|
||||
yield f"data: {json.dumps({'token': remember_response + chr(10) + chr(10), 'conversation_id': conv_id})}\n\n"
|
||||
@@ -204,7 +206,15 @@ async def chat(request: Request):
|
||||
db2.commit()
|
||||
db2.close()
|
||||
|
||||
yield f"data: {json.dumps({'done': True, 'conversation_id': conv_id, 'searched': True, 'perplexity': round(perplexity, 2), 'tokens_per_sec': round(tokens_per_sec, 1), 'prompt_tokens': prompt_tokens, 'completion_tokens': completion_tokens, 'context_length': MODEL_CONTEXT_LENGTH})}\n\n"
|
||||
facts = auto_detect_facts(user_message, cleaned_response)
|
||||
if facts:
|
||||
conflicts = check_fact_conflicts(facts)
|
||||
if conflicts:
|
||||
rag_update = {"conflicts": conflicts}
|
||||
else:
|
||||
asyncio.ensure_future(ingest_auto_fact(facts, user_message, cleaned_response))
|
||||
|
||||
yield f"data: {json.dumps({'done': True, 'conversation_id': conv_id, 'searched': True, 'perplexity': round(perplexity, 2), 'tokens_per_sec': round(tokens_per_sec, 1), 'prompt_tokens': prompt_tokens, 'completion_tokens': completion_tokens, 'context_length': MODEL_CONTEXT_LENGTH, **(rag_update and {'rag_update_suggestion': rag_update} or {})})}\n\n"
|
||||
return
|
||||
|
||||
saved_msg = assistant_msg
|
||||
@@ -217,7 +227,15 @@ async def chat(request: Request):
|
||||
db2.commit()
|
||||
db2.close()
|
||||
|
||||
yield f"data: {json.dumps({'done': True, 'conversation_id': conv_id, 'perplexity': round(perplexity, 2), 'tokens_per_sec': round(tokens_per_sec, 1), 'prompt_tokens': prompt_tokens, 'completion_tokens': completion_tokens, 'context_length': MODEL_CONTEXT_LENGTH})}\n\n"
|
||||
facts = auto_detect_facts(user_message, assistant_msg)
|
||||
if facts:
|
||||
conflicts = check_fact_conflicts(facts)
|
||||
if conflicts:
|
||||
rag_update = {"conflicts": conflicts}
|
||||
else:
|
||||
asyncio.ensure_future(ingest_auto_fact(facts, user_message, assistant_msg))
|
||||
|
||||
yield f"data: {json.dumps({'done': True, 'conversation_id': conv_id, 'perplexity': round(perplexity, 2), 'tokens_per_sec': round(tokens_per_sec, 1), 'prompt_tokens': prompt_tokens, 'completion_tokens': completion_tokens, 'context_length': MODEL_CONTEXT_LENGTH, **(rag_update and {'rag_update_suggestion': rag_update} or {})})}\n\n"
|
||||
|
||||
except httpx.RemoteProtocolError:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user