import { defineStore } from 'pinia' import { computed, ref } from 'vue' export type AiRole = 'user' | 'assistant' | 'system' export interface AiMessage { id: string role: AiRole content: string /** 是否仍在流式生成中,用于 UI 展示打字光标 */ pending?: boolean /** 标记本条消息是否出错,UI 显示重试按钮 */ error?: boolean /** 仅 assistant 消息使用:本轮回答结束后由大模型给出的追问建议 */ recommendQuestions?: string[] createdAt: number } export const useAiStore = defineStore( 'ai', () => { const messages = ref([]) /** 一组对话共用同一个 thread,跨多轮维持上下文 */ const threadId = ref('') const messageCount = computed(() => messages.value.length) function ensureThreadId() { if (!threadId.value) { threadId.value = `thread_id_${Date.now()}${Math.floor(Math.random() * 10000)}` } return threadId.value } function addMessage(message: AiMessage) { messages.value.push(message) } function updateMessage(id: string, patch: Partial) { const target = messages.value.find(m => m.id === id) if (!target) { return } Object.assign(target, patch) } function appendDelta(id: string, delta: string) { const target = messages.value.find(m => m.id === id) if (!target) { return } target.content += delta } function removeMessage(id: string) { messages.value = messages.value.filter(m => m.id !== id) } function clear() { messages.value = [] threadId.value = '' } return { messages, threadId, messageCount, ensureThreadId, addMessage, updateMessage, appendDelta, removeMessage, clear, } }, { persist: true, }, )