Add shared notes with tabbed pages editable by user and AI
Adds a note_pages table backing a tabbed notes panel where the user and the model can both read and write. Only page titles (plus a short preview) are injected into the system prompt on every turn; full page content is kept out of context and fetched on demand via a read_note tool, with write_note letting the model append to, replace, or create a page. Generalizes llm.resolve_web_search into resolve_tool_calls so the tool-calling loop handles web_search and the new note tools through one path. The chat stream emits a notes_updated SSE event when the model edits a note so the frontend panel can refresh; local edits are tracked as dirty and never clobbered by that refresh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ from app.core.memory_kb import memory as mem
|
||||
from app.core import llm
|
||||
from app.core.memory_kb import knowledge
|
||||
from app.core.memory_kb import local_knowledge
|
||||
from app.core.notes import NOTE_TOOLS
|
||||
from app.core.search.websearch import WEB_SEARCH_TOOL
|
||||
from app.core.config import DEFAULT_MODEL
|
||||
from app.core.memory_kb.tagging import tag_message_by_id
|
||||
@@ -210,9 +211,12 @@ async def stream_chat(req: ChatRequest, db: DBSession = Depends(get_db)):
|
||||
used_model = req.model or session.model
|
||||
full_response = []
|
||||
try:
|
||||
resolved_context, searches = await llm.resolve_web_search(
|
||||
context, model=used_model, session_id=session.id,
|
||||
resolved_context, searches, notes_changed = await llm.resolve_tool_calls(
|
||||
context, model=used_model, session_id=session.id, db=db,
|
||||
)
|
||||
if notes_changed:
|
||||
# AIがノートを書き換えたので、フロントのノートパネルを再読み込みさせる
|
||||
yield sse({"type": "notes_updated"})
|
||||
if searches:
|
||||
sources = [
|
||||
{"title": r["title"], "url": r["url"]}
|
||||
@@ -225,9 +229,10 @@ async def stream_chat(req: ChatRequest, db: DBSession = Depends(get_db)):
|
||||
knowledge.save_knowledge(db, s["query"], summary, s["results"])
|
||||
local_knowledge.save_search_result(s["query"], summary, s["results"])
|
||||
|
||||
search_tools = [WEB_SEARCH_TOOL] if len(resolved_context) > len(context) else None
|
||||
# 履歴にtool_callsが含まれる場合、最終呼び出しにも同じツール定義を渡す必要がある
|
||||
used_tools = [WEB_SEARCH_TOOL, *NOTE_TOOLS] if len(resolved_context) > len(context) else None
|
||||
async for chunk in llm.stream_chat(
|
||||
resolved_context, model=used_model, session_id=session.id, tools=search_tools,
|
||||
resolved_context, model=used_model, session_id=session.id, tools=used_tools,
|
||||
):
|
||||
full_response.append(chunk)
|
||||
yield sse({"type": "chunk", "value": chunk})
|
||||
|
||||
Reference in New Issue
Block a user