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:
2026-08-19 01:27:31 +09:00
co-authored by Claude Opus 5
parent ef588d99d8
commit a08b1785a4
16 changed files with 760 additions and 26 deletions
+8 -1
View File
@@ -6,6 +6,7 @@ import MessageInput from './components/MessageInput.vue'
import ModelSelector from './components/ModelSelector.vue'
import LogViewer from './components/LogViewer.vue'
import SettingsPanel from './components/SettingsPanel.vue'
import NotePanel from './components/NotePanel.vue'
import ToastList from './components/ToastList.vue'
import MemoryMonitor from './components/MemoryMonitor.vue'
import Clock from './components/Clock.vue'
@@ -15,7 +16,7 @@ import { useAuthStore } from './stores/auth'
const authStore = useAuthStore()
type SidePanel = 'none' | 'logs' | 'settings'
type SidePanel = 'none' | 'logs' | 'settings' | 'notes'
const activePanel = ref<SidePanel>('none')
function togglePanel(panel: SidePanel) {
@@ -50,6 +51,9 @@ onUnmounted(() => {
<span class="title">PlayChat</span>
<ModelSelector />
<Clock />
<button class="log-toggle" :class="{ active: activePanel === 'notes' }" @click="togglePanel('notes')">
ノート
</button>
<button class="log-toggle" :class="{ active: activePanel === 'settings' }" @click="togglePanel('settings')">
設定
</button>
@@ -71,6 +75,9 @@ onUnmounted(() => {
<div v-else-if="activePanel === 'settings'" class="log-pane">
<SettingsPanel />
</div>
<div v-else-if="activePanel === 'notes'" class="log-pane">
<NotePanel />
</div>
</div>
</div>
</div>