From 7e45689b9f07b8c3a594fe8caef31f4f6a8a631d Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Sat, 8 Aug 2026 20:19:03 +0800 Subject: [PATCH] feat: upgrade AI SDK and improve chat session handling with new store implementation --- .codegraph/daemon.pid | 4 +- app/composables/useAgentChat.ts | 3 + app/composables/useAgentChatStore.ts | 173 +++++++++++++++++++++++++++++++++++ app/pages/index.vue | 24 +++-- packages/drizzle-pkg/db.sqlite | Bin 1634304 -> 1634304 bytes server/api/agent/chat/index.post.ts | 2 +- server/api/llm/chat/index.post.ts | 2 +- server/service/agent/temp-token.ts | 2 +- server/service/auth/cookie.ts | 2 +- 9 files changed, 197 insertions(+), 15 deletions(-) create mode 100644 app/composables/useAgentChatStore.ts diff --git a/.codegraph/daemon.pid b/.codegraph/daemon.pid index 2149e9e..f81707b 100644 --- a/.codegraph/daemon.pid +++ b/.codegraph/daemon.pid @@ -1,6 +1,6 @@ { - "pid": 6400, + "pid": 18358, "version": "0.9.7", "socketPath": "/home/dash/code/nuxt-app/.codegraph/daemon.sock", - "startedAt": 1786156990118 + "startedAt": 1786169176794 } diff --git a/app/composables/useAgentChat.ts b/app/composables/useAgentChat.ts index 07b3a0b..883af7f 100644 --- a/app/composables/useAgentChat.ts +++ b/app/composables/useAgentChat.ts @@ -110,6 +110,7 @@ export function useAgentChat(options: UseAgentChatOptions) { try { res = await fetch(`/api/agent/chat/stream?sessionId=${encodeURIComponent(sid)}`, { method: "GET", + credentials: "include", }); } catch { return; @@ -456,6 +457,7 @@ export function useAgentChat(options: UseAgentChatOptions) { headers: { "Content-Type": "application/json" }, body: JSON.stringify(buildRequestBody(trimmed, opts)), signal: abortController.signal, + credentials: "include", }); if (!auth.loggedIn.value) { @@ -578,6 +580,7 @@ export function useAgentChat(options: UseAgentChatOptions) { approvalReason: reason, }), signal: abortController.signal, + credentials: "include", }); if (!res.ok) { diff --git a/app/composables/useAgentChatStore.ts b/app/composables/useAgentChatStore.ts new file mode 100644 index 0000000..554e264 --- /dev/null +++ b/app/composables/useAgentChatStore.ts @@ -0,0 +1,173 @@ +import { ref, computed, type Ref, type ComputedRef } from "vue"; +import { useAgentChat, type AgentMessage, type UseAgentChatOptions } from "./useAgentChat"; +import { useAgentRateLimit } from "./useAgentRateLimit"; + +export interface AgentChatInstance { + messages: Ref; + isLoading: Ref; + hasPendingApproval: ComputedRef; + errorMessage: Ref; + isStopped: Ref; + rateLimit: ReturnType; + send: ReturnType["send"]; + stopGeneration: ReturnType["stopGeneration"]; + clear: ReturnType["clear"]; + loadMessages: ReturnType["loadMessages"]; + respondToApproval: ReturnType["respondToApproval"]; + sendFeedback: ReturnType["sendFeedback"]; +} + +export interface UseAgentChatStoreOptions { + modelId: () => number | null; + enableThinking: () => boolean; + enableTools: () => boolean; + onStreamComplete?: (sessionId: string) => void; +} + +export function useAgentChatStore(storeOptions: UseAgentChatStoreOptions) { + const instances = new Map(); + const currentSessionId = ref(null); + + const loadedSessionIds = ref>(new Set()); + + function createInstance(sid: string): AgentChatInstance { + const options: UseAgentChatOptions = { + sessionId: () => sid, + modelId: storeOptions.modelId, + enableThinking: storeOptions.enableThinking, + enableTools: storeOptions.enableTools, + onStreamComplete: () => { + storeOptions.onStreamComplete?.(sid); + }, + }; + const chat = useAgentChat(options); + return chat; + } + + function getInstance(sid: string): AgentChatInstance { + let inst = instances.get(sid); + if (!inst) { + inst = createInstance(sid); + instances.set(sid, inst); + } + return inst; + } + + function removeInstance(sid: string) { + const inst = instances.get(sid); + if (inst) { + inst.stopGeneration(); + inst.clear(); + instances.delete(sid); + } + loadedSessionIds.value.delete(sid); + } + + const currentInstance = computed(() => { + const sid = currentSessionId.value; + if (!sid) return null; + return getInstance(sid); + }); + + const messages = computed(() => currentInstance.value?.messages.value ?? []); + const isLoading = computed(() => currentInstance.value?.isLoading.value ?? false); + const hasPendingApproval = computed(() => currentInstance.value?.hasPendingApproval.value ?? false); + const errorMessage = computed(() => currentInstance.value?.errorMessage.value ?? ""); + const isStopped = computed(() => currentInstance.value?.isStopped.value ?? false); + const fallbackRateLimit = useAgentRateLimit(); + const rateLimit = computed(() => currentInstance.value?.rateLimit ?? fallbackRateLimit); + + const anyLoading = computed(() => { + for (const inst of instances.values()) { + if (inst.isLoading.value) return true; + } + return false; + }); + + function getLoadingSessionIds(): string[] { + const ids: string[] = []; + for (const [sid, inst] of instances) { + if (inst.isLoading.value) ids.push(sid); + } + return ids; + } + + async function loadMessages(sid: string) { + const inst = getInstance(sid); + loadedSessionIds.value.add(sid); + await inst.loadMessages(sid); + } + + async function send(content: string, opts?: { editMessageId?: string; regenerate?: boolean }) { + const sid = currentSessionId.value; + if (!sid) return; + const inst = getInstance(sid); + await inst.send(content, opts); + } + + async function respondToApproval(toolCallId: string, approved: boolean, reason?: string) { + const sid = currentSessionId.value; + if (!sid) return; + const inst = getInstance(sid); + await inst.respondToApproval(toolCallId, approved, reason); + } + + async function sendFeedback(messageId: string, feedback: "like" | "dislike") { + const sid = currentSessionId.value; + if (!sid) return; + const inst = getInstance(sid); + await inst.sendFeedback(messageId, feedback); + } + + function stopGeneration() { + const sid = currentSessionId.value; + if (!sid) return; + const inst = getInstance(sid); + inst.stopGeneration(); + } + + function stopAll() { + for (const inst of instances.values()) { + inst.stopGeneration(); + } + } + + function clear() { + const sid = currentSessionId.value; + if (!sid) return; + const inst = getInstance(sid); + inst.clear(); + } + + function setCurrentSessionId(sid: string | null) { + currentSessionId.value = sid; + } + + function isSessionLoaded(sid: string): boolean { + return loadedSessionIds.value.has(sid); + } + + return { + currentSessionId, + currentInstance, + messages, + isLoading, + hasPendingApproval, + errorMessage, + isStopped, + rateLimit, + anyLoading, + getLoadingSessionIds, + loadMessages, + send, + respondToApproval, + sendFeedback, + stopGeneration, + stopAll, + clear, + setCurrentSessionId, + isSessionLoaded, + removeInstance, + getInstance, + }; +} diff --git a/app/pages/index.vue b/app/pages/index.vue index 8b16f01..8ef7da1 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -1,6 +1,6 @@