langgraph-vue3-chatbot 0.1.21 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/components/ai-bot/lib/models.ts","../src/components/ai-bot/lib/thread.ts","../src/components/ai-bot/lib/portal-host.ts","../src/components/ai-bot/ChatHeader.vue","../src/components/ai-bot/lib/utils.ts","../src/components/ai-bot/ToolCall.vue","../src/components/ai-bot/ai-elements/conversation/Conversation.vue","../src/components/ai-bot/ai-elements/conversation/ConversationContent.vue","../src/components/ai-bot/ui/button/Button.vue","../src/components/ai-bot/ui/button/index.ts","../src/components/ai-bot/ai-elements/conversation/ConversationScrollButton.vue","../src/components/ai-bot/ai-elements/message/Message.vue","../src/components/ai-bot/ai-elements/message/MessageContent.vue","../src/components/ai-bot/ChatMessages.vue","../src/components/ai-bot/lib/prompt-input.ts","../src/components/ai-bot/ai-elements/attachments/context.ts","../src/components/ai-bot/ai-elements/attachments/utils.ts","../src/components/ai-bot/ai-elements/attachments/Attachment.vue","../src/components/ai-bot/ai-elements/attachments/AttachmentInfo.vue","../src/components/ai-bot/ai-elements/attachments/AttachmentPreview.vue","../src/components/ai-bot/ai-elements/attachments/AttachmentRemove.vue","../src/components/ai-bot/ai-elements/attachments/Attachments.vue","../src/components/ai-bot/InputAttachmentsDisplay.vue","../src/components/ai-bot/ai-elements/suggestion/Suggestion.vue","../src/components/ai-bot/ChatSuggestions.vue","../src/components/ai-bot/ui/input-group/InputGroup.vue","../src/components/ai-bot/ui/input-group/InputGroupAddon.vue","../src/components/ai-bot/ui/input-group/InputGroupButton.vue","../src/components/ai-bot/ui/textarea/Textarea.vue","../src/components/ai-bot/ui/input-group/InputGroupTextarea.vue","../src/components/ai-bot/ui/input-group/index.ts","../src/components/ai-bot/ui/dropdown-menu/DropdownMenu.vue","../src/components/ai-bot/ui/dropdown-menu/DropdownMenuContent.vue","../src/components/ai-bot/ui/dropdown-menu/DropdownMenuItem.vue","../src/components/ai-bot/ui/dropdown-menu/DropdownMenuTrigger.vue","../src/components/ai-bot/ChatInput.vue","../src/components/ai-bot/ai-elements/loader/LoaderIcon.vue","../src/components/ai-bot/ai-elements/loader/Loader.vue","../src/components/ai-bot/GeneratedFiles.vue","../src/components/ai-bot/ai-elements/shimmer/Shimmer.vue","../src/components/ai-bot/TodoList.vue","../src/components/ai-bot/ChatBot.vue","../src/components/ai-bot/FloatButton.vue","../src/components/ai-bot/AskAiBot.vue"],"sourcesContent":["// 模型信息 (API 返回格式)\nexport interface ModelInfo {\n name: string\n provider: string\n base_url: string\n is_default?: boolean\n}\n\n// 获取模型列表\nexport async function fetchModels(apiUrl: string): Promise<ModelInfo[]> {\n try {\n const response = await fetch(`${apiUrl}/webapp/models`)\n const result = await response.json()\n if (result.success && result.data) {\n return result.data\n }\n return []\n } catch (error) {\n console.error('Failed to fetch models:', error)\n return []\n }\n}\n\n// 获取默认模型\nexport function getDefaultModel(models: ModelInfo[]): ModelInfo | undefined {\n return models.find(m => m.is_default) || models[0]\n}\n\n// 根据模型名获取对应的提供商\nexport function getProviderByModelName(modelName: string): string {\n const name = modelName.toLowerCase()\n\n if (name.startsWith('qwen') || name.includes('阿里') || name.includes('通义')) {\n return 'alibaba'\n }\n if (name.startsWith('glm') || name.includes('智谱') || name.includes('zhipuai')) {\n return 'zhipuai'\n }\n if (name.startsWith('deepseek') || name.includes('deepseek')) {\n return 'deepseek'\n }\n if (name.startsWith('minimax') || name.includes('minimax')) {\n return 'minimax'\n }\n if (name.includes('kimi') || name.includes('月之')) {\n return 'moonshotai'\n }\n if (name.includes('claude') || name.includes('anthropic')) {\n return 'anthropic'\n }\n if (name.includes('gpt') || name.includes('openai')) {\n return 'openai'\n }\n if (name.includes('gemini') || name.includes('google')) {\n return 'google'\n }\n if (name.includes('mistral')) {\n return 'mistral'\n }\n if (name.includes('llama')) {\n return 'llama'\n }\n\n return 'openai'\n}\n","import { Client } from '@langchain/langgraph-sdk'\nimport type { ChatMessage, CustomContent } from '../lib/message-types'\n\n// 创建线程\nexport async function createThread(\n client: Client,\n threadId?: string,\n userId?: string\n): Promise<string> {\n try {\n const thread = await client.threads.create({\n ...(threadId ? { threadId, ifExists: 'do_nothing' } : {}),\n metadata: {\n user_id: userId || 'user001',\n }\n })\n return thread.thread_id || threadId || ''\n } catch (error) {\n console.error('Failed to create thread:', error)\n return threadId || ''\n }\n}\n\n// 获取对话历史\nexport async function loadThreadHistory(\n client: Client,\n threadId: string,\n onSuggestedQuestions?: (questions: string[]) => void,\n onTodos?: (todos: any[]) => void\n): Promise<ChatMessage[]> {\n if (!threadId) return []\n\n try {\n const state = await client.threads.getState(threadId)\n const values = state.values as any\n\n if (!values?.messages || !Array.isArray(values.messages)) {\n return []\n }\n\n const loadedMessages: ChatMessage[] = []\n const langgraphMessages = values.messages\n\n let i = 0\n while (i < langgraphMessages.length) {\n const msg = langgraphMessages[i]\n const msgType = msg.type\n const msgContent = msg.content as any\n\n // system 消息 暂时屏蔽system 消息的显示\n if (msgType === 'system' && 1 + 1 === 3) {\n const content = typeof msgContent === 'string' ? msgContent : Array.isArray(msgContent)\n ? msgContent.filter((b: any) => b.type === 'text').map((b: any) => b.text).join('')\n : ''\n if (content) {\n loadedMessages.push({\n key: msg.id || `system-${Date.now()}-${Math.random()}`,\n type: 'system',\n content\n })\n }\n i++\n continue\n }\n\n // 处理 human/user 消息\n if (msgType === 'human' || msgType === 'user') {\n const content = typeof msgContent === 'string' ? msgContent : Array.isArray(msgContent)\n ? msgContent.filter((b: any) => b.type === 'text').map((b: any) => b.text).join('')\n : ''\n loadedMessages.push({\n key: msg.id || `human-${Date.now()}-${Math.random()}`,\n type: 'human',\n content\n })\n i++\n continue\n }\n\n // 处理 ai 消息\n if (msgType === 'ai') {\n const content = typeof msgContent === 'string' ? msgContent : Array.isArray(msgContent)\n ? msgContent.filter((b: any) => b.type === 'text').map((b: any) => b.text).join('')\n : ''\n\n // 获取 tool_calls\n const toolCalls = msg.tool_calls?.map((tc: any) => ({\n id: tc.id,\n name: tc.name,\n args: JSON.stringify(tc.args, null, 2),\n state: 'completed' as const,\n result: ''\n })) || []\n\n // 先添加 AI 消息\n loadedMessages.push({\n key: msg.id || `ai-${Date.now()}-${Math.random()}`,\n type: 'ai',\n content,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined\n })\n\n // 检查是否有工具调用,从紧跟着的 tool 消息中获取结果\n if (toolCalls.length > 0) {\n let j = i + 1\n while (j < langgraphMessages.length) {\n const nextMsg = langgraphMessages[j]\n if (nextMsg.type === 'tool') {\n const toolMsgContent = typeof nextMsg.content === 'string' ? nextMsg.content : JSON.stringify(nextMsg.content)\n const toolCallId = nextMsg.tool_call_id\n const toolStatus = nextMsg.status\n\n // 根据 status 映射状态\n const mapStatus = (status: string): string => {\n switch (status) {\n case 'success': return 'completed'\n case 'error': return 'error'\n default: return 'completed'\n }\n }\n const toolState = mapStatus(toolStatus)\n\n // 找到对应的 tool_call 并填充结果\n const toolCall = toolCalls.find(tc => tc.id === toolCallId)\n if (toolCall) {\n toolCall.result = toolMsgContent\n toolCall.state = toolState\n\n // 创建独立的工具消息\n const toolMessageId = `tool-${toolCallId}-${Date.now()}`\n loadedMessages.push({\n key: toolMessageId,\n type: 'tool',\n content: toolMsgContent,\n toolCalls: [{\n id: toolCallId,\n name: toolCall.name,\n args: toolCall.args,\n result: toolMsgContent,\n state: toolState,\n error: toolStatus === 'error' ? toolMsgContent : undefined\n }]\n })\n }\n j++\n } else {\n break\n }\n }\n }\n i++\n continue\n }\n\n i++\n }\n\n // 处理 generated_files 自定义消息\n const generatedFiles = values.generated_files\n if (generatedFiles && Array.isArray(generatedFiles) && generatedFiles.length > 0) {\n const customContent: CustomContent = {\n type: 'generated_files',\n content: generatedFiles\n }\n loadedMessages.push({\n key: `custom-generated_files-${Date.now()}-${Math.random()}`,\n type: 'custom',\n content: '',\n customContent\n })\n }\n\n // 处理 suggested_questions 通过 callback 返回,不 push 到消息列表\n const suggestedQuestions = values.suggested_questions\n if (suggestedQuestions && Array.isArray(suggestedQuestions) && suggestedQuestions.length > 0) {\n if (onSuggestedQuestions) {\n onSuggestedQuestions(suggestedQuestions)\n }\n }\n\n const todos = values.todos\n if (onTodos && Array.isArray(todos) && todos.length > 0) {\n onTodos(todos)\n }\n\n return loadedMessages\n } catch (error) {\n console.error('Failed to load thread history:', error)\n return []\n }\n}\n","import type { InjectionKey, Ref } from 'vue'\nimport { computed, inject } from 'vue'\n\nexport interface PortalHostContextValue {\n portalHost: Ref<HTMLElement | null>\n}\n\nexport const PORTAL_HOST_KEY: InjectionKey<PortalHostContextValue> = Symbol('AiBotPortalHost')\n\nexport function usePortalHost(): PortalHostContextValue {\n const ctx = inject(PORTAL_HOST_KEY)\n if (!ctx) {\n return {\n portalHost: computed(() => null),\n }\n }\n return ctx\n}\n","<script setup lang=\"ts\">\nimport { Maximize2Icon, Minimize2Icon, XIcon } from 'lucide-vue-next'\n\ninterface Props {\n title: string\n isMaximized: boolean\n showHeaderActions?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showHeaderActions: true\n})\n\nconst emit = defineEmits<{\n close: []\n toggleMaximize: []\n}>()\n</script>\n\n<template>\n <div class=\"chat-header\">\n <div class=\"chat-title\">\n <span class=\"title-text\">{{ title }}</span>\n </div>\n <div v-if=\"props.showHeaderActions\" class=\"header-actions\">\n <button class=\"action-btn\" @click=\"emit('toggleMaximize')\" type=\"button\" :title=\"isMaximized ? '还原' : '最大化'\">\n <Minimize2Icon v-if=\"isMaximized\" class=\"size-4\" />\n <Maximize2Icon v-else class=\"size-4\" />\n </button>\n <button class=\"action-btn\" @click=\"emit('close')\" type=\"button\" title=\"关闭\">\n <XIcon class=\"size-4\" />\n </button>\n </div>\n </div>\n</template>\n\n<style scoped>\n.chat-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 16px;\n background: var(--ai-surface-subtle);\n color: var(--foreground);\n flex-shrink: 0;\n border-bottom: 1px solid var(--ai-border-subtle);\n}\n\n.chat-title {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.title-text {\n font-size: 14px;\n font-weight: 600;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.action-btn {\n appearance: none;\n background: transparent;\n border: none;\n border-radius: 6px;\n padding: 6px;\n cursor: pointer;\n color: var(--muted-foreground);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.15s ease;\n}\n\n.action-btn:hover {\n color: var(--foreground);\n background: var(--ai-chip-hover-bg);\n}\n</style>\n","import type { ClassValue } from \"clsx\"\nimport { clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","<script setup lang=\"ts\">\nimport type { ToolCall } from './lib/message-types'\nimport { ChevronDownIcon, PlayCircle, Loader, CheckCircle, XCircle, BrainIcon, GlobeIcon, FileTextIcon, FolderSearch, FileEditIcon, ListTodoIcon, EyeIcon, SquarePen, FileSearch, BookOpenCheck, FolderSearchIcon, ZapIcon, WrenchIcon } from 'lucide-vue-next'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { ref } from 'vue'\n\ndefineProps<{\n toolCalls: ToolCall[]\n}>()\n\nconst getStateIcon = (state: string) => {\n switch (state) {\n case 'start':\n return { icon: PlayCircle, color: 'text-blue-500' }\n case 'running':\n return { icon: Loader, color: 'text-yellow-500 animate-spin' }\n case 'completed':\n return { icon: CheckCircle, color: 'text-green-500' }\n case 'error':\n return { icon: XCircle, color: 'text-red-500' }\n default:\n return { icon: PlayCircle, color: 'text-muted-foreground' }\n }\n}\n\nconst toolNameMap: Record<string, string> = {\n think_tool: '战略反思',\n fetch_markdown: '获取网页',\n convert_to_markdown: '文件转换',\n ls: '列出目录',\n read_file: '读取文件',\n write_file: '写入文件',\n edit_file: '编辑文件',\n glob: '查找文件',\n grep: '搜索文本',\n execute: '执行命令',\n write_todos: '待办事项',\n task: '子任务',\n}\n\nconst toolIconMap: Record<string, any> = {\n think_tool: BrainIcon,\n fetch_markdown: GlobeIcon,\n convert_to_markdown: FileTextIcon,\n ls: FolderSearchIcon,\n read_file: EyeIcon,\n write_file: FileEditIcon,\n edit_file: SquarePen,\n glob: FolderSearch,\n grep: FileSearch,\n execute: ZapIcon,\n write_todos: ListTodoIcon,\n task: BookOpenCheck,\n}\n\nconst getToolName = (name: string) => {\n return toolNameMap[name] || name\n}\n\nconst getToolIcon = (name: string) => {\n return toolIconMap[name] || WrenchIcon\n}\n\nconst isTodoTool = (name: string) => {\n return name === 'write_todos' || name.includes('todo')\n}\n\n// 简化 args 展示,只取前100个字符\nconst formatArgs = (args: string) => {\n if (!args) return ''\n return args.length > 50 ? args.slice(0, 100) + '...' : args\n}\n\nconst openStates = ref<Record<string, boolean>>({})\n\nconst toggle = (id: string) => {\n openStates.value[id] = !openStates.value[id]\n}\n</script>\n\n<template>\n <div class=\"mb-3 text-xs max-w-full\">\n <div\n v-for=\"tool in toolCalls\"\n :key=\"tool.id\"\n v-show=\"!isTodoTool(tool.name)\"\n class=\"overflow-hidden\"\n >\n <div\n class=\"flex items-center gap-2 w-full text-left hover:bg-muted/50 rounded px-2 py-1.5 transition-colors cursor-pointer\"\n @click=\"toggle(tool.id)\"\n >\n <ChevronDownIcon\n class=\"h-4 w-4 shrink-0\"\n :class=\"openStates[tool.id] ? '' : '-rotate-90'\"\n />\n <component\n :is=\"getToolIcon(tool.name)\"\n class=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\"\n />\n <span class=\"font-medium\">{{ getToolName(tool.name) }}</span>\n <span class=\"text-muted-foreground truncate flex-1 min-w-0\">{{ formatArgs(tool.args) }}</span>\n <component\n :is=\"getStateIcon(tool.state).icon\"\n :class=\"cn('h-3 w-3 shrink-0 ml-auto', getStateIcon(tool.state).color)\"\n />\n </div>\n <div\n v-show=\"openStates[tool.id]\"\n class=\"mt-2 ml-6 flex flex-col gap-2\"\n >\n <div>\n <p class=\"text-muted-foreground mb-1\">请求:</p>\n <pre class=\"bg-muted p-2 rounded text-[10px] overflow-x-auto max-w-full\">{{ tool.args }}</pre>\n </div>\n <div v-if=\"tool.result || tool.error\">\n <p class=\"text-muted-foreground mb-1\">\n {{ tool.state === 'error' ? 'Error:' : '结果:' }}\n </p>\n <pre\n :class=\"\n cn(\n 'bg-muted p-2 rounded text-[10px] overflow-x-auto max-w-full',\n tool.state === 'error' && 'text-red-500'\n )\n \"\n >{{ tool.error || tool.result }}</pre>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { reactiveOmit } from '@vueuse/core'\nimport { StickToBottom } from 'vue-stick-to-bottom'\n\ninterface Props {\n ariaLabel?: string\n class?: HTMLAttributes['class']\n initial?: boolean | 'instant' | { damping?: number, stiffness?: number, mass?: number }\n resize?: 'instant' | { damping?: number, stiffness?: number, mass?: number }\n damping?: number\n stiffness?: number\n mass?: number\n anchor?: 'auto' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n ariaLabel: 'Conversation',\n initial: true,\n damping: 0.7,\n stiffness: 0.05,\n mass: 1.25,\n anchor: 'none',\n})\nconst delegatedProps = reactiveOmit(props, 'class')\n</script>\n\n<style scoped>\n:deep(> div) {\n scrollbar-width: thin;\n scrollbar-color: var(--ai-scrollbar-thumb) transparent;\n}\n\n:deep(> div::-webkit-scrollbar) {\n width: 6px;\n}\n\n:deep(> div::-webkit-scrollbar-thumb) {\n background: var(--ai-scrollbar-thumb);\n border-radius: 999px;\n}\n\n:deep(> div::-webkit-scrollbar-thumb:hover) {\n background: var(--ai-scrollbar-thumb-hover);\n}\n</style>\n\n<template>\n <StickToBottom\n v-bind=\"delegatedProps\"\n :class=\"cn('relative flex-1 overflow-y-hidden', props.class)\"\n role=\"log\"\n >\n <slot />\n </StickToBottom>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { computed } from 'vue'\n\ninterface Props {\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n\nconst classes = computed(() => cn(\n // 'flex flex-col p-4 border border-border rounded-lg', //这里就是对话整个矩形区域增加边框\n 'flex flex-col p-4', // 无边框\n props.class,\n))\n</script>\n\n<template>\n <div :class=\"classes\">\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { PrimitiveProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport type { ButtonVariants } from \".\"\nimport { Primitive } from \"reka-ui\"\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { buttonVariants } from \".\"\n\ninterface Props extends PrimitiveProps {\n variant?: ButtonVariants[\"variant\"]\n size?: ButtonVariants[\"size\"]\n class?: HTMLAttributes[\"class\"]\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n as: \"button\",\n})\n</script>\n\n<template>\n <Primitive\n data-slot=\"button\"\n :data-variant=\"variant\"\n :data-size=\"size\"\n :as=\"as\"\n :as-child=\"asChild\"\n :class=\"cn(buttonVariants({ variant, size }), props.class)\"\n >\n <slot />\n </Primitive>\n</template>\n","import type { VariantProps } from \"class-variance-authority\"\nimport { cva } from \"class-variance-authority\"\n\nexport { default as Button } from \"./Button.vue\"\n\nexport const buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n submit: \"bg-[var(--ai-accent,#c96442)] text-[var(--ai-accent-foreground,#fff)] hover:bg-[color:var(--ai-accent,#c96442)]/90 disabled:bg-muted disabled:text-muted-foreground\",\n submitLoading: \"bg-[var(--ai-accent,#c96442)] text-[var(--ai-accent-foreground,#fff)] hover:bg-[color:var(--ai-accent,#c96442)]/90\",\n },\n size: {\n \"default\": \"h-9 px-4 py-2 has-[>svg]:px-3\",\n \"sm\": \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n \"lg\": \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n \"icon\": \"size-9\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n)\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Button } from '@/components/ai-bot/ui/button'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { ArrowDownIcon } from 'lucide-vue-next'\nimport { computed } from 'vue'\nimport { useStickToBottomContext } from 'vue-stick-to-bottom'\n\ninterface Props {\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\nconst { isAtBottom, scrollToBottom } = useStickToBottomContext()\nconst showScrollButton = computed(() => !isAtBottom.value)\n\nfunction handleClick() {\n scrollToBottom()\n}\n</script>\n\n<template>\n <Button\n v-if=\"showScrollButton\"\n :class=\"cn(\n 'absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full cursor-pointer dark:bg-background dark:hover:bg-muted',\n props.class,\n )\"\n aria-label=\"Scroll to bottom\"\n size=\"icon\"\n type=\"button\"\n variant=\"outline\"\n v-bind=\"$attrs\"\n @click=\"handleClick\"\n >\n <ArrowDownIcon class=\"size-4\" />\n </Button>\n</template>\n","<script setup lang=\"ts\">\nimport type { UIMessage } from 'ai'\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\n\ninterface Props {\n from: UIMessage['role']\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'group flex w-full max-w-[80%]',\n props.from === 'user' ? 'is-user ml-auto' : 'is-assistant mr-auto',\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\n\ninterface Props {\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'is-user:dark flex w-fit flex-col overflow-hidden text-sm',\n 'group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:bg-[var(--ai-user-bubble-bg)] group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-[var(--ai-user-bubble-text)]',\n 'group-[.is-assistant]:bg-transparent group-[.is-assistant]:p-0 group-[.is-assistant]:text-foreground',\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { ChatMessage, CustomContent } from './lib/message-types'\nimport type { AiBotTheme } from './lib/theme'\nimport ToolCall from './ToolCall.vue'\nimport {\n Conversation,\n ConversationContent,\n ConversationScrollButton,\n} from '@/components/ai-bot/ai-elements/conversation'\nimport {\n Message,\n MessageContent,\n} from '@/components/ai-bot/ai-elements/message'\nimport MarkdownRender from 'markstream-vue'\nimport 'markstream-vue/index.css'\n\ninterface Props {\n messages: ChatMessage[]\n isStreaming?: boolean\n theme?: AiBotTheme\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isStreaming: false,\n theme: 'light'\n})\n\nconst markdownThemes = ['vitesse-dark', 'vitesse-light']\n\nfunction getMessageClass(index: number) {\n if (index === 0) return ''\n const current = props.messages[index]\n // 只有 human 消息需要间隔\n if (current.type === 'human') {\n return 'my-4'\n }\n return ''\n}\n</script>\n\n<style scoped>\n.loading-indicator {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 0;\n}\n\n.dot {\n width: 6px;\n height: 6px;\n background-color: var(--muted-foreground);\n border-radius: 50%;\n animation: bounce 1.4s infinite ease-in-out both;\n}\n\n.dot:nth-child(1) {\n animation-delay: -0.32s;\n}\n\n.dot:nth-child(2) {\n animation-delay: -0.16s;\n}\n\n@keyframes bounce {\n 0%, 80%, 100% {\n transform: scale(0);\n }\n 40% {\n transform: scale(1);\n }\n}\n\n</style>\n\n<template>\n <Conversation>\n <ConversationContent>\n <template v-for=\"(message, index) in messages\" :key=\"message.key\">\n <!-- system/custom 消息按照 assistant 方式渲染 -->\n <Message\n :from=\"message.type === 'tool' || message.type === 'system' || message.type === 'custom' ? 'assistant' : message.type === 'human' ? 'user' : 'assistant'\"\n :class=\"getMessageClass(index)\"\n >\n <!-- tool 消息:显示 ToolCall -->\n <template v-if=\"message.type === 'tool'\">\n <ToolCall :tool-calls=\"message.toolCalls\" />\n </template>\n\n <!-- custom 消息:通过插槽渲染 -->\n <template v-else-if=\"message.type === 'custom'\">\n <MessageContent>\n <slot name=\"custom\" :customContent=\"message.customContent\" />\n </MessageContent>\n </template>\n\n <!-- assistant/system/human 消息 -->\n <template v-else>\n <MessageContent>\n <!-- assistant 和 system 消息使用 MarkdownRender -->\n <MarkdownRender\n v-if=\"message.type === 'ai' || message.type === 'system'\"\n class=\"markdown-body\"\n :content=\"message.content || ''\"\n :is-dark=\"props.theme === 'dark'\"\n code-block-dark-theme=\"vitesse-dark\"\n code-block-light-theme=\"vitesse-light\"\n :themes=\"markdownThemes\"\n :typewriter=\"true\"\n :initial-render-batch-size=\"12\"\n :render-batch-size=\"24\"\n :render-batch-delay=\"20\"\n :max-live-nodes=\"0\"\n :defer-nodes-until-visible=\"true\"\n :viewport-priority=\"true\"\n />\n <!-- human 消息使用普通文本 -->\n <template v-else>\n {{ message.content }}\n </template>\n </MessageContent>\n </template>\n </Message>\n </template>\n <!-- 加载指示器 - 放在左边跟 AI 消息一样 -->\n <Message v-if=\"isStreaming\" from=\"assistant\">\n <div class=\"loading-indicator\">\n <span class=\"dot\"></span>\n <span class=\"dot\"></span>\n <span class=\"dot\"></span>\n </div>\n </Message>\n </ConversationContent>\n <ConversationScrollButton />\n </Conversation>\n</template>\n","import { inject } from 'vue'\nimport type { PromptInputContext } from './input-types'\n\nexport type {\n PromptInputMessage,\n AttachmentFile,\n PromptInputFileAttachment,\n PromptInputImageAttachment,\n PromptInputFileUrlAttachment,\n PromptInputAttachment,\n AttachmentTriggerSlotProps,\n PromptInputContext,\n} from './input-types'\n\nexport const PROMPT_INPUT_KEY = Symbol('PromptInputContext')\n\nexport function usePromptInput() {\n const context = inject<PromptInputContext>(PROMPT_INPUT_KEY)\n if (!context) {\n throw new Error('usePromptInput must be used within a PromptInput component')\n }\n return context\n}\n","import type { InjectionKey, Ref } from 'vue'\nimport type {\n AttachmentData,\n AttachmentMediaCategory,\n AttachmentVariant,\n} from './types'\nimport { computed, inject } from 'vue'\n\nexport interface AttachmentsContextValue {\n variant: Ref<AttachmentVariant>\n}\n\nexport const AttachmentsKey: InjectionKey<AttachmentsContextValue>\n = Symbol('Attachments')\n\nexport function useAttachmentsContext(): AttachmentsContextValue {\n const ctx = inject(AttachmentsKey)\n if (!ctx) {\n return {\n variant: computed(() => 'grid'),\n }\n }\n return ctx\n}\n\nexport interface AttachmentContextValue {\n data: Ref<AttachmentData>\n mediaCategory: Ref<AttachmentMediaCategory>\n remove?: () => void\n variant: Ref<AttachmentVariant>\n}\n\nexport const AttachmentKey: InjectionKey<AttachmentContextValue> = Symbol('Attachment')\n\nexport function useAttachmentContext(): AttachmentContextValue {\n const ctx = inject(AttachmentKey)\n if (!ctx) {\n throw new Error('Attachment components must be used within <Attachment>')\n }\n return ctx\n}\n","import type { AttachmentData, AttachmentMediaCategory } from './types'\n\nexport function getMediaCategory(data: AttachmentData): AttachmentMediaCategory {\n if (data.type === 'source-document') {\n return 'source'\n }\n\n const mediaType = data.mediaType ?? ''\n\n if (mediaType.startsWith('image/')) {\n return 'image'\n }\n if (mediaType.startsWith('video/')) {\n return 'video'\n }\n if (mediaType.startsWith('audio/')) {\n return 'audio'\n }\n if (mediaType.startsWith('application/') || mediaType.startsWith('text/')) {\n return 'document'\n }\n\n return 'unknown'\n}\n\nexport function getAttachmentLabel(data: AttachmentData): string {\n if (data.type === 'source-document') {\n return data.title || data.filename || 'Source'\n }\n\n const category = getMediaCategory(data)\n return data.filename || (category === 'image' ? 'Image' : 'Attachment')\n}\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport type { AttachmentData } from './types'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { computed, provide } from 'vue'\nimport { AttachmentKey, useAttachmentsContext } from './context'\nimport { getMediaCategory } from './utils'\n\ninterface Props extends /* @vue-ignore */ HTMLAttributes {\n data: AttachmentData\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n (e: 'remove'): void\n}>()\n\nconst { variant } = useAttachmentsContext()\nconst data = computed(() => props.data)\nconst mediaCategory = computed(() => getMediaCategory(props.data))\n\nfunction handleRemove() {\n emit('remove')\n}\n\nprovide(AttachmentKey, {\n data,\n mediaCategory,\n remove: handleRemove,\n variant,\n})\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'group relative',\n variant === 'grid' && 'size-24 overflow-hidden rounded-lg',\n variant === 'inline'\n && [\n 'flex h-8 cursor-pointer select-none items-center gap-1',\n 'rounded-md border border-border px-1',\n 'font-medium text-sm transition-all',\n 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',\n ],\n variant === 'list'\n && [\n 'flex w-full items-center gap-3 rounded-lg border p-3',\n 'hover:bg-accent/50',\n ],\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { computed } from 'vue'\nimport { useAttachmentContext } from './context'\nimport { getAttachmentLabel } from './utils'\n\ninterface Props extends /* @vue-ignore */ HTMLAttributes {\n showMediaType?: boolean\n class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showMediaType: false,\n})\n\nconst { data, variant } = useAttachmentContext()\nconst label = computed(() => getAttachmentLabel(data.value))\n</script>\n\n<template>\n <div\n v-if=\"variant !== 'grid'\"\n :class=\"cn('min-w-0 flex-1', props.class)\"\n v-bind=\"$attrs\"\n >\n <span class=\"block truncate\">{{ label }}</span>\n <span\n v-if=\"props.showMediaType && data.mediaType\"\n class=\"block truncate text-muted-foreground text-xs\"\n >\n {{ data.mediaType }}\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes, VNode } from 'vue'\nimport type { AttachmentMediaCategory } from './types'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport {\n FileTextIcon,\n GlobeIcon,\n ImageIcon,\n Music2Icon,\n PaperclipIcon,\n VideoIcon,\n} from 'lucide-vue-next'\nimport { computed } from 'vue'\nimport { useAttachmentContext } from './context'\n\ninterface Props extends /* @vue-ignore */ HTMLAttributes {\n fallbackIcon?: VNode\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n\nconst { data, mediaCategory, variant } = useAttachmentContext()\n\nconst isGrid = computed(() => variant.value === 'grid')\nconst iconSize = computed(() => (variant.value === 'inline' ? 'size-3' : 'size-4'))\nconst fileUrl = computed(() => (data.value.type === 'file' ? data.value.url : undefined))\nconst showImage = computed(\n () => mediaCategory.value === 'image' && data.value.type === 'file' && !!fileUrl.value,\n)\nconst showVideo = computed(\n () => mediaCategory.value === 'video' && data.value.type === 'file' && !!fileUrl.value,\n)\n\nconst iconMap: Record<AttachmentMediaCategory, typeof ImageIcon> = {\n image: ImageIcon,\n video: VideoIcon,\n audio: Music2Icon,\n source: GlobeIcon,\n document: FileTextIcon,\n unknown: PaperclipIcon,\n}\n\nconst iconComponent = computed(() => iconMap[mediaCategory.value])\nconst imageAlt = computed(() =>\n (data.value.type === 'file' ? data.value.filename : undefined) || 'Image',\n)\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'flex shrink-0 items-center justify-center overflow-hidden',\n variant === 'grid' && 'size-full bg-muted',\n variant === 'inline' && 'size-5 rounded bg-background',\n variant === 'list' && 'size-12 rounded bg-muted',\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <img\n v-if=\"showImage\"\n :alt=\"imageAlt\"\n :class=\"isGrid ? 'size-full object-cover' : 'size-full rounded object-cover'\"\n :height=\"isGrid ? 96 : 20\"\n :src=\"fileUrl\"\n :width=\"isGrid ? 96 : 20\"\n >\n <video\n v-else-if=\"showVideo\"\n class=\"size-full object-cover\"\n muted\n :src=\"fileUrl\"\n />\n <component :is=\"props.fallbackIcon\" v-else-if=\"props.fallbackIcon\" />\n <component\n :is=\"iconComponent\"\n v-else\n :class=\"cn(iconSize, 'text-muted-foreground')\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Button } from '@/components/ai-bot/ui/button'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { XIcon } from 'lucide-vue-next'\nimport { useAttachmentContext } from './context'\n\ntype ButtonProps = InstanceType<typeof Button>['$props']\n\ninterface Props extends /* @vue-ignore */ ButtonProps {\n label?: string\n class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: 'Remove',\n})\n\nconst { remove, variant } = useAttachmentContext()\n\nconst { variant: _variant, ...restProps } = props\n\nfunction handleClick(e: Event) {\n e.stopPropagation()\n remove?.()\n}\n</script>\n\n<template>\n <Button\n v-if=\"remove\"\n :aria-label=\"props.label\"\n :class=\"\n cn(\n variant === 'grid'\n && [\n 'absolute top-2 right-2 size-6 rounded-full p-0',\n 'bg-background/80 backdrop-blur-sm',\n 'opacity-0 transition-opacity group-hover:opacity-100',\n 'hover:bg-background',\n '[&>svg]:size-3',\n ],\n variant === 'inline'\n && [\n 'size-5 rounded-sm p-0 cursor-pointer min-w-0',\n 'opacity-0 transition-opacity group-hover:opacity-100',\n '[&>svg]:size-2.5',\n ],\n variant === 'list' && ['size-8 shrink-0 rounded p-0', '[&>svg]:size-4'],\n props.class,\n )\n \"\n type=\"button\"\n variant=\"ghost\"\n v-bind=\"restProps\"\n @click=\"handleClick\"\n >\n <slot>\n <XIcon />\n </slot>\n <span class=\"sr-only\">{{ props.label }}</span>\n </Button>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport type { AttachmentVariant } from './types'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { computed, provide } from 'vue'\nimport { AttachmentsKey } from './context'\n\ninterface Props extends /* @vue-ignore */ HTMLAttributes {\n variant?: AttachmentVariant\n class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'grid',\n})\n\nconst variant = computed(() => props.variant)\n\nprovide(AttachmentsKey, { variant })\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'flex items-start',\n variant === 'list' ? 'flex-col gap-2' : 'flex-wrap gap-2',\n variant === 'grid' && 'ml-auto w-fit',\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport {\n Attachment,\n AttachmentInfo,\n AttachmentPreview,\n AttachmentRemove,\n Attachments,\n} from '@/components/ai-bot/ai-elements/attachments'\nimport type { AttachmentData } from '@/components/ai-bot/ai-elements/attachments/types'\nimport type { AttachmentFile } from '@/components/ai-bot/lib/input-types'\nimport { usePromptInput } from '@/components/ai-bot/lib/prompt-input'\n\nconst { files, removeFile } = usePromptInput()\n\nfunction asAttachmentData(file: AttachmentFile): AttachmentData {\n return file as unknown as AttachmentData\n}\n</script>\n\n<template>\n <Attachments\n v-if=\"files.length > 0\"\n variant=\"inline\"\n class=\"attachments-inline\"\n >\n <Attachment\n v-for=\"attachment in files\"\n :key=\"attachment.id\"\n :data=\"asAttachmentData(attachment)\"\n :title=\"attachment.filename\"\n @remove=\"removeFile(attachment.id)\"\n >\n <AttachmentPreview />\n <AttachmentInfo class=\"attachment-info\" :title=\"attachment.filename\" />\n <AttachmentRemove />\n </Attachment>\n </Attachments>\n</template>\n\n<style scoped>\n.attachments-inline {\n justify-content: flex-start;\n}\n\n.attachment-info {\n max-width: 100px;\n min-width: 0;\n font-size: 11px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Button } from '@/components/ai-bot/ui/button'\nimport { cn } from '@/components/ai-bot/lib/utils'\n\ninterface SuggestionProps {\n suggestion: string\n class?: HTMLAttributes['class']\n variant?: 'outline' | 'default' | 'destructive' | 'secondary' | 'ghost' | 'link'\n size?: 'default' | 'sm' | 'lg' | 'icon'\n}\n\nconst props = withDefaults(defineProps<SuggestionProps>(), {\n variant: 'outline',\n size: 'sm',\n})\n\nconst emit = defineEmits<{\n (e: 'click', suggestion: string): void\n}>()\n\nfunction handleClick() {\n emit('click', props.suggestion)\n}\n</script>\n\n<template>\n <Button\n :class=\"cn('cursor-pointer rounded-full px-4', props.class)\"\n :size=\"props.size\"\n type=\"button\"\n :variant=\"props.variant\"\n v-bind=\"$attrs\"\n @click=\"handleClick\"\n >\n <slot>{{ props.suggestion }}</slot>\n </Button>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { Suggestion } from '@/components/ai-bot/ai-elements/suggestion'\n\ninterface Props {\n suggestions: string[]\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n select: [suggestion: string]\n}>()\n\nconst ROTATE_INTERVAL = 3200\nconst CHIP_GAP = 5\n\nconst viewportRef = ref<HTMLDivElement | null>(null)\nconst measureRefs = ref<(HTMLElement | null)[]>([])\nconst pageRanges = ref<Array<{ start: number, end: number }>>([])\nconst currentPageIndex = ref(0)\nconst isHovered = ref(false)\n\nlet rotationTimer: ReturnType<typeof setInterval> | null = null\nlet resizeObserver: ResizeObserver | null = null\n\nconst shouldRotate = computed(() => pageRanges.value.length > 1)\n\nconst currentPageSuggestions = computed(() => {\n const range = pageRanges.value[currentPageIndex.value]\n if (!range) {\n return props.suggestions\n }\n return props.suggestions.slice(range.start, range.end)\n})\n\nfunction setMeasureRef(el: HTMLElement | null, index: number) {\n measureRefs.value[index] = el\n}\n\nfunction stopRotation() {\n if (rotationTimer) {\n clearInterval(rotationTimer)\n rotationTimer = null\n }\n}\n\nfunction startRotation() {\n stopRotation()\n\n if (!shouldRotate.value || isHovered.value) {\n return\n }\n\n rotationTimer = setInterval(() => {\n currentPageIndex.value = (currentPageIndex.value + 1) % pageRanges.value.length\n }, ROTATE_INTERVAL)\n}\n\nfunction handleMouseEnter() {\n isHovered.value = true\n stopRotation()\n}\n\nfunction handleMouseLeave() {\n isHovered.value = false\n startRotation()\n}\n\nfunction buildPageRanges() {\n const viewportWidth = viewportRef.value?.clientWidth ?? 0\n const widths = props.suggestions.map((_, index) => measureRefs.value[index]?.offsetWidth ?? 0)\n\n if (!props.suggestions.length) {\n pageRanges.value = []\n currentPageIndex.value = 0\n stopRotation()\n return\n }\n\n if (!viewportWidth || widths.some(width => width === 0)) {\n pageRanges.value = [{ start: 0, end: props.suggestions.length }]\n currentPageIndex.value = 0\n stopRotation()\n return\n }\n\n const ranges: Array<{ start: number, end: number }> = []\n let start = 0\n let widthSum = 0\n\n props.suggestions.forEach((_, index) => {\n const itemWidth = widths[index]\n const nextWidth = start === index ? itemWidth : widthSum + CHIP_GAP + itemWidth\n\n if (start !== index && nextWidth > viewportWidth) {\n ranges.push({ start, end: index })\n start = index\n widthSum = itemWidth\n return\n }\n\n widthSum = nextWidth\n })\n\n ranges.push({ start, end: props.suggestions.length })\n pageRanges.value = ranges\n currentPageIndex.value = Math.min(currentPageIndex.value, Math.max(ranges.length - 1, 0))\n startRotation()\n}\n\nasync function recalculatePages() {\n await nextTick()\n buildPageRanges()\n}\n\nwatch(\n () => props.suggestions,\n async () => {\n measureRefs.value = []\n currentPageIndex.value = 0\n stopRotation()\n await recalculatePages()\n },\n { immediate: true },\n)\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(() => {\n currentPageIndex.value = 0\n void recalculatePages()\n })\n\n if (viewportRef.value) {\n resizeObserver.observe(viewportRef.value)\n }\n})\n\nonBeforeUnmount(() => {\n stopRotation()\n resizeObserver?.disconnect()\n})\n</script>\n\n<template>\n <div class=\"suggestions-wrapper\" @mouseenter=\"handleMouseEnter\" @mouseleave=\"handleMouseLeave\">\n <div ref=\"viewportRef\" class=\"suggestions-viewport\" :class=\"{ 'has-fade': shouldRotate }\">\n <Transition name=\"suggestion-slide\" mode=\"out-in\">\n <div :key=\"currentPageIndex\" class=\"suggestions-row\">\n <Suggestion\n v-for=\"suggestion in currentPageSuggestions\"\n :key=\"suggestion\"\n :suggestion=\"suggestion\"\n class=\"suggestion-chip\"\n @click=\"emit('select', suggestion)\"\n />\n </div>\n </Transition>\n </div>\n\n <div class=\"suggestions-measurements\" aria-hidden=\"true\">\n <Suggestion\n v-for=\"(suggestion, index) in suggestions\"\n :key=\"`measure-${suggestion}-${index}`\"\n :ref=\"el => setMeasureRef((el as any)?.$el || el, index)\"\n :suggestion=\"suggestion\"\n class=\"suggestion-chip\"\n tabindex=\"-1\"\n />\n </div>\n </div>\n</template>\n\n<style scoped>\n.suggestions-wrapper {\n padding: 0;\n position: relative;\n}\n\n.suggestions-viewport {\n position: relative;\n width: 100%;\n height: 24px;\n overflow: hidden;\n}\n\n.suggestions-viewport.has-fade::before,\n.suggestions-viewport.has-fade::after {\n content: '';\n position: absolute;\n top: 0;\n z-index: 1;\n width: 16px;\n height: 100%;\n pointer-events: none;\n}\n\n.suggestions-viewport.has-fade::before {\n left: 0;\n background: linear-gradient(90deg, var(--ai-surface) 5%, transparent);\n}\n\n.suggestions-viewport.has-fade::after {\n right: 0;\n background: linear-gradient(270deg, var(--ai-surface) 5%, transparent);\n}\n\n.suggestions-row {\n display: flex;\n align-items: center;\n gap: 5px;\n width: 100%;\n height: 24px;\n overflow: hidden;\n}\n\n.suggestions-measurements {\n position: absolute;\n left: 0;\n top: 0;\n display: flex;\n align-items: center;\n gap: 5px;\n visibility: hidden;\n pointer-events: none;\n white-space: nowrap;\n height: 0;\n overflow: hidden;\n}\n\n:deep(.suggestion-chip) {\n max-width: 100%;\n height: 24px;\n padding: 0 9px;\n border-color: transparent;\n background: var(--ai-chip-bg);\n color: var(--ai-chip-text);\n font-size: 11px;\n line-height: 1;\n font-weight: 500;\n box-shadow: none;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n:deep(.suggestion-chip:hover) {\n background: var(--ai-control-hover-bg);\n border-color: transparent;\n color: var(--ai-chip-hover-text);\n}\n\n.suggestion-slide-enter-active,\n.suggestion-slide-leave-active {\n transition: transform 0.24s ease, opacity 0.24s ease;\n}\n\n.suggestion-slide-enter-from {\n opacity: 0;\n transform: translateY(100%);\n}\n\n.suggestion-slide-leave-to {\n opacity: 0;\n transform: translateY(-100%);\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <div\n data-slot=\"input-group\"\n role=\"group\"\n :class=\"cn(\n 'group/input-group relative flex w-full items-center rounded-md border border-[var(--ai-input-border)] bg-[var(--ai-input-bg)] shadow-xs transition-[color,box-shadow,border-color] outline-none',\n 'h-9 min-w-0 has-[>textarea]:h-auto',\n\n // Variants based on alignment.\n 'has-[>[data-align=inline-start]]:[&>input]:pl-2',\n 'has-[>[data-align=inline-end]]:[&>input]:pr-2',\n 'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',\n 'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',\n\n // Focus state.\n 'has-[[data-slot=input-group-control]:focus-visible]:border-[var(--ai-input-border-focus)] has-[[data-slot=input-group-control]:focus-visible]:ring-[var(--ai-input-ring)] has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]',\n\n // Error state.\n 'has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40',\n\n props.class,\n )\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport type { InputGroupVariants } from \".\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\nimport { inputGroupAddonVariants } from \".\"\n\nconst props = withDefaults(defineProps<{\n align?: InputGroupVariants[\"align\"]\n class?: HTMLAttributes[\"class\"]\n}>(), {\n align: \"inline-start\",\n})\n\nfunction handleInputGroupAddonClick(e: MouseEvent) {\n const currentTarget = e.currentTarget as HTMLElement | null\n const target = e.target as HTMLElement | null\n if (target && target.closest(\"button\")) {\n return\n }\n if (currentTarget && currentTarget?.parentElement) {\n currentTarget.parentElement?.querySelector(\"input\")?.focus()\n }\n}\n</script>\n\n<template>\n <div\n role=\"group\"\n data-slot=\"input-group-addon\"\n :data-align=\"props.align\"\n :class=\"cn(inputGroupAddonVariants({ align: props.align }), props.class)\"\n @click=\"handleInputGroupAddonClick\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport type { InputGroupButtonVariants } from \".\"\nimport type { ButtonVariants } from '@/components/ai-bot/ui/button'\nimport { cn } from \"@/components/ai-bot/lib/utils\"\nimport { Button } from '@/components/ai-bot/ui/button'\nimport { inputGroupButtonVariants } from \".\"\n\ninterface InputGroupButtonProps {\n variant?: ButtonVariants[\"variant\"]\n size?: InputGroupButtonVariants[\"size\"]\n class?: HTMLAttributes[\"class\"]\n}\n\nconst props = withDefaults(defineProps<InputGroupButtonProps>(), {\n size: \"xs\",\n variant: \"ghost\",\n})\n</script>\n\n<template>\n <Button\n :data-size=\"props.size\"\n :variant=\"props.variant\"\n :class=\"cn(inputGroupButtonVariants({ size: props.size }), props.class)\"\n >\n <slot />\n </Button>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { useVModel } from \"@vueuse/core\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n defaultValue?: string | number\n modelValue?: string | number\n}>()\n\nconst emits = defineEmits<{\n (e: \"update:modelValue\", payload: string | number): void\n}>()\n\nconst modelValue = useVModel(props, \"modelValue\", emits, {\n passive: true,\n defaultValue: props.defaultValue,\n})\n</script>\n\n<template>\n <textarea\n v-model=\"modelValue\"\n data-slot=\"textarea\"\n :class=\"cn('border-input text-[var(--ai-input-text)] placeholder:text-[var(--ai-input-placeholder)] focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm', props.class)\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\nimport { Textarea } from '@/components/ai-bot/ui/textarea'\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <Textarea\n data-slot=\"input-group-control\"\n :class=\"cn(\n 'flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent',\n props.class,\n )\"\n />\n</template>\n","import type { VariantProps } from \"class-variance-authority\"\nimport { cva } from \"class-variance-authority\"\n\nexport { default as InputGroup } from \"./InputGroup.vue\"\nexport { default as InputGroupAddon } from \"./InputGroupAddon.vue\"\nexport { default as InputGroupButton } from \"./InputGroupButton.vue\"\nexport { default as InputGroupInput } from \"./InputGroupInput.vue\"\nexport { default as InputGroupText } from \"./InputGroupText.vue\"\nexport { default as InputGroupTextarea } from \"./InputGroupTextarea.vue\"\n\nexport const inputGroupAddonVariants = cva(\n \"text-[var(--ai-control-muted)] flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-4 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-50\",\n {\n variants: {\n align: {\n \"inline-start\":\n \"order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]\",\n \"inline-end\":\n \"order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]\",\n \"block-start\":\n \"order-first w-full justify-start px-3 pt-3 [.border-b]:pb-3 group-has-[>input]/input-group:pt-2.5\",\n \"block-end\":\n \"order-last w-full justify-start px-3 pb-3 [.border-t]:pt-3 group-has-[>input]/input-group:pb-2.5\",\n },\n },\n defaultVariants: {\n align: \"inline-start\",\n },\n },\n)\n\nexport type InputGroupVariants = VariantProps<typeof inputGroupAddonVariants>\n\nexport const inputGroupButtonVariants = cva(\n \"text-sm shadow-none flex gap-2 items-center\",\n {\n variants: {\n size: {\n \"xs\": \"h-6 gap-1 px-2 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2\",\n \"sm\": \"h-8 px-2.5 gap-1.5 rounded-md has-[>svg]:px-2.5\",\n \"icon-xs\": \"size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0\",\n \"icon-sm\": \"size-8 p-0 has-[>svg]:p-0\",\n },\n },\n defaultVariants: {\n size: \"xs\",\n },\n },\n)\n\nexport type InputGroupButtonVariants = VariantProps<typeof inputGroupButtonVariants>\n","<script setup lang=\"ts\">\nimport type { DropdownMenuRootEmits, DropdownMenuRootProps } from \"reka-ui\"\nimport { DropdownMenuRoot, useForwardPropsEmits } from \"reka-ui\"\n\nconst props = defineProps<DropdownMenuRootProps>()\nconst emits = defineEmits<DropdownMenuRootEmits>()\n\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <DropdownMenuRoot\n v-slot=\"slotProps\"\n data-slot=\"dropdown-menu\"\n v-bind=\"forwarded\"\n >\n <slot v-bind=\"slotProps\" />\n </DropdownMenuRoot>\n</template>\n","<script setup lang=\"ts\">\nimport type { DropdownMenuContentEmits, DropdownMenuContentProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport {\n DropdownMenuContent,\n DropdownMenuPortal,\n useForwardPropsEmits,\n} from \"reka-ui\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\nimport { usePortalHost } from '@/components/ai-bot/lib/portal-host'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(\n defineProps<DropdownMenuContentProps & { class?: HTMLAttributes[\"class\"] }>(),\n {\n sideOffset: 4,\n },\n)\nconst emits = defineEmits<DropdownMenuContentEmits>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\nconst { portalHost } = usePortalHost()\n</script>\n\n<template>\n <DropdownMenuPortal :to=\"portalHost || undefined\">\n <DropdownMenuContent\n data-slot=\"dropdown-menu-content\"\n v-bind=\"{ ...$attrs, ...forwarded }\"\n :class=\"cn('bg-[var(--ai-layer-bg)] text-[var(--ai-layer-text)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--reka-dropdown-menu-content-available-height) min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border border-[var(--ai-layer-border)] p-1 shadow-[var(--ai-layer-shadow)]', props.class)\"\n >\n <slot />\n </DropdownMenuContent>\n </DropdownMenuPortal>\n</template>\n","<script setup lang=\"ts\">\nimport type { DropdownMenuItemProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { DropdownMenuItem, useForwardProps } from \"reka-ui\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\n\nconst props = withDefaults(defineProps<DropdownMenuItemProps & {\n class?: HTMLAttributes[\"class\"]\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}>(), {\n variant: \"default\",\n})\n\nconst delegatedProps = reactiveOmit(props, \"inset\", \"variant\", \"class\")\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <DropdownMenuItem\n data-slot=\"dropdown-menu-item\"\n :data-inset=\"inset ? '' : undefined\"\n :data-variant=\"variant\"\n v-bind=\"forwardedProps\"\n :class=\"cn('focus:bg-[var(--ai-control-hover-bg)] focus:text-[var(--ai-control-hover-text)] data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*=\\'text-\\'])]:text-[var(--ai-control-muted)] relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\\'size-\\'])]:size-4', props.class)\"\n >\n <slot />\n </DropdownMenuItem>\n</template>\n","<script setup lang=\"ts\">\nimport type { DropdownMenuTriggerProps } from \"reka-ui\"\nimport { DropdownMenuTrigger, useForwardProps } from \"reka-ui\"\n\nconst props = defineProps<DropdownMenuTriggerProps>()\n\nconst forwardedProps = useForwardProps(props)\n</script>\n\n<template>\n <DropdownMenuTrigger\n data-slot=\"dropdown-menu-trigger\"\n v-bind=\"forwardedProps\"\n >\n <slot />\n </DropdownMenuTrigger>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, provide, onBeforeUnmount } from 'vue'\nimport type { ChatFileType, ChatStatus } from './lib/message-types'\nimport { nanoid } from 'nanoid'\nimport { PROMPT_INPUT_KEY } from './lib/prompt-input'\nimport type { AttachmentFile, AttachmentTriggerSlotProps, PromptInputAttachment, PromptInputContext } from './lib/input-types'\nimport { getProviderByModelName, type ModelInfo } from './lib/models'\nimport PromptInputAttachmentsDisplay from './InputAttachmentsDisplay.vue'\nimport ChatSuggestions from './ChatSuggestions.vue'\nimport { CheckIcon, ChevronDownIcon, Loader2Icon, CornerDownLeftIcon, PaperclipIcon } from 'lucide-vue-next'\nimport { InputGroup, InputGroupAddon, InputGroupTextarea, InputGroupButton } from '@/components/ai-bot/ui/input-group'\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, DropdownMenuItem } from '@/components/ai-bot/ui/dropdown-menu'\n\n// ============== 类型定义 ==============\ninterface Props {\n status: ChatStatus\n currentModel: ModelInfo | null\n models: ModelInfo[]\n suggestions: string[]\n useWebSearch: boolean\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n submit: [message: { text: string, files: AttachmentFile[] }]\n stop: []\n selectSuggestion: [suggestion: string]\n 'update:currentModel': [model: ModelInfo]\n 'update:useWebSearch': [value: boolean]\n}>()\n\nconst modelSelectorOpen = defineModel<boolean>('modelSelectorOpen', { default: false })\n\ndefineSlots<{\n 'attachment-trigger'?: (props: AttachmentTriggerSlotProps) => any\n}>()\n\n// ============== PromptInput Context ==============\n\n// 本地状态\nconst inputText = ref('')\nconst hasFiles = ref(false)\nconst files = ref<AttachmentFile[]>([])\nconst fileInputRef = ref<HTMLInputElement | null>(null)\nconst isLoading = ref(false)\n\n// Cleanup object URLs\nonBeforeUnmount(() => {\n files.value.forEach((f) => {\n if (f.url && f.url.startsWith('blob:')) {\n URL.revokeObjectURL(f.url)\n }\n })\n})\n\nconst setTextInput = (val: string) => {\n inputText.value = val\n}\n\nfunction resolveAttachmentType(attachment: PromptInputAttachment, file?: File, url?: string): ChatFileType {\n if (attachment.type === 'file_url') {\n return 'file_url'\n }\n if (attachment.type === 'image') {\n return 'image'\n }\n if (attachment.type === 'file') {\n return 'file'\n }\n if (url && !url.startsWith('blob:') && !url.startsWith('data:')) {\n return 'file_url'\n }\n const mediaType = file?.type || ''\n return mediaType.startsWith('image/') ? 'image' : 'file'\n}\n\nconst addAttachments = (incoming: PromptInputAttachment[]) => {\n const existingFilenames = new Set(\n files.value\n .map(file => file.filename?.trim())\n .filter((name): name is string => !!name),\n )\n\n const newAttachments: AttachmentFile[] = incoming.flatMap((attachment) => {\n const normalized = attachment.type === 'file_url'\n ? {\n ...attachment,\n id: attachment.id || nanoid(),\n type: 'file_url' as const,\n url: attachment.url,\n mediaType: attachment.mediaType || 'application/octet-stream',\n filename: attachment.filename,\n }\n : (() => {\n const file = attachment.file\n const url = attachment.url || (file ? URL.createObjectURL(file) : undefined)\n const type = resolveAttachmentType(attachment, file, url)\n\n return {\n ...attachment,\n id: attachment.id || nanoid(),\n type,\n url,\n mediaType: attachment.mediaType || file?.type || '',\n filename: attachment.filename || file?.name,\n file,\n }\n })()\n\n const normalizedName = normalized.filename?.trim()\n if (normalizedName && existingFilenames.has(normalizedName)) {\n if (normalized.url?.startsWith('blob:')) {\n URL.revokeObjectURL(normalized.url)\n }\n return []\n }\n\n if (normalizedName) {\n existingFilenames.add(normalizedName)\n }\n\n return [normalized]\n })\n\n files.value = [...files.value, ...newAttachments]\n hasFiles.value = files.value.length > 0\n}\n\nconst addFiles = (incoming: File[] | FileList) => {\n const fileList = Array.from(incoming)\n addAttachments(fileList.map(file => ({\n type: file.type.startsWith('image/') ? 'image' : 'file',\n file,\n })))\n}\n\nconst removeFile = (id: string) => {\n const file = files.value.find(f => f.id === id)\n if (file?.url && file.url.startsWith('blob:')) {\n URL.revokeObjectURL(file.url)\n }\n files.value = files.value.filter(f => f.id !== id)\n hasFiles.value = files.value.length > 0\n}\n\nconst clearFiles = () => {\n files.value.forEach((f) => {\n if (f.url && f.url.startsWith('blob:')) {\n URL.revokeObjectURL(f.url)\n }\n })\n files.value = []\n hasFiles.value = false\n}\n\nconst clearInput = () => {\n inputText.value = ''\n}\n\nconst openFileDialog = () => {\n fileInputRef.value?.click()\n}\n\nconst convertBlobUrlToDataUrl = async (url: string): Promise<string | null> => {\n try {\n const response = await fetch(url)\n const blob = await response.blob()\n return new Promise((resolve) => {\n const reader = new FileReader()\n reader.onloadend = () => resolve(reader.result as string)\n reader.onerror = () => resolve(null)\n reader.readAsDataURL(blob)\n })\n }\n catch {\n return null\n }\n}\n\nconst sendMessage = async () => {\n // Process files (convert blobs to base64 if needed for AI SDK)\n const processedFiles = await Promise.all(\n files.value.map(async (item) => {\n if (item.url && item.url.startsWith('blob:')) {\n const dataUrl = await convertBlobUrlToDataUrl(item.url)\n return {\n ...item,\n type: item.type === 'file_url' ? 'file' : item.type,\n data: dataUrl ?? item.data,\n url: dataUrl ?? item.url,\n }\n }\n return item\n }),\n )\n\n const message = {\n text: inputText.value,\n files: processedFiles,\n }\n\n emit('submit', message)\n clearInput()\n clearFiles()\n}\n\n// 提供 context 给子组件\nconst context: PromptInputContext = {\n textInput: inputText,\n files,\n fileInputRef,\n isLoading,\n setTextInput,\n addAttachments,\n addFiles,\n removeFile,\n clearFiles,\n clearInput,\n openFileDialog,\n sendMessage,\n}\n\nprovide(PROMPT_INPUT_KEY, context)\n\n// ============== 本地输入状态 ==============\n\n// 输入是否为空\nconst isEmpty = computed(() => {\n return !inputText.value.trim() && !hasFiles.value\n})\n\nconst selectedModelData = computed(() => {\n return props.currentModel || props.models.find(m => m.is_default) || props.models[0]\n})\n\n// 按提供商分组模型\nconst groupedModels = computed(() => {\n const groups: Record<string, ModelInfo[]> = {}\n props.models.forEach((model) => {\n const provider = model.provider || 'Other'\n if (!groups[provider]) {\n groups[provider] = []\n }\n groups[provider].push(model)\n })\n return groups\n})\n\nconst providers = computed(() => Object.keys(groupedModels.value))\n\nfunction handleModelSelect(name: string) {\n const model = props.models.find(m => m.name === name)\n if (model) {\n emit('update:currentModel', model)\n }\n modelSelectorOpen.value = false\n}\n\n// ============== PromptInputTextarea 逻辑 ==============\nconst isComposing = ref(false)\n\nfunction handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Enter') {\n // 忙碌状态不允许发送,但 shift+回车允许换行\n if (isLoadingStatus.value) {\n if (!e.shiftKey)\n e.preventDefault()\n return\n }\n // 中文输入或 shift+回车,允许换行\n if (isComposing.value || e.shiftKey)\n return\n e.preventDefault()\n sendMessage()\n }\n\n // Remove last attachment on backspace if input is empty\n if (e.key === 'Backspace' && inputText.value === '' && files.value.length > 0) {\n const lastFile = files.value[files.value.length - 1]\n if (lastFile) {\n removeFile(lastFile.id)\n }\n }\n}\n\nfunction handlePaste(e: ClipboardEvent) {\n const items = e.clipboardData?.items\n if (!items)\n return\n\n const pastedFiles: File[] = []\n for (const item of Array.from(items)) {\n if (item.kind === 'file') {\n const file = item.getAsFile()\n if (file)\n pastedFiles.push(file)\n }\n }\n\n if (pastedFiles.length > 0) {\n e.preventDefault()\n addFiles(pastedFiles)\n }\n}\n\n// ============== PromptInputSubmit 逻辑 ==============\nconst buttonVariant = computed(() => {\n if (props.status === 'streaming') {\n return 'destructive'\n }\n return 'submit'\n})\n\nconst submitIcon = computed(() => {\n if (props.status === 'streaming') {\n return Loader2Icon\n }\n return CornerDownLeftIcon\n})\n\nconst iconClass = computed(() => {\n if (props.status === 'streaming') {\n return 'size-4 animate-spin'\n }\n return 'size-4'\n})\n\nconst isDisabled = computed(() => {\n // 忙碌状态时不应禁用(需要可以点击取消)\n if (isLoadingStatus.value)\n return false\n return isEmpty.value\n})\n\nconst isLoadingStatus = computed(() => {\n return props.status === 'streaming'\n})\n\nfunction handleSubmitClick() {\n if (isLoadingStatus.value) {\n emit('stop')\n } else {\n sendMessage()\n }\n}\n\n// ============== 图片错误处理 ==============\nfunction handleImageError(e: Event) {\n const img = e.target as HTMLImageElement\n img.src = 'https://models.dev/logos/openai.svg'\n}\n\n// ============== 处理文件上传 ==============\nfunction onFileChange(e: Event) {\n const input = e.target as HTMLInputElement\n if (input.files) {\n addFiles(input.files)\n }\n input.value = ''\n}\n</script>\n\n<template>\n <div class=\"input-wrapper\">\n <!-- 隐藏的文件输入 -->\n <input\n ref=\"fileInputRef\"\n type=\"file\"\n class=\"hidden\"\n multiple\n accept=\"image/*,.pdf,.doc,.docx,.txt\"\n @change=\"onFileChange\"\n >\n\n <div class=\"w-full\">\n <InputGroup class=\"input-group-shell overflow-hidden\">\n <div class=\"input-top\">\n <div v-if=\"props.suggestions.length > 0\" class=\"input-suggestions\">\n <ChatSuggestions\n :suggestions=\"props.suggestions\"\n @select=\"emit('selectSuggestion', $event)\"\n />\n </div>\n\n <div v-if=\"props.suggestions.length > 0\" class=\"attachments-divider\" />\n\n <div v-if=\"files.length > 0\" class=\"input-attachments\">\n <PromptInputAttachmentsDisplay />\n </div>\n\n<!-- <div v-if=\"files.length > 0\" class=\"attachments-divider\" />-->\n </div>\n\n <!-- 文本输入区域 (PromptInputBody) -->\n <div class=\"contents\">\n <InputGroupTextarea\n v-model=\"inputText\"\n placeholder=\"有什么我能帮您的?\"\n name=\"message\"\n class=\"field-sizing-content max-h-48 min-h-16 pt-2 pb-3\"\n @keydown=\"handleKeyDown\"\n @paste=\"handlePaste\"\n @compositionstart=\"isComposing = true\"\n @compositionend=\"isComposing = false\"\n />\n </div>\n\n <!-- 底部工具栏 (PromptInputFooter) -->\n <InputGroupAddon\n align=\"block-end\"\n class=\"justify-between gap-1\"\n >\n <!-- 工具栏内容 (PromptInputTools) -->\n <div class=\"flex items-center gap-1\">\n <InputGroupButton\n type=\"button\"\n class=\"attachment-button cursor-pointer text-muted-foreground\"\n @click=\"openFileDialog\"\n >\n <PaperclipIcon class=\"size-4\" />\n </InputGroupButton>\n <slot\n name=\"attachment-trigger\"\n :addAttachments=\"addAttachments\"\n />\n </div>\n\n <!-- 右侧:模型选择器 + 发送按钮 -->\n <div class=\"flex items-center gap-1\">\n <!-- 模型选择器 -->\n <DropdownMenu v-model:open=\"modelSelectorOpen\">\n <DropdownMenuTrigger as-child>\n <InputGroupButton type=\"button\" class=\"flex items-center gap-1 cursor-pointer\">\n <img\n v-if=\"selectedModelData\"\n :src=\"`https://models.dev/logos/${getProviderByModelName(selectedModelData.name)}.svg`\"\n class=\"size-4 rounded-sm object-contain\"\n :alt=\"selectedModelData.name\"\n @error=\"handleImageError\"\n >\n <span v-if=\"selectedModelData\" class=\"whitespace-nowrap\">{{ selectedModelData.name }}</span>\n <span v-else class=\"text-muted-foreground\">选择模型</span>\n <ChevronDownIcon class=\"size-4 opacity-50 shrink-0\" />\n </InputGroupButton>\n </DropdownMenuTrigger>\n\n <DropdownMenuContent align=\"start\">\n <template v-for=\"provider in providers\" :key=\"provider\">\n <div class=\"px-2 py-1.5 text-xs font-semibold text-[var(--ai-menu-heading)]\">\n 请选择模型\n </div>\n <DropdownMenuItem\n v-for=\"model in groupedModels[provider]\"\n :key=\"model.name\"\n @select=\"() => handleModelSelect(model.name)\"\n class=\"cursor-pointer gap-1 text-[13px] text-[var(--ai-menu-text)]\"\n >\n <img\n :src=\"`https://models.dev/logos/${getProviderByModelName(model.name)}.svg`\"\n class=\"size-4 rounded-sm object-contain\"\n :alt=\"model.name\"\n @error=\"handleImageError\"\n >\n <span class=\"flex-1 truncate\">\n {{ model.name }}\n <span v-if=\"model.is_default\" class=\"ml-1.5 rounded bg-[var(--ai-muted-surface)] px-1.5 py-0.5 text-[11px] text-[var(--ai-menu-heading)]\">\n 默认\n </span>\n </span>\n <CheckIcon\n v-if=\"selectedModelData?.name === model.name\"\n class=\"size-4\"\n />\n </DropdownMenuItem>\n </template>\n </DropdownMenuContent>\n </DropdownMenu>\n\n <!-- 发送按钮 (PromptInputSubmit) -->\n <InputGroupButton\n aria-label=\"Submit\"\n type=\"button\"\n size=\"icon-sm\"\n :variant=\"buttonVariant\"\n class=\"cursor-pointer disabled:cursor-not-allowed\"\n :disabled=\"isDisabled\"\n @click=\"handleSubmitClick\"\n >\n <component :is=\"submitIcon\" :class=\"iconClass\" />\n </InputGroupButton>\n </div>\n </InputGroupAddon>\n </InputGroup>\n </div>\n </div>\n</template>\n\n<style scoped>\n.input-wrapper {\n padding: 4px 12px 8px;\n border-top: 1px solid var(--ai-border-subtle);\n background: var(--ai-input-panel-bg);\n flex-shrink: 0;\n}\n\n.input-top {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 100%;\n align-items: flex-start;\n}\n\n.input-suggestions {\n width: 100%;\n padding: 8px 12px 0;\n}\n\n.input-attachments {\n width: 100%;\n max-height: 120px;\n padding: 4px 12px;\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: thin;\n scrollbar-color: var(--ai-scrollbar-thumb) transparent;\n}\n\n.input-attachments::-webkit-scrollbar {\n width: 6px;\n}\n\n.input-attachments::-webkit-scrollbar-thumb {\n background: var(--ai-scrollbar-thumb);\n border-radius: 999px;\n}\n\n.input-attachments::-webkit-scrollbar-thumb:hover {\n background: var(--ai-scrollbar-thumb-hover);\n}\n\n.attachments-divider {\n width: calc(100% - 24px);\n margin: 4px 12px 0;\n border-top: 1px solid var(--ai-border-subtle);\n}\n\n.input-group-shell {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n}\n\n.attachment-button:hover,\n.attachment-button:focus,\n.attachment-button:focus-visible,\n.attachment-button[data-state='open'] {\n background: transparent !important;\n color: inherit !important;\n}\n</style>\n","<script setup lang=\"ts\">\ninterface Props {\n size?: number\n}\n\nwithDefaults(defineProps<Props>(), {\n size: 16,\n})\n</script>\n\n<template>\n <svg\n :height=\"size\"\n stroke-linejoin=\"round\"\n :style=\"{ color: 'currentcolor' }\"\n viewBox=\"0 0 16 16\"\n :width=\"size\"\n >\n <title>Loader</title>\n <g clip-path=\"url(#clip0_2393_1490)\">\n <path d=\"M8 0V4\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M8 16V12\" opacity=\"0.5\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M3.29773 1.52783L5.64887 4.7639\" opacity=\"0.9\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M12.7023 1.52783L10.3511 4.7639\" opacity=\"0.1\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M12.7023 14.472L10.3511 11.236\" opacity=\"0.4\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M3.29773 14.472L5.64887 11.236\" opacity=\"0.6\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M15.6085 5.52783L11.8043 6.7639\" opacity=\"0.2\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M0.391602 10.472L4.19583 9.23598\" opacity=\"0.7\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M15.6085 10.4722L11.8043 9.2361\" opacity=\"0.3\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M0.391602 5.52783L4.19583 6.7639\" opacity=\"0.8\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n </g>\n <defs>\n <clipPath id=\"clip0_2393_1490\">\n <rect fill=\"white\" height=\"16\" width=\"16\" />\n </clipPath>\n </defs>\n </svg>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport LoaderIcon from './LoaderIcon.vue'\n\ninterface Props {\n size?: number\n class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 16,\n})\n</script>\n\n<template>\n <div\n :class=\"cn('inline-flex animate-spin items-center justify-center', props.class)\"\n aria-label=\"Loading\"\n aria-live=\"polite\"\n role=\"status\"\n v-bind=\"$attrs\"\n >\n <LoaderIcon :size=\"props.size\" />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { CustomContent } from './lib/message-types'\nimport { ArrowUpRight } from 'lucide-vue-next'\n\ninterface Props {\n customContent: CustomContent\n apiUrl: string\n threadId: string | null\n}\n\nconst props = defineProps<Props>()\n\n// 只处理 generated_files 类型\nconst files = props.customContent?.type === 'generated_files'\n ? props.customContent.content\n : null\n</script>\n\n<template>\n <div v-if=\"files && Array.isArray(files)\" class=\"generated-files\">\n <a\n v-for=\"(file, index) in files\"\n :key=\"index\"\n class=\"file-item\"\n :href=\"`${props.apiUrl}/webapp/download/${props.threadId}?path=${encodeURIComponent(file)}`\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span>{{ file }}</span>\n <ArrowUpRight class=\"file-icon\" />\n </a>\n </div>\n</template>\n\n<style scoped>\n.generated-files {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.file-item {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n font-size: 13px;\n color: var(--ai-file-pill-text);\n background: var(--ai-file-pill-bg);\n border-radius: 9999px;\n text-decoration: none;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.file-item:hover {\n background: var(--ai-file-pill-hover-bg);\n}\n\n.file-item .file-icon {\n width: 14px;\n height: 14px;\n flex-shrink: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { CSSProperties, HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { motion } from 'motion-v'\nimport { computed, useSlots } from 'vue'\n\nexport interface TextShimmerProps {\n as?: keyof HTMLElementTagNameMap\n class?: HTMLAttributes['class']\n duration?: number\n spread?: number\n}\n\nconst props = withDefaults(defineProps<TextShimmerProps>(), {\n as: 'p',\n duration: 2,\n spread: 2,\n})\n\nconst slots = useSlots()\n\nconst textContent = computed(() => {\n const defaultSlot = slots.default?.()\n if (!defaultSlot || defaultSlot.length === 0)\n return ''\n\n return defaultSlot\n .map((vnode) => {\n if (typeof vnode.children === 'string') {\n return vnode.children\n }\n return ''\n })\n .join('')\n})\n\nconst dynamicSpread = computed(() => {\n return (textContent.value?.length ?? 0) * props.spread\n})\n\nconst componentClasses = computed(() => cn('relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent', '[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]', props.class))\n\nconst componentStyle = computed((): CSSProperties => ({\n '--spread': `${dynamicSpread.value}px`,\n 'backgroundImage':\n 'var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))',\n}))\n\nconst MotionComponent = computed(() => {\n return motion[props.as as keyof typeof motion] || motion.p\n})\n</script>\n\n<template>\n <component\n :is=\"MotionComponent\"\n :class=\"componentClasses\"\n :style=\"componentStyle\"\n :initial=\"{ backgroundPosition: '100% center' }\"\n :animate=\"{ backgroundPosition: '0% center' }\"\n :transition=\"{\n repeat: Number.POSITIVE_INFINITY,\n duration,\n ease: 'linear',\n }\"\n >\n <slot />\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { Ban, ChevronsDown, ChevronsUp, Circle, CircleCheckBig, LoaderCircle } from 'lucide-vue-next'\nimport type { ToolEventPayload } from './lib/tool-events'\nimport { Shimmer } from './ai-elements/shimmer'\n\nexport interface TodoItem {\n id: string\n title: string\n status: 'pending' | 'in_progress' | 'completed' | 'interrupted'\n}\n\ninterface Props {\n initialTodos?: RawTodo[]\n toolEvents?: ToolEventPayload[]\n chatStatus?: 'ready' | 'streaming'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n initialTodos: () => [],\n toolEvents: () => [],\n chatStatus: 'ready'\n})\n\nconst todos = ref<TodoItem[]>([])\nconst processedEventCount = ref(0)\nconst completedCount = computed(() => todos.value.filter(todo => todo.status === 'completed').length)\nconst inProgressCount = computed(() => todos.value.filter(todo => todo.status === 'in_progress').length)\nconst interruptedCount = computed(() => todos.value.filter(todo => todo.status === 'interrupted').length)\nconst pendingCount = computed(() => todos.value.filter(todo => todo.status === 'pending').length)\n\nconst expanded = ref(false)\nconst userCollapsed = ref(false)\n\nfunction toggleExpanded() {\n expanded.value = !expanded.value\n userCollapsed.value = !expanded.value\n}\n\nfunction syncExpandedWithTodos(nextTodos: TodoItem[]) {\n if (nextTodos.length === 0) {\n expanded.value = false\n userCollapsed.value = false\n return\n }\n\n // 仅在对话进行中且仍处于自动模式时,随着流式更新保持展开。\n if (!userCollapsed.value && props.chatStatus === 'streaming') {\n expanded.value = true\n }\n}\n\nfunction isWriteTodosTool(toolName?: string): boolean {\n return (toolName || '') === 'write_todos'\n}\n\nfunction normalizeTodoStatus(rawStatus: unknown, fallback: TodoItem['status']): TodoItem['status'] {\n const status = String(rawStatus || '').toLowerCase()\n if (status === 'completed') return 'completed'\n if (status === 'in_progress') return 'in_progress'\n if (status === 'pending') return 'pending'\n if (status === 'interrupted') return 'interrupted'\n return fallback\n}\n\nfunction normalizeHistoricalTodoStatus(rawStatus: unknown): TodoItem['status'] {\n const status = normalizeTodoStatus(rawStatus, 'pending')\n return status === 'in_progress' ? 'interrupted' : status\n}\n\nfunction statusByPhase(event: ToolEventPayload): TodoItem['status'] {\n if (event.state === 'completed') return 'completed'\n if (event.state === 'interrupted') return 'interrupted'\n if (event.phase === 'tool_call_started') return 'pending'\n return 'in_progress'\n}\n\ntype RawTodo = {\n id?: string\n title?: string\n task?: string\n content?: string\n text?: string\n name?: string\n status?: string\n state?: string\n}\n\nfunction mapRawTodos(rawTodos: RawTodo[], fallbackState: TodoItem['status'] = 'pending'): TodoItem[] {\n return rawTodos.map((todo, index) => ({\n id: todo.id || `todo-${index + 1}`,\n title: todo.title || todo.task || todo.content || todo.text || todo.name || '',\n status: normalizeTodoStatus(todo.status || todo.state, fallbackState)\n })).filter(todo => todo.title)\n}\n\nfunction mapHistoricalTodos(rawTodos: RawTodo[]): TodoItem[] {\n return rawTodos.map((todo, index) => ({\n id: todo.id || `todo-${index + 1}`,\n title: todo.title || todo.task || todo.content || todo.text || todo.name || '',\n status: normalizeHistoricalTodoStatus(todo.status || todo.state)\n })).filter(todo => todo.title)\n}\n\nfunction finalizeInProgressTodos() {\n const nextTodos = todos.value.map(todo => {\n if (todo.status !== 'in_progress') {\n return todo\n }\n return {\n ...todo,\n status: 'interrupted' as const\n }\n })\n\n todos.value = nextTodos\n syncExpandedWithTodos(nextTodos)\n}\n\ntype RawTodoContainer = {\n todo?: RawTodo\n todos?: RawTodo[]\n item?: RawTodo\n items?: RawTodo[]\n}\n\nfunction isRawTodoContainer(payload: RawTodo | RawTodoContainer): payload is RawTodoContainer {\n return 'todo' in payload || 'todos' in payload || 'item' in payload || 'items' in payload\n}\n\nfunction parseRawTodoItems(raw?: string): RawTodo[] {\n if (!raw) return []\n\n try {\n const payload = JSON.parse(raw) as RawTodo | RawTodo[] | RawTodoContainer\n\n if (Array.isArray(payload)) {\n return payload\n }\n\n if (isRawTodoContainer(payload)) {\n if (Array.isArray(payload.todos)) return payload.todos\n if (Array.isArray(payload.items)) return payload.items\n if (payload.todo) return [payload.todo]\n if (payload.item) return [payload.item]\n }\n\n return []\n } catch {\n return []\n }\n}\n\nfunction parseToolTodos(raw?: string, fallbackState: TodoItem['status'] = 'pending'): TodoItem[] {\n const rawTodos = parseRawTodoItems(raw)\n return mapRawTodos(rawTodos, fallbackState)\n}\n\nfunction replaceWriteTodos(raw?: string, fallbackState: TodoItem['status'] = 'pending') {\n const nextTodos = parseToolTodos(raw, fallbackState)\n if (nextTodos.length === 0) return false\n\n todos.value = nextTodos\n syncExpandedWithTodos(nextTodos)\n return true\n}\n\nfunction applyToolEvent(event: ToolEventPayload) {\n const fallbackState = statusByPhase(event)\n\n if (!isWriteTodosTool(event.name)) return\n\n // write_todos 的结构化数据只看 args;result 只是日志文本,不参与待办解析。\n replaceWriteTodos(event.args, fallbackState)\n}\n\nwatch(\n () => props.initialTodos,\n (rawTodos) => {\n const nextTodos = mapHistoricalTodos(rawTodos || [])\n todos.value = nextTodos\n syncExpandedWithTodos(nextTodos)\n },\n { deep: true, immediate: true }\n)\n\nwatch(\n () => props.toolEvents,\n (events) => {\n if (!events.length) {\n processedEventCount.value = 0\n return\n }\n\n if (events.length < processedEventCount.value) {\n todos.value = []\n processedEventCount.value = 0\n syncExpandedWithTodos([])\n }\n\n const nextEvents = events.slice(processedEventCount.value)\n nextEvents.forEach((event) => {\n // TodoList 自己消费 todo 相关工具事件,列表状态和渲染逻辑保持在组件内部。\n applyToolEvent(event)\n })\n processedEventCount.value = events.length\n },\n { deep: true, immediate: true }\n)\n\nwatch(\n () => props.chatStatus,\n (next, prev) => {\n if (prev === 'streaming' && next === 'ready') {\n finalizeInProgressTodos()\n }\n }\n)\n</script>\n\n<template>\n <div v-if=\"todos.length\" class=\"todo-section\">\n <div class=\"todo-card\">\n <div\n class=\"todo-divider\"\n :class=\"{ collapsed: !expanded }\"\n @click=\"toggleExpanded\"\n >\n <div class=\"title\">\n <component\n :is=\"expanded ? ChevronsDown : ChevronsUp\"\n :size=\"13\"\n class=\"title-chevron\"\n />\n <span class=\"title-label\">执行计划</span>\n <span class=\"title-summary\">{{ completedCount }}/{{ todos.length }}</span>\n <span class=\"title-meta\">\n {{ inProgressCount > 0 ? `进行中 ${inProgressCount}` : interruptedCount > 0 ? `中断 ${interruptedCount}` : pendingCount > 0 ? `待处理 ${pendingCount}` : '已完成' }}\n </span>\n </div>\n </div>\n\n <div v-show=\"expanded\" class=\"todo-list\">\n\n <div\n v-for=\"(todo, index) in todos\"\n :key=\"todo.id\"\n class=\"todo-item\"\n >\n\n <div class=\"todo-row\">\n <div\n class=\"todo-content\"\n :class=\"{\n completed: todo.status === 'completed',\n pending: todo.status === 'pending',\n interrupted: todo.status === 'interrupted',\n 'in-progress': todo.status === 'in_progress'\n }\"\n >\n <span class=\"todo-index\">{{ index + 1 }}.</span>\n\n <span class=\"indicator\" aria-hidden=\"true\">\n <Circle\n v-if=\"todo.status === 'pending'\"\n :size=\"13\"\n class=\"status-icon pending-icon\"\n />\n <LoaderCircle\n v-if=\"todo.status === 'in_progress'\"\n :size=\"13\"\n class=\"status-icon in-progress-icon\"\n />\n <Ban\n v-if=\"todo.status === 'interrupted'\"\n :size=\"13\"\n class=\"status-icon interrupted-icon\"\n />\n <CircleCheckBig\n v-if=\"todo.status === 'completed'\"\n :size=\"13\"\n class=\"status-icon completed-icon\"\n />\n </span>\n\n <Shimmer\n v-if=\"todo.status === 'in_progress'\"\n as=\"div\"\n class=\"title-text-base title-text-shimmer\"\n >\n {{ todo.title }}\n </Shimmer>\n\n <div v-else class=\"title-text-base title-text\">\n {{ todo.title }}\n </div>\n </div>\n\n </div>\n\n </div>\n\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.todo-section {\n padding: 2px 12px 0;\n}\n\n.todo-card {\n --todo-surface: var(--ai-plan-bg);\n --todo-surface-strong: var(--ai-plan-bg-strong);\n --todo-border: var(--ai-plan-border);\n --todo-divider: var(--ai-plan-border);\n --todo-title: var(--foreground);\n --todo-muted: var(--ai-plan-muted);\n --todo-summary-bg: color-mix(in srgb, var(--ai-plan-bg-strong) 82%, var(--ai-plan-border));\n --todo-summary-border: var(--ai-plan-border);\n --todo-summary-text: color-mix(in srgb, var(--foreground) 72%, var(--ai-plan-muted));\n --todo-hover: var(--ai-plan-hover);\n --todo-text: color-mix(in srgb, var(--foreground) 88%, transparent);\n --todo-index: color-mix(in srgb, var(--ai-plan-muted) 88%, transparent);\n --todo-pending: color-mix(in srgb, var(--ai-plan-muted) 84%, transparent);\n --todo-progress: var(--ai-plan-progress);\n --todo-interrupted: var(--ai-plan-interrupted);\n --todo-interrupted-text: color-mix(in srgb, var(--foreground) 74%, var(--ai-plan-interrupted));\n --todo-completed: var(--ai-plan-complete);\n --todo-completed-text: color-mix(in srgb, var(--foreground) 62%, var(--ai-plan-complete));\n border-radius: 6px;\n border: 1px solid var(--todo-border);\n background:\n linear-gradient(180deg, var(--todo-surface-strong), var(--todo-surface)),\n var(--todo-surface-strong);\n box-shadow:\n inset 0 1px 0 color-mix(in srgb, var(--foreground) 8%, transparent),\n 0 4px 12px color-mix(in srgb, var(--ai-plan-border) 36%, transparent);\n overflow: hidden;\n}\n\n.todo-divider {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n padding: 6px 12px;\n cursor: pointer;\n user-select: none;\n border-bottom: 1px solid transparent;\n transition: background-color 0.18s ease, border-color 0.18s ease, padding 0.18s ease;\n}\n\n.todo-divider.collapsed {\n padding-top: 6px;\n padding-bottom: 6px;\n}\n\n.todo-divider:hover {\n background: var(--todo-hover);\n}\n\n.title {\n display: flex;\n align-items: center;\n gap: 5px;\n flex-wrap: wrap;\n}\n\n.todo-divider.collapsed .title {\n gap: 4px;\n}\n\n.title-chevron {\n color: var(--todo-muted);\n}\n\n.title-label {\n font-size: 12px;\n line-height: 1;\n font-weight: 700;\n color: var(--todo-title);\n margin-right: 4px;\n letter-spacing: 0.01em;\n}\n\n.title-summary {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 32px;\n height: 17px;\n padding: 0 6px;\n border-radius: 999px;\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n background: var(--todo-summary-bg);\n border: 1px solid var(--todo-summary-border);\n color: var(--todo-summary-text);\n}\n\n.title-meta {\n font-size: 10px;\n line-height: 1;\n color: var(--todo-muted);\n}\n\n.todo-list {\n padding: 0 6px 6px;\n max-height: 180px;\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: thin;\n scrollbar-color: var(--ai-scrollbar-thumb) transparent;\n border-top: 1px solid var(--todo-divider);\n}\n\n.todo-list::-webkit-scrollbar {\n width: 6px;\n}\n\n.todo-list::-webkit-scrollbar-thumb {\n background: var(--ai-scrollbar-thumb);\n border-radius: 999px;\n}\n\n.todo-list::-webkit-scrollbar-thumb:hover {\n background: var(--ai-scrollbar-thumb-hover);\n}\n\n.todo-item {\n padding: 3px 8px;\n}\n\n.todo-row {\n display: flex;\n align-items: center;\n gap: 0;\n}\n\n.todo-content {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n min-height: 24px;\n padding: 2px 8px;\n border-radius: 6px;\n}\n\n.todo-index {\n min-width: 14px;\n text-align: right;\n flex-shrink: 0;\n}\n\n.indicator {\n width: 16px;\n height: 16px;\n border: 0;\n border-radius: 999px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n flex-shrink: 0;\n padding: 0;\n pointer-events: none;\n}\n\n.status-icon {\n display: block;\n}\n\n.todo-index,\n.title-text-base {\n font-size: 13px;\n line-height: 1.35;\n}\n\n.title-text {\n color: var(--todo-text);\n}\n\n.title-text-shimmer {\n --color-muted-foreground: color-mix(in srgb, var(--ai-plan-progress) 36%, transparent);\n --color-background: var(--ai-plan-progress);\n}\n\n.todo-content.pending .title-text,\n.todo-content.in-progress .title-text-shimmer,\n.todo-content.interrupted .title-text,\n.todo-content.completed .title-text {\n font-size: 12px;\n line-height: 1.35;\n}\n\n.todo-content.interrupted .title-text {\n color: var(--todo-interrupted-text);\n}\n\n.todo-content.completed .title-text {\n color: var(--todo-completed-text);\n}\n\n.todo-index {\n color: var(--todo-index);\n font-size: 11px;\n}\n\n.completed .indicator {\n color: var(--todo-completed);\n}\n\n.pending .indicator {\n color: var(--todo-pending);\n}\n\n.in-progress .indicator {\n color: var(--todo-progress);\n}\n\n.interrupted .indicator {\n color: var(--todo-interrupted);\n}\n\n.completed-icon {\n color: var(--todo-completed);\n}\n\n.pending-icon {\n color: var(--todo-pending);\n}\n\n.in-progress-icon {\n color: var(--todo-progress);\n animation: todo-spin 1.4s linear infinite;\n}\n\n.interrupted-icon {\n color: var(--todo-interrupted);\n}\n\n@keyframes todo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n</style>\n","<script setup lang=\"ts\">\nimport { ref, onMounted, provide } from 'vue'\nimport type { AttachmentTriggerSlotProps, PromptInputMessage } from './lib/input-types'\nimport type { ChatMessage, ChatStatus, ChatFile, CustomContent } from './lib/message-types'\nimport type { AiBotTheme } from './lib/theme'\nimport { fetchModels, getDefaultModel, type ModelInfo } from './lib/models'\nimport type { ToolEventPayload, ToolEventPhase, ToolEventState } from './lib/tool-events'\nimport { Client } from '@langchain/langgraph-sdk'\nimport { createThread, loadThreadHistory } from './lib/thread'\nimport { PORTAL_HOST_KEY } from './lib/portal-host'\n\nimport ChatHeader from './ChatHeader.vue'\nimport ChatMessages from './ChatMessages.vue'\nimport ChatInput from './ChatInput.vue'\nimport { Loader } from './ai-elements/loader'\nimport GeneratedFiles from './GeneratedFiles.vue'\nimport TodoList from './TodoList.vue'\n\ninterface Props {\n assistantId?: string\n assistantName?: string\n systemPrompt?: string\n threadId?: string\n userId?: string\n showHeaderActions?: boolean\n suggestions?: string[]\n apiUrl?: string\n apiKey?: string\n theme?: AiBotTheme\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n assistantId: 'research',\n assistantName: 'Chat',\n systemPrompt: '你是一个有用的助手,帮用户解决各种问题。',\n userId: 'user001',\n showHeaderActions: true,\n suggestions: () => [],\n apiUrl: 'http://localhost:2024',\n apiKey: undefined,\n theme: 'light'\n})\n\ndefineSlots<{\n empty?: (props: { sendMessage: (message: string, files?: ChatFile[]) => void }) => any\n custom?: (props: { customContent: CustomContent, threadId: string | null }) => any\n 'attachment-trigger'?: (props: AttachmentTriggerSlotProps) => any\n}>()\n\n// LangGraph Client\nconst client = new Client({\n apiUrl: props.apiUrl,\n apiKey: props.apiKey || undefined\n})\n\n// 状态\nconst isMaximized = ref(false)\nconst threadId = ref<string | null>(null)\nconst portalHost = ref<HTMLElement | null>(null)\nprovide(PORTAL_HOST_KEY, { portalHost })\nconst status = ref<ChatStatus>('ready')\nconst runId = ref<string>('')\nconst useWebSearch = ref(false)\nconst modelSelectorOpen = ref(false)\nconst isLoading = ref(true)\n\n// 消息\nconst messages = ref<ChatMessage[]>([])\n\n// 建议问题(支持动态更新)\nconst suggestions = ref<string[]>([])\n\nconst initialTodos = ref<any[]>([])\nconst todoToolEvents = ref<ToolEventPayload[]>([])\n\nfunction isTodoTool(toolName?: string): boolean {\n const name = toolName || ''\n return name.includes('todo') || name === 'write_todos'\n}\n\nfunction handleToolEvent(params: {\n phase: ToolEventPhase\n id?: string\n name?: string\n rawArgs?: string\n result?: string\n state: ToolEventState\n}) {\n // ChatBot 只捕获通用工具事件,按工具名把 todo 事件分发给 TodoList。\n if (!isTodoTool(params.name)) return\n\n todoToolEvents.value = [...todoToolEvents.value, {\n phase: params.phase,\n id: params.id,\n name: params.name,\n args: params.rawArgs,\n result: params.result,\n state: params.state\n }]\n}\n\n// 模型列表\nconst models = ref<ModelInfo[]>([])\nconst currentModel = ref<ModelInfo | null>(null)\n\n// 初始化\nonMounted(async () => {\n isLoading.value = true\n // 初始化建议问题\n suggestions.value = [...props.suggestions]\n\n // 并行获取模型列表和加载历史\n await Promise.all([\n (async () => {\n const data = await fetchModels(props.apiUrl)\n models.value = data\n currentModel.value = getDefaultModel(data) || null\n })(),\n props.threadId ? (async () => {\n const tid = await createThread(client, props.threadId, props.userId)\n threadId.value = tid\n messages.value = await loadThreadHistory(\n client,\n tid,\n (questions) => {\n suggestions.value = questions\n },\n (todos) => {\n initialTodos.value = todos\n }\n )\n })() : Promise.resolve()\n ])\n isLoading.value = false\n})\n\n// 切换最大化状态\nfunction toggleMaximize() {\n isMaximized.value = !isMaximized.value\n emit('update:isMaximized', isMaximized.value)\n}\n\n// 发送消息\nasync function handleSubmit(userMessage: string, files: ChatFile[] = []) {\n // 统一状态控制:忙碌状态不允许发送\n if (status.value === 'streaming') return\n status.value = 'streaming'\n\n // 构建消息内容:文本 + 附件\n const contentBlocks: any[] = []\n\n // 添加文本内容\n if (userMessage.trim()) {\n contentBlocks.push({ type: 'text', text: userMessage })\n }\n\n // 添加附件内容\n for (const file of files) {\n const mimeType = file.mediaType || 'application/octet-stream'\n const filename = file.filename || file.id || 'unknown'\n const rawData = file.data || file.url || ''\n const isDataUrl = rawData.startsWith('data:')\n const base64Data = isDataUrl ? rawData.split(',')[1] || '' : ''\n const normalizedType = file.type || (isDataUrl ? (mimeType.startsWith('image/') ? 'image' : 'file') : 'file_url')\n\n if ((normalizedType === 'file' || normalizedType === 'image') && base64Data) {\n if (normalizedType === 'image') {\n contentBlocks.push({\n type: 'image',\n mimeType,\n data: base64Data,\n metadata: { name: filename }\n })\n } else {\n contentBlocks.push({\n type: 'file',\n mimeType,\n data: base64Data,\n metadata: { filename }\n })\n }\n continue\n }\n\n if (file.url) {\n contentBlocks.push({\n type: 'file_url',\n url: file.url,\n mimeType,\n metadata: { filename }\n })\n }\n }\n\n // 添加用户消息到本地列表\n const userMessageId = `human-${Date.now()}`\n messages.value = [\n ...messages.value,\n {\n key: userMessageId,\n type: 'human',\n content: userMessage,\n files: files.map(f => ({ url: f.url, mediaType: f.mediaType, filename: f.filename }))\n }\n ]\n\n try {\n if (!threadId.value) {\n const thread = await client.threads.create({\n metadata: {\n user_id: props.userId,\n name: userMessage.slice(0, 50)\n }\n })\n threadId.value = thread.thread_id\n }\n\n const streamResponse = client.runs.stream(\n threadId.value!,\n props.assistantId,\n {\n input: {\n messages: [\n ...(props.systemPrompt ? [{\n type: 'system' as const,\n content: [{ type: 'text', text: props.systemPrompt }]\n }] : []),\n {\n type: 'human' as const,\n content: contentBlocks\n }\n ]\n },\n config: {\n tags: ['serv'],\n configurable: {\n model_provider: currentModel.value?.provider || 'openai',\n model: currentModel.value?.name || '',\n base_url: currentModel.value?.base_url || ''\n }\n },\n metadata: {\n user_id: props.userId,\n name: userMessage.slice(0, 50)\n },\n streamMode: ['messages-tuple', 'custom'],\n stream_resumable: false,\n on_disconnect: 'cancel'\n } as any\n )\n\n // 添加空的助手消息\n const assistantMessageId = `ai-${Date.now()}`\n messages.value = [\n ...messages.value,\n {\n key: assistantMessageId,\n type: 'ai',\n content: '',\n batchId: ''\n }\n ]\n\n let assistantContent = ''\n // 使用 message.id + index 跟踪同一条流式工具调用,避免 chunks 的空 id / 空 name 无法匹配。\n const assistantToolCalls = new Map<string, { id: string; name: string; args: string; messageKey?: string }>()\n let needNewAssistantMessage = false // 是否需要创建新的 assistant 消息\n\n // 辅助函数:创建工具消息\n function createToolMessage(toolCallId: string, name: string, args: string, state: string): ChatMessage {\n return {\n key: `tool-${toolCallId}-${Date.now()}`,\n type: 'tool',\n content: '',\n batchId: runId.value,\n toolCalls: [{\n id: toolCallId,\n name: name,\n args: args,\n result: '',\n state: state\n }]\n }\n }\n\n // 辅助函数:更新工具消息\n function updateToolMessage(messageKey: string, updates: { args?: string; result?: string; state?: string }) {\n const msg = messages.value[messageKey]\n if (msg && msg.toolCalls && msg.toolCalls.length > 0) {\n if (updates.args !== undefined) {\n msg.toolCalls[0].args = updates.args\n }\n if (updates.result !== undefined) {\n msg.toolCalls[0].result = updates.result\n }\n if (updates.state !== undefined) {\n msg.toolCalls[0].state = updates.state\n }\n }\n }\n\n // 流式处理 LangGraph SDK 返回的消息\n for await (const chunk of streamResponse) {\n const chunkEvent = chunk.event as string\n const data = chunk.data as any\n\n // 从 metadata 事件中获取 run_id\n if (chunkEvent === 'metadata' && data?.run_id) {\n runId.value = data.run_id\n }\n\n // 处理 custom 事件\n if (chunkEvent === 'custom') {\n handleCustomEvent(data)\n\n // suggested_questions 类型不外发为消息,只更新 suggestions\n if (data?.type === 'suggested_questions') {\n continue\n }\n\n // 将其他 custom 消息添加到消息列表\n const customContent: CustomContent = {\n type: data?.type || 'unknown',\n content: data?.content\n }\n const customMessageId = `custom-${Date.now()}`\n messages.value = [\n ...messages.value,\n {\n key: customMessageId,\n type: 'custom',\n content: '',\n customContent\n }\n ]\n console.log('📦 Custom 消息:', customContent)\n continue\n }\n\n if (chunkEvent === 'messages' || chunkEvent === 'messages/partial') {\n const messageArray = Array.isArray(data) ? data : [data]\n const message = messageArray[0] as any\n\n // 从消息元数据中获取 run_id\n const messageMeta = messageArray[1] as any\n if (messageMeta?.run_id) {\n runId.value = messageMeta.run_id\n }\n\n if (message) {\n // 获取消息类型\n const messageType = message.type\n\n // 处理工具消息 - tool 类型(阶段4:结果返回)\n // 更新已有的工具消息,而不是创建新的\n if (messageType === 'tool') {\n const toolCallId = message.tool_call_id\n const toolName = message.name || '未知工具'\n const toolResult = typeof message.content === 'string' ? message.content : JSON.stringify(message.content)\n const toolStatus = message.status\n\n // 阶段4:根据 tool_call_id 找回前面阶段累加好的原始参数。\n let foundToolCall: { id: string; name: string; args: string; messageKey?: string } | undefined\n for (const [key, tc] of assistantToolCalls) {\n if (tc.id === toolCallId) {\n foundToolCall = tc\n // 找到后删除,释放内存\n assistantToolCalls.delete(key)\n break\n }\n }\n\n // 映射后端状态到 UI 状态\n const mapToolStatus = (status: string): string => {\n switch (status) {\n case 'success': return 'completed'\n case 'error': return 'error'\n case 'running': return 'running'\n default: return 'completed'\n }\n }\n const uiState = mapToolStatus(toolStatus)\n\n // 工具结果优先回填已有工具消息,找不到时再兜底创建一条。\n if (foundToolCall && foundToolCall.messageKey !== undefined) {\n // 更新已有的工具消息\n updateToolMessage(foundToolCall.messageKey, {\n args: foundToolCall.args,\n result: toolResult,\n state: uiState\n })\n } else {\n // 没有找到对应的工具消息,创建新的(兼容情况)\n const toolMessageId = `tool-${toolCallId}-${Date.now()}`\n const toolMessage: ChatMessage = {\n key: toolMessageId,\n type: 'tool',\n content: toolResult,\n batchId: runId.value,\n toolCalls: [{\n id: toolCallId,\n name: toolName,\n args: foundToolCall?.args || '',\n result: toolResult,\n state: uiState,\n error: toolStatus === 'error' ? toolResult : undefined\n }]\n }\n messages.value.push(toolMessage)\n }\n\n // 把阶段4结果交给通用工具事件分发器,由具体工具自行消费。\n handleToolEvent({\n phase: 'tool_result',\n id: toolCallId,\n name: toolName,\n rawArgs: foundToolCall?.args || '',\n result: toolResult,\n state: uiState as ToolEventState\n })\n\n console.log('🔧 阶段4 - 工具结果返回:', {\n name: toolName,\n id: toolCallId,\n args: foundToolCall?.args || '',\n result: toolResult,\n status: toolStatus,\n messageCount: messages.value.length\n })\n\n // 标记下一条 AI 消息需要创建新消息\n needNewAssistantMessage = true\n\n continue // 跳过后续处理\n }\n\n // 阶段3:tool_call_chunks 已经结束,但工具执行结果可能还没返回。\n if (message.chunk_position === 'last') {\n for (const [, tc] of assistantToolCalls) {\n if (tc.messageKey !== undefined) {\n updateToolMessage(tc.messageKey, { state: 'running' })\n }\n // 这里继续透传生命周期事件,让具体工具决定是否需要“运行中”过渡态。\n handleToolEvent({\n phase: 'tool_call_finished',\n id: tc.id,\n name: tc.name,\n rawArgs: tc.args,\n state: 'running'\n })\n }\n console.log('🛑 阶段3 - 工具调用结束', {\n chunk_position: message.chunk_position,\n toolCallsCount: assistantToolCalls.size,\n allToolCalls: Array.from(assistantToolCalls.values()).map(t => ({ id: t.id, name: t.name, args: t.args }))\n })\n }\n\n // 阶段1-2:先记录工具声明,再逐块累加原始参数字符串。\n const messageId = message.id\n const hasToolCalls = message.tool_calls && message.tool_calls.length > 0\n const hasChunks = message.tool_call_chunks && message.tool_call_chunks.length > 0\n\n if (hasToolCalls || hasChunks) {\n // 阶段1:tool_calls 到达,只拿稳定的 id/name,args 以后续 chunks 为准。\n if (hasToolCalls) {\n for (const tc of message.tool_calls) {\n const index = message.tool_calls.indexOf(tc)\n const messageKey = `${messageId}_${index}`\n\n const existing = assistantToolCalls.get(messageKey)\n if (!existing) {\n // 新建 - 创建工具消息并添加到 messages\n const toolMsg = createToolMessage(tc.id, tc.name, '', 'start')\n messages.value.push(toolMsg)\n // 记录消息在数组中的索引\n const msgIndex = messages.value.length - 1\n\n assistantToolCalls.set(messageKey, {\n id: tc.id,\n name: tc.name,\n args: '',\n messageKey: msgIndex.toString()\n })\n // tool_calls 的 args 常常为空对象,这里只透传原始字符串,不做解释。\n handleToolEvent({\n phase: 'tool_call_started',\n id: tc.id,\n name: tc.name,\n rawArgs: typeof tc.args === 'string' ? tc.args : '',\n state: 'start'\n })\n console.log('📝 阶段1 - 工具调用开始:', {\n messageId,\n index,\n toolCallId: tc.id,\n name: tc.name,\n msgIndex\n })\n } else {\n // 更新 - 只更新 id 和 name\n if (tc.id) existing.id = tc.id\n if (tc.name) existing.name = tc.name\n if (tc.name) existing.name = tc.name\n // 不覆盖 args,保留 tool_call_chunks 累加的结果\n }\n }\n }\n\n // 阶段2:tool_call_chunks 才是真正的原始参数流。\n if (hasChunks) {\n for (const tcChunk of message.tool_call_chunks) {\n const index = tcChunk.index\n if (index === undefined) continue\n\n const messageKey = `${messageId}_${index}`\n\n let existing = assistantToolCalls.get(messageKey)\n\n if (!existing) {\n // 如果还没有工具调用记录,用 chunks 创建\n const toolMsg = createToolMessage(tcChunk.id || '', tcChunk.name || '', tcChunk.args || '', 'running')\n messages.value.push(toolMsg)\n const msgIndex = messages.value.length - 1\n\n assistantToolCalls.set(messageKey, {\n id: tcChunk.id || '',\n name: tcChunk.name || '',\n args: tcChunk.args || '',\n messageKey: msgIndex.toString()\n })\n // 首块 chunk 到达时就通知业务侧,便于展示“运行中”的早期状态。\n handleToolEvent({\n phase: 'tool_args_streaming',\n id: tcChunk.id || '',\n name: tcChunk.name || '',\n rawArgs: tcChunk.args || '',\n state: 'running'\n })\n console.log('📝 阶段1 - 工具调用开始:', {\n messageId,\n index,\n toolCallId: tcChunk.id || '(暂无)',\n name: tcChunk.name || '(暂无)',\n msgIndex\n })\n } else {\n // 已有记录 - 累加有实际内容的 args 并更新工具消息\n if (tcChunk.args && tcChunk.args.trim()) {\n existing.args = (existing.args || '') + tcChunk.args\n // 实时更新工具消息的参数和状态\n if (existing.messageKey) {\n updateToolMessage(existing.messageKey, { args: existing.args, state: 'running' })\n }\n // 后续 chunk 持续透传完整 rawArgs,具体工具自己决定何时解析。\n handleToolEvent({\n phase: 'tool_args_streaming',\n id: existing.id || tcChunk.id || '',\n name: existing.name || tcChunk.name || '',\n rawArgs: existing.args,\n state: 'running'\n })\n }\n // 补充 id 和 name\n if (tcChunk.id && !existing.id) existing.id = tcChunk.id\n if (tcChunk.name) existing.name = tcChunk.name\n\n console.log('📝 阶段2 - args 流式累加:', {\n messageId,\n index,\n newArgs: tcChunk.args,\n accumulatedArgs: existing.args\n })\n }\n }\n }\n }\n\n // 处理 AI 消息 - AIMessageChunk 类型,流式累加 content\n // 解析消息内容\n let content = ''\n if (typeof message.content === 'string') {\n content = message.content\n } else if (Array.isArray(message.content)) {\n content = message.content\n .filter((block: any) => block.type === 'text')\n .map((block: any) => block.text)\n .join('')\n }\n\n // 检查是否需要创建新消息(tool 消息后第一条 AI 消息)\n if (needNewAssistantMessage) {\n // 标记当前 ai 消息完成\n for (let i = messages.value.length - 1; i >= 0; i--) {\n if (messages.value[i].type === 'ai') {\n break\n }\n }\n\n // 创建新的 ai 消息\n const newAssistantMessageId = `ai-${Date.now()}`\n messages.value.push({\n key: newAssistantMessageId,\n type: 'ai',\n content: '',\n batchId: runId.value\n })\n assistantContent = ''\n needNewAssistantMessage = false\n }\n\n // 更新消息内容 - 后端返回的是增量内容,需要累加\n // content 可能是空字符串,所以用 !== undefined 来判断\n if (content !== undefined) {\n // 直接累加内容\n assistantContent += content\n }\n\n // 找到最后一条 ai 消息并更新\n let lastAssistantIndex = -1\n for (let i = messages.value.length - 1; i >= 0; i--) {\n if (messages.value[i].type === 'ai') {\n lastAssistantIndex = i\n break\n }\n }\n if (lastAssistantIndex >= 0) {\n messages.value[lastAssistantIndex].content = assistantContent\n messages.value[lastAssistantIndex].batchId = runId.value\n }\n }\n }\n }\n\n const lastIndex = messages.value.length - 1\n if (lastIndex >= 0) {\n messages.value[lastIndex].batchId = runId.value\n }\n\n status.value = 'ready'\n } catch (error: any) {\n console.error('Error sending message:', error)\n\n // 提取错误信息\n let errorDisplayMessage = '抱歉,发生了一些错误,请稍后重试。'\n if (error) {\n // 尝试从 error 对象中提取详细信息\n const errorMsg = error.message || error.error?.message || String(error)\n const errorType = error.error?.error || error.name || 'APIError'\n\n // 如果是 API 错误,显示更友好的信息\n if (errorMsg && errorMsg !== '[object Object]') {\n if (errorType === 'APIError' && errorMsg.includes('internal error')) {\n errorDisplayMessage = '服务内部错误,请稍后重试。'\n } else if (errorMsg.includes('timeout') || errorMsg.includes('Timeout')) {\n errorDisplayMessage = '请求超时,请稍后重试。'\n } else if (errorMsg.includes('network') || errorMsg.includes('Network')) {\n errorDisplayMessage = '网络连接失败,请检查网络后重试。'\n } else if (errorMsg.includes('401') || errorMsg.includes('unauthorized')) {\n errorDisplayMessage = '认证失败,请重新登录。'\n } else if (errorMsg.includes('403') || errorMsg.includes('forbidden')) {\n errorDisplayMessage = '没有权限执行此操作。'\n } else if (errorMsg.includes('429') || errorMsg.includes('rate limit')) {\n errorDisplayMessage = '请求过于频繁,请稍后再试。'\n } else {\n errorDisplayMessage = `抱歉,发生错误: ${errorMsg}`\n }\n }\n }\n\n const errorMessageId = `error-${Date.now()}`\n messages.value = [\n ...messages.value,\n {\n key: errorMessageId,\n type: 'ai',\n content: errorDisplayMessage,\n batchId: errorMessageId\n }\n ]\n status.value = 'ready'\n }\n}\n\n// 处理表单提交\nfunction handleFormSubmit(message: PromptInputMessage) {\n const hasText = !!message.text\n const hasAttachments = message.files?.length > 0\n\n if (!hasText && !hasAttachments) {\n return\n }\n\n const text = message.text?.trim() || ''\n handleSubmit(text || '仅发送了附件', message.files || [])\n}\n\n// 处理停止按钮点击\nasync function handleStop() {\n console.log('🛑 点击停止按钮:', { threadId: threadId.value, runId: runId.value })\n if (threadId.value && runId.value) {\n try {\n console.log('📡 发送 cancel 请求...')\n await client.runs.cancel(threadId.value, runId.value)\n console.log('✅ cancel 请求成功')\n status.value = 'ready'\n }\n catch (error) {\n console.error('❌ cancel 请求失败:', error)\n status.value = 'ready'\n }\n }\n else {\n console.log('⚠️ 缺少 threadId 或 runId,直接重置状态')\n status.value = 'ready'\n }\n}\n\n// 选择建议\nfunction handleSuggestionClick(suggestion: string) {\n handleSubmit(suggestion)\n}\n\n// 待办事项处理\nconst emit = defineEmits<{\n close: []\n 'update:isMaximized': [value: boolean]\n}>()\n\n// 关闭聊天窗口\nfunction handleClose() {\n emit('close')\n}\n\n// 处理自定义事件\nfunction handleCustomEvent(data: any) {\n // 处理 suggested_questions 类型\n if (data?.type === 'suggested_questions' && Array.isArray(data?.content)) {\n suggestions.value = data.content\n console.log('📝 更新建议问题:', data.content)\n return\n }\n\n console.log('Custom event received:', data)\n}\n</script>\n\n<template>\n <div class=\"chat-bot\" :data-ai-theme=\"props.theme\">\n <div ref=\"portalHost\" class=\"chat-bot-portal-host\" />\n <div class=\"chat-window\" :class=\"{ maximized: isMaximized }\">\n <ChatHeader\n :title=\"assistantName\"\n :is-maximized=\"isMaximized\"\n :show-header-actions=\"showHeaderActions\"\n @close=\"handleClose\"\n @toggle-maximize=\"toggleMaximize\"\n />\n\n <!-- 空状态:messages 为空时显示 -->\n <div v-if=\"!isLoading && messages.length === 0\" class=\"flex-1 overflow-y-hidden flex flex-col items-center justify-center\">\n <slot name=\"empty\" :send-message=\"handleSubmit\">\n <div class=\"default-empty-state\">\n <div class=\"default-empty-badge\">AI</div>\n <h2 class=\"default-empty-title\">欢迎使用 {{ assistantName }}</h2>\n <p class=\"default-empty-desc\">请输入你的问题,开始一段新的对话。</p>\n </div>\n </slot>\n </div>\n <!-- 有消息时显示 ChatMessages -->\n <ChatMessages\n v-else\n :messages=\"messages\"\n :is-streaming=\"status === 'streaming'\"\n :theme=\"props.theme\"\n >\n <!-- custom 消息:透传插槽 -->\n <template #custom=\"{ customContent }\">\n <slot name=\"custom\" :customContent=\"customContent\" :threadId=\"threadId\">\n <GeneratedFiles\n v-if=\"customContent?.type === 'generated_files'\"\n :custom-content=\"customContent\"\n :api-url=\"props.apiUrl\"\n :thread-id=\"threadId\"\n />\n </slot>\n </template>\n </ChatMessages>\n <!-- 待办事项列表 -->\n <TodoList\n :initial-todos=\"initialTodos\"\n :tool-events=\"todoToolEvents\"\n :chat-status=\"status\"\n />\n\n <ChatInput\n :status=\"status\"\n :current-model=\"currentModel\"\n :models=\"models\"\n :suggestions=\"suggestions\"\n :use-web-search=\"useWebSearch\"\n v-model:modelSelectorOpen=\"modelSelectorOpen\"\n @submit=\"handleFormSubmit\"\n @stop=\"handleStop\"\n @select-suggestion=\"handleSuggestionClick\"\n @update:current-model=\"currentModel = $event\"\n @update:use-web-search=\"useWebSearch = $event\"\n >\n <template #attachment-trigger=\"slotProps\">\n <slot name=\"attachment-trigger\" v-bind=\"slotProps\" />\n </template>\n </ChatInput>\n\n <!-- 加载遮罩 -->\n <div v-if=\"isLoading\" class=\"loading-mask\">\n <Loader :size=\"24\" />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.chat-bot {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.chat-bot-portal-host {\n position: absolute;\n inset: 0;\n z-index: 30;\n pointer-events: none;\n isolation: isolate;\n}\n\n.chat-bot-portal-host > * {\n pointer-events: auto;\n}\n\n.chat-window {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--ai-surface);\n border-radius: 8px;\n border: 1px solid var(--ai-border-subtle);\n box-shadow: var(--ai-shadow);\n overflow: hidden;\n position: relative;\n}\n\n.chat-window.maximized {\n border-radius: 8px;\n border: 1px solid var(--ai-border-subtle);\n}\n\n.default-empty-state {\n display: flex;\n min-height: 400px;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px 24px;\n text-align: center;\n}\n\n.default-empty-badge {\n display: grid;\n width: 56px;\n height: 56px;\n place-items: center;\n border-radius: 999px;\n background: var(--ai-accent-soft);\n color: var(--ai-accent-soft-foreground);\n font-size: 18px;\n font-weight: 700;\n}\n\n.default-empty-title {\n margin: 16px 0 8px;\n font-size: 28px;\n line-height: 1.2;\n color: var(--foreground);\n}\n\n.default-empty-desc {\n max-width: 520px;\n margin: 0;\n line-height: 1.6;\n color: var(--muted-foreground);\n}\n\n.loading-mask {\n position: absolute;\n inset: 0;\n background: var(--ai-overlay);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n z-index: 10;\n}\n\n</style>\n","<script setup lang=\"ts\">\nimport { BotMessageSquare, BotOff, X } from 'lucide-vue-next'\n\ninterface Props {\n isExpanded: boolean\n}\n\ndefineProps<Props>()\n\nconst emit = defineEmits<{\n toggle: []\n}>()\n</script>\n\n<template>\n <button class=\"float-button\" :class=\"{ expanded: isExpanded }\" @click=\"emit('toggle')\" type=\"button\">\n <span class=\"icon-wrapper\">\n <BotMessageSquare class=\"icon-svg\" />\n <X :size=\"16\" :stroke-width=\"2\" absoluteStrokeWidth class=\"icon-svg\"/>\n<!-- <BotOff class=\"icon-svg\" />-->\n </span>\n </button>\n</template>\n\n<style scoped>\n.float-button {\n position: relative;\n width: 42px;\n height: 42px;\n border-radius: 50%;\n background: linear-gradient(135deg, var(--ai-fab-bg) 0%, var(--ai-fab-bg-strong) 100%);\n border: none;\n cursor: pointer;\n color: var(--primary-foreground);\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: var(--ai-fab-shadow);\n transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s;\n}\n\n.float-button:hover {\n transform: scale(1.05);\n box-shadow: var(--ai-fab-shadow-hover);\n}\n\n.float-button:active {\n transform: scale(0.95);\n}\n\n.icon-wrapper {\n position: relative;\n width: 24px;\n height: 24px;\n}\n\n.icon-svg {\n position: absolute;\n top: 0;\n left: 0;\n width: 24px;\n height: 24px;\n transition: opacity 0.3s, transform 0.3s;\n}\n\n/* 第一个图标 - 默认显示 */\n.icon-wrapper .icon-svg:first-child {\n opacity: 1;\n transform: rotate(0deg);\n}\n\n/* 第二个图标 - 默认隐藏 */\n.icon-wrapper .icon-svg:last-child {\n opacity: 0;\n transform: rotate(-90deg);\n}\n\n/* 展开状态 - 交换动画 */\n.float-button.expanded .icon-wrapper .icon-svg:first-child {\n opacity: 0;\n transform: rotate(90deg);\n}\n\n.float-button.expanded .icon-wrapper .icon-svg:last-child {\n opacity: 1;\n transform: rotate(0deg);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport type { AttachmentTriggerSlotProps } from './lib/input-types'\nimport type { ChatFile, CustomContent } from './lib/message-types'\nimport type { AiBotTheme } from './lib/theme'\nimport ChatBot from './ChatBot.vue'\nimport FloatButton from './FloatButton.vue'\n\ninterface Props {\n assistantId?: string\n assistantName?: string\n defaultExpanded?: boolean\n systemPrompt?: string\n threadId?: string\n userId?: string\n suggestions?: string[]\n apiUrl?: string\n apiKey?: string\n width?: number | string\n height?: number | string\n theme?: AiBotTheme\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n assistantId: 'research',\n assistantName: 'Chat',\n defaultExpanded: false,\n systemPrompt: '用中文回答',\n userId: 'user001',\n suggestions: () => [],\n apiUrl: 'http://localhost:2024',\n apiKey: undefined,\n width: 400,\n height: 'calc(100vh - 90px)',\n theme: 'light'\n})\n\ndefineSlots<{\n empty?: (props: { sendMessage: (message: string, files?: ChatFile[]) => void }) => any\n custom?: (props: { customContent: CustomContent, threadId: string | null }) => any\n 'attachment-trigger'?: (props: AttachmentTriggerSlotProps) => any\n}>()\n\nconst isExpanded = ref(props.defaultExpanded)\nconst isMaximized = ref(false)\nconst chatWidth = ref(typeof props.width === 'number' ? props.width : 500)\nconst isResizing = ref(false)\n\nfunction toggleExpanded() {\n isExpanded.value = !isExpanded.value\n if (!isExpanded.value) {\n isMaximized.value = false\n }\n}\n\nfunction handleMaximizeChange(value: boolean) {\n isMaximized.value = value\n}\n\n// 拖拽调整宽度\nfunction startResize(e: MouseEvent) {\n e.preventDefault()\n isResizing.value = true\n document.addEventListener('mousemove', handleResize)\n document.addEventListener('mouseup', stopResize)\n}\n\nfunction handleResize(e: MouseEvent) {\n if (!isResizing.value) return\n const newWidth = window.innerWidth - e.clientX - 20\n chatWidth.value = Math.max(300, Math.min(1400, newWidth))\n}\n\nfunction stopResize() {\n isResizing.value = false\n document.removeEventListener('mousemove', handleResize)\n document.removeEventListener('mouseup', stopResize)\n}\n</script>\n\n<template>\n <div class=\"ask-ai-bot\" :data-ai-theme=\"props.theme\">\n <!-- 聊天窗口 -->\n <Transition name=\"slide-up\">\n <div\n v-show=\"isExpanded\"\n class=\"chat-window-container\"\n :class=\"{ maximized: isMaximized }\"\n :style=\"!isMaximized ? {\n width: typeof props.width === 'number' ? `${chatWidth}px` : props.width,\n height: typeof props.height === 'number' ? `${props.height}px` : props.height\n } : {}\"\n >\n <ChatBot\n :api-url=\"apiUrl\"\n :api-key=\"apiKey\"\n :assistant-id=\"assistantId\"\n :assistant-name=\"assistantName\"\n :system-prompt=\"systemPrompt\"\n :thread-id=\"threadId\"\n :user-id=\"userId\"\n :suggestions=\"suggestions\"\n :theme=\"props.theme\"\n @close=\"toggleExpanded\"\n @update:is-maximized=\"handleMaximizeChange\"\n >\n <!-- 透传插槽 -->\n <template #empty=\"slotProps\">\n <slot name=\"empty\" v-bind=\"slotProps\" />\n </template>\n <template #custom=\"slotProps\">\n <slot name=\"custom\" v-bind=\"slotProps\" />\n </template>\n <template #attachment-trigger=\"slotProps\">\n <slot name=\"attachment-trigger\" v-bind=\"slotProps\" />\n </template>\n </ChatBot>\n <!-- 拖拽手柄 -->\n <div\n v-if=\"!isMaximized\"\n class=\"resize-handle\"\n @mousedown=\"startResize\"\n />\n </div>\n </Transition>\n\n <FloatButton\n :is-expanded=\"isExpanded\"\n @toggle=\"toggleExpanded\"\n />\n </div>\n</template>\n\n<style scoped>\n.ask-ai-bot {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 99;\n}\n\n.chat-window-container {\n position: fixed;\n top: 20px;\n right: 20px;\n transition: height 0.3s ease;\n}\n\n.chat-window-container.maximized {\n top: 20px;\n right: 20px;\n left: 20px;\n width: auto;\n height: calc(100vh - 40px);\n}\n\n/* 拖拽手柄 */\n.resize-handle {\n position: absolute;\n top: 0;\n left: 0;\n width: 6px;\n height: 100%;\n cursor: ew-resize;\n background: transparent;\n}\n\n@media (max-width: 480px) {\n .chat-window-container {\n width: calc(100vw - 40px);\n height: 80vh;\n right: -10px;\n }\n}\n\n.slide-up-enter-active,\n.slide-up-leave-active {\n transition: all 0.3s ease;\n}\n\n.slide-up-enter-from,\n.slide-up-leave-to {\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n}\n</style>\n"],"names":["fetchModels","apiUrl","result","error","getDefaultModel","models","m","getProviderByModelName","modelName","name","createThread","client","threadId","userId","loadThreadHistory","onSuggestedQuestions","onTodos","values","loadedMessages","langgraphMessages","i","msg","msgType","msgContent","content","b","toolCalls","_a","tc","j","nextMsg","toolMsgContent","toolCallId","toolStatus","toolState","status","toolCall","toolMessageId","generatedFiles","customContent","suggestedQuestions","todos","PORTAL_HOST_KEY","usePortalHost","ctx","inject","computed","props","__props","emit","__emit","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_toDisplayString","_hoisted_4","_createBlock","_unref","Minimize2Icon","Maximize2Icon","_createVNode","XIcon","cn","inputs","twMerge","clsx","getStateIcon","state","PlayCircle","Loader","CheckCircle","XCircle","toolNameMap","toolIconMap","BrainIcon","GlobeIcon","FileTextIcon","FolderSearchIcon","EyeIcon","FileEditIcon","SquarePen","FolderSearch","FileSearch","ZapIcon","ListTodoIcon","BookOpenCheck","getToolName","getToolIcon","WrenchIcon","isTodoTool","formatArgs","args","openStates","ref","toggle","id","_Fragment","_renderList","tool","$event","ChevronDownIcon","_resolveDynamicComponent","_normalizeClass","_withDirectives","_hoisted_5","_cache","_hoisted_6","_hoisted_7","_hoisted_8","delegatedProps","reactiveOmit","StickToBottom","_mergeProps","_renderSlot","_ctx","classes","Primitive","buttonVariants","cva","isAtBottom","scrollToBottom","useStickToBottomContext","showScrollButton","handleClick","$attrs","ArrowDownIcon","markdownThemes","getMessageClass","index","Conversation","ConversationContent","message","Message","ToolCall","MessageContent","MarkdownRender","_createTextVNode","ConversationScrollButton","PROMPT_INPUT_KEY","usePromptInput","context","AttachmentsKey","useAttachmentsContext","AttachmentKey","useAttachmentContext","getMediaCategory","data","mediaType","getAttachmentLabel","category","variant","mediaCategory","handleRemove","provide","label","isGrid","iconSize","fileUrl","showImage","showVideo","iconMap","ImageIcon","VideoIcon","Music2Icon","PaperclipIcon","iconComponent","imageAlt","remove","_variant","restProps","e","files","removeFile","asAttachmentData","file","Attachments","attachment","Attachment","AttachmentPreview","AttachmentInfo","AttachmentRemove","ROTATE_INTERVAL","CHIP_GAP","viewportRef","measureRefs","pageRanges","currentPageIndex","isHovered","rotationTimer","resizeObserver","shouldRotate","currentPageSuggestions","range","setMeasureRef","el","stopRotation","startRotation","handleMouseEnter","handleMouseLeave","buildPageRanges","viewportWidth","widths","_","width","ranges","start","widthSum","itemWidth","nextWidth","recalculatePages","nextTick","watch","onMounted","onBeforeUnmount","_Transition","suggestion","Suggestion","handleInputGroupAddonClick","currentTarget","target","_b","inputGroupAddonVariants","Button","inputGroupButtonVariants","modelValue","useVModel","Textarea","forwarded","useForwardPropsEmits","_withCtx","slotProps","emits","portalHost","DropdownMenuPortal","DropdownMenuContent","forwardedProps","useForwardProps","modelSelectorOpen","_useModel","inputText","hasFiles","fileInputRef","isLoading","f","setTextInput","val","resolveAttachmentType","url","addAttachments","incoming","existingFilenames","newAttachments","normalized","nanoid","type","normalizedName","addFiles","fileList","clearFiles","clearInput","openFileDialog","convertBlobUrlToDataUrl","blob","resolve","reader","sendMessage","processedFiles","item","dataUrl","isEmpty","selectedModelData","groupedModels","groups","model","provider","providers","handleModelSelect","isComposing","handleKeyDown","isLoadingStatus","lastFile","handlePaste","items","pastedFiles","buttonVariant","submitIcon","Loader2Icon","CornerDownLeftIcon","iconClass","isDisabled","handleSubmitClick","handleImageError","img","onFileChange","input","InputGroup","ChatSuggestions","PromptInputAttachmentsDisplay","InputGroupTextarea","InputGroupAddon","InputGroupButton","_hoisted_9","DropdownMenu","DropdownMenuTrigger","_hoisted_11","_hoisted_12","DropdownMenuItem","_hoisted_14","_hoisted_15","CheckIcon","LoaderIcon","ArrowUpRight","slots","useSlots","textContent","defaultSlot","vnode","dynamicSpread","componentClasses","componentStyle","MotionComponent","motion","processedEventCount","completedCount","todo","inProgressCount","interruptedCount","pendingCount","expanded","userCollapsed","toggleExpanded","syncExpandedWithTodos","nextTodos","isWriteTodosTool","toolName","normalizeTodoStatus","rawStatus","fallback","normalizeHistoricalTodoStatus","statusByPhase","event","mapRawTodos","rawTodos","fallbackState","mapHistoricalTodos","finalizeInProgressTodos","isRawTodoContainer","payload","parseRawTodoItems","raw","parseToolTodos","replaceWriteTodos","applyToolEvent","events","next","prev","ChevronsDown","ChevronsUp","Circle","LoaderCircle","Ban","CircleCheckBig","Shimmer","_hoisted_10","Client","isMaximized","runId","useWebSearch","messages","suggestions","initialTodos","todoToolEvents","handleToolEvent","params","currentModel","tid","questions","toggleMaximize","handleSubmit","userMessage","contentBlocks","mimeType","filename","rawData","isDataUrl","base64Data","normalizedType","userMessageId","createToolMessage","updateToolMessage","messageKey","updates","thread","streamResponse","_c","assistantMessageId","assistantContent","assistantToolCalls","needNewAssistantMessage","chunk","chunkEvent","handleCustomEvent","customMessageId","messageArray","messageMeta","toolResult","foundToolCall","key","uiState","toolMessage","t","messageId","hasToolCalls","hasChunks","existing","toolMsg","msgIndex","tcChunk","block","newAssistantMessageId","lastAssistantIndex","lastIndex","errorDisplayMessage","errorMsg","_d","errorType","_e","errorMessageId","handleFormSubmit","hasText","hasAttachments","text","handleStop","handleSuggestionClick","handleClose","ChatHeader","ChatMessages","GeneratedFiles","TodoList","ChatInput","BotMessageSquare","X","isExpanded","chatWidth","isResizing","handleMaximizeChange","value","startResize","handleResize","stopResize","newWidth","ChatBot","FloatButton"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/components/ai-bot/lib/models.ts","../src/components/ai-bot/lib/thread.ts","../src/components/ai-bot/lib/portal-host.ts","../src/components/ai-bot/ChatHeader.vue","../src/components/ai-bot/lib/utils.ts","../src/components/ai-bot/ToolCall.vue","../src/components/ai-bot/ai-elements/conversation/Conversation.vue","../src/components/ai-bot/ai-elements/conversation/ConversationContent.vue","../src/components/ai-bot/ui/button/Button.vue","../src/components/ai-bot/ui/button/index.ts","../src/components/ai-bot/ai-elements/conversation/ConversationScrollButton.vue","../src/components/ai-bot/ai-elements/message/Message.vue","../src/components/ai-bot/ai-elements/message/MessageContent.vue","../src/components/ai-bot/ChatMessages.vue","../src/components/ai-bot/lib/prompt-input.ts","../src/components/ai-bot/ai-elements/attachments/context.ts","../src/components/ai-bot/ai-elements/attachments/utils.ts","../src/components/ai-bot/ai-elements/attachments/Attachment.vue","../src/components/ai-bot/ai-elements/attachments/AttachmentInfo.vue","../src/components/ai-bot/ai-elements/attachments/AttachmentPreview.vue","../src/components/ai-bot/ai-elements/attachments/AttachmentRemove.vue","../src/components/ai-bot/ai-elements/attachments/Attachments.vue","../src/components/ai-bot/InputAttachmentsDisplay.vue","../src/components/ai-bot/ai-elements/suggestion/Suggestion.vue","../src/components/ai-bot/ChatSuggestions.vue","../src/components/ai-bot/ui/input-group/InputGroup.vue","../src/components/ai-bot/ui/input-group/InputGroupAddon.vue","../src/components/ai-bot/ui/input-group/InputGroupButton.vue","../src/components/ai-bot/ui/textarea/Textarea.vue","../src/components/ai-bot/ui/input-group/InputGroupTextarea.vue","../src/components/ai-bot/ui/input-group/index.ts","../src/components/ai-bot/ui/dropdown-menu/DropdownMenu.vue","../src/components/ai-bot/ui/dropdown-menu/DropdownMenuContent.vue","../src/components/ai-bot/ui/dropdown-menu/DropdownMenuItem.vue","../src/components/ai-bot/ui/dropdown-menu/DropdownMenuTrigger.vue","../src/components/ai-bot/ChatInput.vue","../src/components/ai-bot/ai-elements/loader/LoaderIcon.vue","../src/components/ai-bot/ai-elements/loader/Loader.vue","../src/components/ai-bot/GeneratedFiles.vue","../src/components/ai-bot/ai-elements/shimmer/Shimmer.vue","../src/components/ai-bot/TodoList.vue","../src/components/ai-bot/ChatBot.vue","../src/components/ai-bot/FloatButton.vue","../src/components/ai-bot/AskAiBot.vue"],"sourcesContent":["// 模型信息 (API 返回格式)\nexport interface ModelInfo {\n name: string\n provider: string\n base_url: string\n is_default?: boolean\n}\n\n// 获取模型列表\nexport async function fetchModels(apiUrl: string): Promise<ModelInfo[]> {\n try {\n const response = await fetch(`${apiUrl}/webapp/models`)\n const result = await response.json()\n if (result.success && result.data) {\n return result.data\n }\n return []\n } catch (error) {\n console.error('Failed to fetch models:', error)\n return []\n }\n}\n\n// 获取默认模型\nexport function getDefaultModel(models: ModelInfo[]): ModelInfo | undefined {\n return models.find(m => m.is_default) || models[0]\n}\n\n// 根据模型名获取对应的提供商\nexport function getProviderByModelName(modelName: string): string {\n const name = modelName.toLowerCase()\n\n if (name.startsWith('qwen') || name.includes('阿里') || name.includes('通义')) {\n return 'alibaba'\n }\n if (name.startsWith('glm') || name.includes('智谱') || name.includes('zhipuai')) {\n return 'zhipuai'\n }\n if (name.startsWith('deepseek') || name.includes('deepseek')) {\n return 'deepseek'\n }\n if (name.startsWith('minimax') || name.includes('minimax')) {\n return 'minimax'\n }\n if (name.includes('kimi') || name.includes('月之')) {\n return 'moonshotai'\n }\n if (name.includes('claude') || name.includes('anthropic')) {\n return 'anthropic'\n }\n if (name.includes('gpt') || name.includes('openai')) {\n return 'openai'\n }\n if (name.includes('gemini') || name.includes('google')) {\n return 'google'\n }\n if (name.includes('mistral')) {\n return 'mistral'\n }\n if (name.includes('llama')) {\n return 'llama'\n }\n\n return 'openai'\n}\n","import { Client } from '@langchain/langgraph-sdk'\nimport type { ChatMessage, CustomContent } from '../lib/message-types'\n\n// 创建线程\nexport async function createThread(\n client: Client,\n threadId?: string,\n userId?: string\n): Promise<string> {\n try {\n const thread = await client.threads.create({\n ...(threadId ? { threadId, ifExists: 'do_nothing' } : {}),\n metadata: {\n user_id: userId || 'user001',\n }\n })\n return thread.thread_id || threadId || ''\n } catch (error) {\n console.error('Failed to create thread:', error)\n return threadId || ''\n }\n}\n\n// 获取对话历史\nexport async function loadThreadHistory(\n client: Client,\n threadId: string,\n onSuggestedQuestions?: (questions: string[]) => void,\n onTodos?: (todos: any[]) => void\n): Promise<ChatMessage[]> {\n if (!threadId) return []\n\n try {\n const state = await client.threads.getState(threadId)\n const values = state.values as any\n\n if (!values?.messages || !Array.isArray(values.messages)) {\n return []\n }\n\n const loadedMessages: ChatMessage[] = []\n const langgraphMessages = values.messages\n\n let i = 0\n while (i < langgraphMessages.length) {\n const msg = langgraphMessages[i]\n const msgType = msg.type\n const msgContent = msg.content as any\n\n // system 消息 暂时屏蔽system 消息的显示\n if (msgType === 'system' && 1 + 1 === 3) {\n const content = typeof msgContent === 'string' ? msgContent : Array.isArray(msgContent)\n ? msgContent.filter((b: any) => b.type === 'text').map((b: any) => b.text).join('')\n : ''\n if (content) {\n loadedMessages.push({\n key: msg.id || `system-${Date.now()}-${Math.random()}`,\n type: 'system',\n content\n })\n }\n i++\n continue\n }\n\n // 处理 human/user 消息\n if (msgType === 'human' || msgType === 'user') {\n const content = typeof msgContent === 'string' ? msgContent : Array.isArray(msgContent)\n ? msgContent.filter((b: any) => b.type === 'text').map((b: any) => b.text).join('')\n : ''\n loadedMessages.push({\n key: msg.id || `human-${Date.now()}-${Math.random()}`,\n type: 'human',\n content\n })\n i++\n continue\n }\n\n // 处理 ai 消息\n if (msgType === 'ai') {\n const content = typeof msgContent === 'string' ? msgContent : Array.isArray(msgContent)\n ? msgContent.filter((b: any) => b.type === 'text').map((b: any) => b.text).join('')\n : ''\n\n // 获取 tool_calls\n const toolCalls = msg.tool_calls?.map((tc: any) => ({\n id: tc.id,\n name: tc.name,\n args: JSON.stringify(tc.args, null, 2),\n state: 'completed' as const,\n result: ''\n })) || []\n\n // 先添加 AI 消息\n loadedMessages.push({\n key: msg.id || `ai-${Date.now()}-${Math.random()}`,\n type: 'ai',\n content,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined\n })\n\n // 检查是否有工具调用,从紧跟着的 tool 消息中获取结果\n if (toolCalls.length > 0) {\n let j = i + 1\n while (j < langgraphMessages.length) {\n const nextMsg = langgraphMessages[j]\n if (nextMsg.type === 'tool') {\n const toolMsgContent = typeof nextMsg.content === 'string' ? nextMsg.content : JSON.stringify(nextMsg.content)\n const toolCallId = nextMsg.tool_call_id\n const toolStatus = nextMsg.status\n\n // 根据 status 映射状态\n const mapStatus = (status: string): string => {\n switch (status) {\n case 'success': return 'completed'\n case 'error': return 'error'\n default: return 'completed'\n }\n }\n const toolState = mapStatus(toolStatus)\n\n // 找到对应的 tool_call 并填充结果\n const toolCall = toolCalls.find(tc => tc.id === toolCallId)\n if (toolCall) {\n toolCall.result = toolMsgContent\n toolCall.state = toolState\n\n // 创建独立的工具消息\n const toolMessageId = `tool-${toolCallId}-${Date.now()}`\n loadedMessages.push({\n key: toolMessageId,\n type: 'tool',\n content: toolMsgContent,\n toolCalls: [{\n id: toolCallId,\n name: toolCall.name,\n args: toolCall.args,\n result: toolMsgContent,\n state: toolState,\n error: toolStatus === 'error' ? toolMsgContent : undefined\n }]\n })\n }\n j++\n } else {\n break\n }\n }\n }\n i++\n continue\n }\n\n i++\n }\n\n // 处理 generated_files 自定义消息\n const generatedFiles = values.generated_files\n if (generatedFiles && Array.isArray(generatedFiles) && generatedFiles.length > 0) {\n const customContent: CustomContent = {\n type: 'generated_files',\n content: generatedFiles\n }\n loadedMessages.push({\n key: `custom-generated_files-${Date.now()}-${Math.random()}`,\n type: 'custom',\n content: '',\n customContent\n })\n }\n\n // 处理 suggested_questions 通过 callback 返回,不 push 到消息列表\n const suggestedQuestions = values.suggested_questions\n if (suggestedQuestions && Array.isArray(suggestedQuestions) && suggestedQuestions.length > 0) {\n if (onSuggestedQuestions) {\n onSuggestedQuestions(suggestedQuestions)\n }\n }\n\n const todos = values.todos\n if (onTodos && Array.isArray(todos) && todos.length > 0) {\n onTodos(todos)\n }\n\n return loadedMessages\n } catch (error) {\n console.error('Failed to load thread history:', error)\n return []\n }\n}\n","import type { InjectionKey, Ref } from 'vue'\nimport { computed, inject } from 'vue'\n\nexport interface PortalHostContextValue {\n portalHost: Ref<HTMLElement | null>\n}\n\nexport const PORTAL_HOST_KEY: InjectionKey<PortalHostContextValue> = Symbol('AiBotPortalHost')\n\nexport function usePortalHost(): PortalHostContextValue {\n const ctx = inject(PORTAL_HOST_KEY)\n if (!ctx) {\n return {\n portalHost: computed(() => null),\n }\n }\n return ctx\n}\n","<script setup lang=\"ts\">\nimport { Maximize2Icon, Minimize2Icon, XIcon } from 'lucide-vue-next'\n\ninterface Props {\n title: string\n isMaximized: boolean\n showHeaderActions?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showHeaderActions: true\n})\n\nconst emit = defineEmits<{\n close: []\n toggleMaximize: []\n}>()\n</script>\n\n<template>\n <div class=\"chat-header\">\n <div class=\"chat-title\">\n <span class=\"title-text\">{{ title }}</span>\n </div>\n <div v-if=\"props.showHeaderActions\" class=\"header-actions\">\n <button class=\"action-btn\" @click=\"emit('toggleMaximize')\" type=\"button\" :title=\"isMaximized ? '还原' : '最大化'\">\n <Minimize2Icon v-if=\"isMaximized\" class=\"size-4\" />\n <Maximize2Icon v-else class=\"size-4\" />\n </button>\n <button class=\"action-btn\" @click=\"emit('close')\" type=\"button\" title=\"关闭\">\n <XIcon class=\"size-4\" />\n </button>\n </div>\n </div>\n</template>\n\n<style scoped>\n.chat-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 16px;\n background: var(--ai-surface-subtle);\n color: var(--foreground);\n flex-shrink: 0;\n border-bottom: 1px solid var(--ai-border-subtle);\n}\n\n.chat-title {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.title-text {\n font-size: 14px;\n font-weight: 600;\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.action-btn {\n appearance: none;\n background: transparent;\n border: none;\n border-radius: 6px;\n padding: 6px;\n cursor: pointer;\n color: var(--muted-foreground);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.15s ease;\n}\n\n.action-btn:hover {\n color: var(--foreground);\n background: var(--ai-chip-hover-bg);\n}\n</style>\n","import type { ClassValue } from \"clsx\"\nimport { clsx } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","<script setup lang=\"ts\">\nimport type { ToolCall } from './lib/message-types'\nimport { ChevronDownIcon, PlayCircle, Loader, CheckCircle, XCircle, BrainIcon, GlobeIcon, FileTextIcon, FolderSearch, FileEditIcon, ListTodoIcon, EyeIcon, SquarePen, FileSearch, BookOpenCheck, FolderSearchIcon, ZapIcon, WrenchIcon } from 'lucide-vue-next'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { ref } from 'vue'\n\ndefineProps<{\n toolCalls: ToolCall[]\n}>()\n\nconst getStateIcon = (state: string) => {\n switch (state) {\n case 'start':\n return { icon: PlayCircle, color: 'text-blue-500' }\n case 'running':\n return { icon: Loader, color: 'text-yellow-500 animate-spin' }\n case 'completed':\n return { icon: CheckCircle, color: 'text-green-500' }\n case 'error':\n return { icon: XCircle, color: 'text-red-500' }\n default:\n return { icon: PlayCircle, color: 'text-muted-foreground' }\n }\n}\n\nconst toolNameMap: Record<string, string> = {\n think_tool: '战略反思',\n fetch_markdown: '获取网页',\n convert_to_markdown: '文件转换',\n ls: '列出目录',\n read_file: '读取文件',\n write_file: '写入文件',\n edit_file: '编辑文件',\n glob: '查找文件',\n grep: '搜索文本',\n execute: '执行命令',\n write_todos: '待办事项',\n task: '子任务',\n}\n\nconst toolIconMap: Record<string, any> = {\n think_tool: BrainIcon,\n fetch_markdown: GlobeIcon,\n convert_to_markdown: FileTextIcon,\n ls: FolderSearchIcon,\n read_file: EyeIcon,\n write_file: FileEditIcon,\n edit_file: SquarePen,\n glob: FolderSearch,\n grep: FileSearch,\n execute: ZapIcon,\n write_todos: ListTodoIcon,\n task: BookOpenCheck,\n}\n\nconst getToolName = (name: string) => {\n return toolNameMap[name] || name\n}\n\nconst getToolIcon = (name: string) => {\n return toolIconMap[name] || WrenchIcon\n}\n\nconst isTodoTool = (name: string) => {\n return name === 'write_todos' || name.includes('todo')\n}\n\n// 简化 args 展示,只取前100个字符\nconst formatArgs = (args: string) => {\n if (!args) return ''\n return args.length > 50 ? args.slice(0, 100) + '...' : args\n}\n\nconst openStates = ref<Record<string, boolean>>({})\n\nconst toggle = (id: string) => {\n openStates.value[id] = !openStates.value[id]\n}\n</script>\n\n<template>\n <div class=\"mb-3 text-xs max-w-full\">\n <div\n v-for=\"tool in toolCalls\"\n :key=\"tool.id\"\n v-show=\"!isTodoTool(tool.name)\"\n class=\"overflow-hidden\"\n >\n <div\n class=\"flex items-center gap-2 w-full text-left hover:bg-muted/50 rounded px-2 py-1.5 transition-colors cursor-pointer\"\n @click=\"toggle(tool.id)\"\n >\n <ChevronDownIcon\n class=\"h-4 w-4 shrink-0\"\n :class=\"openStates[tool.id] ? '' : '-rotate-90'\"\n />\n <component\n :is=\"getToolIcon(tool.name)\"\n class=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\"\n />\n <span class=\"font-medium\">{{ getToolName(tool.name) }}</span>\n <span class=\"text-muted-foreground truncate flex-1 min-w-0\">{{ formatArgs(tool.args) }}</span>\n <component\n :is=\"getStateIcon(tool.state).icon\"\n :class=\"cn('h-3 w-3 shrink-0 ml-auto', getStateIcon(tool.state).color)\"\n />\n </div>\n <div\n v-show=\"openStates[tool.id]\"\n class=\"mt-2 ml-6 flex flex-col gap-2\"\n >\n <div>\n <p class=\"text-muted-foreground mb-1\">请求:</p>\n <pre class=\"bg-muted p-2 rounded text-[10px] overflow-x-auto max-w-full\">{{ tool.args }}</pre>\n </div>\n <div v-if=\"tool.result || tool.error\">\n <p class=\"text-muted-foreground mb-1\">\n {{ tool.state === 'error' ? 'Error:' : '结果:' }}\n </p>\n <pre\n :class=\"\n cn(\n 'bg-muted p-2 rounded text-[10px] overflow-x-auto max-w-full',\n tool.state === 'error' && 'text-red-500'\n )\n \"\n >{{ tool.error || tool.result }}</pre>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { reactiveOmit } from '@vueuse/core'\nimport { StickToBottom } from 'vue-stick-to-bottom'\n\ninterface Props {\n ariaLabel?: string\n class?: HTMLAttributes['class']\n initial?: boolean | 'instant' | { damping?: number, stiffness?: number, mass?: number }\n resize?: 'instant' | { damping?: number, stiffness?: number, mass?: number }\n damping?: number\n stiffness?: number\n mass?: number\n anchor?: 'auto' | 'none'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n ariaLabel: 'Conversation',\n initial: true,\n damping: 0.7,\n stiffness: 0.05,\n mass: 1.25,\n anchor: 'none',\n})\nconst delegatedProps = reactiveOmit(props, 'class')\n</script>\n\n<style scoped>\n:deep(> div) {\n scrollbar-width: thin;\n scrollbar-color: var(--ai-scrollbar-thumb) transparent;\n}\n\n:deep(> div::-webkit-scrollbar) {\n width: 6px;\n}\n\n:deep(> div::-webkit-scrollbar-thumb) {\n background: var(--ai-scrollbar-thumb);\n border-radius: 999px;\n}\n\n:deep(> div::-webkit-scrollbar-thumb:hover) {\n background: var(--ai-scrollbar-thumb-hover);\n}\n</style>\n\n<template>\n <StickToBottom\n v-bind=\"delegatedProps\"\n :class=\"cn('relative flex-1 overflow-y-hidden', props.class)\"\n role=\"log\"\n >\n <slot />\n </StickToBottom>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { computed } from 'vue'\n\ninterface Props {\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n\nconst classes = computed(() => cn(\n // 'flex flex-col p-4 border border-border rounded-lg', //这里就是对话整个矩形区域增加边框\n 'flex flex-col p-4', // 无边框\n props.class,\n))\n</script>\n\n<template>\n <div :class=\"classes\">\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { PrimitiveProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport type { ButtonVariants } from \".\"\nimport { Primitive } from \"reka-ui\"\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { buttonVariants } from \".\"\n\ninterface Props extends PrimitiveProps {\n variant?: ButtonVariants[\"variant\"]\n size?: ButtonVariants[\"size\"]\n class?: HTMLAttributes[\"class\"]\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n as: \"button\",\n})\n</script>\n\n<template>\n <Primitive\n data-slot=\"button\"\n :data-variant=\"variant\"\n :data-size=\"size\"\n :as=\"as\"\n :as-child=\"asChild\"\n :class=\"cn(buttonVariants({ variant, size }), props.class)\"\n >\n <slot />\n </Primitive>\n</template>\n","import type { VariantProps } from \"class-variance-authority\"\nimport { cva } from \"class-variance-authority\"\n\nexport { default as Button } from \"./Button.vue\"\n\nexport const buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n submit: \"bg-[var(--ai-accent,#c96442)] text-[var(--ai-accent-foreground,#fff)] hover:bg-[color:var(--ai-accent,#c96442)]/90 disabled:bg-muted disabled:text-muted-foreground\",\n submitLoading: \"bg-[var(--ai-accent,#c96442)] text-[var(--ai-accent-foreground,#fff)] hover:bg-[color:var(--ai-accent,#c96442)]/90\",\n },\n size: {\n \"default\": \"h-9 px-4 py-2 has-[>svg]:px-3\",\n \"sm\": \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n \"lg\": \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n \"icon\": \"size-9\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n)\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Button } from '@/components/ai-bot/ui/button'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { ArrowDownIcon } from 'lucide-vue-next'\nimport { computed } from 'vue'\nimport { useStickToBottomContext } from 'vue-stick-to-bottom'\n\ninterface Props {\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\nconst { isAtBottom, scrollToBottom } = useStickToBottomContext()\nconst showScrollButton = computed(() => !isAtBottom.value)\n\nfunction handleClick() {\n scrollToBottom()\n}\n</script>\n\n<template>\n <Button\n v-if=\"showScrollButton\"\n :class=\"cn(\n 'absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full cursor-pointer dark:bg-background dark:hover:bg-muted',\n props.class,\n )\"\n aria-label=\"Scroll to bottom\"\n size=\"icon\"\n type=\"button\"\n variant=\"outline\"\n v-bind=\"$attrs\"\n @click=\"handleClick\"\n >\n <ArrowDownIcon class=\"size-4\" />\n </Button>\n</template>\n","<script setup lang=\"ts\">\nimport type { UIMessage } from 'ai'\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\n\ninterface Props {\n from: UIMessage['role']\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'group flex w-full max-w-[80%]',\n props.from === 'user' ? 'is-user ml-auto' : 'is-assistant mr-auto',\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\n\ninterface Props {\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'is-user:dark flex w-fit flex-col overflow-hidden text-sm',\n 'group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:bg-[var(--ai-user-bubble-bg)] group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-[var(--ai-user-bubble-text)]',\n 'group-[.is-assistant]:bg-transparent group-[.is-assistant]:p-0 group-[.is-assistant]:text-foreground',\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { ChatMessage, CustomContent } from './lib/message-types'\nimport type { AiBotTheme } from './lib/theme'\nimport ToolCall from './ToolCall.vue'\nimport {\n Conversation,\n ConversationContent,\n ConversationScrollButton,\n} from '@/components/ai-bot/ai-elements/conversation'\nimport {\n Message,\n MessageContent,\n} from '@/components/ai-bot/ai-elements/message'\nimport MarkdownRender from 'markstream-vue'\nimport 'markstream-vue/index.css'\n\ninterface Props {\n messages: ChatMessage[]\n isStreaming?: boolean\n theme?: AiBotTheme\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isStreaming: false,\n theme: 'light'\n})\n\nconst markdownThemes = ['vitesse-dark', 'vitesse-light']\n\nfunction getMessageClass(index: number) {\n if (index === 0) return ''\n const current = props.messages[index]\n // 只有 human 消息需要间隔\n if (current.type === 'human') {\n return 'my-4'\n }\n return ''\n}\n</script>\n\n<style scoped>\n.loading-indicator {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 0;\n}\n\n.dot {\n width: 6px;\n height: 6px;\n background-color: var(--muted-foreground);\n border-radius: 50%;\n animation: bounce 1.4s infinite ease-in-out both;\n}\n\n.dot:nth-child(1) {\n animation-delay: -0.32s;\n}\n\n.dot:nth-child(2) {\n animation-delay: -0.16s;\n}\n\n@keyframes bounce {\n 0%, 80%, 100% {\n transform: scale(0);\n }\n 40% {\n transform: scale(1);\n }\n}\n\n</style>\n\n<template>\n <Conversation>\n <ConversationContent>\n <template v-for=\"(message, index) in messages\" :key=\"message.key\">\n <!-- system/custom 消息按照 assistant 方式渲染 -->\n <Message\n :from=\"message.type === 'tool' || message.type === 'system' || message.type === 'custom' ? 'assistant' : message.type === 'human' ? 'user' : 'assistant'\"\n :class=\"getMessageClass(index)\"\n >\n <!-- tool 消息:显示 ToolCall -->\n <template v-if=\"message.type === 'tool'\">\n <ToolCall :tool-calls=\"message.toolCalls\" />\n </template>\n\n <!-- custom 消息:通过插槽渲染 -->\n <template v-else-if=\"message.type === 'custom'\">\n <MessageContent>\n <slot name=\"custom\" :customContent=\"message.customContent\" />\n </MessageContent>\n </template>\n\n <!-- assistant/system/human 消息 -->\n <template v-else>\n <MessageContent>\n <!-- assistant 和 system 消息使用 MarkdownRender -->\n <MarkdownRender\n v-if=\"message.type === 'ai' || message.type === 'system'\"\n class=\"markdown-body\"\n :content=\"message.content || ''\"\n :is-dark=\"props.theme === 'dark'\"\n code-block-dark-theme=\"vitesse-dark\"\n code-block-light-theme=\"vitesse-light\"\n :themes=\"markdownThemes\"\n :typewriter=\"true\"\n :initial-render-batch-size=\"12\"\n :render-batch-size=\"24\"\n :render-batch-delay=\"20\"\n :max-live-nodes=\"0\"\n :defer-nodes-until-visible=\"true\"\n :viewport-priority=\"true\"\n />\n <!-- human 消息使用普通文本 -->\n <template v-else>\n {{ message.content }}\n </template>\n </MessageContent>\n </template>\n </Message>\n </template>\n <!-- 加载指示器 - 放在左边跟 AI 消息一样 -->\n <Message v-if=\"isStreaming\" from=\"assistant\">\n <div class=\"loading-indicator\">\n <span class=\"dot\"></span>\n <span class=\"dot\"></span>\n <span class=\"dot\"></span>\n </div>\n </Message>\n </ConversationContent>\n <ConversationScrollButton />\n </Conversation>\n</template>\n","import { inject } from 'vue'\nimport type { PromptInputContext } from './input-types'\n\nexport type {\n PromptInputMessage,\n AttachmentFile,\n PromptInputFileAttachment,\n PromptInputImageAttachment,\n PromptInputFileUrlAttachment,\n PromptInputAttachment,\n AttachmentTriggerSlotProps,\n PromptInputContext,\n} from './input-types'\n\nexport const PROMPT_INPUT_KEY = Symbol('PromptInputContext')\n\nexport function usePromptInput() {\n const context = inject<PromptInputContext>(PROMPT_INPUT_KEY)\n if (!context) {\n throw new Error('usePromptInput must be used within a PromptInput component')\n }\n return context\n}\n","import type { InjectionKey, Ref } from 'vue'\nimport type {\n AttachmentData,\n AttachmentMediaCategory,\n AttachmentVariant,\n} from './types'\nimport { computed, inject } from 'vue'\n\nexport interface AttachmentsContextValue {\n variant: Ref<AttachmentVariant>\n}\n\nexport const AttachmentsKey: InjectionKey<AttachmentsContextValue>\n = Symbol('Attachments')\n\nexport function useAttachmentsContext(): AttachmentsContextValue {\n const ctx = inject(AttachmentsKey)\n if (!ctx) {\n return {\n variant: computed(() => 'grid'),\n }\n }\n return ctx\n}\n\nexport interface AttachmentContextValue {\n data: Ref<AttachmentData>\n mediaCategory: Ref<AttachmentMediaCategory>\n remove?: () => void\n variant: Ref<AttachmentVariant>\n}\n\nexport const AttachmentKey: InjectionKey<AttachmentContextValue> = Symbol('Attachment')\n\nexport function useAttachmentContext(): AttachmentContextValue {\n const ctx = inject(AttachmentKey)\n if (!ctx) {\n throw new Error('Attachment components must be used within <Attachment>')\n }\n return ctx\n}\n","import type { AttachmentData, AttachmentMediaCategory } from './types'\n\nexport function getMediaCategory(data: AttachmentData): AttachmentMediaCategory {\n if (data.type === 'source-document') {\n return 'source'\n }\n\n const mediaType = data.mediaType ?? ''\n\n if (mediaType.startsWith('image/')) {\n return 'image'\n }\n if (mediaType.startsWith('video/')) {\n return 'video'\n }\n if (mediaType.startsWith('audio/')) {\n return 'audio'\n }\n if (mediaType.startsWith('application/') || mediaType.startsWith('text/')) {\n return 'document'\n }\n\n return 'unknown'\n}\n\nexport function getAttachmentLabel(data: AttachmentData): string {\n if (data.type === 'source-document') {\n return data.title || data.filename || 'Source'\n }\n\n const category = getMediaCategory(data)\n return data.filename || (category === 'image' ? 'Image' : 'Attachment')\n}\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport type { AttachmentData } from './types'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { computed, provide } from 'vue'\nimport { AttachmentKey, useAttachmentsContext } from './context'\nimport { getMediaCategory } from './utils'\n\ninterface Props extends /* @vue-ignore */ HTMLAttributes {\n data: AttachmentData\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n (e: 'remove'): void\n}>()\n\nconst { variant } = useAttachmentsContext()\nconst data = computed(() => props.data)\nconst mediaCategory = computed(() => getMediaCategory(props.data))\n\nfunction handleRemove() {\n emit('remove')\n}\n\nprovide(AttachmentKey, {\n data,\n mediaCategory,\n remove: handleRemove,\n variant,\n})\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'group relative',\n variant === 'grid' && 'size-24 overflow-hidden rounded-lg',\n variant === 'inline'\n && [\n 'flex h-8 cursor-pointer select-none items-center gap-1',\n 'rounded-md border border-border px-1',\n 'font-medium text-sm transition-all',\n 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',\n ],\n variant === 'list'\n && [\n 'flex w-full items-center gap-3 rounded-lg border p-3',\n 'hover:bg-accent/50',\n ],\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { computed } from 'vue'\nimport { useAttachmentContext } from './context'\nimport { getAttachmentLabel } from './utils'\n\ninterface Props extends /* @vue-ignore */ HTMLAttributes {\n showMediaType?: boolean\n class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showMediaType: false,\n})\n\nconst { data, variant } = useAttachmentContext()\nconst label = computed(() => getAttachmentLabel(data.value))\n</script>\n\n<template>\n <div\n v-if=\"variant !== 'grid'\"\n :class=\"cn('min-w-0 flex-1', props.class)\"\n v-bind=\"$attrs\"\n >\n <span class=\"block truncate\">{{ label }}</span>\n <span\n v-if=\"props.showMediaType && data.mediaType\"\n class=\"block truncate text-muted-foreground text-xs\"\n >\n {{ data.mediaType }}\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes, VNode } from 'vue'\nimport type { AttachmentMediaCategory } from './types'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport {\n FileTextIcon,\n GlobeIcon,\n ImageIcon,\n Music2Icon,\n PaperclipIcon,\n VideoIcon,\n} from 'lucide-vue-next'\nimport { computed } from 'vue'\nimport { useAttachmentContext } from './context'\n\ninterface Props extends /* @vue-ignore */ HTMLAttributes {\n fallbackIcon?: VNode\n class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n\nconst { data, mediaCategory, variant } = useAttachmentContext()\n\nconst isGrid = computed(() => variant.value === 'grid')\nconst iconSize = computed(() => (variant.value === 'inline' ? 'size-3' : 'size-4'))\nconst fileUrl = computed(() => (data.value.type === 'file' ? data.value.url : undefined))\nconst showImage = computed(\n () => mediaCategory.value === 'image' && data.value.type === 'file' && !!fileUrl.value,\n)\nconst showVideo = computed(\n () => mediaCategory.value === 'video' && data.value.type === 'file' && !!fileUrl.value,\n)\n\nconst iconMap: Record<AttachmentMediaCategory, typeof ImageIcon> = {\n image: ImageIcon,\n video: VideoIcon,\n audio: Music2Icon,\n source: GlobeIcon,\n document: FileTextIcon,\n unknown: PaperclipIcon,\n}\n\nconst iconComponent = computed(() => iconMap[mediaCategory.value])\nconst imageAlt = computed(() =>\n (data.value.type === 'file' ? data.value.filename : undefined) || 'Image',\n)\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'flex shrink-0 items-center justify-center overflow-hidden',\n variant === 'grid' && 'size-full bg-muted',\n variant === 'inline' && 'size-5 rounded bg-background',\n variant === 'list' && 'size-12 rounded bg-muted',\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <img\n v-if=\"showImage\"\n :alt=\"imageAlt\"\n :class=\"isGrid ? 'size-full object-cover' : 'size-full rounded object-cover'\"\n :height=\"isGrid ? 96 : 20\"\n :src=\"fileUrl\"\n :width=\"isGrid ? 96 : 20\"\n >\n <video\n v-else-if=\"showVideo\"\n class=\"size-full object-cover\"\n muted\n :src=\"fileUrl\"\n />\n <component :is=\"props.fallbackIcon\" v-else-if=\"props.fallbackIcon\" />\n <component\n :is=\"iconComponent\"\n v-else\n :class=\"cn(iconSize, 'text-muted-foreground')\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Button } from '@/components/ai-bot/ui/button'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { XIcon } from 'lucide-vue-next'\nimport { useAttachmentContext } from './context'\n\ntype ButtonProps = InstanceType<typeof Button>['$props']\n\ninterface Props extends /* @vue-ignore */ ButtonProps {\n label?: string\n class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: 'Remove',\n})\n\nconst { remove, variant } = useAttachmentContext()\n\nconst { variant: _variant, ...restProps } = props\n\nfunction handleClick(e: Event) {\n e.stopPropagation()\n remove?.()\n}\n</script>\n\n<template>\n <Button\n v-if=\"remove\"\n :aria-label=\"props.label\"\n :class=\"\n cn(\n variant === 'grid'\n && [\n 'absolute top-2 right-2 size-6 rounded-full p-0',\n 'bg-background/80 backdrop-blur-sm',\n 'opacity-0 transition-opacity group-hover:opacity-100',\n 'hover:bg-background',\n '[&>svg]:size-3',\n ],\n variant === 'inline'\n && [\n 'size-5 rounded-sm p-0 cursor-pointer min-w-0',\n 'opacity-0 transition-opacity group-hover:opacity-100',\n '[&>svg]:size-2.5',\n ],\n variant === 'list' && ['size-8 shrink-0 rounded p-0', '[&>svg]:size-4'],\n props.class,\n )\n \"\n type=\"button\"\n variant=\"ghost\"\n v-bind=\"restProps\"\n @click=\"handleClick\"\n >\n <slot>\n <XIcon />\n </slot>\n <span class=\"sr-only\">{{ props.label }}</span>\n </Button>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport type { AttachmentVariant } from './types'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { computed, provide } from 'vue'\nimport { AttachmentsKey } from './context'\n\ninterface Props extends /* @vue-ignore */ HTMLAttributes {\n variant?: AttachmentVariant\n class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n variant: 'grid',\n})\n\nconst variant = computed(() => props.variant)\n\nprovide(AttachmentsKey, { variant })\n</script>\n\n<template>\n <div\n :class=\"\n cn(\n 'flex items-start',\n variant === 'list' ? 'flex-col gap-2' : 'flex-wrap gap-2',\n variant === 'grid' && 'ml-auto w-fit',\n props.class,\n )\n \"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport {\n Attachment,\n AttachmentInfo,\n AttachmentPreview,\n AttachmentRemove,\n Attachments,\n} from '@/components/ai-bot/ai-elements/attachments'\nimport type { AttachmentData } from '@/components/ai-bot/ai-elements/attachments/types'\nimport type { AttachmentFile } from '@/components/ai-bot/lib/input-types'\nimport { usePromptInput } from '@/components/ai-bot/lib/prompt-input'\n\nconst { files, removeFile } = usePromptInput()\n\nfunction asAttachmentData(file: AttachmentFile): AttachmentData {\n return file as unknown as AttachmentData\n}\n</script>\n\n<template>\n <Attachments\n v-if=\"files.length > 0\"\n variant=\"inline\"\n class=\"attachments-inline\"\n >\n <Attachment\n v-for=\"attachment in files\"\n :key=\"attachment.id\"\n :data=\"asAttachmentData(attachment)\"\n :title=\"attachment.filename\"\n @remove=\"removeFile(attachment.id)\"\n >\n <AttachmentPreview />\n <AttachmentInfo class=\"attachment-info\" :title=\"attachment.filename\" />\n <AttachmentRemove />\n </Attachment>\n </Attachments>\n</template>\n\n<style scoped>\n.attachments-inline {\n justify-content: flex-start;\n}\n\n.attachment-info {\n max-width: 100px;\n min-width: 0;\n font-size: 11px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Button } from '@/components/ai-bot/ui/button'\nimport { cn } from '@/components/ai-bot/lib/utils'\n\ninterface SuggestionProps {\n suggestion: string\n class?: HTMLAttributes['class']\n variant?: 'outline' | 'default' | 'destructive' | 'secondary' | 'ghost' | 'link'\n size?: 'default' | 'sm' | 'lg' | 'icon'\n}\n\nconst props = withDefaults(defineProps<SuggestionProps>(), {\n variant: 'outline',\n size: 'sm',\n})\n\nconst emit = defineEmits<{\n (e: 'click', suggestion: string): void\n}>()\n\nfunction handleClick() {\n emit('click', props.suggestion)\n}\n</script>\n\n<template>\n <Button\n :class=\"cn('cursor-pointer rounded-full px-4', props.class)\"\n :size=\"props.size\"\n type=\"button\"\n :variant=\"props.variant\"\n v-bind=\"$attrs\"\n @click=\"handleClick\"\n >\n <slot>{{ props.suggestion }}</slot>\n </Button>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { Suggestion } from '@/components/ai-bot/ai-elements/suggestion'\n\ninterface Props {\n suggestions: string[]\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n select: [suggestion: string]\n}>()\n\nconst ROTATE_INTERVAL = 3200\nconst CHIP_GAP = 5\n\nconst viewportRef = ref<HTMLDivElement | null>(null)\nconst measureRefs = ref<(HTMLElement | null)[]>([])\nconst pageRanges = ref<Array<{ start: number, end: number }>>([])\nconst currentPageIndex = ref(0)\nconst isHovered = ref(false)\n\nlet rotationTimer: ReturnType<typeof setInterval> | null = null\nlet resizeObserver: ResizeObserver | null = null\n\nconst shouldRotate = computed(() => pageRanges.value.length > 1)\n\nconst currentPageSuggestions = computed(() => {\n const range = pageRanges.value[currentPageIndex.value]\n if (!range) {\n return props.suggestions\n }\n return props.suggestions.slice(range.start, range.end)\n})\n\nfunction setMeasureRef(el: HTMLElement | null, index: number) {\n measureRefs.value[index] = el\n}\n\nfunction stopRotation() {\n if (rotationTimer) {\n clearInterval(rotationTimer)\n rotationTimer = null\n }\n}\n\nfunction startRotation() {\n stopRotation()\n\n if (!shouldRotate.value || isHovered.value) {\n return\n }\n\n rotationTimer = setInterval(() => {\n currentPageIndex.value = (currentPageIndex.value + 1) % pageRanges.value.length\n }, ROTATE_INTERVAL)\n}\n\nfunction handleMouseEnter() {\n isHovered.value = true\n stopRotation()\n}\n\nfunction handleMouseLeave() {\n isHovered.value = false\n startRotation()\n}\n\nfunction buildPageRanges() {\n const viewportWidth = viewportRef.value?.clientWidth ?? 0\n const widths = props.suggestions.map((_, index) => measureRefs.value[index]?.offsetWidth ?? 0)\n\n if (!props.suggestions.length) {\n pageRanges.value = []\n currentPageIndex.value = 0\n stopRotation()\n return\n }\n\n if (!viewportWidth || widths.some(width => width === 0)) {\n pageRanges.value = [{ start: 0, end: props.suggestions.length }]\n currentPageIndex.value = 0\n stopRotation()\n return\n }\n\n const ranges: Array<{ start: number, end: number }> = []\n let start = 0\n let widthSum = 0\n\n props.suggestions.forEach((_, index) => {\n const itemWidth = widths[index]\n const nextWidth = start === index ? itemWidth : widthSum + CHIP_GAP + itemWidth\n\n if (start !== index && nextWidth > viewportWidth) {\n ranges.push({ start, end: index })\n start = index\n widthSum = itemWidth\n return\n }\n\n widthSum = nextWidth\n })\n\n ranges.push({ start, end: props.suggestions.length })\n pageRanges.value = ranges\n currentPageIndex.value = Math.min(currentPageIndex.value, Math.max(ranges.length - 1, 0))\n startRotation()\n}\n\nasync function recalculatePages() {\n await nextTick()\n buildPageRanges()\n}\n\nwatch(\n () => props.suggestions,\n async () => {\n measureRefs.value = []\n currentPageIndex.value = 0\n stopRotation()\n await recalculatePages()\n },\n { immediate: true },\n)\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(() => {\n currentPageIndex.value = 0\n void recalculatePages()\n })\n\n if (viewportRef.value) {\n resizeObserver.observe(viewportRef.value)\n }\n})\n\nonBeforeUnmount(() => {\n stopRotation()\n resizeObserver?.disconnect()\n})\n</script>\n\n<template>\n <div class=\"suggestions-wrapper\" @mouseenter=\"handleMouseEnter\" @mouseleave=\"handleMouseLeave\">\n <div ref=\"viewportRef\" class=\"suggestions-viewport\" :class=\"{ 'has-fade': shouldRotate }\">\n <Transition name=\"suggestion-slide\" mode=\"out-in\">\n <div :key=\"currentPageIndex\" class=\"suggestions-row\">\n <Suggestion\n v-for=\"suggestion in currentPageSuggestions\"\n :key=\"suggestion\"\n :suggestion=\"suggestion\"\n class=\"suggestion-chip\"\n @click=\"emit('select', suggestion)\"\n />\n </div>\n </Transition>\n </div>\n\n <div class=\"suggestions-measurements\" aria-hidden=\"true\">\n <Suggestion\n v-for=\"(suggestion, index) in suggestions\"\n :key=\"`measure-${suggestion}-${index}`\"\n :ref=\"el => setMeasureRef((el as any)?.$el || el, index)\"\n :suggestion=\"suggestion\"\n class=\"suggestion-chip\"\n tabindex=\"-1\"\n />\n </div>\n </div>\n</template>\n\n<style scoped>\n.suggestions-wrapper {\n padding: 0;\n position: relative;\n}\n\n.suggestions-viewport {\n position: relative;\n width: 100%;\n height: 24px;\n overflow: hidden;\n}\n\n.suggestions-viewport.has-fade::before,\n.suggestions-viewport.has-fade::after {\n content: '';\n position: absolute;\n top: 0;\n z-index: 1;\n width: 16px;\n height: 100%;\n pointer-events: none;\n}\n\n.suggestions-viewport.has-fade::before {\n left: 0;\n background: linear-gradient(90deg, var(--ai-surface) 5%, transparent);\n}\n\n.suggestions-viewport.has-fade::after {\n right: 0;\n background: linear-gradient(270deg, var(--ai-surface) 5%, transparent);\n}\n\n.suggestions-row {\n display: flex;\n align-items: center;\n gap: 5px;\n width: 100%;\n height: 24px;\n overflow: hidden;\n}\n\n.suggestions-measurements {\n position: absolute;\n left: 0;\n top: 0;\n display: flex;\n align-items: center;\n gap: 5px;\n visibility: hidden;\n pointer-events: none;\n white-space: nowrap;\n height: 0;\n overflow: hidden;\n}\n\n:deep(.suggestion-chip) {\n max-width: 100%;\n height: 24px;\n padding: 0 9px;\n border-color: transparent;\n background: var(--ai-chip-bg);\n color: var(--ai-chip-text);\n font-size: 11px;\n line-height: 1;\n font-weight: 500;\n box-shadow: none;\n white-space: nowrap;\n flex-shrink: 0;\n}\n\n:deep(.suggestion-chip:hover) {\n background: var(--ai-control-hover-bg);\n border-color: transparent;\n color: var(--ai-chip-hover-text);\n}\n\n.suggestion-slide-enter-active,\n.suggestion-slide-leave-active {\n transition: transform 0.24s ease, opacity 0.24s ease;\n}\n\n.suggestion-slide-enter-from {\n opacity: 0;\n transform: translateY(100%);\n}\n\n.suggestion-slide-leave-to {\n opacity: 0;\n transform: translateY(-100%);\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <div\n data-slot=\"input-group\"\n role=\"group\"\n :class=\"cn(\n 'group/input-group relative flex w-full items-center rounded-md border border-[var(--ai-input-border)] bg-[var(--ai-input-bg)] shadow-xs transition-[color,box-shadow,border-color] outline-none',\n 'h-9 min-w-0 has-[>textarea]:h-auto',\n\n // Variants based on alignment.\n 'has-[>[data-align=inline-start]]:[&>input]:pl-2',\n 'has-[>[data-align=inline-end]]:[&>input]:pr-2',\n 'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',\n 'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',\n\n // Focus state.\n 'has-[[data-slot=input-group-control]:focus-visible]:border-[var(--ai-input-border-focus)] has-[[data-slot=input-group-control]:focus-visible]:ring-[var(--ai-input-ring)] has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]',\n\n // Error state.\n 'has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40',\n\n props.class,\n )\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport type { InputGroupVariants } from \".\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\nimport { inputGroupAddonVariants } from \".\"\n\nconst props = withDefaults(defineProps<{\n align?: InputGroupVariants[\"align\"]\n class?: HTMLAttributes[\"class\"]\n}>(), {\n align: \"inline-start\",\n})\n\nfunction handleInputGroupAddonClick(e: MouseEvent) {\n const currentTarget = e.currentTarget as HTMLElement | null\n const target = e.target as HTMLElement | null\n if (target && target.closest(\"button\")) {\n return\n }\n if (currentTarget && currentTarget?.parentElement) {\n currentTarget.parentElement?.querySelector(\"input\")?.focus()\n }\n}\n</script>\n\n<template>\n <div\n role=\"group\"\n data-slot=\"input-group-addon\"\n :data-align=\"props.align\"\n :class=\"cn(inputGroupAddonVariants({ align: props.align }), props.class)\"\n @click=\"handleInputGroupAddonClick\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport type { InputGroupButtonVariants } from \".\"\nimport type { ButtonVariants } from '@/components/ai-bot/ui/button'\nimport { cn } from \"@/components/ai-bot/lib/utils\"\nimport { Button } from '@/components/ai-bot/ui/button'\nimport { inputGroupButtonVariants } from \".\"\n\ninterface InputGroupButtonProps {\n variant?: ButtonVariants[\"variant\"]\n size?: InputGroupButtonVariants[\"size\"]\n class?: HTMLAttributes[\"class\"]\n}\n\nconst props = withDefaults(defineProps<InputGroupButtonProps>(), {\n size: \"xs\",\n variant: \"ghost\",\n})\n</script>\n\n<template>\n <Button\n :data-size=\"props.size\"\n :variant=\"props.variant\"\n :class=\"cn(inputGroupButtonVariants({ size: props.size }), props.class)\"\n >\n <slot />\n </Button>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { useVModel } from \"@vueuse/core\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n defaultValue?: string | number\n modelValue?: string | number\n}>()\n\nconst emits = defineEmits<{\n (e: \"update:modelValue\", payload: string | number): void\n}>()\n\nconst modelValue = useVModel(props, \"modelValue\", emits, {\n passive: true,\n defaultValue: props.defaultValue,\n})\n</script>\n\n<template>\n <textarea\n v-model=\"modelValue\"\n data-slot=\"textarea\"\n :class=\"cn('border-input text-[var(--ai-input-text)] placeholder:text-[var(--ai-input-placeholder)] focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm', props.class)\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\nimport { Textarea } from '@/components/ai-bot/ui/textarea'\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <Textarea\n data-slot=\"input-group-control\"\n :class=\"cn(\n 'flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent',\n props.class,\n )\"\n />\n</template>\n","import type { VariantProps } from \"class-variance-authority\"\nimport { cva } from \"class-variance-authority\"\n\nexport { default as InputGroup } from \"./InputGroup.vue\"\nexport { default as InputGroupAddon } from \"./InputGroupAddon.vue\"\nexport { default as InputGroupButton } from \"./InputGroupButton.vue\"\nexport { default as InputGroupInput } from \"./InputGroupInput.vue\"\nexport { default as InputGroupText } from \"./InputGroupText.vue\"\nexport { default as InputGroupTextarea } from \"./InputGroupTextarea.vue\"\n\nexport const inputGroupAddonVariants = cva(\n \"text-[var(--ai-control-muted)] flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-4 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-50\",\n {\n variants: {\n align: {\n \"inline-start\":\n \"order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]\",\n \"inline-end\":\n \"order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]\",\n \"block-start\":\n \"order-first w-full justify-start px-3 pt-3 [.border-b]:pb-3 group-has-[>input]/input-group:pt-2.5\",\n \"block-end\":\n \"order-last w-full justify-start px-3 pb-3 [.border-t]:pt-3 group-has-[>input]/input-group:pb-2.5\",\n },\n },\n defaultVariants: {\n align: \"inline-start\",\n },\n },\n)\n\nexport type InputGroupVariants = VariantProps<typeof inputGroupAddonVariants>\n\nexport const inputGroupButtonVariants = cva(\n \"text-sm shadow-none flex gap-2 items-center\",\n {\n variants: {\n size: {\n \"xs\": \"h-6 gap-1 px-2 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2\",\n \"sm\": \"h-8 px-2.5 gap-1.5 rounded-md has-[>svg]:px-2.5\",\n \"icon-xs\": \"size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0\",\n \"icon-sm\": \"size-8 p-0 has-[>svg]:p-0\",\n },\n },\n defaultVariants: {\n size: \"xs\",\n },\n },\n)\n\nexport type InputGroupButtonVariants = VariantProps<typeof inputGroupButtonVariants>\n","<script setup lang=\"ts\">\nimport type { DropdownMenuRootEmits, DropdownMenuRootProps } from \"reka-ui\"\nimport { DropdownMenuRoot, useForwardPropsEmits } from \"reka-ui\"\n\nconst props = defineProps<DropdownMenuRootProps>()\nconst emits = defineEmits<DropdownMenuRootEmits>()\n\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <DropdownMenuRoot\n v-slot=\"slotProps\"\n data-slot=\"dropdown-menu\"\n v-bind=\"forwarded\"\n >\n <slot v-bind=\"slotProps\" />\n </DropdownMenuRoot>\n</template>\n","<script setup lang=\"ts\">\nimport type { DropdownMenuContentEmits, DropdownMenuContentProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport {\n DropdownMenuContent,\n DropdownMenuPortal,\n useForwardPropsEmits,\n} from \"reka-ui\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\nimport { usePortalHost } from '@/components/ai-bot/lib/portal-host'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(\n defineProps<DropdownMenuContentProps & { class?: HTMLAttributes[\"class\"] }>(),\n {\n sideOffset: 4,\n },\n)\nconst emits = defineEmits<DropdownMenuContentEmits>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\nconst { portalHost } = usePortalHost()\n</script>\n\n<template>\n <DropdownMenuPortal :to=\"portalHost || undefined\">\n <DropdownMenuContent\n data-slot=\"dropdown-menu-content\"\n v-bind=\"{ ...$attrs, ...forwarded }\"\n :class=\"cn('bg-[var(--ai-layer-bg)] text-[var(--ai-layer-text)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--reka-dropdown-menu-content-available-height) min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border border-[var(--ai-layer-border)] p-1 shadow-[var(--ai-layer-shadow)]', props.class)\"\n >\n <slot />\n </DropdownMenuContent>\n </DropdownMenuPortal>\n</template>\n","<script setup lang=\"ts\">\nimport type { DropdownMenuItemProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { DropdownMenuItem, useForwardProps } from \"reka-ui\"\nimport { cn } from \"@/components/ai-bot/lib/utils\"\n\nconst props = withDefaults(defineProps<DropdownMenuItemProps & {\n class?: HTMLAttributes[\"class\"]\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}>(), {\n variant: \"default\",\n})\n\nconst delegatedProps = reactiveOmit(props, \"inset\", \"variant\", \"class\")\n\nconst forwardedProps = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <DropdownMenuItem\n data-slot=\"dropdown-menu-item\"\n :data-inset=\"inset ? '' : undefined\"\n :data-variant=\"variant\"\n v-bind=\"forwardedProps\"\n :class=\"cn('focus:bg-[var(--ai-control-hover-bg)] focus:text-[var(--ai-control-hover-text)] data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*=\\'text-\\'])]:text-[var(--ai-control-muted)] relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\\'size-\\'])]:size-4', props.class)\"\n >\n <slot />\n </DropdownMenuItem>\n</template>\n","<script setup lang=\"ts\">\nimport type { DropdownMenuTriggerProps } from \"reka-ui\"\nimport { DropdownMenuTrigger, useForwardProps } from \"reka-ui\"\n\nconst props = defineProps<DropdownMenuTriggerProps>()\n\nconst forwardedProps = useForwardProps(props)\n</script>\n\n<template>\n <DropdownMenuTrigger\n data-slot=\"dropdown-menu-trigger\"\n v-bind=\"forwardedProps\"\n >\n <slot />\n </DropdownMenuTrigger>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, provide, onBeforeUnmount } from 'vue'\nimport type { ChatFileType, ChatStatus } from './lib/message-types'\nimport { nanoid } from 'nanoid'\nimport { PROMPT_INPUT_KEY } from './lib/prompt-input'\nimport type { AiBotInputApi, AttachmentFile, AttachmentTriggerSlotProps, PromptInputAttachment, PromptInputContext } from './lib/input-types'\nimport { getProviderByModelName, type ModelInfo } from './lib/models'\nimport PromptInputAttachmentsDisplay from './InputAttachmentsDisplay.vue'\nimport ChatSuggestions from './ChatSuggestions.vue'\nimport { CheckIcon, ChevronDownIcon, Loader2Icon, CornerDownLeftIcon, PaperclipIcon } from 'lucide-vue-next'\nimport { InputGroup, InputGroupAddon, InputGroupTextarea, InputGroupButton } from '@/components/ai-bot/ui/input-group'\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, DropdownMenuItem } from '@/components/ai-bot/ui/dropdown-menu'\n\n// ============== 类型定义 ==============\ninterface Props {\n status: ChatStatus\n currentModel: ModelInfo | null\n models: ModelInfo[]\n suggestions: string[]\n useWebSearch: boolean\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n submit: [message: { text: string, files: AttachmentFile[] }]\n stop: []\n selectSuggestion: [suggestion: string]\n 'update:currentModel': [model: ModelInfo]\n 'update:useWebSearch': [value: boolean]\n}>()\n\nconst modelSelectorOpen = defineModel<boolean>('modelSelectorOpen', { default: false })\n\ndefineSlots<{\n 'attachment-trigger'?: (props: AttachmentTriggerSlotProps) => any\n}>()\n\n// ============== PromptInput Context ==============\n\n// 本地状态\nconst inputText = ref('')\nconst hasFiles = ref(false)\nconst files = ref<AttachmentFile[]>([])\nconst fileInputRef = ref<HTMLInputElement | null>(null)\nconst isLoading = ref(false)\n\n// Cleanup object URLs\nonBeforeUnmount(() => {\n files.value.forEach((f) => {\n if (f.url && f.url.startsWith('blob:')) {\n URL.revokeObjectURL(f.url)\n }\n })\n})\n\nconst setTextInput = (val: string) => {\n inputText.value = val\n}\n\nfunction resolveAttachmentType(attachment: PromptInputAttachment, file?: File, url?: string): ChatFileType {\n if (attachment.type === 'file_url') {\n return 'file_url'\n }\n if (attachment.type === 'image') {\n return 'image'\n }\n if (attachment.type === 'file') {\n return 'file'\n }\n if (url && !url.startsWith('blob:') && !url.startsWith('data:')) {\n return 'file_url'\n }\n const mediaType = file?.type || ''\n return mediaType.startsWith('image/') ? 'image' : 'file'\n}\n\nconst addAttachments = (incoming: PromptInputAttachment[]) => {\n const existingFilenames = new Set(\n files.value\n .map(file => file.filename?.trim())\n .filter((name): name is string => !!name),\n )\n\n const newAttachments: AttachmentFile[] = incoming.flatMap((attachment) => {\n const normalized = attachment.type === 'file_url'\n ? {\n ...attachment,\n id: attachment.id || nanoid(),\n type: 'file_url' as const,\n url: attachment.url,\n mediaType: attachment.mediaType || 'application/octet-stream',\n filename: attachment.filename,\n }\n : (() => {\n const file = attachment.file\n const url = attachment.url || (file ? URL.createObjectURL(file) : undefined)\n const type = resolveAttachmentType(attachment, file, url)\n\n return {\n ...attachment,\n id: attachment.id || nanoid(),\n type,\n url,\n mediaType: attachment.mediaType || file?.type || '',\n filename: attachment.filename || file?.name,\n file,\n }\n })()\n\n const normalizedName = normalized.filename?.trim()\n if (normalizedName && existingFilenames.has(normalizedName)) {\n if (normalized.url?.startsWith('blob:')) {\n URL.revokeObjectURL(normalized.url)\n }\n return []\n }\n\n if (normalizedName) {\n existingFilenames.add(normalizedName)\n }\n\n return [normalized]\n })\n\n files.value = [...files.value, ...newAttachments]\n hasFiles.value = files.value.length > 0\n}\n\nconst addFiles = (incoming: File[] | FileList) => {\n const fileList = Array.from(incoming)\n addAttachments(fileList.map(file => ({\n type: file.type.startsWith('image/') ? 'image' : 'file',\n file,\n })))\n}\n\nconst removeFile = (id: string) => {\n const file = files.value.find(f => f.id === id)\n if (file?.url && file.url.startsWith('blob:')) {\n URL.revokeObjectURL(file.url)\n }\n files.value = files.value.filter(f => f.id !== id)\n hasFiles.value = files.value.length > 0\n}\n\nconst clearFiles = () => {\n files.value.forEach((f) => {\n if (f.url && f.url.startsWith('blob:')) {\n URL.revokeObjectURL(f.url)\n }\n })\n files.value = []\n hasFiles.value = false\n}\n\nconst clearInput = () => {\n inputText.value = ''\n}\n\nconst openFileDialog = () => {\n fileInputRef.value?.click()\n}\n\nconst convertBlobUrlToDataUrl = async (url: string): Promise<string | null> => {\n try {\n const response = await fetch(url)\n const blob = await response.blob()\n return new Promise((resolve) => {\n const reader = new FileReader()\n reader.onloadend = () => resolve(reader.result as string)\n reader.onerror = () => resolve(null)\n reader.readAsDataURL(blob)\n })\n }\n catch {\n return null\n }\n}\n\nconst sendMessage: AiBotInputApi['sendMessage'] = async () => {\n if (props.status === 'streaming') {\n return\n }\n\n // Process files (convert blobs to base64 if needed for AI SDK)\n const processedFiles = await Promise.all(\n files.value.map(async (item) => {\n if (item.url && item.url.startsWith('blob:')) {\n const dataUrl = await convertBlobUrlToDataUrl(item.url)\n return {\n ...item,\n type: item.type === 'file_url' ? 'file' : item.type,\n data: dataUrl ?? item.data,\n url: dataUrl ?? item.url,\n }\n }\n return item\n }),\n )\n\n const message = {\n text: inputText.value,\n files: processedFiles,\n }\n\n emit('submit', message)\n clearInput()\n clearFiles()\n}\n\ndefineExpose<AiBotInputApi>({\n setTextInput,\n addAttachments,\n sendMessage,\n})\n\n// 提供 context 给子组件\nconst context: PromptInputContext = {\n textInput: inputText,\n files,\n fileInputRef,\n isLoading,\n setTextInput,\n addAttachments,\n addFiles,\n removeFile,\n clearFiles,\n clearInput,\n openFileDialog,\n sendMessage,\n}\n\nprovide(PROMPT_INPUT_KEY, context)\n\n// ============== 本地输入状态 ==============\n\n// 输入是否为空\nconst isEmpty = computed(() => {\n return !inputText.value.trim() && !hasFiles.value\n})\n\nconst selectedModelData = computed(() => {\n return props.currentModel || props.models.find(m => m.is_default) || props.models[0]\n})\n\n// 按提供商分组模型\nconst groupedModels = computed(() => {\n const groups: Record<string, ModelInfo[]> = {}\n props.models.forEach((model) => {\n const provider = model.provider || 'Other'\n if (!groups[provider]) {\n groups[provider] = []\n }\n groups[provider].push(model)\n })\n return groups\n})\n\nconst providers = computed(() => Object.keys(groupedModels.value))\n\nfunction handleModelSelect(name: string) {\n const model = props.models.find(m => m.name === name)\n if (model) {\n emit('update:currentModel', model)\n }\n modelSelectorOpen.value = false\n}\n\n// ============== PromptInputTextarea 逻辑 ==============\nconst isComposing = ref(false)\n\nfunction handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Enter') {\n // 忙碌状态不允许发送,但 shift+回车允许换行\n if (isLoadingStatus.value) {\n if (!e.shiftKey)\n e.preventDefault()\n return\n }\n // 中文输入或 shift+回车,允许换行\n if (isComposing.value || e.shiftKey)\n return\n e.preventDefault()\n sendMessage()\n }\n\n // Remove last attachment on backspace if input is empty\n if (e.key === 'Backspace' && inputText.value === '' && files.value.length > 0) {\n const lastFile = files.value[files.value.length - 1]\n if (lastFile) {\n removeFile(lastFile.id)\n }\n }\n}\n\nfunction handlePaste(e: ClipboardEvent) {\n const items = e.clipboardData?.items\n if (!items)\n return\n\n const pastedFiles: File[] = []\n for (const item of Array.from(items)) {\n if (item.kind === 'file') {\n const file = item.getAsFile()\n if (file)\n pastedFiles.push(file)\n }\n }\n\n if (pastedFiles.length > 0) {\n e.preventDefault()\n addFiles(pastedFiles)\n }\n}\n\n// ============== PromptInputSubmit 逻辑 ==============\nconst buttonVariant = computed(() => {\n if (props.status === 'streaming') {\n return 'destructive'\n }\n return 'submit'\n})\n\nconst submitIcon = computed(() => {\n if (props.status === 'streaming') {\n return Loader2Icon\n }\n return CornerDownLeftIcon\n})\n\nconst iconClass = computed(() => {\n if (props.status === 'streaming') {\n return 'size-4 animate-spin'\n }\n return 'size-4'\n})\n\nconst isDisabled = computed(() => {\n // 忙碌状态时不应禁用(需要可以点击取消)\n if (isLoadingStatus.value)\n return false\n return isEmpty.value\n})\n\nconst isLoadingStatus = computed(() => {\n return props.status === 'streaming'\n})\n\nfunction handleSubmitClick() {\n if (isLoadingStatus.value) {\n emit('stop')\n } else {\n sendMessage()\n }\n}\n\n// ============== 图片错误处理 ==============\nfunction handleImageError(e: Event) {\n const img = e.target as HTMLImageElement\n img.src = 'https://models.dev/logos/openai.svg'\n}\n\n// ============== 处理文件上传 ==============\nfunction onFileChange(e: Event) {\n const input = e.target as HTMLInputElement\n if (input.files) {\n addFiles(input.files)\n }\n input.value = ''\n}\n</script>\n\n<template>\n <div class=\"input-wrapper\">\n <!-- 隐藏的文件输入 -->\n <input\n ref=\"fileInputRef\"\n type=\"file\"\n class=\"hidden\"\n multiple\n accept=\"image/*,.pdf,.doc,.docx,.txt\"\n @change=\"onFileChange\"\n >\n\n <div class=\"w-full\">\n <InputGroup class=\"input-group-shell overflow-hidden\">\n <div class=\"input-top\">\n <div v-if=\"props.suggestions.length > 0\" class=\"input-suggestions\">\n <ChatSuggestions\n :suggestions=\"props.suggestions\"\n @select=\"emit('selectSuggestion', $event)\"\n />\n </div>\n\n <div v-if=\"props.suggestions.length > 0\" class=\"attachments-divider\" />\n\n <div v-if=\"files.length > 0\" class=\"input-attachments\">\n <PromptInputAttachmentsDisplay />\n </div>\n\n<!-- <div v-if=\"files.length > 0\" class=\"attachments-divider\" />-->\n </div>\n\n <!-- 文本输入区域 (PromptInputBody) -->\n <div class=\"contents\">\n <InputGroupTextarea\n v-model=\"inputText\"\n placeholder=\"有什么我能帮您的?\"\n name=\"message\"\n class=\"field-sizing-content max-h-48 min-h-16 pt-2 pb-3\"\n @keydown=\"handleKeyDown\"\n @paste=\"handlePaste\"\n @compositionstart=\"isComposing = true\"\n @compositionend=\"isComposing = false\"\n />\n </div>\n\n <!-- 底部工具栏 (PromptInputFooter) -->\n <InputGroupAddon\n align=\"block-end\"\n class=\"justify-between gap-1\"\n >\n <!-- 工具栏内容 (PromptInputTools) -->\n <div class=\"flex items-center gap-1\">\n <InputGroupButton\n type=\"button\"\n class=\"attachment-button cursor-pointer text-muted-foreground\"\n @click=\"openFileDialog\"\n >\n <PaperclipIcon class=\"size-4\" />\n </InputGroupButton>\n <slot\n name=\"attachment-trigger\"\n :addAttachments=\"addAttachments\"\n />\n </div>\n\n <!-- 右侧:模型选择器 + 发送按钮 -->\n <div class=\"flex items-center gap-1\">\n <!-- 模型选择器 -->\n <DropdownMenu v-model:open=\"modelSelectorOpen\">\n <DropdownMenuTrigger as-child>\n <InputGroupButton type=\"button\" class=\"flex items-center gap-1 cursor-pointer\">\n <img\n v-if=\"selectedModelData\"\n :src=\"`https://models.dev/logos/${getProviderByModelName(selectedModelData.name)}.svg`\"\n class=\"size-4 rounded-sm object-contain\"\n :alt=\"selectedModelData.name\"\n @error=\"handleImageError\"\n >\n <span v-if=\"selectedModelData\" class=\"whitespace-nowrap\">{{ selectedModelData.name }}</span>\n <span v-else class=\"text-muted-foreground\">选择模型</span>\n <ChevronDownIcon class=\"size-4 opacity-50 shrink-0\" />\n </InputGroupButton>\n </DropdownMenuTrigger>\n\n <DropdownMenuContent align=\"start\">\n <template v-for=\"provider in providers\" :key=\"provider\">\n <div class=\"px-2 py-1.5 text-xs font-semibold text-[var(--ai-menu-heading)]\">\n 请选择模型\n </div>\n <DropdownMenuItem\n v-for=\"model in groupedModels[provider]\"\n :key=\"model.name\"\n @select=\"() => handleModelSelect(model.name)\"\n class=\"cursor-pointer gap-1 text-[13px] text-[var(--ai-menu-text)]\"\n >\n <img\n :src=\"`https://models.dev/logos/${getProviderByModelName(model.name)}.svg`\"\n class=\"size-4 rounded-sm object-contain\"\n :alt=\"model.name\"\n @error=\"handleImageError\"\n >\n <span class=\"flex-1 truncate\">\n {{ model.name }}\n <span v-if=\"model.is_default\" class=\"ml-1.5 rounded bg-[var(--ai-muted-surface)] px-1.5 py-0.5 text-[11px] text-[var(--ai-menu-heading)]\">\n 默认\n </span>\n </span>\n <CheckIcon\n v-if=\"selectedModelData?.name === model.name\"\n class=\"size-4\"\n />\n </DropdownMenuItem>\n </template>\n </DropdownMenuContent>\n </DropdownMenu>\n\n <!-- 发送按钮 (PromptInputSubmit) -->\n <InputGroupButton\n aria-label=\"Submit\"\n type=\"button\"\n size=\"icon-sm\"\n :variant=\"buttonVariant\"\n class=\"cursor-pointer disabled:cursor-not-allowed\"\n :disabled=\"isDisabled\"\n @click=\"handleSubmitClick\"\n >\n <component :is=\"submitIcon\" :class=\"iconClass\" />\n </InputGroupButton>\n </div>\n </InputGroupAddon>\n </InputGroup>\n </div>\n </div>\n</template>\n\n<style scoped>\n.input-wrapper {\n padding: 4px 12px 8px;\n border-top: 1px solid var(--ai-border-subtle);\n background: var(--ai-input-panel-bg);\n flex-shrink: 0;\n}\n\n.input-top {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 100%;\n align-items: flex-start;\n}\n\n.input-suggestions {\n width: 100%;\n padding: 8px 12px 0;\n}\n\n.input-attachments {\n width: 100%;\n max-height: 120px;\n padding: 4px 12px;\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: thin;\n scrollbar-color: var(--ai-scrollbar-thumb) transparent;\n}\n\n.input-attachments::-webkit-scrollbar {\n width: 6px;\n}\n\n.input-attachments::-webkit-scrollbar-thumb {\n background: var(--ai-scrollbar-thumb);\n border-radius: 999px;\n}\n\n.input-attachments::-webkit-scrollbar-thumb:hover {\n background: var(--ai-scrollbar-thumb-hover);\n}\n\n.attachments-divider {\n width: calc(100% - 24px);\n margin: 4px 12px 0;\n border-top: 1px solid var(--ai-border-subtle);\n}\n\n.input-group-shell {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n}\n\n.attachment-button:hover,\n.attachment-button:focus,\n.attachment-button:focus-visible,\n.attachment-button[data-state='open'] {\n background: transparent !important;\n color: inherit !important;\n}\n</style>\n","<script setup lang=\"ts\">\ninterface Props {\n size?: number\n}\n\nwithDefaults(defineProps<Props>(), {\n size: 16,\n})\n</script>\n\n<template>\n <svg\n :height=\"size\"\n stroke-linejoin=\"round\"\n :style=\"{ color: 'currentcolor' }\"\n viewBox=\"0 0 16 16\"\n :width=\"size\"\n >\n <title>Loader</title>\n <g clip-path=\"url(#clip0_2393_1490)\">\n <path d=\"M8 0V4\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M8 16V12\" opacity=\"0.5\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M3.29773 1.52783L5.64887 4.7639\" opacity=\"0.9\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M12.7023 1.52783L10.3511 4.7639\" opacity=\"0.1\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M12.7023 14.472L10.3511 11.236\" opacity=\"0.4\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M3.29773 14.472L5.64887 11.236\" opacity=\"0.6\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M15.6085 5.52783L11.8043 6.7639\" opacity=\"0.2\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M0.391602 10.472L4.19583 9.23598\" opacity=\"0.7\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M15.6085 10.4722L11.8043 9.2361\" opacity=\"0.3\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M0.391602 5.52783L4.19583 6.7639\" opacity=\"0.8\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n </g>\n <defs>\n <clipPath id=\"clip0_2393_1490\">\n <rect fill=\"white\" height=\"16\" width=\"16\" />\n </clipPath>\n </defs>\n </svg>\n</template>\n","<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport LoaderIcon from './LoaderIcon.vue'\n\ninterface Props {\n size?: number\n class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 16,\n})\n</script>\n\n<template>\n <div\n :class=\"cn('inline-flex animate-spin items-center justify-center', props.class)\"\n aria-label=\"Loading\"\n aria-live=\"polite\"\n role=\"status\"\n v-bind=\"$attrs\"\n >\n <LoaderIcon :size=\"props.size\" />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { CustomContent } from './lib/message-types'\nimport { ArrowUpRight } from 'lucide-vue-next'\n\ninterface Props {\n customContent: CustomContent\n apiUrl: string\n threadId: string | null\n}\n\nconst props = defineProps<Props>()\n\n// 只处理 generated_files 类型\nconst files = props.customContent?.type === 'generated_files'\n ? props.customContent.content\n : null\n</script>\n\n<template>\n <div v-if=\"files && Array.isArray(files)\" class=\"generated-files\">\n <a\n v-for=\"(file, index) in files\"\n :key=\"index\"\n class=\"file-item\"\n :href=\"`${props.apiUrl}/webapp/download/${props.threadId}?path=${encodeURIComponent(file)}`\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n <span>{{ file }}</span>\n <ArrowUpRight class=\"file-icon\" />\n </a>\n </div>\n</template>\n\n<style scoped>\n.generated-files {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.file-item {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n font-size: 13px;\n color: var(--ai-file-pill-text);\n background: var(--ai-file-pill-bg);\n border-radius: 9999px;\n text-decoration: none;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.file-item:hover {\n background: var(--ai-file-pill-hover-bg);\n}\n\n.file-item .file-icon {\n width: 14px;\n height: 14px;\n flex-shrink: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { CSSProperties, HTMLAttributes } from 'vue'\nimport { cn } from '@/components/ai-bot/lib/utils'\nimport { motion } from 'motion-v'\nimport { computed, useSlots } from 'vue'\n\nexport interface TextShimmerProps {\n as?: keyof HTMLElementTagNameMap\n class?: HTMLAttributes['class']\n duration?: number\n spread?: number\n}\n\nconst props = withDefaults(defineProps<TextShimmerProps>(), {\n as: 'p',\n duration: 2,\n spread: 2,\n})\n\nconst slots = useSlots()\n\nconst textContent = computed(() => {\n const defaultSlot = slots.default?.()\n if (!defaultSlot || defaultSlot.length === 0)\n return ''\n\n return defaultSlot\n .map((vnode) => {\n if (typeof vnode.children === 'string') {\n return vnode.children\n }\n return ''\n })\n .join('')\n})\n\nconst dynamicSpread = computed(() => {\n return (textContent.value?.length ?? 0) * props.spread\n})\n\nconst componentClasses = computed(() => cn('relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent', '[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]', props.class))\n\nconst componentStyle = computed((): CSSProperties => ({\n '--spread': `${dynamicSpread.value}px`,\n 'backgroundImage':\n 'var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))',\n}))\n\nconst MotionComponent = computed(() => {\n return motion[props.as as keyof typeof motion] || motion.p\n})\n</script>\n\n<template>\n <component\n :is=\"MotionComponent\"\n :class=\"componentClasses\"\n :style=\"componentStyle\"\n :initial=\"{ backgroundPosition: '100% center' }\"\n :animate=\"{ backgroundPosition: '0% center' }\"\n :transition=\"{\n repeat: Number.POSITIVE_INFINITY,\n duration,\n ease: 'linear',\n }\"\n >\n <slot />\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { Ban, ChevronsDown, ChevronsUp, Circle, CircleCheckBig, LoaderCircle } from 'lucide-vue-next'\nimport type { ToolEventPayload } from './lib/tool-events'\nimport { Shimmer } from './ai-elements/shimmer'\n\nexport interface TodoItem {\n id: string\n title: string\n status: 'pending' | 'in_progress' | 'completed' | 'interrupted'\n}\n\ninterface Props {\n initialTodos?: RawTodo[]\n toolEvents?: ToolEventPayload[]\n chatStatus?: 'ready' | 'streaming'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n initialTodos: () => [],\n toolEvents: () => [],\n chatStatus: 'ready'\n})\n\nconst todos = ref<TodoItem[]>([])\nconst processedEventCount = ref(0)\nconst completedCount = computed(() => todos.value.filter(todo => todo.status === 'completed').length)\nconst inProgressCount = computed(() => todos.value.filter(todo => todo.status === 'in_progress').length)\nconst interruptedCount = computed(() => todos.value.filter(todo => todo.status === 'interrupted').length)\nconst pendingCount = computed(() => todos.value.filter(todo => todo.status === 'pending').length)\n\nconst expanded = ref(false)\nconst userCollapsed = ref(false)\n\nfunction toggleExpanded() {\n expanded.value = !expanded.value\n userCollapsed.value = !expanded.value\n}\n\nfunction syncExpandedWithTodos(nextTodos: TodoItem[]) {\n if (nextTodos.length === 0) {\n expanded.value = false\n userCollapsed.value = false\n return\n }\n\n // 仅在对话进行中且仍处于自动模式时,随着流式更新保持展开。\n if (!userCollapsed.value && props.chatStatus === 'streaming') {\n expanded.value = true\n }\n}\n\nfunction isWriteTodosTool(toolName?: string): boolean {\n return (toolName || '') === 'write_todos'\n}\n\nfunction normalizeTodoStatus(rawStatus: unknown, fallback: TodoItem['status']): TodoItem['status'] {\n const status = String(rawStatus || '').toLowerCase()\n if (status === 'completed') return 'completed'\n if (status === 'in_progress') return 'in_progress'\n if (status === 'pending') return 'pending'\n if (status === 'interrupted') return 'interrupted'\n return fallback\n}\n\nfunction normalizeHistoricalTodoStatus(rawStatus: unknown): TodoItem['status'] {\n const status = normalizeTodoStatus(rawStatus, 'pending')\n return status === 'in_progress' ? 'interrupted' : status\n}\n\nfunction statusByPhase(event: ToolEventPayload): TodoItem['status'] {\n if (event.state === 'completed') return 'completed'\n if (event.state === 'interrupted') return 'interrupted'\n if (event.phase === 'tool_call_started') return 'pending'\n return 'in_progress'\n}\n\ntype RawTodo = {\n id?: string\n title?: string\n task?: string\n content?: string\n text?: string\n name?: string\n status?: string\n state?: string\n}\n\nfunction mapRawTodos(rawTodos: RawTodo[], fallbackState: TodoItem['status'] = 'pending'): TodoItem[] {\n return rawTodos.map((todo, index) => ({\n id: todo.id || `todo-${index + 1}`,\n title: todo.title || todo.task || todo.content || todo.text || todo.name || '',\n status: normalizeTodoStatus(todo.status || todo.state, fallbackState)\n })).filter(todo => todo.title)\n}\n\nfunction mapHistoricalTodos(rawTodos: RawTodo[]): TodoItem[] {\n return rawTodos.map((todo, index) => ({\n id: todo.id || `todo-${index + 1}`,\n title: todo.title || todo.task || todo.content || todo.text || todo.name || '',\n status: normalizeHistoricalTodoStatus(todo.status || todo.state)\n })).filter(todo => todo.title)\n}\n\nfunction finalizeInProgressTodos() {\n const nextTodos = todos.value.map(todo => {\n if (todo.status !== 'in_progress') {\n return todo\n }\n return {\n ...todo,\n status: 'interrupted' as const\n }\n })\n\n todos.value = nextTodos\n syncExpandedWithTodos(nextTodos)\n}\n\ntype RawTodoContainer = {\n todo?: RawTodo\n todos?: RawTodo[]\n item?: RawTodo\n items?: RawTodo[]\n}\n\nfunction isRawTodoContainer(payload: RawTodo | RawTodoContainer): payload is RawTodoContainer {\n return 'todo' in payload || 'todos' in payload || 'item' in payload || 'items' in payload\n}\n\nfunction parseRawTodoItems(raw?: string): RawTodo[] {\n if (!raw) return []\n\n try {\n const payload = JSON.parse(raw) as RawTodo | RawTodo[] | RawTodoContainer\n\n if (Array.isArray(payload)) {\n return payload\n }\n\n if (isRawTodoContainer(payload)) {\n if (Array.isArray(payload.todos)) return payload.todos\n if (Array.isArray(payload.items)) return payload.items\n if (payload.todo) return [payload.todo]\n if (payload.item) return [payload.item]\n }\n\n return []\n } catch {\n return []\n }\n}\n\nfunction parseToolTodos(raw?: string, fallbackState: TodoItem['status'] = 'pending'): TodoItem[] {\n const rawTodos = parseRawTodoItems(raw)\n return mapRawTodos(rawTodos, fallbackState)\n}\n\nfunction replaceWriteTodos(raw?: string, fallbackState: TodoItem['status'] = 'pending') {\n const nextTodos = parseToolTodos(raw, fallbackState)\n if (nextTodos.length === 0) return false\n\n todos.value = nextTodos\n syncExpandedWithTodos(nextTodos)\n return true\n}\n\nfunction applyToolEvent(event: ToolEventPayload) {\n const fallbackState = statusByPhase(event)\n\n if (!isWriteTodosTool(event.name)) return\n\n // write_todos 的结构化数据只看 args;result 只是日志文本,不参与待办解析。\n replaceWriteTodos(event.args, fallbackState)\n}\n\nwatch(\n () => props.initialTodos,\n (rawTodos) => {\n const nextTodos = mapHistoricalTodos(rawTodos || [])\n todos.value = nextTodos\n syncExpandedWithTodos(nextTodos)\n },\n { deep: true, immediate: true }\n)\n\nwatch(\n () => props.toolEvents,\n (events) => {\n if (!events.length) {\n processedEventCount.value = 0\n return\n }\n\n if (events.length < processedEventCount.value) {\n todos.value = []\n processedEventCount.value = 0\n syncExpandedWithTodos([])\n }\n\n const nextEvents = events.slice(processedEventCount.value)\n nextEvents.forEach((event) => {\n // TodoList 自己消费 todo 相关工具事件,列表状态和渲染逻辑保持在组件内部。\n applyToolEvent(event)\n })\n processedEventCount.value = events.length\n },\n { deep: true, immediate: true }\n)\n\nwatch(\n () => props.chatStatus,\n (next, prev) => {\n if (prev === 'streaming' && next === 'ready') {\n finalizeInProgressTodos()\n }\n }\n)\n</script>\n\n<template>\n <div v-if=\"todos.length\" class=\"todo-section\">\n <div class=\"todo-card\">\n <div\n class=\"todo-divider\"\n :class=\"{ collapsed: !expanded }\"\n @click=\"toggleExpanded\"\n >\n <div class=\"title\">\n <component\n :is=\"expanded ? ChevronsDown : ChevronsUp\"\n :size=\"13\"\n class=\"title-chevron\"\n />\n <span class=\"title-label\">执行计划</span>\n <span class=\"title-summary\">{{ completedCount }}/{{ todos.length }}</span>\n <span class=\"title-meta\">\n {{ inProgressCount > 0 ? `进行中 ${inProgressCount}` : interruptedCount > 0 ? `中断 ${interruptedCount}` : pendingCount > 0 ? `待处理 ${pendingCount}` : '已完成' }}\n </span>\n </div>\n </div>\n\n <div v-show=\"expanded\" class=\"todo-list\">\n\n <div\n v-for=\"(todo, index) in todos\"\n :key=\"todo.id\"\n class=\"todo-item\"\n >\n\n <div class=\"todo-row\">\n <div\n class=\"todo-content\"\n :class=\"{\n completed: todo.status === 'completed',\n pending: todo.status === 'pending',\n interrupted: todo.status === 'interrupted',\n 'in-progress': todo.status === 'in_progress'\n }\"\n >\n <span class=\"todo-index\">{{ index + 1 }}.</span>\n\n <span class=\"indicator\" aria-hidden=\"true\">\n <Circle\n v-if=\"todo.status === 'pending'\"\n :size=\"13\"\n class=\"status-icon pending-icon\"\n />\n <LoaderCircle\n v-if=\"todo.status === 'in_progress'\"\n :size=\"13\"\n class=\"status-icon in-progress-icon\"\n />\n <Ban\n v-if=\"todo.status === 'interrupted'\"\n :size=\"13\"\n class=\"status-icon interrupted-icon\"\n />\n <CircleCheckBig\n v-if=\"todo.status === 'completed'\"\n :size=\"13\"\n class=\"status-icon completed-icon\"\n />\n </span>\n\n <Shimmer\n v-if=\"todo.status === 'in_progress'\"\n as=\"div\"\n class=\"title-text-base title-text-shimmer\"\n >\n {{ todo.title }}\n </Shimmer>\n\n <div v-else class=\"title-text-base title-text\">\n {{ todo.title }}\n </div>\n </div>\n\n </div>\n\n </div>\n\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.todo-section {\n padding: 2px 12px 0;\n}\n\n.todo-card {\n --todo-surface: var(--ai-plan-bg);\n --todo-surface-strong: var(--ai-plan-bg-strong);\n --todo-border: var(--ai-plan-border);\n --todo-divider: var(--ai-plan-border);\n --todo-title: var(--foreground);\n --todo-muted: var(--ai-plan-muted);\n --todo-summary-bg: color-mix(in srgb, var(--ai-plan-bg-strong) 82%, var(--ai-plan-border));\n --todo-summary-border: var(--ai-plan-border);\n --todo-summary-text: color-mix(in srgb, var(--foreground) 72%, var(--ai-plan-muted));\n --todo-hover: var(--ai-plan-hover);\n --todo-text: color-mix(in srgb, var(--foreground) 88%, transparent);\n --todo-index: color-mix(in srgb, var(--ai-plan-muted) 88%, transparent);\n --todo-pending: color-mix(in srgb, var(--ai-plan-muted) 84%, transparent);\n --todo-progress: var(--ai-plan-progress);\n --todo-interrupted: var(--ai-plan-interrupted);\n --todo-interrupted-text: color-mix(in srgb, var(--foreground) 74%, var(--ai-plan-interrupted));\n --todo-completed: var(--ai-plan-complete);\n --todo-completed-text: color-mix(in srgb, var(--foreground) 62%, var(--ai-plan-complete));\n border-radius: 6px;\n border: 1px solid var(--todo-border);\n background:\n linear-gradient(180deg, var(--todo-surface-strong), var(--todo-surface)),\n var(--todo-surface-strong);\n box-shadow:\n inset 0 1px 0 color-mix(in srgb, var(--foreground) 8%, transparent),\n 0 4px 12px color-mix(in srgb, var(--ai-plan-border) 36%, transparent);\n overflow: hidden;\n}\n\n.todo-divider {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n padding: 6px 12px;\n cursor: pointer;\n user-select: none;\n border-bottom: 1px solid transparent;\n transition: background-color 0.18s ease, border-color 0.18s ease, padding 0.18s ease;\n}\n\n.todo-divider.collapsed {\n padding-top: 6px;\n padding-bottom: 6px;\n}\n\n.todo-divider:hover {\n background: var(--todo-hover);\n}\n\n.title {\n display: flex;\n align-items: center;\n gap: 5px;\n flex-wrap: wrap;\n}\n\n.todo-divider.collapsed .title {\n gap: 4px;\n}\n\n.title-chevron {\n color: var(--todo-muted);\n}\n\n.title-label {\n font-size: 12px;\n line-height: 1;\n font-weight: 700;\n color: var(--todo-title);\n margin-right: 4px;\n letter-spacing: 0.01em;\n}\n\n.title-summary {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 32px;\n height: 17px;\n padding: 0 6px;\n border-radius: 999px;\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n background: var(--todo-summary-bg);\n border: 1px solid var(--todo-summary-border);\n color: var(--todo-summary-text);\n}\n\n.title-meta {\n font-size: 10px;\n line-height: 1;\n color: var(--todo-muted);\n}\n\n.todo-list {\n padding: 0 6px 6px;\n max-height: 180px;\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: thin;\n scrollbar-color: var(--ai-scrollbar-thumb) transparent;\n border-top: 1px solid var(--todo-divider);\n}\n\n.todo-list::-webkit-scrollbar {\n width: 6px;\n}\n\n.todo-list::-webkit-scrollbar-thumb {\n background: var(--ai-scrollbar-thumb);\n border-radius: 999px;\n}\n\n.todo-list::-webkit-scrollbar-thumb:hover {\n background: var(--ai-scrollbar-thumb-hover);\n}\n\n.todo-item {\n padding: 3px 8px;\n}\n\n.todo-row {\n display: flex;\n align-items: center;\n gap: 0;\n}\n\n.todo-content {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n min-height: 24px;\n padding: 2px 8px;\n border-radius: 6px;\n}\n\n.todo-index {\n min-width: 14px;\n text-align: right;\n flex-shrink: 0;\n}\n\n.indicator {\n width: 16px;\n height: 16px;\n border: 0;\n border-radius: 999px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n flex-shrink: 0;\n padding: 0;\n pointer-events: none;\n}\n\n.status-icon {\n display: block;\n}\n\n.todo-index,\n.title-text-base {\n font-size: 13px;\n line-height: 1.35;\n}\n\n.title-text {\n color: var(--todo-text);\n}\n\n.title-text-shimmer {\n --color-muted-foreground: color-mix(in srgb, var(--ai-plan-progress) 36%, transparent);\n --color-background: var(--ai-plan-progress);\n}\n\n.todo-content.pending .title-text,\n.todo-content.in-progress .title-text-shimmer,\n.todo-content.interrupted .title-text,\n.todo-content.completed .title-text {\n font-size: 12px;\n line-height: 1.35;\n}\n\n.todo-content.interrupted .title-text {\n color: var(--todo-interrupted-text);\n}\n\n.todo-content.completed .title-text {\n color: var(--todo-completed-text);\n}\n\n.todo-index {\n color: var(--todo-index);\n font-size: 11px;\n}\n\n.completed .indicator {\n color: var(--todo-completed);\n}\n\n.pending .indicator {\n color: var(--todo-pending);\n}\n\n.in-progress .indicator {\n color: var(--todo-progress);\n}\n\n.interrupted .indicator {\n color: var(--todo-interrupted);\n}\n\n.completed-icon {\n color: var(--todo-completed);\n}\n\n.pending-icon {\n color: var(--todo-pending);\n}\n\n.in-progress-icon {\n color: var(--todo-progress);\n animation: todo-spin 1.4s linear infinite;\n}\n\n.interrupted-icon {\n color: var(--todo-interrupted);\n}\n\n@keyframes todo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n</style>\n","<script setup lang=\"ts\">\nimport { ref, onMounted, provide } from 'vue'\nimport type { AiBotInputApi, AiBotPublicApi, AttachmentTriggerSlotProps, PromptInputMessage } from './lib/input-types'\nimport type { ChatMessage, ChatStatus, ChatFile, CustomContent } from './lib/message-types'\nimport type { AiBotTheme } from './lib/theme'\nimport { fetchModels, getDefaultModel, type ModelInfo } from './lib/models'\nimport type { ToolEventPayload, ToolEventPhase, ToolEventState } from './lib/tool-events'\nimport { Client } from '@langchain/langgraph-sdk'\nimport { createThread, loadThreadHistory } from './lib/thread'\nimport { PORTAL_HOST_KEY } from './lib/portal-host'\n\nimport ChatHeader from './ChatHeader.vue'\nimport ChatMessages from './ChatMessages.vue'\nimport ChatInput from './ChatInput.vue'\nimport { Loader } from './ai-elements/loader'\nimport GeneratedFiles from './GeneratedFiles.vue'\nimport TodoList from './TodoList.vue'\n\nconst chatInputRef = ref<AiBotInputApi | null>(null)\n\ninterface Props {\n assistantId?: string\n assistantName?: string\n systemPrompt?: string\n threadId?: string\n userId?: string\n showHeaderActions?: boolean\n suggestions?: string[]\n apiUrl?: string\n apiKey?: string\n theme?: AiBotTheme\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n assistantId: 'research',\n assistantName: 'Chat',\n systemPrompt: '你是一个有用的助手,帮用户解决各种问题。',\n userId: 'user001',\n showHeaderActions: true,\n suggestions: () => [],\n apiUrl: 'http://localhost:2024',\n apiKey: undefined,\n theme: 'light'\n})\n\ndefineSlots<{\n empty?: (props: { sendMessage: (message: string, files?: ChatFile[]) => void }) => any\n custom?: (props: { customContent: CustomContent, threadId: string | null }) => any\n 'attachment-trigger'?: (props: AttachmentTriggerSlotProps) => any\n}>()\n\n// LangGraph Client\nconst client = new Client({\n apiUrl: props.apiUrl,\n apiKey: props.apiKey || undefined\n})\n\n// 状态\nconst isMaximized = ref(false)\nconst threadId = ref<string | null>(null)\nconst portalHost = ref<HTMLElement | null>(null)\nprovide(PORTAL_HOST_KEY, { portalHost })\nconst status = ref<ChatStatus>('ready')\nconst runId = ref<string>('')\nconst useWebSearch = ref(false)\nconst modelSelectorOpen = ref(false)\nconst isLoading = ref(true)\n\n// 消息\nconst messages = ref<ChatMessage[]>([])\n\n// 建议问题(支持动态更新)\nconst suggestions = ref<string[]>([])\n\nconst initialTodos = ref<any[]>([])\nconst todoToolEvents = ref<ToolEventPayload[]>([])\n\nfunction isTodoTool(toolName?: string): boolean {\n const name = toolName || ''\n return name.includes('todo') || name === 'write_todos'\n}\n\nfunction handleToolEvent(params: {\n phase: ToolEventPhase\n id?: string\n name?: string\n rawArgs?: string\n result?: string\n state: ToolEventState\n}) {\n // ChatBot 只捕获通用工具事件,按工具名把 todo 事件分发给 TodoList。\n if (!isTodoTool(params.name)) return\n\n todoToolEvents.value = [...todoToolEvents.value, {\n phase: params.phase,\n id: params.id,\n name: params.name,\n args: params.rawArgs,\n result: params.result,\n state: params.state\n }]\n}\n\n// 模型列表\nconst models = ref<ModelInfo[]>([])\nconst currentModel = ref<ModelInfo | null>(null)\n\n// 初始化\nonMounted(async () => {\n isLoading.value = true\n // 初始化建议问题\n suggestions.value = [...props.suggestions]\n\n // 并行获取模型列表和加载历史\n await Promise.all([\n (async () => {\n const data = await fetchModels(props.apiUrl)\n models.value = data\n currentModel.value = getDefaultModel(data) || null\n })(),\n props.threadId ? (async () => {\n const tid = await createThread(client, props.threadId, props.userId)\n threadId.value = tid\n messages.value = await loadThreadHistory(\n client,\n tid,\n (questions) => {\n suggestions.value = questions\n },\n (todos) => {\n initialTodos.value = todos\n }\n )\n })() : Promise.resolve()\n ])\n isLoading.value = false\n})\n\n// 切换最大化状态\nfunction toggleMaximize() {\n isMaximized.value = !isMaximized.value\n emit('update:isMaximized', isMaximized.value)\n}\n\n// 发送消息\nasync function handleSubmit(userMessage: string, files: ChatFile[] = []) {\n // 统一状态控制:忙碌状态不允许发送\n if (status.value === 'streaming') return\n status.value = 'streaming'\n\n // 构建消息内容:文本 + 附件\n const contentBlocks: any[] = []\n\n // 添加文本内容\n if (userMessage.trim()) {\n contentBlocks.push({ type: 'text', text: userMessage })\n }\n\n // 添加附件内容\n for (const file of files) {\n const mimeType = file.mediaType || 'application/octet-stream'\n const filename = file.filename || file.id || 'unknown'\n const rawData = file.data || file.url || ''\n const isDataUrl = rawData.startsWith('data:')\n const base64Data = isDataUrl ? rawData.split(',')[1] || '' : ''\n const normalizedType = file.type || (isDataUrl ? (mimeType.startsWith('image/') ? 'image' : 'file') : 'file_url')\n\n if ((normalizedType === 'file' || normalizedType === 'image') && base64Data) {\n if (normalizedType === 'image') {\n contentBlocks.push({\n type: 'image',\n mimeType,\n data: base64Data,\n metadata: { name: filename }\n })\n } else {\n contentBlocks.push({\n type: 'file',\n mimeType,\n data: base64Data,\n metadata: { filename }\n })\n }\n continue\n }\n\n if (file.url) {\n contentBlocks.push({\n type: 'file_url',\n url: file.url,\n mimeType,\n metadata: { filename }\n })\n }\n }\n\n // 添加用户消息到本地列表\n const userMessageId = `human-${Date.now()}`\n messages.value = [\n ...messages.value,\n {\n key: userMessageId,\n type: 'human',\n content: userMessage,\n files: files.map(f => ({ url: f.url, mediaType: f.mediaType, filename: f.filename }))\n }\n ]\n\n try {\n if (!threadId.value) {\n const thread = await client.threads.create({\n metadata: {\n user_id: props.userId,\n name: userMessage.slice(0, 50)\n }\n })\n threadId.value = thread.thread_id\n }\n\n const streamResponse = client.runs.stream(\n threadId.value!,\n props.assistantId,\n {\n input: {\n messages: [\n ...(props.systemPrompt ? [{\n type: 'system' as const,\n content: [{ type: 'text', text: props.systemPrompt }]\n }] : []),\n {\n type: 'human' as const,\n content: contentBlocks\n }\n ]\n },\n config: {\n tags: ['serv'],\n configurable: {\n model_provider: currentModel.value?.provider || 'openai',\n model: currentModel.value?.name || '',\n base_url: currentModel.value?.base_url || ''\n }\n },\n metadata: {\n user_id: props.userId,\n name: userMessage.slice(0, 50)\n },\n streamMode: ['messages-tuple', 'custom'],\n stream_resumable: false,\n on_disconnect: 'cancel'\n } as any\n )\n\n // 添加空的助手消息\n const assistantMessageId = `ai-${Date.now()}`\n messages.value = [\n ...messages.value,\n {\n key: assistantMessageId,\n type: 'ai',\n content: '',\n batchId: ''\n }\n ]\n\n let assistantContent = ''\n // 使用 message.id + index 跟踪同一条流式工具调用,避免 chunks 的空 id / 空 name 无法匹配。\n const assistantToolCalls = new Map<string, { id: string; name: string; args: string; messageKey?: string }>()\n let needNewAssistantMessage = false // 是否需要创建新的 assistant 消息\n\n // 辅助函数:创建工具消息\n function createToolMessage(toolCallId: string, name: string, args: string, state: string): ChatMessage {\n return {\n key: `tool-${toolCallId}-${Date.now()}`,\n type: 'tool',\n content: '',\n batchId: runId.value,\n toolCalls: [{\n id: toolCallId,\n name: name,\n args: args,\n result: '',\n state: state\n }]\n }\n }\n\n // 辅助函数:更新工具消息\n function updateToolMessage(messageKey: string, updates: { args?: string; result?: string; state?: string }) {\n const msg = messages.value[messageKey]\n if (msg && msg.toolCalls && msg.toolCalls.length > 0) {\n if (updates.args !== undefined) {\n msg.toolCalls[0].args = updates.args\n }\n if (updates.result !== undefined) {\n msg.toolCalls[0].result = updates.result\n }\n if (updates.state !== undefined) {\n msg.toolCalls[0].state = updates.state\n }\n }\n }\n\n // 流式处理 LangGraph SDK 返回的消息\n for await (const chunk of streamResponse) {\n const chunkEvent = chunk.event as string\n const data = chunk.data as any\n\n // 从 metadata 事件中获取 run_id\n if (chunkEvent === 'metadata' && data?.run_id) {\n runId.value = data.run_id\n }\n\n // 处理 custom 事件\n if (chunkEvent === 'custom') {\n handleCustomEvent(data)\n\n // suggested_questions 类型不外发为消息,只更新 suggestions\n if (data?.type === 'suggested_questions') {\n continue\n }\n\n // 将其他 custom 消息添加到消息列表\n const customContent: CustomContent = {\n type: data?.type || 'unknown',\n content: data?.content\n }\n const customMessageId = `custom-${Date.now()}`\n messages.value = [\n ...messages.value,\n {\n key: customMessageId,\n type: 'custom',\n content: '',\n customContent\n }\n ]\n console.log('📦 Custom 消息:', customContent)\n continue\n }\n\n if (chunkEvent === 'messages' || chunkEvent === 'messages/partial') {\n const messageArray = Array.isArray(data) ? data : [data]\n const message = messageArray[0] as any\n\n // 从消息元数据中获取 run_id\n const messageMeta = messageArray[1] as any\n if (messageMeta?.run_id) {\n runId.value = messageMeta.run_id\n }\n\n if (message) {\n // 获取消息类型\n const messageType = message.type\n\n // 处理工具消息 - tool 类型(阶段4:结果返回)\n // 更新已有的工具消息,而不是创建新的\n if (messageType === 'tool') {\n const toolCallId = message.tool_call_id\n const toolName = message.name || '未知工具'\n const toolResult = typeof message.content === 'string' ? message.content : JSON.stringify(message.content)\n const toolStatus = message.status\n\n // 阶段4:根据 tool_call_id 找回前面阶段累加好的原始参数。\n let foundToolCall: { id: string; name: string; args: string; messageKey?: string } | undefined\n for (const [key, tc] of assistantToolCalls) {\n if (tc.id === toolCallId) {\n foundToolCall = tc\n // 找到后删除,释放内存\n assistantToolCalls.delete(key)\n break\n }\n }\n\n // 映射后端状态到 UI 状态\n const mapToolStatus = (status: string): string => {\n switch (status) {\n case 'success': return 'completed'\n case 'error': return 'error'\n case 'running': return 'running'\n default: return 'completed'\n }\n }\n const uiState = mapToolStatus(toolStatus)\n\n // 工具结果优先回填已有工具消息,找不到时再兜底创建一条。\n if (foundToolCall && foundToolCall.messageKey !== undefined) {\n // 更新已有的工具消息\n updateToolMessage(foundToolCall.messageKey, {\n args: foundToolCall.args,\n result: toolResult,\n state: uiState\n })\n } else {\n // 没有找到对应的工具消息,创建新的(兼容情况)\n const toolMessageId = `tool-${toolCallId}-${Date.now()}`\n const toolMessage: ChatMessage = {\n key: toolMessageId,\n type: 'tool',\n content: toolResult,\n batchId: runId.value,\n toolCalls: [{\n id: toolCallId,\n name: toolName,\n args: foundToolCall?.args || '',\n result: toolResult,\n state: uiState,\n error: toolStatus === 'error' ? toolResult : undefined\n }]\n }\n messages.value.push(toolMessage)\n }\n\n // 把阶段4结果交给通用工具事件分发器,由具体工具自行消费。\n handleToolEvent({\n phase: 'tool_result',\n id: toolCallId,\n name: toolName,\n rawArgs: foundToolCall?.args || '',\n result: toolResult,\n state: uiState as ToolEventState\n })\n\n console.log('🔧 阶段4 - 工具结果返回:', {\n name: toolName,\n id: toolCallId,\n args: foundToolCall?.args || '',\n result: toolResult,\n status: toolStatus,\n messageCount: messages.value.length\n })\n\n // 标记下一条 AI 消息需要创建新消息\n needNewAssistantMessage = true\n\n continue // 跳过后续处理\n }\n\n // 阶段3:tool_call_chunks 已经结束,但工具执行结果可能还没返回。\n if (message.chunk_position === 'last') {\n for (const [, tc] of assistantToolCalls) {\n if (tc.messageKey !== undefined) {\n updateToolMessage(tc.messageKey, { state: 'running' })\n }\n // 这里继续透传生命周期事件,让具体工具决定是否需要“运行中”过渡态。\n handleToolEvent({\n phase: 'tool_call_finished',\n id: tc.id,\n name: tc.name,\n rawArgs: tc.args,\n state: 'running'\n })\n }\n console.log('🛑 阶段3 - 工具调用结束', {\n chunk_position: message.chunk_position,\n toolCallsCount: assistantToolCalls.size,\n allToolCalls: Array.from(assistantToolCalls.values()).map(t => ({ id: t.id, name: t.name, args: t.args }))\n })\n }\n\n // 阶段1-2:先记录工具声明,再逐块累加原始参数字符串。\n const messageId = message.id\n const hasToolCalls = message.tool_calls && message.tool_calls.length > 0\n const hasChunks = message.tool_call_chunks && message.tool_call_chunks.length > 0\n\n if (hasToolCalls || hasChunks) {\n // 阶段1:tool_calls 到达,只拿稳定的 id/name,args 以后续 chunks 为准。\n if (hasToolCalls) {\n for (const tc of message.tool_calls) {\n const index = message.tool_calls.indexOf(tc)\n const messageKey = `${messageId}_${index}`\n\n const existing = assistantToolCalls.get(messageKey)\n if (!existing) {\n // 新建 - 创建工具消息并添加到 messages\n const toolMsg = createToolMessage(tc.id, tc.name, '', 'start')\n messages.value.push(toolMsg)\n // 记录消息在数组中的索引\n const msgIndex = messages.value.length - 1\n\n assistantToolCalls.set(messageKey, {\n id: tc.id,\n name: tc.name,\n args: '',\n messageKey: msgIndex.toString()\n })\n // tool_calls 的 args 常常为空对象,这里只透传原始字符串,不做解释。\n handleToolEvent({\n phase: 'tool_call_started',\n id: tc.id,\n name: tc.name,\n rawArgs: typeof tc.args === 'string' ? tc.args : '',\n state: 'start'\n })\n console.log('📝 阶段1 - 工具调用开始:', {\n messageId,\n index,\n toolCallId: tc.id,\n name: tc.name,\n msgIndex\n })\n } else {\n // 更新 - 只更新 id 和 name\n if (tc.id) existing.id = tc.id\n if (tc.name) existing.name = tc.name\n if (tc.name) existing.name = tc.name\n // 不覆盖 args,保留 tool_call_chunks 累加的结果\n }\n }\n }\n\n // 阶段2:tool_call_chunks 才是真正的原始参数流。\n if (hasChunks) {\n for (const tcChunk of message.tool_call_chunks) {\n const index = tcChunk.index\n if (index === undefined) continue\n\n const messageKey = `${messageId}_${index}`\n\n let existing = assistantToolCalls.get(messageKey)\n\n if (!existing) {\n // 如果还没有工具调用记录,用 chunks 创建\n const toolMsg = createToolMessage(tcChunk.id || '', tcChunk.name || '', tcChunk.args || '', 'running')\n messages.value.push(toolMsg)\n const msgIndex = messages.value.length - 1\n\n assistantToolCalls.set(messageKey, {\n id: tcChunk.id || '',\n name: tcChunk.name || '',\n args: tcChunk.args || '',\n messageKey: msgIndex.toString()\n })\n // 首块 chunk 到达时就通知业务侧,便于展示“运行中”的早期状态。\n handleToolEvent({\n phase: 'tool_args_streaming',\n id: tcChunk.id || '',\n name: tcChunk.name || '',\n rawArgs: tcChunk.args || '',\n state: 'running'\n })\n console.log('📝 阶段1 - 工具调用开始:', {\n messageId,\n index,\n toolCallId: tcChunk.id || '(暂无)',\n name: tcChunk.name || '(暂无)',\n msgIndex\n })\n } else {\n // 已有记录 - 累加有实际内容的 args 并更新工具消息\n if (tcChunk.args && tcChunk.args.trim()) {\n existing.args = (existing.args || '') + tcChunk.args\n // 实时更新工具消息的参数和状态\n if (existing.messageKey) {\n updateToolMessage(existing.messageKey, { args: existing.args, state: 'running' })\n }\n // 后续 chunk 持续透传完整 rawArgs,具体工具自己决定何时解析。\n handleToolEvent({\n phase: 'tool_args_streaming',\n id: existing.id || tcChunk.id || '',\n name: existing.name || tcChunk.name || '',\n rawArgs: existing.args,\n state: 'running'\n })\n }\n // 补充 id 和 name\n if (tcChunk.id && !existing.id) existing.id = tcChunk.id\n if (tcChunk.name) existing.name = tcChunk.name\n\n console.log('📝 阶段2 - args 流式累加:', {\n messageId,\n index,\n newArgs: tcChunk.args,\n accumulatedArgs: existing.args\n })\n }\n }\n }\n }\n\n // 处理 AI 消息 - AIMessageChunk 类型,流式累加 content\n // 解析消息内容\n let content = ''\n if (typeof message.content === 'string') {\n content = message.content\n } else if (Array.isArray(message.content)) {\n content = message.content\n .filter((block: any) => block.type === 'text')\n .map((block: any) => block.text)\n .join('')\n }\n\n // 检查是否需要创建新消息(tool 消息后第一条 AI 消息)\n if (needNewAssistantMessage) {\n // 标记当前 ai 消息完成\n for (let i = messages.value.length - 1; i >= 0; i--) {\n if (messages.value[i].type === 'ai') {\n break\n }\n }\n\n // 创建新的 ai 消息\n const newAssistantMessageId = `ai-${Date.now()}`\n messages.value.push({\n key: newAssistantMessageId,\n type: 'ai',\n content: '',\n batchId: runId.value\n })\n assistantContent = ''\n needNewAssistantMessage = false\n }\n\n // 更新消息内容 - 后端返回的是增量内容,需要累加\n // content 可能是空字符串,所以用 !== undefined 来判断\n if (content !== undefined) {\n // 直接累加内容\n assistantContent += content\n }\n\n // 找到最后一条 ai 消息并更新\n let lastAssistantIndex = -1\n for (let i = messages.value.length - 1; i >= 0; i--) {\n if (messages.value[i].type === 'ai') {\n lastAssistantIndex = i\n break\n }\n }\n if (lastAssistantIndex >= 0) {\n messages.value[lastAssistantIndex].content = assistantContent\n messages.value[lastAssistantIndex].batchId = runId.value\n }\n }\n }\n }\n\n const lastIndex = messages.value.length - 1\n if (lastIndex >= 0) {\n messages.value[lastIndex].batchId = runId.value\n }\n\n status.value = 'ready'\n } catch (error: any) {\n console.error('Error sending message:', error)\n\n // 提取错误信息\n let errorDisplayMessage = '抱歉,发生了一些错误,请稍后重试。'\n if (error) {\n // 尝试从 error 对象中提取详细信息\n const errorMsg = error.message || error.error?.message || String(error)\n const errorType = error.error?.error || error.name || 'APIError'\n\n // 如果是 API 错误,显示更友好的信息\n if (errorMsg && errorMsg !== '[object Object]') {\n if (errorType === 'APIError' && errorMsg.includes('internal error')) {\n errorDisplayMessage = '服务内部错误,请稍后重试。'\n } else if (errorMsg.includes('timeout') || errorMsg.includes('Timeout')) {\n errorDisplayMessage = '请求超时,请稍后重试。'\n } else if (errorMsg.includes('network') || errorMsg.includes('Network')) {\n errorDisplayMessage = '网络连接失败,请检查网络后重试。'\n } else if (errorMsg.includes('401') || errorMsg.includes('unauthorized')) {\n errorDisplayMessage = '认证失败,请重新登录。'\n } else if (errorMsg.includes('403') || errorMsg.includes('forbidden')) {\n errorDisplayMessage = '没有权限执行此操作。'\n } else if (errorMsg.includes('429') || errorMsg.includes('rate limit')) {\n errorDisplayMessage = '请求过于频繁,请稍后再试。'\n } else {\n errorDisplayMessage = `抱歉,发生错误: ${errorMsg}`\n }\n }\n }\n\n const errorMessageId = `error-${Date.now()}`\n messages.value = [\n ...messages.value,\n {\n key: errorMessageId,\n type: 'ai',\n content: errorDisplayMessage,\n batchId: errorMessageId\n }\n ]\n status.value = 'ready'\n }\n}\n\n// 处理表单提交\nfunction handleFormSubmit(message: PromptInputMessage) {\n const hasText = !!message.text\n const hasAttachments = message.files?.length > 0\n\n if (!hasText && !hasAttachments) {\n return\n }\n\n const text = message.text?.trim() || ''\n handleSubmit(text || '仅发送了附件', message.files || [])\n}\n\n// 处理停止按钮点击\nasync function handleStop() {\n console.log('🛑 点击停止按钮:', { threadId: threadId.value, runId: runId.value })\n if (threadId.value && runId.value) {\n try {\n console.log('📡 发送 cancel 请求...')\n await client.runs.cancel(threadId.value, runId.value)\n console.log('✅ cancel 请求成功')\n status.value = 'ready'\n }\n catch (error) {\n console.error('❌ cancel 请求失败:', error)\n status.value = 'ready'\n }\n }\n else {\n console.log('⚠️ 缺少 threadId 或 runId,直接重置状态')\n status.value = 'ready'\n }\n}\n\n// 选择建议\nfunction handleSuggestionClick(suggestion: string) {\n handleSubmit(suggestion)\n}\n\n// 待办事项处理\nconst emit = defineEmits<{\n close: []\n 'update:isMaximized': [value: boolean]\n}>()\n\n// 关闭聊天窗口\nfunction handleClose() {\n emit('close')\n}\n\n// 处理自定义事件\nfunction handleCustomEvent(data: any) {\n // 处理 suggested_questions 类型\n if (data?.type === 'suggested_questions' && Array.isArray(data?.content)) {\n suggestions.value = data.content\n console.log('📝 更新建议问题:', data.content)\n return\n }\n\n console.log('Custom event received:', data)\n}\n\nconst setTextInput: AiBotPublicApi['setTextInput'] = (text) => {\n chatInputRef.value?.setTextInput(text)\n}\n\nconst addAttachments: AiBotPublicApi['addAttachments'] = (attachments) => {\n chatInputRef.value?.addAttachments(attachments)\n}\n\nconst sendMessage: AiBotPublicApi['sendMessage'] = async () => {\n await chatInputRef.value?.sendMessage()\n}\n\ndefineExpose<AiBotPublicApi>({\n setTextInput,\n addAttachments,\n sendMessage,\n})\n</script>\n\n<template>\n <div class=\"chat-bot\" :data-ai-theme=\"props.theme\">\n <div ref=\"portalHost\" class=\"chat-bot-portal-host\" />\n <div class=\"chat-window\" :class=\"{ maximized: isMaximized }\">\n <ChatHeader\n :title=\"assistantName\"\n :is-maximized=\"isMaximized\"\n :show-header-actions=\"showHeaderActions\"\n @close=\"handleClose\"\n @toggle-maximize=\"toggleMaximize\"\n />\n\n <!-- 空状态:messages 为空时显示 -->\n <div v-if=\"!isLoading && messages.length === 0\" class=\"flex-1 overflow-y-hidden flex flex-col items-center justify-center\">\n <slot name=\"empty\" :send-message=\"handleSubmit\">\n <div class=\"default-empty-state\">\n <div class=\"default-empty-badge\">AI</div>\n <h2 class=\"default-empty-title\">欢迎使用 {{ assistantName }}</h2>\n <p class=\"default-empty-desc\">请输入你的问题,开始一段新的对话。</p>\n </div>\n </slot>\n </div>\n <!-- 有消息时显示 ChatMessages -->\n <ChatMessages\n v-else\n :messages=\"messages\"\n :is-streaming=\"status === 'streaming'\"\n :theme=\"props.theme\"\n >\n <!-- custom 消息:透传插槽 -->\n <template #custom=\"{ customContent }\">\n <slot name=\"custom\" :customContent=\"customContent\" :threadId=\"threadId\">\n <GeneratedFiles\n v-if=\"customContent?.type === 'generated_files'\"\n :custom-content=\"customContent\"\n :api-url=\"props.apiUrl\"\n :thread-id=\"threadId\"\n />\n </slot>\n </template>\n </ChatMessages>\n <!-- 待办事项列表 -->\n <TodoList\n :initial-todos=\"initialTodos\"\n :tool-events=\"todoToolEvents\"\n :chat-status=\"status\"\n />\n\n <ChatInput\n ref=\"chatInputRef\"\n :status=\"status\"\n :current-model=\"currentModel\"\n :models=\"models\"\n :suggestions=\"suggestions\"\n :use-web-search=\"useWebSearch\"\n v-model:modelSelectorOpen=\"modelSelectorOpen\"\n @submit=\"handleFormSubmit\"\n @stop=\"handleStop\"\n @select-suggestion=\"handleSuggestionClick\"\n @update:current-model=\"currentModel = $event\"\n @update:use-web-search=\"useWebSearch = $event\"\n >\n <template #attachment-trigger=\"slotProps\">\n <slot name=\"attachment-trigger\" v-bind=\"slotProps\" />\n </template>\n </ChatInput>\n\n <!-- 加载遮罩 -->\n <div v-if=\"isLoading\" class=\"loading-mask\">\n <Loader :size=\"24\" />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.chat-bot {\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.chat-bot-portal-host {\n position: absolute;\n inset: 0;\n z-index: 30;\n pointer-events: none;\n isolation: isolate;\n}\n\n.chat-bot-portal-host > * {\n pointer-events: auto;\n}\n\n.chat-window {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--ai-surface);\n border-radius: 8px;\n border: 1px solid var(--ai-border-subtle);\n box-shadow: var(--ai-shadow);\n overflow: hidden;\n position: relative;\n}\n\n.chat-window.maximized {\n border-radius: 8px;\n border: 1px solid var(--ai-border-subtle);\n}\n\n.default-empty-state {\n display: flex;\n min-height: 400px;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px 24px;\n text-align: center;\n}\n\n.default-empty-badge {\n display: grid;\n width: 56px;\n height: 56px;\n place-items: center;\n border-radius: 999px;\n background: var(--ai-accent-soft);\n color: var(--ai-accent-soft-foreground);\n font-size: 18px;\n font-weight: 700;\n}\n\n.default-empty-title {\n margin: 16px 0 8px;\n font-size: 28px;\n line-height: 1.2;\n color: var(--foreground);\n}\n\n.default-empty-desc {\n max-width: 520px;\n margin: 0;\n line-height: 1.6;\n color: var(--muted-foreground);\n}\n\n.loading-mask {\n position: absolute;\n inset: 0;\n background: var(--ai-overlay);\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n z-index: 10;\n}\n\n</style>\n","<script setup lang=\"ts\">\nimport { BotMessageSquare, BotOff, X } from 'lucide-vue-next'\n\ninterface Props {\n isExpanded: boolean\n}\n\ndefineProps<Props>()\n\nconst emit = defineEmits<{\n toggle: []\n}>()\n</script>\n\n<template>\n <button class=\"float-button\" :class=\"{ expanded: isExpanded }\" @click=\"emit('toggle')\" type=\"button\">\n <span class=\"icon-wrapper\">\n <BotMessageSquare class=\"icon-svg\" />\n <X :size=\"16\" :stroke-width=\"2\" absoluteStrokeWidth class=\"icon-svg\"/>\n<!-- <BotOff class=\"icon-svg\" />-->\n </span>\n </button>\n</template>\n\n<style scoped>\n.float-button {\n position: relative;\n width: 42px;\n height: 42px;\n border-radius: 50%;\n background: linear-gradient(135deg, var(--ai-fab-bg) 0%, var(--ai-fab-bg-strong) 100%);\n border: none;\n cursor: pointer;\n color: var(--primary-foreground);\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: var(--ai-fab-shadow);\n transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s;\n}\n\n.float-button:hover {\n transform: scale(1.05);\n box-shadow: var(--ai-fab-shadow-hover);\n}\n\n.float-button:active {\n transform: scale(0.95);\n}\n\n.icon-wrapper {\n position: relative;\n width: 24px;\n height: 24px;\n}\n\n.icon-svg {\n position: absolute;\n top: 0;\n left: 0;\n width: 24px;\n height: 24px;\n transition: opacity 0.3s, transform 0.3s;\n}\n\n/* 第一个图标 - 默认显示 */\n.icon-wrapper .icon-svg:first-child {\n opacity: 1;\n transform: rotate(0deg);\n}\n\n/* 第二个图标 - 默认隐藏 */\n.icon-wrapper .icon-svg:last-child {\n opacity: 0;\n transform: rotate(-90deg);\n}\n\n/* 展开状态 - 交换动画 */\n.float-button.expanded .icon-wrapper .icon-svg:first-child {\n opacity: 0;\n transform: rotate(90deg);\n}\n\n.float-button.expanded .icon-wrapper .icon-svg:last-child {\n opacity: 1;\n transform: rotate(0deg);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { nextTick, ref } from 'vue'\nimport type { AiBotPublicApi, AskAiBotPublicApi, AttachmentTriggerSlotProps } from './lib/input-types'\nimport type { ChatFile, CustomContent } from './lib/message-types'\nimport type { AiBotTheme } from './lib/theme'\nimport ChatBot from './ChatBot.vue'\nimport FloatButton from './FloatButton.vue'\n\nconst chatBotRef = ref<AiBotPublicApi | null>(null)\n\ninterface Props {\n assistantId?: string\n assistantName?: string\n defaultExpanded?: boolean\n systemPrompt?: string\n threadId?: string\n userId?: string\n suggestions?: string[]\n apiUrl?: string\n apiKey?: string\n width?: number | string\n height?: number | string\n theme?: AiBotTheme\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n assistantId: 'research',\n assistantName: 'Chat',\n defaultExpanded: false,\n systemPrompt: '用中文回答',\n userId: 'user001',\n suggestions: () => [],\n apiUrl: 'http://localhost:2024',\n apiKey: undefined,\n width: 400,\n height: 'calc(100vh - 90px)',\n theme: 'light'\n})\n\ndefineSlots<{\n empty?: (props: { sendMessage: (message: string, files?: ChatFile[]) => void }) => any\n custom?: (props: { customContent: CustomContent, threadId: string | null }) => any\n 'attachment-trigger'?: (props: AttachmentTriggerSlotProps) => any\n}>()\n\nconst isExpanded = ref(props.defaultExpanded)\nconst isMaximized = ref(false)\nconst chatWidth = ref(typeof props.width === 'number' ? props.width : 500)\nconst isResizing = ref(false)\n\nfunction toggleExpanded() {\n isExpanded.value = !isExpanded.value\n if (!isExpanded.value) {\n isMaximized.value = false\n }\n}\n\nfunction handleMaximizeChange(value: boolean) {\n isMaximized.value = value\n}\n\n// 拖拽调整宽度\nfunction startResize(e: MouseEvent) {\n e.preventDefault()\n isResizing.value = true\n document.addEventListener('mousemove', handleResize)\n document.addEventListener('mouseup', stopResize)\n}\n\nfunction handleResize(e: MouseEvent) {\n if (!isResizing.value) return\n const newWidth = window.innerWidth - e.clientX - 20\n chatWidth.value = Math.max(300, Math.min(1400, newWidth))\n}\n\nfunction stopResize() {\n isResizing.value = false\n document.removeEventListener('mousemove', handleResize)\n document.removeEventListener('mouseup', stopResize)\n}\n\nasync function ensureExpanded() {\n if (isExpanded.value) {\n return\n }\n isExpanded.value = true\n await nextTick()\n}\n\nconst setTextInput: AskAiBotPublicApi['setTextInput'] = (text) => {\n chatBotRef.value?.setTextInput(text)\n}\n\nconst addAttachments: AskAiBotPublicApi['addAttachments'] = (attachments) => {\n chatBotRef.value?.addAttachments(attachments)\n}\n\nconst sendMessage: AskAiBotPublicApi['sendMessage'] = async () => {\n await ensureExpanded()\n await chatBotRef.value?.sendMessage()\n}\n\ndefineExpose<AskAiBotPublicApi>({\n setTextInput,\n addAttachments,\n sendMessage,\n})\n</script>\n\n<template>\n <div class=\"ask-ai-bot\" :data-ai-theme=\"props.theme\">\n <!-- 聊天窗口 -->\n <Transition name=\"slide-up\">\n <div\n v-show=\"isExpanded\"\n class=\"chat-window-container\"\n :class=\"{ maximized: isMaximized }\"\n :style=\"!isMaximized ? {\n width: typeof props.width === 'number' ? `${chatWidth}px` : props.width,\n height: typeof props.height === 'number' ? `${props.height}px` : props.height\n } : {}\"\n >\n <ChatBot\n ref=\"chatBotRef\"\n :api-url=\"apiUrl\"\n :api-key=\"apiKey\"\n :assistant-id=\"assistantId\"\n :assistant-name=\"assistantName\"\n :system-prompt=\"systemPrompt\"\n :thread-id=\"threadId\"\n :user-id=\"userId\"\n :suggestions=\"suggestions\"\n :theme=\"props.theme\"\n @close=\"toggleExpanded\"\n @update:is-maximized=\"handleMaximizeChange\"\n >\n <!-- 透传插槽 -->\n <template #empty=\"slotProps\">\n <slot name=\"empty\" v-bind=\"slotProps\" />\n </template>\n <template #custom=\"slotProps\">\n <slot name=\"custom\" v-bind=\"slotProps\" />\n </template>\n <template #attachment-trigger=\"slotProps\">\n <slot name=\"attachment-trigger\" v-bind=\"slotProps\" />\n </template>\n </ChatBot>\n <!-- 拖拽手柄 -->\n <div\n v-if=\"!isMaximized\"\n class=\"resize-handle\"\n @mousedown=\"startResize\"\n />\n </div>\n </Transition>\n\n <FloatButton\n :is-expanded=\"isExpanded\"\n @toggle=\"toggleExpanded\"\n />\n </div>\n</template>\n\n<style scoped>\n.ask-ai-bot {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 99;\n}\n\n.chat-window-container {\n position: fixed;\n top: 20px;\n right: 20px;\n transition: height 0.3s ease;\n}\n\n.chat-window-container.maximized {\n top: 20px;\n right: 20px;\n left: 20px;\n width: auto;\n height: calc(100vh - 40px);\n}\n\n/* 拖拽手柄 */\n.resize-handle {\n position: absolute;\n top: 0;\n left: 0;\n width: 6px;\n height: 100%;\n cursor: ew-resize;\n background: transparent;\n}\n\n@media (max-width: 480px) {\n .chat-window-container {\n width: calc(100vw - 40px);\n height: 80vh;\n right: -10px;\n }\n}\n\n.slide-up-enter-active,\n.slide-up-leave-active {\n transition: all 0.3s ease;\n}\n\n.slide-up-enter-from,\n.slide-up-leave-to {\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n}\n</style>\n"],"names":["fetchModels","apiUrl","result","error","getDefaultModel","models","m","getProviderByModelName","modelName","name","createThread","client","threadId","userId","loadThreadHistory","onSuggestedQuestions","onTodos","values","loadedMessages","langgraphMessages","i","msg","msgType","msgContent","content","b","toolCalls","_a","tc","nextMsg","toolMsgContent","toolCallId","toolStatus","toolState","status","toolCall","toolMessageId","generatedFiles","customContent","suggestedQuestions","todos","PORTAL_HOST_KEY","usePortalHost","ctx","inject","computed","props","__props","emit","__emit","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_toDisplayString","_hoisted_4","_createBlock","_unref","Minimize2Icon","Maximize2Icon","_createVNode","XIcon","cn","inputs","twMerge","clsx","getStateIcon","state","PlayCircle","Loader","CheckCircle","XCircle","toolNameMap","toolIconMap","BrainIcon","GlobeIcon","FileTextIcon","FolderSearchIcon","EyeIcon","FileEditIcon","SquarePen","FolderSearch","FileSearch","ZapIcon","ListTodoIcon","BookOpenCheck","getToolName","getToolIcon","WrenchIcon","isTodoTool","formatArgs","args","openStates","ref","toggle","id","_Fragment","_renderList","tool","$event","ChevronDownIcon","_resolveDynamicComponent","_normalizeClass","_withDirectives","_hoisted_5","_cache","_hoisted_6","_hoisted_7","_hoisted_8","delegatedProps","reactiveOmit","StickToBottom","_mergeProps","_renderSlot","_ctx","classes","Primitive","buttonVariants","cva","isAtBottom","scrollToBottom","useStickToBottomContext","showScrollButton","handleClick","$attrs","ArrowDownIcon","markdownThemes","getMessageClass","index","Conversation","ConversationContent","message","Message","ToolCall","MessageContent","MarkdownRender","_createTextVNode","ConversationScrollButton","PROMPT_INPUT_KEY","usePromptInput","context","AttachmentsKey","useAttachmentsContext","AttachmentKey","useAttachmentContext","getMediaCategory","data","mediaType","getAttachmentLabel","category","variant","mediaCategory","handleRemove","provide","label","isGrid","iconSize","fileUrl","showImage","showVideo","iconMap","ImageIcon","VideoIcon","Music2Icon","PaperclipIcon","iconComponent","imageAlt","remove","_variant","restProps","e","files","removeFile","asAttachmentData","file","Attachments","attachment","Attachment","AttachmentPreview","AttachmentInfo","AttachmentRemove","ROTATE_INTERVAL","CHIP_GAP","viewportRef","measureRefs","pageRanges","currentPageIndex","isHovered","rotationTimer","resizeObserver","shouldRotate","currentPageSuggestions","range","setMeasureRef","el","stopRotation","startRotation","handleMouseEnter","handleMouseLeave","buildPageRanges","viewportWidth","widths","_","width","ranges","start","widthSum","itemWidth","nextWidth","recalculatePages","nextTick","watch","onMounted","onBeforeUnmount","_Transition","suggestion","Suggestion","handleInputGroupAddonClick","currentTarget","target","_b","inputGroupAddonVariants","Button","inputGroupButtonVariants","modelValue","useVModel","Textarea","forwarded","useForwardPropsEmits","_withCtx","slotProps","emits","portalHost","DropdownMenuPortal","DropdownMenuContent","forwardedProps","useForwardProps","modelSelectorOpen","_useModel","inputText","hasFiles","fileInputRef","isLoading","setTextInput","val","resolveAttachmentType","url","addAttachments","incoming","existingFilenames","newAttachments","normalized","nanoid","type","normalizedName","addFiles","fileList","f","clearFiles","clearInput","openFileDialog","convertBlobUrlToDataUrl","blob","resolve","reader","sendMessage","processedFiles","item","dataUrl","__expose","isEmpty","selectedModelData","groupedModels","groups","model","provider","providers","handleModelSelect","isComposing","handleKeyDown","isLoadingStatus","lastFile","handlePaste","items","pastedFiles","buttonVariant","submitIcon","Loader2Icon","CornerDownLeftIcon","iconClass","isDisabled","handleSubmitClick","handleImageError","img","onFileChange","input","InputGroup","ChatSuggestions","PromptInputAttachmentsDisplay","InputGroupTextarea","InputGroupAddon","InputGroupButton","_hoisted_9","DropdownMenu","DropdownMenuTrigger","_hoisted_11","_hoisted_12","DropdownMenuItem","_hoisted_14","_hoisted_15","CheckIcon","LoaderIcon","ArrowUpRight","slots","useSlots","textContent","defaultSlot","vnode","dynamicSpread","componentClasses","componentStyle","MotionComponent","motion","processedEventCount","completedCount","todo","inProgressCount","interruptedCount","pendingCount","expanded","userCollapsed","toggleExpanded","syncExpandedWithTodos","nextTodos","isWriteTodosTool","toolName","normalizeTodoStatus","rawStatus","fallback","normalizeHistoricalTodoStatus","statusByPhase","event","mapRawTodos","rawTodos","fallbackState","mapHistoricalTodos","finalizeInProgressTodos","isRawTodoContainer","payload","parseRawTodoItems","raw","parseToolTodos","replaceWriteTodos","applyToolEvent","events","next","prev","ChevronsDown","ChevronsUp","Circle","LoaderCircle","Ban","CircleCheckBig","Shimmer","_hoisted_10","chatInputRef","Client","isMaximized","runId","useWebSearch","messages","suggestions","initialTodos","todoToolEvents","handleToolEvent","params","currentModel","tid","questions","toggleMaximize","handleSubmit","userMessage","contentBlocks","mimeType","filename","rawData","isDataUrl","base64Data","normalizedType","userMessageId","createToolMessage","updateToolMessage","messageKey","updates","thread","streamResponse","_c","assistantMessageId","assistantContent","assistantToolCalls","needNewAssistantMessage","chunk","chunkEvent","handleCustomEvent","customMessageId","messageArray","messageMeta","toolResult","foundToolCall","key","uiState","toolMessage","t","messageId","hasToolCalls","hasChunks","existing","toolMsg","msgIndex","tcChunk","block","newAssistantMessageId","lastAssistantIndex","lastIndex","errorDisplayMessage","errorMsg","_d","errorType","_e","errorMessageId","handleFormSubmit","hasText","hasAttachments","text","handleStop","handleSuggestionClick","handleClose","attachments","ChatHeader","ChatMessages","GeneratedFiles","TodoList","ChatInput","BotMessageSquare","X","chatBotRef","isExpanded","chatWidth","isResizing","handleMaximizeChange","value","startResize","handleResize","stopResize","newWidth","ensureExpanded","ChatBot","FloatButton"],"mappings":"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"}