@blade-hq/agent-kit 0.4.8 → 0.4.11
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.
- package/dist/{SkillStatusBar-CDmaNuOE.d.ts → SkillStatusBar-CHnXqybx.d.ts} +2 -2
- package/dist/{blade-client-X5TOnkQa.d.ts → blade-client-BfYaHLco.d.ts} +44 -2
- package/dist/{chunk-MAMDVXTM.js → chunk-3LCNDPP6.js} +2 -2
- package/dist/{chunk-SAKSQ7OO.js → chunk-4XID5JVK.js} +2 -2
- package/dist/{chunk-TWZHUASA.js → chunk-CDSCC4OQ.js} +86 -17
- package/dist/chunk-CDSCC4OQ.js.map +1 -0
- package/dist/{chunk-QO6CO372.js → chunk-O2BVC7QE.js} +119 -86
- package/dist/chunk-O2BVC7QE.js.map +1 -0
- package/dist/{chunk-I5BTVM3C.js → chunk-PJJ3Y3DZ.js} +2 -2
- package/dist/{chunk-DNT6RM5E.js → chunk-VCCMO7G5.js} +59 -5
- package/dist/chunk-VCCMO7G5.js.map +1 -0
- package/dist/{chunk-YFKHSFRB.js → chunk-Z4FPELIQ.js} +228 -82
- package/dist/chunk-Z4FPELIQ.js.map +1 -0
- package/dist/client/index.d.ts +297 -29
- package/dist/client/index.js +1 -1
- package/dist/{licenses-DWJmNvpn.d.ts → licenses-BGw5jiC4.d.ts} +1 -1
- package/dist/react/api/licenses.d.ts +3 -3
- package/dist/react/api/licenses.js +3 -3
- package/dist/react/api/vibe-coding.d.ts +3 -3
- package/dist/react/api/vibe-coding.js +2 -2
- package/dist/react/components/chat/index.d.ts +4 -4
- package/dist/react/components/chat/index.js +5 -5
- package/dist/react/components/plan/index.js +3 -3
- package/dist/react/components/session/index.d.ts +1 -1
- package/dist/react/components/session/index.js +3 -3
- package/dist/react/components/workspace/index.js +3 -3
- package/dist/react/index.d.ts +42 -13
- package/dist/react/index.js +21 -7
- package/dist/react/index.js.map +1 -1
- package/dist/{session-CDeiO81j.d.ts → session-BKOc2lsz.d.ts} +9 -1
- package/dist/style.css +1 -1
- package/package.json +2 -1
- package/dist/chunk-DNT6RM5E.js.map +0 -1
- package/dist/chunk-QO6CO372.js.map +0 -1
- package/dist/chunk-TWZHUASA.js.map +0 -1
- package/dist/chunk-YFKHSFRB.js.map +0 -1
- /package/dist/{chunk-MAMDVXTM.js.map → chunk-3LCNDPP6.js.map} +0 -0
- /package/dist/{chunk-SAKSQ7OO.js.map → chunk-4XID5JVK.js.map} +0 -0
- /package/dist/{chunk-I5BTVM3C.js.map → chunk-PJJ3Y3DZ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/components/chat/ChatView.tsx","../src/react/hooks/use-chat.ts","../src/react/components/chat/ChatInput.tsx","../src/react/asr/use-tiptap-voice-input.ts","../src/react/asr/use-voice-input.ts","../src/react/asr/voice-input-support.ts","../src/react/asr/VoiceWaveform.tsx","../src/react/components/model/ModelSelector.tsx","../src/react/hooks/use-model-preferences.ts","../src/react/api/models.ts","../src/react/api/user-preferences.ts","../src/react/hooks/use-input-history.ts","../src/react/hooks/use-resolved-model.ts","../src/react/lib/attachment-upload.ts","../src/react/schemas/skill.ts","../src/react/components/chat/FileCompletionMenu.tsx","../src/react/components/chat/SkillCompletionMenu.tsx","../src/react/components/chat/FileSizeLimitDialog.tsx","../src/react/components/chat/SkillStatusBar.tsx","../src/react/hooks/use-background-tasks.ts","../src/react/hooks/use-context-stats.ts","../src/react/hooks/use-skill-stats.ts","../src/react/hooks/use-token-pressure.ts","../src/react/components/chat/ProgressCircle.tsx","../src/react/components/chat/extensions/file-mention.ts","../src/react/components/chat/extensions/skill-mention.ts","../src/react/components/chat/ConnectionBanner.tsx","../src/react/components/chat/MessageList.tsx","../../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js","../../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/StickToBottom.js","../src/react/components/chat/AssistantTurnBlock.tsx","../src/react/routes.ts","../src/react/components/ai-elements/reasoning.tsx","../src/react/components/ai-elements/shimmer.tsx","../src/react/components/chat/AgentLoopBlock.tsx","../src/react/components/chat/ResourceIframe.tsx","../src/react/components/chat/ToolCallBlock.tsx","../src/react/components/chat/tool-renderers/shared.tsx","../src/react/components/chat/tool-renderers/BashRenderer.tsx","../src/react/components/chat/tool-renderers/FileEditRenderer.tsx","../src/react/components/chat/tool-renderers/FileReadRenderer.tsx","../src/react/components/chat/ImageLightbox.tsx","../src/react/components/chat/tool-renderers/SearchRenderer.tsx","../src/react/components/chat/tool-renderers/registry.ts","../src/react/components/chat/UserMessageBubble.tsx","../src/react/lib/preview-dispatch.ts","../src/react/lib/whatif-prompt.ts","../src/react/components/chat/AttachmentPreviewDialog.tsx","../src/react/components/chat/MessageContextPills.tsx","../src/react/components/chat/MessageFileAttachmentList.tsx","../src/react/components/chat/MessageActions.tsx","../src/react/components/chat/TextAttachmentPills.tsx","../src/react/components/chat/WhatIfUserBubble.tsx","../src/react/components/chat/whatif-quote-context.tsx","../src/react/components/chat/CompactionCard.tsx","../src/react/components/chat/RenderErrorBoundary.tsx","../src/react/components/chat/StickyStatusBar.tsx","../src/react/components/chat/TurnNavRail.tsx"],"sourcesContent":["import { Eye } from \"lucide-react\"\nimport { useCallback, type ReactNode } from \"react\"\nimport { useChat } from \"../../hooks/use-chat\"\nimport type { MessageContent } from \"../../schemas/message\"\nimport { useSessionStore } from \"../../stores/session-store\"\nimport { ChatInput } from \"./ChatInput\"\nimport { ConnectionBanner } from \"./ConnectionBanner\"\nimport { MessageList } from \"./MessageList\"\nimport type { ChatViewCustomization } from \"./customization\"\n\nexport interface ChatViewProps extends ChatViewCustomization {\n sessionId: string\n renderAttachments?: () => ReactNode\n onBeforeSend?: (content: MessageContent) => MessageContent\n onCommand?: (commandId: string) => void | Promise<void>\n canShareSession?: boolean\n onResyncSkills?: () => void\n isResyncingSkills?: boolean\n}\n\nexport function ChatView({\n sessionId,\n renderAttachments,\n onBeforeSend,\n onCommand,\n canShareSession = false,\n onResyncSkills,\n isResyncingSkills = false,\n classNames,\n components,\n renderers,\n}: ChatViewProps) {\n const {\n messages,\n isStreaming,\n send,\n stop,\n } = useChat(sessionId)\n const session = useSessionStore((s) => s.sessions.find((ss) => ss.id === sessionId))\n const mode = useSessionStore((s) => s.modes[sessionId] ?? \"executing\")\n const toggleMode = useCallback(\n () => useSessionStore.getState().togglePlanningMode(sessionId),\n [sessionId],\n )\n const sessionStatus = session?.status\n const isViewer = session?.viewer_role === \"viewer\"\n const onConfirmPlan = useCallback(\n (action: \"execute\" | \"revise\", text?: string) => {\n if (action === \"execute\") {\n send(\"计划已确认,开始执行\", \"executing\")\n } else if (text) {\n send(text, \"planning\")\n }\n },\n [send],\n )\n\n const customization = { classNames, components, renderers }\n const SkillStatus = components?.SkillStatusBar\n\n return (\n <div className={`flex min-h-0 flex-1 flex-col overflow-hidden ${classNames?.root ?? \"\"}`}>\n {isViewer && (\n <div className={`flex items-center justify-center gap-2 border-b border-[hsl(var(--border))] bg-[hsl(var(--card))] py-2 text-xs text-[hsl(var(--muted-foreground))] ${classNames?.viewerBanner ?? \"\"}`}>\n <Eye size={14} />\n 你正在查看分享的会话(只读)\n </div>\n )}\n {!isViewer && <ConnectionBanner />}\n <MessageList\n key={sessionId}\n sessionId={sessionId}\n messages={messages}\n onAnswer={\n isViewer\n ? undefined\n : (msg, toolCallId, answerData) =>\n send(msg, mode, { tool_call_id: toolCallId, ...answerData })\n }\n sessionStatus={sessionStatus}\n onConfirmPlan={isViewer ? undefined : onConfirmPlan}\n customization={customization}\n />\n {!isViewer && (\n <ChatInput\n onSend={(msg, _targetSessionId, model) =>\n send(msg, mode, undefined, { model: model || undefined })\n }\n onStop={stop}\n isStreaming={isStreaming}\n mode={mode}\n onToggleMode={toggleMode}\n renderAttachments={renderAttachments}\n onBeforeSend={onBeforeSend}\n onCommand={onCommand}\n canShareSession={canShareSession}\n className={classNames?.chatInputRoot}\n innerClassName={classNames?.chatInputInner}\n SkillStatusBarComponent={SkillStatus}\n skillStatusBarClassName={classNames?.skillStatusBarRoot}\n skillStatusBarInnerClassName={classNames?.skillStatusBarInner}\n onResyncSkills={onResyncSkills}\n isResyncingSkills={isResyncingSkills}\n />\n )}\n </div>\n )\n}\n","import { useCallback, useEffect } from \"react\"\nimport { getSocket } from \"../api/socket\"\nimport type { ChatMessage, MessageContent } from \"../schemas/message\"\nimport { useAnswerCallbackStore } from \"../stores/answer-callback-store\"\nimport { useChatStore } from \"../stores/chat-store\"\nimport { useSessionStore } from \"../stores/session-store\"\n\nconst EMPTY_MESSAGES: ChatMessage[] = []\n\nexport function useChat(sessionId: string) {\n const messages = useChatStore((s) => s.messages[sessionId] ?? EMPTY_MESSAGES)\n const isStreaming = useChatStore((s) => s.isStreaming[sessionId] ?? false)\n const mode = useSessionStore((s) => s.modes[sessionId] ?? \"executing\")\n const setAnswerCallback = useAnswerCallbackStore((s) => s.setAnswerCallback)\n\n const send = useCallback(\n (\n msg: MessageContent,\n mode?: string,\n askuserAnswer?: Record<string, unknown>,\n options?: { model?: string },\n ) => {\n const synthesizedAnswer =\n askuserAnswer ?? buildPendingAskUserAnswer(sessionId, msg)\n getSocket().send(sessionId, msg, mode, synthesizedAnswer, options)\n },\n [sessionId],\n )\n\n const stop = useCallback(() => {\n getSocket().stop(sessionId)\n }, [sessionId])\n\n const answer = useCallback(\n (msg: string, toolCallId: string, answerData: { selections: Record<number, number[]>; custom: Record<number, string> }) => {\n send(msg, mode, { tool_call_id: toolCallId, ...answerData })\n },\n [mode, send],\n )\n\n useEffect(() => {\n setAnswerCallback(sessionId, answer)\n return () => setAnswerCallback(sessionId, undefined)\n }, [answer, sessionId, setAnswerCallback])\n\n return { messages, isStreaming, send, stop }\n}\n\nexport function buildPendingAskUserAnswer(\n sessionId: string,\n message: MessageContent,\n): Record<string, unknown> | undefined {\n const session = useSessionStore.getState().sessions.find((item) => item.id === sessionId)\n if (session?.status !== \"waiting_for_input\") {\n return undefined\n }\n const text = extractMessageText(message)\n if (!text) {\n return undefined\n }\n const turns = useChatStore.getState().turns[sessionId] ?? []\n for (let turnIndex = turns.length - 1; turnIndex >= 0; turnIndex -= 1) {\n const turn = turns[turnIndex]\n if (turn.loop_id === \"root\" || turn.role !== \"assistant\") continue\n for (let toolIndex = turn.tool_calls.length - 1; toolIndex >= 0; toolIndex -= 1) {\n const toolCall = turn.tool_calls[toolIndex]\n if (toolCall.status !== \"awaiting_answer\") continue\n if (!toolCall.tool_name.includes(\"AskUserQuestion\")) continue\n return {\n tool_call_id: toolCall.id,\n selections: {},\n custom: { \"0\": text },\n }\n }\n }\n return undefined\n}\n\nfunction extractMessageText(message: MessageContent): string {\n if (typeof message === \"string\") {\n return message.trim()\n }\n return message\n .filter((part) => part.type === \"text\")\n .map((part) => part.text.trim())\n .filter(Boolean)\n .join(\"\\n\")\n .trim()\n}\n","import { EditorContent, type Editor as TiptapEditor, useEditor } from \"@tiptap/react\"\nimport StarterKit from \"@tiptap/starter-kit\"\nimport {\n type SuggestionKeyDownProps,\n type SuggestionProps,\n exitSuggestion,\n} from \"@tiptap/suggestion\"\nimport {\n Archive,\n ChevronDown,\n File,\n FileCode2,\n FileText,\n Film,\n FolderUp,\n CircleHelp,\n Download,\n FlaskConical,\n Import,\n Lightbulb,\n Loader2,\n Mic,\n MicOff,\n Music,\n Paperclip,\n Plus,\n Rocket,\n Scissors,\n Send,\n Sparkles,\n Share2,\n Square,\n X,\n} from \"lucide-react\"\nimport { useQueryClient } from \"@tanstack/react-query\"\nimport {\n useEffect,\n useEffectEvent,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type ReactNode,\n} from \"react\"\nimport { createRoot } from \"react-dom/client\"\nimport { toast } from \"sonner\"\nimport { useTiptapVoiceInput } from \"../../asr/use-tiptap-voice-input\"\nimport type { VoiceInputError } from \"../../asr/voice-input-support\"\nimport { VoiceWaveform } from \"../../asr/VoiceWaveform\"\nimport { ModelSelector } from \"../model/ModelSelector\"\nimport { useRuntimeFeaturesStore } from \"../../stores/runtime-features-store\"\nimport { getAuthedUrl } from \"../../api/client\"\nimport { getSessionTurns, listSessions, uploadFiles, writeFile } from \"../../api/sessions\"\nimport { listSessionSkills, searchSkills } from \"../../api/skills\"\nimport { useInputHistory } from \"../../hooks/use-input-history\"\nimport { usePreferredModel } from \"../../hooks/use-model-preferences\"\nimport { useResolvedModel } from \"../../hooks/use-resolved-model\"\nimport {\n ATTACHMENT_SIZE_LIMIT_BYTES,\n splitFilesBySize,\n type OversizedFileInfo,\n} from \"../../lib/attachment-upload\"\nimport { buildMessageContent, transformSlashCommand } from \"../../lib/chat\"\nimport type { MessageContent, MessageContentPart } from \"../../schemas/message\"\nimport { skillDisplayName } from \"../../schemas/skill\"\nimport { useConnectionStore } from \"../../stores/connection-store\"\nimport type { SessionMode } from \"../../stores/session-store\"\nimport { useSessionStore } from \"../../stores/session-store\"\nimport { useUiBridgeStore } from \"../../stores/ui-bridge-store\"\nimport {\n FileCompletionMenu,\n type FileCompletionMenuProps,\n type FileCompletionMenuRef,\n getFileSuggestionItems,\n} from \"./FileCompletionMenu\"\nimport {\n SkillCompletionMenu,\n type SkillCompletionMenuRef,\n} from \"./SkillCompletionMenu\"\nimport { FileSizeLimitDialog } from \"./FileSizeLimitDialog\"\nimport { SkillStatusBar } from \"./SkillStatusBar\"\nimport type { SkillStatusBarComponentProps } from \"./customization\"\nimport {\n FileMention,\n type FileSuggestionItem,\n fileMentionSuggestionKey,\n} from \"./extensions/file-mention\"\nimport {\n COMMANDS,\n SkillMention,\n type SkillSuggestionSkillItem,\n type SkillSuggestionItem,\n skillMentionSuggestionKey,\n} from \"./extensions/skill-mention\"\n\ninterface Props {\n onSend: (message: MessageContent, targetSessionId?: string, model?: string | null) => void\n onStop: () => void\n isStreaming: boolean\n mode?: SessionMode\n onToggleMode?: () => void\n renderAttachments?: () => ReactNode\n onBeforeSend?: (content: MessageContent) => MessageContent\n /**\n * Creates (or returns) a session to upload pending attachments into when\n * the composer has files but no active session yet. The returned id is\n * used for the upload, and is also passed back to `onSend` so the send\n * path reaches exactly the session the files landed in — independent of\n * whatever the global activeSessionId is at that moment.\n */\n ensureSession?: (draftText: string) => Promise<string>\n onCommand?: (commandId: string) => void | Promise<void>\n canShareSession?: boolean\n /**\n * Optional slot rendered directly above the textarea (below any file-pill\n * bar). ship-attack uses this to mount QuoteChipList for R4.\n */\n slotAboveTextarea?: ReactNode\n /**\n * Optional external draft channel. When provided, the composer initializes\n * from `value` on mount and mirrors every internal `setInput` call into\n * `setValue`. Intended for ship-attack's cross-view draft sharing (R3.8),\n * not full controlled-input semantics — the tiptap editor remains the\n * source of truth, this is a persistence side-channel.\n */\n externalDraft?: {\n value: string\n setValue: (v: string) => void\n }\n /**\n * Optional external attachments channel. Same mirror semantics as\n * externalDraft. Upload state (pending/uploading/...) is carried on\n * `FileComposerAttachment.status`, so sharing the array is enough.\n */\n externalAttachments?: {\n value: FileComposerAttachment[]\n setValue: (a: FileComposerAttachment[]) => void\n }\n /** Tailwind class for the inner max-width wrapper. Defaults to `max-w-3xl`. */\n maxWidthClassName?: string\n className?: string\n innerClassName?: string\n SkillStatusBarComponent?: ComponentType<SkillStatusBarComponentProps>\n skillStatusBarClassName?: string\n skillStatusBarInnerClassName?: string\n onResyncSkills?: () => void\n isResyncingSkills?: boolean\n}\n\ninterface EditorJSON {\n type?: string\n text?: string\n attrs?: Record<string, unknown>\n content?: EditorJSON[]\n}\n\nexport type FileComposerAttachment = {\n id: string\n kind: \"file\"\n name: string\n size: number\n mimeType: string\n status: \"pending\" | \"uploading\" | \"uploaded\" | \"failed\"\n file?: File\n uploadedPath?: string\n textContent?: string | null\n}\n\ntype ComposerAttachment = FileComposerAttachment\n\nfunction getEditorText(editor: TiptapEditor | null) {\n return editor?.getText({ blockSeparator: \"\\n\" }) ?? \"\"\n}\n\nfunction buildPlainTextDocument(text: string): EditorJSON {\n return {\n type: \"doc\",\n content: text.split(\"\\n\").map((line) => ({\n type: \"paragraph\",\n content: line ? [{ type: \"text\", text: line }] : [],\n })),\n }\n}\n\nfunction replaceEditorText(editor: TiptapEditor | null, text: string) {\n if (!editor) {\n return\n }\n\n if (!text) {\n editor.commands.clearContent()\n editor.commands.focus(\"end\")\n return\n }\n\n editor.commands.setContent(buildPlainTextDocument(text))\n editor.commands.focus(\"end\")\n}\n\nfunction getFileCardIcon(attachment: FileComposerAttachment) {\n const lowerName = attachment.name.toLowerCase()\n\n if (attachment.mimeType.startsWith(\"audio/\")) {\n return Music\n }\n if (attachment.mimeType.startsWith(\"video/\")) {\n return Film\n }\n if (/\\.(zip|rar|7z|tar|gz|bz2|xz)$/.test(lowerName)) {\n return Archive\n }\n if (/\\.(ts|tsx|js|jsx|py|rb|go|rs|java|kt|swift|c|cc|cpp|h|hpp|css|scss|html|json|yaml|yml|toml|md)$/.test(lowerName)) {\n return FileCode2\n }\n if (attachment.mimeType.startsWith(\"text/\") || /\\.(txt|pdf|doc|docx|rtf|odt)$/.test(lowerName)) {\n return FileText\n }\n return File\n}\n\nasync function hashFileContent(file: File): Promise<string> {\n const buffer = await file.arrayBuffer()\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", buffer)\n const hashArray = Array.from(new Uint8Array(hashBuffer))\n return hashArray\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")\n .slice(0, 12)\n}\n\nfunction getFileExtension(file: File): string {\n const name = file.name || \"\"\n const dotIndex = name.lastIndexOf(\".\")\n return dotIndex >= 0 ? name.slice(dotIndex) : \"\"\n}\n\nfunction isClipboardPastedFile(file: File): boolean {\n // Browsers assign generic names like \"image.png\" for pasted clipboard images\n return /^image\\.\\w+$/.test(file.name)\n}\n\nasync function getUploadFileName(file: File): Promise<string> {\n if (file.webkitRelativePath) return file.webkitRelativePath\n if (isClipboardPastedFile(file)) {\n const hash = await hashFileContent(file)\n return `paste_${hash}${getFileExtension(file)}`\n }\n return file.name || \"未命名文件\"\n}\n\nfunction getImagePreviewUrl(\n attachment: FileComposerAttachment,\n sessionId: string | null,\n localImageUrls: Record<string, string>,\n): string | undefined {\n if (attachment.status === \"uploaded\" && sessionId && attachment.uploadedPath) {\n return getAuthedUrl(\n `/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(attachment.uploadedPath)}`,\n )\n }\n return localImageUrls[attachment.id]\n}\n\nfunction isMessageContentEmpty(content: MessageContent) {\n if (typeof content === \"string\") {\n return !content.trim()\n }\n\n return content.length === 0 || content.every((part) => part.type === \"text\" && !part.text.trim())\n}\n\nfunction isImageAttachment(\n attachment: ComposerAttachment,\n): attachment is FileComposerAttachment {\n return attachment.kind === \"file\" && attachment.mimeType.startsWith(\"image/\")\n}\n\nfunction buildSubmitPayload(\n text: string,\n attachments: ComposerAttachment[],\n pendingContexts: { label: string; content: string }[],\n onBeforeSend?: (content: MessageContent) => MessageContent,\n) {\n const validAttachments = attachments.filter((attachment) => attachment.status !== \"failed\")\n const payload = buildMessageContent(text, validAttachments)\n const contextParts: MessageContentPart[] = pendingContexts.map((context) => ({\n type: \"text\" as const,\n text: `[上下文: ${context.label}]\\n${context.content}`,\n }))\n\n const mergedPayload =\n contextParts.length === 0\n ? payload\n : typeof payload === \"string\"\n ? payload.trim()\n ? [...contextParts, { type: \"text\" as const, text: payload }]\n : contextParts\n : [...contextParts, ...payload]\n\n return onBeforeSend ? onBeforeSend(mergedPayload) : mergedPayload\n}\n\nfunction estimateTokenCount(text: string): number {\n const cjkCount = (text.match(/[\\u3400-\\u9FFF]/g) ?? []).length\n const visibleCount = text.replace(/\\s/g, \"\").length\n const otherCount = Math.max(0, visibleCount - cjkCount)\n return Math.max(0, Math.round(cjkCount * 1.2 + otherCount / 4))\n}\n\nfunction formatTokenK(text: string): string {\n const tokenCount = estimateTokenCount(text)\n const tokenK = tokenCount / 1000\n if (tokenK >= 10) {\n return `约 ${tokenK.toFixed(1)}k`\n }\n return `约 ${tokenK.toFixed(2)}k`\n}\n\nfunction ComposerFilePill({\n attachment,\n onRemove,\n}: {\n attachment: ComposerAttachment\n onRemove: (id: string) => void\n}) {\n const Icon = getFileCardIcon(attachment)\n const isFile = attachment.kind === \"file\"\n const isFailed = isFile && attachment.status === \"failed\"\n const isUploading = isFile && attachment.status === \"uploading\"\n\n return (\n <div\n className={`flex shrink-0 items-center gap-1.5 rounded-full border px-2.5 py-1 text-[11px] ${\n isFailed\n ? \"border-red-500/30 bg-red-500/5 text-red-400\"\n : \"border-[hsl(var(--border))] bg-[hsl(var(--card))] text-[hsl(var(--foreground))]\"\n }`}\n >\n {isUploading ? (\n <Loader2 size={12} className=\"shrink-0 animate-spin text-[hsl(var(--muted-foreground))]\" />\n ) : (\n <Icon size={12} className=\"shrink-0 text-[hsl(var(--muted-foreground))]\" />\n )}\n <span className=\"max-w-32 truncate\">{attachment.name}</span>\n <button\n type=\"button\"\n onClick={() => onRemove(attachment.id)}\n aria-label={`移除 ${attachment.name}`}\n className=\"ml-0.5 inline-flex shrink-0 items-center justify-center rounded-full text-[hsl(var(--muted-foreground))] transition hover:text-rose-400\"\n >\n <X size={10} />\n </button>\n </div>\n )\n}\n\nfunction AddContextDialog({\n sessionId,\n onClose,\n onAdd,\n}: {\n sessionId: string\n onClose: () => void\n onAdd: (label: string, content: string) => void\n}) {\n const CONTEXT_INLINE_THRESHOLD = 200\n const [label, setLabel] = useState(\"\")\n const [content, setContent] = useState(\"\")\n const [showSessionPicker, setShowSessionPicker] = useState(false)\n const [sessions, setSessions] = useState<{ id: string; intent: string }[]>([])\n const [loadingSessions, setLoadingSessions] = useState(false)\n const [importingId, setImportingId] = useState<string | null>(null)\n const [isImportProcessing, setIsImportProcessing] = useState(false)\n\n const sanitizeContextFolderName = (raw: string) => {\n const normalized = raw.trim().toLowerCase()\n const safe = normalized.replace(/[^\\w\\-.\\u4e00-\\u9fa5]+/g, \"_\").replace(/^_+|_+$/g, \"\")\n return safe || \"untitled\"\n }\n\n const uploadContextSnippet = async (\n folder: string,\n fileName: string,\n fileContent: string,\n ): Promise<string> => {\n const filePath = `context/${folder}/${fileName}`\n await writeFile(sessionId, filePath, fileContent)\n return filePath\n }\n\n const handleLoadSessions = async () => {\n if (showSessionPicker) {\n setShowSessionPicker(false)\n return\n }\n setLoadingSessions(true)\n setShowSessionPicker(true)\n try {\n const list = await listSessions()\n setSessions(\n list\n .filter((s) => s.id !== sessionId)\n .map((s) => ({ id: s.id, intent: s.intent || s.id })),\n )\n } catch {\n setSessions([])\n } finally {\n setLoadingSessions(false)\n }\n }\n\n const handleImportSession = async (sid: string) => {\n setImportingId(sid)\n setIsImportProcessing(false)\n try {\n const turns = await getSessionTurns(sid)\n const session = sessions.find((s) => s.id === sid)\n const nextLabel = session?.intent || \"导入的会话\"\n const folder = sanitizeContextFolderName(nextLabel)\n let contextFileIndex = 1\n\n const pendingUploads: Array<{\n pendingText: string\n finalText: string\n fallbackPrefix: string\n fileName: string\n rawResultStr: string\n }> = []\n const segments: string[] = []\n for (const turn of turns.filter((t) => t.role === \"user\" || t.role === \"assistant\")) {\n const textParts = turn.blocks\n .filter((b) => b.type === \"text\")\n .map((b) => (typeof b.content === \"string\" ? b.content : \"\"))\n .filter(Boolean)\n const toolParts: string[] = []\n for (const tc of (turn.tool_calls ?? []).filter((item) => item.status === \"done\")) {\n const rawResultStr =\n typeof tc.result === \"string\"\n ? tc.result\n : tc.result != null\n ? JSON.stringify(tc.result, null, 2)\n : \"\"\n\n const hasLongResult = rawResultStr.length > CONTEXT_INLINE_THRESHOLD\n const toolName = (tc.tool_name || \"\").toLowerCase()\n const looksLikeReadFile = toolName.includes(\"read\") || toolName.includes(\"file\")\n\n let resultText = rawResultStr\n if (hasLongResult || (looksLikeReadFile && rawResultStr.length > CONTEXT_INLINE_THRESHOLD)) {\n const fileName = `tool-result-${String(contextFileIndex).padStart(3, \"0\")}.txt`\n contextFileIndex += 1\n const filePath = `context/${folder}/${fileName}`\n const pendingText = `[处理中: 将转存到工作区文件 ${filePath}]`\n pendingUploads.push({\n pendingText,\n finalText: `[内容已转存到工作区文件: ${filePath}]`,\n fallbackPrefix: \"[转存失败,保留原文片段]\",\n fileName,\n rawResultStr,\n })\n resultText = pendingText\n }\n\n toolParts.push(\n `[工具调用: ${tc.display_name || tc.tool_name}]\\n参数: ${tc.arguments}\\n结果: ${resultText}`,\n )\n }\n segments.push(`[${turn.role}]: ${[...textParts, ...toolParts].join(\"\\n\\n\")}`)\n }\n const resolvedText = segments.join(\"\\n\\n\")\n\n setLabel(nextLabel)\n setContent(resolvedText)\n setShowSessionPicker(false)\n\n if (pendingUploads.length > 0) {\n setIsImportProcessing(true)\n let finalText = resolvedText\n for (const upload of pendingUploads) {\n try {\n await uploadContextSnippet(folder, upload.fileName, upload.rawResultStr)\n finalText = finalText.split(upload.pendingText).join(upload.finalText)\n } catch (error) {\n const reason = error instanceof Error ? error.message : \"unknown error\"\n finalText = finalText.split(upload.pendingText).join(\n `${upload.fallbackPrefix}\\n原因: ${reason}\\n${upload.rawResultStr.slice(0, CONTEXT_INLINE_THRESHOLD)}...`,\n )\n }\n setContent(finalText)\n }\n setIsImportProcessing(false)\n }\n } catch {\n // ignore\n } finally {\n setIsImportProcessing(false)\n setImportingId(null)\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-[60] flex items-center justify-center bg-black/55 p-4\"\n onClick={onClose}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") onClose()\n }}\n >\n <div\n className=\"w-full max-w-lg flex flex-col rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center justify-between border-b border-[hsl(var(--border))] px-5 py-3\">\n <h4 className=\"text-sm font-semibold text-[hsl(var(--foreground))]\">添加上下文</h4>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-md p-1 text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <X size={14} />\n </button>\n </div>\n\n <div className=\"px-5 py-4 space-y-3\">\n {/* 操作按钮行 */}\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={handleLoadSessions}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-[hsl(var(--border))] px-2.5 py-1.5 text-xs text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n <Import size={12} />\n 从其他会话导入\n <ChevronDown size={10} className={`transition-transform ${showSessionPicker ? \"rotate-180\" : \"\"}`} />\n </button>\n {showSessionPicker && (\n <div className=\"absolute left-0 top-full z-10 mt-1 max-h-48 w-full overflow-y-auto rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--card))] shadow-lg\">\n {loadingSessions ? (\n <div className=\"flex items-center gap-2 px-3 py-2.5 text-xs text-[hsl(var(--muted-foreground))]\">\n <Loader2 size={12} className=\"animate-spin\" />\n 加载会话列表…\n </div>\n ) : sessions.length === 0 ? (\n <div className=\"px-3 py-2.5 text-xs text-[hsl(var(--muted-foreground))]\">\n 暂无其他会话\n </div>\n ) : (\n sessions.map((s) => (\n <button\n key={s.id}\n type=\"button\"\n disabled={importingId === s.id}\n onClick={() => handleImportSession(s.id)}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left text-xs text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))] disabled:opacity-50\"\n >\n {importingId === s.id && <Loader2 size={10} className=\"shrink-0 animate-spin\" />}\n <span className=\"truncate\">{s.intent}</span>\n </button>\n ))\n )}\n </div>\n )}\n </div>\n\n {/* 标签 */}\n <div>\n <label htmlFor=\"ctx-label\" className=\"block text-xs font-medium text-[hsl(var(--foreground))] mb-1\">\n 标签\n </label>\n <input\n id=\"ctx-label\"\n value={label}\n onChange={(e) => setLabel(e.target.value)}\n placeholder=\"例如:参考对话、背景资料…\"\n className=\"w-full rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))] px-3 py-1.5 text-xs text-[hsl(var(--foreground))] placeholder:text-[hsl(var(--muted-foreground))] outline-none focus-visible:border-[hsl(var(--ring))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))]\"\n />\n </div>\n\n {/* 内容 */}\n <div>\n <label htmlFor=\"ctx-content\" className=\"block text-xs font-medium text-[hsl(var(--foreground))] mb-1\">\n 内容\n </label>\n {isImportProcessing && (\n <div className=\"mb-1.5 flex items-center gap-1.5 text-[11px] text-[hsl(var(--muted-foreground))]\">\n <Loader2 size={11} className=\"animate-spin\" />\n 正在处理导入内容并写入 workspace/context,完成后可点击“确定”\n </div>\n )}\n <textarea\n id=\"ctx-content\"\n value={content}\n onChange={(e) => setContent(e.target.value)}\n placeholder=\"输入或从其他会话导入上下文内容…\"\n rows={6}\n className=\"w-full rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))] px-3 py-2 font-mono text-[11px] leading-[1.6] text-[hsl(var(--foreground))] placeholder:text-[hsl(var(--muted-foreground))] outline-none focus-visible:border-[hsl(var(--ring))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] resize-y\"\n />\n </div>\n </div>\n\n <div className=\"flex justify-end gap-2 border-t border-[hsl(var(--border))] px-5 py-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-md border border-[hsl(var(--border))] px-3 py-1.5 text-xs text-[hsl(var(--foreground))] transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n 取消\n </button>\n <button\n type=\"button\"\n onClick={() => {\n if (label.trim() && content.trim()) {\n onAdd(label.trim(), content.trim())\n onClose()\n }\n }}\n disabled={isImportProcessing || !label.trim() || !content.trim()}\n className=\"rounded-md bg-blue-500 px-3 py-1.5 text-xs text-white transition-colors hover:bg-blue-600 disabled:opacity-50\"\n >\n 确定\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nfunction ComposerContextPill({\n id,\n label,\n content,\n onRemove,\n}: {\n id: string\n label: string\n content: string\n onRemove: (id: string) => void\n}) {\n const [showDetail, setShowDetail] = useState(false)\n const tokenK = formatTokenK(content)\n\n return (\n <>\n <div className=\"flex shrink-0 items-center gap-1.5 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--accent))] px-2.5 py-1 text-[11px] text-[hsl(var(--foreground))]\">\n <button\n type=\"button\"\n onClick={() => setShowDetail(true)}\n className=\"max-w-40 truncate hover:text-blue-400 transition-colors\"\n title=\"点击查看完整内容\"\n >\n {label}\n </button>\n <span\n className=\"shrink-0 rounded bg-[hsl(var(--background))] px-1.5 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))]\"\n title=\"上下文内容 token 估算值\"\n >\n {tokenK}\n </span>\n <button\n type=\"button\"\n onClick={() => onRemove(id)}\n aria-label={`移除上下文 ${label}`}\n className=\"ml-0.5 inline-flex shrink-0 items-center justify-center rounded-full text-[hsl(var(--muted-foreground))] transition hover:text-rose-400\"\n >\n <X size={10} />\n </button>\n </div>\n {showDetail && (\n <div\n className=\"fixed inset-0 z-[60] flex items-center justify-center bg-black/55 p-6\"\n onClick={() => setShowDetail(false)}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") setShowDetail(false)\n }}\n >\n <div\n className=\"w-full max-w-4xl max-h-[85vh] flex flex-col rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center justify-between border-b border-[hsl(var(--border))] px-6 py-3\">\n <h4 className=\"text-xs font-semibold text-[hsl(var(--foreground))]\">{label}</h4>\n <button\n type=\"button\"\n onClick={() => setShowDetail(false)}\n className=\"rounded-md p-1 text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <X size={14} />\n </button>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto px-6 py-4\">\n <pre className=\"whitespace-pre-wrap break-words font-mono text-[11px] leading-[1.6] text-[hsl(var(--foreground)/0.85)]\">\n {content}\n </pre>\n </div>\n </div>\n </div>\n )}\n </>\n )\n}\n\nfunction serializeEditorContent(node: EditorJSON | null | undefined): string {\n if (!node) return \"\"\n\n if (node.type === \"text\") {\n return node.text ?? \"\"\n }\n\n if (node.type === \"hardBreak\") {\n return \"\\n\"\n }\n\n if (node.type === \"fileMention\") {\n const path = typeof node.attrs?.path === \"string\" ? node.attrs.path : \"\"\n return path ? `\\`${path}\\`` : \"\"\n }\n\n if (node.type === \"skillMention\") {\n const skillId = typeof node.attrs?.skillId === \"string\" ? node.attrs.skillId : \"\"\n return skillId ? `<skill>${skillId}</skill>` : \"\"\n }\n\n const children = (node.content ?? []).map((child: EditorJSON) => serializeEditorContent(child))\n\n if (node.type === \"doc\") {\n return children.join(\"\\n\")\n }\n\n return children.join(\"\")\n}\n\nfunction findLeadingSkillMention(node: EditorJSON | null | undefined): string | null {\n const result = scanLeadingSkillMention(node, false)\n return result.skillId\n}\n\nfunction scanLeadingSkillMention(\n node: EditorJSON | null | undefined,\n seenContent: boolean,\n): { skillId: string | null; seenContent: boolean } {\n if (!node) {\n return { skillId: null, seenContent }\n }\n\n if (node.type === \"text\") {\n return { skillId: null, seenContent: seenContent || /\\S/.test(node.text ?? \"\") }\n }\n\n if (node.type === \"hardBreak\" || node.type === \"fileMention\") {\n return { skillId: null, seenContent: true }\n }\n\n if (node.type === \"skillMention\") {\n return {\n skillId:\n seenContent ? null : (typeof node.attrs?.skillId === \"string\" ? node.attrs.skillId : null),\n seenContent: true,\n }\n }\n\n let nextSeenContent = seenContent\n for (const child of node.content ?? []) {\n const result = scanLeadingSkillMention(child, nextSeenContent)\n if (result.skillId) {\n return result\n }\n nextSeenContent = result.seenContent\n }\n\n return { skillId: null, seenContent: nextSeenContent }\n}\n\nasync function getSkillSuggestionItems(\n sessionId: string | null,\n query: string,\n): Promise<SkillSuggestionSkillItem[]> {\n const loadSessionSkills = async () => {\n if (!sessionId) {\n return []\n }\n try {\n return await listSessionSkills(sessionId)\n } catch {\n return []\n }\n }\n\n if (!query) {\n const source = await loadSessionSkills()\n return source.map((s) => ({\n type: \"skill\" as const,\n skillId: s.skill_id,\n displayName: s.display_name,\n description: s.description,\n local: s.local,\n }))\n }\n\n const q = query.toLowerCase()\n const sessionSkills = await loadSessionSkills()\n const localMatches = sessionSkills\n .filter(\n (s) =>\n s.skill_id.toLowerCase().includes(q) ||\n s.description.toLowerCase().includes(q),\n )\n .map((s) => ({\n type: \"skill\" as const,\n skillId: s.skill_id,\n displayName: s.display_name,\n description: s.description,\n local: s.local,\n }))\n\n try {\n const remoteResults = await searchSkills(query, 10)\n const seen = new Set(localMatches.map((s) => s.skillId))\n const dedupedRemote = remoteResults\n .filter((r) => !seen.has(r.skill_id))\n .map((r) => ({\n type: \"skill\" as const,\n skillId: r.skill_id,\n displayName: r.display_name,\n description: r.description,\n local: r.local,\n }))\n return [...localMatches, ...dedupedRemote]\n } catch {\n return localMatches\n }\n}\n\nfunction updateSuggestionPosition(\n element: HTMLDivElement,\n clientRect?: (() => DOMRect | null) | null,\n) {\n const rect = clientRect?.()\n if (!rect) {\n element.style.display = \"none\"\n return\n }\n\n const width = Math.min(420, window.innerWidth - 16)\n const left = Math.min(Math.max(8, rect.left), window.innerWidth - width - 8)\n // Always place above the cursor, anchored to bottom\n const bottom = window.innerHeight - rect.top + 4\n\n element.style.display = \"block\"\n element.style.position = \"fixed\"\n element.style.left = `${left}px`\n element.style.top = \"\"\n element.style.bottom = `${bottom}px`\n element.style.maxHeight = `${rect.top - 16}px`\n element.style.width = `${width}px`\n element.style.zIndex = \"60\"\n}\n\nfunction showVoiceInputErrorToast(error: VoiceInputError) {\n toast.error(error.title, {\n description: error.description,\n duration: error.description ? 15000 : undefined,\n })\n}\n\nexport function ChatInput({\n onSend,\n onStop,\n isStreaming,\n mode = \"executing\",\n onToggleMode,\n renderAttachments,\n onBeforeSend,\n ensureSession,\n onCommand,\n canShareSession = false,\n slotAboveTextarea,\n externalDraft,\n externalAttachments,\n maxWidthClassName = \"max-w-3xl\",\n className,\n innerClassName,\n SkillStatusBarComponent = SkillStatusBar,\n skillStatusBarClassName,\n skillStatusBarInnerClassName,\n onResyncSkills,\n isResyncingSkills = false,\n}: Props) {\n const [input, setInputInternal] = useState(externalDraft?.value ?? \"\")\n // Mirror every setInput into the optional external channel so the caller\n // (e.g. ship-attack's chat-draft-store) can persist the draft across view\n // switches. The internal useState stays the source of truth for tiptap.\n const setInput = useEffectEvent((value: string) => {\n setInputInternal(value)\n externalDraft?.setValue(value)\n })\n // Reverse sync: when external value changes from the outside (e.g. a sibling\n // ChatInput wrote to the shared store, or the user switched to a session with\n // a different saved draft), pull it back into both this instance's input state\n // AND the tiptap editor.\n //\n // No \"non-empty → empty\" guard: it used to be here to paper over a race where\n // ship-attack's draft store briefly observed `drafts[newId] === undefined`\n // during createSession → setActiveSession before migrateDraftKey landed. But\n // migrateDraftKey is now invoked synchronously right after setActiveSession\n // in the same React commit, so the race can't happen. Keeping the guard would\n // *break* the legitimate \"user switches to a session with no saved draft\"\n // case: external goes to \"\" and the composer would stubbornly keep the\n // previous session's text — which then gets posted into the wrong session on\n // next send, since `send` resolves against the new active session id.\n const externalDraftValue = externalDraft?.value\n const inputRef = useRef(input)\n inputRef.current = input\n useEffect(() => {\n if (externalDraftValue == null) return\n // inputRef 读当前 internal 值;updater callback 里做 diff 是 render-phase\n // 副作用,React 19 的 useEffectEvent 检查会把之后同步触发的 editor.onUpdate\n // 判为 \"被 render 调用\",这里改成 effect 体内直接 diff + 写。\n if (inputRef.current === externalDraftValue) return\n if (editorRef.current) {\n replaceEditorText(editorRef.current, externalDraftValue)\n }\n setInputInternal(externalDraftValue)\n }, [externalDraftValue])\n\n const [composerAttachments, setComposerAttachmentsInternal] = useState<ComposerAttachment[]>(\n externalAttachments?.value ?? [],\n )\n const setComposerAttachments = useEffectEvent(\n (\n valueOrUpdater:\n | ComposerAttachment[]\n | ((prev: ComposerAttachment[]) => ComposerAttachment[]),\n ) => {\n setComposerAttachmentsInternal((prev) => {\n const next =\n typeof valueOrUpdater === \"function\"\n ? (valueOrUpdater as (p: ComposerAttachment[]) => ComposerAttachment[])(prev)\n : valueOrUpdater\n externalAttachments?.setValue(next)\n return next\n })\n },\n )\n // Reverse sync for attachments — same reasoning as the draft channel above:\n // no \"non-empty → empty\" guard, because session switching legitimately needs\n // to clear the previous session's attachments and the migrate path never\n // actually goes through an empty intermediate.\n const externalAttachmentsValue = externalAttachments?.value\n const composerAttachmentsRef = useRef(composerAttachments)\n composerAttachmentsRef.current = composerAttachments\n useEffect(() => {\n if (externalAttachmentsValue == null) return\n if (composerAttachmentsRef.current === externalAttachmentsValue) return\n setComposerAttachmentsInternal(externalAttachmentsValue)\n }, [externalAttachmentsValue])\n const [dragging, setDragging] = useState(false)\n const [isEditorFocused, setIsEditorFocused] = useState(false)\n const [oversizedFiles, setOversizedFiles] = useState<OversizedFileInfo[]>([])\n const [selectedModel, setSelectedModel] = useState(\"\")\n const { setPreferredModel } = usePreferredModel()\n const queryClient = useQueryClient()\n const actionMenuRef = useRef<HTMLDetailsElement>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n const folderInputRef = useRef<HTMLInputElement>(null)\n const editorRef = useRef<TiptapEditor | null>(null)\n const localImageUrlsRef = useRef(new Map<string, string>())\n const activeSessionId = useSessionStore((state) => state.activeSessionId)\n const sessions = useSessionStore((state) => state.sessions)\n const activeSessionModel = useMemo(\n () => sessions.find((session) => session.id === activeSessionId)?.model ?? null,\n [activeSessionId, sessions],\n )\n const rewindDraft = useSessionStore((state) =>\n activeSessionId ? state.rewindDrafts[activeSessionId] : undefined,\n )\n const patchSession = useSessionStore((state) => state.patchSession)\n const setRewindDraft = useSessionStore((state) => state.setRewindDraft)\n const pendingContexts = useUiBridgeStore((state) =>\n activeSessionId ? state.pendingContexts[activeSessionId] : undefined,\n )\n const draftAppends = useUiBridgeStore((state) =>\n activeSessionId ? state.draftAppends[activeSessionId] : undefined,\n )\n const { resolvedModel } = useResolvedModel(activeSessionModel)\n useEffect(() => {\n setSelectedModel(resolvedModel)\n }, [resolvedModel])\n const sendRequests = useUiBridgeStore((state) =>\n activeSessionId ? state.sendRequests[activeSessionId] : undefined,\n )\n const removePendingContext = useUiBridgeStore((state) => state.removePendingContext)\n const consumePendingContexts = useUiBridgeStore((state) => state.consumePendingContexts)\n const consumeDraftAppends = useUiBridgeStore((state) => state.consumeDraftAppends)\n const consumeSendRequests = useUiBridgeStore((state) => state.consumeSendRequests)\n const connectionStatus = useConnectionStore((state) => state.status)\n const inputHistory = useInputHistory(activeSessionId)\n const getSessionId = useEffectEvent(() => activeSessionId)\n const handleSlashCommand = useEffectEvent((commandId: string) => onCommand?.(commandId))\n const [localImageUrls, setLocalImageUrls] = useState<Record<string, string>>({})\n\n useEffect(() => {\n const closeActionMenu = (event: PointerEvent) => {\n const menu = actionMenuRef.current\n if (!menu?.open || menu.contains(event.target as Node)) {\n return\n }\n menu.removeAttribute(\"open\")\n }\n const closeActionMenuOnEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n actionMenuRef.current?.removeAttribute(\"open\")\n }\n }\n\n window.addEventListener(\"pointerdown\", closeActionMenu)\n window.addEventListener(\"keydown\", closeActionMenuOnEscape)\n return () => {\n window.removeEventListener(\"pointerdown\", closeActionMenu)\n window.removeEventListener(\"keydown\", closeActionMenuOnEscape)\n }\n }, [])\n\n const getMentionSuggestionItems = useEffectEvent(\n async (query: string): Promise<SkillSuggestionItem[]> => {\n const normalizedQuery = query.trim().toLowerCase()\n const commandItems = COMMANDS.filter((item) => {\n if (!normalizedQuery) {\n return true\n }\n return (\n item.id.toLowerCase().startsWith(normalizedQuery) ||\n item.label.toLowerCase().startsWith(normalizedQuery)\n )\n })\n const skillItems = await getSkillSuggestionItems(getSessionId(), query)\n return [...commandItems, ...skillItems]\n },\n )\n\n const appendFiles = async (files: FileList | File[]) => {\n const { accepted, rejected } = splitFilesBySize(files, ATTACHMENT_SIZE_LIMIT_BYTES)\n\n if (rejected.length > 0) {\n setOversizedFiles(rejected)\n }\n\n if (accepted.length === 0) {\n return\n }\n\n // Files are always staged as `pending` with the raw File handle; upload happens\n // at submit time so that no-active-session hosts (e.g. ship-attack left panel)\n // can create the session via `ensureSession` and still upload to workdir.\n const pendingFileAttachments: FileComposerAttachment[] = await Promise.all(\n accepted.map(async (file) => {\n const uploadName = await getUploadFileName(file)\n const id = `${uploadName}-${file.size}-${file.lastModified}-${Math.random().toString(36).slice(2)}`\n return {\n id,\n kind: \"file\" as const,\n name: uploadName,\n size: file.size,\n mimeType: file.type,\n status: \"pending\" as const,\n file,\n }\n }),\n )\n\n if (pendingFileAttachments.length > 0) {\n setComposerAttachments((prev) => [...prev, ...pendingFileAttachments])\n }\n }\n\n const stableAppendFiles = useEffectEvent((files: FileList | File[]) => appendFiles(files))\n\n const stableHandleSubmit = useEffectEvent(() => handleSubmit())\n\n const getEditorState = useEffectEvent(() => ({\n input,\n connectionStatus,\n navigateUp: inputHistory.navigateUp,\n navigateDown: inputHistory.navigateDown,\n isNavigatingHistory: inputHistory.isNavigating,\n handleSubmit: stableHandleSubmit,\n }))\n\n const syncEditorState = (editorInstance: TiptapEditor) => {\n const value = getEditorText(editorInstance)\n setInput(value)\n }\n\n const resetComposer = () => {\n editorRef.current?.commands.clearContent()\n setInput(\"\")\n setComposerAttachments([])\n }\n\n const editor = useEditor({\n immediatelyRender: false,\n extensions: [\n StarterKit.configure({\n blockquote: false,\n bulletList: false,\n codeBlock: false,\n dropcursor: false,\n gapcursor: false,\n heading: false,\n horizontalRule: false,\n orderedList: false,\n }),\n FileMention.configure({\n suggestion: {\n char: \"@\",\n pluginKey: fileMentionSuggestionKey,\n items: async ({ query }) => getFileSuggestionItems(getSessionId(), query),\n command: ({ editor: suggestionEditor, props, range }) => {\n const item = props as unknown as FileSuggestionItem\n suggestionEditor\n .chain()\n .focus()\n .insertContentAt(range, [\n {\n type: \"fileMention\",\n attrs: {\n name: item.name,\n path: item.path,\n },\n },\n {\n type: \"text\",\n text: \" \",\n },\n ])\n .run()\n },\n render: () => {\n let container: HTMLDivElement | null = null\n let root: ReturnType<typeof createRoot> | null = null\n const menuRef = { current: null as FileCompletionMenuRef | null }\n\n const handleExit = () => {\n const view = editorRef.current?.view\n if (view) {\n exitSuggestion(view, fileMentionSuggestionKey)\n }\n }\n\n const renderMenu = (props: FileCompletionMenuProps) => {\n if (!container || !root) return\n updateSuggestionPosition(container, props.clientRect)\n root.render(\n <FileCompletionMenu\n ref={(instance) => {\n menuRef.current = instance\n }}\n {...props}\n sessionId={getSessionId()}\n onExit={handleExit}\n />,\n )\n }\n\n return {\n onStart: (props: SuggestionProps) => {\n container = document.createElement(\"div\")\n document.body.appendChild(container)\n root = createRoot(container)\n renderMenu(props as unknown as FileCompletionMenuProps)\n },\n onUpdate: (props: SuggestionProps) => {\n renderMenu(props as unknown as FileCompletionMenuProps)\n },\n onExit: () => {\n menuRef.current = null\n root?.unmount()\n container?.remove()\n root = null\n container = null\n },\n onKeyDown: ({ event, view }: SuggestionKeyDownProps) => {\n if (event.key === \"Escape\") {\n event.preventDefault()\n exitSuggestion(view, fileMentionSuggestionKey)\n return true\n }\n\n return menuRef.current?.onKeyDown(event) ?? false\n },\n }\n },\n },\n }),\n SkillMention.configure({\n suggestion: {\n char: \"/\",\n pluginKey: skillMentionSuggestionKey,\n items: ({ query }) => getMentionSuggestionItems(query),\n command: ({ editor: suggestionEditor, props, range }) => {\n const item = props as unknown as SkillSuggestionItem\n if (item.type === \"command\") {\n suggestionEditor.chain().focus().deleteRange(range).run()\n void handleSlashCommand(item.id)\n return\n }\n suggestionEditor\n .chain()\n .focus()\n .insertContentAt(range, [\n {\n type: \"skillMention\",\n attrs: {\n skillId: item.skillId,\n displayName: skillDisplayName(item),\n description: item.description,\n },\n },\n {\n type: \"text\",\n text: \" \",\n },\n ])\n .run()\n },\n render: () => {\n let container: HTMLDivElement | null = null\n let root: ReturnType<typeof createRoot> | null = null\n const menuRef = { current: null as SkillCompletionMenuRef | null }\n\n const renderMenu = (props: SuggestionProps) => {\n if (!container || !root) return\n updateSuggestionPosition(container, props.clientRect)\n root.render(\n <SkillCompletionMenu\n ref={(instance) => {\n menuRef.current = instance\n }}\n items={props.items as SkillSuggestionItem[]}\n command={(item) => props.command(item)}\n />,\n )\n }\n\n return {\n onStart: (props: SuggestionProps) => {\n container = document.createElement(\"div\")\n document.body.appendChild(container)\n root = createRoot(container)\n renderMenu(props)\n },\n onUpdate: (props: SuggestionProps) => {\n renderMenu(props)\n },\n onExit: () => {\n menuRef.current = null\n root?.unmount()\n container?.remove()\n root = null\n container = null\n },\n onKeyDown: ({ event, view }: SuggestionKeyDownProps) => {\n if (event.key === \"Escape\") {\n event.preventDefault()\n exitSuggestion(view, skillMentionSuggestionKey)\n return true\n }\n\n return menuRef.current?.onKeyDown(event) ?? false\n },\n }\n },\n },\n }),\n ],\n content: \"\",\n onCreate: ({ editor: editorInstance }) => {\n editorRef.current = editorInstance\n syncEditorState(editorInstance)\n },\n onUpdate: ({ editor: editorInstance }) => {\n syncEditorState(editorInstance)\n },\n editorProps: {\n attributes: {\n \"aria-label\": \"输入消息\",\n class:\n \"min-h-[40px] max-h-[240px] overflow-y-auto px-4 py-3 text-sm leading-relaxed text-[hsl(var(--foreground))] focus:outline-none [&_.file-mention-pill]:inline-flex [&_.file-mention-pill]:items-center [&_.file-mention-pill]:rounded-full [&_.file-mention-pill]:bg-[hsl(var(--accent))] [&_.file-mention-pill]:px-2 [&_.file-mention-pill]:py-0.5 [&_.file-mention-pill]:font-medium [&_.file-mention-pill]:text-[hsl(var(--primary))] [&_.file-mention-pill]:select-none [&_.file-mention-pill]:whitespace-nowrap [&_.skill-mention-pill]:inline-flex [&_.skill-mention-pill]:items-center [&_.skill-mention-pill]:rounded-full [&_.skill-mention-pill]:bg-[hsl(var(--primary)/0.15)] [&_.skill-mention-pill]:px-2 [&_.skill-mention-pill]:py-0.5 [&_.skill-mention-pill]:font-medium [&_.skill-mention-pill]:text-[hsl(var(--primary))] [&_.skill-mention-pill]:select-none [&_.skill-mention-pill]:whitespace-nowrap [&_p:first-child]:mt-0 [&_p:last-child]:mb-0\",\n },\n handleDOMEvents: {\n focus: () => {\n setIsEditorFocused(true)\n return false\n },\n blur: () => {\n setIsEditorFocused(false)\n return false\n },\n keydown: (_view, event) => {\n const state = getEditorState()\n const fileMentionState = editorRef.current\n ? (fileMentionSuggestionKey.getState(editorRef.current.view.state) as\n | { active?: boolean }\n | undefined)\n : undefined\n\n if (fileMentionState?.active) {\n return false\n }\n\n const skillMentionState = editorRef.current\n ? (skillMentionSuggestionKey.getState(editorRef.current.view.state) as\n | { active?: boolean }\n | undefined)\n : undefined\n\n if (skillMentionState?.active) {\n return false\n }\n\n if (!event.isComposing && event.key === \"ArrowUp\" && (state.input.trim().length === 0 || state.isNavigatingHistory)) {\n const previousEntry = state.navigateUp(state.input)\n if (!previousEntry) {\n return false\n }\n\n event.preventDefault()\n replaceEditorText(editorRef.current, previousEntry)\n return true\n }\n\n if (!event.isComposing && event.key === \"ArrowDown\") {\n const nextEntry = state.navigateDown()\n if (nextEntry == null) {\n return false\n }\n\n event.preventDefault()\n replaceEditorText(editorRef.current, nextEntry)\n return true\n }\n\n if (event.key === \"Enter\" && !event.shiftKey && !event.isComposing) {\n event.preventDefault()\n if (state.connectionStatus !== \"connected\") {\n return true\n }\n void state.handleSubmit()\n return true\n }\n\n return false\n },\n paste: (_view, event) => {\n if (event.clipboardData?.files.length) {\n event.preventDefault()\n void stableAppendFiles(event.clipboardData.files)\n return true\n }\n return false\n },\n },\n },\n })\n\n useEffect(() => {\n if (!editor || !activeSessionId || rewindDraft == null) {\n return\n }\n\n editor.commands.clearContent()\n if (rewindDraft) {\n editor.commands.insertContent({ type: \"text\", text: rewindDraft })\n }\n editor.commands.focus(\"end\")\n setRewindDraft(activeSessionId, null)\n }, [activeSessionId, editor, rewindDraft, setRewindDraft])\n\n const submittingRef = useRef(false)\n\n useEffect(() => {\n let changed = false\n const nextLocalIds = new Set<string>()\n\n for (const attachment of composerAttachments) {\n if (!isImageAttachment(attachment) || !attachment.file || attachment.status === \"uploaded\") {\n continue\n }\n nextLocalIds.add(attachment.id)\n if (!localImageUrlsRef.current.has(attachment.id)) {\n localImageUrlsRef.current.set(attachment.id, URL.createObjectURL(attachment.file))\n changed = true\n }\n }\n\n for (const [attachmentId, url] of localImageUrlsRef.current) {\n if (nextLocalIds.has(attachmentId)) {\n continue\n }\n URL.revokeObjectURL(url)\n localImageUrlsRef.current.delete(attachmentId)\n changed = true\n }\n\n if (changed) {\n setLocalImageUrls(Object.fromEntries(localImageUrlsRef.current))\n }\n }, [composerAttachments])\n\n useEffect(() => {\n return () => {\n for (const url of localImageUrlsRef.current.values()) {\n URL.revokeObjectURL(url)\n }\n localImageUrlsRef.current.clear()\n }\n }, [])\n\n const applyDraftAppends = useEffectEvent(() => {\n if (!activeSessionId || !editor) {\n return\n }\n\n const appends = consumeDraftAppends(activeSessionId)\n if (appends.length === 0) {\n return\n }\n\n const text = appends.map((append) => append.text).join(\"\")\n if (!text) {\n return\n }\n\n editor.chain().focus(\"end\").insertContent(text).run()\n })\n\n useEffect(() => {\n if (!draftAppends?.length) {\n return\n }\n\n applyDraftAppends()\n }, [applyDraftAppends, draftAppends])\n\n const applySendRequests = useEffectEvent(() => {\n if (!activeSessionId) {\n return\n }\n\n const requests = consumeSendRequests(activeSessionId)\n if (requests.length === 0) {\n return\n }\n\n void stableHandleSubmit()\n })\n\n useEffect(() => {\n if (!sendRequests?.length) {\n return\n }\n\n applySendRequests()\n }, [applySendRequests, sendRequests])\n\n // ASR 语音输入:partial 实时替换、final 落定;录音中锁定编辑器\n const viteEnv = (import.meta as unknown as { env?: Record<string, string | undefined> }).env ?? {}\n const asrEnabled = useRuntimeFeaturesStore((s) => s.asrEnabled)\n const voice = useTiptapVoiceInput({\n editorRef,\n workletUrl: `${viteEnv.BASE_URL ?? \"/\"}asr/pcm-worklet.js`,\n onError: showVoiceInputErrorToast,\n })\n const { isRecording, level: voiceLevel } = voice\n const handleMicDisabledClick = () =>\n toast.info(\"语音输入功能未开启,请在后端 .env 配置 ASR_API_KEY\")\n\n // 流式中 / session 切换 时强制停录音,避免回调打到错会话\n const voiceStopRef = useRef(voice.stop)\n voiceStopRef.current = voice.stop\n\n useEffect(() => {\n if (isStreaming && isRecording) {\n void voiceStopRef.current()\n }\n }, [isStreaming, isRecording])\n\n const prevSessionIdRef = useRef(activeSessionId)\n useEffect(() => {\n if (prevSessionIdRef.current !== activeSessionId) {\n prevSessionIdRef.current = activeSessionId\n if (isRecording) {\n void voiceStopRef.current()\n }\n }\n }, [activeSessionId, isRecording])\n\n const handleSubmit = async () => {\n if (isStreaming || connectionStatus !== \"connected\") {\n return\n }\n if (submittingRef.current) {\n return\n }\n if (\n composerAttachments.some(\n (attachment) => attachment.kind === \"file\" && attachment.status === \"uploading\",\n )\n ) {\n return\n }\n submittingRef.current = true\n try {\n const json = editor?.getJSON()\n const rawText = serializeEditorContent(json)\n const skillName = findLeadingSkillMention(json)\n const text = skillName ? transformSlashCommand(skillName, rawText) : rawText\n\n const pendingFiles = composerAttachments.filter(\n (a): a is FileComposerAttachment => a.kind === \"file\" && a.status === \"pending\" && !!a.file,\n )\n let updatedAttachments = composerAttachments\n let uploadTargetSessionId: string | undefined\n if (pendingFiles.length > 0) {\n let uploadSessionId = activeSessionId\n if (!uploadSessionId && ensureSession) {\n try {\n uploadSessionId = await ensureSession(text || \"新会话\")\n } catch {\n setComposerAttachments((prev) =>\n prev.map((a) =>\n a.kind === \"file\" && a.status === \"pending\"\n ? { ...a, status: \"failed\" as const }\n : a,\n ),\n )\n return\n }\n }\n if (uploadSessionId) {\n uploadTargetSessionId = uploadSessionId\n if (pendingFiles.length > 0) {\n setComposerAttachments((prev) =>\n prev.map((a) =>\n a.kind === \"file\" && a.status === \"pending\"\n ? { ...a, status: \"uploading\" as const }\n : a,\n ),\n )\n try {\n const result = await uploadFiles(\n uploadSessionId,\n \".\",\n pendingFiles.map((a) => ({ file: a.file!, name: a.name })),\n )\n // Map pending file id → server result synchronously,\n // so buildSubmitPayload sees the correct server-deduped names.\n const uploadResultById = new Map<string, string | null>()\n const failedSet = new Set(result.failed)\n let uploadIdx = 0\n for (const pf of pendingFiles) {\n if (failedSet.has(pf.name)) {\n failedSet.delete(pf.name)\n uploadResultById.set(pf.id, null)\n } else {\n uploadResultById.set(pf.id, result.uploaded[uploadIdx++] ?? null)\n }\n }\n updatedAttachments = composerAttachments.map((a) => {\n if (!uploadResultById.has(a.id)) return a\n const uploadedPath = uploadResultById.get(a.id)\n if (!uploadedPath) return { ...a, status: \"failed\" as const }\n const actualName = uploadedPath.split(\"/\").pop() || a.name\n return { ...a, name: actualName, status: \"uploaded\" as const, uploadedPath }\n })\n setComposerAttachments(updatedAttachments)\n if (result.uploaded.length > 0) {\n void queryClient.invalidateQueries({ queryKey: [\"file-tree\", uploadSessionId] })\n }\n } catch {\n setComposerAttachments((prev) =>\n prev.map((a) =>\n a.kind === \"file\" && a.status === \"uploading\"\n ? { ...a, status: \"failed\" as const }\n : a,\n ),\n )\n return\n }\n }\n }\n }\n\n const activePendingContexts = pendingContexts ?? []\n const nextPayload = buildSubmitPayload(\n text,\n updatedAttachments,\n activePendingContexts,\n onBeforeSend,\n )\n if (isMessageContentEmpty(nextPayload)) {\n return\n }\n if (activeSessionId && activePendingContexts.length > 0) {\n consumePendingContexts(activeSessionId)\n }\n onSend(nextPayload, uploadTargetSessionId, selectedModel || null)\n if (text.trim()) {\n inputHistory.addEntry(text)\n }\n resetComposer()\n } finally {\n submittingRef.current = false\n }\n }\n\n const removeAttachment = (id: string) => {\n setComposerAttachments((prev) => prev.filter((attachment) => attachment.id !== id))\n }\n\n const [showAddContext, setShowAddContext] = useState(false)\n const isPlanning = mode === \"planning\"\n const placeholder = isPlanning ? \"规划进行中… 可输入补充需求或等待完成\" : \"输入消息…\"\n const attachments = renderAttachments?.() ?? null\n const hasRenderedAttachments = attachments !== null\n const hasPendingContexts = (pendingContexts?.length ?? 0) > 0\n const currentSession = useSessionStore((state) =>\n activeSessionId ? state.sessions.find((s) => s.id === activeSessionId) : undefined,\n )\n const isSkillEditor =\n currentSession?.solution_id === \"skill_editor\" ||\n currentSession?.template_id === \"skill_editor\"\n const imageAttachments = composerAttachments.filter(isImageAttachment)\n const fileAttachments = composerAttachments.filter(\n (attachment): attachment is FileComposerAttachment => !isImageAttachment(attachment),\n )\n const hasUploadingFiles = composerAttachments.some(\n (attachment) => attachment.status === \"uploading\",\n )\n const hasValidAttachments = composerAttachments.some((attachment) => attachment.status !== \"failed\")\n const isSendDisabled =\n connectionStatus !== \"connected\" ||\n hasUploadingFiles ||\n (!input.trim() && !hasValidAttachments && !hasRenderedAttachments && !hasPendingContexts)\n\n return (\n <>\n <div className={`bg-[hsl(var(--background))] px-5 py-3 ${className ?? \"\"}`}>\n <div className={`mx-auto ${maxWidthClassName} ${innerClassName ?? \"\"}`}>\n <div\n className=\"relative\"\n onDragOver={(event) => {\n event.preventDefault()\n setDragging(true)\n }}\n onDragLeave={() => setDragging(false)}\n onDrop={(event) => {\n event.preventDefault()\n setDragging(false)\n void stableAppendFiles(event.dataTransfer.files)\n }}\n >\n <div\n className={`overflow-visible rounded-2xl border bg-[hsl(var(--card))] transition-[box-shadow,border-color] duration-300 ${\n isRecording\n ? \"border-emerald-400/70! shadow-[0_0_0_3px_rgba(52,211,153,0.18),0_0_24px_rgba(52,211,153,0.28)]\"\n : dragging\n ? isPlanning\n ? \"border-amber-400/60\"\n : \"border-[hsl(var(--primary)/0.6)]\"\n : isEditorFocused\n ? isPlanning\n ? \"border-amber-400/60\"\n : \"border-[hsl(var(--primary)/0.6)]\"\n : isPlanning\n ? \"border-amber-400/30\"\n : \"border-[hsl(var(--border))]\"\n }`}\n >\n {composerAttachments.length > 0 && (\n <div className=\"flex max-h-40 flex-col gap-2 overflow-y-auto border-b border-[hsl(var(--border))] px-3 py-2\">\n {imageAttachments.length > 0 && (\n <div className=\"grid grid-cols-3 gap-2\">\n {imageAttachments.map((attachment) => (\n <div\n key={attachment.id}\n className=\"relative overflow-hidden rounded-xl border border-[hsl(var(--border))]\"\n >\n <img\n src={getImagePreviewUrl(attachment, activeSessionId, localImageUrls)}\n alt={attachment.name || \"图片预览\"}\n className=\"h-24 w-full object-cover\"\n />\n <button\n type=\"button\"\n onClick={() => removeAttachment(attachment.id)}\n aria-label={`移除 ${attachment.name || \"图片\"}`}\n className=\"absolute right-1.5 top-1.5 flex h-6 w-6 items-center justify-center rounded-full bg-[hsl(var(--background)/0.85)] text-[hsl(var(--foreground))]\"\n >\n <X size={12} />\n </button>\n </div>\n ))}\n </div>\n )}\n {fileAttachments.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {fileAttachments.map((attachment) => (\n <ComposerFilePill\n key={attachment.id}\n attachment={attachment}\n onRemove={removeAttachment}\n />\n ))}\n </div>\n )}\n </div>\n )}\n {(hasPendingContexts || isSkillEditor) ? (\n <div className=\"flex flex-wrap items-center gap-1.5 border-b border-[hsl(var(--border))] px-3 py-2\">\n {pendingContexts?.map((context) => (\n <ComposerContextPill\n key={context.id}\n id={context.id}\n label={context.label}\n content={context.content}\n onRemove={(contextId) => {\n if (!activeSessionId) {\n return\n }\n removePendingContext(activeSessionId, contextId)\n }}\n />\n ))}\n {isSkillEditor && (\n <button\n type=\"button\"\n onClick={() => setShowAddContext(true)}\n title=\"添加上下文\"\n className=\"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-dashed border-[hsl(var(--border))] text-[hsl(var(--muted-foreground))] transition-colors hover:border-[hsl(var(--ring))] hover:text-[hsl(var(--foreground))]\"\n >\n <Plus size={12} />\n </button>\n )}\n </div>\n ) : null}\n {showAddContext && activeSessionId && (\n <AddContextDialog\n sessionId={activeSessionId}\n onClose={() => setShowAddContext(false)}\n onAdd={(label, content) => {\n if (activeSessionId) {\n useUiBridgeStore.getState().addPendingContext(activeSessionId, { label, content })\n }\n }}\n />\n )}\n {attachments ? (\n <div className=\"border-b border-[hsl(var(--border))] px-3 py-3\">\n {attachments}\n </div>\n ) : null}\n {slotAboveTextarea ? (\n <div className=\"border-b border-[hsl(var(--border))] px-3 py-2\">\n {slotAboveTextarea}\n </div>\n ) : null}\n <div className=\"relative\">\n {input.length === 0 && (\n <div className=\"pointer-events-none absolute left-4 top-3 text-sm leading-relaxed text-[hsl(var(--muted-foreground))]\">\n {placeholder}\n </div>\n )}\n <EditorContent editor={editor} />\n </div>\n <div className=\"flex items-center justify-between border-t border-[hsl(var(--border))] px-3 py-1.5\">\n <div className=\"flex items-center gap-2\">\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"*/*\"\n multiple\n onChange={(event) => {\n if (event.target.files) {\n void appendFiles(event.target.files)\n event.target.value = \"\"\n }\n }}\n className=\"hidden\"\n />\n <input\n ref={folderInputRef}\n type=\"file\"\n multiple\n onChange={(event) => {\n if (event.target.files) {\n void appendFiles(event.target.files)\n event.target.value = \"\"\n }\n }}\n className=\"hidden\"\n // biome-ignore lint/suspicious/noExplicitAny: webkitdirectory is a non-standard HTML attribute\n {...({ webkitdirectory: \"\" } as any)}\n />\n <details ref={actionMenuRef} className=\"group relative\">\n <summary\n aria-label=\"添加内容\"\n title=\"添加内容\"\n className=\"flex h-7 w-7 shrink-0 cursor-pointer list-none items-center justify-center rounded-lg border border-[hsl(var(--border))] text-[hsl(var(--muted-foreground))] transition-colors hover:border-[hsl(var(--ring))] hover:text-[hsl(var(--foreground))] [&::-webkit-details-marker]:hidden\"\n >\n <Plus size={14} />\n </summary>\n <div className=\"absolute bottom-full left-0 z-30 mb-2 min-w-36 overflow-visible rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 text-[11px] text-[hsl(var(--popover-foreground))] shadow-lg\">\n <button\n type=\"button\"\n onClick={() => {\n actionMenuRef.current?.removeAttribute(\"open\")\n fileInputRef.current?.click()\n }}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n <Paperclip size={13} />\n 上传文件\n </button>\n <button\n type=\"button\"\n onClick={() => {\n actionMenuRef.current?.removeAttribute(\"open\")\n folderInputRef.current?.click()\n }}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n <FolderUp size={13} />\n 上传文件夹\n </button>\n {onCommand ? (\n <>\n <button\n type=\"button\"\n onClick={() => {\n actionMenuRef.current?.removeAttribute(\"open\")\n void onCommand(\"compact\")\n }}\n disabled={isStreaming}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {isStreaming ? <Loader2 size={13} className=\"animate-spin\" /> : <Scissors size={13} />}\n 整理对话\n </button>\n <button\n type=\"button\"\n onClick={() => {\n actionMenuRef.current?.removeAttribute(\"open\")\n void onCommand(\"download_session\")\n }}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n <Download size={13} />\n 导出会话\n </button>\n {canShareSession ? (\n <button\n type=\"button\"\n onClick={() => {\n actionMenuRef.current?.removeAttribute(\"open\")\n void onCommand(\"share_session\")\n }}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n <Share2 size={13} />\n 分享会话\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={() => {\n actionMenuRef.current?.removeAttribute(\"open\")\n void onCommand(\"extract_skill\")\n }}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n <FlaskConical size={13} />\n 提取技能\n </button>\n <button\n type=\"button\"\n onClick={() => {\n actionMenuRef.current?.removeAttribute(\"open\")\n void onCommand(\"generate_app\")\n }}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left transition-colors hover:bg-[hsl(var(--accent))]\"\n >\n <Rocket size={13} />\n 生成应用\n </button>\n </>\n ) : null}\n <div className=\"flex items-center gap-2 px-3 py-2\">\n <Sparkles size={13} />\n <span className=\"shrink-0\">模型</span>\n <ModelSelector\n value={selectedModel}\n onValueChange={(model) => {\n setSelectedModel(model)\n if (activeSessionId) {\n patchSession(activeSessionId, { model })\n }\n setPreferredModel(model)\n }}\n compact\n placement=\"top\"\n />\n </div>\n </div>\n </details>\n <button\n type=\"button\"\n onClick={onToggleMode}\n disabled={isStreaming || !onToggleMode}\n aria-pressed={isPlanning}\n aria-label={isPlanning ? \"关闭规划模式\" : \"开启规划模式\"}\n title={isPlanning ? \"规划模式已开启\" : \"开启规划模式\"}\n className={`flex h-7 w-7 shrink-0 items-center justify-center rounded-lg border transition-colors ${\n isPlanning\n ? \"border-amber-500/45 bg-amber-500/15 text-amber-400\"\n : \"border-[hsl(var(--border))] text-[hsl(var(--muted-foreground))] hover:border-amber-500/35 hover:text-[hsl(var(--foreground))]\"\n } disabled:cursor-not-allowed disabled:opacity-50`}\n >\n <Lightbulb size={13} />\n </button>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <div className=\"group/help relative\">\n <button\n type=\"button\"\n aria-label=\"查看输入提示\"\n className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-lg text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]\"\n >\n <CircleHelp size={13} />\n </button>\n <div className=\"pointer-events-auto absolute bottom-full right-0 z-30 hidden pb-2 group-hover/help:block group-focus-within/help:block\">\n <div className=\"min-w-64 rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] p-3 text-left text-[11px] leading-5 text-[hsl(var(--popover-foreground))] shadow-lg\">\n {activeSessionId ? (\n <div className=\"mb-2 border-b border-[hsl(var(--border))] pb-2\">\n <SkillStatusBarComponent\n sessionId={activeSessionId}\n onResync={onResyncSkills}\n isResyncing={isResyncingSkills}\n vertical\n className={skillStatusBarClassName}\n innerClassName={skillStatusBarInnerClassName}\n />\n </div>\n ) : null}\n <div className=\"space-y-0.5\">\n <div>Shift+Enter 换行</div>\n <div>/ 调用技能</div>\n <div>@ 引用文件</div>\n </div>\n </div>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={asrEnabled ? voice.toggle : handleMicDisabledClick}\n disabled={isStreaming}\n aria-label={\n !asrEnabled ? \"语音输入未开启\" : isRecording ? \"停止语音输入\" : \"开始语音输入\"\n }\n title={\n !asrEnabled ? \"语音输入未开启\" : isRecording ? \"停止语音输入\" : \"语音输入\"\n }\n className={`flex items-center justify-center rounded-lg border transition-[width,height,border-color,background-color,color,box-shadow] duration-300 disabled:opacity-40 ${\n !asrEnabled\n ? \"h-7 w-7 border-[hsl(var(--border))] text-[hsl(var(--muted-foreground))]/50 hover:text-[hsl(var(--muted-foreground))]\"\n : isRecording\n ? \"h-9 w-9 border-emerald-400/80! bg-emerald-400/15 text-emerald-400 shadow-[0_0_0_2px_rgba(52,211,153,0.2),0_0_12px_rgba(52,211,153,0.35)]\"\n : \"h-7 w-7 border-[hsl(var(--border))] text-[hsl(var(--muted-foreground))] hover:border-[hsl(var(--ring))] hover:text-[hsl(var(--foreground))]\"\n }`}\n >\n {!asrEnabled ? (\n <MicOff size={13} />\n ) : isRecording ? (\n <VoiceWaveform level={voiceLevel} size={18} />\n ) : (\n <Mic size={13} />\n )}\n </button>\n {isStreaming ? (\n <button\n type=\"button\"\n onClick={onStop}\n aria-label=\"停止生成\"\n className=\"flex h-7 w-7 items-center justify-center rounded-lg bg-[hsl(var(--destructive))] text-[hsl(var(--destructive-foreground))] transition-opacity hover:opacity-80\"\n >\n <Square size={13} />\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={isSendDisabled || isRecording}\n aria-label=\"发送消息\"\n className=\"flex h-7 w-7 items-center justify-center rounded-lg bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-80 disabled:opacity-25\"\n >\n <Send size={13} />\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <FileSizeLimitDialog\n open={oversizedFiles.length > 0}\n onOpenChange={(open) => {\n if (!open) {\n setOversizedFiles([])\n }\n }}\n files={oversizedFiles}\n limitBytes={ATTACHMENT_SIZE_LIMIT_BYTES}\n />\n </>\n )\n}\n","import type { Editor as TiptapEditor } from \"@tiptap/react\"\nimport { useCallback, useEffect, useEffectEvent, useRef } from \"react\"\nimport { useVoiceInput, type VoiceInputStatus } from \"./use-voice-input\"\nimport type { VoiceInputError } from \"./voice-input-support\"\n\nexport interface UseTiptapVoiceInputOptions {\n /** Tiptap editor ref;null 时 voice 回调会静默丢弃 */\n editorRef: { current: TiptapEditor | null }\n /** AudioWorklet processor 文件 URL */\n workletUrl: string\n /** 外部可选回调:识别错误时拿 message */\n onError?: (error: VoiceInputError) => void\n}\n\nexport interface UseTiptapVoiceInputResult {\n status: VoiceInputStatus\n isRecording: boolean\n error: string | null\n /** 当前音频 RMS 幅度,0..1,仅在 recording 期间有意义,用于驱动波形动画 */\n level: number\n toggle: () => void\n stop: () => Promise<void>\n}\n\n/**\n * Tiptap 编辑器里的语音输入集成:\n * - partial 段用 `insertContentAt({from,to}, text)` 替换一个可变 range\n * - final 段落定后把 range 推进到末尾,下一段重新起\n * - 录音期间调用 `editor.setEditable(false)` 锁定键盘输入\n */\nexport function useTiptapVoiceInput(\n options: UseTiptapVoiceInputOptions,\n): UseTiptapVoiceInputResult {\n const { editorRef, workletUrl, onError } = options\n const partialRangeRef = useRef<{ from: number; to: number } | null>(null)\n // 最近一次 partial 的字符数:豆包 result_type=single 模式下每段话 VAD 结束后\n // 累积器会归零,下一段 partial 从空开始增长。只要新 partial 比上一次短,就\n // 说明跨过了句子边界:把之前的内容冻结在原位,为新句子开新 range。\n const lastPartialLenRef = useRef(0)\n\n const handlePartial = useEffectEvent((text: string) => {\n const ed = editorRef.current\n if (!ed) return\n let range = partialRangeRef.current\n if (range && text.length < lastPartialLenRef.current) {\n range = { from: range.to, to: range.to }\n partialRangeRef.current = range\n }\n if (!range) {\n const pos = ed.state.selection.from\n range = { from: pos, to: pos }\n partialRangeRef.current = range\n }\n const { from, to } = range\n if (text) {\n ed.chain().insertContentAt({ from, to }, text).run()\n partialRangeRef.current = { from, to: from + text.length }\n lastPartialLenRef.current = text.length\n } else if (to > from) {\n ed.chain().deleteRange({ from, to }).run()\n partialRangeRef.current = { from, to: from }\n lastPartialLenRef.current = 0\n }\n })\n\n const handleFinal = useEffectEvent((text: string) => {\n const ed = editorRef.current\n if (!ed || !text) return\n const range = partialRangeRef.current\n if (range) {\n ed.chain().insertContentAt({ from: range.from, to: range.to }, text).run()\n const newEnd = range.from + text.length\n partialRangeRef.current = { from: newEnd, to: newEnd }\n } else {\n ed.chain().focus(\"end\").insertContent(text).run()\n }\n lastPartialLenRef.current = 0\n })\n\n const handleError = useEffectEvent((error: VoiceInputError) => {\n partialRangeRef.current = null\n lastPartialLenRef.current = 0\n onError?.(error)\n })\n\n const voice = useVoiceInput({\n workletUrl,\n onPartial: handlePartial,\n onFinal: handleFinal,\n onError: handleError,\n })\n\n const isRecording = voice.status === \"recording\"\n\n // 录音中锁定编辑器\n useEffect(() => {\n const ed = editorRef.current\n if (!ed) return\n ed.setEditable(!isRecording)\n }, [isRecording, editorRef])\n\n // 回到 idle/error 时清掉 range 游标\n useEffect(() => {\n if (voice.status === \"idle\" || voice.status === \"error\") {\n partialRangeRef.current = null\n lastPartialLenRef.current = 0\n }\n }, [voice.status])\n\n const toggle = useCallback(() => {\n if (voice.status === \"recording\") {\n void voice.stop()\n } else {\n void voice.start()\n }\n }, [voice])\n\n return {\n status: voice.status,\n isRecording,\n error: voice.error,\n level: voice.level,\n toggle,\n stop: voice.stop,\n }\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\"\nimport { getSocket } from \"../api/socket\"\nimport {\n buildVoiceInputUnavailableError,\n type VoiceInputError,\n} from \"./voice-input-support\"\n\nexport type VoiceInputStatus = \"idle\" | \"starting\" | \"recording\" | \"stopping\" | \"error\"\n\nexport interface UseVoiceInputOptions {\n workletUrl: string\n onPartial?: (text: string) => void\n onFinal?: (text: string) => void\n onError?: (error: VoiceInputError) => void\n}\n\nexport interface UseVoiceInputResult {\n status: VoiceInputStatus\n error: string | null\n /** 当前音频 RMS 幅度,0..1,仅在 recording 期间有意义,用于驱动波形动画 */\n level: number\n start: () => Promise<void>\n stop: () => Promise<void>\n}\n\ninterface Session {\n requestId: string\n stream: MediaStream\n ctx: AudioContext\n source: MediaStreamAudioSourceNode\n workletNode: AudioWorkletNode\n handlers: {\n partial: (data: unknown) => void\n final: (data: unknown) => void\n error: (data: unknown) => void\n }\n disposed: boolean\n flushAck: (() => void) | null\n}\n\nconst STARTUP_TIMEOUT_MS = 6000\n// 批式 provider(如 Qwen)要等整段转写跑完才会发 asr:closed,可能 5–10s;\n// 流式 provider(火山)通常 <1s 就到 closed。给一个够宽的兜底,正常路径由\n// asr:closed 事件即时 resolve,不会真的等够这么久。\nconst STOP_TIMEOUT_MS = 30000\nconst FLUSH_ACK_TIMEOUT_MS = 200\n\nfunction matchesRequest(data: unknown, requestId: string): boolean {\n const rid = (data as { request_id?: string })?.request_id\n return !rid || rid === requestId\n}\n\nexport function useVoiceInput(options: UseVoiceInputOptions): UseVoiceInputResult {\n const [status, setStatus] = useState<VoiceInputStatus>(\"idle\")\n const [error, setError] = useState<string | null>(null)\n const [level, setLevel] = useState(0)\n const sessionRef = useRef<Session | null>(null)\n const startingRef = useRef(false)\n const stoppingRef = useRef(false)\n const unmountedRef = useRef(false)\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n const reportError = useCallback((err: string | VoiceInputError) => {\n const payload = typeof err === \"string\" ? { title: err } : err\n setError(payload.title)\n setStatus(\"error\")\n setLevel(0)\n optionsRef.current.onError?.(payload)\n }, [])\n\n const disposeSession = useCallback((s: Session) => {\n if (s.disposed) return\n s.disposed = true\n const socket = getSocket()\n socket.off(\"asr:partial\", s.handlers.partial)\n socket.off(\"asr:final\", s.handlers.final)\n socket.off(\"asr:error\", s.handlers.error)\n try {\n s.workletNode.port.onmessage = null\n s.workletNode.disconnect()\n } catch {}\n try {\n s.source.disconnect()\n } catch {}\n try {\n for (const t of s.stream.getTracks()) t.stop()\n } catch {}\n try {\n void s.ctx.close()\n } catch {}\n }, [])\n\n const stop = useCallback(async () => {\n const s = sessionRef.current\n if (!s || stoppingRef.current) {\n setStatus((prev) => (prev === \"error\" ? \"error\" : \"idle\"))\n return\n }\n stoppingRef.current = true\n setStatus(\"stopping\")\n\n // 尾部 <100ms 的音频 flush,等 worklet 回 ack 再继续\n await new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, FLUSH_ACK_TIMEOUT_MS)\n s.flushAck = () => {\n clearTimeout(timer)\n resolve()\n }\n try {\n s.workletNode.port.postMessage(\"flush\")\n } catch {\n clearTimeout(timer)\n resolve()\n }\n })\n\n // 等 closed,期间保持 partial/final 监听活着以收尾部识别结果;超时兜底\n const socket = getSocket()\n await new Promise<void>((resolve) => {\n let settled = false\n const finish = () => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n socket.off(\"asr:closed\", onClosed)\n resolve()\n }\n const onClosed = (data: unknown) => {\n if (matchesRequest(data, s.requestId)) finish()\n }\n const timer = setTimeout(finish, STOP_TIMEOUT_MS)\n socket.on(\"asr:closed\", onClosed)\n socket.emit(\"asr:stop\", { request_id: s.requestId })\n })\n\n // 等服务端 final/closed 到齐后再 off partial/final/error 并释放资源\n disposeSession(s)\n if (sessionRef.current === s) {\n sessionRef.current = null\n }\n stoppingRef.current = false\n setLevel(0)\n setStatus((prev) => (prev === \"error\" ? \"error\" : \"idle\"))\n }, [disposeSession])\n\n const start = useCallback(async () => {\n if (\n sessionRef.current ||\n startingRef.current ||\n stoppingRef.current ||\n unmountedRef.current\n ) {\n return\n }\n startingRef.current = true\n setError(null)\n setStatus(\"starting\")\n\n if (typeof window === \"undefined\" || !navigator.mediaDevices?.getUserMedia) {\n startingRef.current = false\n reportError(buildVoiceInputUnavailableError())\n return\n }\n\n let stream: MediaStream | null = null\n let ctx: AudioContext | null = null\n let source: MediaStreamAudioSourceNode | null = null\n let workletNode: AudioWorkletNode | null = null\n const socket = getSocket()\n const requestId =\n typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : `asr-${Date.now()}-${Math.random().toString(36).slice(2)}`\n\n const cleanupPartial = () => {\n if (workletNode) {\n try {\n workletNode.port.onmessage = null\n workletNode.disconnect()\n } catch {}\n }\n if (source) {\n try {\n source.disconnect()\n } catch {}\n }\n if (stream) {\n try {\n for (const t of stream.getTracks()) t.stop()\n } catch {}\n }\n if (ctx) {\n try {\n void ctx.close()\n } catch {}\n }\n }\n\n const checkCancelled = (): boolean => {\n if (unmountedRef.current) {\n cleanupPartial()\n // 若已经对后端发过 asr:start,补发 asr:stop 让服务端释放 bridge\n try {\n getSocket().emit(\"asr:stop\", { request_id: requestId })\n } catch {}\n return true\n }\n return false\n }\n\n try {\n stream = await navigator.mediaDevices.getUserMedia({\n audio: {\n channelCount: 1,\n sampleRate: 16000,\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n })\n if (checkCancelled()) return\n const AudioCtx: typeof AudioContext =\n window.AudioContext ??\n (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext!\n ctx = new AudioCtx({ sampleRate: 16000 })\n await ctx.audioWorklet.addModule(optionsRef.current.workletUrl)\n if (checkCancelled()) return\n source = ctx.createMediaStreamSource(stream)\n workletNode = new AudioWorkletNode(ctx, \"pcm-processor\")\n\n // 等后端 ready(带作用域)\n await new Promise<void>((resolve, reject) => {\n let settled = false\n const finish = (ok: boolean, err?: string) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n socket.off(\"asr:ready\", onReady)\n socket.off(\"asr:error\", onEarlyError)\n if (ok) resolve()\n else reject(new Error(err ?? \"unknown\"))\n }\n const onReady = (data: unknown) => {\n if (matchesRequest(data, requestId)) finish(true)\n }\n const onEarlyError = (data: unknown) => {\n if (!matchesRequest(data, requestId)) return\n finish(false, (data as { message?: string })?.message ?? \"后端语音识别启动失败\")\n }\n const timer = setTimeout(() => finish(false, \"语音识别连接超时\"), STARTUP_TIMEOUT_MS)\n socket.on(\"asr:ready\", onReady)\n socket.on(\"asr:error\", onEarlyError)\n socket.emit(\"asr:start\", { request_id: requestId })\n })\n if (checkCancelled()) return\n\n // 订阅运行期事件(按 request_id 过滤)\n const onPartial = (data: unknown) => {\n if (!matchesRequest(data, requestId)) return\n const text = (data as { text?: string })?.text\n if (text) optionsRef.current.onPartial?.(text)\n }\n const onFinal = (data: unknown) => {\n if (!matchesRequest(data, requestId)) return\n const text = (data as { text?: string })?.text\n if (text) optionsRef.current.onFinal?.(text)\n }\n const onError = (data: unknown) => {\n if (!matchesRequest(data, requestId)) return\n const msg = (data as { message?: string })?.message ?? \"语音识别失败\"\n const cur = sessionRef.current\n if (cur && cur.requestId === requestId) {\n sessionRef.current = null\n disposeSession(cur)\n }\n reportError(msg)\n }\n socket.on(\"asr:partial\", onPartial)\n socket.on(\"asr:final\", onFinal)\n socket.on(\"asr:error\", onError)\n\n const session: Session = {\n requestId,\n stream,\n ctx,\n source,\n workletNode,\n handlers: { partial: onPartial, final: onFinal, error: onError },\n disposed: false,\n flushAck: null,\n }\n\n workletNode.port.onmessage = (ev) => {\n const msg = ev.data as\n | { type: \"flushed\" }\n | { type: \"audio\"; pcm: ArrayBuffer; level: number }\n | undefined\n if (!msg || typeof msg !== \"object\") return\n if (msg.type === \"flushed\") {\n session.flushAck?.()\n session.flushAck = null\n return\n }\n if (msg.type !== \"audio\") return\n if (!(msg.pcm instanceof ArrayBuffer) || msg.pcm.byteLength === 0) return\n // RMS ~ 0..0.3 for typical speech;放大到 0..1 区间给 UI 用\n setLevel(Math.min(1, msg.level * 4))\n socket.emit(\"asr:audio\", { pcm: msg.pcm, request_id: requestId })\n }\n source.connect(workletNode)\n\n sessionRef.current = session\n setStatus(\"recording\")\n } catch (err) {\n cleanupPartial()\n const msg = err instanceof Error ? err.message : String(err)\n reportError(msg)\n } finally {\n startingRef.current = false\n }\n }, [reportError, disposeSession])\n\n // 组件卸载时停止录音与正在进行的 start 流程,避免 MediaStream / AudioContext /\n // socket listener / 后端 bridge 泄漏\n useEffect(() => {\n unmountedRef.current = false\n return () => {\n unmountedRef.current = true\n const s = sessionRef.current\n if (s) {\n sessionRef.current = null\n disposeSession(s)\n try {\n getSocket().emit(\"asr:stop\", { request_id: s.requestId })\n } catch {}\n }\n }\n }, [disposeSession])\n\n return { status, error, level, start, stop }\n}\n","export interface VoiceInputError {\n title: string\n description?: string\n}\n\nfunction isIpHost(hostname: string): boolean {\n if (!hostname) {\n return false\n }\n if (/^\\d{1,3}(?:\\.\\d{1,3}){3}$/.test(hostname)) {\n return true\n }\n return hostname.includes(\":\")\n}\n\nexport function buildVoiceInputUnavailableError(): VoiceInputError {\n if (typeof window === \"undefined\") {\n return { title: \"当前浏览器不支持麦克风采集\" }\n }\n\n const { location } = window\n if (!window.isSecureContext && location.protocol === \"http:\" && isIpHost(location.hostname)) {\n return {\n title: \"当前浏览器未开放语音输入\",\n description: [\n `你正在通过内网 IP 访问 ${location.origin}。`,\n \"Chrome / Edge 可按以下方式手工开启:\",\n \"1. 打开 chrome://flags/#unsafely-treat-insecure-origin-as-secure\",\n \" Edge 请打开 edge://flags/#unsafely-treat-insecure-origin-as-secure\",\n \"2. 启用该 flag,并填入完整 origin(必须带协议和端口)\",\n ` 当前可直接填写:${location.origin}`,\n \"3. 重启浏览器\",\n \"4. 重新打开页面,并在站点权限里允许麦克风\",\n ].join(\"\\n\"),\n }\n }\n\n return {\n title: \"当前浏览器不支持麦克风采集\",\n description: \"请使用最新版 Chrome / Edge,或改用 HTTPS、localhost 访问。\",\n }\n}\n","interface VoiceWaveformProps {\n /** RMS 幅度 0..1 */\n level: number\n /** 线条颜色;默认跟随 currentColor */\n color?: string\n /** 按钮直径参考值,决定波形尺寸 */\n size?: number\n}\n\n// 五根竖条,中间最高、两边递减。每根用不同的乘数制造错落感,但都由同一个 level 驱动:\n// 说话时整体跃起,静音时平直。CSS transform 让浏览器走 GPU 合成层,100ms 一次的\n// setState 足够顺。\nconst BAR_MULTIPLIERS = [0.45, 0.75, 1, 0.75, 0.45]\n\nexport function VoiceWaveform({ level, color = \"currentColor\", size = 16 }: VoiceWaveformProps) {\n const barWidth = Math.max(1.5, size / 10)\n const gap = Math.max(1, size / 14)\n const maxHeight = size * 0.85\n const minHeight = Math.max(2, size / 8)\n\n return (\n <div\n aria-hidden=\"true\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap,\n height: size,\n }}\n >\n {BAR_MULTIPLIERS.map((mul, i) => {\n const h = minHeight + (maxHeight - minHeight) * Math.min(1, level * mul)\n return (\n <span\n key={i}\n style={{\n width: barWidth,\n height: h,\n borderRadius: barWidth,\n backgroundColor: color,\n transition: \"height 80ms linear\",\n }}\n />\n )\n })}\n </div>\n )\n}\n","import { Loader2, Sparkles } from \"lucide-react\"\nimport { useEffect, useMemo, useRef, useState } from \"react\"\nimport { useModelConfig } from \"../../hooks/use-model-preferences\"\n\ntype ModelSelectorProps = {\n value: string\n onValueChange: (model: string) => void\n disabled?: boolean\n compact?: boolean\n placement?: \"top\" | \"bottom\"\n}\n\nexport function ModelSelector({\n value,\n onValueChange,\n disabled = false,\n compact = false,\n placement = \"bottom\",\n}: ModelSelectorProps) {\n const { models, defaultModel, isLoading } = useModelConfig()\n const [isOpen, setIsOpen] = useState(false)\n const [query, setQuery] = useState(\"\")\n const rootRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!isOpen) return\n const closeOnPointerDown = (event: PointerEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) {\n setIsOpen(false)\n }\n }\n window.addEventListener(\"pointerdown\", closeOnPointerDown)\n return () => window.removeEventListener(\"pointerdown\", closeOnPointerDown)\n }, [isOpen])\n\n const filteredModels = useMemo(() => {\n const normalized = query.trim().toLowerCase()\n if (!normalized) return models\n return models.filter(\n (model) =>\n model.id.toLowerCase().includes(normalized) ||\n model.label.toLowerCase().includes(normalized),\n )\n }, [models, query])\n\n const canSelect = models.length > 0\n const selectedLabel = models.find((model) => model.id === value)?.label\n const defaultLabel = models.find((model) => model.id === defaultModel)?.label\n const label = isLoading\n ? \"正在加载模型...\"\n : models.length === 0\n ? \"无可用模型\"\n : selectedLabel || defaultLabel || value.trim() || \"未连接到模型\"\n const dropdownPosition =\n placement === \"top\" ? \"bottom-[calc(100%+8px)]\" : \"top-[calc(100%+8px)]\"\n\n if (!canSelect) {\n return (\n <div\n className=\"flex min-w-0 items-center gap-1 rounded-lg px-2.5 py-[5px] text-[hsl(var(--muted-foreground))]\"\n title={label}\n >\n {isLoading ? (\n <Loader2 size={14} className=\"animate-spin\" aria-hidden=\"true\" />\n ) : (\n <Sparkles size={14} aria-hidden=\"true\" />\n )}\n <span className={`whitespace-nowrap text-xs ${compact ? \"\" : \"max-w-[180px]\"}`}>\n {label}\n </span>\n </div>\n )\n }\n\n return (\n <div ref={rootRef} className=\"relative\">\n <button\n type=\"button\"\n disabled={disabled}\n onClick={() => setIsOpen((current) => !current)}\n className=\"flex min-w-0 items-center gap-1 rounded-lg px-2.5 py-[5px] text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] disabled:cursor-not-allowed disabled:opacity-50\"\n title={label}\n >\n <Sparkles size={14} aria-hidden=\"true\" />\n <span className={`whitespace-nowrap text-xs ${compact ? \"\" : \"max-w-[180px]\"}`}>\n {label}\n </span>\n </button>\n\n {isOpen && (\n <div\n className={`absolute right-0 z-50 w-[260px] overflow-hidden rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] shadow-xl ${\n dropdownPosition\n }`}\n >\n <div className=\"border-b border-[hsl(var(--border))] p-2\">\n <input\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder=\"筛选模型...\"\n className=\"h-8 w-full rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--background))] px-2.5 text-xs text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground))] focus:border-[hsl(var(--ring))]\"\n />\n </div>\n <div className=\"max-h-[220px] overflow-y-auto p-1\">\n {filteredModels.length === 0 ? (\n <div className=\"px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]\">\n 没有匹配的模型\n </div>\n ) : (\n filteredModels.map((model) => (\n <button\n key={model.id}\n type=\"button\"\n onClick={() => {\n onValueChange(model.id)\n setIsOpen(false)\n setQuery(\"\")\n }}\n className={`block w-full truncate rounded-lg px-3 py-2 text-left text-xs transition-colors ${\n model.id === value\n ? \"bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]\"\n : \"text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n }`}\n title={model.id === model.label ? model.id : `${model.label} (${model.id})`}\n >\n {model.label}\n </button>\n ))\n )}\n </div>\n </div>\n )}\n </div>\n )\n}\n","import { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\"\nimport { getModelsConfig, type ModelOption } from \"../api/models\"\nimport { getUserPreference, setUserPreference } from \"../api/user-preferences\"\n\nconst PREFERRED_MODEL_KEY = \"preferred_model\"\nconst MODEL_CONFIG_QUERY_KEY = [\"model-config\"] as const\nconst PREFERRED_MODEL_QUERY_KEY = [\"user-preference\", PREFERRED_MODEL_KEY] as const\n\nexport function useModelConfig(): {\n models: ModelOption[]\n defaultModel: string\n isLoading: boolean\n} {\n const { data, isLoading } = useQuery({\n queryKey: MODEL_CONFIG_QUERY_KEY,\n queryFn: () => getModelsConfig(),\n staleTime: 5 * 60 * 1000,\n // 全局 QueryClient 默认关闭 refetchOnWindowFocus,这里显式开启,\n // 让模型列表在 staleTime 过期后能随窗口聚焦自动刷新\n refetchOnWindowFocus: true,\n })\n\n return {\n models: data?.models ?? [],\n defaultModel: data?.default ?? \"\",\n isLoading,\n }\n}\n\nexport function usePreferredModel(): {\n preferredModel: string | null\n setPreferredModel: (modelId: string) => void\n} {\n const queryClient = useQueryClient()\n\n const { data } = useQuery({\n queryKey: PREFERRED_MODEL_QUERY_KEY,\n queryFn: () => getUserPreference(PREFERRED_MODEL_KEY),\n staleTime: Number.POSITIVE_INFINITY,\n })\n\n const mutation = useMutation({\n mutationFn: (modelId: string) => setUserPreference(PREFERRED_MODEL_KEY, modelId),\n onMutate: async (modelId) => {\n await queryClient.cancelQueries({ queryKey: PREFERRED_MODEL_QUERY_KEY })\n const previous = queryClient.getQueryData<string | null>(PREFERRED_MODEL_QUERY_KEY)\n queryClient.setQueryData(PREFERRED_MODEL_QUERY_KEY, modelId)\n return { previous }\n },\n onError: (_error, _modelId, context) => {\n queryClient.setQueryData(PREFERRED_MODEL_QUERY_KEY, context?.previous ?? null)\n },\n onSettled: () => {\n void queryClient.invalidateQueries({ queryKey: PREFERRED_MODEL_QUERY_KEY })\n },\n })\n\n return {\n preferredModel: data ?? null,\n setPreferredModel: (modelId: string) => mutation.mutate(modelId),\n }\n}\n","import type { ModelsResource } from \"../../client/resources/models\"\nimport { getClient } from \"./client\"\nexport * from \"../../client/resources/models\"\nconst r = (): ModelsResource => getClient().models\nexport const getModelsConfig = (...args: Parameters<ModelsResource[\"getModelsConfig\"]>) => r().getModelsConfig(...args)\n","import type { UserPreferencesResource } from \"../../client/resources/user-preferences\"\nimport { getClient } from \"./client\"\nconst r = (): UserPreferencesResource => getClient().userPreferences\nexport const getUserPreference = (...args: Parameters<UserPreferencesResource[\"getUserPreference\"]>) => r().getUserPreference(...args)\nexport const setUserPreference = (...args: Parameters<UserPreferencesResource[\"setUserPreference\"]>) => r().setUserPreference(...args)\nexport const getPersistentDefault = (...args: Parameters<UserPreferencesResource[\"getPersistentDefault\"]>) => r().getPersistentDefault(...args)\nexport const setPersistentDefault = (...args: Parameters<UserPreferencesResource[\"setPersistentDefault\"]>) => r().setPersistentDefault(...args)\nexport const resetComputer = (...args: Parameters<UserPreferencesResource[\"resetComputer\"]>) => r().resetComputer(...args)\nexport const getComputerUpgradeStatus = (...args: Parameters<UserPreferencesResource[\"getComputerUpgradeStatus\"]>) => r().getComputerUpgradeStatus(...args)\nexport const upgradeComputer = (...args: Parameters<UserPreferencesResource[\"upgradeComputer\"]>) => r().upgradeComputer(...args)\n","import { useCallback, useEffect, useMemo, useState } from \"react\"\n\nconst MAX_HISTORY_ENTRIES = 50\n\nfunction getStorageKey(sessionId: string | null) {\n return sessionId ? `input-history:${sessionId}` : null\n}\n\nfunction readEntries(storageKey: string | null) {\n if (typeof window === \"undefined\" || !storageKey) {\n return []\n }\n\n try {\n const raw = window.sessionStorage.getItem(storageKey)\n if (!raw) {\n return []\n }\n\n const parsed = JSON.parse(raw)\n if (!Array.isArray(parsed)) {\n return []\n }\n\n return parsed.filter((item): item is string => typeof item === \"string\").slice(0, MAX_HISTORY_ENTRIES)\n } catch {\n return []\n }\n}\n\nexport function useInputHistory(sessionId: string | null) {\n const storageKey = useMemo(() => getStorageKey(sessionId), [sessionId])\n const [entries, setEntries] = useState<string[]>([])\n const [cursor, setCursor] = useState<number | null>(null)\n const [draft, setDraft] = useState(\"\")\n\n useEffect(() => {\n setEntries(readEntries(storageKey))\n setCursor(null)\n setDraft(\"\")\n }, [storageKey])\n\n const persistEntries = useCallback(\n (nextEntries: string[]) => {\n if (typeof window === \"undefined\" || !storageKey) {\n return\n }\n\n try {\n window.sessionStorage.setItem(storageKey, JSON.stringify(nextEntries))\n } catch {\n // 忽略 sessionStorage 写入失败,避免打断输入流程\n }\n },\n [storageKey],\n )\n\n const addEntry = useCallback(\n (value: string) => {\n if (!value.trim()) {\n return\n }\n\n setEntries((prev) => {\n const nextEntries = [value, ...prev].slice(0, MAX_HISTORY_ENTRIES)\n persistEntries(nextEntries)\n return nextEntries\n })\n setCursor(null)\n setDraft(\"\")\n },\n [persistEntries],\n )\n\n const navigateUp = useCallback(\n (currentDraft = \"\") => {\n if (entries.length === 0) {\n return null\n }\n\n if (cursor == null) {\n setDraft(currentDraft)\n }\n\n const nextCursor = cursor == null ? 0 : Math.min(cursor + 1, entries.length - 1)\n setCursor(nextCursor)\n return entries[nextCursor] ?? null\n },\n [cursor, entries],\n )\n\n const navigateDown = useCallback(() => {\n if (cursor == null) {\n return null\n }\n\n if (cursor <= 0) {\n setCursor(null)\n return draft\n }\n\n const nextCursor = cursor - 1\n setCursor(nextCursor)\n return entries[nextCursor] ?? draft\n }, [cursor, draft, entries])\n\n const currentEntry = cursor == null ? draft : (entries[cursor] ?? draft)\n\n return {\n addEntry,\n navigateUp,\n navigateDown,\n currentEntry,\n isNavigating: cursor != null,\n }\n}\n","import { useMemo } from \"react\"\nimport { useModelConfig, usePreferredModel } from \"./use-model-preferences\"\n\nexport function useResolvedModel(activeSessionModel?: string | null): {\n resolvedModel: string\n hasAvailableModel: boolean\n isLoading: boolean\n} {\n const { models, defaultModel, isLoading } = useModelConfig()\n const { preferredModel } = usePreferredModel()\n\n return useMemo(() => {\n if (isLoading) {\n const optimistic =\n activeSessionModel || preferredModel || defaultModel || \"\"\n return {\n resolvedModel: optimistic,\n hasAvailableModel: !!optimistic,\n isLoading,\n }\n }\n\n const ids = models.map((model) => model.id)\n const inList = (id: string | null | undefined): id is string =>\n !!id && ids.includes(id)\n\n if (inList(activeSessionModel)) {\n return { resolvedModel: activeSessionModel, hasAvailableModel: true, isLoading }\n }\n if (inList(preferredModel)) {\n return { resolvedModel: preferredModel, hasAvailableModel: true, isLoading }\n }\n if (inList(defaultModel)) {\n return { resolvedModel: defaultModel, hasAvailableModel: true, isLoading }\n }\n if (ids.length > 0) {\n return { resolvedModel: ids[0], hasAvailableModel: true, isLoading }\n }\n\n return { resolvedModel: \"\", hasAvailableModel: false, isLoading }\n }, [activeSessionModel, preferredModel, defaultModel, models, isLoading])\n}\n","export const ATTACHMENT_SIZE_LIMIT_BYTES = 1000 * 1024 * 1024\n\nexport type OversizedFileInfo = {\n name: string\n size: number\n}\n\nexport function formatFileSize(size: number) {\n if (size < 1024) {\n return `${size} B`\n }\n if (size < 1024 * 1024) {\n return `${(size / 1024).toFixed(size >= 100 * 1024 ? 0 : 1)} KB`\n }\n return `${(size / (1024 * 1024)).toFixed(size >= 10 * 1024 * 1024 ? 0 : 1)} MB`\n}\n\nexport function splitFilesBySize(\n files: FileList | File[],\n limitBytes: number = ATTACHMENT_SIZE_LIMIT_BYTES,\n) {\n const accepted: File[] = []\n const rejected: OversizedFileInfo[] = []\n\n for (const file of Array.from(files)) {\n if (file.size <= limitBytes) {\n accepted.push(file)\n continue\n }\n rejected.push({\n name: file.webkitRelativePath || file.name || \"未命名文件\",\n size: file.size,\n })\n }\n\n return { accepted, rejected }\n}\n","export interface SkillSummary {\n skill_id: string\n display_name: string\n dir_name: string\n description: string\n path: string\n references: string[]\n local: boolean\n}\n\nexport interface SkillSearchResult {\n skill_id: string\n display_name: string\n dir_name: string\n description: string\n local: boolean\n}\n\ntype SkillDisplayTarget = {\n skill_id?: string | null\n display_name?: string | null\n skillId?: string | null\n displayName?: string | null\n}\n\nexport function skillDisplayName(skill: SkillDisplayTarget): string {\n const displayName = (skill.display_name ?? skill.displayName ?? \"\").trim()\n if (displayName) {\n return displayName\n }\n return (skill.skill_id ?? skill.skillId ?? \"\").trim()\n}\n\nexport interface SkillStats {\n loaded_skill_count: number\n loaded_skill_names: string[]\n remote_configured: boolean\n remote_connected: boolean\n installed_skill_count: number\n}\n\nexport interface StepSpec {\n n: number\n label: string\n}\n\nexport interface StageSpec {\n id: string\n name: string\n steps: StepSpec[]\n}\n\nexport interface ParallelMode {\n id: string\n name: string\n prompt_hint: string\n}\n\nexport interface SkillDetail extends SkillSummary {\n content: string\n stages?: StageSpec[]\n parallel_modes?: ParallelMode[]\n}\n","import type { SuggestionProps } from \"@tiptap/suggestion\"\nimport { ChevronRight, File, Folder } from \"lucide-react\"\nimport { forwardRef, useCallback, useImperativeHandle, useMemo, useState } from \"react\"\nimport * as sessionsApi from \"../../api/sessions\"\nimport { useSessionStore } from \"../../stores/session-store\"\nimport type { FileSuggestionItem } from \"./extensions/file-mention\"\n\nconst ROOT_DIR = \".\"\n\ntype FileEntry = sessionsApi.FileEntry\n\nexport interface FileCompletionMenuProps\n extends Omit<SuggestionProps<FileSuggestionItem, FileSuggestionItem>, \"command\"> {\n command: (props: FileSuggestionItem) => void\n onExit?: () => void\n sessionId?: string | null\n}\n\nexport interface FileCompletionMenuRef {\n onKeyDown: (event: KeyboardEvent) => boolean\n}\n\ninterface ParsedQuery {\n dirPath: string\n filterQuery: string\n}\n\nfunction isVisibleEntry(entry: FileEntry) {\n return !entry.name.startsWith(\".\")\n}\n\nfunction fuzzyMatch(value: string, query: string) {\n if (!query) return true\n\n const target = value.toLowerCase()\n const source = query.toLowerCase()\n\n if (target.includes(source)) return true\n\n let cursor = 0\n for (const char of source) {\n cursor = target.indexOf(char, cursor)\n if (cursor === -1) return false\n cursor += 1\n }\n\n return true\n}\n\nfunction getEntryScore(entry: FileEntry, query: string) {\n if (!query) return 0\n\n const q = query.toLowerCase()\n const name = entry.name.toLowerCase()\n const path = entry.path.toLowerCase()\n\n if (name === q) return 5\n if (name.startsWith(q)) return 4\n if (path.startsWith(q)) return 3\n if (name.includes(q)) return 2\n if (path.includes(q)) return 1\n return 0\n}\n\nfunction filterEntries(entries: FileEntry[], query: string) {\n return entries\n .filter((entry) => isVisibleEntry(entry) && fuzzyMatch(`${entry.name} ${entry.path}`, query))\n .sort((a, b) => {\n if (a.is_dir !== b.is_dir) {\n return a.is_dir ? -1 : 1\n }\n\n const scoreDiff = getEntryScore(b, query) - getEntryScore(a, query)\n if (scoreDiff !== 0) {\n return scoreDiff\n }\n\n return a.name.localeCompare(b.name)\n })\n}\n\nfunction hasHiddenSegment(segments: string[]) {\n return segments.some((s) => s.startsWith(\".\"))\n}\n\nfunction parseSuggestionQuery(query: string): ParsedQuery {\n const normalized = query.replace(/^\\/+/, \"\")\n\n if (!normalized) {\n return { dirPath: ROOT_DIR, filterQuery: \"\" }\n }\n\n if (normalized.endsWith(\"/\")) {\n const dirPath = normalized.slice(0, -1)\n const segments = dirPath.split(\"/\").filter(Boolean)\n if (hasHiddenSegment(segments)) {\n return { dirPath: ROOT_DIR, filterQuery: \"\" }\n }\n return { dirPath: dirPath || ROOT_DIR, filterQuery: \"\" }\n }\n\n const segments = normalized.split(\"/\").filter(Boolean)\n if (segments.length <= 1) {\n return { dirPath: ROOT_DIR, filterQuery: normalized }\n }\n\n const dirSegments = segments.slice(0, -1)\n if (hasHiddenSegment(dirSegments)) {\n return { dirPath: ROOT_DIR, filterQuery: \"\" }\n }\n\n return {\n dirPath: dirSegments.join(\"/\"),\n filterQuery: segments.at(-1) ?? \"\",\n }\n}\n\nasync function listDirectory(sessionId: string, dirPath: string) {\n const entries = await sessionsApi.listDir(sessionId, dirPath)\n return entries.filter(isVisibleEntry)\n}\n\nexport async function getFileSuggestionItems(sessionId: string | null, query: string) {\n if (!sessionId) return []\n\n const { dirPath, filterQuery } = parseSuggestionQuery(query)\n const entries = await listDirectory(sessionId, dirPath)\n return filterEntries(entries, filterQuery)\n}\n\nexport const FileCompletionMenu = forwardRef<FileCompletionMenuRef, FileCompletionMenuProps>(\n function FileCompletionMenu(\n { command, editor, items, onExit, query, range, sessionId: sessionIdProp },\n ref,\n ) {\n const activeSessionId = useSessionStore((state) => state.activeSessionId)\n const sessionId = sessionIdProp ?? activeSessionId\n const { dirPath, filterQuery } = useMemo(() => parseSuggestionQuery(query), [query])\n return (\n <FileCompletionMenuContent\n key={`${sessionId ?? \"none\"}:${dirPath}:${filterQuery}`}\n ref={ref}\n command={command}\n editor={editor}\n filterQuery={filterQuery}\n items={items as FileEntry[]}\n onExit={onExit}\n range={range}\n sessionId={sessionId}\n />\n )\n },\n)\n\nconst FileCompletionMenuContent = forwardRef<\n FileCompletionMenuRef,\n {\n command: FileCompletionMenuProps[\"command\"]\n editor: FileCompletionMenuProps[\"editor\"]\n filterQuery: string\n items: FileEntry[]\n onExit?: () => void\n range: FileCompletionMenuProps[\"range\"]\n sessionId?: string | null\n }\n>(function FileCompletionMenuContent(\n { command, editor, filterQuery, items, onExit, range, sessionId },\n ref,\n) {\n const [rawSelectedIndex, setRawSelectedIndex] = useState(0)\n const filteredEntries = useMemo(() => filterEntries(items, filterQuery), [filterQuery, items])\n const selectedIndex =\n filteredEntries.length === 0 ? 0 : Math.min(rawSelectedIndex, filteredEntries.length - 1)\n\n const handleSelect = useCallback(\n (entry: FileEntry) => {\n if (entry.is_dir) {\n const nextValue = entry.path === ROOT_DIR ? \"@\" : `@${entry.path}/`\n editor.chain().focus().insertContentAt(range, nextValue).run()\n return\n }\n\n command({\n is_dir: false,\n name: entry.name,\n path: entry.path,\n })\n },\n [command, editor, range],\n )\n\n useImperativeHandle(\n ref,\n () => ({\n onKeyDown: (event: KeyboardEvent) => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault()\n if (filteredEntries.length > 0) {\n setRawSelectedIndex((current) => (current + 1) % filteredEntries.length)\n }\n return true\n }\n\n if (event.key === \"ArrowUp\") {\n event.preventDefault()\n if (filteredEntries.length > 0) {\n setRawSelectedIndex(\n (current) => (current - 1 + filteredEntries.length) % filteredEntries.length,\n )\n }\n return true\n }\n\n if (event.key === \"Enter\") {\n event.preventDefault()\n const entry = filteredEntries[selectedIndex]\n if (entry) {\n handleSelect(entry)\n }\n return true\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault()\n onExit?.()\n return true\n }\n\n return false\n },\n }),\n [filteredEntries, handleSelect, onExit, selectedIndex],\n )\n\n return (\n <div className=\"max-h-64 overflow-y-auto rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 shadow-lg\">\n {!sessionId ? (\n <div className=\"px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]\">暂无会话</div>\n ) : filteredEntries.length === 0 ? (\n <div className=\"px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]\">没有文件</div>\n ) : (\n filteredEntries.map((entry, index) => (\n <button\n key={entry.path}\n ref={(element) => {\n if (element && index === selectedIndex) {\n element.scrollIntoView({ block: \"nearest\" })\n }\n }}\n type=\"button\"\n onMouseDown={(event) => {\n event.preventDefault()\n handleSelect(entry)\n }}\n className={`flex w-full items-center gap-2 px-3 py-1.5 text-left text-sm transition-colors ${\n index === selectedIndex\n ? \"bg-[hsl(var(--accent))] text-[hsl(var(--accent-foreground))]\"\n : \"text-[hsl(var(--popover-foreground))] hover:bg-[hsl(var(--accent))]\"\n }`}\n >\n {entry.is_dir ? (\n <Folder size={14} className=\"shrink-0 text-[hsl(var(--primary))]\" />\n ) : (\n <File size={14} className=\"shrink-0 text-[hsl(var(--muted-foreground))]\" />\n )}\n <span className=\"truncate\">{entry.name}</span>\n {entry.is_dir && <ChevronRight size={12} className=\"ml-auto shrink-0 opacity-40\" />}\n </button>\n ))\n )}\n </div>\n )\n})\n","import { skillDisplayName } from \"../../schemas/skill\"\nimport { forwardRef, useCallback, useImperativeHandle, useState } from \"react\"\nimport type { SkillSuggestionItem } from \"./extensions/skill-mention\"\n\nexport interface SkillCompletionMenuProps {\n items: SkillSuggestionItem[]\n command: (item: SkillSuggestionItem) => void\n}\n\nexport interface SkillCompletionMenuRef {\n onKeyDown: (event: KeyboardEvent) => boolean\n}\n\nexport const SkillCompletionMenu = forwardRef<SkillCompletionMenuRef, SkillCompletionMenuProps>(\n function SkillCompletionMenu({ command, items }, ref) {\n const [rawSelectedIndex, setRawSelectedIndex] = useState(0)\n const selectedIndex = items.length === 0 ? 0 : Math.min(rawSelectedIndex, items.length - 1)\n\n const handleSelect = useCallback(\n (item: SkillSuggestionItem) => {\n command(item)\n },\n [command],\n )\n\n useImperativeHandle(\n ref,\n () => ({\n onKeyDown: (event: KeyboardEvent) => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault()\n if (items.length > 0) {\n setRawSelectedIndex((current) => (current + 1) % items.length)\n }\n return true\n }\n\n if (event.key === \"ArrowUp\") {\n event.preventDefault()\n if (items.length > 0) {\n setRawSelectedIndex((current) => (current - 1 + items.length) % items.length)\n }\n return true\n }\n\n if (event.key === \"Enter\") {\n event.preventDefault()\n const item = items[selectedIndex]\n if (item) {\n handleSelect(item)\n }\n return true\n }\n\n if (event.key === \"Escape\") {\n return false\n }\n\n return false\n },\n }),\n [handleSelect, items, selectedIndex],\n )\n\n const commandItems = items.filter((item) => item.type === \"command\")\n const skillItems = items.filter((item) => item.type === \"skill\")\n\n return (\n <div className=\"max-h-64 overflow-y-auto rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] py-1 shadow-lg\">\n {items.length === 0 ? (\n <div className=\"px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]\">\n 没有匹配的命令或技能\n </div>\n ) : (\n <div>\n {commandItems.length > 0 ? (\n <div className=\"px-2 pb-1 pt-1\">\n <div className=\"px-1 pb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-[hsl(var(--muted-foreground))]\">\n 命令\n </div>\n {commandItems.map((item, index) => (\n <button\n key={item.id}\n ref={(element) => {\n if (element && index === selectedIndex) {\n element.scrollIntoView({ block: \"nearest\" })\n }\n }}\n type=\"button\"\n onMouseDown={(event) => {\n event.preventDefault()\n handleSelect(item)\n }}\n className={`flex w-full items-start gap-2 rounded-lg px-2 py-1.5 text-left transition-colors ${\n index === selectedIndex\n ? \"bg-[hsl(var(--accent))] text-[hsl(var(--accent-foreground))]\"\n : \"text-[hsl(var(--popover-foreground))] hover:bg-[hsl(var(--accent))]\"\n }`}\n >\n <span className=\"pt-0.5 text-sm\">↻</span>\n <span className=\"flex min-w-0 flex-1 flex-col gap-0.5\">\n <span className=\"text-sm font-medium\">{item.label}</span>\n <span className=\"text-xs text-[hsl(var(--muted-foreground))]\">\n {item.description}\n </span>\n </span>\n </button>\n ))}\n </div>\n ) : null}\n {skillItems.length > 0 ? (\n <div className=\"px-2 pb-1 pt-1\">\n <div className=\"px-1 pb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-[hsl(var(--muted-foreground))]\">\n 技能\n </div>\n {skillItems.map((item, skillIndex) => {\n const index = commandItems.length + skillIndex\n return (\n <button\n key={item.skillId}\n ref={(element) => {\n if (element && index === selectedIndex) {\n element.scrollIntoView({ block: \"nearest\" })\n }\n }}\n type=\"button\"\n onMouseDown={(event) => {\n event.preventDefault()\n handleSelect(item)\n }}\n className={`flex w-full flex-col gap-0.5 rounded-lg px-2 py-1.5 text-left transition-colors ${\n index === selectedIndex\n ? \"bg-[hsl(var(--accent))] text-[hsl(var(--accent-foreground))]\"\n : \"text-[hsl(var(--popover-foreground))] hover:bg-[hsl(var(--accent))]\"\n }`}\n >\n <span className=\"text-sm font-medium\">{skillDisplayName(item)}</span>\n <span className=\"text-xs text-[hsl(var(--muted-foreground))]\">\n {item.description}\n </span>\n </button>\n )\n })}\n </div>\n ) : null}\n </div>\n )}\n </div>\n )\n },\n)\n","import { X } from \"lucide-react\"\nimport { useEffect } from \"react\"\nimport { createPortal } from \"react-dom\"\nimport { ATTACHMENT_SIZE_LIMIT_BYTES, formatFileSize, type OversizedFileInfo } from \"../../lib/attachment-upload\"\n\ninterface Props {\n open: boolean\n onOpenChange: (open: boolean) => void\n files: OversizedFileInfo[]\n limitBytes?: number\n}\n\nexport function FileSizeLimitDialog({\n open,\n onOpenChange,\n files,\n limitBytes = ATTACHMENT_SIZE_LIMIT_BYTES,\n}: Props) {\n useEffect(() => {\n if (!open) return\n const handleKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onOpenChange(false)\n }\n }\n window.addEventListener(\"keydown\", handleKey)\n return () => window.removeEventListener(\"keydown\", handleKey)\n }, [open, onOpenChange])\n\n if (!open || files.length === 0) {\n return null\n }\n\n const limitText = formatFileSize(limitBytes)\n\n return createPortal(\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4\"\n onClick={() => onOpenChange(false)}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n onOpenChange(false)\n }\n }}\n // biome-ignore lint/a11y/useSemanticElements: 原生 <dialog> 需要 showModal() + 内置 backdrop,本组件用外层 div 充当点击关闭的 backdrop,不走 modal API。\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"file-size-limit-dialog-title\"\n >\n <div\n className=\"w-full max-w-lg overflow-hidden rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--background))] shadow-2xl\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n <div className=\"flex items-center justify-between border-b border-[hsl(var(--border))] px-4 py-3\">\n <div>\n <h3 id=\"file-size-limit-dialog-title\" className=\"text-sm font-semibold text-[hsl(var(--foreground))]\">\n 附件超过大小限制\n </h3>\n <p className=\"mt-1 text-xs text-[hsl(var(--muted-foreground))]\">\n 单个附件最大支持 {limitText}。以下文件未加入附件列表。\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => onOpenChange(false)}\n title=\"关闭\"\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <X size={14} />\n </button>\n </div>\n <div className=\"max-h-[min(50vh,24rem)] overflow-auto px-4 py-3\">\n <div className=\"flex flex-col gap-2\">\n {files.map((file) => (\n <div\n key={`${file.name}:${file.size}`}\n className=\"flex items-center justify-between gap-3 rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--accent))] px-3 py-2\"\n >\n <span className=\"min-w-0 truncate text-sm text-[hsl(var(--foreground))]\">\n {file.name}\n </span>\n <span className=\"shrink-0 text-xs text-[hsl(var(--muted-foreground))]\">\n {formatFileSize(file.size)}\n </span>\n </div>\n ))}\n </div>\n </div>\n <div className=\"flex justify-end border-t border-[hsl(var(--border))] px-4 py-3\">\n <button\n type=\"button\"\n onClick={() => onOpenChange(false)}\n className=\"rounded-md bg-[hsl(var(--primary))] px-4 py-1.5 text-xs font-semibold text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90\"\n >\n 知道了\n </button>\n </div>\n </div>\n </div>,\n document.body,\n )\n}\n","import { useQuery } from \"@tanstack/react-query\"\nimport { RefreshCw } from \"lucide-react\"\nimport { type ReactNode, useMemo } from \"react\"\nimport { listSessionSkills } from \"../../api/skills\"\nimport { useBackgroundTasks } from \"../../hooks/use-background-tasks\"\nimport { useContextStats } from \"../../hooks/use-context-stats\"\nimport { useSkillStats } from \"../../hooks/use-skill-stats\"\nimport { useTokenPressure } from \"../../hooks/use-token-pressure\"\nimport { cn } from \"../../lib/utils\"\nimport { skillDisplayName } from \"../../schemas/skill\"\nimport { useConnectionStore } from \"../../stores/connection-store\"\nimport { ProgressCircle } from \"./ProgressCircle\"\n\nconst COMPACT_NUMBER_FORMATTER = new Intl.NumberFormat(\"zh-CN\", {\n notation: \"compact\",\n maximumFractionDigits: 1,\n})\n\nconst TOKEN_NUMBER_FORMATTER = new Intl.NumberFormat(\"zh-CN\")\n\nfunction formatCompactNumber(value: number) {\n return COMPACT_NUMBER_FORMATTER.format(value)\n}\n\nfunction formatTokensK(value: number) {\n const k = value / 1000\n return k < 10 ? `${k.toFixed(1)}k` : `${Math.round(k)}k`\n}\n\nfunction formatTokenNumber(value: number | null) {\n if (value == null) {\n return \"暂无明细\"\n }\n\n return TOKEN_NUMBER_FORMATTER.format(value)\n}\n\nfunction getConnectionMeta(\n status: \"connecting\" | \"connected\" | \"disconnected\",\n reconnectAttempt: number,\n hasEverConnected: boolean,\n) {\n if (status === \"connected\") {\n return {\n dotClass: \"bg-emerald-400\",\n label: \"连接正常\",\n toneClass:\n \"border-emerald-500/20 bg-emerald-500/8 text-emerald-100\",\n }\n }\n\n if (status === \"connecting\") {\n return {\n dotClass: \"bg-amber-400 animate-pulse\",\n label:\n reconnectAttempt > 0 ? `重连中 ${reconnectAttempt}` : \"连接中\",\n toneClass:\n \"border-amber-500/20 bg-amber-500/8 text-amber-100\",\n }\n }\n\n return {\n dotClass: \"bg-rose-400\",\n label: hasEverConnected ? \"连接断开\" : \"尚未连接\",\n toneClass: \"border-rose-500/20 bg-rose-500/8 text-rose-100\",\n }\n}\n\nfunction HoverPanel({\n title,\n children,\n}: {\n title: string\n children: ReactNode\n}) {\n return (\n <div className=\"pointer-events-none absolute bottom-full left-1/2 z-20 mb-2 hidden w-64 max-w-[min(20rem,calc(100vw-2rem))] -translate-x-1/2 rounded-xl border border-slate-700 bg-slate-950 px-3 py-2 text-[11px] text-slate-100 shadow-xl group-hover:block\">\n <div className=\"mb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-slate-400\">\n {title}\n </div>\n {children}\n </div>\n )\n}\n\nexport function SkillStatusBar({\n sessionId,\n onResync,\n isResyncing = false,\n vertical = false,\n className,\n innerClassName,\n}: {\n sessionId: string\n onResync?: () => void\n isResyncing?: boolean\n vertical?: boolean\n className?: string\n innerClassName?: string\n}) {\n const { data: skillStats, error, loading } = useSkillStats(sessionId)\n const { data: sessionSkills = [] } = useQuery({\n queryKey: [\"session-skills\", sessionId],\n queryFn: ({ signal }) => listSessionSkills(sessionId, { signal }),\n enabled: Boolean(sessionId),\n })\n const { data: contextStats } = useContextStats(sessionId)\n const { data: tasks } = useBackgroundTasks(sessionId)\n const tokenPressure = useTokenPressure(sessionId)\n const connectionStatus = useConnectionStore((state) => state.status)\n const reconnectAttempt = useConnectionStore((state) => state.reconnectAttempt)\n const hasEverConnected = useConnectionStore((state) => state.hasEverConnected)\n const runningTaskItems = tasks.filter((task) => task.status === \"running\")\n const runningTasks = runningTaskItems.length\n const statsReady = !loading && !error\n const skillStoreConnected = statsReady && skillStats.remote_connected\n const connectionMeta = useMemo(\n () =>\n getConnectionMeta(\n connectionStatus,\n reconnectAttempt,\n hasEverConnected,\n ),\n [connectionStatus, reconnectAttempt, hasEverConnected],\n )\n\n const items = [\n {\n key: \"bg\",\n dotClass: runningTasks > 0 ? \"bg-amber-400\" : \"bg-[hsl(var(--muted-foreground))]\",\n text: `后台任务 ${runningTasks}`,\n },\n {\n key: \"loaded\",\n dotClass: statsReady ? \"bg-emerald-500\" : \"bg-[hsl(var(--muted-foreground))]\",\n text: statsReady ? `已加载 ${skillStats.loaded_skill_count} 个技能` : \"技能状态不可用\",\n },\n {\n key: \"total\",\n dotClass: skillStoreConnected ? \"bg-emerald-500\" : \"bg-[hsl(var(--muted-foreground))]\",\n text: skillStoreConnected\n ? `已安装 ${skillStats.installed_skill_count} 个技能`\n : \"尚未登录技能商店\",\n },\n ].filter((item) => item.key !== \"total\" || skillStats.remote_configured)\n\n const tokenSummary = useMemo(() => {\n return {\n detail: (\n <div className=\"space-y-1\">\n <div className=\"flex items-center justify-between gap-3 border-t border-slate-800 pt-1\">\n <span className=\"text-slate-400\">已用</span>\n <span className=\"font-mono\">{formatTokenNumber(contextStats.tokens_used)}</span>\n </div>\n {contextStats.context_window > 0 ? (\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-slate-400\">上下文窗口</span>\n <span className=\"font-mono\">{formatCompactNumber(contextStats.context_window)}</span>\n </div>\n ) : (\n <div className=\"pt-1 text-slate-500\">\n 未配置上下文窗口大小,可通过 CONTEXT_WINDOW 环境变量设置\n </div>\n )}\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-slate-400\">整理阈值</span>\n <span className=\"font-mono\">\n {contextStats.compaction_ratio > 0\n ? `${Math.round(contextStats.compaction_ratio * 100)}%`\n : \"已禁用\"}\n </span>\n </div>\n </div>\n ),\n label:\n contextStats.context_window > 0\n ? `${formatTokensK(contextStats.tokens_used)} / ${formatTokensK(contextStats.context_window)} 上下文`\n : `${formatTokensK(contextStats.tokens_used)} 上下文`,\n warn: tokenPressure.level === \"critical\",\n }\n }, [contextStats.compaction_ratio, contextStats.context_window, contextStats.tokens_used, tokenPressure.level])\n\n const containerClass = vertical\n ? \"text-[11px] text-[hsl(var(--muted-foreground))]\"\n : \"bg-[hsl(var(--background))] px-5 pt-2\"\n const innerClass = vertical ? \"\" : \"mx-auto max-w-3xl\"\n const listClass = vertical\n ? \"flex flex-col items-stretch gap-1.5 text-[11px] text-[hsl(var(--muted-foreground))]\"\n : \"flex flex-wrap items-center gap-2 text-[10px] text-[hsl(var(--muted-foreground))]\"\n\n return (\n <div className={cn(containerClass, className)}>\n <div className={cn(innerClass, innerClassName)}>\n <div className={listClass}>\n {tokenSummary ? (\n <div className=\"flex items-center gap-2 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-2.5 py-1\">\n <ProgressCircle\n percentage={tokenPressure.ratio * 100}\n level={tokenPressure.level}\n detail={tokenSummary.detail}\n />\n <span className=\"font-mono\">{tokenSummary.label}</span>\n {tokenSummary.warn ? (\n <span className=\"rounded-full border border-rose-500/25 bg-rose-500/10 px-1.5 py-0.5 text-[10px] font-medium text-rose-200\">\n 建议整理对话\n </span>\n ) : null}\n </div>\n ) : null}\n {connectionStatus !== \"connected\" ? (\n <div\n className={cn(\n \"flex items-center gap-2 rounded-full border px-2.5 py-1 font-mono\",\n connectionMeta.toneClass,\n )}\n >\n <span className={cn(\"inline-block h-1.5 w-1.5 rounded-full\", connectionMeta.dotClass)} />\n <span>{connectionMeta.label}</span>\n </div>\n ) : null}\n {items.map((item, index) => (\n <div\n key={item.key}\n className=\"flex items-center gap-2 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-2.5 py-1\"\n >\n {index > 0 && !tokenPressure && (\n <span className=\"hidden text-[hsl(var(--border))]\">·</span>\n )}\n <span className={`inline-block h-1.5 w-1.5 rounded-full ${item.dotClass}`} />\n {item.key === \"bg\" ? (\n <div className=\"group relative\">\n <span className=\"cursor-help font-mono\">{item.text}</span>\n {runningTaskItems.length > 0 ? (\n <HoverPanel title=\"运行中任务\">\n <div className=\"max-h-40 overflow-y-auto\">\n {runningTaskItems.map((task) => (\n <div key={task.id} className=\"flex items-start gap-2 py-1 leading-relaxed\">\n <span className=\"mt-1.5 inline-block h-2 w-2 shrink-0 rounded-full border border-amber-300 bg-transparent\" />\n <div className=\"min-w-0\">\n <div className=\"font-medium\">{task.id}</div>\n <div className=\"break-words text-slate-300/85\">\n {task.description || task.command}\n </div>\n </div>\n </div>\n ))}\n </div>\n </HoverPanel>\n ) : null}\n </div>\n ) : item.key === \"loaded\" ? (\n <div className=\"group relative flex items-center gap-1.5\">\n <span className=\"cursor-help font-mono\">{item.text}</span>\n {onResync ? (\n <button\n type=\"button\"\n onClick={onResync}\n disabled={isResyncing}\n aria-label=\"同步技能\"\n className=\"inline-flex h-5 w-5 items-center justify-center rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--background))] text-[hsl(var(--muted-foreground))] transition-colors hover:border-[hsl(var(--ring))] hover:text-[hsl(var(--foreground))] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <RefreshCw size={11} className={isResyncing ? \"animate-spin\" : \"\"} />\n </button>\n ) : null}\n {statsReady && sessionSkills.length > 0 ? (\n <HoverPanel title=\"已加载技能\">\n <div className=\"max-h-40 overflow-y-auto\">\n {sessionSkills.map((skill) => (\n <div\n key={skill.skill_id}\n className=\"flex items-start gap-2 py-1 leading-relaxed\"\n >\n <span className=\"mt-1.5 inline-block h-2 w-2 shrink-0 rounded-full border border-emerald-300 bg-transparent\" />\n <span className=\"break-words\">{skillDisplayName(skill)}</span>\n </div>\n ))}\n </div>\n </HoverPanel>\n ) : null}\n </div>\n ) : (\n <span className=\"font-mono\">{item.text}</span>\n )}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n}\n","import { useQuery } from \"@tanstack/react-query\"\nimport { listBackgroundTasks } from \"../api/sessions\"\nimport type { BackgroundTask } from \"../schemas/background\"\nimport { useBackgroundStore } from \"../stores/background-store\"\n\nconst EMPTY_TASKS: BackgroundTask[] = []\n\nexport function useBackgroundTasks(sessionId: string | null | undefined) {\n const setTasks = useBackgroundStore((state) => state.setTasks)\n const tasks = useBackgroundStore((state) => (sessionId ? state.tasks[sessionId] : undefined))\n\n const query = useQuery({\n queryKey: [\"background-tasks\", sessionId],\n queryFn: ({ signal }) =>\n listBackgroundTasks(sessionId!, { signal }).then((items) => {\n setTasks(sessionId!, items)\n return items\n }),\n enabled: Boolean(sessionId),\n })\n\n return {\n data: tasks ?? query.data ?? EMPTY_TASKS,\n loading: query.isLoading,\n error: query.error,\n refetch: query.refetch,\n }\n}\n","import { useQuery } from \"@tanstack/react-query\"\nimport { getSessionContextStats, type SessionContextStats } from \"../api/sessions\"\n\nconst EMPTY_CONTEXT_STATS: SessionContextStats = {\n tokens_used: 0,\n context_window: 0,\n compaction_ratio: 0,\n}\n\nexport function useContextStats(sessionId: string | null | undefined) {\n const query = useQuery({\n queryKey: [\"context-stats\", sessionId],\n queryFn: ({ signal }) => getSessionContextStats(sessionId!, { signal }),\n enabled: Boolean(sessionId),\n refetchInterval: 60_000,\n })\n\n return {\n data: query.data ?? EMPTY_CONTEXT_STATS,\n loading: query.isLoading,\n error: query.error,\n refetch: query.refetch,\n }\n}\n","import { useQuery } from \"@tanstack/react-query\"\nimport { getSkillStats } from \"../api/skills\"\nimport type { SkillStats } from \"../schemas/skill\"\n\nconst EMPTY_SKILL_STATS: SkillStats = {\n loaded_skill_count: 0,\n loaded_skill_names: [],\n remote_configured: false,\n remote_connected: false,\n installed_skill_count: 0,\n}\n\nexport function useSkillStats(sessionId: string | null | undefined) {\n const query = useQuery({\n queryKey: [\"skill-stats\", sessionId],\n queryFn: ({ signal }) => getSkillStats(sessionId!, { signal }),\n enabled: Boolean(sessionId),\n refetchInterval: 300_000,\n })\n\n return {\n data: query.data ?? EMPTY_SKILL_STATS,\n loading: query.isLoading,\n error: query.error,\n refetch: query.refetch,\n }\n}\n","import { useMemo } from \"react\"\nimport { useContextStats } from \"./use-context-stats\"\n\nexport type TokenPressureLevel = \"normal\" | \"warn\" | \"critical\"\n\nexport interface TokenPressure {\n ratio: number\n level: TokenPressureLevel\n}\n\nfunction clampRatio(value: number) {\n return Math.min(1, Math.max(0, value))\n}\n\nfunction resolveLevel(ratio: number, compactionRatio: number): TokenPressureLevel {\n if (compactionRatio <= 0) {\n return \"normal\"\n }\n if (ratio >= compactionRatio) {\n return \"critical\"\n }\n if (ratio >= Math.max(0, compactionRatio - 0.1)) {\n return \"warn\"\n }\n return \"normal\"\n}\n\nexport function useTokenPressure(sessionId: string | null | undefined): TokenPressure {\n const { data } = useContextStats(sessionId)\n\n return useMemo(() => {\n const ratio =\n data.context_window > 0 ? clampRatio(data.tokens_used / data.context_window) : 0\n return {\n ratio,\n level: resolveLevel(ratio, data.compaction_ratio),\n }\n }, [data.compaction_ratio, data.context_window, data.tokens_used])\n}\n","import type { ReactNode } from \"react\"\nimport { cn } from \"../../lib/utils\"\nimport type { TokenPressureLevel } from \"../../hooks/use-token-pressure\"\n\ninterface ProgressCircleProps {\n percentage: number\n level: TokenPressureLevel\n size?: number\n strokeWidth?: number\n detail?: ReactNode\n className?: string\n}\n\nconst LEVEL_STYLES: Record<\n TokenPressureLevel,\n {\n strokeClass: string\n textClass: string\n trackClass: string\n }\n> = {\n normal: {\n strokeClass: \"stroke-slate-400\",\n textClass: \"text-slate-300\",\n trackClass: \"stroke-slate-500/20\",\n },\n warn: {\n strokeClass: \"stroke-amber-400\",\n textClass: \"text-amber-300\",\n trackClass: \"stroke-amber-500/20\",\n },\n critical: {\n strokeClass: \"stroke-rose-400\",\n textClass: \"text-rose-300\",\n trackClass: \"stroke-rose-500/20\",\n },\n}\n\nexport function ProgressCircle({\n percentage,\n level,\n size = 16,\n strokeWidth = 2,\n detail,\n className,\n}: ProgressCircleProps) {\n const clamped = Math.min(100, Math.max(0, percentage))\n const radius = (size - strokeWidth) / 2\n const circumference = 2 * Math.PI * radius\n const dashOffset = circumference * (1 - clamped / 100)\n const styles = LEVEL_STYLES[level]\n\n return (\n <div className={cn(\"group relative inline-flex\", className)}>\n <button\n type=\"button\"\n aria-label={`上下文已使用 ${Math.round(clamped)}%`}\n className=\"relative inline-flex cursor-help items-center justify-center rounded-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))] focus-visible:ring-offset-2 focus-visible:ring-offset-[hsl(var(--background))]\"\n >\n <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} aria-hidden=\"true\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={strokeWidth}\n className={styles.trackClass}\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n strokeDashoffset={dashOffset}\n className={cn(styles.strokeClass, \"transition-[stroke-dashoffset] duration-300\")}\n transform={`rotate(-90 ${size / 2} ${size / 2})`}\n />\n </svg>\n </button>\n {detail ? (\n <div className=\"pointer-events-none absolute bottom-full left-1/2 z-20 mb-2 hidden w-64 max-w-[min(20rem,calc(100vw-2rem))] -translate-x-1/2 rounded-xl border border-slate-700 bg-slate-950 px-3 py-2 text-[11px] text-slate-100 shadow-xl group-hover:block group-focus-within:block\">\n {detail}\n </div>\n ) : null}\n </div>\n )\n}\n","import Mention from \"@tiptap/extension-mention\"\nimport { PluginKey } from \"@tiptap/pm/state\"\n\nexport interface FileMentionAttrs {\n path: string\n name: string\n}\n\nexport interface FileSuggestionItem {\n path: string\n name: string\n is_dir: boolean\n}\n\nexport const fileMentionSuggestionKey = new PluginKey(\"fileMentionSuggestion\")\n\nfunction getFileMentionName(attrs: Partial<FileMentionAttrs>) {\n return attrs.name || attrs.path || \"\"\n}\n\nexport const FileMention = Mention.extend({\n name: \"fileMention\",\n\n addOptions() {\n const parentOptions = this.parent?.()\n\n return {\n ...parentOptions,\n HTMLAttributes: {\n ...(parentOptions?.HTMLAttributes ?? {}),\n class: \"file-mention-pill\",\n },\n deleteTriggerWithBackspace: true,\n suggestion: {\n ...(parentOptions?.suggestion ?? {}),\n char: \"@\",\n pluginKey: fileMentionSuggestionKey,\n },\n suggestions: parentOptions?.suggestions ?? [],\n renderText: ({ node }) => `@${getFileMentionName(node.attrs)}`,\n renderHTML: ({ options, node }) => [\n \"span\",\n {\n ...(options.HTMLAttributes ?? {}),\n class: \"file-mention-pill\",\n \"data-name\": node.attrs.name,\n \"data-path\": node.attrs.path,\n },\n getFileMentionName(node.attrs),\n ],\n }\n },\n\n addAttributes() {\n return {\n path: {\n default: \"\",\n parseHTML: (element: HTMLElement) => element.getAttribute(\"data-path\") || \"\",\n renderHTML: (attributes: FileMentionAttrs) => ({ \"data-path\": attributes.path }),\n },\n name: {\n default: \"\",\n parseHTML: (element: HTMLElement) => element.getAttribute(\"data-name\") || \"\",\n renderHTML: (attributes: FileMentionAttrs) => ({ \"data-name\": attributes.name }),\n },\n }\n },\n})\n","import Mention from \"@tiptap/extension-mention\"\nimport { PluginKey } from \"@tiptap/pm/state\"\n\nexport interface SkillMentionAttrs {\n skillId: string\n displayName: string\n description: string\n}\n\nexport interface SkillOnlySuggestionItem {\n skillId: string\n displayName?: string\n description: string\n local?: boolean\n}\n\nexport interface SkillCommandSuggestionItem {\n type: \"command\"\n id: string\n label: string\n description: string\n}\n\nexport interface SkillSuggestionSkillItem extends SkillOnlySuggestionItem {\n type: \"skill\"\n}\n\nexport type SkillSuggestionItem = SkillSuggestionSkillItem | SkillCommandSuggestionItem\n\nexport const COMMANDS: SkillCommandSuggestionItem[] = [\n {\n type: \"command\",\n id: \"resync\",\n label: \"同步技能\",\n description: \"从配置的技能目录拉取最新内容\",\n },\n]\n\nexport const skillMentionSuggestionKey = new PluginKey(\"skillMentionSuggestion\")\n\nfunction getSkillMentionName(attrs: Partial<SkillMentionAttrs>) {\n return attrs.displayName || attrs.skillId || \"\"\n}\n\nexport const SkillMention = Mention.extend({\n name: \"skillMention\",\n\n addOptions() {\n const parentOptions = this.parent?.()\n\n return {\n ...parentOptions,\n HTMLAttributes: {\n ...(parentOptions?.HTMLAttributes ?? {}),\n class: \"skill-mention-pill\",\n },\n deleteTriggerWithBackspace: true,\n suggestion: {\n ...(parentOptions?.suggestion ?? {}),\n char: \"/\",\n pluginKey: skillMentionSuggestionKey,\n },\n suggestions: parentOptions?.suggestions ?? [],\n renderText: ({ node }) => getSkillMentionName(node.attrs),\n renderHTML: ({ options, node }) => [\n \"span\",\n {\n ...(options.HTMLAttributes ?? {}),\n class: \"skill-mention-pill\",\n \"data-skill-id\": node.attrs.skillId,\n \"data-display-name\": node.attrs.displayName,\n \"data-description\": node.attrs.description,\n },\n getSkillMentionName(node.attrs),\n ],\n }\n },\n\n addAttributes() {\n return {\n skillId: {\n default: \"\",\n parseHTML: (element: HTMLElement) => element.getAttribute(\"data-skill-id\") || \"\",\n renderHTML: (attributes: SkillMentionAttrs) => ({\n \"data-skill-id\": attributes.skillId,\n }),\n },\n displayName: {\n default: \"\",\n parseHTML: (element: HTMLElement) => element.getAttribute(\"data-display-name\") || \"\",\n renderHTML: (attributes: SkillMentionAttrs) => ({\n \"data-display-name\": attributes.displayName,\n }),\n },\n description: {\n default: \"\",\n parseHTML: (element: HTMLElement) => element.getAttribute(\"data-description\") || \"\",\n renderHTML: (attributes: SkillMentionAttrs) => ({\n \"data-description\": attributes.description,\n }),\n },\n }\n },\n})\n","import { AlertTriangle, LoaderCircle } from \"lucide-react\"\nimport { cn } from \"../../lib/utils\"\nimport { useConnectionStore } from \"../../stores/connection-store\"\n\nfunction getBannerCopy(\n status: \"connecting\" | \"connected\" | \"disconnected\",\n reconnectAttempt: number,\n hasEverConnected: boolean,\n) {\n if (status === \"connecting\") {\n return {\n icon: <LoaderCircle size={14} className=\"animate-spin\" />,\n toneClass:\n \"border-amber-500/25 bg-amber-500/10 text-amber-100\",\n title: \"连接已断开,正在重连…\",\n detail:\n reconnectAttempt > 0\n ? `正在尝试恢复实时连接(第 ${reconnectAttempt} 次)`\n : \"正在尝试恢复实时连接,请稍候\",\n }\n }\n\n return {\n icon: <AlertTriangle size={14} />,\n toneClass: \"border-rose-500/25 bg-rose-500/10 text-rose-100\",\n title: hasEverConnected ? \"连接已断开,正在等待重连…\" : \"暂时无法建立连接\",\n detail: hasEverConnected\n ? \"消息同步可能会延迟,系统会继续自动重试\"\n : \"请检查服务是否可用,系统会继续自动重试\",\n }\n}\n\nexport function ConnectionBanner() {\n const status = useConnectionStore((state) => state.status)\n const reconnectAttempt = useConnectionStore((state) => state.reconnectAttempt)\n const hasEverConnected = useConnectionStore((state) => state.hasEverConnected)\n const lastDisconnectedAt = useConnectionStore((state) => state.lastDisconnectedAt)\n\n if (\n status === \"connected\" ||\n (!hasEverConnected && lastDisconnectedAt == null)\n ) {\n return null\n }\n\n const copy = getBannerCopy(status, reconnectAttempt, hasEverConnected)\n\n return (\n <div className=\"bg-[hsl(var(--background))] px-5 pt-3\">\n <div\n className={cn(\n \"mx-auto flex max-w-3xl items-start gap-3 rounded-2xl border px-4 py-3\",\n copy.toneClass,\n )}\n >\n <span className=\"mt-0.5 shrink-0\">{copy.icon}</span>\n <div className=\"min-w-0\">\n <div className=\"text-sm font-medium\">{copy.title}</div>\n <div className=\"text-xs opacity-80\">{copy.detail}</div>\n </div>\n </div>\n </div>\n )\n}\n","import { ChevronDown, Lightbulb, MessageSquare } from \"lucide-react\"\nimport {\n useCallback,\n useEffect,\n useEffectEvent,\n useMemo,\n useRef,\n useState,\n} from \"react\"\nimport { StickToBottom, useStickToBottomContext } from \"use-stick-to-bottom\"\nimport { contentPreview, isHiddenInternalMessage } from \"../../lib/chat\"\nimport type { ChatMessage } from \"../../schemas/message\"\nimport { useChatStore } from \"../../stores/chat-store\"\nimport { PlanSummaryCard } from \"../plan/PlanSummaryCard\"\nimport { extractLatestPlanMessages } from \"../plan/extract-plan-messages\"\nimport type { AskUserAnswerData } from \"./AskUserQuestionBlock\"\nimport { AssistantTurnBlock } from \"./AssistantTurnBlock\"\nimport { CompactionCard } from \"./CompactionCard\"\nimport { RenderErrorBoundary } from \"./RenderErrorBoundary\"\nimport { StickyStatusBar } from \"./StickyStatusBar\"\nimport { TurnNavRail, type TurnNavItem } from \"./TurnNavRail\"\nimport {\n ErrorMessageBlock,\n UserMessageBubble,\n isErrorMessage,\n isUserMessage,\n} from \"./UserMessageBubble\"\nimport { formatToolName } from \"./display-utils\"\nimport type { ChatViewCustomization } from \"./customization\"\n\ntype AssistantTurnRenderBlock = {\n type: \"assistant_turn\"\n messages: ChatMessage[]\n key: string\n anchorId: string\n isStreaming: boolean\n railTitle: string\n}\n\ntype RenderBlock =\n | { type: \"message\"; message: ChatMessage; key: string }\n | AssistantTurnRenderBlock\n | { type: \"compaction\"; message: ChatMessage; key: string }\n | { type: \"planning_divider\"; kind: \"planning_enter\" | \"planning_exit\"; key: string }\n\nfunction parseModeChange(message: ChatMessage): { from: string; to: string } | null {\n if (message.kind !== \"mode_change\" || typeof message.content !== \"string\") {\n return null\n }\n try {\n const parsed = JSON.parse(message.content) as { from?: unknown; to?: unknown }\n if (typeof parsed.from === \"string\" && typeof parsed.to === \"string\") {\n return { from: parsed.from, to: parsed.to }\n }\n } catch {}\n return null\n}\n\nfunction getPlanningDividerKind(message: ChatMessage): \"planning_enter\" | \"planning_exit\" | null {\n if (message.kind === \"planning_enter\" || message.kind === \"planning_exit\") {\n return message.kind\n }\n const modeChange = parseModeChange(message)\n if (modeChange?.to === \"planning\") {\n return \"planning_enter\"\n }\n if (modeChange?.from === \"planning\") {\n return \"planning_exit\"\n }\n return null\n}\n\nfunction getMessagePreview(message: ChatMessage) {\n return contentPreview(message.content, 42)\n}\n\nfunction getAssistantTurnPreview(messages: ChatMessage[]) {\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n const preview = getMessagePreview(messages[index])\n if (preview) {\n return preview\n }\n }\n return \"本轮回复\"\n}\n\nfunction getMessageMeasureSignature(message: ChatMessage) {\n const contentSize =\n typeof message.content === \"string\"\n ? message.content.length\n : message.content.reduce((size, part) => size + JSON.stringify(part).length, 0)\n\n return [\n message.entry_id ?? message.timestamp ?? message.role,\n message.status ?? \"\",\n message.reasoning?.length ?? 0,\n message.tool_calls?.length ?? 0,\n contentSize,\n ].join(\":\")\n}\n\nfunction getMessagesMeasureSignature(messages: ChatMessage[]) {\n return messages.map((message) => getMessageMeasureSignature(message)).join(\"|\")\n}\n\nfunction safeJson(value: unknown) {\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n}\n\nfunction hashString(value: string) {\n let hash = 0\n for (let index = 0; index < value.length; index += 1) {\n hash = (hash * 31 + value.charCodeAt(index)) | 0\n }\n return hash.toString(36)\n}\n\nfunction getMessageRenderSignature(message: ChatMessage) {\n return [\n message.entry_id ?? message.timestamp ?? message.role,\n message.status ?? \"\",\n hashString(safeJson(message.content)),\n hashString(message.reasoning ?? \"\"),\n hashString(safeJson(message.tool_calls ?? [])),\n hashString(safeJson(message.blocks ?? [])),\n hashString(safeJson(message.memory_refs ?? [])),\n ].join(\":\")\n}\n\nfunction getMessagesRenderSignature(messages: ChatMessage[]) {\n return messages.map((message) => getMessageRenderSignature(message)).join(\"|\")\n}\n\nfunction findScrollContainer(start: HTMLElement | null) {\n let current = start\n while (current) {\n const overflowY = getComputedStyle(current).overflowY\n if (overflowY === \"auto\" || overflowY === \"scroll\") {\n return current\n }\n current = current.parentElement\n }\n return null\n}\n\ninterface Props {\n sessionId: string\n messages: ChatMessage[]\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n sessionStatus?: string\n onConfirmPlan?: (action: \"execute\" | \"revise\", text?: string) => void\n customization?: ChatViewCustomization\n}\n\nexport function MessageList({\n sessionId,\n messages: rawMessages,\n onAnswer,\n sessionStatus,\n onConfirmPlan,\n customization,\n}: Props) {\n const messages = Array.isArray(rawMessages) ? rawMessages : []\n const agentLoops = useChatStore((state) => state.agentLoops[sessionId])\n const askAnswers = useChatStore((state) => state.askAnswers[sessionId])\n const agentLoopNameSet = useMemo(() => new Set(Object.keys(agentLoops ?? {})), [agentLoops])\n\n const renderBlocks = useMemo(() => {\n const visible = messages.filter((message) => {\n const loopName = message.loop_name ?? \"root\"\n if (loopName !== \"root\") return false\n if (agentLoopNameSet.has(loopName)) return false\n if (isHiddenInternalMessage(message)) return false\n if (message.kind === \"compaction\") return true\n return message.role !== \"tool\" || getPlanningDividerKind(message) !== null\n })\n\n const blocks: RenderBlock[] = []\n let assistantBuffer: ChatMessage[] = []\n let assistantTurnCount = 0\n let lastUserPreview = \"\"\n\n const flushAssistant = () => {\n if (assistantBuffer.length === 0) return\n\n assistantTurnCount += 1\n const last = assistantBuffer[assistantBuffer.length - 1]\n const isStreaming = assistantBuffer.some((message) => message.status === \"streaming\")\n\n blocks.push({\n type: \"assistant_turn\",\n messages: assistantBuffer,\n key: last.entry_id ?? `assistant-${blocks.length}`,\n anchorId: `chat-turn-${assistantTurnCount}`,\n isStreaming,\n railTitle: lastUserPreview || getAssistantTurnPreview(assistantBuffer),\n })\n assistantBuffer = []\n }\n\n for (const message of visible) {\n const dividerKind = getPlanningDividerKind(message)\n if (dividerKind) {\n flushAssistant()\n blocks.push({\n type: \"planning_divider\",\n kind: dividerKind,\n key: message.entry_id ?? `${dividerKind}-${blocks.length}`,\n })\n continue\n }\n\n if (message.kind === \"compaction\") {\n flushAssistant()\n blocks.push({\n type: \"compaction\",\n message,\n key: message.entry_id ?? `compaction-${blocks.length}`,\n })\n continue\n }\n\n if (message.role === \"assistant\") {\n assistantBuffer.push(message)\n continue\n }\n\n flushAssistant()\n if (isUserMessage(message)) {\n lastUserPreview = getMessagePreview(message)\n }\n blocks.push({\n type: \"message\",\n message,\n key: message.entry_id ?? `${message.role}-${blocks.length}`,\n })\n }\n\n flushAssistant()\n\n return blocks\n }, [agentLoopNameSet, messages])\n\n const hasInterruptedTurn = useMemo(\n () =>\n renderBlocks.some(\n (block) =>\n block.type === \"assistant_turn\" &&\n block.messages.some((message) => message.status === \"interrupted\"),\n ),\n [renderBlocks],\n )\n\n const lastTurnId = useMemo(() => {\n for (let index = renderBlocks.length - 1; index >= 0; index -= 1) {\n const block = renderBlocks[index]\n if (block.type === \"assistant_turn\") return block.anchorId\n if (block.type === \"message\" && isUserMessage(block.message)) return null\n }\n return null\n }, [renderBlocks])\n\n const turnNavItems = useMemo<TurnNavItem[]>(\n () =>\n renderBlocks\n .filter((block): block is AssistantTurnRenderBlock => block.type === \"assistant_turn\")\n .map((block) => ({\n id: block.anchorId,\n title: block.railTitle,\n })),\n [renderBlocks],\n )\n\n const stickyTurn = useMemo(\n () =>\n renderBlocks.find(\n (block): block is AssistantTurnRenderBlock =>\n block.type === \"assistant_turn\" &&\n block.anchorId === lastTurnId &&\n block.isStreaming,\n ) ?? null,\n [lastTurnId, renderBlocks],\n )\n\n const containerRef = useRef<HTMLDivElement>(null)\n const scrollContainerRef = useRef<HTMLElement | null>(null)\n const frameRef = useRef<number | null>(null)\n const [activeTurnId, setActiveTurnId] = useState<string | null>(lastTurnId)\n\n const layoutSignature = useMemo(\n () => getMessagesMeasureSignature(messages),\n [messages],\n )\n\n const measureActiveTurn = useEffectEvent(() => {\n const container = scrollContainerRef.current\n const root = containerRef.current\n if (!container || !root) {\n setActiveTurnId(lastTurnId)\n return\n }\n const turnElements = Array.from(root.querySelectorAll<HTMLElement>(\"[data-turn-id]\"))\n if (turnElements.length === 0) {\n setActiveTurnId(lastTurnId)\n return\n }\n const containerRect = container.getBoundingClientRect()\n const targetY = containerRect.top + containerRect.height * 0.15\n let bestId = lastTurnId\n let bestDistance = Number.POSITIVE_INFINITY\n for (const el of turnElements) {\n const rect = el.getBoundingClientRect()\n if (rect.bottom < containerRect.top || rect.top > containerRect.bottom) continue\n const turnId = el.dataset.turnId\n if (!turnId) continue\n const distance = Math.abs(rect.top - targetY)\n if (distance < bestDistance) {\n bestDistance = distance\n bestId = turnId\n }\n }\n setActiveTurnId(bestId)\n })\n\n const scheduleMeasure = useEffectEvent(() => {\n if (frameRef.current != null) return\n frameRef.current = window.requestAnimationFrame(() => {\n frameRef.current = null\n measureActiveTurn()\n })\n })\n\n useEffect(() => {\n scrollContainerRef.current = findScrollContainer(containerRef.current)\n const sc = scrollContainerRef.current\n if (!sc) return\n sc.addEventListener(\"scroll\", scheduleMeasure, { passive: true })\n window.addEventListener(\"resize\", scheduleMeasure)\n scheduleMeasure()\n return () => {\n sc.removeEventListener(\"scroll\", scheduleMeasure)\n window.removeEventListener(\"resize\", scheduleMeasure)\n if (frameRef.current != null) {\n window.cancelAnimationFrame(frameRef.current)\n frameRef.current = null\n }\n }\n }, [scheduleMeasure])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: lastTurnId and layoutSignature are intentional triggers to re-measure\n useEffect(() => {\n scheduleMeasure()\n }, [lastTurnId, layoutSignature, scheduleMeasure])\n\n const handleSelectTurn = useCallback((turnId: string) => {\n document.getElementById(turnId)?.scrollIntoView({ behavior: \"smooth\", block: \"start\" })\n }, [])\n\n return (\n <div\n ref={containerRef}\n className={`relative min-h-0 flex-1 ${customization?.classNames?.messageListRoot ?? \"\"}`}\n >\n {turnNavItems.length > 1 ? (\n <TurnNavRail\n items={turnNavItems}\n activeTurnId={activeTurnId ?? lastTurnId}\n onSelectTurn={handleSelectTurn}\n />\n ) : null}\n <StickToBottom className=\"h-full overflow-y-hidden\" resize=\"smooth\">\n <StickToBottom.Content className=\"px-5 py-6\">\n <MessageListContent\n askAnswers={askAnswers}\n hasInterruptedTurn={hasInterruptedTurn}\n lastTurnId={lastTurnId}\n layoutSignature={layoutSignature}\n messages={messages}\n onAnswer={onAnswer}\n onConfirmPlan={onConfirmPlan}\n renderBlocks={renderBlocks}\n sessionId={sessionId}\n sessionStatus={sessionStatus}\n stickyTurn={stickyTurn}\n customization={customization}\n />\n </StickToBottom.Content>\n <ScrollToBottomButton />\n </StickToBottom>\n </div>\n )\n}\n\nfunction MessageListContent({\n askAnswers,\n hasInterruptedTurn,\n lastTurnId,\n layoutSignature,\n messages,\n onAnswer,\n onConfirmPlan,\n renderBlocks,\n sessionId,\n sessionStatus,\n stickyTurn,\n customization,\n}: {\n askAnswers?: Record<string, AskUserAnswerData>\n hasInterruptedTurn: boolean\n lastTurnId: string | null\n layoutSignature: string\n messages: ChatMessage[]\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n onConfirmPlan?: (action: \"execute\" | \"revise\", text?: string) => void\n renderBlocks: RenderBlock[]\n sessionId: string\n sessionStatus?: string\n stickyTurn: AssistantTurnRenderBlock | null\n customization?: ChatViewCustomization\n}) {\n const { scrollToBottom } = useStickToBottomContext()\n\n const handleJumpToLatest = useCallback(() => {\n if (lastTurnId) {\n document.getElementById(lastTurnId)?.scrollIntoView({ behavior: \"smooth\", block: \"end\" })\n return\n }\n scrollToBottom()\n }, [lastTurnId, scrollToBottom])\n\n return (\n <div className={`mx-auto max-w-3xl ${customization?.classNames?.messageListContent ?? \"\"}`}>\n <div className={`min-w-0 flex flex-col gap-8 ${customization?.classNames?.messageListInner ?? \"\"}`}>\n {stickyTurn ? (\n <StickyStatusBar\n sessionId={sessionId}\n messages={stickyTurn.messages}\n isLastTurn={stickyTurn.anchorId === lastTurnId}\n isStreaming={stickyTurn.isStreaming}\n onJumpToLatest={handleJumpToLatest}\n />\n ) : null}\n\n {renderBlocks.length === 0 ? (\n customization?.components?.EmptyState ? (\n <customization.components.EmptyState />\n ) : (\n <div className={`flex flex-col items-center justify-center gap-3 py-24 text-[hsl(var(--muted-foreground))] ${customization?.classNames?.emptyState ?? \"\"}`}>\n <MessageSquare size={40} strokeWidth={1.5} />\n <span className=\"text-base font-medium\">开始对话</span>\n <span className=\"text-sm opacity-60\">在下方输入消息开始聊天</span>\n </div>\n )\n ) : (\n renderBlocks.map((block, blockIndex) => {\n if (block.type === \"message\") {\n return (\n <div key={block.key} className=\"msg-animate\">\n {isUserMessage(block.message) ? (\n customization?.components?.UserMessage ? (\n <customization.components.UserMessage\n message={block.message}\n className={customization.classNames?.userMessage}\n />\n ) : (\n <UserMessageBubble\n message={block.message}\n className={customization?.classNames?.userMessage}\n />\n )\n ) : isErrorMessage(block.message) ? (\n customization?.components?.ErrorMessage ? (\n <customization.components.ErrorMessage\n message={block.message}\n className={customization.classNames?.errorMessage}\n />\n ) : (\n <ErrorMessageBlock\n message={block.message}\n className={customization?.classNames?.errorMessage}\n />\n )\n ) : null}\n </div>\n )\n }\n\n if (block.type === \"assistant_turn\") {\n const nextBlock = renderBlocks[blockIndex + 1]\n const hasExitPlan = block.messages.some((message) =>\n message.tool_calls?.some(\n (toolCall) =>\n formatToolName(toolCall.name) === \"ExitPlanMode\" &&\n toolCall.status !== \"error\" &&\n toolCall.status !== \"cancelled\",\n ),\n )\n const isFollowedByPlanningExit =\n nextBlock?.type === \"planning_divider\" && nextBlock.kind === \"planning_exit\"\n const showPlanCard =\n (hasExitPlan || isFollowedByPlanningExit) &&\n onConfirmPlan &&\n sessionStatus === \"waiting_for_input\"\n\n return (\n <div\n key={block.key}\n id={block.anchorId}\n data-turn-id={block.anchorId}\n className=\"msg-animate flex scroll-mt-6 flex-col gap-4\"\n >\n <RenderErrorBoundary\n label=\"助手消息\"\n details={block.key}\n resetKey={getMessagesRenderSignature(block.messages)}\n >\n {customization?.components?.AssistantTurn ? (\n <customization.components.AssistantTurn\n turnKey={block.key}\n sessionId={sessionId}\n messages={block.messages}\n isStreaming={block.isStreaming}\n isLastTurn={block.anchorId === lastTurnId}\n askAnswers={askAnswers}\n onAnswer={onAnswer}\n sessionStatus={sessionStatus}\n customization={customization}\n />\n ) : (\n <AssistantTurnBlock\n turnKey={block.key}\n sessionId={sessionId}\n messages={block.messages}\n isStreaming={block.isStreaming}\n isLastTurn={block.anchorId === lastTurnId}\n askAnswers={askAnswers}\n onAnswer={onAnswer}\n sessionStatus={sessionStatus}\n customization={customization}\n />\n )}\n </RenderErrorBoundary>\n {showPlanCard ? (\n <RenderErrorBoundary\n label=\"规划摘要\"\n details={block.key}\n resetKey={`${sessionStatus ?? \"\"}:${layoutSignature}`}\n >\n <PlanSummaryCard\n messages={extractLatestPlanMessages(messages)}\n sessionStatus={sessionStatus}\n onConfirmPlan={onConfirmPlan}\n />\n </RenderErrorBoundary>\n ) : null}\n </div>\n )\n }\n\n if (block.type === \"compaction\") {\n return (\n <div key={block.key} className=\"msg-animate\">\n <CompactionCard\n sessionId={sessionId}\n compaction={block.message.compaction}\n status={block.message.status}\n />\n </div>\n )\n }\n\n return <PlanningDivider key={block.key} kind={block.kind} />\n })\n )}\n\n {sessionStatus === \"interrupted\" && !hasInterruptedTurn ? (\n <div className=\"flex\">\n <div className=\"rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300\">\n 已中断\n </div>\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\nfunction ScrollToBottomButton() {\n const { isAtBottom, scrollToBottom } = useStickToBottomContext()\n if (isAtBottom) return null\n\n return (\n <button\n type=\"button\"\n onClick={() => scrollToBottom()}\n className=\"absolute bottom-4 right-4 flex items-center gap-1 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-1.5 text-xs text-[hsl(var(--muted-foreground))] shadow-lg transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <ChevronDown size={14} />\n <span>滚动到底部</span>\n </button>\n )\n}\n\nfunction PlanningDivider({ kind }: { kind: \"planning_enter\" | \"planning_exit\" }) {\n const isEnter = kind === \"planning_enter\"\n\n return (\n <div className=\"flex items-center gap-3 py-1\">\n <div className=\"h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent\" />\n <div className=\"inline-flex items-center gap-1.5 rounded-full border border-amber-500/30 bg-amber-500/10 px-3 py-1 text-[11px] text-amber-300\">\n <Lightbulb size={12} />\n <span>{isEnter ? \"进入规划模式\" : \"规划完成\"}</span>\n </div>\n <div className=\"h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent\" />\n </div>\n )\n}\n","/*!---------------------------------------------------------------------------------------------\n * Copyright (c) StackBlitz. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\nimport { useCallback, useMemo, useRef, useState, } from \"react\";\nconst DEFAULT_SPRING_ANIMATION = {\n /**\n * A value from 0 to 1, on how much to damp the animation.\n * 0 means no damping, 1 means full damping.\n *\n * @default 0.7\n */\n damping: 0.7,\n /**\n * The stiffness of how fast/slow the animation gets up to speed.\n *\n * @default 0.05\n */\n stiffness: 0.05,\n /**\n * The inertial mass associated with the animation.\n * Higher numbers make the animation slower.\n *\n * @default 1.25\n */\n mass: 1.25,\n};\nconst STICK_TO_BOTTOM_OFFSET_PX = 70;\nconst SIXTY_FPS_INTERVAL_MS = 1000 / 60;\nconst RETAIN_ANIMATION_DURATION_MS = 350;\nlet mouseDown = false;\nglobalThis.document?.addEventListener(\"mousedown\", () => {\n mouseDown = true;\n});\nglobalThis.document?.addEventListener(\"mouseup\", () => {\n mouseDown = false;\n});\nglobalThis.document?.addEventListener(\"click\", () => {\n mouseDown = false;\n});\nexport const useStickToBottom = (options = {}) => {\n const [escapedFromLock, updateEscapedFromLock] = useState(false);\n const [isAtBottom, updateIsAtBottom] = useState(options.initial !== false);\n const [isNearBottom, setIsNearBottom] = useState(false);\n const optionsRef = useRef(null);\n optionsRef.current = options;\n const isSelecting = useCallback(() => {\n if (!mouseDown) {\n return false;\n }\n const selection = window.getSelection();\n if (!selection || !selection.rangeCount) {\n return false;\n }\n const range = selection.getRangeAt(0);\n return (range.commonAncestorContainer.contains(scrollRef.current) ||\n scrollRef.current?.contains(range.commonAncestorContainer));\n }, []);\n const setIsAtBottom = useCallback((isAtBottom) => {\n state.isAtBottom = isAtBottom;\n updateIsAtBottom(isAtBottom);\n }, []);\n const setEscapedFromLock = useCallback((escapedFromLock) => {\n state.escapedFromLock = escapedFromLock;\n updateEscapedFromLock(escapedFromLock);\n }, []);\n // biome-ignore lint/correctness/useExhaustiveDependencies: not needed\n const state = useMemo(() => {\n let lastCalculation;\n return {\n escapedFromLock,\n isAtBottom,\n resizeDifference: 0,\n accumulated: 0,\n velocity: 0,\n listeners: new Set(),\n get scrollTop() {\n return scrollRef.current?.scrollTop ?? 0;\n },\n set scrollTop(scrollTop) {\n if (scrollRef.current) {\n scrollRef.current.scrollTop = scrollTop;\n state.ignoreScrollToTop = scrollRef.current.scrollTop;\n }\n },\n get targetScrollTop() {\n if (!scrollRef.current || !contentRef.current) {\n return 0;\n }\n return (scrollRef.current.scrollHeight - 1 - scrollRef.current.clientHeight);\n },\n get calculatedTargetScrollTop() {\n if (!scrollRef.current || !contentRef.current) {\n return 0;\n }\n const { targetScrollTop } = this;\n if (!options.targetScrollTop) {\n return targetScrollTop;\n }\n if (lastCalculation?.targetScrollTop === targetScrollTop) {\n return lastCalculation.calculatedScrollTop;\n }\n const calculatedScrollTop = Math.max(Math.min(options.targetScrollTop(targetScrollTop, {\n scrollElement: scrollRef.current,\n contentElement: contentRef.current,\n }), targetScrollTop), 0);\n lastCalculation = { targetScrollTop, calculatedScrollTop };\n requestAnimationFrame(() => {\n lastCalculation = undefined;\n });\n return calculatedScrollTop;\n },\n get scrollDifference() {\n return this.calculatedTargetScrollTop - this.scrollTop;\n },\n get isNearBottom() {\n return this.scrollDifference <= STICK_TO_BOTTOM_OFFSET_PX;\n },\n };\n }, []);\n const scrollToBottom = useCallback((scrollOptions = {}) => {\n if (typeof scrollOptions === \"string\") {\n scrollOptions = { animation: scrollOptions };\n }\n if (!scrollOptions.preserveScrollPosition) {\n setIsAtBottom(true);\n }\n const waitElapsed = Date.now() + (Number(scrollOptions.wait) || 0);\n const behavior = mergeAnimations(optionsRef.current, scrollOptions.animation);\n const { ignoreEscapes = false } = scrollOptions;\n let durationElapsed;\n let startTarget = state.calculatedTargetScrollTop;\n if (scrollOptions.duration instanceof Promise) {\n scrollOptions.duration.finally(() => {\n durationElapsed = Date.now();\n });\n }\n else {\n durationElapsed = waitElapsed + (scrollOptions.duration ?? 0);\n }\n const next = async () => {\n const promise = new Promise(requestAnimationFrame).then(() => {\n if (!state.isAtBottom) {\n state.animation = undefined;\n return false;\n }\n const { scrollTop } = state;\n const tick = performance.now();\n const tickDelta = (tick - (state.lastTick ?? tick)) / SIXTY_FPS_INTERVAL_MS;\n state.animation || (state.animation = { behavior, promise, ignoreEscapes });\n if (state.animation.behavior === behavior) {\n state.lastTick = tick;\n }\n if (isSelecting()) {\n return next();\n }\n if (waitElapsed > Date.now()) {\n return next();\n }\n if (scrollTop < Math.min(startTarget, state.calculatedTargetScrollTop)) {\n if (state.animation?.behavior === behavior) {\n if (behavior === \"instant\") {\n state.scrollTop = state.calculatedTargetScrollTop;\n return next();\n }\n state.velocity =\n (behavior.damping * state.velocity +\n behavior.stiffness * state.scrollDifference) /\n behavior.mass;\n state.accumulated += state.velocity * tickDelta;\n state.scrollTop += state.accumulated;\n if (state.scrollTop !== scrollTop) {\n state.accumulated = 0;\n }\n }\n return next();\n }\n if (durationElapsed > Date.now()) {\n startTarget = state.calculatedTargetScrollTop;\n return next();\n }\n state.animation = undefined;\n /**\n * If we're still below the target, then queue\n * up another scroll to the bottom with the last\n * requested animatino.\n */\n if (state.scrollTop < state.calculatedTargetScrollTop) {\n return scrollToBottom({\n animation: mergeAnimations(optionsRef.current, optionsRef.current.resize),\n ignoreEscapes,\n duration: Math.max(0, durationElapsed - Date.now()) || undefined,\n });\n }\n return state.isAtBottom;\n });\n return promise.then((isAtBottom) => {\n requestAnimationFrame(() => {\n if (!state.animation) {\n state.lastTick = undefined;\n state.velocity = 0;\n }\n });\n return isAtBottom;\n });\n };\n if (scrollOptions.wait !== true) {\n state.animation = undefined;\n }\n if (state.animation?.behavior === behavior) {\n return state.animation.promise;\n }\n return next();\n }, [setIsAtBottom, isSelecting, state]);\n const stopScroll = useCallback(() => {\n setEscapedFromLock(true);\n setIsAtBottom(false);\n }, [setEscapedFromLock, setIsAtBottom]);\n const handleScroll = useCallback(({ target }) => {\n if (target !== scrollRef.current) {\n return;\n }\n const { scrollTop, ignoreScrollToTop } = state;\n let { lastScrollTop = scrollTop } = state;\n state.lastScrollTop = scrollTop;\n state.ignoreScrollToTop = undefined;\n if (ignoreScrollToTop && ignoreScrollToTop > scrollTop) {\n /**\n * When the user scrolls up while the animation plays, the `scrollTop` may\n * not come in separate events; if this happens, to make sure `isScrollingUp`\n * is correct, set the lastScrollTop to the ignored event.\n */\n lastScrollTop = ignoreScrollToTop;\n }\n setIsNearBottom(state.isNearBottom);\n /**\n * Scroll events may come before a ResizeObserver event,\n * so in order to ignore resize events correctly we use a\n * timeout.\n *\n * @see https://github.com/WICG/resize-observer/issues/25#issuecomment-248757228\n */\n setTimeout(() => {\n /**\n * When theres a resize difference ignore the resize event.\n */\n if (state.resizeDifference || scrollTop === ignoreScrollToTop) {\n return;\n }\n if (isSelecting()) {\n setEscapedFromLock(true);\n setIsAtBottom(false);\n return;\n }\n const isScrollingDown = scrollTop > lastScrollTop;\n const isScrollingUp = scrollTop < lastScrollTop;\n if (state.animation?.ignoreEscapes) {\n state.scrollTop = lastScrollTop;\n return;\n }\n if (isScrollingUp) {\n setEscapedFromLock(true);\n setIsAtBottom(false);\n }\n if (isScrollingDown) {\n setEscapedFromLock(false);\n }\n if (!state.escapedFromLock && state.isNearBottom) {\n setIsAtBottom(true);\n }\n }, 1);\n }, [setEscapedFromLock, setIsAtBottom, isSelecting, state]);\n const handleWheel = useCallback(({ target, deltaY }) => {\n let element = target;\n while (![\"scroll\", \"auto\"].includes(getComputedStyle(element).overflow)) {\n if (!element.parentElement) {\n return;\n }\n element = element.parentElement;\n }\n /**\n * The browser may cancel the scrolling from the mouse wheel\n * if we update it from the animation in meantime.\n * To prevent this, always escape when the wheel is scrolled up.\n */\n if (element === scrollRef.current &&\n deltaY < 0 &&\n scrollRef.current.scrollHeight > scrollRef.current.clientHeight &&\n !state.animation?.ignoreEscapes) {\n setEscapedFromLock(true);\n setIsAtBottom(false);\n }\n }, [setEscapedFromLock, setIsAtBottom, state]);\n const scrollRef = useRefCallback((scroll) => {\n scrollRef.current?.removeEventListener(\"scroll\", handleScroll);\n scrollRef.current?.removeEventListener(\"wheel\", handleWheel);\n scroll?.addEventListener(\"scroll\", handleScroll, { passive: true });\n scroll?.addEventListener(\"wheel\", handleWheel, { passive: true });\n }, []);\n const contentRef = useRefCallback((content) => {\n state.resizeObserver?.disconnect();\n if (!content) {\n return;\n }\n let previousHeight;\n state.resizeObserver = new ResizeObserver(([entry]) => {\n const { height } = entry.contentRect;\n const difference = height - (previousHeight ?? height);\n state.resizeDifference = difference;\n /**\n * Sometimes the browser can overscroll past the target,\n * so check for this and adjust appropriately.\n */\n if (state.scrollTop > state.targetScrollTop) {\n state.scrollTop = state.targetScrollTop;\n }\n setIsNearBottom(state.isNearBottom);\n if (difference >= 0) {\n /**\n * If it's a positive resize, scroll to the bottom when\n * we're already at the bottom.\n */\n const animation = mergeAnimations(optionsRef.current, previousHeight\n ? optionsRef.current.resize\n : optionsRef.current.initial);\n scrollToBottom({\n animation,\n wait: true,\n preserveScrollPosition: true,\n duration: animation === \"instant\" ? undefined : RETAIN_ANIMATION_DURATION_MS,\n });\n }\n else {\n /**\n * Else if it's a negative resize, check if we're near the bottom\n * if we are want to un-escape from the lock, because the resize\n * could have caused the container to be at the bottom.\n */\n if (state.isNearBottom) {\n setEscapedFromLock(false);\n setIsAtBottom(true);\n }\n }\n previousHeight = height;\n /**\n * Reset the resize difference after the scroll event\n * has fired. Requires a rAF to wait for the scroll event,\n * and a setTimeout to wait for the other timeout we have in\n * resizeObserver in case the scroll event happens after the\n * resize event.\n */\n requestAnimationFrame(() => {\n setTimeout(() => {\n if (state.resizeDifference === difference) {\n state.resizeDifference = 0;\n }\n }, 1);\n });\n });\n state.resizeObserver?.observe(content);\n }, []);\n return {\n contentRef,\n scrollRef,\n scrollToBottom,\n stopScroll,\n isAtBottom: isAtBottom || isNearBottom,\n isNearBottom,\n escapedFromLock,\n state,\n };\n};\nfunction useRefCallback(callback, deps) {\n // biome-ignore lint/correctness/useExhaustiveDependencies: not needed\n const result = useCallback((ref) => {\n result.current = ref;\n return callback(ref);\n }, deps);\n return result;\n}\nconst animationCache = new Map();\nfunction mergeAnimations(...animations) {\n const result = { ...DEFAULT_SPRING_ANIMATION };\n let instant = false;\n for (const animation of animations) {\n if (animation === \"instant\") {\n instant = true;\n continue;\n }\n if (typeof animation !== \"object\") {\n continue;\n }\n instant = false;\n result.damping = animation.damping ?? result.damping;\n result.stiffness = animation.stiffness ?? result.stiffness;\n result.mass = animation.mass ?? result.mass;\n }\n const key = JSON.stringify(result);\n if (!animationCache.has(key)) {\n animationCache.set(key, Object.freeze(result));\n }\n return instant ? \"instant\" : animationCache.get(key);\n}\n","/*!---------------------------------------------------------------------------------------------\n * Copyright (c) StackBlitz. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\nimport * as React from \"react\";\nimport { createContext, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, } from \"react\";\nimport { useStickToBottom, } from \"./useStickToBottom.js\";\nconst StickToBottomContext = createContext(null);\nconst useIsomorphicLayoutEffect = typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\nexport function StickToBottom({ instance, children, resize, initial, mass, damping, stiffness, targetScrollTop: currentTargetScrollTop, contextRef, ...props }) {\n const customTargetScrollTop = useRef(null);\n const targetScrollTop = React.useCallback((target, elements) => {\n const get = context?.targetScrollTop ?? currentTargetScrollTop;\n return get?.(target, elements) ?? target;\n }, [currentTargetScrollTop]);\n const defaultInstance = useStickToBottom({\n mass,\n damping,\n stiffness,\n resize,\n initial,\n targetScrollTop,\n });\n const { scrollRef, contentRef, scrollToBottom, stopScroll, isAtBottom, escapedFromLock, state, } = instance ?? defaultInstance;\n const context = useMemo(() => ({\n scrollToBottom,\n stopScroll,\n scrollRef,\n isAtBottom,\n escapedFromLock,\n contentRef,\n state,\n get targetScrollTop() {\n return customTargetScrollTop.current;\n },\n set targetScrollTop(targetScrollTop) {\n customTargetScrollTop.current = targetScrollTop;\n },\n }), [\n scrollToBottom,\n isAtBottom,\n contentRef,\n scrollRef,\n stopScroll,\n escapedFromLock,\n state,\n ]);\n useImperativeHandle(contextRef, () => context, [context]);\n useIsomorphicLayoutEffect(() => {\n if (!scrollRef.current) {\n return;\n }\n if (getComputedStyle(scrollRef.current).overflow === \"visible\") {\n scrollRef.current.style.overflow = \"auto\";\n }\n }, []);\n return (React.createElement(StickToBottomContext.Provider, { value: context },\n React.createElement(\"div\", { ...props }, typeof children === \"function\" ? children(context) : children)));\n}\n(function (StickToBottom) {\n function Content({ children, scrollClassName, ...props }) {\n const context = useStickToBottomContext();\n return (React.createElement(\"div\", { ref: context.scrollRef, style: {\n height: \"100%\",\n width: \"100%\",\n scrollbarGutter: \"stable both-edges\",\n }, className: scrollClassName },\n React.createElement(\"div\", { ...props, ref: context.contentRef }, typeof children === \"function\" ? children(context) : children)));\n }\n StickToBottom.Content = Content;\n})(StickToBottom || (StickToBottom = {}));\n/**\n * Use this hook inside a <StickToBottom> component to gain access to whether the component is at the bottom of the scrollable area.\n */\nexport function useStickToBottomContext() {\n const context = useContext(StickToBottomContext);\n if (!context) {\n throw new Error(\"use-stick-to-bottom component context must be used within a StickToBottom component\");\n }\n return context;\n}\n","import { AlertCircle, BookOpen, Check, ChevronRight } from \"lucide-react\"\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\nimport { getSocket } from \"../../api/socket\"\nimport { getFileParts, getImageParts } from \"../../lib/chat\"\nimport { isUiMeta } from \"../../lib/ui-meta\"\nimport { cn } from \"../../lib/utils\"\nimport { MEMORIES_ROUTE } from \"../../routes\"\nimport type { ChatMessage, MemoryRefInfo, ToolCallInfo } from \"../../schemas/message\"\nimport { useChatStore } from \"../../stores/chat-store\"\nimport {\n Reasoning,\n ReasoningContent,\n ReasoningTrigger,\n ThinkingBadge,\n} from \"../ai-elements/reasoning\"\nimport { CardContext, type CardContextValue } from \"../card/CardContext\"\nimport { MarkdownContent } from \"../markdown/MarkdownContent\"\nimport { AgentLoopBlock } from \"./AgentLoopBlock\"\nimport type { AskUserAnswerData } from \"./AskUserQuestionBlock\"\nimport { MessageFileAttachmentList } from \"./MessageFileAttachmentList\"\nimport { ResourceIframe } from \"./ResourceIframe\"\nimport { ToolCallBlock } from \"./ToolCallBlock\"\nimport type { ChatViewCustomization } from \"./customization\"\nimport {\n extractToolFilePath,\n formatToolName,\n} from \"./display-utils\"\n\ninterface Props {\n turnKey: string\n sessionId: string\n messages: ChatMessage[]\n isStreaming?: boolean\n isLastTurn?: boolean\n askAnswers?: Record<string, AskUserAnswerData>\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n sessionStatus?: string\n level?: 1 | 2\n forceExpanded?: boolean\n customization?: ChatViewCustomization\n}\n\nexport type TurnDisplayMode = \"compact\" | \"detail\"\n\n// 决定 turn 折叠状态的默认值:流式结束/历史加载时,有需关注的工具调用(错误、被取消、待回答)默认展开为详细模式\nexport function defaultTurnDisplayMode({\n forceExpanded,\n hasActionableToolCall,\n}: {\n forceExpanded: boolean\n hasActionableToolCall: boolean\n}): TurnDisplayMode {\n return forceExpanded || hasActionableToolCall ? \"detail\" : \"compact\"\n}\n\n// 实际渲染采用的模式:流式中强制详细,否则完全跟随用户的显式选择(不再被 hasActionableToolCall 反向锁死)\nexport function resolveTurnDisplayMode({\n isStreaming,\n displayMode,\n}: {\n isStreaming: boolean\n displayMode: TurnDisplayMode\n}): TurnDisplayMode {\n return isStreaming ? \"detail\" : displayMode\n}\n\nfunction getMessageText(message: ChatMessage) {\n return typeof message.content === \"string\"\n ? message.content.trim()\n : message.content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim()\n}\n\nfunction getLastTextMessage(messages: ChatMessage[]) {\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n if (getMessageText(messages[index])) {\n return messages[index]\n }\n }\n return null\n}\n\nfunction getInlineResourceBlocks(messages: ChatMessage[]) {\n return messages.flatMap((message) =>\n (message.blocks ?? []).flatMap((block, index) =>\n block.type === \"tool_ui\" &&\n block.tool_call_id &&\n isUiMeta(block.content) &&\n block.content.target === \"inline\"\n ? [\n {\n key: `${message.entry_id ?? message.timestamp ?? \"message\"}-${block.tool_call_id}-${index}`,\n ui: block.content,\n },\n ]\n : [],\n ),\n )\n}\n\ntype ToolRenderItem =\n | { key: string; kind: \"single\"; toolCall: ToolCallInfo }\n | { key: string; kind: \"read_group\"; toolCalls: ToolCallInfo[] }\n | { key: string; kind: \"load_skill_group\"; toolCalls: ToolCallInfo[] }\n\nfunction groupDetailedToolCalls(toolCalls: ToolCallInfo[]): ToolRenderItem[] {\n const items: ToolRenderItem[] = []\n let index = 0\n\n while (index < toolCalls.length) {\n const toolCall = toolCalls[index]\n const normalizedName = formatToolName(toolCall.name)\n if (normalizedName !== \"Read\" && normalizedName !== \"LoadSkillTools\") {\n items.push({ key: toolCall.id, kind: \"single\", toolCall })\n index += 1\n continue\n }\n\n const group = [toolCall]\n index += 1\n while (index < toolCalls.length && formatToolName(toolCalls[index].name) === normalizedName) {\n group.push(toolCalls[index])\n index += 1\n }\n\n const kind = normalizedName === \"Read\" ? \"read_group\" : \"load_skill_group\"\n items.push(\n group.length === 1 && normalizedName === \"Read\"\n ? { key: group[0].id, kind: \"single\", toolCall: group[0] }\n : {\n key: `${kind}-${group.map((item) => item.id).join(\"-\")}`,\n kind,\n toolCalls: group,\n },\n )\n }\n\n return items\n}\n\nfunction formatToolDuration(durationMs: number) {\n if (durationMs < 1000) return `${Math.round(durationMs)}ms`\n const seconds = durationMs / 1000\n if (seconds < 60) return `${seconds.toFixed(seconds >= 10 ? 0 : 1)}s`\n const minutes = Math.floor(seconds / 60)\n const remainingSeconds = Math.round(seconds % 60)\n return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`\n}\n\nfunction formatFileName(filePath: string) {\n return filePath.split(\"/\").pop() ?? filePath\n}\n\nfunction parseToolArguments(value: string | null | undefined): Record<string, unknown> | null {\n if (!value) return null\n try {\n const parsed = JSON.parse(value)\n return typeof parsed === \"object\" && parsed !== null && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : null\n } catch {\n return null\n }\n}\n\nfunction getLoadedSkillName(toolCall: ToolCallInfo) {\n const args = parseToolArguments(toolCall.arguments)\n const skillId = typeof args?.skill_id === \"string\" ? args.skill_id.trim() : \"\"\n if (skillId) return skillId\n const skillName = typeof args?.skill_name === \"string\" ? args.skill_name.trim() : \"\"\n return skillName || \"未知技能\"\n}\n\nfunction getAgentToolCallIds(messages: ChatMessage[]) {\n return new Set(\n messages\n .flatMap((message) => message.tool_calls ?? [])\n .filter((toolCall) => formatToolName(toolCall.name) === \"Agent\")\n .map((toolCall) => toolCall.id),\n )\n}\n\nfunction collectTurnMessages({\n rootMessages,\n sessionMessages,\n agentLoops,\n}: {\n rootMessages: ChatMessage[]\n sessionMessages: ChatMessage[]\n agentLoops: Record<string, { toolCallId: string }>\n}) {\n const collectedLoopNames = new Set<string>()\n const visitedToolCallIds = new Set<string>()\n let pendingToolCallIds = [...getAgentToolCallIds(rootMessages)]\n\n while (pendingToolCallIds.length > 0) {\n const currentIds = pendingToolCallIds\n pendingToolCallIds = []\n\n for (const [loopName, info] of Object.entries(agentLoops)) {\n if (collectedLoopNames.has(loopName) || visitedToolCallIds.has(info.toolCallId)) {\n continue\n }\n if (!currentIds.includes(info.toolCallId)) {\n continue\n }\n visitedToolCallIds.add(info.toolCallId)\n collectedLoopNames.add(loopName)\n const childMessages = sessionMessages.filter((message) => message.loop_name === loopName)\n pendingToolCallIds.push(...getAgentToolCallIds(childMessages))\n }\n }\n\n if (collectedLoopNames.size === 0) {\n return rootMessages\n }\n\n const rootIds = new Set(rootMessages.map((message) => message.entry_id).filter(Boolean))\n const childMessages = sessionMessages.filter(\n (message) =>\n message.loop_name &&\n collectedLoopNames.has(message.loop_name) &&\n (!message.entry_id || !rootIds.has(message.entry_id)),\n )\n const merged = [...rootMessages, ...childMessages]\n merged.sort((a, b) => {\n const ta = a.timestamp ?? \"\"\n const tb = b.timestamp ?? \"\"\n return ta < tb ? -1 : ta > tb ? 1 : 0\n })\n return merged\n}\n\nexport function AssistantTurnBlock({\n sessionId,\n messages: rawMessages,\n isStreaming = false,\n askAnswers,\n onAnswer,\n sessionStatus,\n level = 1,\n forceExpanded = false,\n customization,\n}: Props) {\n const messages = Array.isArray(rawMessages) ? rawMessages : []\n const allToolCalls = useMemo(() => messages.flatMap((m) => m.tool_calls ?? []), [messages])\n const hasActionableToolCall = useMemo(\n () =>\n allToolCalls.some(\n (tc) =>\n tc.status === \"error\" ||\n tc.status === \"cancelled\" ||\n (formatToolName(tc.name) === \"AskUserQuestion\" && tc.status === \"awaiting_answer\"),\n ),\n [allToolCalls],\n )\n const [displayMode, setDisplayMode] = useState<TurnDisplayMode>(\n defaultTurnDisplayMode({ forceExpanded, hasActionableToolCall }),\n )\n const wasStreamingRef = useRef(isStreaming)\n useEffect(() => {\n if (wasStreamingRef.current && !isStreaming && !forceExpanded) {\n setDisplayMode(defaultTurnDisplayMode({ forceExpanded, hasActionableToolCall }))\n }\n wasStreamingRef.current = isStreaming\n }, [forceExpanded, hasActionableToolCall, isStreaming])\n\n const sessionMessages = useChatStore((state) => state.messages[sessionId] ?? [])\n const agentLoops = useChatStore((state) => state.agentLoops[sessionId] ?? {})\n const turnMessages = useMemo(\n () => collectTurnMessages({ rootMessages: messages, sessionMessages, agentLoops }),\n [agentLoops, messages, sessionMessages],\n )\n const resourceBlocks = useMemo(() => getInlineResourceBlocks(turnMessages), [turnMessages])\n const finalMessage = useMemo(() => getLastTextMessage(turnMessages), [turnMessages])\n const hasInterruptedState = messages.some((message) => message.status === \"interrupted\")\n const effectiveMode = resolveTurnDisplayMode({ isStreaming, displayMode })\n\n const memoryRefs = Array.isArray(messages[0]?.memory_refs) ? messages[0].memory_refs : []\n\n return (\n <div\n className={cn(\n \"flex flex-col gap-3\",\n level === 2 && \"gap-2.5\",\n customization?.classNames?.assistantTurn,\n )}\n >\n {memoryRefs.length > 0 && (\n <MemoryRefsHint refs={memoryRefs} />\n )}\n {hasInterruptedState && (\n <div className=\"ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300\">\n 已中断\n </div>\n )}\n {!isStreaming && (\n <div className=\"flex justify-end\">\n <button\n type=\"button\"\n onClick={() => setDisplayMode(displayMode === \"detail\" ? \"compact\" : \"detail\")}\n className=\"inline-flex shrink-0 items-center gap-1 text-xs text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]\"\n >\n <span>{effectiveMode === \"detail\" ? \"精简\" : \"详细\"}</span>\n <ChevronRight\n size={18}\n className={cn(\"transition-transform\", effectiveMode === \"detail\" && \"rotate-180\")}\n />\n </button>\n </div>\n )}\n {effectiveMode === \"detail\" ? (\n <div className=\"flex flex-col gap-3\">\n <AssistantMessages\n messages={messages}\n isStreaming={isStreaming}\n sessionId={sessionId}\n askAnswers={askAnswers}\n onAnswer={onAnswer}\n sessionStatus={sessionStatus}\n level={level}\n showToolDetails\n customization={customization}\n />\n </div>\n ) : (\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-4\">\n {resourceBlocks.length > 0 ? (\n <div className=\"flex flex-col gap-3\">\n {resourceBlocks.map((block) => (\n <ResourceIframe key={block.key} ui={block.ui} sessionId={sessionId} />\n ))}\n </div>\n ) : null}\n\n {finalMessage ? (\n <div\n className={cn(\n resourceBlocks.length > 0 && \"border-t border-[hsl(var(--border))] pt-4\",\n )}\n >\n <AssistantMessageContent\n message={finalMessage}\n isStreaming={isStreaming && finalMessage === messages[messages.length - 1]}\n sessionId={sessionId}\n reasoning={finalMessage.reasoning}\n className={customization?.classNames?.assistantText}\n />\n </div>\n ) : isStreaming ? (\n <span className=\"text-sm text-[hsl(var(--muted-foreground))]\">正在生成...</span>\n ) : null}\n </div>\n </div>\n )}\n </div>\n )\n}\n\nfunction AssistantMessages({\n messages,\n isStreaming,\n sessionId,\n askAnswers,\n onAnswer,\n sessionStatus,\n level,\n showToolDetails,\n customization,\n}: {\n messages: ChatMessage[]\n isStreaming: boolean\n sessionId: string\n askAnswers?: Record<string, AskUserAnswerData>\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n sessionStatus?: string\n level: 1 | 2\n showToolDetails: boolean\n customization?: ChatViewCustomization\n}) {\n return messages.map((message, index) =>\n isRenderableAssistantMessage(message, isStreaming && index === messages.length - 1)\n ? (() => {\n const isStreamingLastMessage = isStreaming && index === messages.length - 1\n const hasText = !!getMessageText(message)\n const reasoning = message.reasoning\n const hasReasoning = !!reasoning\n const hasAttachments =\n getImageParts(message.content).length > 0 || getFileParts(message.content).length > 0\n const toolCalls = message.tool_calls ?? []\n const hasToolCalls = toolCalls.length > 0\n const firstToolCallId = toolCalls[0]?.id\n const toolRenderItems = groupDetailedToolCalls(toolCalls)\n const toolReasoning =\n hasReasoning && !hasText && !hasAttachments && hasToolCalls && !isStreamingLastMessage\n ? reasoning\n : undefined\n const contentReasoning =\n hasReasoning && !isStreamingLastMessage && (hasText || hasAttachments || !hasToolCalls)\n ? reasoning\n : undefined\n\n return (\n <div\n key={message.entry_id ?? `${message.timestamp ?? \"assistant\"}-${index}`}\n className=\"flex flex-col gap-3\"\n >\n {hasReasoning && isStreamingLastMessage && (\n <Reasoning isStreaming={isStreamingLastMessage}>\n <ReasoningTrigger />\n <ReasoningContent>{reasoning}</ReasoningContent>\n </Reasoning>\n )}\n <AssistantMessageContent\n message={message}\n isStreaming={isStreamingLastMessage}\n sessionId={sessionId}\n reasoning={contentReasoning}\n className={customization?.classNames?.assistantText}\n />\n\n {hasToolCalls && showToolDetails && (\n <div className=\"flex flex-col gap-2\">\n {toolRenderItems.map((item) => {\n if (item.kind === \"read_group\" || item.kind === \"load_skill_group\") {\n return (\n <CompactToolGroupBlock\n key={item.key}\n toolCalls={item.toolCalls}\n kind={item.kind}\n reasoning={\n item.toolCalls[0]?.id === firstToolCallId ? toolReasoning : undefined\n }\n sessionId={sessionId}\n sessionStatus={sessionStatus}\n askAnswers={askAnswers}\n onAnswer={onAnswer}\n turnBlocks={message.blocks}\n level={level}\n customization={customization}\n />\n )\n }\n\n const { toolCall } = item\n return formatToolName(toolCall.name) === \"Agent\" ? (\n <AgentLoopBlock\n key={toolCall.id}\n toolCall={toolCall}\n sessionId={sessionId}\n reasoning={toolCall.id === firstToolCallId ? toolReasoning : undefined}\n />\n ) : (\n customization?.components?.ToolCall ? (\n <customization.components.ToolCall\n key={toolCall.id}\n toolCall={toolCall}\n answerData={askAnswers?.[toolCall.id]}\n onAnswer={onAnswer}\n answered={sessionStatus !== \"waiting_for_input\"}\n sessionId={sessionId}\n sessionStatus={sessionStatus}\n level={level}\n turnBlocks={message.blocks}\n reasoning={toolCall.id === firstToolCallId ? toolReasoning : undefined}\n customization={customization}\n />\n ) : (\n <ToolCallBlock\n key={toolCall.id}\n toolCall={toolCall}\n answerData={askAnswers?.[toolCall.id]}\n onAnswer={onAnswer}\n answered={sessionStatus !== \"waiting_for_input\"}\n sessionId={sessionId}\n sessionStatus={sessionStatus}\n level={level}\n turnBlocks={message.blocks}\n reasoning={toolCall.id === firstToolCallId ? toolReasoning : undefined}\n customization={customization}\n />\n )\n )\n })}\n </div>\n )}\n {showToolDetails && message.blocks?.some((block) => block.type === \"tool_ui\") ? (\n <div className=\"flex flex-col gap-2\">\n {message.blocks.map((block, blockIndex) =>\n block.type === \"tool_ui\" &&\n block.tool_call_id &&\n isUiMeta(block.content) &&\n block.content.target === \"inline\" ? (\n <div key={`${block.tool_call_id}-${blockIndex}`} className=\"ml-4\">\n <ResourceIframe ui={block.content} sessionId={sessionId} />\n </div>\n ) : null,\n )}\n </div>\n ) : null}\n </div>\n )\n })()\n : null,\n )\n}\n\nfunction isRenderableAssistantMessage(message: ChatMessage, isStreaming: boolean) {\n if (message.reasoning || (message.tool_calls?.length ?? 0) > 0) {\n return true\n }\n\n const fileParts = getFileParts(message.content)\n const imageParts = getImageParts(message.content)\n const text = getMessageText(message)\n\n if (text || imageParts.length > 0 || fileParts.length > 0 || isStreaming) {\n return true\n }\n\n return (\n message.blocks?.some(\n (block) =>\n block.type === \"tool_ui\" &&\n block.tool_call_id &&\n isUiMeta(block.content) &&\n block.content.target === \"inline\",\n ) ?? false\n )\n}\n\nfunction CompactToolGroupBlock({\n toolCalls,\n kind,\n reasoning,\n sessionId,\n sessionStatus,\n askAnswers,\n onAnswer,\n turnBlocks,\n level,\n customization,\n}: {\n toolCalls: ToolCallInfo[]\n kind: \"read_group\" | \"load_skill_group\"\n reasoning?: string\n sessionId: string\n sessionStatus?: string\n askAnswers?: Record<string, AskUserAnswerData>\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n turnBlocks?: NonNullable<ChatMessage[\"blocks\"]>\n level: 1 | 2\n customization?: ChatViewCustomization\n}) {\n const [expanded, setExpanded] = useState(false)\n const indentClass = level === 2 ? \"ml-3\" : \"ml-4\"\n const hasError = toolCalls.some(\n (tc) => tc.status === \"error\" || tc.status === \"cancelled\",\n )\n const totalDurationMs = toolCalls.reduce(\n (total, toolCall) =>\n total + (typeof toolCall.duration_ms === \"number\" && toolCall.duration_ms > 0 ? toolCall.duration_ms : 0),\n 0,\n )\n const fileNames = toolCalls.map((toolCall) => {\n const filePath = extractToolFilePath(toolCall)\n return filePath ? formatFileName(filePath) : \"未知文件\"\n })\n const tags = kind === \"read_group\" ? fileNames : toolCalls.map(getLoadedSkillName)\n const title =\n kind === \"read_group\"\n ? `读取 ${toolCalls.length} 个文件`\n : toolCalls.length > 1\n ? `加载 ${toolCalls.length} 个技能`\n : \"加载技能\"\n\n return (\n <div className={cn(indentClass, \"text-xs\")}>\n <div className={cn(\n \"flex items-center gap-2 border-l-[3px] px-3 py-2\",\n hasError ? \"border-l-[hsl(var(--destructive))]\" : \"border-l-[hsl(var(--primary))]\",\n )}>\n <button\n type=\"button\"\n onClick={() => setExpanded((value) => !value)}\n className=\"flex min-w-0 shrink-0 items-center gap-2 text-left transition-colors hover:bg-white/3 focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n aria-expanded={expanded}\n >\n <ChevronRight\n size={11}\n className={cn(\n \"shrink-0 text-[hsl(var(--muted-foreground))] transition-transform\",\n expanded && \"rotate-90\",\n )}\n />\n {hasError ? (\n <span className=\"flex shrink-0 items-center gap-1 text-[10px] text-[hsl(var(--destructive))]\">\n <AlertCircle size={11} />\n <span>失败</span>\n </span>\n ) : (\n <span className=\"flex shrink-0 items-center gap-1 text-[10px] text-[hsl(var(--primary))]\">\n <Check size={11} />\n <span>完成</span>\n </span>\n )}\n <span className=\"min-w-0 shrink-0 font-medium text-[hsl(var(--foreground))]\">\n {title}\n </span>\n </button>\n <div className=\"flex min-w-0 flex-1 flex-wrap gap-1.5\">\n {tags.map((tag, index) => (\n <span\n key={`${tag}-${index}`}\n className=\"max-w-40 truncate rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.35)] px-1.5 py-0.5 font-mono text-[10px] text-[hsl(var(--muted-foreground))]\"\n title={tag}\n >\n {tag}\n </span>\n ))}\n </div>\n {reasoning ? <ThinkingBadge reasoning={reasoning} variant=\"block\" /> : null}\n {totalDurationMs > 0 ? (\n <span className=\"shrink-0 font-mono text-[10px] text-[hsl(var(--muted-foreground))]\">\n {formatToolDuration(totalDurationMs)}\n </span>\n ) : null}\n </div>\n {expanded ? (\n <div className=\"mt-1 flex flex-col gap-1\">\n {toolCalls.map((toolCall) => {\n const CustomToolCall = customization?.components?.ToolCall\n return CustomToolCall ? (\n <CustomToolCall\n key={toolCall.id}\n toolCall={toolCall}\n answerData={askAnswers?.[toolCall.id]}\n onAnswer={onAnswer}\n answered={sessionStatus !== \"waiting_for_input\"}\n sessionId={sessionId}\n sessionStatus={sessionStatus}\n level={level}\n turnBlocks={turnBlocks}\n customization={customization}\n />\n ) : (\n <ToolCallBlock\n key={toolCall.id}\n toolCall={toolCall}\n answerData={askAnswers?.[toolCall.id]}\n onAnswer={onAnswer}\n answered={sessionStatus !== \"waiting_for_input\"}\n sessionId={sessionId}\n sessionStatus={sessionStatus}\n level={level}\n turnBlocks={turnBlocks}\n customization={customization}\n />\n )\n })}\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction AssistantMessageContent({\n message,\n isStreaming,\n sessionId,\n reasoning,\n className,\n}: {\n message: ChatMessage\n isStreaming: boolean\n sessionId: string\n reasoning?: string\n className?: string\n}) {\n const fileParts = getFileParts(message.content)\n const imageParts = getImageParts(message.content)\n const text =\n typeof message.content === \"string\"\n ? message.content.trim()\n : message.content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim()\n\n if (!text && imageParts.length === 0 && fileParts.length === 0 && !isStreaming && !reasoning) {\n return null\n }\n\n return (\n <div className=\"flex flex-col gap-3\">\n {imageParts.length > 0 && (\n <div className=\"grid gap-2\">\n {imageParts.map((part) => (\n <img\n key={part.image_url.url}\n src={part.image_url.url}\n alt=\"消息附件\"\n className=\"max-h-72 rounded-xl border border-[hsl(var(--border))] object-cover\"\n />\n ))}\n </div>\n )}\n <MessageFileAttachmentList files={fileParts} />\n {text ? (\n <AssistantText\n text={text}\n sessionId={sessionId}\n messageId={message.entry_id}\n reasoning={reasoning}\n className={className}\n />\n ) : null}\n {!text && isStreaming && (\n <span className=\"text-sm text-[hsl(var(--muted-foreground))]\">正在生成...</span>\n )}\n {!text && reasoning ? <ThinkingBadge reasoning={reasoning} variant=\"block\" /> : null}\n </div>\n )\n}\n\nfunction AssistantText({\n text,\n sessionId,\n messageId,\n reasoning,\n className,\n}: {\n text: string\n sessionId: string\n messageId?: string\n reasoning?: string\n className?: string\n}) {\n const sendMessage = useCallback(\n async (content: string) => {\n getSocket().send(sessionId, content)\n },\n [sessionId],\n )\n\n const cardCtx = useMemo<CardContextValue>(\n () => ({ sessionId, messageId, sendMessage }),\n [sessionId, messageId, sendMessage],\n )\n\n return (\n <div className={cn(\"text-[15px] leading-8 text-[hsl(var(--foreground))]\", className)}>\n <CardContext.Provider value={cardCtx}>\n <MarkdownContent\n mode=\"streaming\"\n sessionId={sessionId}\n className=\"prose prose-sm prose-invert inline max-w-none [&_li>p]:inline [&_p]:mb-3 [&_p:last-child]:mb-0 [&_p:last-child]:inline\"\n controls={{ code: true }}\n >\n {text}\n </MarkdownContent>\n </CardContext.Provider>\n {reasoning ? <ThinkingBadge reasoning={reasoning} /> : null}\n </div>\n )\n}\n\nfunction MemoryRefsHint({ refs: rawRefs }: { refs: MemoryRefInfo[] }) {\n const refs = Array.isArray(rawRefs) ? rawRefs : []\n const [expanded, setExpanded] = useState(false)\n const hasSkill = refs.some((r) => r.skill_name)\n const label = hasSkill ? \"参考了该技能的历史经验\" : \"参考了历史经验\"\n\n return (\n <div className=\"ml-4\">\n <button\n type=\"button\"\n onClick={() => setExpanded(!expanded)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-[hsl(var(--primary)/0.25)] bg-[hsl(var(--primary)/0.08)] px-2.5 py-1 text-[11px] text-[hsl(var(--primary))] transition-colors hover:bg-[hsl(var(--primary)/0.12)]\"\n >\n <BookOpen size={12} />\n <span>{label}({refs.length})</span>\n <ChevronRight\n size={10}\n className={cn(\"transition-transform\", expanded && \"rotate-90\")}\n />\n </button>\n {expanded && (\n <div className=\"mt-1.5 flex flex-col gap-1 rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.45)] px-3 py-2\">\n {refs.map((ref) => (\n <div key={ref.id} className=\"flex items-start gap-2 text-[11px] text-[hsl(var(--foreground)/0.82)]\">\n <span className=\"mt-0.5 shrink-0 text-[hsl(var(--primary)/0.75)]\">•</span>\n <span className=\"line-clamp-1\">{ref.content_preview}</span>\n {ref.skill_name && (\n <span className=\"ml-auto shrink-0 rounded bg-[hsl(var(--primary)/0.12)] px-1.5 py-0.5 text-[10px] text-[hsl(var(--primary))]\">\n {ref.skill_name}\n </span>\n )}\n </div>\n ))}\n <a\n href={MEMORIES_ROUTE}\n className=\"mt-1 self-start text-[10px] text-[hsl(var(--primary))] transition-colors hover:opacity-80\"\n >\n 查看全部经验 →\n </a>\n </div>\n )}\n </div>\n )\n}\n","export const MEMORIES_ROUTE = \"/memories\"\n","\"use client\"\n\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\"\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"../ui/collapsible\"\nimport { cn } from \"../../lib/utils\"\nimport { cjk } from \"@streamdown/cjk\"\nimport { math } from \"@streamdown/math\"\nimport { mermaid } from \"@streamdown/mermaid\"\nimport { BrainIcon, ChevronDownIcon, XIcon } from \"lucide-react\"\nimport type { ComponentProps, ReactNode } from \"react\"\nimport {\n createContext,\n memo,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\"\nimport { createPortal } from \"react-dom\"\nimport { Streamdown } from \"streamdown\"\n\nimport { Shimmer } from \"./shimmer\"\nimport { CardCodeBlock } from \"../card/CardCodeBlock\"\n\ninterface ReasoningContextValue {\n isStreaming: boolean\n isOpen: boolean\n setIsOpen: (open: boolean) => void\n duration: number | undefined\n}\n\nconst ReasoningContext = createContext<ReasoningContextValue | null>(null)\n\nexport const useReasoning = () => {\n const context = useContext(ReasoningContext)\n if (!context) {\n throw new Error(\"Reasoning components must be used within Reasoning\")\n }\n return context\n}\n\nexport type ReasoningProps = ComponentProps<typeof Collapsible> & {\n isStreaming?: boolean\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n duration?: number\n}\n\nconst AUTO_CLOSE_DELAY = 3000\nconst MS_IN_S = 1000\n\nexport const Reasoning = memo(\n ({\n className,\n isStreaming = false,\n open,\n defaultOpen,\n onOpenChange,\n duration: durationProp,\n children,\n ...props\n }: ReasoningProps) => {\n const resolvedDefaultOpen = defaultOpen ?? isStreaming\n // Track if defaultOpen was explicitly set to false (to prevent auto-open)\n const isExplicitlyClosed = defaultOpen === false\n\n const [isOpen, setIsOpen] = useControllableState<boolean>({\n defaultProp: resolvedDefaultOpen,\n onChange: onOpenChange,\n prop: open,\n })\n const [duration, setDuration] = useControllableState<number | undefined>({\n defaultProp: undefined,\n prop: durationProp,\n })\n\n const hasEverStreamedRef = useRef(isStreaming)\n const [hasAutoClosed, setHasAutoClosed] = useState(false)\n const startTimeRef = useRef<number | null>(null)\n\n // Track when streaming starts and compute duration\n useEffect(() => {\n if (isStreaming) {\n hasEverStreamedRef.current = true\n if (startTimeRef.current === null) {\n startTimeRef.current = Date.now()\n }\n } else if (startTimeRef.current !== null) {\n setDuration(Math.ceil((Date.now() - startTimeRef.current) / MS_IN_S))\n startTimeRef.current = null\n }\n }, [isStreaming, setDuration])\n\n // Auto-open when streaming starts (unless explicitly closed)\n useEffect(() => {\n if (isStreaming && !isOpen && !isExplicitlyClosed) {\n setIsOpen(true)\n }\n }, [isStreaming, isOpen, setIsOpen, isExplicitlyClosed])\n\n // Auto-close when streaming ends (once only, and only if it ever streamed)\n useEffect(() => {\n if (\n hasEverStreamedRef.current &&\n !isStreaming &&\n isOpen &&\n !hasAutoClosed\n ) {\n const timer = setTimeout(() => {\n setIsOpen(false)\n setHasAutoClosed(true)\n }, AUTO_CLOSE_DELAY)\n\n return () => clearTimeout(timer)\n }\n }, [isStreaming, isOpen, setIsOpen, hasAutoClosed])\n\n const handleOpenChange = useCallback(\n (newOpen: boolean) => {\n setIsOpen(newOpen)\n },\n [setIsOpen],\n )\n\n const contextValue = useMemo(\n () => ({ duration, isOpen, isStreaming, setIsOpen }),\n [duration, isOpen, isStreaming, setIsOpen],\n )\n\n return (\n <ReasoningContext.Provider value={contextValue}>\n <Collapsible\n className={cn(\"not-prose mb-4\", className)}\n onOpenChange={handleOpenChange}\n open={isOpen}\n {...props}\n >\n {children}\n </Collapsible>\n </ReasoningContext.Provider>\n )\n },\n)\n\nexport type ReasoningTriggerProps = ComponentProps<\n typeof CollapsibleTrigger\n> & {\n getThinkingMessage?: (isStreaming: boolean, duration?: number) => ReactNode\n}\n\nconst defaultGetThinkingMessage = (isStreaming: boolean, duration?: number) => {\n if (isStreaming || duration === 0) {\n return <Shimmer duration={1}>深度思考中...</Shimmer>\n }\n if (duration === undefined) {\n return <p>已深度思考</p>\n }\n return <p>已深度思考 {duration} 秒</p>\n}\n\nexport const ReasoningTrigger = memo(\n ({\n className,\n children,\n getThinkingMessage = defaultGetThinkingMessage,\n ...props\n }: ReasoningTriggerProps) => {\n const { isStreaming, isOpen, duration } = useReasoning()\n\n return (\n <CollapsibleTrigger\n className={cn(\n \"flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground\",\n className,\n )}\n {...props}\n >\n {children ?? (\n <>\n <BrainIcon className=\"size-4\" />\n {getThinkingMessage(isStreaming, duration)}\n <ChevronDownIcon\n className={cn(\n \"size-4 transition-transform\",\n isOpen ? \"rotate-180\" : \"rotate-0\",\n )}\n />\n </>\n )}\n </CollapsibleTrigger>\n )\n },\n)\n\nexport type ReasoningContentProps = ComponentProps<\n typeof CollapsibleContent\n> & {\n children: string\n}\n\nconst streamdownPlugins = { cjk, math, mermaid }\nconst streamdownComponents = { code: CardCodeBlock }\n\nexport const ReasoningContent = memo(\n ({ className, children, ...props }: ReasoningContentProps) => (\n <CollapsibleContent\n className={cn(\n \"mt-4 text-sm\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in\",\n className,\n )}\n {...props}\n >\n <Streamdown components={streamdownComponents} plugins={streamdownPlugins}>\n {children}\n </Streamdown>\n </CollapsibleContent>\n ),\n)\n\nexport type ThinkingBadgeProps = {\n reasoning: string\n variant?: \"inline\" | \"block\"\n onClick?: ComponentProps<\"button\">[\"onClick\"]\n}\n\nfunction compactReasoningText(text: string): string {\n return text\n .split(\"\\n\")\n .map((line) => line.trim())\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim()\n}\n\nexport function ThinkingBadge({ reasoning, variant = \"inline\", onClick }: ThinkingBadgeProps) {\n const compactReasoning = compactReasoningText(reasoning)\n const [open, setOpen] = useState(false)\n\n return (\n <span\n className={cn(\n \"relative inline-flex align-baseline\",\n variant === \"inline\" ? \"ml-1\" : \"ml-1 shrink-0\",\n )}\n >\n <button\n type=\"button\"\n onClick={(event) => {\n onClick?.(event)\n setOpen(true)\n }}\n className=\"inline-flex items-center rounded-full bg-[hsl(var(--muted))]/40 px-2 py-0.5 text-[10px] leading-none text-[hsl(var(--muted-foreground))]/70 transition-colors hover:bg-[hsl(var(--muted))]/60 hover:text-[hsl(var(--muted-foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n aria-label=\"查看深度思考\"\n aria-expanded={open}\n >\n 思考详情\n </button>\n {open\n ? createPortal(\n <div\n className=\"fixed inset-0 z-[70] flex items-center justify-center bg-black/10 p-6\"\n role=\"presentation\"\n tabIndex={-1}\n onClick={(event) => {\n if (event.target === event.currentTarget) {\n setOpen(false)\n }\n }}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n setOpen(false)\n }\n }}\n >\n <div\n className=\"m-0 flex max-h-[min(520px,calc(100vh-48px))] w-[min(760px,calc(100vw-48px))] flex-col overflow-hidden rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] text-left text-[13px] leading-6 text-[hsl(var(--popover-foreground))] shadow-xl\"\n aria-label=\"思考详情\"\n >\n <div className=\"flex items-center justify-between gap-3 border-b border-[hsl(var(--border))] px-4 py-2\">\n <span className=\"text-xs font-medium text-[hsl(var(--muted-foreground))]\">\n 思考详情\n </span>\n <button\n type=\"button\"\n onClick={() => setOpen(false)}\n className=\"inline-flex h-6 w-6 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n aria-label=\"关闭思考详情\"\n >\n <XIcon size={14} aria-hidden=\"true\" />\n </button>\n </div>\n <div className=\"overflow-auto px-4 py-3 whitespace-normal [&_*]:whitespace-normal [&_p]:my-1.5 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0 [&_ul]:my-1.5 [&_ol]:my-1.5\">\n <Streamdown components={streamdownComponents} plugins={streamdownPlugins}>\n {compactReasoning}\n </Streamdown>\n </div>\n </div>\n </div>,\n document.body,\n )\n : null}\n </span>\n )\n}\n\nReasoning.displayName = \"Reasoning\"\nReasoningTrigger.displayName = \"ReasoningTrigger\"\nReasoningContent.displayName = \"ReasoningContent\"\n","\"use client\"\n\nimport { cn } from \"../../lib/utils\"\nimport type { MotionProps } from \"motion/react\"\nimport { motion } from \"motion/react\"\nimport type { CSSProperties, ElementType, JSX } from \"react\"\nimport { memo, useMemo } from \"react\"\n\ntype MotionHTMLProps = MotionProps & Record<string, unknown>\n\n// Cache motion components at module level to avoid creating during render\nconst motionComponentCache = new Map<\n keyof JSX.IntrinsicElements,\n React.ComponentType<MotionHTMLProps>\n>()\n\nconst getMotionComponent = (element: keyof JSX.IntrinsicElements) => {\n let component = motionComponentCache.get(element)\n if (!component) {\n component = motion.create(element)\n motionComponentCache.set(element, component)\n }\n return component\n}\n\nexport interface TextShimmerProps {\n children: string\n as?: ElementType\n className?: string\n duration?: number\n spread?: number\n}\n\nconst ShimmerComponent = ({\n children,\n as: Component = \"p\",\n className,\n duration = 2,\n spread = 2,\n}: TextShimmerProps) => {\n const MotionComponent = getMotionComponent(\n Component as keyof JSX.IntrinsicElements,\n )\n\n const dynamicSpread = useMemo(\n () => (children?.length ?? 0) * spread,\n [children, spread],\n )\n\n return (\n <MotionComponent\n animate={{ backgroundPosition: \"0% center\" }}\n className={cn(\n \"relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent\",\n \"[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]\",\n className,\n )}\n initial={{ backgroundPosition: \"100% center\" }}\n style={\n {\n \"--spread\": `${dynamicSpread}px`,\n backgroundImage:\n \"var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))\",\n } as CSSProperties\n }\n transition={{\n duration,\n ease: \"linear\",\n repeat: Number.POSITIVE_INFINITY,\n }}\n >\n {children}\n </MotionComponent>\n )\n}\n\nexport const Shimmer = memo(ShimmerComponent)\n","import { Bot, Check, ChevronRight, FileText, Loader2, MessageSquareMore } from \"lucide-react\"\nimport { useEffect, useMemo, useState } from \"react\"\nimport { isUiMeta } from \"../../lib/ui-meta\"\nimport { cn } from \"../../lib/utils\"\nimport type { ChatMessage, ToolCallInfo } from \"../../schemas/message\"\nimport { useChatStore } from \"../../stores/chat-store\"\nimport {\n Reasoning,\n ReasoningContent,\n ReasoningTrigger,\n ThinkingBadge,\n} from \"../ai-elements/reasoning\"\nimport { MarkdownContent } from \"../markdown/MarkdownContent\"\nimport { ResourceIframe } from \"./ResourceIframe\"\nimport { ToolCallBlock } from \"./ToolCallBlock\"\nimport { type UserChatMessage, UserMessageBubble } from \"./UserMessageBubble\"\nimport { formatToolName, getToolDisplayLabel, getToolOutputTag } from \"./display-utils\"\n\ninterface Props {\n toolCall: ToolCallInfo\n sessionId: string\n reasoning?: string\n}\n\ntype LoopStatus = \"running\" | \"done\" | \"error\" | \"cancelled\" | \"awaiting_answer\"\n\nconst EMPTY_MESSAGES: ChatMessage[] = []\nconst EMPTY_AGENT_LOOPS: Record<\n string,\n {\n toolCallId: string\n description: string\n status: \"running\" | \"done\" | \"error\" | \"cancelled\" | \"awaiting_answer\"\n }\n> = {}\n\nconst COLLAPSED_SUMMARY_HIDDEN_TOOLS = new Set([\n \"SearchSkills\",\n \"GetSkillContent\",\n \"ListSkillTools\",\n \"LoadSkillTools\",\n \"Read\",\n])\n\ntype CompletedToolLabel = {\n key: string\n label: string\n kind: \"file\" | \"tool\"\n}\n\nfunction safeParseDescription(argsStr: string): string {\n try {\n return JSON.parse(argsStr)?.description ?? \"子智能体\"\n } catch {\n return \"子智能体\"\n }\n}\n\nfunction stripFileExtension(fileName: string): string {\n return fileName.replace(/\\.[^.]+$/, \"\")\n}\n\nexport function AgentLoopBlock({ toolCall, sessionId, reasoning }: Props) {\n const agentLoops = useChatStore((state) => state.agentLoops[sessionId] ?? EMPTY_AGENT_LOOPS)\n const messages = useChatStore((state) => state.messages[sessionId] ?? EMPTY_MESSAGES)\n\n const loopEntry = useMemo(() => {\n for (const [loopName, info] of Object.entries(agentLoops)) {\n if (info.toolCallId === toolCall.id) {\n return { loopName, info }\n }\n }\n return null\n }, [agentLoops, toolCall.id])\n\n const childMessages = useMemo(() => {\n if (!loopEntry) return []\n return messages.filter((message) => (message.loop_name ?? \"root\") === loopEntry.loopName)\n }, [loopEntry, messages])\n\n const loopToolCalls = useMemo(\n () => childMessages.flatMap((message) => message.tool_calls ?? []),\n [childMessages],\n )\n const visibleLoopToolCalls = useMemo(\n () => loopToolCalls.filter((childToolCall) => formatToolName(childToolCall.name) !== \"Agent\"),\n [loopToolCalls],\n )\n const hasAwaitingAnswer = useMemo(\n () => visibleLoopToolCalls.some((childToolCall) => childToolCall.status === \"awaiting_answer\"),\n [visibleLoopToolCalls],\n )\n const [expanded, setExpanded] = useState(hasAwaitingAnswer)\n const completedToolLabels = useMemo<CompletedToolLabel[]>(\n () =>\n visibleLoopToolCalls\n .flatMap((childToolCall): CompletedToolLabel[] => {\n const isCompleted =\n childToolCall.status === \"done\" ||\n (childToolCall.status !== \"pending\" &&\n childToolCall.status !== \"awaiting_answer\" &&\n childToolCall.status !== \"error\" &&\n childToolCall.status !== \"cancelled\")\n if (!isCompleted) return []\n\n const outputTag = getToolOutputTag(childToolCall)\n if (outputTag) {\n const fileName = outputTag.label.replace(/^[^\\s]+\\s+/, \"\")\n return [\n {\n key: `${childToolCall.id}-${fileName}`,\n label: stripFileExtension(fileName),\n kind: \"file\",\n },\n ]\n }\n if (COLLAPSED_SUMMARY_HIDDEN_TOOLS.has(formatToolName(childToolCall.name))) {\n return []\n }\n return [\n {\n key: childToolCall.id,\n label: getToolDisplayLabel(childToolCall),\n kind: \"tool\",\n },\n ]\n }),\n [visibleLoopToolCalls],\n )\n const inlineToolUiBlocks = useMemo(\n () =>\n childMessages.flatMap((message) =>\n (message.blocks ?? []).flatMap((block, index) =>\n block.type === \"tool_ui\" &&\n block.tool_call_id &&\n isUiMeta(block.content) &&\n block.content.target === \"inline\"\n ? [{ key: `${message.entry_id ?? message.timestamp ?? \"message\"}-${block.tool_call_id}-${index}`, ui: block.content }]\n : [],\n ),\n ),\n [childMessages],\n )\n useEffect(() => {\n if (hasAwaitingAnswer) {\n setExpanded(true)\n }\n }, [hasAwaitingAnswer])\n const toggleExpanded = () => setExpanded((value) => !value)\n\n const description = safeParseDescription(toolCall.arguments)\n const status: LoopStatus =\n hasAwaitingAnswer || toolCall.status === \"awaiting_answer\"\n ? \"awaiting_answer\"\n : toolCall.status === \"pending\" || loopEntry?.info.status === \"running\"\n ? \"running\"\n : \"done\"\n const cardStyles = getLoopCardStyles(status)\n return (\n <div\n className={cn(\n \"ml-4 overflow-visible rounded-xl border border-[hsl(var(--border))] border-l-[3px] bg-[hsl(var(--card))]/50\",\n cardStyles.borderClass,\n )}\n >\n {status === \"running\" || status === \"awaiting_answer\" ? (\n <>\n <div\n className={cn(\n \"flex items-center gap-3 px-4 py-3 transition-colors\",\n cardStyles.headerClass,\n )}\n >\n <button\n type=\"button\"\n onClick={toggleExpanded}\n aria-expanded={expanded}\n className=\"flex min-w-0 flex-1 items-center gap-2 text-left focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n >\n <span className=\"min-w-0 flex items-center gap-2\">\n {status === \"awaiting_answer\" ? (\n <MessageSquareMore size={14} className=\"shrink-0 text-amber-500\" />\n ) : (\n <Bot size={14} className=\"shrink-0 text-blue-500\" />\n )}\n <span className=\"truncate text-sm font-medium text-[hsl(var(--foreground))]\">\n {description}\n {status === \"awaiting_answer\" ? \" — 等待回答\" : \"\"}\n </span>\n </span>\n </button>\n {reasoning ? <ThinkingBadge reasoning={reasoning} variant=\"block\" /> : null}\n <Bot\n size={13}\n className=\"shrink-0 text-[hsl(var(--muted-foreground))]/70\"\n aria-label=\"子智能体\"\n />\n <button\n type=\"button\"\n onClick={toggleExpanded}\n aria-expanded={expanded}\n className=\"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--muted))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n >\n <ChevronRight\n size={14}\n className={cn(\n \"shrink-0 text-[hsl(var(--muted-foreground))] transition-transform\",\n expanded && \"rotate-90\",\n )}\n />\n </button>\n </div>\n {!expanded ? (\n <div className=\"flex flex-col gap-1 py-2\">\n {visibleLoopToolCalls.length > 0 ? (\n visibleLoopToolCalls.map((childToolCall) => (\n <ToolCallBlock\n key={childToolCall.id}\n toolCall={childToolCall}\n sessionId={sessionId}\n level={2}\n />\n ))\n ) : (\n <div className=\"flex items-center gap-2 px-4 py-1 text-xs text-[hsl(var(--muted-foreground))]\">\n <Loader2 size={12} className=\"shrink-0 animate-spin text-blue-500\" />\n <span>正在启动...</span>\n </div>\n )}\n </div>\n ) : status === \"awaiting_answer\" ? (\n <div className=\"flex flex-col gap-1 py-2\">\n <div className=\"px-4 py-1 text-xs text-[hsl(var(--muted-foreground))]\">\n 请在下方子智能体对话中完成确认\n </div>\n </div>\n ) : null}\n </>\n ) : (\n <>\n <div\n className={cn(\n \"flex items-center gap-3 px-4 py-3 transition-colors\",\n cardStyles.headerClass,\n )}\n >\n <button\n type=\"button\"\n onClick={toggleExpanded}\n aria-expanded={expanded}\n className=\"flex min-w-0 flex-1 items-center gap-2 text-left focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n >\n <span className=\"min-w-0 flex items-center gap-2\">\n <Check size={14} className=\"shrink-0 text-emerald-500\" />\n <span className=\"truncate text-sm font-medium text-[hsl(var(--foreground))]\">\n {description}\n </span>\n </span>\n </button>\n {reasoning ? <ThinkingBadge reasoning={reasoning} variant=\"block\" /> : null}\n <Bot\n size={13}\n className=\"shrink-0 text-[hsl(var(--muted-foreground))]/70\"\n aria-label=\"子智能体\"\n />\n <button\n type=\"button\"\n onClick={toggleExpanded}\n aria-expanded={expanded}\n className=\"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--muted))] focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n >\n <ChevronRight\n size={14}\n className={cn(\n \"shrink-0 text-[hsl(var(--muted-foreground))] transition-transform\",\n expanded && \"rotate-90\",\n )}\n />\n </button>\n </div>\n {!expanded ? (\n <>\n <div className=\"flex flex-wrap gap-1.5 px-4 py-2\">\n {completedToolLabels.length > 0 ? (\n completedToolLabels.map((item) =>\n item.kind === \"file\" ? (\n <span\n key={item.key}\n className=\"inline-flex min-w-0 items-center gap-1 rounded-md border px-2 py-0.5 text-xs font-semibold dark:border-emerald-500/25 dark:bg-emerald-500/10 dark:text-emerald-300\"\n style={{\n backgroundColor: \"#DCFCE7\",\n borderColor: \"#15803D\",\n color: \"#14532D\",\n }}\n title={item.label}\n >\n <FileText size={12} className=\"shrink-0\" aria-hidden=\"true\" />\n <span className=\"truncate\">{item.label}</span>\n </span>\n ) : (\n <span\n key={item.key}\n className=\"inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-semibold dark:border-blue-300 dark:bg-blue-400/10 dark:text-blue-300\"\n style={{\n backgroundColor: \"#DBEAFE\",\n borderColor: \"#1D4ED8\",\n color: \"#1D4ED8\",\n }}\n >\n {item.label}\n </span>\n ),\n )\n ) : (\n <span className=\"text-xs text-[hsl(var(--muted-foreground))]\">暂无工具调用</span>\n )}\n </div>\n {inlineToolUiBlocks.length > 0 ? (\n <div className=\"flex flex-col gap-2 px-4 pb-3\">\n {inlineToolUiBlocks.map((block) => (\n <ResourceIframe key={block.key} ui={block.ui} sessionId={sessionId} />\n ))}\n </div>\n ) : null}\n </>\n ) : null}\n </>\n )}\n {expanded && (\n <div className=\"border-t border-[hsl(var(--border))] py-2\">\n {childMessages.length > 0 ? (\n <div className=\"flex flex-col gap-3 px-3\">\n {childMessages.map((message, index) =>\n message.role === \"assistant\" ? (\n <ExpandedChildAssistantMessage\n key={message.entry_id ?? `${message.timestamp ?? \"child\"}-${index}`}\n message={message}\n sessionId={sessionId}\n isStreaming={message.status === \"streaming\"}\n />\n ) : message.role === \"user\" ? (\n <ExpandedChildUserMessage\n key={message.entry_id ?? `${message.timestamp ?? \"user\"}-${index}`}\n message={message as UserChatMessage}\n />\n ) : message.role === \"error\" ? (\n <div\n key={message.entry_id ?? `${message.timestamp ?? \"error\"}-${index}`}\n className=\"border-l-[2px] border-l-red-500 px-3 py-2 text-[11px] text-red-200\"\n >\n {typeof message.content === \"string\" ? message.content : \"子智能体执行出错\"}\n </div>\n ) : null,\n )}\n </div>\n ) : status === \"running\" ? (\n <div className=\"px-3 py-2 text-[11px] text-[hsl(var(--muted-foreground))]\">\n <Loader2 size={12} className=\"mr-1.5 inline animate-spin\" />\n 正在启动...\n </div>\n ) : toolCall.result ? (\n <pre className=\"max-h-[400px] overflow-auto px-3 py-2 whitespace-pre-wrap text-[11px] text-[hsl(var(--muted-foreground))]\">\n {typeof toolCall.result === \"string\"\n ? toolCall.result\n : JSON.stringify(toolCall.result, null, 2)}\n </pre>\n ) : null}\n </div>\n )}\n </div>\n )\n}\n\nfunction ExpandedChildUserMessage({ message }: { message: UserChatMessage }) {\n return (\n <div className=\"pl-8\">\n <UserMessageBubble message={message} />\n </div>\n )\n}\n\nfunction ExpandedChildAssistantMessage({\n message,\n sessionId,\n isStreaming,\n}: {\n message: ChatMessage\n sessionId: string\n isStreaming: boolean\n}) {\n const text =\n typeof message.content === \"string\"\n ? message.content.trim()\n : message.content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n .trim()\n const toolCalls = message.tool_calls ?? []\n const hasToolCalls = toolCalls.length > 0\n const firstToolCallId = toolCalls[0]?.id\n const toolReasoning = !isStreaming && !text && hasToolCalls ? message.reasoning : undefined\n const standaloneReasoning = !isStreaming && !text && !hasToolCalls ? message.reasoning : undefined\n\n return (\n <div className=\"flex flex-col gap-2\">\n {message.reasoning && isStreaming && (\n <Reasoning isStreaming={isStreaming}>\n <ReasoningTrigger />\n <ReasoningContent>{message.reasoning}</ReasoningContent>\n </Reasoning>\n )}\n {text ? (\n <ChildText\n text={text}\n isStreaming={isStreaming}\n sessionId={sessionId}\n reasoning={!isStreaming ? message.reasoning : undefined}\n />\n ) : null}\n {!text && isStreaming && (\n <span className=\"pl-8 text-[12px] text-[hsl(var(--muted-foreground))]\">正在生成...</span>\n )}\n {standaloneReasoning ? (\n <div className=\"pl-8\">\n <ThinkingBadge reasoning={standaloneReasoning} variant=\"block\" />\n </div>\n ) : null}\n {hasToolCalls && (\n <div className=\"flex flex-col gap-2\">\n {toolCalls.map((toolCall, index) =>\n formatToolName(toolCall.name) === \"Agent\" ? (\n <AgentLoopBlock\n key={toolCall.id}\n toolCall={toolCall}\n sessionId={sessionId}\n reasoning={toolCall.id === firstToolCallId ? toolReasoning : undefined}\n />\n ) : (\n <ToolCallBlock\n key={toolCall.id}\n toolCall={toolCall}\n sessionId={sessionId}\n level={2}\n turnBlocks={message.blocks}\n reasoning={index === 0 ? toolReasoning : undefined}\n />\n ),\n )}\n </div>\n )}\n {message.blocks?.some((block) => block.type === \"tool_ui\") ? (\n <div className=\"flex flex-col gap-2\">\n {message.blocks.map((block, index) =>\n block.type === \"tool_ui\" &&\n block.tool_call_id &&\n isUiMeta(block.content) &&\n block.content.target === \"inline\" ? (\n <div key={`${block.tool_call_id}-${index}`} className=\"ml-4\">\n <ResourceIframe ui={block.content} sessionId={sessionId} />\n </div>\n ) : null,\n )}\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction ChildText({\n text,\n isStreaming,\n sessionId,\n reasoning,\n}: { text: string; isStreaming: boolean; sessionId: string; reasoning?: string }) {\n return (\n <div className=\"pl-8 text-[12px] leading-6 text-[hsl(var(--foreground))]\">\n <MarkdownContent\n mode=\"streaming\"\n sessionId={sessionId}\n className=\"prose prose-sm prose-invert inline max-w-none [&_li>p]:inline [&_p]:mb-2 [&_p:last-child]:mb-0 [&_p:last-child]:inline\"\n controls={{ code: true }}\n >\n {text}\n </MarkdownContent>\n {isStreaming && (\n <span className=\"ml-0.5 inline-block h-[1em] w-[3px] animate-pulse rounded-sm bg-current opacity-60\" />\n )}\n {reasoning ? <ThinkingBadge reasoning={reasoning} /> : null}\n </div>\n )\n}\n\nfunction getLoopCardStyles(status: LoopStatus) {\n if (status === \"running\") {\n return {\n borderClass: \"border-l-blue-500\",\n headerClass: \"bg-blue-500/5\",\n iconClass: \"text-blue-500\",\n }\n }\n\n if (status === \"awaiting_answer\") {\n return {\n borderClass: \"border-l-amber-500\",\n headerClass: \"bg-amber-500/5\",\n iconClass: \"text-amber-500\",\n }\n }\n\n if (status === \"cancelled\") {\n return {\n borderClass: \"border-l-amber-500\",\n headerClass: \"bg-amber-500/5\",\n iconClass: \"text-amber-500\",\n }\n }\n\n if (status === \"error\") {\n return {\n borderClass: \"border-l-red-500\",\n headerClass: \"bg-red-500/5\",\n iconClass: \"text-red-500\",\n }\n }\n\n return {\n borderClass: \"border-l-[hsl(var(--primary))]\",\n headerClass: \"bg-[hsl(var(--primary)/0.05)]\",\n iconClass: \"text-[hsl(var(--primary))]\",\n }\n}\n","import { useEffect, useEffectEvent, useRef, useState } from \"react\"\nimport { registerBridgeIframe, tapBridgeEvent } from \"../../devtools/bridge-devtools/tap\"\nimport { resourceBridgeDispatch } from \"../../lib/resource-bridge\"\nimport type { UiMeta } from \"../../lib/ui-meta\"\nimport { useChatStore } from \"../../stores/chat-store\"\nimport { useSessionStore } from \"../../stores/session-store\"\nimport { resolveEffectiveTheme, useUiStore } from \"../../stores/ui-store\"\n\nfunction isResourceBridgeMessage(\n value: unknown,\n): value is { __resourceBridge: true; action: string; payload?: unknown } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { __resourceBridge?: unknown }).__resourceBridge === true &&\n typeof (value as { action?: unknown }).action === \"string\"\n )\n}\n\n// inline target 的 height 上下限,避免恶意/失误内容把 iframe 撑爆或缩没\nconst INLINE_HEIGHT_MIN = 80\nconst INLINE_HEIGHT_MAX = 6000\nconst INLINE_HEIGHT_PADDING = 8\n\nexport function ResourceIframe({ ui, sessionId }: { ui: UiMeta; sessionId: string }) {\n const iframeRef = useRef<HTMLIFrameElement | null>(null)\n const iframeKeyRef = useRef<string>(\n `iframe-${Math.random().toString(36).slice(2, 10)}`,\n )\n const activeSessionId = useSessionStore((state) => state.activeSessionId)\n const isStreaming = useChatStore((state) => state.isStreaming[sessionId] ?? false)\n const theme = useUiStore((state) => state.theme)\n const resourceUri = ui.resourceUri ?? ui.resourceURI\n const iframeLabel = ui.title ?? resourceUri ?? \"工具界面\"\n // 由 iframe 内容自报的高度(resize 消息)。null 表示沿用工具声明的 ui.height。\n const [autoHeight, setAutoHeight] = useState<number | null>(null)\n\n // 工具更换 / 切换会话时重置自报高度(依赖列举的内容变化即触发重置)\n // biome-ignore lint/correctness/useExhaustiveDependencies: 此处依赖只用于触发重置,body 内无需引用\n useEffect(() => {\n setAutoHeight(null)\n }, [ui.resourceHTML, resourceUri])\n\n const effectiveTheme =\n theme === \"system\"\n ? document.documentElement.getAttribute(\"data-theme\") === \"light\" ||\n document.documentElement.getAttribute(\"data-theme\") === \"dark\"\n ? (document.documentElement.getAttribute(\"data-theme\") as \"light\" | \"dark\")\n : resolveEffectiveTheme(theme)\n : theme\n\n const handleMessage = useEffectEvent((event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow\n if (!iframeWindow || event.source !== iframeWindow) {\n return\n }\n\n if (!isResourceBridgeMessage(event.data)) {\n return\n }\n\n tapBridgeEvent({\n side: \"host\",\n direction: \"iframe-to-host\",\n action: event.data.action,\n payload: event.data.payload,\n iframeKey: iframeKeyRef.current,\n iframeLabel,\n })\n\n // inline target 下,iframe 内容可通过 resize 消息上报真实高度,由 host 实时贴合\n if (event.data.action === \"resize\" && ui.target !== \"preview\") {\n const payload = event.data.payload\n const rawHeight =\n payload && typeof payload === \"object\"\n ? (payload as { height?: unknown }).height\n : undefined\n if (typeof rawHeight === \"number\" && Number.isFinite(rawHeight) && rawHeight > 0) {\n const clamped = Math.min(\n Math.max(Math.ceil(rawHeight) + INLINE_HEIGHT_PADDING, INLINE_HEIGHT_MIN),\n INLINE_HEIGHT_MAX,\n )\n setAutoHeight((prev) => (prev === clamped ? prev : clamped))\n }\n return\n }\n\n resourceBridgeDispatch({\n sessionId,\n activeSessionId,\n isStreaming,\n action: event.data.action,\n payload: event.data.payload,\n })\n })\n\n useEffect(() => {\n const listener = (event: MessageEvent) => {\n handleMessage(event)\n }\n window.addEventListener(\"message\", listener)\n return () => {\n window.removeEventListener(\"message\", listener)\n }\n }, [handleMessage])\n\n const postTheme = useEffectEvent((themeValue: \"light\" | \"dark\") => {\n const iframeWindow = iframeRef.current?.contentWindow\n if (!iframeWindow) {\n return\n }\n iframeWindow.postMessage(\n {\n __resourceBridge: true,\n direction: \"host-to-iframe\",\n event: \"theme\",\n payload: { theme: themeValue },\n },\n \"*\",\n )\n tapBridgeEvent({\n side: \"host\",\n direction: \"host-to-iframe\",\n action: \"theme\",\n payload: { theme: themeValue },\n iframeKey: iframeKeyRef.current,\n iframeLabel,\n })\n })\n\n useEffect(() => {\n const key = iframeKeyRef.current\n return registerBridgeIframe({\n key,\n label: iframeLabel,\n getContentWindow: () => iframeRef.current?.contentWindow ?? null,\n })\n }, [iframeLabel])\n\n useEffect(() => {\n postTheme(effectiveTheme)\n }, [effectiveTheme, postTheme])\n\n if (!ui.resourceHTML && !resourceUri) {\n return null\n }\n\n const inlineHeight = autoHeight ?? ui.height\n const sandbox = resourceUri ? \"allow-scripts allow-same-origin\" : \"allow-scripts\"\n\n return (\n <iframe\n ref={iframeRef}\n title={ui.title ?? \"工具界面\"}\n src={resourceUri}\n srcDoc={ui.resourceHTML}\n sandbox={sandbox}\n loading=\"lazy\"\n scrolling={ui.target === \"preview\" ? undefined : \"no\"}\n className=\"w-full rounded-xl border border-[hsl(var(--border))] bg-white\"\n referrerPolicy=\"no-referrer\"\n style={{ height: ui.target === \"preview\" ? \"100%\" : inlineHeight }}\n onLoad={() => {\n postTheme(effectiveTheme)\n }}\n />\n )\n}\n","import { Check, ChevronRight, Loader2, MessageSquareMore, PanelRightOpen, X } from \"lucide-react\"\nimport { useMemo, useState } from \"react\"\nimport { resolveSessionFilePreviewTarget } from \"../../lib/session-file-preview\"\nimport { buildToolPreviewKey } from \"../../lib/tool-preview\"\nimport { isUiMeta } from \"../../lib/ui-meta\"\nimport { cn } from \"../../lib/utils\"\nimport type { ToolCallInfo } from \"../../schemas/message\"\nimport type { ContentBlock } from \"../../schemas/projection\"\nimport { useAnswerCallbackStore } from \"../../stores/answer-callback-store\"\nimport { useChatStore } from \"../../stores/chat-store\"\nimport { useSessionStore } from \"../../stores/session-store\"\nimport { useUiStore } from \"../../stores/ui-store\"\nimport {\n ThinkingBadge,\n} from \"../ai-elements/reasoning\"\nimport {\n AskUserQuestionBlock,\n type AskUserAnswerData,\n parseAskUserQuestion,\n} from \"./AskUserQuestionBlock\"\nimport {\n extractToolFilePath,\n formatToolName,\n getToolDisplayLabel,\n getToolStatusLabel,\n getToolTone,\n} from \"./display-utils\"\nimport { getRenderer } from \"./tool-renderers/registry\"\nimport type { ChatViewCustomization } from \"./customization\"\n\nfunction FilePathLink({ filePath, sessionId }: { filePath: string; sessionId?: string }) {\n const activeSessionId = useSessionStore((s) => s.activeSessionId)\n const pushArtifact = useUiStore((s) => s.pushArtifact)\n const resolvedSessionId = sessionId ?? activeSessionId\n\n const fileName = filePath.split(\"/\").pop() ?? filePath\n\n const handleClick = async () => {\n if (!resolvedSessionId) return\n try {\n const target = await resolveSessionFilePreviewTarget(\n resolvedSessionId,\n filePath,\n fileName,\n )\n pushArtifact(target)\n } catch {\n // Silently fail -- file may not exist in sandbox\n }\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n className=\"flex min-w-0 items-center gap-1 text-blue-400 hover:text-blue-300 hover:underline cursor-pointer font-mono\"\n title={`预览 ${filePath}`}\n >\n <span className=\"truncate\">{fileName}</span>\n </button>\n )\n}\n\ninterface Props {\n toolCall: ToolCallInfo\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n answered?: boolean\n answerData?: AskUserAnswerData\n sessionId?: string\n sessionStatus?: string\n level?: 1 | 2\n turnBlocks?: ContentBlock[]\n reasoning?: string\n customization?: ChatViewCustomization\n}\n\nexport function ToolCallBlock({\n toolCall,\n onAnswer,\n answered,\n answerData,\n sessionId: providedSessionId,\n sessionStatus,\n level = 1,\n turnBlocks,\n reasoning,\n customization,\n}: Props) {\n const [expanded, setExpanded] = useState(false)\n const activeSessionId = useSessionStore((s) => s.activeSessionId)\n const sessions = useSessionStore((s) => s.sessions)\n const pushArtifact = useUiStore((s) => s.pushArtifact)\n const resolvedSessionId = providedSessionId ?? activeSessionId ?? undefined\n const storedAnswerData = useChatStore((s) =>\n resolvedSessionId ? s.askAnswers[resolvedSessionId]?.[toolCall.id] : undefined,\n )\n const answerCallback = useAnswerCallbackStore((s) =>\n resolvedSessionId ? s.callbacks[resolvedSessionId] : undefined,\n )\n const normalizedName = formatToolName(toolCall.name)\n const resolvedSessionStatus =\n sessionStatus ??\n sessions.find((session) => session.id === resolvedSessionId)?.status\n const resolvedAnswerData = answerData ?? storedAnswerData\n const resolvedAnswered =\n answered ?? (!!resolvedAnswerData && resolvedSessionStatus !== \"waiting_for_input\")\n const resolvedOnAnswer = onAnswer ?? answerCallback\n const uiMeta = useMemo(() => {\n const block = turnBlocks?.find(\n (item) => item.type === \"tool_ui\" && item.tool_call_id === toolCall.id && isUiMeta(item.content),\n )\n return block && isUiMeta(block.content) ? block.content : null\n }, [toolCall.id, turnBlocks])\n\n // Special rendering for AskUserQuestion\n if (normalizedName === \"AskUserQuestion\") {\n const askData =\n parseAskUserQuestion(typeof toolCall.result === \"string\" ? toolCall.result : null) ??\n parseAskUserQuestion(buildAskUserPayload(toolCall.arguments))\n const canAnswer =\n toolCall.status === \"awaiting_answer\" && Boolean(resolvedOnAnswer) && Boolean(resolvedSessionStatus)\n const shouldRenderQuestion = Boolean(askData) && (canAnswer || resolvedAnswered || toolCall.status === \"done\")\n if (askData && shouldRenderQuestion) {\n const questionBlock = (\n <AskUserQuestionBlock\n data={askData}\n answered={resolvedAnswered || toolCall.status === \"done\"}\n toolCallId={toolCall.id}\n sessionStatus={resolvedSessionStatus ?? \"\"}\n answerData={resolvedAnswerData}\n onAnswer={canAnswer ? resolvedOnAnswer : undefined}\n />\n )\n if (!reasoning) {\n return questionBlock\n }\n return (\n <div className=\"flex flex-col gap-1\">\n {questionBlock}\n <div className=\"ml-4\">\n <ThinkingBadge reasoning={reasoning} variant=\"block\" />\n </div>\n </div>\n )\n }\n }\n\n const filePath = extractToolFilePath(toolCall)\n const loadedSkillName = normalizedName === \"LoadSkillTools\" ? extractLoadedSkillName(toolCall) : null\n const tone = getToolTone(toolCall.status)\n const displayName = getToolDisplayLabel(toolCall)\n const Renderer = customization?.renderers?.tool?.[normalizedName] ?? getRenderer(normalizedName)\n const borderWidthClass = level === 2 ? \"border-l-[2px]\" : \"border-l-[3px]\"\n const indentClass = level === 2 ? \"ml-3\" : \"ml-4\"\n const toneClass =\n tone === \"red\"\n ? \"border-l-[hsl(var(--muted-foreground)/0.5)]\"\n : tone === \"amber\"\n ? \"border-l-amber-400\"\n : tone === \"blue\"\n ? \"border-l-blue-500\"\n : \"border-l-[hsl(var(--primary))]\"\n\n const statusIcon =\n toolCall.status === \"pending\" ? (\n <Loader2 size={11} className=\"animate-spin\" />\n ) : toolCall.status === \"awaiting_answer\" ? (\n <MessageSquareMore size={11} />\n ) : toolCall.status === \"cancelled\" || toolCall.status === \"error\" ? (\n <X size={11} />\n ) : (\n <Check size={11} />\n )\n\n const statusTextClass =\n tone === \"red\"\n ? \"text-[hsl(var(--muted-foreground))]\"\n : tone === \"amber\"\n ? \"text-amber-300\"\n : tone === \"blue\"\n ? \"text-blue-300\"\n : \"text-[hsl(var(--primary))]\"\n\n return (\n <div className={cn(indentClass, \"text-xs\", customization?.classNames?.toolCall)}>\n <div className={cn(borderWidthClass, toneClass, \"flex items-center gap-2 px-3 py-2\")}>\n <button\n type=\"button\"\n onClick={() => setExpanded(!expanded)}\n className=\"flex min-w-0 flex-1 items-center gap-2 text-left transition-colors hover:bg-white/3 focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none\"\n aria-expanded={expanded}\n >\n <ChevronRight\n size={11}\n className={cn(\n \"shrink-0 text-[hsl(var(--muted-foreground))] transition-transform\",\n expanded && \"rotate-90\",\n )}\n />\n <span className={cn(\"flex shrink-0 items-center gap-1 text-[10px]\", statusTextClass)}>\n {statusIcon}\n <span>{getToolStatusLabel(toolCall.status)}</span>\n </span>\n <span className=\"min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]\">\n {displayName}\n {toolCall.status === \"error\" ? \"(待重试)\" : \"\"}\n </span>\n </button>\n {filePath && (\n <span className=\"flex min-w-0 max-w-[50%] text-[hsl(var(--muted-foreground))]\">\n <FilePathLink filePath={filePath} sessionId={resolvedSessionId} />\n </span>\n )}\n {loadedSkillName ? (\n <span\n className=\"min-w-0 max-w-[50%] shrink truncate text-[hsl(var(--foreground))]\"\n title={loadedSkillName}\n >\n {loadedSkillName}\n </span>\n ) : null}\n {reasoning ? <ThinkingBadge reasoning={reasoning} variant=\"block\" /> : null}\n {typeof toolCall.duration_ms === \"number\" && toolCall.duration_ms > 0 && (\n <span className=\"shrink-0 font-mono text-[10px] text-[hsl(var(--muted-foreground))]\">\n {formatToolDuration(toolCall.duration_ms)}\n </span>\n )}\n {uiMeta?.target === \"preview\" && resolvedSessionId && !isInternalStatusPreview(uiMeta) ? (\n <button\n type=\"button\"\n onClick={() => {\n const type = uiMeta.resourceHTML ? \"resource-html\" : \"resource-uri\"\n const content = uiMeta.resourceHTML ?? uiMeta.resourceUri ?? uiMeta.resourceURI ?? \"\"\n pushArtifact({\n type,\n content,\n title: uiMeta.title ?? displayName,\n key: buildToolPreviewKey(content, type, toolCall.id),\n bridgeSessionId: resolvedSessionId,\n })\n }}\n className=\"inline-flex shrink-0 items-center gap-1 text-blue-400 hover:text-blue-300 hover:underline cursor-pointer\"\n title={`打开 ${uiMeta.title ?? displayName}`}\n >\n <PanelRightOpen size={11} />\n <span>{uiMeta.title ?? displayName}</span>\n </button>\n ) : null}\n </div>\n {expanded && (\n <div className=\"ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3\">\n {Renderer ? (\n <Renderer toolCall={toolCall} sessionId={resolvedSessionId} />\n ) : (\n <>\n <div className=\"mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]\">\n 参数\n </div>\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {formatArgs(toolCall.arguments)}\n </pre>\n {toolCall.result != null && (\n <>\n <div className=\"mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]\">\n 结果\n </div>\n <pre\n className={cn(\n \"max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md p-2 font-mono text-[11px]\",\n \"bg-[hsl(var(--muted))] text-[hsl(var(--foreground))]\",\n )}\n >\n {typeof toolCall.result === \"string\"\n ? toolCall.result\n : JSON.stringify(toolCall.result, null, 2)}\n </pre>\n </>\n )}\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction extractLoadedSkillName(toolCall: ToolCallInfo): string | null {\n const args = parseToolArguments(toolCall.arguments)\n const skillId = typeof args?.skill_id === \"string\" ? args.skill_id.trim() : \"\"\n if (skillId) return skillId\n\n const result = parseToolResult(toolCall.result)\n if (isRecord(result) && typeof result.skill_id === \"string\") {\n const resultSkillId = result.skill_id.trim()\n if (resultSkillId) return resultSkillId\n }\n return null\n}\n\nfunction parseToolArguments(value: string | null | undefined): Record<string, unknown> | null {\n if (!value) return null\n try {\n const parsed = JSON.parse(value)\n return isRecord(parsed) ? parsed : null\n } catch {\n return null\n }\n}\n\nfunction parseToolResult(value: unknown): unknown {\n if (typeof value !== \"string\") return value\n try {\n return JSON.parse(value)\n } catch {\n return value\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction isInternalStatusPreview(uiMeta: { title?: string | null } | null): boolean {\n return uiMeta?.title?.trim() === \"阶段进度\"\n}\n\nfunction formatToolDuration(ms: number): string {\n if (ms < 1000) return `${Math.round(ms)}ms`\n const seconds = ms / 1000\n if (seconds < 60) return `${seconds.toFixed(1)}s`\n const minutes = Math.floor(seconds / 60)\n const remainingSeconds = Math.round(seconds % 60)\n return remainingSeconds > 0 ? `${minutes}m${remainingSeconds}s` : `${minutes}m`\n}\n\nfunction formatArgs(args: string): string {\n try {\n return JSON.stringify(JSON.parse(args), null, 2)\n } catch {\n return args\n }\n}\n\nfunction buildAskUserPayload(argumentsJson: string): string | null {\n try {\n const parsed = JSON.parse(argumentsJson)\n if (parsed && typeof parsed === \"object\" && Array.isArray((parsed as { questions?: unknown }).questions)) {\n return JSON.stringify({ questions: (parsed as { questions: unknown[] }).questions })\n }\n } catch {\n return null\n }\n return null\n}\n","import {\n getCodeLanguageFromFilename,\n useHighlightedCodeHtml,\n} from \"../../../lib/code-highlight\"\nimport { cn } from \"../../../lib/utils\"\n\n/**\n * 从工具结果中提取纯文本。如果 result 是多模态 list 则提取 text parts;\n * 如果是 string 则原样返回。\n */\nexport function getResultText(result: unknown): string | null {\n if (typeof result === \"string\") return result\n if (Array.isArray(result)) {\n const texts = result\n .filter(\n (p): p is { type: \"text\"; text: string } =>\n typeof p === \"object\" && p !== null && p.type === \"text\" && typeof p.text === \"string\",\n )\n .map((p) => p.text)\n return texts.length > 0 ? texts.join(\"\\n\") : null\n }\n return result != null ? String(result) : null\n}\n\n/**\n * 从工具结果中提取图片 URL 列表(data:image/... base64 或 http URL)。\n */\nexport function getResultImageUrls(result: unknown): string[] {\n if (!Array.isArray(result)) return []\n return result\n .filter(\n (p): p is { type: \"image_url\"; image_url: { url: string } } =>\n typeof p === \"object\" &&\n p !== null &&\n p.type === \"image_url\" &&\n typeof p.image_url?.url === \"string\",\n )\n .map((p) => p.image_url.url)\n}\n\nexport function parseJsonValue(value?: string | null): unknown {\n if (!value) return null\n try {\n return JSON.parse(value)\n } catch {\n return null\n }\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value)\n}\n\nexport function getStringValue(\n data: Record<string, unknown> | null,\n key: string,\n): string | null {\n const value = data?.[key]\n return typeof value === \"string\" && value.trim() ? value.trim() : null\n}\n\nexport function getNumberValue(\n data: Record<string, unknown> | null,\n key: string,\n): number | null {\n const value = data?.[key]\n return typeof value === \"number\" && Number.isFinite(value) ? value : null\n}\n\nexport function getBooleanValue(\n data: Record<string, unknown> | null,\n key: string,\n): boolean {\n return data?.[key] === true\n}\n\nexport function extractErrorMessage(value?: unknown): string | null {\n const text = typeof value === \"string\" ? value : getResultText(value)\n if (!text?.trim()) return null\n const parsed = parseJsonValue(text)\n if (!isPlainObject(parsed)) return null\n return typeof parsed.error === \"string\" && parsed.error.trim() ? parsed.error.trim() : null\n}\n\nexport function getFileName(filePath?: string | null): string {\n if (!filePath) return \"未命名文件\"\n return filePath.split(\"/\").pop() ?? filePath\n}\n\nexport function getCodeLanguage(filePath?: string | null): string | null {\n return getCodeLanguageFromFilename(filePath)\n}\n\nexport function formatBytes(size?: number | null): string | null {\n if (typeof size !== \"number\" || !Number.isFinite(size) || size < 0) return null\n if (size < 1024) return `${size} B`\n if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`\n return `${(size / (1024 * 1024)).toFixed(1)} MB`\n}\n\ninterface CodePreviewProps {\n content: string\n filePath?: string | null\n emptyLabel?: string\n className?: string\n}\n\nexport function CodePreview({\n content,\n filePath,\n emptyLabel = \"(暂无内容)\",\n className,\n}: CodePreviewProps) {\n const { highlightedHtml } = useHighlightedCodeHtml(content, getCodeLanguage(filePath))\n\n if (!content.trim()) {\n return (\n <pre\n className={cn(\n \"overflow-auto rounded-lg border border-[hsl(var(--border))]\",\n \"bg-[hsl(var(--muted))]/35 p-3 font-mono text-[11px] text-[hsl(var(--muted-foreground))]\",\n className,\n )}\n >\n <code>{emptyLabel}</code>\n </pre>\n )\n }\n\n return (\n <pre\n className={cn(\n \"overflow-auto rounded-lg border border-[hsl(var(--border))]\",\n \"bg-[hsl(var(--muted))]/35 p-3 text-[11px]\",\n className,\n )}\n >\n {highlightedHtml ? (\n <code\n className=\"font-mono\"\n // biome-ignore lint/security/noDangerouslySetInnerHtml: syntax highlighting output is generated locally\n dangerouslySetInnerHTML={{ __html: highlightedHtml }}\n />\n ) : (\n <code className=\"whitespace-pre-wrap break-words font-mono text-[hsl(var(--foreground))]\">\n {content}\n </code>\n )}\n </pre>\n )\n}\n","import { cn } from \"../../../lib/utils\"\nimport { formatToolName } from \"../display-utils\"\nimport type { ToolRendererProps } from \"./registry\"\nimport {\n extractErrorMessage,\n getBooleanValue,\n getNumberValue,\n getResultText,\n getStringValue,\n isPlainObject,\n parseJsonValue,\n} from \"./shared\"\n\nfunction pickOutputField(data: Record<string, unknown> | null): string | null {\n if (!data) return null\n for (const key of [\"output\", \"stdout\", \"stderr\"] as const) {\n const value = data[key]\n if (typeof value === \"string\") return value\n }\n return null\n}\n\nfunction MetaPill({ label }: { label: string }) {\n return (\n <span className=\"rounded-full border border-border bg-muted px-2 py-0.5 text-[10px] text-secondary-foreground\">\n {label}\n </span>\n )\n}\n\nexport function BashRenderer({ toolCall }: ToolRendererProps) {\n const argsValue = parseJsonValue(toolCall.arguments)\n const rawText = getResultText(toolCall.result)\n const resultStr =\n typeof rawText === \"string\" && rawText.trim().length > 0 ? rawText : null\n const resultValue = parseJsonValue(resultStr)\n const args = isPlainObject(argsValue) ? argsValue : null\n const result = isPlainObject(resultValue) ? resultValue : null\n const normalizedName = formatToolName(toolCall.name)\n\n const command = getStringValue(result, \"command\") ?? getStringValue(args, \"command\") ?? \"\"\n const description =\n getStringValue(args, \"description\") ?? getStringValue(result, \"description\") ?? \"\"\n const cwd = getStringValue(result, \"cwd\") ?? getStringValue(args, \"cwd\")\n const taskId = getStringValue(result, \"task_id\")\n const exitCode = getNumberValue(result, \"exit_code\")\n const timedOut = getBooleanValue(result, \"timed_out\")\n const truncated = getBooleanValue(result, \"truncated\")\n const cwdResetNote = getStringValue(result, \"cwd_reset_note\")\n const errorMessage =\n extractErrorMessage(toolCall.result) ??\n (toolCall.status === \"error\" ? resultStr?.trim() ?? null : null)\n const structuredOutput = pickOutputField(result)\n const rawFallbackOutput =\n result === null && typeof resultStr === \"string\" && resultStr.trim().length > 0\n ? resultStr\n : null\n const output =\n structuredOutput !== null\n ? structuredOutput\n : errorMessage ?? rawFallbackOutput ?? (normalizedName === \"BgBash\" ? \"\" : null)\n const hasFailure =\n toolCall.status === \"error\" || timedOut || (exitCode !== null && exitCode !== 0)\n\n return (\n <div className=\"space-y-3\">\n {(description || cwd) && (\n <div className=\"flex flex-wrap items-center gap-2 text-[11px] text-[hsl(var(--muted-foreground))]\">\n {description ? <span>{description}</span> : null}\n {cwd ? (\n <span className=\"rounded-full bg-[hsl(var(--muted))] px-2 py-0.5 font-mono\">\n {cwd}\n </span>\n ) : null}\n </div>\n )}\n\n <div className=\"overflow-hidden rounded-lg border border-border bg-card\">\n <div className=\"border-b border-border px-3 py-2 text-[10px] uppercase tracking-[0.16em] text-muted-foreground\">\n 命令\n </div>\n <pre className=\"overflow-x-auto px-3 py-3 font-mono text-[11px] leading-5 text-foreground\">\n <code>{`$ ${command || \"(未提供命令)\"}`}</code>\n </pre>\n </div>\n\n <div\n className={cn(\n \"overflow-hidden rounded-lg border bg-muted/50\",\n hasFailure ? \"border-red-500/50\" : \"border-border\",\n )}\n >\n <div className=\"flex flex-wrap items-center justify-between gap-2 border-b border-border px-3 py-2\">\n <div className=\"text-[10px] uppercase tracking-[0.16em] text-muted-foreground\">输出</div>\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {taskId ? <MetaPill label={`任务 ${taskId}`} /> : null}\n {exitCode !== null ? <MetaPill label={`退出码 ${exitCode}`} /> : null}\n {timedOut ? <MetaPill label=\"已超时\" /> : null}\n {truncated ? <MetaPill label=\"输出已截断\" /> : null}\n {normalizedName === \"BgBash\" && !taskId ? <MetaPill label=\"后台任务\" /> : null}\n </div>\n </div>\n <pre className=\"max-h-[280px] overflow-auto px-3 py-3 font-mono text-[11px] leading-5 text-foreground\">\n <code className=\"whitespace-pre-wrap break-words\">\n {output !== null && output.trim().length > 0\n ? output\n : normalizedName === \"BgBash\"\n ? \"任务已进入后台执行,输出会在后台任务面板中继续更新。\"\n : output !== null && output.trim().length === 0 && hasFailure\n ? \"命令已结束,但未捕获到终端输出(请查看退出码)。\"\n : \"命令未返回输出。\"}\n </code>\n </pre>\n </div>\n\n {cwdResetNote ? (\n <div className=\"rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted))]/35 px-3 py-2 text-[11px] text-[hsl(var(--muted-foreground))]\">\n {cwdResetNote}\n </div>\n ) : null}\n </div>\n )\n}\n","import { cn } from \"../../../lib/utils\"\nimport { extractToolFilePath, formatToolName } from \"../display-utils\"\nimport type { ToolRendererProps } from \"./registry\"\nimport {\n extractErrorMessage,\n getFileName,\n getStringValue,\n isPlainObject,\n parseJsonValue,\n} from \"./shared\"\n\ninterface DiffLine {\n type: \"added\" | \"removed\" | \"unchanged\"\n value: string\n oldLine: number | null\n newLine: number | null\n}\n\nconst MAX_DIFF_LINES = 200\n\nfunction computeDiff(oldText: string, newText: string): DiffLine[] {\n const oldLines = oldText.split(\"\\n\")\n const newLines = newText.split(\"\\n\")\n\n if (oldLines.length > MAX_DIFF_LINES || newLines.length > MAX_DIFF_LINES) {\n return [\n ...oldLines.slice(0, MAX_DIFF_LINES).map((line, i) => ({\n type: \"removed\" as const,\n value: line,\n oldLine: i + 1,\n newLine: null,\n })),\n ...newLines.slice(0, MAX_DIFF_LINES).map((line, i) => ({\n type: \"added\" as const,\n value: line,\n oldLine: null,\n newLine: i + 1,\n })),\n ]\n }\n\n const rows = oldLines.length\n const cols = newLines.length\n const lcs: number[][] = Array.from({ length: rows + 1 }, () => Array(cols + 1).fill(0))\n\n for (let row = 1; row <= rows; row += 1) {\n for (let col = 1; col <= cols; col += 1) {\n lcs[row][col] =\n oldLines[row - 1] === newLines[col - 1]\n ? lcs[row - 1][col - 1] + 1\n : Math.max(lcs[row - 1][col], lcs[row][col - 1])\n }\n }\n\n const diff: Array<Omit<DiffLine, \"oldLine\" | \"newLine\">> = []\n let row = rows\n let col = cols\n\n while (row > 0 || col > 0) {\n if (row > 0 && col > 0 && oldLines[row - 1] === newLines[col - 1]) {\n diff.push({ type: \"unchanged\", value: oldLines[row - 1] })\n row -= 1\n col -= 1\n continue\n }\n\n if (col > 0 && (row === 0 || lcs[row][col - 1] >= lcs[row - 1][col])) {\n diff.push({ type: \"added\", value: newLines[col - 1] })\n col -= 1\n continue\n }\n\n if (row > 0) {\n diff.push({ type: \"removed\", value: oldLines[row - 1] })\n row -= 1\n }\n }\n\n const numbered: DiffLine[] = []\n let oldLine = 0\n let newLine = 0\n\n for (const line of diff.reverse()) {\n if (line.type === \"unchanged\") {\n oldLine += 1\n newLine += 1\n numbered.push({ ...line, oldLine, newLine })\n continue\n }\n\n if (line.type === \"removed\") {\n oldLine += 1\n numbered.push({ ...line, oldLine, newLine: null })\n continue\n }\n\n newLine += 1\n numbered.push({ ...line, oldLine: null, newLine })\n }\n\n return numbered\n}\n\nfunction buildWritePreview(content: string): DiffLine[] {\n return content.split(\"\\n\").map((line, index) => ({\n type: \"added\",\n value: line,\n oldLine: null,\n newLine: index + 1,\n }))\n}\n\nfunction extractChecksum(result?: unknown): string | null {\n const text = typeof result === \"string\" ? result : null\n const match = text?.match(/\\[checksum:\\s*([^\\]]+)\\]/)\n return match?.[1]?.trim() ?? null\n}\n\nexport function FileEditRenderer({ toolCall }: ToolRendererProps) {\n const argsValue = parseJsonValue(toolCall.arguments)\n const args = isPlainObject(argsValue) ? argsValue : null\n const normalizedName = formatToolName(toolCall.name)\n const filePath = extractToolFilePath(toolCall)\n const fileName = getFileName(filePath)\n const errorMessage = extractErrorMessage(toolCall.result)\n const checksum = extractChecksum(toolCall.result)\n\n const writeContent = getStringValue(args, \"content\") ?? \"\"\n const oldString = getStringValue(args, \"old_string\") ?? \"\"\n const newString = getStringValue(args, \"new_string\") ?? \"\"\n const diffLines =\n normalizedName === \"Write\" ? buildWritePreview(writeContent) : computeDiff(oldString, newString)\n const resultStr = typeof toolCall.result === \"string\" ? toolCall.result : null\n const summaryText = resultStr?.trim() && !errorMessage ? resultStr.trim() : null\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"text-[10px] uppercase tracking-[0.16em] text-[hsl(var(--muted-foreground))]\">\n {normalizedName === \"Write\" ? \"写入文件\" : \"编辑文件\"}\n </div>\n <div className=\"truncate font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {filePath ?? fileName}\n </div>\n </div>\n {checksum ? (\n <span className=\"rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--muted))] px-2 py-0.5 font-mono text-[10px] text-[hsl(var(--muted-foreground))]\">\n {checksum}\n </span>\n ) : null}\n </div>\n\n {errorMessage ? (\n <div className=\"rounded-lg border border-red-500/30 bg-red-500/8 px-3 py-2 text-[11px] text-red-300\">\n {errorMessage}\n </div>\n ) : null}\n\n <div className=\"overflow-hidden rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted))]/20\">\n <div className=\"border-b border-[hsl(var(--border))] px-3 py-2 text-[10px] uppercase tracking-[0.16em] text-[hsl(var(--muted-foreground))]\">\n {normalizedName === \"Write\" ? \"内容预览\" : \"变更预览\"}\n </div>\n <pre className=\"max-h-[320px] overflow-auto p-0 font-mono text-[11px] leading-5\">\n {diffLines.length > 0 ? (\n diffLines.map((line, index) => {\n const prefix =\n line.type === \"added\" ? \"+ \" : line.type === \"removed\" ? \"- \" : \" \"\n\n return (\n <div\n key={`${line.type}-${line.oldLine}-${line.newLine}-${index}`}\n className={cn(\n \"grid grid-cols-[3rem_3rem_minmax(0,1fr)] gap-0 px-3\",\n line.type === \"added\" && \"bg-emerald-500/10 text-emerald-200\",\n line.type === \"removed\" && \"bg-red-500/10 text-red-200\",\n line.type === \"unchanged\" && \"text-[hsl(var(--foreground))]\",\n )}\n >\n <span className=\"select-none py-0.5 text-right text-[10px] text-[hsl(var(--muted-foreground))]\">\n {line.oldLine ?? \"\"}\n </span>\n <span className=\"select-none py-0.5 text-right text-[10px] text-[hsl(var(--muted-foreground))]\">\n {line.newLine ?? \"\"}\n </span>\n <span className=\"min-w-0 whitespace-pre-wrap break-words py-0.5\">\n {prefix}\n {line.value}\n </span>\n </div>\n )\n })\n ) : (\n <div className=\"px-3 py-4 text-[11px] text-[hsl(var(--muted-foreground))]\">\n 未检测到可预览的变更。\n </div>\n )}\n </pre>\n </div>\n\n {summaryText ? (\n <div className=\"rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted))]/35 px-3 py-2 text-[11px] text-[hsl(var(--muted-foreground))]\">\n {summaryText}\n </div>\n ) : null}\n </div>\n )\n}\n","import { useState } from \"react\"\nimport { ImageLightbox } from \"../ImageLightbox\"\nimport { extractToolFilePath } from \"../display-utils\"\nimport type { ToolRendererProps } from \"./registry\"\nimport {\n CodePreview,\n extractErrorMessage,\n getFileName,\n getNumberValue,\n getResultImageUrls,\n getResultText,\n isPlainObject,\n parseJsonValue,\n} from \"./shared\"\n\nconst NUMBERED_LINE_RE = /^(\\s*\\d+)\\t([\\s\\S]*)$/\n\nfunction parseReadResult(result?: string | null) {\n if (!result) {\n return {\n checksum: null,\n content: \"\",\n endLine: null,\n note: null,\n startLine: null,\n }\n }\n\n let body = result.trimEnd()\n const checksumMatch = body.match(/\\n\\n\\[checksum:\\s*([^\\]]+)\\]\\s*$/)\n const checksum = checksumMatch?.[1]?.trim() ?? null\n\n if (checksumMatch?.index !== undefined) {\n body = body.slice(0, checksumMatch.index).trimEnd()\n }\n\n const noteMatch = body.match(/\\n\\n(文件共[\\s\\S]*?)\\s*$/)\n const note = noteMatch?.[0]?.trim() ?? null\n\n if (noteMatch?.index !== undefined) {\n body = body.slice(0, noteMatch.index).trimEnd()\n }\n\n const numberedLines = body\n .split(\"\\n\")\n .map((line) => {\n const match = line.match(NUMBERED_LINE_RE)\n if (!match) return null\n return {\n number: Number(match[1].trim()),\n text: match[2],\n }\n })\n .filter((line): line is { number: number; text: string } => Boolean(line))\n\n return {\n checksum,\n content: numberedLines.length > 0 ? numberedLines.map((line) => line.text).join(\"\\n\") : body,\n endLine: numberedLines.length > 0 ? numberedLines[numberedLines.length - 1].number : null,\n note,\n startLine: numberedLines.length > 0 ? numberedLines[0].number : null,\n }\n}\n\nfunction formatLineRange(startLine: number | null, endLine: number | null): string | null {\n if (startLine === null || endLine === null) return null\n return startLine === endLine ? `第 ${startLine} 行` : `第 ${startLine}-${endLine} 行`\n}\n\nexport function FileReadRenderer({ toolCall }: ToolRendererProps) {\n const [lightboxIndex, setLightboxIndex] = useState<number | null>(null)\n\n const argsValue = parseJsonValue(toolCall.arguments)\n const args = isPlainObject(argsValue) ? argsValue : null\n const filePath = extractToolFilePath(toolCall)\n const fileName = getFileName(filePath)\n\n // 提取文本和图片\n const resultText = getResultText(toolCall.result)\n const imageUrls = getResultImageUrls(toolCall.result)\n const isImageResult = imageUrls.length > 0\n\n const errorMessage = extractErrorMessage(resultText)\n const { checksum, content, note, startLine, endLine } = parseReadResult(resultText)\n const fallbackStart = getNumberValue(args, \"offset\") ?? 1\n const lineCount = content ? content.split(\"\\n\").length : 0\n const resolvedStartLine = startLine ?? (lineCount > 0 ? fallbackStart : null)\n const resolvedEndLine =\n endLine ?? (resolvedStartLine !== null && lineCount > 0 ? resolvedStartLine + lineCount - 1 : null)\n const lineRange = formatLineRange(resolvedStartLine, resolvedEndLine)\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"truncate font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {fileName}\n </div>\n {filePath ? (\n <div className=\"truncate text-[10px] text-[hsl(var(--muted-foreground))]\">\n {filePath}\n </div>\n ) : null}\n </div>\n <div className=\"flex flex-wrap items-center justify-end gap-1.5\">\n {lineRange ? (\n <span className=\"rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--muted))] px-2 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))]\">\n {lineRange}\n </span>\n ) : null}\n {checksum ? (\n <span className=\"rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--muted))] px-2 py-0.5 font-mono text-[10px] text-[hsl(var(--muted-foreground))]\">\n {checksum}\n </span>\n ) : null}\n </div>\n </div>\n\n {errorMessage ? (\n <div className=\"rounded-lg border border-red-500/30 bg-red-500/8 px-3 py-2 text-[11px] text-red-300\">\n {errorMessage}\n </div>\n ) : null}\n\n {isImageResult ? (\n <div className=\"grid gap-2\">\n {imageUrls.map((url, idx) => (\n <button\n type=\"button\"\n key={url.slice(0, 64)}\n onClick={() => setLightboxIndex(idx)}\n className=\"cursor-zoom-in\"\n title=\"查看大图\"\n >\n <img\n src={url}\n alt={fileName}\n className=\"max-h-64 rounded-lg border border-[hsl(var(--border))] object-contain\"\n />\n </button>\n ))}\n <ImageLightbox\n open={lightboxIndex != null}\n onOpenChange={(open) => {\n if (!open) setLightboxIndex(null)\n }}\n images={imageUrls.map((url) => ({ src: url, alt: fileName }))}\n initialIndex={lightboxIndex ?? 0}\n />\n {content ? (\n <div className=\"text-[11px] text-[hsl(var(--muted-foreground))]\">{content}</div>\n ) : null}\n </div>\n ) : !errorMessage ? (\n <CodePreview content={content} filePath={filePath} className=\"max-h-[360px]\" />\n ) : null}\n\n {note ? (\n <div className=\"rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted))]/35 px-3 py-2 text-[11px] text-[hsl(var(--muted-foreground))]\">\n {note}\n </div>\n ) : null}\n </div>\n )\n}\n","import { ChevronLeft, ChevronRight, Download, ExternalLink, Minus, Plus, RotateCcw, X } from \"lucide-react\"\nimport { useCallback, useEffect, useRef, useState } from \"react\"\nimport { createPortal } from \"react-dom\"\n\ninterface ImageLightboxProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n images: { src: string; alt: string }[]\n initialIndex?: number\n}\n\nexport function ImageLightbox({ open, onOpenChange, images, initialIndex = 0 }: ImageLightboxProps) {\n const [currentIndex, setCurrentIndex] = useState(initialIndex)\n const [scale, setScale] = useState(1)\n const [translate, setTranslate] = useState({ x: 0, y: 0 })\n const dragging = useRef(false)\n const dragStart = useRef({ x: 0, y: 0 })\n const translateStart = useRef({ x: 0, y: 0 })\n const imgRef = useRef<HTMLImageElement>(null)\n\n const reset = useCallback(() => {\n setScale(1)\n setTranslate({ x: 0, y: 0 })\n }, [])\n\n const close = useCallback(() => {\n reset()\n onOpenChange(false)\n }, [onOpenChange, reset])\n\n const zoomIn = useCallback(() => setScale((s) => Math.min(s + 0.5, 5)), [])\n const zoomOut = useCallback(() => setScale((s) => Math.max(s - 0.5, 0.5)), [])\n\n const goPrev = useCallback(() => {\n setCurrentIndex((i) => Math.max(0, i - 1))\n reset()\n }, [reset])\n\n const goNext = useCallback(() => {\n setCurrentIndex((i) => Math.min(images.length - 1, i + 1))\n reset()\n }, [images.length, reset])\n\n // Reset state only on closed→open transition\n const prevOpenRef = useRef(false)\n useEffect(() => {\n if (open && !prevOpenRef.current) {\n setCurrentIndex(initialIndex)\n reset()\n }\n prevOpenRef.current = open\n }, [open, initialIndex, reset])\n\n // Keyboard: ESC to close, arrow keys to navigate\n useEffect(() => {\n if (!open) return\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") close()\n if (images.length > 1) {\n if (e.key === \"ArrowLeft\") goPrev()\n if (e.key === \"ArrowRight\") goNext()\n }\n }\n document.addEventListener(\"keydown\", handleKey)\n return () => document.removeEventListener(\"keydown\", handleKey)\n }, [open, close, goPrev, goNext, images.length])\n\n // Prevent body scroll when open\n useEffect(() => {\n if (!open) return\n const prev = document.body.style.overflow\n document.body.style.overflow = \"hidden\"\n return () => {\n document.body.style.overflow = prev\n }\n }, [open])\n\n const handleWheel = useCallback((e: React.WheelEvent) => {\n e.preventDefault()\n setScale((s) => {\n const delta = e.deltaY > 0 ? -0.2 : 0.2\n return Math.min(Math.max(s + delta, 0.5), 5)\n })\n }, [])\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (scale <= 1) return\n e.preventDefault()\n dragging.current = true\n dragStart.current = { x: e.clientX, y: e.clientY }\n translateStart.current = { ...translate }\n },\n [scale, translate],\n )\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!dragging.current) return\n setTranslate({\n x: translateStart.current.x + e.clientX - dragStart.current.x,\n y: translateStart.current.y + e.clientY - dragStart.current.y,\n })\n }, [])\n\n const handleMouseUp = useCallback(() => {\n dragging.current = false\n }, [])\n\n const handleDoubleClick = useCallback(() => {\n reset()\n }, [reset])\n\n // Close when clicking outside the image (on the padding area)\n const handleAreaClick = useCallback(\n (e: React.MouseEvent) => {\n if (imgRef.current && !imgRef.current.contains(e.target as Node)) {\n close()\n }\n },\n [close],\n )\n\n const handleDownload = useCallback(() => {\n const img = images[currentIndex] ?? images[0]\n if (!img?.src) return\n const a = document.createElement(\"a\")\n a.href = img.src\n a.download = img.alt || \"image.png\"\n a.click()\n }, [images, currentIndex])\n\n const handleOpenInNewTab = useCallback(() => {\n const img = images[currentIndex] ?? images[0]\n if (!img?.src) return\n window.open(img.src, \"_blank\")\n }, [images, currentIndex])\n\n if (!open) return null\n\n // Show loading state when open but images not yet ready\n if (images.length === 0) {\n return createPortal(\n // biome-ignore lint/a11y/useKeyWithClickEvents: ESC handler is registered via useEffect\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/80\"\n onClick={close}\n >\n <button\n type=\"button\"\n onClick={close}\n className=\"absolute right-4 top-4 z-10 rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white\"\n >\n <X size={20} />\n </button>\n <span className=\"text-sm text-white/60\">加载中...</span>\n </div>,\n document.body,\n )\n }\n\n const current = images[currentIndex] ?? images[0]\n const showNav = images.length > 1\n\n return createPortal(\n // biome-ignore lint/a11y/useKeyWithClickEvents: ESC handler is registered via useEffect\n <div className=\"fixed inset-0 z-50 bg-black/80\" onClick={handleAreaClick}>\n {/* Top-right actions — stopPropagation prevents handleAreaClick from closing the lightbox */}\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: only used to stop event propagation */}\n <div\n className=\"absolute right-4 top-4 z-10 flex items-center gap-1.5\"\n onClick={(e) => e.stopPropagation()}\n >\n <button\n type=\"button\"\n onClick={handleDownload}\n title=\"下载图片\"\n className=\"rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white\"\n >\n <Download size={18} />\n </button>\n <button\n type=\"button\"\n onClick={handleOpenInNewTab}\n title=\"新标签页打开\"\n className=\"rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white\"\n >\n <ExternalLink size={18} />\n </button>\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white\"\n >\n <X size={20} />\n </button>\n </div>\n\n {/* Prev arrow */}\n {showNav && currentIndex > 0 && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n goPrev()\n }}\n className=\"absolute left-4 top-1/2 z-10 -translate-y-1/2 rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white\"\n >\n <ChevronLeft size={24} />\n </button>\n )}\n\n {/* Next arrow */}\n {showNav && currentIndex < images.length - 1 && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n goNext()\n }}\n className=\"absolute right-4 top-1/2 z-10 -translate-y-1/2 rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white\"\n >\n <ChevronRight size={24} />\n </button>\n )}\n\n {/* Zoom controls + image counter */}\n <div className=\"absolute bottom-6 left-1/2 z-10 flex -translate-x-1/2 items-center gap-1 rounded-full bg-black/50 px-2 py-1\">\n <button\n type=\"button\"\n onClick={zoomOut}\n className=\"rounded-full p-1.5 text-white/80 transition-colors hover:bg-white/10 hover:text-white\"\n >\n <Minus size={16} />\n </button>\n <span className=\"min-w-[3rem] text-center text-xs text-white/80\">\n {Math.round(scale * 100)}%\n </span>\n <button\n type=\"button\"\n onClick={zoomIn}\n className=\"rounded-full p-1.5 text-white/80 transition-colors hover:bg-white/10 hover:text-white\"\n >\n <Plus size={16} />\n </button>\n <button\n type=\"button\"\n onClick={reset}\n className=\"rounded-full p-1.5 text-white/80 transition-colors hover:bg-white/10 hover:text-white\"\n >\n <RotateCcw size={16} />\n </button>\n {showNav && (\n <>\n <div className=\"mx-1 h-4 w-px bg-white/20\" />\n <span className=\"min-w-[3rem] text-center text-xs text-white/80\">\n {currentIndex + 1} / {images.length}\n </span>\n </>\n )}\n </div>\n\n {/* Image area */}\n <div\n className=\"flex h-full w-full items-center justify-center overflow-hidden p-12\"\n style={{ cursor: scale > 1 ? \"grab\" : \"default\" }}\n onWheel={handleWheel}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n onDoubleClick={handleDoubleClick}\n >\n <img\n ref={imgRef}\n src={current.src}\n alt={current.alt}\n draggable={false}\n className=\"max-h-full max-w-full select-none object-contain\"\n style={{\n transform: `scale(${scale}) translate(${translate.x / scale}px, ${translate.y / scale}px)`,\n transition: dragging.current ? \"none\" : \"transform 0.2s ease\",\n }}\n />\n </div>\n </div>,\n document.body,\n )\n}\n","import { ExternalLink, FileText, Folder, Globe2 } from \"lucide-react\"\nimport { cn } from \"../../../lib/utils\"\nimport { formatToolName } from \"../display-utils\"\nimport type { ToolRendererProps } from \"./registry\"\nimport {\n extractErrorMessage,\n formatBytes,\n getResultText,\n getStringValue,\n isPlainObject,\n parseJsonValue,\n} from \"./shared\"\n\ninterface DirectoryItem {\n isDir: boolean\n name: string\n size: number | null\n}\n\ninterface GrepMatch {\n line: string\n lineNumber: number | null\n path: string\n}\n\ninterface SearchResultItem {\n description: string | null\n title: string | null\n url: string | null\n}\n\nfunction toRecordArray(value: unknown): Record<string, unknown>[] {\n return Array.isArray(value) ? value.filter(isPlainObject) : []\n}\n\nfunction parseDirectoryItems(result?: string | null): DirectoryItem[] {\n const value = parseJsonValue(result)\n\n if (!Array.isArray(value)) {\n return []\n }\n\n return value\n .map((item) => {\n if (typeof item === \"string\") {\n return {\n isDir: item.endsWith(\"/\"),\n name: item,\n size: null,\n }\n }\n\n if (!isPlainObject(item)) {\n return null\n }\n\n return {\n isDir: item.is_dir === true,\n name: typeof item.name === \"string\" ? item.name : \"未命名\",\n size: typeof item.size === \"number\" ? item.size : null,\n }\n })\n .filter((item): item is DirectoryItem => Boolean(item))\n}\n\nfunction parseGrepResult(result?: string | null): {\n matches: GrepMatch[]\n searchPath: string | null\n} {\n if (!result?.trim()) {\n return { matches: [], searchPath: null }\n }\n\n const [header, ...rest] = result.split(\"\\n\")\n const searchPath = header.startsWith(\"搜索路径:\") ? header.replace(\"搜索路径:\", \"\").trim() : null\n const matches = toRecordArray(parseJsonValue(rest.join(\"\\n\"))).map((item) => ({\n line: typeof item.line === \"string\" ? item.line : \"\",\n lineNumber: typeof item.line_number === \"number\" ? item.line_number : null,\n path: typeof item.path === \"string\" ? item.path : \"未知路径\",\n }))\n\n return { matches, searchPath }\n}\n\nfunction parseWebResults(result?: string | null): SearchResultItem[] {\n return toRecordArray(parseJsonValue(result)).map((item) => ({\n description: typeof item.description === \"string\" ? item.description : null,\n title: typeof item.title === \"string\" ? item.title : null,\n url: typeof item.url === \"string\" ? item.url : null,\n }))\n}\n\nfunction parseWebFetchResult(result?: string | null): {\n results: SearchResultItem[]\n summary: string | null\n} {\n const value = parseJsonValue(result)\n if (!isPlainObject(value)) {\n return { results: [], summary: null }\n }\n\n return {\n results: toRecordArray(value.results).map((item) => ({\n description: typeof item.description === \"string\" ? item.description : null,\n title: typeof item.title === \"string\" ? item.title : null,\n url: typeof item.url === \"string\" ? item.url : null,\n })),\n summary: typeof value.summary === \"string\" && value.summary.trim() ? value.summary.trim() : null,\n }\n}\n\nfunction renderEmptyState(label: string) {\n return (\n <div className=\"rounded-lg border border-dashed border-[hsl(var(--border))] bg-[hsl(var(--muted))]/20 px-3 py-4 text-[11px] text-[hsl(var(--muted-foreground))]\">\n {label}\n </div>\n )\n}\n\nexport function SearchRenderer({ toolCall }: ToolRendererProps) {\n const normalizedName = formatToolName(toolCall.name)\n const argsValue = parseJsonValue(toolCall.arguments)\n const args = isPlainObject(argsValue) ? argsValue : null\n const resultStr = getResultText(toolCall.result)\n const errorMessage = extractErrorMessage(resultStr)\n\n if (errorMessage) {\n return (\n <div className=\"rounded-lg border border-red-500/30 bg-red-500/8 px-3 py-2 text-[11px] text-red-300\">\n {errorMessage}\n </div>\n )\n }\n\n if (normalizedName === \"Ls\" || normalizedName === \"Glob\") {\n const items = parseDirectoryItems(resultStr)\n const path = getStringValue(args, \"path\")\n\n return (\n <div className=\"space-y-3\">\n {path ? (\n <div className=\"text-[11px] text-[hsl(var(--muted-foreground))]\">目录:{path}</div>\n ) : null}\n {items.length > 0 ? (\n <div className=\"grid gap-2\">\n {items.map((item) => (\n <div\n key={`${item.name}-${item.size}-${item.isDir}`}\n className=\"flex items-center justify-between gap-3 rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted))]/20 px-3 py-2\"\n >\n <div className=\"flex min-w-0 items-center gap-2\">\n {item.isDir ? (\n <Folder size={14} className=\"shrink-0 text-blue-300\" />\n ) : (\n <FileText size={14} className=\"shrink-0 text-[hsl(var(--muted-foreground))]\" />\n )}\n <span className=\"truncate font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {item.name}\n </span>\n </div>\n <span className=\"shrink-0 text-[10px] text-[hsl(var(--muted-foreground))]\">\n {item.isDir ? \"目录\" : formatBytes(item.size) ?? \"文件\"}\n </span>\n </div>\n ))}\n </div>\n ) : (\n renderEmptyState(\"没有可展示的文件结果。\")\n )}\n </div>\n )\n }\n\n if (normalizedName === \"Grep\") {\n const { matches, searchPath } = parseGrepResult(resultStr)\n const pattern = getStringValue(args, \"pattern\")\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-2 text-[11px] text-[hsl(var(--muted-foreground))]\">\n {pattern ? (\n <span className=\"rounded-full bg-[hsl(var(--muted))] px-2 py-0.5 font-mono\">\n {pattern}\n </span>\n ) : null}\n {searchPath ? <span>范围:{searchPath}</span> : null}\n </div>\n {matches.length > 0 ? (\n <div className=\"grid gap-2\">\n {matches.map((match) => (\n <div\n key={`${match.path}-${match.lineNumber}-${match.line}`}\n className=\"rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted))]/20 px-3 py-2\"\n >\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"truncate font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {match.path}\n </span>\n {match.lineNumber !== null ? (\n <span className=\"shrink-0 text-[10px] text-[hsl(var(--muted-foreground))]\">\n 第 {match.lineNumber} 行\n </span>\n ) : null}\n </div>\n <pre className=\"mt-2 overflow-x-auto whitespace-pre-wrap font-mono text-[11px] text-[hsl(var(--muted-foreground))]\">\n <code>{match.line}</code>\n </pre>\n </div>\n ))}\n </div>\n ) : (\n renderEmptyState(\"没有找到匹配结果。\")\n )}\n </div>\n )\n }\n\n const { results, summary } =\n normalizedName === \"WebFetch\"\n ? parseWebFetchResult(resultStr)\n : { results: parseWebResults(resultStr), summary: null }\n const query = getStringValue(args, \"query\")\n\n return (\n <div className=\"space-y-3\">\n {query ? (\n <div className=\"text-[11px] text-[hsl(var(--muted-foreground))]\">查询:{query}</div>\n ) : null}\n\n {summary ? (\n <div className=\"rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted))]/20 px-3 py-3\">\n <div className=\"mb-2 text-[10px] uppercase tracking-[0.16em] text-[hsl(var(--muted-foreground))]\">\n 摘要\n </div>\n <p className=\"whitespace-pre-wrap text-[11px] leading-5 text-[hsl(var(--foreground))]\">\n {summary}\n </p>\n </div>\n ) : null}\n\n {results.length > 0 ? (\n <div className=\"grid gap-2\">\n {results.map((item, index) => (\n <a\n key={`${item.url ?? item.title ?? \"result\"}-${index}`}\n href={item.url ?? undefined}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={cn(\n \"rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted))]/20 px-3 py-3 transition-colors\",\n item.url && \"hover:border-[hsl(var(--ring))] hover:bg-[hsl(var(--muted))]/35\",\n )}\n >\n <div className=\"flex items-start gap-3\">\n <Globe2 size={15} className=\"mt-0.5 shrink-0 text-blue-300\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start justify-between gap-3\">\n <span className=\"line-clamp-2 text-[11px] font-medium text-[hsl(var(--foreground))]\">\n {item.title ?? item.url ?? \"未命名结果\"}\n </span>\n {item.url ? (\n <ExternalLink\n size={12}\n className=\"mt-0.5 shrink-0 text-[hsl(var(--muted-foreground))]\"\n />\n ) : null}\n </div>\n {item.url ? (\n <div className=\"mt-1 truncate font-mono text-[10px] text-[hsl(var(--muted-foreground))]\">\n {item.url}\n </div>\n ) : null}\n {item.description ? (\n <p className=\"mt-2 line-clamp-3 text-[11px] leading-5 text-[hsl(var(--muted-foreground))]\">\n {item.description}\n </p>\n ) : null}\n </div>\n </div>\n </a>\n ))}\n </div>\n ) : (\n renderEmptyState(\"没有可展示的搜索结果。\")\n )}\n </div>\n )\n}\n","import type { ComponentType } from \"react\"\nimport type { ToolCallInfo } from \"../../../schemas/message\"\nimport { formatToolName } from \"../display-utils\"\nimport { BashRenderer } from \"./BashRenderer\"\nimport { FileEditRenderer } from \"./FileEditRenderer\"\nimport { FileReadRenderer } from \"./FileReadRenderer\"\nimport { SearchRenderer } from \"./SearchRenderer\"\n\nexport interface ToolRendererProps {\n toolCall: ToolCallInfo\n sessionId?: string\n}\n\ntype ToolRenderer = ComponentType<ToolRendererProps>\n\nconst RENDERERS = new Map<string, ToolRenderer>([\n [\"Bash\", BashRenderer],\n [\"BgBash\", BashRenderer],\n [\"Edit\", FileEditRenderer],\n [\"Grep\", SearchRenderer],\n [\"Glob\", SearchRenderer],\n [\"Ls\", SearchRenderer],\n [\"Read\", FileReadRenderer],\n [\"WebFetch\", SearchRenderer],\n [\"WebSearch\", SearchRenderer],\n [\"Write\", FileEditRenderer],\n])\n\nexport function getRenderer(toolName: string): ToolRenderer | null {\n return RENDERERS.get(formatToolName(toolName)) ?? null\n}\n","import { useState } from \"react\"\nimport { getAuthedUrl } from \"../../api/client\"\nimport { extractTextAttachments, getFileParts, getImageParts, getTextContent } from \"../../lib/chat\"\nimport { dispatchPreview, isImageFilename } from \"../../lib/preview-dispatch\"\nimport { parseWhatIfPrompt } from \"../../lib/whatif-prompt\"\nimport type { ChatMessage } from \"../../schemas/message\"\nimport { useSessionStore } from \"../../stores/session-store\"\nimport { cn } from \"../../lib/utils\"\nimport { MarkdownContent } from \"../markdown/MarkdownContent\"\nimport { AttachmentPreviewDialog } from \"./AttachmentPreviewDialog\"\nimport { ImageLightbox } from \"./ImageLightbox\"\nimport { MessageContextPills } from \"./MessageContextPills\"\nimport { MessageFileAttachmentList } from \"./MessageFileAttachmentList\"\nimport { MessageActions } from \"./MessageActions\"\nimport { TextAttachmentPills } from \"./TextAttachmentPills\"\nimport { WhatIfUserBubble } from \"./WhatIfUserBubble\"\n\nexport type UserChatMessage = ChatMessage & { role: \"user\" }\nexport type ErrorChatMessage = ChatMessage & { role: \"error\" }\n\nexport function isUserMessage(message: ChatMessage): message is UserChatMessage {\n return message.role === \"user\"\n}\n\nexport function isErrorMessage(message: ChatMessage): message is ErrorChatMessage {\n return message.role === \"error\"\n}\n\ninterface UserMessageProps {\n message: UserChatMessage\n className?: string\n}\n\n/**\n * 把内联图片判定统一到 preview-dispatch 的 IMAGE_EXTS(R6 / PR7 fix):\n * 避免\"规则 A 判定非图片 → 落到 pill → 规则 B 判定是图片 → handleTextAttachmentPreview\n * 早返回\"的死胡同,让 svg/heic/apng/avif 这类扩展名也有明确的预览入口。\n * name 先于 uploadedPath:服务端重命名后的路径可能丢掉扩展名,而用户上传时的\n * 原文件名是权威源。\n */\nfunction isImageTextAttachment(name: string, uploadedPath?: string): boolean {\n return isImageFilename(name) || isImageFilename(uploadedPath ?? \"\")\n}\n\nfunction buildSessionFileUrl(sessionId: string, filePath: string): string {\n return getAuthedUrl(\n `/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(filePath)}`,\n )\n}\n\nexport function UserMessageBubble({ message, className }: UserMessageProps) {\n const activeSessionId = useSessionStore((state) => state.activeSessionId)\n const _textContent = getTextContent(message.content)\n const fileParts = getFileParts(message.content)\n const imageParts = getImageParts(message.content)\n const {\n cleanText,\n attachments: textAttachments,\n contexts: textContexts,\n } = extractTextAttachments(message.content)\n const trimmedClean = cleanText.trim()\n\n // what-if 重跑 prompt:压成小徽章 + 步骤跳转 chip + 用户真正输入气泡。\n // 只有在没有附件/图片时走这条快路——有附件说明是混合消息,保留完整渲染。\n const whatifParsed =\n trimmedClean &&\n imageParts.length === 0 &&\n fileParts.length === 0 &&\n textAttachments.length === 0\n ? parseWhatIfPrompt(cleanText)\n : null\n if (whatifParsed) {\n return (\n <div className=\"flex justify-end\">\n <div className=\"group flex max-w-[72%] flex-col items-end gap-2\">\n <WhatIfUserBubble parsed={whatifParsed} />\n {whatifParsed.userText && (\n <MessageActions\n content={whatifParsed.userText}\n className=\"opacity-0 transition-opacity group-hover:opacity-100\"\n />\n )}\n </div>\n </div>\n )\n }\n // uploadedPath 缺失兜底:历史消息里有些用户上传的附件没有回写 path\n // (早期上传链路 bug),但文件实际上已经落到 session workspace 根目录,\n // 用文件名当路径即可。图片判定靠文件名扩展名,比扫 uploadedPath 更稳。\n const imageTextAttachments = activeSessionId\n ? textAttachments\n .flatMap((attachment) => {\n if (!isImageTextAttachment(attachment.name, attachment.uploadedPath)) {\n return []\n }\n const pathForUrl = attachment.uploadedPath ?? attachment.name\n return [\n {\n ...attachment,\n url: buildSessionFileUrl(activeSessionId, pathForUrl),\n },\n ]\n })\n : []\n const nonImageTextAttachments = textAttachments.filter(\n (attachment) => !isImageTextAttachment(attachment.name, attachment.uploadedPath),\n )\n\n // R6:把两批图片合并成 lightbox 能直接消费的列表,点击任一图片在原位置\n // 打开 lightbox 并定位到对应 index。组合顺序必须和下面渲染的 DOM 一致,\n // 否则 index 会错位。\n const lightboxImages = [\n ...imageParts.map((part) => ({\n src: part.image_url.url,\n alt: \"用户上传的图片\",\n })),\n ...imageTextAttachments.map((attachment) => ({\n src: attachment.url,\n alt: attachment.name || \"用户上传的图片\",\n })),\n ]\n const [lightboxIndex, setLightboxIndex] = useState<number | null>(null)\n\n // R6:文本/未知附件预览 state\n const [preview, setPreview] = useState<{\n filename: string\n url: string\n mode: \"markdown\" | \"text\" | \"default\"\n } | null>(null)\n const handleTextAttachmentPreview = (\n attachment: { name: string; uploadedPath?: string },\n ) => {\n if (!activeSessionId) return\n // uploadedPath 缺失兜底:历史会话里 [附件: xxx] 行没有附带\"已上传到工作区路径\"\n // 后缀时,前端的 extractTextAttachments 拿不到 uploadedPath。但文件实际落在\n // session workspace 根目录,用原文件名当路径即可。和图片附件的兜底策略保持一致。\n const pathForUrl = attachment.uploadedPath ?? attachment.name\n const url = buildSessionFileUrl(activeSessionId, pathForUrl)\n const kind = dispatchPreview(attachment.name, url).kind\n // 图片附件正常情况下已经被 isImageTextAttachment 过滤到 imageTextAttachments,\n // 走 inline lightbox;但如果规则将来再次分叉或边缘情况,兜底也把它塞给\n // ImageLightbox(single-image 模式)而不是静默无反应。\n if (kind === \"image\") {\n const existingIdx = lightboxImages.findIndex((img) => img.src === url)\n if (existingIdx >= 0) {\n setLightboxIndex(existingIdx)\n } else {\n // 动态追加一条 image 到 lightbox(临时):由于 lightboxImages 是每次\n // render 重新计算的派生值,这里写 state 不合适——改成把 attachment 的\n // 信息落到 preview state 以 \"default\" mode 显示,让用户至少能下载。\n setPreview({ filename: attachment.name, url, mode: \"default\" })\n }\n return\n }\n const lower = attachment.name.toLowerCase()\n const mode: \"markdown\" | \"text\" | \"default\" =\n kind === \"text\" ? (lower.endsWith(\".md\") ? \"markdown\" : \"text\") : \"default\"\n setPreview({ filename: attachment.name, url, mode })\n }\n\n return (\n <div className={cn(\"flex justify-end\", className)}>\n <div className=\"group flex max-w-[72%] flex-col items-end gap-3\">\n {(imageParts.length > 0 || imageTextAttachments.length > 0) && (\n <div className=\"grid gap-2\">\n {imageParts.map((part, idx) => (\n <button\n type=\"button\"\n key={part.image_url.url}\n onClick={() => setLightboxIndex(idx)}\n className=\"cursor-zoom-in\"\n title=\"查看大图\"\n >\n <img\n src={part.image_url.url}\n alt=\"用户上传的图片\"\n className=\"max-h-64 rounded-xl border border-[hsl(var(--user-msg-border))] object-cover\"\n />\n </button>\n ))}\n {imageTextAttachments.map((attachment, idx) => (\n <button\n type=\"button\"\n key={`${attachment.uploadedPath}:${attachment.name}`}\n onClick={() => setLightboxIndex(imageParts.length + idx)}\n className=\"cursor-zoom-in\"\n title=\"查看大图\"\n >\n <img\n src={attachment.url}\n alt={attachment.name || \"用户上传的图片\"}\n className=\"max-h-64 rounded-xl border border-[hsl(var(--user-msg-border))] object-cover\"\n />\n </button>\n ))}\n </div>\n )}\n {lightboxImages.length > 0 && (\n <ImageLightbox\n open={lightboxIndex != null}\n onOpenChange={(open) => {\n if (!open) setLightboxIndex(null)\n }}\n images={lightboxImages}\n initialIndex={lightboxIndex ?? 0}\n />\n )}\n <MessageFileAttachmentList files={fileParts} />\n <TextAttachmentPills\n attachments={nonImageTextAttachments}\n onPreview={handleTextAttachmentPreview}\n />\n {preview && (\n <AttachmentPreviewDialog\n open={preview != null}\n onOpenChange={(open) => {\n if (!open) setPreview(null)\n }}\n filename={preview.filename}\n url={preview.url}\n mode={preview.mode}\n />\n )}\n <MessageContextPills contexts={textContexts} />\n {trimmedClean && (\n <div className=\"rounded-2xl border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-4 py-2.5 text-sm leading-relaxed text-[hsl(var(--user-msg-fg))] shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]\">\n <MarkdownContent\n className=\"prose prose-sm prose-invert max-w-none [&_li>p]:inline [&_p]:mb-3 [&_p:last-child]:mb-0\"\n controls={{ code: true }}\n >\n {cleanText}\n </MarkdownContent>\n </div>\n )}\n {trimmedClean && (\n <MessageActions\n content={trimmedClean}\n className=\"opacity-0 transition-opacity group-hover:opacity-100\"\n />\n )}\n </div>\n </div>\n )\n}\n\nexport function ErrorMessageBlock({\n message,\n className,\n}: {\n message: ErrorChatMessage\n className?: string\n}) {\n const text = getTextContent(message.content)\n const looksLikeModelUnavailable = /no source matches this model|404/i.test(text)\n return (\n <div className={cn(\"flex justify-center\", className)}>\n <div className=\"max-w-[85%] border-l-[3px] border-[hsl(var(--destructive))] px-4 py-1 text-sm leading-7 text-[hsl(var(--destructive))]\">\n {text}\n {looksLikeModelUnavailable ? (\n <div className=\"mt-1 opacity-80\">模型可能未启动,请稍后重试。</div>\n ) : null}\n </div>\n </div>\n )\n}\n","/**\n * 按文件扩展名决定预览渲染方式(R6)。\n *\n * 为什么按扩展名不按 MIME:当前消息 schema 里 FileContentPart / TextAttachment\n * 都只存 `name` + `uploadedPath`,没有 mime_type(见 design.md §3.6)。\n * 改 schema 面太大,扩展名在实际数据里足够稳定(前端上传时就是文件名)。\n *\n * 动图(.gif/.webp/.apng/.avif)归为 image,因为浏览器 `<img>` 原生播放。\n * video 类扩展名本期不覆盖(见 design.md §3.6 决策:\"只动图,不视频\")。\n */\n\nconst IMAGE_EXTS = [\n // 静态\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".bmp\",\n \".svg\",\n \".heic\",\n // 动图(<img> 原生播放)\n \".gif\",\n \".webp\",\n \".apng\",\n \".avif\",\n] as const\n\nconst TEXT_EXTS = [\".md\", \".json\", \".txt\", \".yaml\", \".yml\"] as const\n\nexport type PreviewKind = \"image\" | \"text\" | \"default\"\n\nexport interface PreviewDescriptor {\n kind: PreviewKind\n filename: string\n url: string\n}\n\nfunction lower(filename: string): string {\n return filename.toLowerCase()\n}\n\nfunction endsWithAny(name: string, exts: readonly string[]): boolean {\n const n = lower(name)\n for (const ext of exts) {\n if (n.endsWith(ext)) return true\n }\n return false\n}\n\n/**\n * 判断扩展名能不能用 `<img>` 预览(含动图)。\n * 独立导出是为了让调用方可以在不走完整 dispatchPreview 的场景(如 UserMessageBubble\n * 已经在 render 时把图片渲染成 <img>,不需要再走 kind 分派)直接查一次。\n */\nexport function isImageFilename(filename: string): boolean {\n return endsWithAny(filename, IMAGE_EXTS)\n}\n\nexport function isTextFilename(filename: string): boolean {\n return endsWithAny(filename, TEXT_EXTS)\n}\n\nexport function dispatchPreview(filename: string, url: string): PreviewDescriptor {\n if (isImageFilename(filename)) return { kind: \"image\", filename, url }\n if (isTextFilename(filename)) return { kind: \"text\", filename, url }\n return { kind: \"default\", filename, url }\n}\n","/**\n * 把 whatif-rerun 后端组装的 prompt 文本解析成可折叠展示的结构。\n *\n * 当前后端格式(`host/orchestrator/whatif_rerun.py::_compose_whatif_prompt`):\n *\n * 以下消息和 step 产物标记为 deprecated_by_rerun,请基于最新用户假设从 step{N} 开始完整重新推演,不要复用旧结论。\n *\n * [引用]\n * [步骤{n} · {label}]\n * {snapshot markdown…(内部允许空行)}\n * [步骤{m} · {label}]\n * {snapshot markdown…}\n *\n * [用户输入]\n * {用户真正输入的文本}\n *\n * Legacy 格式(历史 session 里没有 `[用户输入]` 标签):\n * …最后一条 snapshot 末尾…\n * <空行>\n * {用户真正输入的文本}\n *\n * Legacy 情况下用\"从末尾反向扫描第一段连续空行\"做切分。markdown 末尾段落\n * 被误吃的风险可接受——总比让用户完全看不到自己的输入好。\n */\n\nexport interface WhatIfQuote {\n stepNumber: number | null\n label: string\n snapshot: string\n}\n\nexport interface ParsedWhatIfPrompt {\n fromStep: number | null\n quotes: WhatIfQuote[]\n userText: string\n}\n\nexport interface BuildWhatIfPromptInput {\n fromStep: number\n quotes: Array<{\n stepNumber?: number | null\n label?: string | null\n snapshot?: string | null\n }>\n userText: string\n}\n\nconst HEADER_RE =\n /^以下消息和 step 产物标记为 deprecated_by_rerun,请基于最新用户假设从 step(\\d+) 开始完整重新推演,不要复用旧结论。$/\n\nconst QUOTE_HEADER_RE = /^\\[步骤(\\d+)\\s*·\\s*(.+?)\\]$/\nconst USER_INPUT_TAG = \"[用户输入]\"\n\nexport function buildWhatIfPrompt({\n fromStep,\n quotes,\n userText,\n}: BuildWhatIfPromptInput): string {\n const lines: string[] = [\n `以下消息和 step 产物标记为 deprecated_by_rerun,请基于最新用户假设从 step${fromStep} 开始完整重新推演,不要复用旧结论。`,\n ]\n if (quotes.length > 0) {\n lines.push(\"\")\n lines.push(\"[引用]\")\n for (const quote of quotes) {\n const stepNumber = Number.isFinite(quote.stepNumber) ? quote.stepNumber : null\n const label = quote.label?.trim() || \"卡片\"\n lines.push(`[步骤${stepNumber ?? \"?\"} · ${label}]`)\n lines.push(quote.snapshot ?? \"\")\n }\n }\n if (userText) {\n lines.push(\"\")\n lines.push(USER_INPUT_TAG)\n lines.push(userText)\n }\n return lines.join(\"\\n\")\n}\n\nexport function parseWhatIfPrompt(text: string): ParsedWhatIfPrompt | null {\n const trimmed = text.replace(/\\r\\n/g, \"\\n\").trimEnd()\n const lines = trimmed.split(\"\\n\")\n if (lines.length === 0) return null\n\n const headerMatch = lines[0].match(HEADER_RE)\n if (!headerMatch) return null\n\n const fromStep = Number.parseInt(headerMatch[1], 10)\n\n const userTagIdx = lines.indexOf(USER_INPUT_TAG)\n const hasUserTag = userTagIdx >= 0\n const quoteBlockEndExclusive = hasUserTag ? userTagIdx : lines.length\n\n // 收集 [引用] 段内的所有 quote header 行号\n const quoteHeaderIdxs: number[] = []\n let refBlockFound = false\n for (let i = 1; i < quoteBlockEndExclusive; i++) {\n if (!refBlockFound && lines[i].trim() === \"[引用]\") {\n refBlockFound = true\n continue\n }\n if (refBlockFound && lines[i].match(QUOTE_HEADER_RE)) {\n quoteHeaderIdxs.push(i)\n }\n }\n\n // Legacy 模式下从最后一条 snapshot 的末尾反向找\"第一段连续空行\"作为\n // snapshot / userText 分隔点。有 [用户输入] 标签时不走这条。\n let legacyUserTextStart = -1\n if (!hasUserTag && quoteHeaderIdxs.length > 0) {\n const lastSnapshotStart = quoteHeaderIdxs[quoteHeaderIdxs.length - 1] + 1\n // 从末尾(lines.length - 1)往前扫,找第一段连续空行\n let i = lines.length - 1\n // 跳过末尾可能的空行\n while (i >= lastSnapshotStart && lines[i].trim() === \"\") i -= 1\n // 回扫直到遇到空行\n while (i >= lastSnapshotStart && lines[i].trim() !== \"\") i -= 1\n // i 此时要么 < lastSnapshotStart(没找到空行,说明整个尾部都是一段文本,\n // 保留作为 snapshot 一部分),要么指向空行\n if (i >= lastSnapshotStart) {\n legacyUserTextStart = i + 1\n }\n }\n\n const quotes: WhatIfQuote[] = quoteHeaderIdxs.map((headerIdx, k) => {\n const m = lines[headerIdx].match(QUOTE_HEADER_RE)!\n const isLast = k + 1 >= quoteHeaderIdxs.length\n let endIdxExclusive: number\n if (!isLast) {\n endIdxExclusive = quoteHeaderIdxs[k + 1]\n } else if (legacyUserTextStart >= 0) {\n endIdxExclusive = legacyUserTextStart\n } else {\n endIdxExclusive = quoteBlockEndExclusive\n }\n const snapshotLines = lines.slice(headerIdx + 1, endIdxExclusive)\n while (snapshotLines.length && snapshotLines[snapshotLines.length - 1].trim() === \"\") {\n snapshotLines.pop()\n }\n return {\n stepNumber: Number.parseInt(m[1], 10),\n label: m[2].trim(),\n snapshot: snapshotLines.join(\"\\n\"),\n }\n })\n\n let userText = \"\"\n if (hasUserTag) {\n const rest = lines.slice(userTagIdx + 1)\n while (rest.length > 0 && rest[0].trim() === \"\") rest.shift()\n while (rest.length > 0 && rest[rest.length - 1].trim() === \"\") rest.pop()\n userText = rest.join(\"\\n\")\n } else if (legacyUserTextStart >= 0) {\n const rest = lines.slice(legacyUserTextStart)\n while (rest.length > 0 && rest[0].trim() === \"\") rest.shift()\n while (rest.length > 0 && rest[rest.length - 1].trim() === \"\") rest.pop()\n userText = rest.join(\"\\n\")\n }\n\n return {\n fromStep: Number.isFinite(fromStep) ? fromStep : null,\n quotes,\n userText,\n }\n}\n","import { Download, X } from \"lucide-react\"\nimport { useEffect } from \"react\"\nimport { createPortal } from \"react-dom\"\nimport { useQuery } from \"@tanstack/react-query\"\nimport { MarkdownContent } from \"../markdown/MarkdownContent\"\n\n/**\n * R6:用户上传的附件(文本 / 未知类型)预览弹窗。\n *\n * 图片走独立的 ImageLightbox;本组件处理:\n * - .md → markdown 渲染\n * - .json / .txt / .yaml / .yml / 其他文本 → 纯文本等宽展示\n * - 不可在浏览器内渲染的类型 → 下载链接兜底\n *\n * 无 URL 时兜底为只显示文件名 + 下载入口。\n */\n\ninterface Props {\n open: boolean\n onOpenChange: (open: boolean) => void\n filename: string\n /**\n * 由调用方用 `getAuthedUrl()` 构造的完整 URL(baseUrl + 路径 + ?token=…)。\n * 内部 fetch 直接用原串,**不**再走 `apiFetchText` —— 否则会二次拼 baseUrl,\n * 在独立前后端部署时会得到形如 `http://api.xxxhttp://api.xxx/…` 的非法 URL。\n * token 靠 query 字符串携带,因此也不需要再挂 Authorization header。\n */\n url: string | null\n /** text-like 视为\"可文本预览\";其他只显示下载按钮。 */\n mode: \"markdown\" | \"text\" | \"default\"\n}\n\nexport function AttachmentPreviewDialog({ open, onOpenChange, filename, url, mode }: Props) {\n useEffect(() => {\n if (!open) return\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onOpenChange(false)\n }\n window.addEventListener(\"keydown\", handleKey)\n return () => window.removeEventListener(\"keydown\", handleKey)\n }, [open, onOpenChange])\n\n const { data: content, error } = useQuery({\n queryKey: [\"attachment-preview\", url, mode],\n queryFn: async ({ signal }) => {\n if (!url) return null\n const res = await fetch(url, {\n signal,\n credentials: \"include\",\n })\n if (!res.ok) {\n const body = await res.text().catch(() => \"\")\n throw new Error(`加载失败(HTTP ${res.status})${body ? `:${body.slice(0, 200)}` : \"\"}`)\n }\n return res.text()\n },\n enabled: open && url != null && (mode === \"markdown\" || mode === \"text\"),\n staleTime: 60_000,\n })\n\n if (!open) return null\n\n const body = (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4\"\n onClick={() => onOpenChange(false)}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") onOpenChange(false)\n }}\n // biome-ignore lint/a11y/useSemanticElements: 原生 <dialog> 需要 showModal() + 内置 backdrop,本组件用外层 div 充当点击关闭的 backdrop,不走 modal API。\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"attachment-preview-title\"\n >\n <div\n className=\"max-h-[90vh] w-full max-w-3xl overflow-hidden rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--background))] shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center justify-between border-b border-[hsl(var(--border))] px-4 py-3\">\n <h3 id=\"attachment-preview-title\" className=\"truncate text-sm font-semibold text-[hsl(var(--foreground))]\">\n {filename}\n </h3>\n <div className=\"flex items-center gap-1\">\n {url && (\n <a\n href={url}\n download={filename}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title=\"下载\"\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <Download size={14} />\n </a>\n )}\n <button\n type=\"button\"\n onClick={() => onOpenChange(false)}\n title=\"关闭\"\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <X size={14} />\n </button>\n </div>\n </div>\n <div className=\"max-h-[calc(90vh-56px)] overflow-auto px-4 py-3 text-sm text-[hsl(var(--foreground))]\">\n {renderContent({ mode, url, content, error })}\n </div>\n </div>\n </div>\n )\n\n return createPortal(body, document.body)\n}\n\nfunction renderContent({\n mode,\n url,\n content,\n error,\n}: {\n mode: \"markdown\" | \"text\" | \"default\"\n url: string | null\n content: string | null | undefined\n error: unknown\n}) {\n if (!url) {\n return <p className=\"text-[hsl(var(--muted-foreground))]\">此附件暂无可用预览地址。</p>\n }\n if (mode === \"default\") {\n return (\n <p className=\"text-[hsl(var(--muted-foreground))]\">\n 此类型暂不支持内嵌预览。请点击右上角\n <span className=\"mx-1 font-medium text-[hsl(var(--foreground))]\">下载</span>\n 按钮查看。\n </p>\n )\n }\n if (error) {\n return <p className=\"text-[hsl(var(--destructive))]\">加载失败:{String((error as Error)?.message ?? error)}</p>\n }\n if (content == null) {\n return <p className=\"text-[hsl(var(--muted-foreground))]\">加载中…</p>\n }\n if (mode === \"markdown\") {\n return (\n <MarkdownContent className=\"prose prose-sm prose-invert max-w-none\">{content}</MarkdownContent>\n )\n }\n return (\n <pre className=\"whitespace-pre-wrap font-mono text-xs leading-relaxed\">{content}</pre>\n )\n}\n","import { Bookmark } from \"lucide-react\"\nimport type { ParsedTextContext } from \"../../lib/chat\"\n\ninterface MessageContextPillsProps {\n contexts: ParsedTextContext[]\n}\n\nexport function MessageContextPills({ contexts }: MessageContextPillsProps) {\n if (contexts.length === 0) return null\n\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {contexts.map((ctx, index) => (\n <div\n key={`${ctx.label}:${index}`}\n className=\"flex shrink-0 items-center gap-1.5 rounded-full border border-[hsl(var(--primary)/0.25)] bg-[hsl(var(--primary)/0.1)] px-2.5 py-1 text-[11px] text-[hsl(var(--primary)/0.85)]\"\n title={ctx.content}\n >\n <Bookmark size={12} className=\"shrink-0 text-[hsl(var(--primary)/0.65)]\" />\n <span className=\"max-w-56 truncate\">{ctx.label}</span>\n </div>\n ))}\n </div>\n )\n}\n","import { Archive, File, FileCode2, FileText, Film, Music } from \"lucide-react\"\nimport type { FileContentPart } from \"../../schemas/message\"\nimport { cn } from \"../../lib/utils\"\n\nfunction getFileIcon(fileName: string) {\n const lowerName = fileName.toLowerCase()\n\n if (/\\.(zip|rar|7z|tar|gz|bz2|xz)$/.test(lowerName)) {\n return Archive\n }\n if (/\\.(ts|tsx|js|jsx|py|rb|go|rs|java|kt|swift|c|cc|cpp|h|hpp|css|scss|html|json|yaml|yml|toml|md)$/.test(lowerName)) {\n return FileCode2\n }\n if (/\\.(mp3|wav|flac|m4a|aac|ogg)$/.test(lowerName)) {\n return Music\n }\n if (/\\.(mp4|mov|mkv|avi|webm|wmv)$/.test(lowerName)) {\n return Film\n }\n if (/\\.(txt|pdf|doc|docx|rtf|odt)$/.test(lowerName)) {\n return FileText\n }\n return File\n}\n\ninterface MessageFileAttachmentListProps {\n files: FileContentPart[]\n className?: string\n /**\n * R6:点击 pill 时的预览回调。不传时 pill 保持纯展示(向后兼容,Home /\n * ChatDev 等复用点零改动)。调用方自己决定 URL 来源 + 渲染什么(lightbox /\n * FilePreviewDialog / 下载等)。\n */\n onPreview?: (file: FileContentPart) => void\n}\n\nexport function MessageFileAttachmentList({\n files,\n className,\n onPreview,\n}: MessageFileAttachmentListProps) {\n if (files.length === 0) {\n return null\n }\n\n const pillClass =\n \"flex shrink-0 items-center gap-1.5 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-2.5 py-1 text-[11px] text-[hsl(var(--foreground))]\"\n\n return (\n <div className={cn(\"flex flex-wrap gap-1.5\", className)}>\n {files.map((file) => {\n const Icon = getFileIcon(file.name)\n const key = `${file.name}-${file.data.slice(0, 32)}`\n const content = (\n <>\n <Icon size={12} className=\"shrink-0 text-[hsl(var(--muted-foreground))]\" />\n <span className=\"max-w-32 truncate\">{file.name}</span>\n </>\n )\n if (onPreview) {\n return (\n <button\n key={key}\n type=\"button\"\n onClick={() => onPreview(file)}\n className={cn(pillClass, \"cursor-pointer transition-colors hover:border-[hsl(var(--ring)/0.5)]\")}\n title={`预览 ${file.name}`}\n >\n {content}\n </button>\n )\n }\n return (\n <div key={key} className={pillClass} title={file.name}>\n {content}\n </div>\n )\n })}\n </div>\n )\n}\n","import { Check, Copy } from \"lucide-react\"\nimport { useState } from \"react\"\nimport { cn, copyToClipboard } from \"../../lib/utils\"\n\ninterface Props {\n content: string\n className?: string\n}\n\nexport function MessageActions({ content, className }: Props) {\n const [copied, setCopied] = useState(false)\n\n const handleCopy = async () => {\n const ok = await copyToClipboard(content)\n if (ok) {\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n }\n\n return (\n <div className={cn(\"flex items-center gap-1 mt-1.5\", className)}>\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n \"flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] transition-colors\",\n copied\n ? \"text-[hsl(var(--primary))]\"\n : \"text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))] hover:bg-[hsl(var(--accent))]\",\n )}\n >\n {copied ? <Check size={12} /> : <Copy size={12} />}\n <span>{copied ? \"已复制\" : \"复制\"}</span>\n </button>\n </div>\n )\n}\n","import { Archive, File, FileCode2, FileText, Film, Music, FileSpreadsheet, Image } from \"lucide-react\"\nimport type { ParsedTextAttachment } from \"../../lib/chat\"\n\nfunction getFileIcon(fileName: string) {\n const lower = fileName.toLowerCase()\n if (/\\.(zip|rar|7z|tar|gz)$/.test(lower)) return Archive\n if (/\\.(ts|tsx|js|jsx|py|go|rs|java|html|json|yaml|yml|css)$/.test(lower)) return FileCode2\n if (/\\.(mp3|wav|flac|m4a|aac|ogg)$/.test(lower)) return Music\n if (/\\.(mp4|mov|mkv|avi|webm)$/.test(lower)) return Film\n if (/\\.(png|jpg|jpeg|gif|svg|webp|bmp)$/.test(lower)) return Image\n if (/\\.(xlsx?|csv)$/.test(lower)) return FileSpreadsheet\n if (/\\.(txt|pdf|docx?|rtf|md)$/.test(lower)) return FileText\n return File\n}\n\ninterface TextAttachmentPillsProps {\n attachments: ParsedTextAttachment[]\n /**\n * R6:点击 pill 时的预览回调。不传时保持纯展示(向后兼容)。\n */\n onPreview?: (attachment: ParsedTextAttachment) => void\n}\n\nexport function TextAttachmentPills({ attachments, onPreview }: TextAttachmentPillsProps) {\n if (attachments.length === 0) return null\n\n const pillClass =\n \"flex shrink-0 items-center gap-1.5 rounded-full border border-[hsl(var(--primary)/0.2)] bg-[hsl(var(--primary)/0.08)] px-2.5 py-1 text-[11px] text-[hsl(var(--primary)/0.8)]\"\n\n return (\n <div className=\"flex flex-wrap gap-1.5\">\n {attachments.map((att, index) => {\n const Icon = getFileIcon(att.name)\n const key = `${att.uploadedPath ?? att.name}:${att.name}:${index}`\n const content = (\n <>\n <Icon size={12} className=\"shrink-0 text-[hsl(var(--primary)/0.6)]\" />\n <span className=\"max-w-40 truncate\">{att.name}</span>\n </>\n )\n if (onPreview) {\n return (\n <button\n key={key}\n type=\"button\"\n onClick={() => onPreview(att)}\n className={`${pillClass} cursor-pointer transition-colors hover:border-[hsl(var(--primary)/0.45)]`}\n title={`预览 ${att.name}`}\n >\n {content}\n </button>\n )\n }\n return (\n <div key={key} className={pillClass} title={att.name}>\n {content}\n </div>\n )\n })}\n </div>\n )\n}\n","import { RefreshCcw } from \"lucide-react\"\nimport { MarkdownContent } from \"../markdown/MarkdownContent\"\nimport type { ParsedWhatIfPrompt } from \"../../lib/whatif-prompt\"\nimport { useWhatIfQuoteContext } from \"./whatif-quote-context\"\n\ninterface Props {\n parsed: ParsedWhatIfPrompt\n /** 点击引用 chip 时回调。如果未传,尝试从 WhatIfQuoteProvider 取;两者都无则 chip 不可点。 */\n onQuoteClick?: (stepNumber: number) => void\n}\n\n/**\n * what-if 重跑 prompt 的紧凑展示:小徽章 + 步骤跳转 chip + 用户真正输入气泡。\n * 原 prompt 里夹带的 snapshot markdown 不再全量展开——它们对 LLM 有用,\n * 但对用户只会造成噪音;点 chip 可以跳到对应 step 卡查看。\n */\nexport function WhatIfUserBubble({ parsed, onQuoteClick }: Props) {\n const { onJumpToStep } = useWhatIfQuoteContext()\n const handleQuoteClick = onQuoteClick ?? onJumpToStep\n const { fromStep, quotes, userText } = parsed\n\n return (\n <div className=\"flex flex-col items-end gap-2\">\n <div className=\"flex items-center gap-1.5 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.5)] px-2.5 py-0.5 text-[10px] text-[hsl(var(--muted-foreground))]\">\n <RefreshCcw size={10} />\n <span>{fromStep != null ? `重跑自 step ${fromStep}` : \"重跑\"}</span>\n </div>\n\n {quotes.length > 0 && (\n <div className=\"flex flex-wrap justify-end gap-1.5\">\n {quotes.map((q, i) => {\n const clickable = q.stepNumber != null && !!handleQuoteClick\n const label =\n q.stepNumber != null ? `步骤${q.stepNumber} · ${q.label}` : q.label\n return (\n <button\n key={`${q.stepNumber ?? \"x\"}-${i}`}\n type=\"button\"\n disabled={!clickable}\n onClick={() => clickable && handleQuoteClick!(q.stepNumber!)}\n className=\"inline-flex items-center gap-1 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-2.5 py-0.5 text-[11px] text-[hsl(var(--muted-foreground))] transition-colors hover:border-[hsl(var(--ring)/0.5)] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] disabled:cursor-default disabled:hover:border-[hsl(var(--border))] disabled:hover:bg-[hsl(var(--card))]\"\n title={clickable ? \"跳转到对应步骤卡片\" : undefined}\n >\n <span>↳</span>\n <span className=\"max-w-[14rem] truncate\">{label}</span>\n </button>\n )\n })}\n </div>\n )}\n\n {userText && (\n <div className=\"rounded-2xl border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-4 py-2.5 text-sm leading-relaxed text-[hsl(var(--user-msg-fg))] shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]\">\n <MarkdownContent\n className=\"prose prose-sm prose-invert max-w-none [&_li>p]:inline [&_p]:mb-3 [&_p:last-child]:mb-0\"\n controls={{ code: true }}\n >\n {userText}\n </MarkdownContent>\n </div>\n )}\n </div>\n )\n}\n","import { createContext, type ReactNode, useContext, useMemo } from \"react\"\n\ninterface WhatIfQuoteContextValue {\n onJumpToStep?: (stepNumber: number) => void\n}\n\nconst WhatIfQuoteContext = createContext<WhatIfQuoteContextValue>({})\n\n/**\n * Provide a callback used by `WhatIfUserBubble`'s quote chip to navigate to\n * the corresponding step card. Host apps (ship-attack) mount this provider\n * near the chat view and wire it to their step selector.\n */\nexport function WhatIfQuoteProvider({\n onJumpToStep,\n children,\n}: {\n onJumpToStep?: (stepNumber: number) => void\n children: ReactNode\n}) {\n const value = useMemo(() => ({ onJumpToStep }), [onJumpToStep])\n return <WhatIfQuoteContext.Provider value={value}>{children}</WhatIfQuoteContext.Provider>\n}\n\nexport function useWhatIfQuoteContext(): WhatIfQuoteContextValue {\n return useContext(WhatIfQuoteContext)\n}\n","import { ChevronDown, ChevronRight, Loader2, Square, XCircle } from \"lucide-react\"\nimport { useState } from \"react\"\nimport { getSocket } from \"../../api/socket\"\nimport type { ArchivedFileInfo, ArchivedToolCallInfo, CompactionInfo } from \"../../schemas/message\"\nimport { useChatStore } from \"../../stores/chat-store\"\nimport { cn } from \"../../lib/utils\"\n\nconst PERCENT_FORMATTER = new Intl.NumberFormat(\"zh-CN\", {\n style: \"percent\",\n maximumFractionDigits: 0,\n})\nfunction formatTokens(value: number | null | undefined) {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n return \"0\"\n }\n const k = value / 1000\n if (k < 1) {\n return `${Math.round(value)}`\n }\n return k < 10 ? `${k.toFixed(1)}k` : `${Math.round(k)}k`\n}\n\nfunction formatSavedRatio(value: number | null | undefined) {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n return \"0%\"\n }\n return PERCENT_FORMATTER.format(Math.max(0, Math.min(1, value)))\n}\n\nfunction shortId(compactionId: string | undefined) {\n if (!compactionId) {\n return \"------\"\n }\n return compactionId.slice(0, 6)\n}\n\ntype CompactionCardState = CompactionInfo & {\n status: \"streaming\" | \"completed\" | \"paused\" | \"failed\" | \"interrupted\"\n}\n\nconst ARCHIVED_TOOL_LABELS: Record<string, string> = {\n GetSkillContent: \"读取技能内容\",\n SearchSkills: \"搜索技能\",\n ListSkillTools: \"列出技能工具\",\n LoadSkillTools: \"加载技能工具\",\n}\n\nfunction getArchivedToolLabel(item: ArchivedToolCallInfo) {\n const name = item.tool_name?.trim()\n if (!name) {\n return \"工具调用\"\n }\n return ARCHIVED_TOOL_LABELS[name] ?? name\n}\n\nfunction getArchivePath(item: ArchivedToolCallInfo, files: ArchivedFileInfo[]) {\n if (item.archive_path) {\n return item.archive_path\n }\n return files.find((file) => file.tool_name === item.tool_name)?.relative_path ?? null\n}\n\nfunction isGenericArchiveSummary(summary: string | null | undefined) {\n return /^已归档\\s*\\d+\\s*个大型工具结果。?$/.test(summary?.trim() ?? \"\")\n}\n\nexport function CompactionCard({\n sessionId,\n compaction,\n status,\n}: {\n sessionId: string\n compaction?: CompactionInfo | null\n status?: \"streaming\" | \"completed\" | \"paused\" | \"failed\" | \"interrupted\"\n}) {\n const activeCompaction = useChatStore((state) => state.activeCompactions[sessionId] ?? null)\n const source = compaction\n ? ({\n ...compaction,\n status: status ?? \"completed\",\n } satisfies CompactionCardState)\n : activeCompaction\n const [expanded, setExpanded] = useState(false)\n\n if (!source || !source.compaction_id) {\n return null\n }\n\n const canCancel = source.status === \"streaming\"\n const archivedFiles = source.archived_files ?? []\n const archivedToolCalls = source.archived_tool_calls ?? []\n const archivedCount = source.archived_count ?? archivedToolCalls.length ?? archivedFiles.length\n const hasSummary =\n typeof source.summary_full === \"string\" &&\n source.summary_full.trim().length > 0 &&\n !isGenericArchiveSummary(source.summary_full)\n const hasFailureReason = source.status === \"failed\" && Boolean(source.failure_reason)\n const canExpand =\n (source.status === \"completed\" && (hasSummary || archivedToolCalls.length > 0)) ||\n hasFailureReason\n\n return (\n <div className=\"text-xs text-[hsl(var(--muted-foreground))]\">\n <div className=\"flex items-center justify-between gap-2\">\n <button\n type=\"button\"\n onClick={() => canExpand && setExpanded((prev) => !prev)}\n className={cn(\n \"inline-flex min-w-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] text-[hsl(var(--muted-foreground))]/65 transition-colors hover:bg-[hsl(var(--muted))]/60 hover:text-[hsl(var(--foreground))]\",\n !canExpand && \"cursor-default hover:bg-transparent hover:text-[hsl(var(--muted-foreground))]/65\",\n )}\n aria-expanded={expanded}\n >\n {canExpand ? (\n expanded ? (\n <ChevronDown size={12} className=\"shrink-0\" />\n ) : (\n <ChevronRight size={12} className=\"shrink-0\" />\n )\n ) : null}\n <span>\n {source.status === \"streaming\" ? (\n <span className=\"inline-flex items-center gap-1\">\n <Loader2 size={12} className=\"animate-spin\" />\n 正在压缩上下文\n </span>\n ) : source.status === \"failed\" ? (\n <span className=\"inline-flex items-center gap-1 text-rose-500/80\">\n <XCircle size={12} />\n 上下文压缩失败\n </span>\n ) : source.status === \"interrupted\" ? (\n <span className=\"inline-flex items-center gap-1 text-amber-500/80\">\n <Square size={11} />\n 上下文压缩已取消\n </span>\n ) : (\n \"上下文已压缩\"\n )}\n </span>\n </button>\n\n {canCancel ? (\n <button\n type=\"button\"\n onClick={() => getSocket().stop(sessionId)}\n className=\"shrink-0 rounded-md border border-current/15 px-2 py-0.5 text-[11px] transition-opacity hover:opacity-80\"\n >\n 取消整理\n </button>\n ) : null}\n </div>\n\n {expanded ? (\n <div className=\"mt-1 max-w-3xl rounded-lg border border-[hsl(var(--border))]/70 bg-[hsl(var(--card))]/80 px-3 py-2 text-[11px] leading-relaxed shadow-sm\">\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1 text-[hsl(var(--muted-foreground))]\">\n <span>#{shortId(source.compaction_id)}</span>\n <span>\n 节省 {formatSavedRatio(source.saved_ratio)}({formatTokens(source.tokens_before)} →{\" \"}\n {formatTokens(source.tokens_after)} token)\n </span>\n <span>归档 {archivedCount} 个工具结果</span>\n </div>\n\n {archivedToolCalls.length > 0 ? (\n <div className=\"mt-2 space-y-1.5\">\n {archivedToolCalls.map((item, index) => {\n const archivePath = getArchivePath(item, archivedFiles)\n return (\n <div\n key={item.tool_call_id || item.entry_id || `${item.tool_name}-${index}`}\n className=\"rounded-md border border-[hsl(var(--border))]/70 bg-[hsl(var(--muted))]/35 px-2 py-1.5\"\n >\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1 text-[hsl(var(--foreground))]\">\n <span className=\"font-medium\">{getArchivedToolLabel(item)}</span>\n {item.tool_call_id ? (\n <span className=\"font-mono text-[10px] text-[hsl(var(--muted-foreground))]\">\n {item.tool_call_id}\n </span>\n ) : null}\n </div>\n {archivePath ? (\n <div className=\"mt-0.5 break-all font-mono text-[10px] text-[hsl(var(--muted-foreground))]\">\n {archivePath}\n </div>\n ) : null}\n </div>\n )\n })}\n </div>\n ) : null}\n\n {hasSummary ? (\n <pre className=\"mt-2 max-h-[360px] overflow-auto whitespace-pre-wrap rounded-md border border-[hsl(var(--border))]/70 bg-[hsl(var(--muted))]/25 px-2 py-1.5 font-mono text-[11px] leading-relaxed text-[hsl(var(--foreground))]\">\n {source.summary_full}\n </pre>\n ) : null}\n\n {source.status === \"failed\" && source.failure_reason ? (\n <div className=\"mt-2 text-rose-500/90\">失败原因:{source.failure_reason}</div>\n ) : null}\n </div>\n ) : null}\n </div>\n )\n}\n","import { AlertTriangle } from \"lucide-react\"\nimport { Component, type ErrorInfo, type ReactNode } from \"react\"\n\ninterface Props {\n label: string\n details?: string\n resetKey?: string\n children: ReactNode\n}\n\ninterface State {\n componentStack: string\n error: Error | null\n}\n\nfunction getFirstComponentName(componentStack: string): string | null {\n const match = componentStack.match(/\\n\\s+at\\s+([^\\s(]+)/)\n return match?.[1] ?? null\n}\n\nexport class RenderErrorBoundary extends Component<Props, State> {\n state: State = {\n componentStack: \"\",\n error: null,\n }\n\n static getDerivedStateFromError(error: Error): State {\n return {\n componentStack: \"\",\n error,\n }\n }\n\n componentDidCatch(error: Error, info: ErrorInfo) {\n const componentStack = info.componentStack ?? \"\"\n console.error(`${this.props.label} render error:`, error, info)\n this.setState({ componentStack })\n }\n\n componentDidUpdate(prevProps: Props) {\n if (this.state.error && prevProps.resetKey !== this.props.resetKey) {\n this.setState({ componentStack: \"\", error: null })\n }\n }\n\n render() {\n const { children, details, label } = this.props\n const { componentStack, error } = this.state\n\n if (!error) {\n return children\n }\n\n const componentName = getFirstComponentName(componentStack)\n\n return (\n <div className=\"rounded-xl border border-amber-500/30 bg-amber-500/8 px-4 py-3 text-sm text-amber-100\">\n <div className=\"flex items-start gap-2\">\n <AlertTriangle className=\"mt-0.5 h-4 w-4 shrink-0 text-amber-300\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-medium\">{label}渲染失败</div>\n <div className=\"mt-1 break-words text-xs leading-5 text-amber-100/75\">\n {componentName ? `组件:${componentName}。` : null}\n {error.message || \"发生了未预期的渲染错误。\"}\n </div>\n {details ? (\n <div className=\"mt-1 truncate text-xs text-amber-100/55\">{details}</div>\n ) : null}\n </div>\n </div>\n </div>\n )\n }\n}\n","import {\n Bot,\n FilePenLine,\n FileSearch,\n Globe,\n LoaderCircle,\n MessageSquareText,\n Search,\n TerminalSquare,\n WandSparkles,\n type LucideIcon,\n} from \"lucide-react\"\nimport { useEffect, useMemo, useState } from \"react\"\nimport type { ChatMessage, ToolCallInfo } from \"../../schemas/message\"\nimport { useRuntimeStore } from \"../../stores/runtime-store\"\nimport { formatToolName, getToolDisplayLabel } from \"./display-utils\"\n\nconst EMPTY_EVENTS = [] as const\n\nfunction formatElapsedDuration(durationMs: number | null) {\n if (durationMs == null) return null\n\n const totalSeconds = Math.max(0, Math.floor(durationMs / 1000))\n const hours = Math.floor(totalSeconds / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n\n if (hours > 0) {\n return `${hours}:${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`\n }\n\n return `${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`\n}\n\nfunction getToolIcon(toolCall: ToolCallInfo): LucideIcon {\n switch (formatToolName(toolCall.name)) {\n case \"Agent\":\n return Bot\n case \"Bash\":\n case \"BgBash\":\n return TerminalSquare\n case \"Read\":\n return FileSearch\n case \"Write\":\n case \"Edit\":\n return FilePenLine\n case \"Ls\":\n case \"Glob\":\n case \"Grep\":\n return Search\n case \"WebSearch\":\n case \"WebFetch\":\n return Globe\n case \"AskUserQuestion\":\n return MessageSquareText\n default:\n return WandSparkles\n }\n}\n\nfunction getLatestPendingTool(messages: ChatMessage[]) {\n const toolCalls = messages.flatMap((message) => message.tool_calls ?? [])\n for (let index = toolCalls.length - 1; index >= 0; index -= 1) {\n if (toolCalls[index].status === \"pending\" || toolCalls[index].status === \"awaiting_answer\") {\n return toolCalls[index]\n }\n }\n return null\n}\n\nfunction getCurrentAction(messages: ChatMessage[]) {\n const pendingTool = getLatestPendingTool(messages)\n if (pendingTool) {\n return {\n Icon: getToolIcon(pendingTool),\n label:\n pendingTool.status === \"awaiting_answer\"\n ? `等待你回答:${getToolDisplayLabel(pendingTool)}`\n : `正在${getToolDisplayLabel(pendingTool)}`,\n }\n }\n\n const lastMessage = messages[messages.length - 1]\n if (lastMessage?.reasoning?.trim()) {\n return {\n Icon: WandSparkles,\n label: \"正在整理思路\",\n }\n }\n\n return {\n Icon: LoaderCircle,\n label: \"正在生成回复\",\n }\n}\n\nfunction getTurnStartedAt(events: readonly { type: string; timestamp: string }[]) {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n if (events[index].type !== \"chat:start\") continue\n const timestamp = new Date(events[index].timestamp).getTime()\n if (!Number.isNaN(timestamp)) {\n return timestamp\n }\n }\n return null\n}\n\nfunction useElapsedDuration(startedAt: number | null, active: boolean) {\n const [now, setNow] = useState(() => Date.now())\n\n useEffect(() => {\n if (!active || startedAt == null) {\n return\n }\n\n setNow(Date.now())\n const timer = window.setInterval(() => {\n setNow(Date.now())\n }, 1000)\n\n return () => window.clearInterval(timer)\n }, [active, startedAt])\n\n if (!active || startedAt == null) {\n return null\n }\n\n return Math.max(0, now - startedAt)\n}\n\ninterface StickyStatusBarProps {\n sessionId: string\n messages: ChatMessage[]\n isStreaming: boolean\n isLastTurn: boolean\n onJumpToLatest: () => void\n}\n\nexport function StickyStatusBar({\n sessionId,\n messages,\n isStreaming,\n isLastTurn,\n onJumpToLatest,\n}: StickyStatusBarProps) {\n const events = useRuntimeStore((state) => state.events[sessionId] ?? EMPTY_EVENTS)\n const startedAt = useMemo(() => getTurnStartedAt(events), [events])\n const elapsedDuration = useElapsedDuration(startedAt, isStreaming && isLastTurn)\n const action = useMemo(() => getCurrentAction(messages), [messages])\n\n if (!isStreaming || !isLastTurn) {\n return null\n }\n\n const elapsedLabel = formatElapsedDuration(elapsedDuration)\n const Icon = action.Icon\n\n return (\n <button\n type=\"button\"\n onClick={onJumpToLatest}\n className=\"sticky top-0 z-20 mb-4 flex w-full items-center gap-3 rounded-2xl border border-[hsl(var(--primary)/0.2)] bg-[hsl(var(--background)/0.92)] px-4 py-3 text-left shadow-[0_12px_32px_-24px_hsl(var(--foreground)/0.6)] backdrop-blur\"\n >\n <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-[hsl(var(--primary)/0.12)] text-[hsl(var(--primary))]\">\n <Icon size={18} className={Icon === LoaderCircle ? \"animate-spin\" : undefined} />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-medium text-[hsl(var(--foreground))]\">\n {action.label}\n </div>\n <div className=\"mt-1 flex flex-wrap items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]\">\n {elapsedLabel ? <span className=\"font-mono\">已持续 {elapsedLabel}</span> : null}\n <span>点击跳到最新位置</span>\n </div>\n </div>\n </button>\n )\n}\n","import { cn } from \"../../lib/utils\"\n\nexport interface TurnNavItem {\n id: string\n title: string\n}\n\ninterface TurnNavRailProps {\n items: TurnNavItem[]\n activeTurnId: string | null\n onSelectTurn: (turnId: string) => void\n}\n\nexport function TurnNavRail({\n items,\n activeTurnId,\n onSelectTurn,\n}: TurnNavRailProps) {\n if (items.length < 2) {\n return null\n }\n\n return (\n <nav\n aria-label=\"回合导航\"\n className=\"absolute right-2 top-4 z-10 hidden flex-col items-end gap-0.5 md:flex\"\n >\n {items.map((item, index) => {\n const isActive = item.id === activeTurnId\n\n return (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => onSelectTurn(item.id)}\n aria-current={isActive ? \"true\" : undefined}\n className=\"group relative flex h-3.5 items-center\"\n >\n <span className=\"pointer-events-none absolute right-full mr-2 hidden max-w-48 truncate whitespace-nowrap rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--popover))] px-2.5 py-1.5 text-xs text-[hsl(var(--popover-foreground))] shadow-lg group-hover:block\">\n {item.title || `第 ${index + 1} 轮`}\n </span>\n <span\n className={cn(\n \"block rounded-full transition-all\",\n isActive\n ? \"h-1 w-5 bg-[hsl(var(--primary))]\"\n : \"h-0.5 w-3 bg-[hsl(var(--muted-foreground)/0.3)] group-hover:h-1 group-hover:w-5 group-hover:bg-[hsl(var(--muted-foreground)/0.6)]\",\n )}\n />\n </button>\n )\n })}\n </nav>\n )\n}\n"],"mappings":"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","names":["useCallback","mode","File","Loader2","Sparkles","X","useQueryClient","useEffect","useEffectEvent","useMemo","useRef","useState","useCallback","useEffect","useRef","useCallback","useEffect","useCallback","useEffect","useRef","useEffect","useCallback","useEffect","useRef","useState","r","jsx","useState","useRef","useEffect","useCallback","useEffect","useMemo","useState","useMemo","useMemo","useCallback","useMemo","useState","jsx","jsxs","segments","FileCompletionMenu","useMemo","FileCompletionMenuContent","useState","useCallback","forwardRef","useCallback","useImperativeHandle","useState","jsx","jsxs","SkillCompletionMenu","useEffect","jsx","jsxs","useEffect","useQuery","useMemo","useQuery","useQuery","useQuery","useQuery","useQuery","useQuery","useMemo","useMemo","jsx","jsxs","jsx","jsxs","useQuery","useMemo","Mention","PluginKey","jsx","jsxs","File","Loader2","X","useState","r","useEffectEvent","useRef","useEffect","useQueryClient","useMemo","Sparkles","jsx","jsxs","ChevronDown","Lightbulb","useCallback","useEffect","useEffectEvent","useMemo","useRef","useState","useCallback","useMemo","useRef","useState","isAtBottom","escapedFromLock","useEffect","useImperativeHandle","useMemo","useRef","useEffect","useRef","useMemo","targetScrollTop","useImperativeHandle","StickToBottom","Check","ChevronRight","useCallback","useEffect","useMemo","useRef","useState","createContext","memo","useCallback","useContext","useEffect","useMemo","useRef","useState","createPortal","useMemo","jsx","Component","Fragment","jsx","jsxs","createContext","useContext","memo","useRef","useState","useEffect","useCallback","useMemo","createPortal","Check","ChevronRight","FileText","Loader2","MessageSquareMore","useEffect","useMemo","useState","useEffect","useEffectEvent","useRef","useState","jsx","useRef","useState","useEffect","useEffectEvent","ChevronRight","Loader2","X","useMemo","useState","jsx","jsx","jsxs","jsx","jsxs","row","col","useState","ChevronRight","Download","Plus","X","useCallback","useEffect","useRef","useState","createPortal","Fragment","jsx","jsxs","jsx","jsxs","useState","ExternalLink","FileText","Folder","jsx","jsxs","Folder","FileText","ExternalLink","Fragment","jsx","jsxs","useState","useMemo","Loader2","X","ChevronRight","useState","Download","X","useEffect","createPortal","useQuery","jsx","jsxs","useEffect","useQuery","body","Download","X","createPortal","jsx","jsxs","Archive","File","FileCode2","FileText","Film","Music","Fragment","jsx","jsxs","Archive","FileCode2","Music","Film","FileText","File","Check","useState","jsx","jsxs","useState","Check","Archive","File","FileCode2","FileText","Film","Music","Fragment","jsx","jsxs","getFileIcon","lower","createContext","useContext","useMemo","jsx","jsx","jsxs","jsx","jsxs","useState","lower","Fragment","jsx","jsxs","EMPTY_MESSAGES","useMemo","useState","useEffect","MessageSquareMore","ChevronRight","Loader2","Check","FileText","jsx","jsxs","formatToolDuration","parseToolArguments","childMessages","useMemo","useState","useRef","useEffect","ChevronRight","Check","useCallback","r","ChevronDown","ChevronRight","Loader2","Square","useState","jsx","jsxs","useState","ChevronDown","ChevronRight","Loader2","Square","AlertTriangle","jsx","jsxs","Bot","LoaderCircle","useEffect","useMemo","useState","jsx","jsxs","Bot","LoaderCircle","useState","useEffect","useMemo","jsx","jsxs","jsx","jsxs","useMemo","useRef","useState","useEffectEvent","useEffect","useCallback","ChevronDown","Lightbulb","jsx","jsxs","useCallback"]}
|