@blade-hq/agent-react 2608.0.5 → 2608.0.6

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/context.tsx","../src/hooks/use-agent-session.ts","../src/components/ChatView.tsx","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/shared/src/utils.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/defaultAttributes.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/Icon.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/createLucideIcon.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/archive.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/arrow-up.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/bot.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/brain.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/check.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/chevron-down.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/chevron-right.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/circle-alert.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/copy.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/download.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/file-code-2.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/file-spreadsheet.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/file-text.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/file.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/film.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/image.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/layers.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/lightbulb.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/loader-circle.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/lock-keyhole.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/message-square-more.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/message-square.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/music.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/square.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/triangle-alert.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/x.ts","../src/lib/utils.ts","../src/components/ChatInput.tsx","../src/components/ConnectionBanner.tsx","../src/components/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/components/AssistantTurnBlock.tsx","../src/components/AgentLoopBlock.tsx","../src/components/display-utils.ts","../src/components/MarkdownContent.tsx","../src/lib/media-tags.ts","../src/components/FileCard.tsx","../src/components/Shimmer.tsx","../src/components/ToolCallBlock.tsx","../src/components/AskUserQuestionBlock.tsx","../src/components/RenderErrorBoundary.tsx","../src/components/UserMessageBubble.tsx","../src/index.ts"],"sourcesContent":["import type { BladeClient } from \"@blade-hq/agent-client\"\nimport { createContext, useContext, type ReactNode } from \"react\"\n\nconst BladeClientContext = createContext<BladeClient | null>(null)\n\nexport interface BladeProviderProps {\n client: BladeClient\n children: ReactNode\n}\n\n/**\n * 提供 client 级共享(一条连接、一份鉴权)。不含任何全局状态:\n * 同一 Provider 下多个 ChatView / useAgentSession 各自独立。\n */\nexport function BladeProvider({ client, children }: BladeProviderProps) {\n return <BladeClientContext.Provider value={client}>{children}</BladeClientContext.Provider>\n}\n\n/** 读取当前 BladeProvider 提供的 client。不在 Provider 内使用时抛错。 */\nexport function useBladeClient(): BladeClient {\n const client = useContext(BladeClientContext)\n if (!client) {\n throw new Error(\"useBladeClient 必须在 <BladeProvider> 内使用\")\n }\n return client\n}\n","import type {\n AgentSession,\n CreateSessionRequest,\n SessionState,\n} from \"@blade-hq/agent-client\"\nimport { useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\"\nimport { useBladeClient } from \"../context\"\n\nexport interface UseAgentSessionOptions {\n /** 不传 sessionId 时按此配置新建会话;两者都不传则新建默认对话。 */\n createOptions?: CreateSessionRequest\n /** 自动创建出的 sessionId 通过此回调交还调用方持有(重挂载复用的依据)。 */\n onSessionCreated?: (sessionId: string) => void\n}\n\nexport interface UseAgentSessionResult {\n /** 连接/创建完成前为 null。 */\n session: AgentSession | null\n /** 会话状态快照;session 未就绪时为 null。 */\n state: SessionState | null\n /** 连接或创建失败的错误。 */\n error: Error | null\n}\n\nconst EMPTY_SUBSCRIBE = () => () => {}\n\n/** 卸载后延迟释放引用:StrictMode/路由抖动的立即重挂载会在窗口内重新\n * connect(引用计数 +1),延迟 dispose 只把计数减回去,实例得以复用;\n * 真正的卸载则在窗口结束后正常释放订阅。 */\nconst DISPOSE_DELAY_MS = 1000\n\n/**\n * 连接(或创建)一个会话并订阅其状态。\n *\n * - 优先级:sessionId(连接既有会话)> createOptions(按配置新建)> 默认新建。\n * - 同一 sessionId 重复调用复用同一 AgentSession 实例(SessionHub 引用计数)。\n * - 自动创建只发生一次(含 StrictMode 双跑);创建出的 id 经 onSessionCreated\n * 交还调用方。\n *\n * **连接与 sessionId 变更分离**:连接在挂载时建立、仅在卸载时释放;只有\n * 当 sessionId 明确切到一个「与当前已连接会话不同」的 id 时才重连。这样宿主\n * (如 Vue 把自动创建的 id 写回 `session-id` 属性)回填同一个 id 不会触发\n * 拆–重连——否则会把正在流式的会话换成新实例、当前渲染整个丢失。\n */\nexport function useAgentSession(\n sessionId?: string,\n options: UseAgentSessionOptions = {},\n): UseAgentSessionResult {\n const client = useBladeClient()\n const [session, setSession] = useState<AgentSession | null>(null)\n const [error, setError] = useState<Error | null>(null)\n\n // 当前连接:id + 实例 + 一个递增的「代」号,用于让过期的异步连接结果作废。\n const connRef = useRef<{ id: string | null; session: AgentSession | null; gen: number }>({\n id: null,\n session: null,\n gen: 0,\n })\n // 自动创建去重:StrictMode 双跑时同一组件实例只创建一次会话。\n const createdIdPromiseRef = useRef<Promise<string> | null>(null)\n const onCreatedRef = useRef(options.onSessionCreated)\n onCreatedRef.current = options.onSessionCreated\n const createOptionsRef = useRef(options.createOptions)\n createOptionsRef.current = options.createOptions\n // 最新的目标 sessionId,供挂载 effect 的异步链读取(不进依赖,避免重连)。\n const sessionIdRef = useRef(sessionId)\n sessionIdRef.current = sessionId\n\n // 把「连接到某个 id / 自动创建」封成一次操作;gen 作废过期结果。\n const connect = useMemo(() => {\n return (targetId: string | undefined) => {\n const gen = ++connRef.current.gen\n const idPromise = targetId\n ? Promise.resolve(targetId)\n : // biome-ignore lint/suspicious/noAssignInExpressions: ??= 挂 ref 是 StrictMode 下\"只创建一次\"的关键\n (createdIdPromiseRef.current ??= client.sessions\n .create(createOptionsRef.current ?? {})\n .then((created) => {\n // create() 的实例引用立即归还,由下面的 connect() 统一取,避免多挂一份计数\n const id = created.sessionId\n created.dispose()\n onCreatedRef.current?.(id)\n return id\n }))\n\n idPromise\n .then((id) => client.hub.connect(id))\n .then((next) => {\n if (connRef.current.gen !== gen) {\n next.dispose() // 已被更新的连接请求取代\n return\n }\n connRef.current.id = next.sessionId\n connRef.current.session = next\n setSession(next)\n setError(null)\n })\n .catch((err) => {\n if (connRef.current.gen !== gen) return\n createdIdPromiseRef.current = null // 创建失败允许下次重试\n setError(err instanceof Error ? err : new Error(String(err)))\n })\n }\n }, [client])\n\n // 挂载时建立连接,仅在卸载(或 client 变化)时释放。\n useEffect(() => {\n connect(sessionIdRef.current)\n return () => {\n connRef.current.gen++ // 作废在途的连接结果\n const toRelease = connRef.current.session\n connRef.current.id = null\n connRef.current.session = null\n setSession(null)\n if (toRelease) setTimeout(() => toRelease.dispose(), DISPOSE_DELAY_MS)\n }\n }, [connect])\n\n // 仅当 sessionId 明确切到「与已连接会话不同」的 id 时才重连。\n // 回填自动创建的 id(sessionId === 已连接 id)在此被跳过。\n useEffect(() => {\n if (!sessionId) return\n if (connRef.current.id === null) return // 首连仍在进行,交给挂载 effect\n if (sessionId === connRef.current.id) return\n const previous = connRef.current.session\n connRef.current.id = null\n connRef.current.session = null\n if (previous) setTimeout(() => previous.dispose(), DISPOSE_DELAY_MS)\n connect(sessionId)\n }, [sessionId, connect])\n\n const store = useMemo(\n () => ({\n subscribe: session ? (listener: () => void) => session.subscribe(listener) : EMPTY_SUBSCRIBE,\n getSnapshot: () => (session ? session.getState() : null),\n }),\n [session],\n )\n const state = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot)\n\n return { session, state, error }\n}\n","import type { AgentSession, BladeClient, CreateSessionRequest } from \"@blade-hq/agent-client\"\nimport { BladeApiError } from \"@blade-hq/agent-client\"\nimport { CircleAlert, LockKeyhole } from \"lucide-react\"\nimport { useEffect, useState, type ReactNode } from \"react\"\nimport { useBladeClient } from \"../context\"\nimport { useAgentSession } from \"../hooks/use-agent-session\"\nimport { cn } from \"../lib/utils\"\nimport { ChatInput } from \"./ChatInput\"\nimport { ConnectionBanner } from \"./ConnectionBanner\"\nimport { MessageList } from \"./MessageList\"\nimport type { ToolCallRenderer } from \"./ToolCallBlock\"\n\nexport interface ChatViewClassNames {\n root?: string\n banner?: string\n messageList?: string\n chatInput?: string\n}\n\nexport interface ChatViewRenderers {\n /** 自定义工具调用渲染;返回 null 走默认渲染。 */\n toolCall?: ToolCallRenderer\n}\n\nexport interface ChatViewSlots {\n /** 消息列表上方的自定义区域。 */\n header?: ReactNode\n /** 无消息时的空状态。 */\n emptyState?: ReactNode\n /** 输入框下方的自定义区域。 */\n footer?: ReactNode\n}\n\nexport interface ChatViewProps {\n /** 连接既有会话;不传则按 createOptions 自动新建。 */\n sessionId?: string\n createOptions?: CreateSessionRequest\n /** 自动创建出的 sessionId 通过此回调交还调用方持有。 */\n onSessionCreated?: (sessionId: string) => void\n /** 会话连接完成后回调(页面协作场景拿 AgentSession 实例用)。 */\n onSessionReady?: (session: AgentSession) => void\n /** 智能体下发给宿主页面的指令处理器(action → handler)。 */\n commands?: Record<string, (data: unknown) => void>\n classNames?: ChatViewClassNames\n renderers?: ChatViewRenderers\n slots?: ChatViewSlots\n placeholder?: string\n /** 配色主题,默认浅色。宿主已经在祖先元素上写了 data-theme 时不用传。 */\n theme?: \"light\" | \"dark\"\n}\n\n/** 主题落到聊天根节点上:深色变量挂在 [data-theme=\"dark\"] 上,由它继承给整棵子树。 */\nfunction themeAttr(theme: ChatViewProps[\"theme\"]): \"dark\" | undefined {\n return theme === \"dark\" ? \"dark\" : undefined\n}\n\nfunction isUnauthorizedError(error: Error | null): boolean {\n return error instanceof BladeApiError && error.status === 401\n}\n\n/** 登录引导卡片:未持有令牌或令牌失效时展示,按钮走弹窗授权。 */\nfunction LoginCard({ client, onLoggedIn }: { client: BladeClient; onLoggedIn: () => void }) {\n const [loggingIn, setLoggingIn] = useState(false)\n const [loginError, setLoginError] = useState<string | null>(null)\n\n const handleLogin = async () => {\n setLoggingIn(true)\n setLoginError(null)\n try {\n await client.login()\n onLoggedIn()\n } catch (error) {\n setLoginError(error instanceof Error && error.message ? error.message : \"登录失败,请重试\")\n } finally {\n setLoggingIn(false)\n }\n }\n\n return (\n <div className=\"blade-chat-login flex flex-1 items-center justify-center p-6\">\n <div className=\"flex w-full max-w-sm flex-col items-center gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-6 py-8 text-center\">\n <LockKeyhole size={28} className=\"text-[hsl(var(--muted-foreground))]\" />\n <div className=\"text-base font-medium text-[hsl(var(--foreground))]\">需要登录后使用</div>\n <div className=\"text-sm text-[hsl(var(--muted-foreground))]\">\n 登录后即可与智能体对话,你的会话内容仅自己可见。\n </div>\n <button\n type=\"button\"\n onClick={handleLogin}\n disabled={loggingIn}\n className=\"w-full rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-sm font-semibold text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:opacity-60\"\n >\n {loggingIn ? \"登录中…\" : \"登录\"}\n </button>\n {loginError && <div className=\"text-xs text-[hsl(var(--destructive))]\">{loginError}</div>}\n </div>\n </div>\n )\n}\n\n/**\n * 开箱即用的聊天界面:连接(或新建)一个会话,渲染消息流与输入框。\n * 状态全部来自 useAgentSession,不依赖任何全局 store。\n */\nexport function ChatView(props: ChatViewProps) {\n const client = useBladeClient()\n // attempt 作为会话子树的 key:登录成功后整体重挂载,重新走连接/创建流程\n const [attempt, setAttempt] = useState(0)\n const [needLogin, setNeedLogin] = useState(() => !client.hasToken())\n\n if (needLogin) {\n return (\n <div\n data-theme={themeAttr(props.theme)}\n className={cn(\"blade-chat flex min-h-0 flex-1 flex-col\", props.classNames?.root)}\n >\n <LoginCard\n client={client}\n onLoggedIn={() => {\n setNeedLogin(false)\n setAttempt((value) => value + 1)\n }}\n />\n </div>\n )\n }\n\n return (\n <ChatSessionView key={attempt} {...props} onUnauthorized={() => setNeedLogin(true)} />\n )\n}\n\nfunction ChatSessionView({\n sessionId,\n createOptions,\n onSessionCreated,\n onSessionReady,\n commands,\n classNames,\n renderers,\n slots,\n placeholder,\n theme,\n onUnauthorized,\n}: ChatViewProps & { onUnauthorized: () => void }) {\n const { session, state, error } = useAgentSession(sessionId, {\n createOptions,\n onSessionCreated,\n })\n const [stopRequested, setStopRequested] = useState(false)\n const [inputText, setInputText] = useState(\"\")\n\n // 会话就绪后交还实例\n useEffect(() => {\n if (session) {\n onSessionReady?.(session)\n }\n }, [session, onSessionReady])\n\n // session.attach() / insertText() 注入到输入框:页面把业务数据(如地图选中\n // 的点位)塞进输入框,随下一条消息发给智能体。\n useEffect(() => {\n if (!session) return\n const offAttach = session.on(\"attachRequested\", ({ label, content }) => {\n setInputText((prev) => `${prev ? `${prev}\\n\\n` : \"\"}[${label}]\\n${content}`)\n })\n const offInsert = session.on(\"insertTextRequested\", ({ text }) => {\n setInputText((prev) => prev + text)\n })\n return () => {\n offAttach()\n offInsert()\n }\n }, [session])\n\n // 令牌失效(401)时回到登录引导\n useEffect(() => {\n if (isUnauthorizedError(error)) {\n onUnauthorized()\n }\n }, [error, onUnauthorized])\n\n // 注册宿主页面指令:卸载或 commands 变化时反注册\n useEffect(() => {\n if (!session || !commands) return\n const unsubscribes = Object.entries(commands).map(([action, handler]) =>\n session.onCommand(action, (payload) => handler(payload)),\n )\n return () => {\n for (const unsubscribe of unsubscribes) unsubscribe()\n }\n }, [session, commands])\n\n const isStreaming = state?.isStreaming ?? false\n const isStopping = stopRequested && isStreaming\n const connectError =\n error && !isUnauthorizedError(error)\n ? error.message || \"连接失败,请稍后重试\"\n : null\n const errorMessage = connectError ?? state?.errorMessage ?? null\n\n const handleSend = (text: string): Promise<boolean> => {\n setStopRequested(false)\n return session?.send(text, { mode: state?.mode ?? undefined }) ?? Promise.resolve(false)\n }\n\n const handleStop = () => {\n setStopRequested(true)\n void session?.stop()\n }\n\n return (\n <div\n data-theme={themeAttr(theme)}\n className={cn(\n \"blade-chat flex min-h-0 flex-1 flex-col overflow-hidden\",\n classNames?.root,\n )}\n >\n <ConnectionBanner\n connection={state?.connection ?? \"connecting\"}\n className={classNames?.banner}\n />\n {/* 出错条的配色由 .blade-chat-error-bar 的 --destructive 变量给,别写死 red-*:\n Tailwind 的 dark: 变体跟的是系统偏好,会和 data-theme 主题打架。 */}\n {errorMessage && (\n <div className=\"blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm\">\n <CircleAlert size={16} className=\"mt-0.5 shrink-0\" />\n <span>{errorMessage}</span>\n </div>\n )}\n {slots?.header}\n <MessageList\n messages={state?.messages ?? []}\n isStreaming={isStreaming}\n sessionStatus={state?.status ?? undefined}\n askAnswers={state?.askAnswers}\n onAnswer={(answer, toolCallId, answerData) => {\n void session?.send(answer, {\n mode: state?.mode ?? undefined,\n askUserAnswer: { tool_call_id: toolCallId, ...answerData },\n })\n }}\n toolCallRenderer={renderers?.toolCall}\n emptyState={slots?.emptyState}\n className={classNames?.messageList}\n // 用 session 自己持有的 id,不是 sessionId prop——后者是可选的,\n // 自动建会话时一直是 undefined,文件卡片会永远不可用。\n sessionId={session?.sessionId}\n />\n <ChatInput\n value={inputText}\n onValueChange={setInputText}\n onSend={handleSend}\n onStop={handleStop}\n isStreaming={isStreaming}\n isStopping={isStopping}\n placeholder={placeholder}\n className={classNames?.chatInput}\n />\n {slots?.footer}\n </div>\n )\n}\n","import { CamelToPascal } from './utility-types';\n\n/**\n * Converts string to kebab case\n *\n * @param {string} string\n * @returns {string} A kebabized string\n */\nexport const toKebabCase = (string: string) =>\n string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Converts string to camel case\n *\n * @param {string} string\n * @returns {string} A camelized string\n */\nexport const toCamelCase = <T extends string>(string: T) =>\n string.replace(/^([A-Z])|[\\s-_]+(\\w)/g, (match, p1, p2) =>\n p2 ? p2.toUpperCase() : p1.toLowerCase(),\n );\n\n/**\n * Converts string to pascal case\n *\n * @param {string} string\n * @returns {string} A pascalized string\n */\nexport const toPascalCase = <T extends string>(string: T): CamelToPascal<T> => {\n const camelCase = toCamelCase(string);\n\n return (camelCase.charAt(0).toUpperCase() + camelCase.slice(1)) as CamelToPascal<T>;\n};\n\n/**\n * Merges classes into a single string\n *\n * @param {array} classes\n * @returns {string} A string of classes\n */\nexport const mergeClasses = <ClassType = string | undefined | null>(...classes: ClassType[]) =>\n classes\n .filter((className, index, array) => {\n return (\n Boolean(className) &&\n (className as string).trim() !== '' &&\n array.indexOf(className) === index\n );\n })\n .join(' ')\n .trim();\n","export default {\n xmlns: 'http://www.w3.org/2000/svg',\n width: 24,\n height: 24,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n};\n","import { createElement, forwardRef } from 'react';\nimport defaultAttributes from './defaultAttributes';\nimport { IconNode, LucideProps } from './types';\nimport { mergeClasses } from '@lucide/shared';\n\ninterface IconComponentProps extends LucideProps {\n iconNode: IconNode;\n}\n\n/**\n * Lucide icon component\n *\n * @component Icon\n * @param {object} props\n * @param {string} props.color - The color of the icon\n * @param {number} props.size - The size of the icon\n * @param {number} props.strokeWidth - The stroke width of the icon\n * @param {boolean} props.absoluteStrokeWidth - Whether to use absolute stroke width\n * @param {string} props.className - The class name of the icon\n * @param {IconNode} props.children - The children of the icon\n * @param {IconNode} props.iconNode - The icon node of the icon\n *\n * @returns {ForwardRefExoticComponent} LucideIcon\n */\nconst Icon = forwardRef<SVGSVGElement, IconComponentProps>(\n (\n {\n color = 'currentColor',\n size = 24,\n strokeWidth = 2,\n absoluteStrokeWidth,\n className = '',\n children,\n iconNode,\n ...rest\n },\n ref,\n ) => {\n return createElement(\n 'svg',\n {\n ref,\n ...defaultAttributes,\n width: size,\n height: size,\n stroke: color,\n strokeWidth: absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth,\n className: mergeClasses('lucide', className),\n ...rest,\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...(Array.isArray(children) ? children : [children]),\n ],\n );\n },\n);\n\nexport default Icon;\n","import { createElement, forwardRef } from 'react';\nimport { mergeClasses, toKebabCase } from '@lucide/shared';\nimport { IconNode, LucideProps } from './types';\nimport Icon from './Icon';\n\n/**\n * Create a Lucide icon component\n * @param {string} iconName\n * @param {array} iconNode\n * @returns {ForwardRefExoticComponent} LucideIcon\n */\nconst createLucideIcon = (iconName: string, iconNode: IconNode) => {\n const Component = forwardRef<SVGSVGElement, LucideProps>(({ className, ...props }, ref) =>\n createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(`lucide-${toKebabCase(iconName)}`, className),\n ...props,\n }),\n );\n\n Component.displayName = `${iconName}`;\n\n return Component;\n};\n\nexport default createLucideIcon;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Archive\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cmVjdCB3aWR0aD0iMjAiIGhlaWdodD0iNSIgeD0iMiIgeT0iMyIgcng9IjEiIC8+CiAgPHBhdGggZD0iTTQgOHYxMWEyIDIgMCAwIDAgMiAyaDEyYTIgMiAwIDAgMCAyLTJWOCIgLz4KICA8cGF0aCBkPSJNMTAgMTJoNCIgLz4KPC9zdmc+Cg==) - https://lucide.dev/icons/archive\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Archive = createLucideIcon('Archive', [\n ['rect', { width: '20', height: '5', x: '2', y: '3', rx: '1', key: '1wp1u1' }],\n ['path', { d: 'M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8', key: '1s80jp' }],\n ['path', { d: 'M10 12h4', key: 'a56b0p' }],\n]);\n\nexport default Archive;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name ArrowUp\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJtNSAxMiA3LTcgNyA3IiAvPgogIDxwYXRoIGQ9Ik0xMiAxOVY1IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/arrow-up\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ArrowUp = createLucideIcon('ArrowUp', [\n ['path', { d: 'm5 12 7-7 7 7', key: 'hav0vg' }],\n ['path', { d: 'M12 19V5', key: 'x0mq9r' }],\n]);\n\nexport default ArrowUp;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Bot\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTIgOFY0SDgiIC8+CiAgPHJlY3Qgd2lkdGg9IjE2IiBoZWlnaHQ9IjEyIiB4PSI0IiB5PSI4IiByeD0iMiIgLz4KICA8cGF0aCBkPSJNMiAxNGgyIiAvPgogIDxwYXRoIGQ9Ik0yMCAxNGgyIiAvPgogIDxwYXRoIGQ9Ik0xNSAxM3YyIiAvPgogIDxwYXRoIGQ9Ik05IDEzdjIiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/bot\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Bot = createLucideIcon('Bot', [\n ['path', { d: 'M12 8V4H8', key: 'hb8ula' }],\n ['rect', { width: '16', height: '12', x: '4', y: '8', rx: '2', key: 'enze0r' }],\n ['path', { d: 'M2 14h2', key: 'vft8re' }],\n ['path', { d: 'M20 14h2', key: '4cs60a' }],\n ['path', { d: 'M15 13v2', key: '1xurst' }],\n ['path', { d: 'M9 13v2', key: 'rq6x2g' }],\n]);\n\nexport default Bot;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Brain\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTIgNWEzIDMgMCAxIDAtNS45OTcuMTI1IDQgNCAwIDAgMC0yLjUyNiA1Ljc3IDQgNCAwIDAgMCAuNTU2IDYuNTg4QTQgNCAwIDEgMCAxMiAxOFoiIC8+CiAgPHBhdGggZD0iTTEyIDVhMyAzIDAgMSAxIDUuOTk3LjEyNSA0IDQgMCAwIDEgMi41MjYgNS43NyA0IDQgMCAwIDEtLjU1NiA2LjU4OEE0IDQgMCAxIDEgMTIgMThaIiAvPgogIDxwYXRoIGQ9Ik0xNSAxM2E0LjUgNC41IDAgMCAxLTMtNCA0LjUgNC41IDAgMCAxLTMgNCIgLz4KICA8cGF0aCBkPSJNMTcuNTk5IDYuNWEzIDMgMCAwIDAgLjM5OS0xLjM3NSIgLz4KICA8cGF0aCBkPSJNNi4wMDMgNS4xMjVBMyAzIDAgMCAwIDYuNDAxIDYuNSIgLz4KICA8cGF0aCBkPSJNMy40NzcgMTAuODk2YTQgNCAwIDAgMSAuNTg1LS4zOTYiIC8+CiAgPHBhdGggZD0iTTE5LjkzOCAxMC41YTQgNCAwIDAgMSAuNTg1LjM5NiIgLz4KICA8cGF0aCBkPSJNNiAxOGE0IDQgMCAwIDEtMS45NjctLjUxNiIgLz4KICA8cGF0aCBkPSJNMTkuOTY3IDE3LjQ4NEE0IDQgMCAwIDEgMTggMTgiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/brain\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Brain = createLucideIcon('Brain', [\n [\n 'path',\n {\n d: 'M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z',\n key: 'l5xja',\n },\n ],\n [\n 'path',\n {\n d: 'M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z',\n key: 'ep3f8r',\n },\n ],\n ['path', { d: 'M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4', key: '1p4c4q' }],\n ['path', { d: 'M17.599 6.5a3 3 0 0 0 .399-1.375', key: 'tmeiqw' }],\n ['path', { d: 'M6.003 5.125A3 3 0 0 0 6.401 6.5', key: '105sqy' }],\n ['path', { d: 'M3.477 10.896a4 4 0 0 1 .585-.396', key: 'ql3yin' }],\n ['path', { d: 'M19.938 10.5a4 4 0 0 1 .585.396', key: '1qfode' }],\n ['path', { d: 'M6 18a4 4 0 0 1-1.967-.516', key: '2e4loj' }],\n ['path', { d: 'M19.967 17.484A4 4 0 0 1 18 18', key: '159ez6' }],\n]);\n\nexport default Brain;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Check\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMjAgNiA5IDE3bC01LTUiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/check\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Check = createLucideIcon('Check', [['path', { d: 'M20 6 9 17l-5-5', key: '1gmf2c' }]]);\n\nexport default Check;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name ChevronDown\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJtNiA5IDYgNiA2LTYiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/chevron-down\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ChevronDown = createLucideIcon('ChevronDown', [\n ['path', { d: 'm6 9 6 6 6-6', key: 'qrunsl' }],\n]);\n\nexport default ChevronDown;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name ChevronRight\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJtOSAxOCA2LTYtNi02IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/chevron-right\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ChevronRight = createLucideIcon('ChevronRight', [\n ['path', { d: 'm9 18 6-6-6-6', key: 'mthhwq' }],\n]);\n\nexport default ChevronRight;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name CircleAlert\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIgLz4KICA8bGluZSB4MT0iMTIiIHgyPSIxMiIgeTE9IjgiIHkyPSIxMiIgLz4KICA8bGluZSB4MT0iMTIiIHgyPSIxMi4wMSIgeTE9IjE2IiB5Mj0iMTYiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/circle-alert\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst CircleAlert = createLucideIcon('CircleAlert', [\n ['circle', { cx: '12', cy: '12', r: '10', key: '1mglay' }],\n ['line', { x1: '12', x2: '12', y1: '8', y2: '12', key: '1pkeuh' }],\n ['line', { x1: '12', x2: '12.01', y1: '16', y2: '16', key: '4dfq90' }],\n]);\n\nexport default CircleAlert;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Copy\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cmVjdCB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHg9IjgiIHk9IjgiIHJ4PSIyIiByeT0iMiIgLz4KICA8cGF0aCBkPSJNNCAxNmMtMS4xIDAtMi0uOS0yLTJWNGMwLTEuMS45LTIgMi0yaDEwYzEuMSAwIDIgLjkgMiAyIiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/copy\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Copy = createLucideIcon('Copy', [\n ['rect', { width: '14', height: '14', x: '8', y: '8', rx: '2', ry: '2', key: '17jyea' }],\n ['path', { d: 'M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2', key: 'zix9uf' }],\n]);\n\nexport default Copy;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Download\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMjEgMTV2NGEyIDIgMCAwIDEtMiAySDVhMiAyIDAgMCAxLTItMnYtNCIgLz4KICA8cG9seWxpbmUgcG9pbnRzPSI3IDEwIDEyIDE1IDE3IDEwIiAvPgogIDxsaW5lIHgxPSIxMiIgeDI9IjEyIiB5MT0iMTUiIHkyPSIzIiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/download\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Download = createLucideIcon('Download', [\n ['path', { d: 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4', key: 'ih7n3h' }],\n ['polyline', { points: '7 10 12 15 17 10', key: '2ggqvy' }],\n ['line', { x1: '12', x2: '12', y1: '15', y2: '3', key: '1vk2je' }],\n]);\n\nexport default Download;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name FileCode2\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNNCAyMmgxNGEyIDIgMCAwIDAgMi0yVjdsLTUtNUg2YTIgMiAwIDAgMC0yIDJ2NCIgLz4KICA8cGF0aCBkPSJNMTQgMnY0YTIgMiAwIDAgMCAyIDJoNCIgLz4KICA8cGF0aCBkPSJtNSAxMi0zIDMgMyAzIiAvPgogIDxwYXRoIGQ9Im05IDE4IDMtMy0zLTMiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/file-code-2\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst FileCode2 = createLucideIcon('FileCode2', [\n ['path', { d: 'M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4', key: '1pf5j1' }],\n ['path', { d: 'M14 2v4a2 2 0 0 0 2 2h4', key: 'tnqrlb' }],\n ['path', { d: 'm5 12-3 3 3 3', key: 'oke12k' }],\n ['path', { d: 'm9 18 3-3-3-3', key: '112psh' }],\n]);\n\nexport default FileCode2;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name FileSpreadsheet\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTUgMkg2YTIgMiAwIDAgMC0yIDJ2MTZhMiAyIDAgMCAwIDIgMmgxMmEyIDIgMCAwIDAgMi0yVjdaIiAvPgogIDxwYXRoIGQ9Ik0xNCAydjRhMiAyIDAgMCAwIDIgMmg0IiAvPgogIDxwYXRoIGQ9Ik04IDEzaDIiIC8+CiAgPHBhdGggZD0iTTE0IDEzaDIiIC8+CiAgPHBhdGggZD0iTTggMTdoMiIgLz4KICA8cGF0aCBkPSJNMTQgMTdoMiIgLz4KPC9zdmc+Cg==) - https://lucide.dev/icons/file-spreadsheet\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst FileSpreadsheet = createLucideIcon('FileSpreadsheet', [\n ['path', { d: 'M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z', key: '1rqfz7' }],\n ['path', { d: 'M14 2v4a2 2 0 0 0 2 2h4', key: 'tnqrlb' }],\n ['path', { d: 'M8 13h2', key: 'yr2amv' }],\n ['path', { d: 'M14 13h2', key: 'un5t4a' }],\n ['path', { d: 'M8 17h2', key: '2yhykz' }],\n ['path', { d: 'M14 17h2', key: '10kma7' }],\n]);\n\nexport default FileSpreadsheet;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name FileText\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTUgMkg2YTIgMiAwIDAgMC0yIDJ2MTZhMiAyIDAgMCAwIDIgMmgxMmEyIDIgMCAwIDAgMi0yVjdaIiAvPgogIDxwYXRoIGQ9Ik0xNCAydjRhMiAyIDAgMCAwIDIgMmg0IiAvPgogIDxwYXRoIGQ9Ik0xMCA5SDgiIC8+CiAgPHBhdGggZD0iTTE2IDEzSDgiIC8+CiAgPHBhdGggZD0iTTE2IDE3SDgiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/file-text\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst FileText = createLucideIcon('FileText', [\n ['path', { d: 'M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z', key: '1rqfz7' }],\n ['path', { d: 'M14 2v4a2 2 0 0 0 2 2h4', key: 'tnqrlb' }],\n ['path', { d: 'M10 9H8', key: 'b1mrlr' }],\n ['path', { d: 'M16 13H8', key: 't4e002' }],\n ['path', { d: 'M16 17H8', key: 'z1uh3a' }],\n]);\n\nexport default FileText;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name File\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTUgMkg2YTIgMiAwIDAgMC0yIDJ2MTZhMiAyIDAgMCAwIDIgMmgxMmEyIDIgMCAwIDAgMi0yVjdaIiAvPgogIDxwYXRoIGQ9Ik0xNCAydjRhMiAyIDAgMCAwIDIgMmg0IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/file\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst File = createLucideIcon('File', [\n ['path', { d: 'M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z', key: '1rqfz7' }],\n ['path', { d: 'M14 2v4a2 2 0 0 0 2 2h4', key: 'tnqrlb' }],\n]);\n\nexport default File;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Film\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cmVjdCB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHg9IjMiIHk9IjMiIHJ4PSIyIiAvPgogIDxwYXRoIGQ9Ik03IDN2MTgiIC8+CiAgPHBhdGggZD0iTTMgNy41aDQiIC8+CiAgPHBhdGggZD0iTTMgMTJoMTgiIC8+CiAgPHBhdGggZD0iTTMgMTYuNWg0IiAvPgogIDxwYXRoIGQ9Ik0xNyAzdjE4IiAvPgogIDxwYXRoIGQ9Ik0xNyA3LjVoNCIgLz4KICA8cGF0aCBkPSJNMTcgMTYuNWg0IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/film\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Film = createLucideIcon('Film', [\n ['rect', { width: '18', height: '18', x: '3', y: '3', rx: '2', key: 'afitv7' }],\n ['path', { d: 'M7 3v18', key: 'bbkbws' }],\n ['path', { d: 'M3 7.5h4', key: 'zfgn84' }],\n ['path', { d: 'M3 12h18', key: '1i2n21' }],\n ['path', { d: 'M3 16.5h4', key: '1230mu' }],\n ['path', { d: 'M17 3v18', key: 'in4fa5' }],\n ['path', { d: 'M17 7.5h4', key: 'myr1c1' }],\n ['path', { d: 'M17 16.5h4', key: 'go4c1d' }],\n]);\n\nexport default Film;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Image\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cmVjdCB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHg9IjMiIHk9IjMiIHJ4PSIyIiByeT0iMiIgLz4KICA8Y2lyY2xlIGN4PSI5IiBjeT0iOSIgcj0iMiIgLz4KICA8cGF0aCBkPSJtMjEgMTUtMy4wODYtMy4wODZhMiAyIDAgMCAwLTIuODI4IDBMNiAyMSIgLz4KPC9zdmc+Cg==) - https://lucide.dev/icons/image\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Image = createLucideIcon('Image', [\n ['rect', { width: '18', height: '18', x: '3', y: '3', rx: '2', ry: '2', key: '1m3agn' }],\n ['circle', { cx: '9', cy: '9', r: '2', key: 'af1f0g' }],\n ['path', { d: 'm21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21', key: '1xmnt7' }],\n]);\n\nexport default Image;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Layers\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTIuODMgMi4xOGEyIDIgMCAwIDAtMS42NiAwTDIuNiA2LjA4YTEgMSAwIDAgMCAwIDEuODNsOC41OCAzLjkxYTIgMiAwIDAgMCAxLjY2IDBsOC41OC0zLjlhMSAxIDAgMCAwIDAtMS44M3oiIC8+CiAgPHBhdGggZD0iTTIgMTJhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxMiIgLz4KICA8cGF0aCBkPSJNMiAxN2ExIDEgMCAwIDAgLjU4LjkxbDguNiAzLjkxYTIgMiAwIDAgMCAxLjY1IDBsOC41OC0zLjlBMSAxIDAgMCAwIDIyIDE3IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/layers\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Layers = createLucideIcon('Layers', [\n [\n 'path',\n {\n d: 'M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z',\n key: 'zw3jo',\n },\n ],\n [\n 'path',\n {\n d: 'M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12',\n key: '1wduqc',\n },\n ],\n [\n 'path',\n {\n d: 'M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17',\n key: 'kqbvx6',\n },\n ],\n]);\n\nexport default Layers;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Lightbulb\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTUgMTRjLjItMSAuNy0xLjcgMS41LTIuNSAxLS45IDEuNS0yLjIgMS41LTMuNUE2IDYgMCAwIDAgNiA4YzAgMSAuMiAyLjIgMS41IDMuNS43LjcgMS4zIDEuNSAxLjUgMi41IiAvPgogIDxwYXRoIGQ9Ik05IDE4aDYiIC8+CiAgPHBhdGggZD0iTTEwIDIyaDQiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/lightbulb\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Lightbulb = createLucideIcon('Lightbulb', [\n [\n 'path',\n {\n d: 'M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5',\n key: '1gvzjb',\n },\n ],\n ['path', { d: 'M9 18h6', key: 'x1upvd' }],\n ['path', { d: 'M10 22h4', key: 'ceow96' }],\n]);\n\nexport default Lightbulb;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name LoaderCircle\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMjEgMTJhOSA5IDAgMSAxLTYuMjE5LTguNTYiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/loader-circle\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst LoaderCircle = createLucideIcon('LoaderCircle', [\n ['path', { d: 'M21 12a9 9 0 1 1-6.219-8.56', key: '13zald' }],\n]);\n\nexport default LoaderCircle;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name LockKeyhole\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8Y2lyY2xlIGN4PSIxMiIgY3k9IjE2IiByPSIxIiAvPgogIDxyZWN0IHg9IjMiIHk9IjEwIiB3aWR0aD0iMTgiIGhlaWdodD0iMTIiIHJ4PSIyIiAvPgogIDxwYXRoIGQ9Ik03IDEwVjdhNSA1IDAgMCAxIDEwIDB2MyIgLz4KPC9zdmc+Cg==) - https://lucide.dev/icons/lock-keyhole\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst LockKeyhole = createLucideIcon('LockKeyhole', [\n ['circle', { cx: '12', cy: '16', r: '1', key: '1au0dj' }],\n ['rect', { x: '3', y: '10', width: '18', height: '12', rx: '2', key: '6s8ecr' }],\n ['path', { d: 'M7 10V7a5 5 0 0 1 10 0v3', key: '1pqi11' }],\n]);\n\nexport default LockKeyhole;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name MessageSquareMore\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMjEgMTVhMiAyIDAgMCAxLTIgMkg3bC00IDRWNWEyIDIgMCAwIDEgMi0yaDE0YTIgMiAwIDAgMSAyIDJ6IiAvPgogIDxwYXRoIGQ9Ik04IDEwaC4wMSIgLz4KICA8cGF0aCBkPSJNMTIgMTBoLjAxIiAvPgogIDxwYXRoIGQ9Ik0xNiAxMGguMDEiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/message-square-more\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst MessageSquareMore = createLucideIcon('MessageSquareMore', [\n ['path', { d: 'M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z', key: '1lielz' }],\n ['path', { d: 'M8 10h.01', key: '19clt8' }],\n ['path', { d: 'M12 10h.01', key: '1nrarc' }],\n ['path', { d: 'M16 10h.01', key: '1m94wz' }],\n]);\n\nexport default MessageSquareMore;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name MessageSquare\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMjEgMTVhMiAyIDAgMCAxLTIgMkg3bC00IDRWNWEyIDIgMCAwIDEgMi0yaDE0YTIgMiAwIDAgMSAyIDJ6IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/message-square\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst MessageSquare = createLucideIcon('MessageSquare', [\n ['path', { d: 'M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z', key: '1lielz' }],\n]);\n\nexport default MessageSquare;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Music\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNOSAxOFY1bDEyLTJ2MTMiIC8+CiAgPGNpcmNsZSBjeD0iNiIgY3k9IjE4IiByPSIzIiAvPgogIDxjaXJjbGUgY3g9IjE4IiBjeT0iMTYiIHI9IjMiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/music\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Music = createLucideIcon('Music', [\n ['path', { d: 'M9 18V5l12-2v13', key: '1jmyc2' }],\n ['circle', { cx: '6', cy: '18', r: '3', key: 'fqmcym' }],\n ['circle', { cx: '18', cy: '16', r: '3', key: '1hluhg' }],\n]);\n\nexport default Music;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Square\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cmVjdCB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHg9IjMiIHk9IjMiIHJ4PSIyIiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/square\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Square = createLucideIcon('Square', [\n ['rect', { width: '18', height: '18', x: '3', y: '3', rx: '2', key: 'afitv7' }],\n]);\n\nexport default Square;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name TriangleAlert\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJtMjEuNzMgMTgtOC0xNGEyIDIgMCAwIDAtMy40OCAwbC04IDE0QTIgMiAwIDAgMCA0IDIxaDE2YTIgMiAwIDAgMCAxLjczLTMiIC8+CiAgPHBhdGggZD0iTTEyIDl2NCIgLz4KICA8cGF0aCBkPSJNMTIgMTdoLjAxIiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/triangle-alert\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst TriangleAlert = createLucideIcon('TriangleAlert', [\n [\n 'path',\n {\n d: 'm21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3',\n key: 'wmoenq',\n },\n ],\n ['path', { d: 'M12 9v4', key: 'juzpu7' }],\n ['path', { d: 'M12 17h.01', key: 'p32p05' }],\n]);\n\nexport default TriangleAlert;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name X\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTggNiA2IDE4IiAvPgogIDxwYXRoIGQ9Im02IDYgMTIgMTIiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/x\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst X = createLucideIcon('X', [\n ['path', { d: 'M18 6 6 18', key: '1bl5f8' }],\n ['path', { d: 'm6 6 12 12', key: 'd8bk6v' }],\n]);\n\nexport default X;\n","import { clsx, type ClassValue } from \"clsx\"\n\n/** 合并 className(SDK 内不引入 tailwind-merge,按序拼接即可)。 */\nexport function cn(...inputs: ClassValue[]): string {\n return clsx(inputs)\n}\n\n/** 复制文本到剪贴板,返回是否成功。 */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n try {\n await navigator.clipboard.writeText(text)\n return true\n } catch {\n return false\n }\n}\n","import { ArrowUp, Loader2, Square } from \"lucide-react\"\nimport type { KeyboardEvent } from \"react\"\nimport { cn } from \"../lib/utils\"\n\ninterface Props {\n /** 受控输入内容(由 ChatView 持有,便于 attach/insertText 注入)。 */\n value: string\n onValueChange: (value: string) => void\n onSend: (text: string) => boolean | Promise<boolean>\n onStop: () => void\n isStreaming: boolean\n isStopping?: boolean\n placeholder?: string\n className?: string\n}\n\n/**\n * 轻量聊天输入框:textarea(Enter 发送 / Shift+Enter 换行)+ 发送/停止按钮。\n * 不含第一方版本的富文本编辑、@ 补全、技能菜单、语音输入与模型选择。\n * 内容受控,session.attach() / insertText() 通过 ChatView 注入到这里。\n */\nexport function ChatInput({\n value,\n onValueChange,\n onSend,\n onStop,\n isStreaming,\n isStopping = false,\n placeholder = \"输入消息…\",\n className,\n}: Props) {\n const trimmed = value.trim()\n const canSend = trimmed.length > 0 && !isStreaming\n\n const handleSend = async () => {\n if (!canSend) return\n const accepted = await onSend(trimmed)\n if (!accepted) return\n onValueChange(\"\")\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n // 输入法组合中回车用于选字,不能触发发送\n if (event.key === \"Enter\" && !event.shiftKey && !event.nativeEvent.isComposing) {\n event.preventDefault()\n void handleSend()\n }\n }\n\n return (\n <div className={cn(\"blade-chat-input border-t border-[hsl(var(--border))] py-3\", className)}>\n <div className=\"blade-chat-input-inner mx-auto flex max-w-[748px] items-end gap-2 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2\">\n <textarea\n value={value}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={handleKeyDown}\n onInput={(event) => {\n // 内容驱动的高度自适应:先复位再按 scrollHeight 撑开,上限约 8 行\n const el = event.currentTarget\n el.style.height = \"auto\"\n el.style.height = `${Math.min(el.scrollHeight, 192)}px`\n }}\n rows={1}\n placeholder={placeholder}\n aria-label=\"聊天输入\"\n className=\"blade-chat-textarea max-h-48 min-h-[28px] flex-1 resize-none bg-transparent py-1 text-sm leading-6 text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.6)]\"\n />\n {isStreaming ? (\n <button\n type=\"button\"\n onClick={onStop}\n disabled={isStopping}\n aria-label={isStopping ? \"正在停止\" : \"停止回复\"}\n title={isStopping ? \"正在停止\" : \"停止回复\"}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--muted))] text-[hsl(var(--foreground))] transition-opacity hover:opacity-90 disabled:opacity-60\"\n >\n {isStopping ? (\n <Loader2 size={14} className=\"animate-spin\" />\n ) : (\n <Square size={12} fill=\"currentColor\" />\n )}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend}\n aria-label=\"发送消息\"\n title=\"发送消息\"\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ArrowUp size={15} />\n </button>\n )}\n </div>\n </div>\n )\n}\n","import type { ConnectionStatus } from \"@blade-hq/agent-client\"\nimport { AlertTriangle, LoaderCircle } from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\n\ninterface Props {\n connection: ConnectionStatus\n className?: string\n}\n\n/** 连接状态提示条:数据来自 SessionState.connection,正常连接时不渲染。 */\nexport function ConnectionBanner({ connection, className }: Props) {\n if (connection === \"connected\" || connection === \"connecting\") {\n return null\n }\n\n const reconnecting = connection === \"reconnecting\"\n\n return (\n <div className={cn(\"blade-chat-banner bg-[hsl(var(--background))] px-5 pt-3\", className)}>\n <div\n className={cn(\n \"mx-auto flex max-w-3xl items-start gap-3 rounded-2xl border px-4 py-3\",\n reconnecting\n ? \"border-amber-500/25 bg-amber-500/10 text-amber-100\"\n : \"border-rose-500/25 bg-rose-500/10 text-rose-100\",\n )}\n >\n <span className=\"mt-0.5 shrink-0\">\n {reconnecting ? (\n <LoaderCircle size={14} className=\"animate-spin\" />\n ) : (\n <AlertTriangle size={14} />\n )}\n </span>\n <div className=\"min-w-0\">\n <div className=\"text-sm font-medium\">\n {reconnecting ? \"连接已断开,正在重连…\" : \"连接已断开\"}\n </div>\n <div className=\"text-xs opacity-80\">消息同步可能会延迟,系统会继续自动重试</div>\n </div>\n </div>\n </div>\n )\n}\n","import type { AskUserAnswerData, ChatMessage } from \"@blade-hq/agent-client\"\nimport { isHiddenInternalMessage } from \"@blade-hq/agent-client\"\nimport { ChevronDown, Layers, Lightbulb, MessageSquare } from \"lucide-react\"\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\"\nimport { StickToBottom, useStickToBottomContext } from \"use-stick-to-bottom\"\nimport { cn } from \"../lib/utils\"\nimport { AssistantTurnBlock } from \"./AssistantTurnBlock\"\nimport { RenderErrorBoundary } from \"./RenderErrorBoundary\"\nimport type { ToolCallRenderer } from \"./ToolCallBlock\"\nimport {\n ErrorMessageBlock,\n UserMessageBubble,\n isErrorMessage,\n isUserMessage,\n} from \"./UserMessageBubble\"\n\ntype RenderBlock =\n | { type: \"message\"; message: ChatMessage; key: string }\n | { type: \"assistant_turn\"; messages: ChatMessage[]; key: string; isStreaming: boolean }\n | { type: \"compaction\"; key: string }\n | { type: \"planning_divider\"; kind: \"enter\" | \"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): \"enter\" | \"exit\" | null {\n const modeChange = parseModeChange(message)\n if (modeChange?.to === \"planning\") return \"enter\"\n if (modeChange?.from === \"planning\") return \"exit\"\n return null\n}\n\nfunction getMessageResetSignature(messages: ChatMessage[]): string {\n return messages\n .map((message) => {\n const contentSize =\n typeof message.content === \"string\" ? message.content.length : message.content.length\n const toolSignature =\n message.tool_calls\n ?.map((toolCall) => `${toolCall.id}:${toolCall.status ?? \"\"}`)\n .join(\",\") ?? \"\"\n return [\n message.entry_id ?? message.timestamp ?? message.role,\n message.status ?? \"\",\n contentSize,\n toolSignature,\n ].join(\":\")\n })\n .join(\"|\")\n}\n\ninterface Props {\n messages: ChatMessage[]\n isStreaming: boolean\n sessionStatus?: string\n askAnswers?: Record<string, AskUserAnswerData>\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n toolCallRenderer?: ToolCallRenderer\n emptyState?: ReactNode\n className?: string\n /** 传给助手消息的 Markdown 渲染,用于把 MEDIA 行折叠成文件下载卡片。 */\n sessionId?: string\n}\n\n/**\n * 消息列表:use-stick-to-bottom 自动滚动 + 按轮次分组渲染。\n * 相比第一方版本去掉了轮次导航栏、吸顶状态条与规划摘要卡片。\n */\nexport function MessageList({\n messages,\n isStreaming,\n sessionStatus,\n askAnswers,\n onAnswer,\n toolCallRenderer,\n emptyState,\n className,\n sessionId,\n}: Props) {\n const renderBlocks = useMemo(() => {\n const visible = messages.filter((message) => {\n if ((message.loop_name ?? \"root\") !== \"root\") 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\n const flushAssistant = () => {\n if (assistantBuffer.length === 0) return\n assistantTurnCount += 1\n const first = assistantBuffer[0]\n blocks.push({\n type: \"assistant_turn\",\n messages: assistantBuffer,\n key: first.entry_id ?? `assistant-${assistantTurnCount}`,\n isStreaming: assistantBuffer.some((message) => message.status === \"streaming\"),\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({ type: \"compaction\", key: message.entry_id ?? `compaction-${blocks.length}` })\n continue\n }\n\n if (message.role === \"assistant\") {\n assistantBuffer.push(message)\n continue\n }\n\n flushAssistant()\n blocks.push({\n type: \"message\",\n message,\n key: message.entry_id ?? `${message.role}-${blocks.length}`,\n })\n }\n\n flushAssistant()\n\n // 流式中但最后一块还是用户消息:补一个空的助手轮占位,立即出现\"正在生成\"\n const last = blocks[blocks.length - 1]\n if (isStreaming) {\n if (last?.type === \"assistant_turn\") {\n last.isStreaming = true\n } else if (last?.type === \"message\" && isUserMessage(last.message)) {\n blocks.push({\n type: \"assistant_turn\",\n messages: [\n {\n role: \"assistant\",\n content: \"\",\n entry_id: `pending-assistant-${last.key}`,\n status: \"streaming\",\n loop_name: \"root\",\n },\n ],\n key: `pending-assistant-${last.key}`,\n isStreaming: true,\n })\n }\n }\n\n return blocks\n }, [messages, isStreaming])\n\n return (\n <div className={cn(\"blade-chat-messages relative min-h-0 flex-1\", className)}>\n <StickToBottom className=\"h-full overflow-y-hidden\" initial=\"instant\" resize=\"instant\">\n <StickToBottom.Content className=\"blade-chat-messages-scroll\">\n <div className=\"blade-chat-messages-content mx-auto max-w-[748px]\">\n <div className=\"flex min-w-0 flex-col\">\n {renderBlocks.length === 0\n ? (emptyState ?? (\n <div className=\"blade-chat-empty\">\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 : renderBlocks.map((block) => {\n if (block.type === \"message\") {\n return (\n <div key={block.key} data-entry-id={block.message.entry_id}>\n {isUserMessage(block.message) ? (\n <UserMessageBubble message={block.message} />\n ) : isErrorMessage(block.message) ? (\n <ErrorMessageBlock message={block.message} />\n ) : null}\n </div>\n )\n }\n\n if (block.type === \"assistant_turn\") {\n return (\n <div key={block.key} data-entry-id={block.messages[0]?.entry_id}>\n <RenderErrorBoundary\n label=\"助手消息\"\n details={block.key}\n resetKey={getMessageResetSignature(block.messages)}\n >\n <AssistantTurnBlock\n messages={block.messages}\n isStreaming={block.isStreaming}\n askAnswers={askAnswers}\n onAnswer={onAnswer}\n sessionStatus={sessionStatus}\n toolCallRenderer={toolCallRenderer}\n sessionId={sessionId}\n />\n </RenderErrorBoundary>\n </div>\n )\n }\n\n if (block.type === \"compaction\") {\n return (\n <div\n key={block.key}\n className=\"flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]\"\n >\n <Layers size={12} />\n <span>上下文已压缩</span>\n </div>\n )\n }\n\n return <PlanningDivider key={block.key} kind={block.kind} />\n })}\n\n {sessionStatus === \"interrupted\" && !isStreaming ? (\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 </StickToBottom.Content>\n <AutoScrollOnUserSend userMessageCount={messages.filter((m) => isUserMessage(m)).length} />\n <ScrollToBottomButton />\n </StickToBottom>\n </div>\n )\n}\n\n/** 用户每发一条消息就滚到底部;流式期间用户向上翻阅历史则不打扰。 */\nfunction AutoScrollOnUserSend({ userMessageCount }: { userMessageCount: number }) {\n const { scrollToBottom } = useStickToBottomContext()\n const previousCountRef = useRef(userMessageCount)\n useEffect(() => {\n if (userMessageCount > previousCountRef.current) {\n scrollToBottom(\"instant\")\n }\n previousCountRef.current = userMessageCount\n }, [userMessageCount, scrollToBottom])\n return null\n}\n\nfunction ScrollToBottomButton() {\n const { isAtBottom, scrollToBottom } = useStickToBottomContext()\n const [visible, setVisible] = useState(false)\n const hideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n // 防抖:isAtBottom 变为 true 时不立即隐藏,等 300ms 确认稳定后再隐藏\n // 避免流式内容高度变化导致 isAtBottom 在 true/false 之间快速切换闪烁\n useEffect(() => {\n if (isAtBottom) {\n // 启动延迟隐藏定时器\n if (!hideTimerRef.current) {\n hideTimerRef.current = setTimeout(() => {\n setVisible(false)\n hideTimerRef.current = null\n }, 300)\n }\n } else {\n // 不在底部,取消所有待执行的隐藏,立即显示\n if (hideTimerRef.current) {\n clearTimeout(hideTimerRef.current)\n hideTimerRef.current = null\n }\n setVisible(true)\n }\n\n return () => {\n if (hideTimerRef.current) {\n clearTimeout(hideTimerRef.current)\n hideTimerRef.current = null\n }\n }\n }, [isAtBottom])\n\n // hook 必须在任何早退之前调用,否则 visible 变化时 hook 顺序不一致\n const handleClick = useCallback(() => {\n // 点击滚动到底部时立即隐藏按钮,避免闪烁\n if (hideTimerRef.current) {\n clearTimeout(hideTimerRef.current)\n hideTimerRef.current = null\n }\n setVisible(false)\n scrollToBottom()\n }, [scrollToBottom])\n\n if (!visible) return null\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n aria-label=\"滚动到底部\"\n className=\"blade-chat-scroll-bottom 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 {/* 窄容器里这行字会横跨近半个宽度,收起来只留图标;可访问名由 aria-label 保住。 */}\n <span className=\"blade-chat-scroll-bottom-label\">滚动到底部</span>\n </button>\n )\n}\n\nfunction PlanningDivider({ kind }: { kind: \"enter\" | \"exit\" }) {\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>{kind === \"enter\" ? \"进入规划模式\" : \"规划完成\"}</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 type { AskUserAnswerData, ChatMessage } from \"@blade-hq/agent-client\"\nimport { getTextContent, normalizeMessageContent } from \"@blade-hq/agent-client\"\nimport { Brain, ChevronDown } from \"lucide-react\"\nimport { useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { AgentLoopBlock } from \"./AgentLoopBlock\"\nimport { MarkdownContent } from \"./MarkdownContent\"\nimport { Shimmer } from \"./Shimmer\"\nimport { ToolCallBlock, type ToolCallRenderer } from \"./ToolCallBlock\"\nimport { formatToolName } from \"./display-utils\"\n\ninterface Props {\n messages: ChatMessage[]\n isStreaming?: boolean\n askAnswers?: Record<string, AskUserAnswerData>\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n sessionStatus?: string\n toolCallRenderer?: ToolCallRenderer\n /** 传给 Markdown 渲染,用于把 MEDIA 行折叠成文件下载卡片。 */\n sessionId?: string\n}\n\n/** 思考折叠块:折叠状态归组件自身,不依赖全局 store。 */\nfunction ThinkingBlock({ reasoning, isStreaming }: { reasoning: string; isStreaming: boolean }) {\n const [open, setOpen] = useState(false)\n\n return (\n <div className=\"blade-chat-thinking ml-4 text-sm\">\n <button\n type=\"button\"\n onClick={() => setOpen(!open)}\n aria-expanded={open}\n className=\"inline-flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]\"\n >\n <Brain size={12} className=\"shrink-0\" />\n {isStreaming ? <Shimmer className=\"text-xs\">正在思考</Shimmer> : <span>思考过程</span>}\n <span className=\"text-[hsl(var(--muted-foreground))]/70\">\n · {new Intl.NumberFormat(\"zh-CN\").format(reasoning.length)} 字\n </span>\n <ChevronDown\n size={12}\n className={cn(\"shrink-0 transition-transform\", open && \"rotate-180\")}\n />\n </button>\n {open && (\n <div className=\"mt-1.5 whitespace-pre-wrap border-l-2 border-[hsl(var(--border))] pl-3 text-[11px] leading-5 text-[hsl(var(--muted-foreground))]\">\n {reasoning}\n </div>\n )}\n </div>\n )\n}\n\nfunction getMessageText(message: ChatMessage): string {\n return getTextContent(normalizeMessageContent(message.content)).trim()\n}\n\nfunction findLatestReasoningMessageIndex(messages: readonly ChatMessage[]): number {\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n if (messages[index].reasoning) return index\n }\n return -1\n}\n\n/**\n * 一轮助手回复:按消息顺序渲染 thinking 折叠块、正文 Markdown 与工具调用。\n * 相比第一方版本去掉了紧凑/详细模式切换、文件交付卡片与内联资源 iframe。\n */\nexport function AssistantTurnBlock({\n messages,\n isStreaming = false,\n askAnswers,\n onAnswer,\n sessionStatus,\n toolCallRenderer,\n sessionId,\n}: Props) {\n const hasInterrupted = messages.some((message) => message.status === \"interrupted\")\n const hasAnyContent = messages.some(\n (message) =>\n getMessageText(message) || message.reasoning || (message.tool_calls?.length ?? 0) > 0,\n )\n const latestReasoningIndex = isStreaming\n ? findLatestReasoningMessageIndex(messages)\n : -1\n\n return (\n <div className=\"blade-chat-assistant-turn flex flex-col gap-3\">\n {hasInterrupted && (\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 {messages.map((message, index) => {\n const isLast = index === messages.length - 1\n const streamingThis = isStreaming && isLast\n const text = getMessageText(message)\n const toolCalls = message.tool_calls ?? []\n const showReasoning =\n !!message.reasoning && (!isStreaming || index === latestReasoningIndex)\n\n return (\n <div\n key={message.entry_id ?? `${message.timestamp ?? \"assistant\"}-${index}`}\n className=\"flex flex-col gap-3\"\n >\n {showReasoning && message.reasoning && (\n <ThinkingBlock reasoning={message.reasoning} isStreaming={streamingThis && !text} />\n )}\n {text && (\n <div className=\"blade-chat-assistant-text text-[15px] leading-8 text-[hsl(var(--foreground))]\">\n <MarkdownContent\n mode={streamingThis ? \"streaming\" : \"static\"}\n className=\"blade-chat-prose\"\n sessionId={sessionId}\n >\n {text}\n </MarkdownContent>\n </div>\n )}\n {toolCalls.length > 0 && (\n <div className=\"flex flex-col gap-2\">\n {toolCalls.map((toolCall) =>\n formatToolName(toolCall.name) === \"Agent\" ? (\n <AgentLoopBlock key={toolCall.id} toolCall={toolCall} />\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 sessionStatus={sessionStatus}\n renderer={toolCallRenderer}\n />\n ),\n )}\n </div>\n )}\n </div>\n )\n })}\n {isStreaming && !hasAnyContent && <Shimmer className=\"ml-4\">正在生成...</Shimmer>}\n </div>\n )\n}\n","import type { ToolCallInfo } from \"@blade-hq/agent-client\"\nimport { Bot, Check, ChevronRight, Loader2, X } from \"lucide-react\"\nimport { useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { formatToolDuration, formatToolResult } from \"./display-utils\"\n\ninterface Props {\n toolCall: ToolCallInfo\n}\n\nfunction parseAgentDescription(argumentsJson: string): string {\n try {\n const parsed = JSON.parse(argumentsJson)\n return typeof parsed?.description === \"string\" && parsed.description\n ? parsed.description\n : \"子智能体\"\n } catch {\n return \"子智能体\"\n }\n}\n\n/**\n * 子智能体(fork Agent)状态块的 SDK 简化版:只展示描述、状态与最终结果,\n * 不再嵌套渲染子循环的完整消息流(那是第一方界面的能力)。\n */\nexport function AgentLoopBlock({ toolCall }: Props) {\n const [expanded, setExpanded] = useState(false)\n const description = parseAgentDescription(toolCall.arguments)\n const running = toolCall.status === \"pending\" || toolCall.status === \"awaiting_answer\"\n const failed = toolCall.status === \"error\" || toolCall.status === \"cancelled\"\n\n return (\n <div className=\"blade-chat-agent-loop ml-4 text-xs\">\n <div\n className={cn(\n \"border-l-[3px] flex items-center gap-2 px-3 py-2\",\n failed\n ? \"border-l-[hsl(var(--muted-foreground)/0.5)]\"\n : running\n ? \"border-l-blue-500\"\n : \"border-l-[hsl(var(--primary))]\",\n )}\n >\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 <Bot size={12} className=\"shrink-0 text-[hsl(var(--muted-foreground))]\" />\n <span\n className={cn(\n \"flex shrink-0 items-center gap-1 text-[10px]\",\n failed\n ? \"text-[hsl(var(--muted-foreground))]\"\n : running\n ? \"text-blue-300\"\n : \"text-[hsl(var(--primary))]\",\n )}\n >\n {running ? (\n <Loader2 size={11} className=\"animate-spin\" />\n ) : failed ? (\n <X size={11} />\n ) : (\n <Check size={11} />\n )}\n <span>{running ? \"执行中\" : failed ? \"已终止\" : \"完成\"}</span>\n </span>\n <span className=\"min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]\">\n 子智能体:{description}\n </span>\n </button>\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 </div>\n {expanded && toolCall.result != null && (\n <div className=\"ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3\">\n <div className=\"mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]\">\n 结果\n </div>\n <pre className=\"max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {formatToolResult(toolCall.result)}\n </pre>\n </div>\n )}\n </div>\n )\n}\n","import type { ToolCallInfo } from \"@blade-hq/agent-client\"\n\n/** 工具名归一化别名表:把后端各种命名风格统一为展示用的驼峰名。 */\nconst TOOL_NAME_ALIASES: Record<string, string> = {\n agent: \"Agent\",\n ask_user_question: \"AskUserQuestion\",\n bash: \"Bash\",\n bg_bash: \"BgBash\",\n edit: \"Edit\",\n exit_plan_mode: \"ExitPlanMode\",\n file_edit: \"Edit\",\n file_read: \"Read\",\n file_write: \"Write\",\n finish_task: \"FinishTask\",\n glob: \"Glob\",\n grep: \"Grep\",\n ls: \"Ls\",\n read: \"Read\",\n read_skill: \"ReadSkill\",\n web_fetch: \"WebFetch\",\n web_search: \"WebSearch\",\n write: \"Write\",\n}\n\n/** 系统工具的中文展示名。 */\nconst TOOL_DISPLAY_LABELS: Record<string, string> = {\n Bash: \"执行命令\",\n BgBash: \"后台执行命令\",\n Read: \"读取文件\",\n Write: \"写入文件\",\n Edit: \"编辑文件\",\n Ls: \"列出目录\",\n Glob: \"匹配文件\",\n Grep: \"搜索文本\",\n WebSearch: \"搜索网页\",\n WebFetch: \"整理网页内容\",\n Agent: \"派生子智能体\",\n AskUserQuestion: \"向用户提问\",\n ReadSkill: \"读取技能\",\n FinishTask: \"任务完成\",\n ExitPlanMode: \"提交计划\",\n ListSessions: \"列出历史会话\",\n GetSessionHistory: \"读取会话历史\",\n}\n\nexport type ToolTone = \"emerald\" | \"blue\" | \"amber\" | \"red\"\n\nfunction safeParseJson(value: string | null | undefined): unknown {\n if (!value) return null\n try {\n return JSON.parse(value)\n } catch {\n return null\n }\n}\n\nfunction getStringArgValue(args: Record<string, unknown> | null, key: string): string {\n const value = args?.[key]\n return typeof value === \"string\" ? value.trim() : \"\"\n}\n\n/** 归一化工具名:去掉命名空间前缀并映射到别名表(如 \"fork:Agent\" → \"Agent\")。 */\nexport function formatToolName(name: string): string {\n const trimmed = name.trim()\n if (!trimmed) return name\n\n const stripped = trimmed.split(\":\").pop()?.split(\"/\").pop()?.split(\".\").pop()?.trim() || trimmed\n const normalized = stripped\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/[^a-zA-Z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .toLowerCase()\n\n return TOOL_NAME_ALIASES[normalized] ?? stripped\n}\n\n/**\n * 返回工具调用的中文展示标签:优先取参数里的 description,\n * 其次取后端下发的 display_name / 系统工具中文名。\n */\nexport function getToolDisplayLabel(toolCall: ToolCallInfo): string {\n const normalized = formatToolName(toolCall.name)\n const args = safeParseJson(toolCall.arguments) as Record<string, unknown> | null\n const displayName = toolCall.display_name?.trim() ?? \"\"\n const baseLabel = displayName || TOOL_DISPLAY_LABELS[normalized] || normalized\n const metaDisplayName = getStringArgValue(args, \"_meta_display_name\")\n if (metaDisplayName) {\n return metaDisplayName\n }\n\n const description = getStringArgValue(args, \"description\")\n\n if (normalized === \"BgBash\") {\n return description ? `后台执行:${description}` : \"后台执行命令\"\n }\n if (normalized === \"ReadSkill\") {\n const skillName = getStringArgValue(args, \"skill\") || getStringArgValue(args, \"skill_name\")\n return skillName ? `${baseLabel}「${skillName}」` : baseLabel\n }\n if (normalized === \"FinishTask\") {\n const title = getStringArgValue(args, \"title\")\n return title ? `${baseLabel}:${title}` : baseLabel\n }\n\n return description || baseLabel\n}\n\nexport function getToolTone(status?: ToolCallInfo[\"status\"]): ToolTone {\n if (status === \"error\" || status === \"cancelled\") return \"red\"\n if (status === \"awaiting_answer\") return \"amber\"\n if (status === \"pending\") return \"blue\"\n return \"emerald\"\n}\n\nexport function getToolStatusLabel(status?: ToolCallInfo[\"status\"]): string {\n if (status === \"pending\") return \"运行中\"\n if (status === \"awaiting_answer\") return \"等待回答\"\n if (status === \"error\") return \"错误\"\n if (status === \"cancelled\") return \"已取消\"\n return \"完成\"\n}\n\nexport function 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\n/** 参数 JSON 美化:无法解析时按原文展示。 */\nexport function formatToolArgs(args: string): string {\n try {\n return JSON.stringify(JSON.parse(args), null, 2)\n } catch {\n return args\n }\n}\n\nconst RESULT_PREVIEW_LIMIT = 4000\n\n/** 工具结果的文本化 + 截断:长结果只在折叠面板里展示前若干字符。 */\nexport function formatToolResult(result: unknown): string {\n const text = typeof result === \"string\" ? result : JSON.stringify(result, null, 2)\n if (text == null) return \"\"\n if (text.length <= RESULT_PREVIEW_LIMIT) return text\n return `${text.slice(0, RESULT_PREVIEW_LIMIT)}\\n…(结果过长,已截断)`\n}\n","import { Check, Copy } from \"lucide-react\"\nimport {\n type ComponentProps,\n type ComponentPropsWithRef,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\"\nimport { type ExtraProps, Streamdown } from \"streamdown\"\nimport { FILE_CARD_TAG, collapseMediaTags } from \"../lib/media-tags\"\nimport { cn, copyToClipboard } from \"../lib/utils\"\nimport { FileCard, type FileCardProps } from \"./FileCard\"\n\ntype StreamdownProps = ComponentProps<typeof Streamdown>\n\n/** 平台内部提醒标记:不属于给用户看的内容,渲染前整段剥掉。 */\nconst SYSTEM_REMINDER_RE = /<system-reminder>[\\s\\S]*?<\\/system-reminder>/gi\n\ntype PreProps = ComponentPropsWithRef<\"pre\"> & ExtraProps\n\n/** 代码块外壳:常驻头部栏(语言标签 + 复制按钮),代码区浅底。 */\nfunction CodeBlockPre({ children, node: _node, ...props }: PreProps) {\n const preRef = useRef<HTMLPreElement>(null)\n const [copied, setCopied] = useState(false)\n const [language, setLanguage] = useState(\"\")\n\n // DOM 测量:语言标签写在内层 code 的 className 上,只能挂载后读取。\n useEffect(() => {\n const codeEl = preRef.current?.querySelector(\"code\")\n setLanguage(codeEl?.className.match(/language-(\\S+)/)?.[1] ?? \"\")\n }, [])\n\n const handleCopy = async () => {\n const ok = await copyToClipboard(preRef.current?.querySelector(\"code\")?.textContent ?? \"\")\n if (ok) {\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n }\n\n return (\n <div className=\"blade-chat-codeblock not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]\">\n <div className=\"blade-chat-codeblock-header flex h-[34px] items-center justify-between border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))/0.5] pl-3.5 pr-1.5\">\n <span className=\"font-mono text-[12px] text-[hsl(var(--muted-foreground))]\">\n {language || \"code\"}\n </span>\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n \"flex h-6 items-center gap-1 rounded-md px-1.5 text-[11px] transition-colors\",\n copied\n ? \"text-[hsl(var(--primary))]\"\n : \"text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\",\n )}\n >\n {copied ? <Check size={12} /> : <Copy size={12} />}\n <span>{copied ? \"已复制\" : \"复制\"}</span>\n </button>\n </div>\n <pre\n ref={preRef}\n {...props}\n className={cn(props.className, \"blade-chat-codeblock-body m-0 overflow-x-auto\")}\n >\n {children}\n </pre>\n </div>\n )\n}\n\ntype AnchorProps = ComponentPropsWithRef<\"a\"> & ExtraProps\n\n/** 链接一律新窗口打开并断开 opener,SDK 不接管站内跳转。 */\nfunction ExternalAnchor({ node: _node, children, ...props }: AnchorProps) {\n return (\n <a {...props} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n )\n}\n\nconst MARKDOWN_COMPONENTS = {\n pre: CodeBlockPre,\n a: ExternalAnchor,\n} as NonNullable<StreamdownProps[\"components\"]>\n\n/**\n * 文件卡片标签要显式过 sanitize 白名单,否则标签和属性都会被消毒掉。属性名写的是 HAST\n * 形式(`data-path` 解析进 HAST 后叫 `dataPath`);kebab-case 那两个是防御性冗余,\n * 万一 streamdown 换了属性名的处理方式也不至于静默丢属性。\n *\n * 注意不要给 Streamdown 传自定义 rehypePlugins——那样 streamdown 就不会再自动把这里声明的\n * 标签合并进它的 sanitize schema,白名单会静默失效。\n */\nconst CUSTOM_ALLOWED_TAGS = {\n [FILE_CARD_TAG]: [\"dataPath\", \"dataName\", \"data-path\", \"data-name\"],\n} as NonNullable<StreamdownProps[\"allowedTags\"]>\n\nexport interface MarkdownContentProps {\n children: string\n className?: string\n /** 流式渲染传 \"streaming\",历史静态内容默认 \"static\"。 */\n mode?: \"streaming\" | \"static\"\n /**\n * 会话 id。传了才会把 `MEDIA:` 行折叠成文件下载卡片——下载要用它。\n * 不要给用户消息传:用户自己在输入框打一行 `MEDIA:` 不该被当成平台产物。\n */\n sessionId?: string\n}\n\n/**\n * SDK 版 Markdown 渲染:附带代码块复制按钮、智能体产出文件的下载卡片;\n * 相比第一方版本去掉了 mermaid、外链确认弹窗与文件预览。\n */\nexport function MarkdownContent({ children, className, mode, sessionId }: MarkdownContentProps) {\n const streaming = mode === \"streaming\"\n const resolvedChildren = useMemo(() => {\n const withoutReminders = children.replace(SYSTEM_REMINDER_RE, \"\")\n if (!sessionId) return withoutReminders\n return collapseMediaTags(withoutReminders, { streaming })\n }, [children, sessionId, streaming])\n\n const components = useMemo(\n () =>\n ({\n ...MARKDOWN_COMPONENTS,\n [FILE_CARD_TAG]: (fileCardProps: FileCardProps) => (\n <FileCard {...fileCardProps} sessionId={sessionId} />\n ),\n }) as NonNullable<StreamdownProps[\"components\"]>,\n [sessionId],\n )\n\n return (\n <Streamdown\n // Streamdown 外层 memo 不比较 components,光换 sessionId 可能留着旧闭包,\n // 卡片就会拿旧会话去下载。挂 key 强制重建,切会话本来也要换内容。\n key={sessionId ?? \"no-session\"}\n className={cn(\"blade-chat-markdown break-words\", className)}\n mode={mode ?? \"static\"}\n components={components}\n allowedTags={CUSTOM_ALLOWED_TAGS}\n >\n {resolvedChildren}\n </Streamdown>\n )\n}\n","/**\n * MEDIA 行处理。后端提示词要求智能体产出文件时单独写一行 `MEDIA:<绝对路径>`\n * (见 host/src/blade_agent/host/orchestrator/prompt.py),界面必须把它折叠成文件卡片——\n * 这是内部标记,直接摆给用户看就是 bug。\n */\n\nexport const FILE_CARD_TAG = \"blade-file-card\"\n\n/**\n * 模型经常给这一行加点装饰——写成列表项、加粗、包引号、末尾补句号,这些都还是同一个\n * 意思,识别不了就会把内部标记裸露给用户,所以一并放宽。\n *\n * 尾部的包裹符用反向引用要求和开头那组一模一样:没写开头装饰就一个字符都不剥,\n * 否则 `draft_`、`报表*` 这种本来就以这些字符结尾的文件名会被削掉最后一位,卡片指向\n * 一个不存在的路径。行尾标点同理只认中文标点和逗号分号——英文句点是扩展名分隔符,\n * 不能碰。\n *\n * 路径部分用 `.+?` 而不是 `\\S+?`:文件名里带空格很常见(`季度 报告.xlsx`),用 `\\S`\n * 会在空格处截断、导致整行匹配不上,最后把 `MEDIA:` 原样暴露给用户。行尾的 `\\r?` 是给\n * CRLF 文本用的,不写会把 `\\r` 算进路径。\n */\nconst MEDIA_LINE_RE =\n /^[ \\t]*(?:[-*+][ \\t]+|\\d+\\.[ \\t]+)?(?<wrap>[`\"'*_]*)MEDIA:[ \\t]*(?<path>.+?)\\k<wrap>[ \\t]*[。,、;;,]?[ \\t]*\\r?$/gm\n\n/** 只判断「这行是不是正在写一个 MEDIA 行」,不要求路径已经写完。 */\nconst MEDIA_LINE_START_RE = /^[ \\t]*(?:[-*+][ \\t]+|\\d+\\.[ \\t]+)?[`\"'*_]*MEDIA:/\n\n/** 同时按 `/` 和 `\\` 取末段:daemon 可能跑在 Windows 上,路径是反斜杠分隔的。 */\nfunction basename(path: string): string {\n return path.split(/[/\\\\]/).filter(Boolean).pop() || path\n}\n\n/** 路径写成 `<...>` 的形式(Markdown 里包空格路径的写法)时剥掉尖括号。 */\nfunction unwrapMediaPath(path: string): string | null {\n if (!path.startsWith(\"<\")) return path\n const closingBracket = path.indexOf(\">\")\n // 流式输出里尖括号还没闭合,等后续 token 到齐再判断。\n if (closingBracket < 0) return null\n return `${path.slice(1, closingBracket)}${path.slice(closingBracket + 1)}`\n}\n\n/**\n * 能不能拿这个路径去下载。绝对路径原样交给服务端解析(它会把工作区路径映射进沙盒、\n * 并拒绝越界),所以这里只挡明显不该放过的:空路径和 `..`。\n */\nexport function isSafeMediaPath(path: string): boolean {\n if (!path) return false\n return !path.split(/[/\\\\]/).includes(\"..\")\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n}\n\nfunction foldMediaLines(text: string): string {\n return text.replace(MEDIA_LINE_RE, (match: string, _wrap: string, rawPath: string) => {\n const path = unwrapMediaPath(rawPath)\n if (path === null) return match\n const name = basename(path)\n if (!isSafeMediaPath(path)) {\n // 路径没法用,但 MEDIA: 是内部标记,不能就这么摆给用户看——退化成文件名。\n return `\\`${name}\\``\n }\n return `<${FILE_CARD_TAG} data-path=\"${escapeAttribute(path)}\" data-name=\"${escapeAttribute(name)}\">${escapeAttribute(name)}</${FILE_CARD_TAG}>`\n })\n}\n\n/**\n * 把 MEDIA 行折叠成文件卡片标签。\n *\n * `streaming` 时最后一行要特殊对待:MEDIA_LINE_RE 用 `$` 匹配行尾,而流式过程中最后一行\n * 随时都是「行尾」,逐 token 折叠会依次闪出 `MEDIA:`、半截路径的卡片、再变成正确卡片。\n * 所以正在写的那一行整行先不渲染,等它以换行结束、或消息转为 static 之后再折叠。\n *\n * 判据只能是 `streaming`,不能是「有没有尾随换行」:AssistantTurnBlock 传进来的文本是\n * trim 过的,静态消息永远没有尾随换行,那样判断会导致 MEDIA 行永远不折叠。\n */\nexport function collapseMediaTags(text: string, options?: { streaming?: boolean }): string {\n if (!text.includes(\"MEDIA:\")) return text\n if (!options?.streaming) return foldMediaLines(text)\n\n const newlineIndex = text.lastIndexOf(\"\\n\")\n const head = newlineIndex < 0 ? \"\" : text.slice(0, newlineIndex + 1)\n const lastLine = newlineIndex < 0 ? text : text.slice(newlineIndex + 1)\n\n if (MEDIA_LINE_START_RE.test(lastLine)) {\n return foldMediaLines(head)\n }\n return foldMediaLines(head) + lastLine\n}\n","import {\n Archive,\n Download,\n File,\n FileCode2,\n FileSpreadsheet,\n FileText,\n Film,\n Image,\n Loader2,\n Music,\n} from \"lucide-react\"\nimport { type ComponentPropsWithRef, useState } from \"react\"\nimport type { ExtraProps } from \"streamdown\"\nimport { useBladeClient } from \"../context\"\nimport { cn } from \"../lib/utils\"\nimport { isSafeMediaPath } from \"../lib/media-tags\"\n\nexport type FileCardProps = ComponentPropsWithRef<\"span\"> &\n ExtraProps & {\n \"data-path\"?: string\n \"data-name\"?: string\n dataPath?: string\n dataName?: string\n sessionId?: string\n }\n\nconst IMAGE_EXTS = new Set([\"png\", \"jpg\", \"jpeg\", \"gif\", \"svg\", \"webp\", \"ico\", \"bmp\"])\nconst SHEET_EXTS = new Set([\"xlsx\", \"xls\", \"xlsm\", \"xlsb\", \"csv\"])\nconst TEXT_EXTS = new Set([\"txt\", \"md\", \"markdown\", \"pdf\", \"doc\", \"docx\", \"rtf\"])\nconst CODE_EXTS = new Set([\"js\", \"jsx\", \"ts\", \"tsx\", \"py\", \"go\", \"json\", \"yaml\", \"yml\", \"html\", \"css\"])\nconst VIDEO_EXTS = new Set([\"mp4\", \"webm\", \"mov\", \"mkv\", \"avi\"])\nconst AUDIO_EXTS = new Set([\"mp3\", \"wav\", \"ogg\", \"m4a\", \"flac\"])\nconst ARCHIVE_EXTS = new Set([\"zip\", \"tar\", \"gz\", \"tgz\", \"rar\", \"7z\"])\n\nfunction getFileIcon(name: string) {\n const ext = name.split(\".\").pop()?.toLowerCase() ?? \"\"\n if (IMAGE_EXTS.has(ext)) return Image\n if (SHEET_EXTS.has(ext)) return FileSpreadsheet\n if (TEXT_EXTS.has(ext)) return FileText\n if (CODE_EXTS.has(ext)) return FileCode2\n if (VIDEO_EXTS.has(ext)) return Film\n if (AUDIO_EXTS.has(ext)) return Music\n if (ARCHIVE_EXTS.has(ext)) return Archive\n return File\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined\n}\n\nfunction extractChildrenText(children: unknown): string {\n if (typeof children === \"string\") return children\n if (Array.isArray(children)) return children.map(extractChildrenText).join(\"\")\n if (children && typeof children === \"object\" && \"props\" in children) {\n return extractChildrenText((children as { props?: { children?: unknown } }).props?.children)\n }\n return \"\"\n}\n\n/**\n * 智能体产出文件的下载卡片(由 MEDIA 行折叠而来)。\n *\n * 整张卡片只有一个动作:下载。第一方界面点卡片是「在右侧预览」,那依赖 app 的 artifact\n * 面板,SDK 里没有这块,所以不摆预览入口也不写预览文案——UI 不能承诺不存在的能力。\n */\nexport function FileCard({\n node,\n \"data-path\": pathAttribute,\n \"data-name\": nameAttribute,\n dataPath,\n dataName,\n sessionId,\n children,\n className,\n ...props\n}: FileCardProps) {\n const client = useBladeClient()\n const [downloading, setDownloading] = useState(false)\n const [failed, setFailed] = useState(false)\n\n // sanitize 之后属性可能以 kebab-case prop、camelCase prop 或 HAST node 属性抵达,\n // 三种都读一遍;全都没有时退回标签内容(折叠时写的就是文件名)。\n const nodeProperties =\n node && typeof node === \"object\" && \"properties\" in node\n ? (node.properties as Record<string, unknown>)\n : undefined\n const path =\n pathAttribute ??\n dataPath ??\n stringValue(nodeProperties?.[\"data-path\"]) ??\n stringValue(nodeProperties?.dataPath) ??\n \"\"\n const name =\n nameAttribute ??\n dataName ??\n stringValue(nodeProperties?.[\"data-name\"]) ??\n stringValue(nodeProperties?.dataName) ??\n extractChildrenText(children) ??\n \"\"\n\n const disabled = !sessionId || !isSafeMediaPath(path)\n const Icon = getFileIcon(name)\n\n const handleDownload = async () => {\n if (disabled || downloading || !sessionId) return\n setDownloading(true)\n setFailed(false)\n try {\n await client.sessions.downloadFile(sessionId, path, name)\n } catch {\n setFailed(true)\n } finally {\n setDownloading(false)\n }\n }\n\n return (\n <span {...props} className={cn(\"blade-chat-file-card\", className)}>\n <button\n type=\"button\"\n onClick={handleDownload}\n disabled={disabled || downloading}\n aria-label={`下载文件:${name}`}\n title={failed ? \"下载失败,点击重试\" : `下载 ${name}`}\n >\n <span className=\"blade-chat-file-card-icon\">\n {downloading ? <Loader2 size={15} className=\"animate-spin\" /> : <Icon size={15} />}\n </span>\n <span className=\"blade-chat-file-card-name\">{name}</span>\n <Download size={13} className=\"blade-chat-file-card-action\" />\n </button>\n {failed && <span className=\"blade-chat-file-card-error\">下载失败</span>}\n </span>\n )\n}\n","import { cn } from \"../lib/utils\"\n\ninterface ShimmerProps {\n children?: string\n className?: string\n}\n\n/** 流式等待时的呼吸文字效果(样式见 style.css 的 .blade-shimmer-text)。 */\nexport function Shimmer({ children = \"正在思考...\", className }: ShimmerProps) {\n return (\n <span className={cn(\"blade-shimmer-text text-sm font-medium\", className)}>{children}</span>\n )\n}\n","import type { AskUserAnswerData, ToolCallInfo } from \"@blade-hq/agent-client\"\nimport { Check, ChevronRight, Loader2, MessageSquareMore, X } from \"lucide-react\"\nimport { useState, type ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { AskUserQuestionBlock, parseAskUserQuestion } from \"./AskUserQuestionBlock\"\nimport {\n formatToolArgs,\n formatToolDuration,\n formatToolName,\n formatToolResult,\n getToolDisplayLabel,\n getToolStatusLabel,\n getToolTone,\n} from \"./display-utils\"\n\n/** 接入方自定义渲染器:返回 null 时回落到默认渲染。 */\nexport type ToolCallRenderer = (info: ToolCallInfo) => ReactNode | null\n\ninterface Props {\n toolCall: ToolCallInfo\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n answered?: boolean\n answerData?: AskUserAnswerData\n sessionStatus?: string\n renderer?: ToolCallRenderer\n}\n\n/**\n * 判断提问卡片该等待作答还是展示成已作答,只认工具状态。\n * 与 apps/web 的 ToolCallBlock 里同名函数保持一致:两处算出不同结果时,\n * 同一份会话在内置页面能点、在 SDK 里点不动。\n *\n * 不要再拿 sessionStatus 兜底。历史投影算错时用 waiting_for_input 补救,\n * 会同时把已经回答过的旧提问重新变成可作答(历史加载不会带回 answerData),\n * 而且会盖住投影层的错误——这个 bug 就是这么藏住的。\n */\nexport function resolveAskQuestionState({\n toolStatus,\n hasAnswerData,\n fallbackAnswered,\n}: {\n toolStatus: ToolCallInfo[\"status\"]\n hasAnswerData: boolean\n fallbackAnswered?: boolean\n}) {\n const awaitingAnswer = !hasAnswerData && toolStatus === \"awaiting_answer\"\n return {\n awaitingAnswer,\n answered:\n hasAnswerData ||\n (!awaitingAnswer &&\n (Boolean(fallbackAnswered) ||\n toolStatus === \"done\" ||\n toolStatus === \"cancelled\" ||\n toolStatus === \"error\")),\n }\n}\n\n/**\n * 极简工具调用块:状态 + 展示名一行,点开后是参数/结果的 <pre> 折叠展示。\n * AskUserQuestion 特殊处理为提问选项卡片。\n */\nexport function ToolCallBlock({\n toolCall,\n onAnswer,\n answered,\n answerData,\n sessionStatus,\n renderer,\n}: Props) {\n const [expanded, setExpanded] = useState(false)\n const normalizedName = formatToolName(toolCall.name)\n\n if (renderer) {\n const custom = renderer(toolCall)\n if (custom !== null && custom !== undefined) {\n return <>{custom}</>\n }\n }\n\n // AskUserQuestion:渲染成可作答的提问卡片\n if (normalizedName === \"AskUserQuestion\") {\n const askData =\n parseAskUserQuestion(typeof toolCall.result === \"string\" ? toolCall.result : null) ??\n parseAskUserQuestion(buildAskUserPayload(toolCall.arguments))\n const questionState = resolveAskQuestionState({\n toolStatus: toolCall.status,\n hasAnswerData: Boolean(answerData),\n fallbackAnswered: answered,\n })\n const canAnswer = questionState.awaitingAnswer && Boolean(onAnswer)\n if (askData) {\n return (\n <AskUserQuestionBlock\n data={askData}\n answered={questionState.answered}\n toolCallId={toolCall.id}\n sessionStatus={sessionStatus ?? \"\"}\n answerData={answerData}\n onAnswer={canAnswer ? onAnswer : undefined}\n />\n )\n }\n if (toolCall.status === \"pending\") {\n return (\n <div className=\"ml-4 flex max-w-lg items-center gap-2 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-4 text-sm text-[hsl(var(--muted-foreground))]\">\n <Loader2 size={14} className=\"animate-spin\" />\n <span>正在准备问题…</span>\n </div>\n )\n }\n return (\n <div className=\"ml-4 max-w-lg rounded-xl border border-amber-500/35 bg-amber-500/10 p-4 text-sm text-[hsl(var(--foreground))]\">\n <div className=\"font-semibold\">选择题内容暂时无法显示</div>\n <div className=\"mt-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]\">\n 收到的交互数据不完整。请让智能体重新提问。\n </div>\n </div>\n )\n }\n\n const tone = getToolTone(toolCall.status)\n const displayName = getToolDisplayLabel(toolCall)\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=\"blade-chat-tool ml-4 text-xs\">\n <div className={cn(\"border-l-[3px] flex items-center gap-2 px-3 py-2\", toneClass)}>\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 </span>\n </button>\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 </div>\n {expanded && (\n <div className=\"blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3\">\n <div className=\"mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]\">\n 工具\n </div>\n <div className=\"mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {normalizedName}\n </div>\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 {formatToolArgs(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 className=\"max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {formatToolResult(toolCall.result)}\n </pre>\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction buildAskUserPayload(argumentsJson: string): string | null {\n try {\n const parsed = JSON.parse(argumentsJson)\n if (\n parsed &&\n typeof parsed === \"object\" &&\n Array.isArray((parsed as { questions?: unknown }).questions)\n ) {\n return JSON.stringify({ questions: (parsed as { questions: unknown[] }).questions })\n }\n } catch {\n return null\n }\n return null\n}\n","import type { AskUserAnswerData } from \"@blade-hq/agent-client\"\nimport { Check, Loader2, MessageSquareMore } from \"lucide-react\"\nimport { useEffect, useMemo, useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { MarkdownContent } from \"./MarkdownContent\"\n\ninterface OptionItem {\n label: string\n description: string\n}\n\ninterface QuestionItem {\n question: string\n options: OptionItem[]\n multiSelect?: boolean\n}\n\ninterface SourceLoopInfo {\n loop_name: string\n description: string\n}\n\nexport interface AskUserQuestionData {\n questions: QuestionItem[]\n source_loop?: SourceLoopInfo | null\n}\n\ninterface Props {\n data: AskUserQuestionData\n answered: boolean\n toolCallId: string\n sessionStatus: string\n answerData?: AskUserAnswerData | undefined\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n}\n\n/** 提问选项卡片:单选/多选 + 自定义输入,回答通过 onAnswer 回调交还 ChatView。 */\nexport function AskUserQuestionBlock({\n data,\n answered,\n toolCallId,\n sessionStatus,\n answerData,\n onAnswer,\n}: Props) {\n // 每个问题独立的选择状态:选项下标集合或自定义文本\n const [selections, setSelections] = useState<Map<number, Set<number>>>(new Map())\n const [customTexts, setCustomTexts] = useState<Map<number, string>>(new Map())\n const [usingCustom, setUsingCustom] = useState<Set<number>>(new Set())\n const [submitted, setSubmitted] = useState(false)\n\n useEffect(() => {\n if (sessionStatus === \"failed\" || sessionStatus === \"interrupted\") {\n setSubmitted(false)\n }\n }, [sessionStatus])\n\n // 已作答时按历史答案展示,未作答时展示本地编辑状态\n const displayAnswerState = useMemo(() => {\n if (!(answered && answerData)) {\n return { selections, customTexts, usingCustom }\n }\n\n const nextSelections = new Map<number, Set<number>>()\n const nextCustomTexts = new Map<number, string>()\n const nextUsingCustom = new Set<number>()\n\n for (const [questionKey, optionIndexes] of Object.entries(answerData.selections)) {\n nextSelections.set(Number(questionKey), new Set(optionIndexes))\n }\n\n for (const [questionKey, text] of Object.entries(answerData.custom)) {\n const qIdx = Number(questionKey)\n nextCustomTexts.set(qIdx, text)\n nextUsingCustom.add(qIdx)\n }\n\n return {\n selections: nextSelections,\n customTexts: nextCustomTexts,\n usingCustom: nextUsingCustom,\n }\n }, [answerData, answered, customTexts, selections, usingCustom])\n\n const toggleOption = (qIdx: number, optIdx: number, multi: boolean) => {\n if (answered || submitted) return\n setSelections((prev) => {\n const next = new Map(prev)\n const current = new Set(next.get(qIdx) ?? [])\n if (multi) {\n if (current.has(optIdx)) current.delete(optIdx)\n else current.add(optIdx)\n } else {\n current.clear()\n current.add(optIdx)\n }\n next.set(qIdx, current)\n return next\n })\n setUsingCustom((prev) => {\n const next = new Set(prev)\n next.delete(qIdx)\n return next\n })\n }\n\n const handleCustomFocus = (qIdx: number) => {\n if (answered || submitted) return\n setSelections((prev) => {\n const next = new Map(prev)\n next.delete(qIdx)\n return next\n })\n setUsingCustom((prev) => new Set(prev).add(qIdx))\n }\n\n const setCustomText = (qIdx: number, text: string) => {\n if (answered || submitted) return\n setCustomTexts((prev) => new Map(prev).set(qIdx, text))\n }\n\n const getAnswer = (qIdx: number): string | null => {\n const q = data.questions[qIdx]\n if (usingCustom.has(qIdx)) {\n const text = (customTexts.get(qIdx) ?? \"\").trim()\n return text || null\n }\n const sel = selections.get(qIdx)\n if (!sel || sel.size === 0) return null\n return [...sel]\n .sort()\n .map((i) => q.options[i].label)\n .join(\", \")\n }\n\n const allAnswered = data.questions.every((_, i) => getAnswer(i) !== null)\n\n const handleSubmit = () => {\n if (answered || submitted || !allAnswered || !onAnswer) return\n\n const nextAnswerData: AskUserAnswerData = {\n selections: Object.fromEntries(\n Array.from(selections.entries()).map(([qIdx, optionIndexes]) => [\n qIdx,\n Array.from(optionIndexes).sort((a, b) => a - b),\n ]),\n ) as Record<number, number[]>,\n custom: Object.fromEntries(\n Array.from(usingCustom)\n .map((qIdx) => [qIdx, (customTexts.get(qIdx) ?? \"\").trim()] as const)\n .filter(([, text]) => text.length > 0),\n ) as Record<number, string>,\n }\n\n const parts = data.questions.map((q, i) => `- ${q.question} -> ${getAnswer(i)}`)\n const text = `关于需要确认的问题,用户的回答如下:\\n${parts.join(\"\\n\")}`\n setSubmitted(true)\n onAnswer(text, toolCallId, nextAnswerData)\n }\n\n return (\n <div\n className={cn(\n \"blade-chat-ask-card ml-4 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))]\",\n answered\n ? \"max-w-2xl space-y-3 p-3 text-xs text-[hsl(var(--muted-foreground))] opacity-80\"\n : \"max-w-lg space-y-5 p-4 text-sm\",\n )}\n >\n {data.source_loop?.description && (\n <div className=\"rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]\">\n 子智能体「{data.source_loop.description}」在等待你的回答\n </div>\n )}\n {data.questions.map((q, qIdx) => (\n <QuestionCard\n key={q.question}\n question={q}\n qIdx={qIdx}\n answered={answered}\n selected={displayAnswerState.selections.get(qIdx) ?? new Set()}\n isCustom={displayAnswerState.usingCustom.has(qIdx)}\n customText={displayAnswerState.customTexts.get(qIdx) ?? \"\"}\n onToggle={toggleOption}\n onCustomFocus={handleCustomFocus}\n onCustomChange={setCustomText}\n />\n ))}\n\n {!answered && !submitted && onAnswer && (\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!allAnswered}\n className=\"w-full rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {allAnswered ? \"确认\" : \"请先选择一个选项\"}\n </button>\n )}\n\n {submitted && !answered && (\n <button\n type=\"button\"\n disabled\n className=\"flex w-full items-center justify-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] opacity-80\"\n >\n <Loader2 size={14} className=\"animate-spin\" />\n 确认中\n </button>\n )}\n </div>\n )\n}\n\nfunction QuestionCard({\n question,\n qIdx,\n answered,\n selected,\n isCustom,\n customText,\n onToggle,\n onCustomFocus,\n onCustomChange,\n}: {\n question: QuestionItem\n qIdx: number\n answered: boolean\n selected: Set<number>\n isCustom: boolean\n customText: string\n onToggle: (qIdx: number, optIdx: number, multi: boolean) => void\n onCustomFocus: (qIdx: number) => void\n onCustomChange: (qIdx: number, text: string) => void\n}) {\n const multi = question.multiSelect ?? false\n\n return (\n <div>\n <div className={cn(\"flex items-start gap-2\", answered ? \"mb-2\" : \"mb-3\")}>\n <MessageSquareMore\n size={answered ? 12 : 13}\n className=\"mt-0.5 shrink-0 text-[hsl(var(--primary))]\"\n />\n <div\n className={cn(\n \"min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]\",\n answered ? \"text-xs\" : \"text-sm\",\n )}\n >\n <MarkdownContent className=\"blade-chat-prose\">{question.question}</MarkdownContent>\n </div>\n </div>\n\n <div className={cn(\"flex flex-col pl-5\", answered ? \"gap-1\" : \"gap-1.5\")}>\n {question.options.map((opt, optIdx) => {\n const isSel = selected.has(optIdx)\n return (\n <button\n key={opt.label}\n type=\"button\"\n disabled={answered}\n onClick={() => onToggle(qIdx, optIdx, multi)}\n className={cn(\n \"flex items-start gap-2.5 rounded-lg border text-left transition-all\",\n answered ? \"px-2.5 py-1.5\" : \"px-3 py-2.5\",\n isSel && !answered\n ? \"border-[hsl(var(--primary)/0.8)] bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]\"\n : isSel\n ? \"border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.08)] text-[hsl(var(--foreground))]\"\n : \"border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.2)]\",\n !answered &&\n !isSel &&\n \"hover:border-[hsl(var(--ring)/0.4)] hover:bg-[hsl(var(--accent))]\",\n answered && \"cursor-default opacity-70\",\n )}\n >\n {multi && (\n <div\n className={cn(\n \"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors\",\n isSel && !answered\n ? \"border-[hsl(var(--primary-foreground)/0.6)] bg-[hsl(var(--primary-foreground)/0.2)]\"\n : isSel\n ? \"border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.12)]\"\n : \"border-[hsl(var(--border))]\",\n )}\n >\n {isSel && (\n <Check\n size={9}\n className={\n answered\n ? \"text-[hsl(var(--primary))]\"\n : \"text-[hsl(var(--primary-foreground))]\"\n }\n />\n )}\n </div>\n )}\n <div className=\"min-w-0\">\n <div className={cn(\"font-medium\", answered ? \"text-xs\" : \"text-[13px]\")}>\n {opt.label}\n </div>\n {opt.description && (\n <div\n className={cn(\n \"mt-0.5\",\n answered ? \"text-[11px]\" : \"text-xs\",\n isSel && !answered ? \"opacity-75\" : \"text-[hsl(var(--muted-foreground))]\",\n )}\n >\n {opt.description}\n </div>\n )}\n </div>\n </button>\n )\n })}\n\n {/* 「其他」内联输入 */}\n {answered && !isCustom ? null : (\n <div\n className={cn(\n \"flex items-center gap-2 rounded-lg border transition-all\",\n answered ? \"px-2.5 py-1.5\" : \"px-3 py-2.5\",\n isCustom\n ? \"border-[hsl(var(--ring)/0.6)] bg-[hsl(var(--accent))]\"\n : \"border-[hsl(var(--border))] hover:border-[hsl(var(--ring)/0.3)] hover:bg-[hsl(var(--accent))]\",\n answered && \"cursor-default opacity-70\",\n )}\n >\n <span className=\"shrink-0 text-xs text-[hsl(var(--muted-foreground))]\">其他:</span>\n <input\n type=\"text\"\n value={customText}\n disabled={answered}\n onChange={(e) => onCustomChange(qIdx, e.target.value)}\n onFocus={() => onCustomFocus(qIdx)}\n aria-label=\"自定义回答\"\n placeholder=\"输入你的答案...\"\n className={cn(\n \"min-w-0 flex-1 bg-transparent text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.5)]\",\n answered ? \"text-xs\" : \"text-sm\",\n )}\n />\n </div>\n )}\n </div>\n </div>\n )\n}\n\n/** 解析 AskUserQuestion 的工具结果/参数,容错 LLM 把 questions 输出为字符串的情况。 */\nexport function parseAskUserQuestion(\n toolResult: string | null | undefined,\n): AskUserQuestionData | null {\n if (!toolResult) return null\n try {\n const parsed = JSON.parse(toolResult)\n let questions = parsed?.questions\n if (typeof questions === \"string\") {\n try {\n questions = JSON.parse(questions)\n } catch {\n return null\n }\n }\n if (Array.isArray(questions) && questions.length > 0) {\n const normalized = questions.map(normalizeQuestionItem)\n if (normalized.every((question): question is QuestionItem => question !== null)) {\n return { ...parsed, questions: normalized } as AskUserQuestionData\n }\n }\n } catch {\n // 非 JSON,忽略\n }\n return null\n}\n\nfunction normalizeQuestionItem(value: unknown): QuestionItem | null {\n if (!value || typeof value !== \"object\") return null\n const item = value as {\n question?: unknown\n options?: unknown\n multiSelect?: unknown\n multi_select?: unknown\n }\n if (typeof item.question !== \"string\" || !Array.isArray(item.options)) return null\n const options = item.options.map(normalizeOptionItem)\n if (!options.every((option): option is OptionItem => option !== null)) return null\n return {\n question: item.question,\n options,\n multiSelect: item.multiSelect === true || item.multi_select === true,\n }\n}\n\nfunction normalizeOptionItem(value: unknown): OptionItem | null {\n if (typeof value === \"string\") return { label: value, description: \"\" }\n if (!value || typeof value !== \"object\") return null\n const option = value as { label?: unknown; description?: unknown }\n if (typeof option.label !== \"string\") return null\n return {\n label: option.label,\n description: typeof option.description === \"string\" ? option.description : \"\",\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\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=\"blade-chat-render-error 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 type { ChatMessage } from \"@blade-hq/agent-client\"\nimport { getFileParts, getImageParts, getTextContent } from \"@blade-hq/agent-client\"\nimport { FileText, Loader2 } from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\nimport { MarkdownContent } from \"./MarkdownContent\"\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\nconst isSending = (message: ChatMessage) => message.status === \"streaming\"\n\n/** 用户消息气泡:文本 + 图片/文件附件展示(不含第一方的预览弹窗与 what-if 徽章)。 */\nexport function UserMessageBubble({ message, className }: UserMessageProps) {\n const text = getTextContent(message.content).trim()\n const fileParts = getFileParts(message.content)\n const imageParts = getImageParts(message.content)\n\n return (\n <div className={cn(\"blade-chat-user-row flex justify-end\", className)}>\n <div className=\"blade-chat-user-col flex max-w-[72%] flex-col items-end 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-64 rounded-xl border border-[hsl(var(--user-msg-border))] object-cover\"\n />\n ))}\n </div>\n )}\n {fileParts.length > 0 && (\n <div className=\"flex flex-col items-end gap-1.5\">\n {fileParts.map((part) => (\n <div\n key={`${part.name}-${part.data.length}`}\n className=\"flex items-center gap-1.5 rounded-lg border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--muted)/0.3)] px-2.5 py-1.5 text-xs text-[hsl(var(--muted-foreground))]\"\n >\n <FileText size={12} className=\"shrink-0\" />\n <span className=\"max-w-56 truncate\" title={part.name}>\n {part.name}\n </span>\n </div>\n ))}\n </div>\n )}\n {text && (\n <div className=\"blade-chat-user-bubble max-w-full rounded-[20px] rounded-br-[6px] border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-[18px] py-[13px] text-sm leading-[1.65] text-[hsl(var(--user-msg-fg))]\">\n <MarkdownContent className=\"blade-chat-prose\">{text}</MarkdownContent>\n </div>\n )}\n {text && isSending(message) && (\n <div className=\"flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]\">\n <Loader2 size={11} className=\"animate-spin\" aria-hidden=\"true\" />\n <span>发送中</span>\n </div>\n )}\n </div>\n </div>\n )\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 return (\n <div className={cn(\"blade-chat-error-row flex justify-center\", className)}>\n {/* 与内置 Web 的 ErrorMessageBlock 保持一致:消息流里的错误不用红色。 */}\n <div className=\"blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--border))] px-4 py-1 text-sm leading-7 text-[hsl(var(--muted-foreground))]\">\n {text}\n </div>\n </div>\n )\n}\n","// ============================== React 绑定 ==============================\nexport { BladeProvider, useBladeClient } from \"./context\"\nexport type { BladeProviderProps } from \"./context\"\nexport { useAgentSession } from \"./hooks/use-agent-session\"\nexport type { UseAgentSessionOptions, UseAgentSessionResult } from \"./hooks/use-agent-session\"\n\n// ============================== 聊天界面 ==============================\nexport { ChatView } from \"./components/ChatView\"\nexport type {\n ChatViewClassNames,\n ChatViewProps,\n ChatViewRenderers,\n ChatViewSlots,\n} from \"./components/ChatView\"\nexport { MarkdownContent } from \"./components/MarkdownContent\"\nexport type { MarkdownContentProps } from \"./components/MarkdownContent\"\nexport type { ToolCallRenderer } from \"./components/ToolCallBlock\"\n\n// ============================== 客户端全量转出 ==============================\n// 方便接入方只装一个包:agent-client 的全部公共面从这里原样可用。\nexport * from \"@blade-hq/agent-client\"\n"],"mappings":"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","names":["Component","forwardRef","createElement","useEffect","useState","jsx","jsx","jsxs","useCallback","useEffect","useMemo","useRef","useState","useMemo","useRef","useState","isAtBottom","escapedFromLock","createContext","useContext","useEffect","useMemo","useRef","createContext","useEffect","useRef","useMemo","targetScrollTop","StickToBottom","useContext","useState","useState","jsx","jsxs","useState","useEffect","useMemo","useRef","useState","useState","jsx","jsxs","useState","Icon","jsx","jsxs","useRef","useState","useEffect","useMemo","jsx","useState","useEffect","useMemo","useState","jsx","jsxs","useState","useEffect","useMemo","text","jsx","jsxs","useState","jsx","jsxs","useState","jsx","jsxs","getTextContent","jsx","jsxs","getTextContent","jsx","jsxs","useMemo","useRef","useEffect","useState","useCallback","jsx","jsxs","useState","useEffect"]}
1
+ {"version":3,"sources":["../src/context.tsx","../src/hooks/use-agent-session.ts","../src/components/ChatView.tsx","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/shared/src/utils.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/defaultAttributes.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/Icon.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/createLucideIcon.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/arrow-up.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/bot.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/brain.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/check.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/chevron-down.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/chevron-right.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/circle-alert.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/copy.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/file-text.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/layers.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/lightbulb.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/loader-circle.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/lock-keyhole.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/message-square-more.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/message-square.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/square.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/triangle-alert.ts","../../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/src/icons/x.ts","../src/lib/utils.ts","../src/components/ChatInput.tsx","../src/components/ConnectionBanner.tsx","../src/components/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/components/AssistantTurnBlock.tsx","../src/components/AgentLoopBlock.tsx","../src/components/display-utils.ts","../src/components/MarkdownContent.tsx","../src/lib/media-tags.ts","../src/components/FileCard.tsx","../src/components/Shimmer.tsx","../src/components/ToolCallBlock.tsx","../src/components/AskUserQuestionBlock.tsx","../src/components/RenderErrorBoundary.tsx","../src/components/UserMessageBubble.tsx","../src/index.ts"],"sourcesContent":["import type { BladeClient } from \"@blade-hq/agent-client\"\nimport { createContext, useContext, type ReactNode } from \"react\"\n\nconst BladeClientContext = createContext<BladeClient | null>(null)\n\nexport interface BladeProviderProps {\n client: BladeClient\n children: ReactNode\n}\n\n/**\n * 提供 client 级共享(一条连接、一份鉴权)。不含任何全局状态:\n * 同一 Provider 下多个 ChatView / useAgentSession 各自独立。\n */\nexport function BladeProvider({ client, children }: BladeProviderProps) {\n return <BladeClientContext.Provider value={client}>{children}</BladeClientContext.Provider>\n}\n\n/** 读取当前 BladeProvider 提供的 client。不在 Provider 内使用时抛错。 */\nexport function useBladeClient(): BladeClient {\n const client = useContext(BladeClientContext)\n if (!client) {\n throw new Error(\"useBladeClient 必须在 <BladeProvider> 内使用\")\n }\n return client\n}\n","import type {\n AgentSession,\n CreateSessionRequest,\n SessionState,\n} from \"@blade-hq/agent-client\"\nimport { useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\"\nimport { useBladeClient } from \"../context\"\n\nexport interface UseAgentSessionOptions {\n /** 不传 sessionId 时按此配置新建会话;两者都不传则新建默认对话。 */\n createOptions?: CreateSessionRequest\n /** 自动创建出的 sessionId 通过此回调交还调用方持有(重挂载复用的依据)。 */\n onSessionCreated?: (sessionId: string) => void\n}\n\nexport interface UseAgentSessionResult {\n /** 连接/创建完成前为 null。 */\n session: AgentSession | null\n /** 会话状态快照;session 未就绪时为 null。 */\n state: SessionState | null\n /** 连接或创建失败的错误。 */\n error: Error | null\n}\n\nconst EMPTY_SUBSCRIBE = () => () => {}\n\n/** 卸载后延迟释放引用:StrictMode/路由抖动的立即重挂载会在窗口内重新\n * connect(引用计数 +1),延迟 dispose 只把计数减回去,实例得以复用;\n * 真正的卸载则在窗口结束后正常释放订阅。 */\nconst DISPOSE_DELAY_MS = 1000\n\n/**\n * 连接(或创建)一个会话并订阅其状态。\n *\n * - 优先级:sessionId(连接既有会话)> createOptions(按配置新建)> 默认新建。\n * - 同一 sessionId 重复调用复用同一 AgentSession 实例(SessionHub 引用计数)。\n * - 自动创建只发生一次(含 StrictMode 双跑);创建出的 id 经 onSessionCreated\n * 交还调用方。\n *\n * **连接与 sessionId 变更分离**:连接在挂载时建立、仅在卸载时释放;只有\n * 当 sessionId 明确切到一个「与当前已连接会话不同」的 id 时才重连。这样宿主\n * (如 Vue 把自动创建的 id 写回 `session-id` 属性)回填同一个 id 不会触发\n * 拆–重连——否则会把正在流式的会话换成新实例、当前渲染整个丢失。\n */\nexport function useAgentSession(\n sessionId?: string,\n options: UseAgentSessionOptions = {},\n): UseAgentSessionResult {\n const client = useBladeClient()\n const [session, setSession] = useState<AgentSession | null>(null)\n const [error, setError] = useState<Error | null>(null)\n\n // 当前连接:id + 实例 + 一个递增的「代」号,用于让过期的异步连接结果作废。\n const connRef = useRef<{ id: string | null; session: AgentSession | null; gen: number }>({\n id: null,\n session: null,\n gen: 0,\n })\n // 自动创建去重:StrictMode 双跑时同一组件实例只创建一次会话。\n const createdIdPromiseRef = useRef<Promise<string> | null>(null)\n const onCreatedRef = useRef(options.onSessionCreated)\n onCreatedRef.current = options.onSessionCreated\n const createOptionsRef = useRef(options.createOptions)\n createOptionsRef.current = options.createOptions\n // 最新的目标 sessionId,供挂载 effect 的异步链读取(不进依赖,避免重连)。\n const sessionIdRef = useRef(sessionId)\n sessionIdRef.current = sessionId\n\n // 把「连接到某个 id / 自动创建」封成一次操作;gen 作废过期结果。\n const connect = useMemo(() => {\n return (targetId: string | undefined) => {\n const gen = ++connRef.current.gen\n const idPromise = targetId\n ? Promise.resolve(targetId)\n : // biome-ignore lint/suspicious/noAssignInExpressions: ??= 挂 ref 是 StrictMode 下\"只创建一次\"的关键\n (createdIdPromiseRef.current ??= client.sessions\n .create(createOptionsRef.current ?? {})\n .then((created) => {\n // create() 的实例引用立即归还,由下面的 connect() 统一取,避免多挂一份计数\n const id = created.sessionId\n created.dispose()\n onCreatedRef.current?.(id)\n return id\n }))\n\n idPromise\n .then((id) => client.hub.connect(id))\n .then((next) => {\n if (connRef.current.gen !== gen) {\n next.dispose() // 已被更新的连接请求取代\n return\n }\n connRef.current.id = next.sessionId\n connRef.current.session = next\n setSession(next)\n setError(null)\n })\n .catch((err) => {\n if (connRef.current.gen !== gen) return\n createdIdPromiseRef.current = null // 创建失败允许下次重试\n setError(err instanceof Error ? err : new Error(String(err)))\n })\n }\n }, [client])\n\n // 挂载时建立连接,仅在卸载(或 client 变化)时释放。\n useEffect(() => {\n connect(sessionIdRef.current)\n return () => {\n connRef.current.gen++ // 作废在途的连接结果\n const toRelease = connRef.current.session\n connRef.current.id = null\n connRef.current.session = null\n setSession(null)\n if (toRelease) setTimeout(() => toRelease.dispose(), DISPOSE_DELAY_MS)\n }\n }, [connect])\n\n // 仅当 sessionId 明确切到「与已连接会话不同」的 id 时才重连。\n // 回填自动创建的 id(sessionId === 已连接 id)在此被跳过。\n useEffect(() => {\n if (!sessionId) return\n if (connRef.current.id === null) return // 首连仍在进行,交给挂载 effect\n if (sessionId === connRef.current.id) return\n const previous = connRef.current.session\n connRef.current.id = null\n connRef.current.session = null\n if (previous) setTimeout(() => previous.dispose(), DISPOSE_DELAY_MS)\n connect(sessionId)\n }, [sessionId, connect])\n\n const store = useMemo(\n () => ({\n subscribe: session ? (listener: () => void) => session.subscribe(listener) : EMPTY_SUBSCRIBE,\n getSnapshot: () => (session ? session.getState() : null),\n }),\n [session],\n )\n const state = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot)\n\n return { session, state, error }\n}\n","import type { AgentSession, BladeClient, CreateSessionRequest } from \"@blade-hq/agent-client\"\nimport { BladeApiError } from \"@blade-hq/agent-client\"\nimport { CircleAlert, LockKeyhole } from \"lucide-react\"\nimport { useEffect, useState, type ReactNode } from \"react\"\nimport { useBladeClient } from \"../context\"\nimport { useAgentSession } from \"../hooks/use-agent-session\"\nimport { cn } from \"../lib/utils\"\nimport { ChatInput } from \"./ChatInput\"\nimport { ConnectionBanner } from \"./ConnectionBanner\"\nimport { MessageList } from \"./MessageList\"\nimport type { ToolCallRenderer } from \"./ToolCallBlock\"\n\nexport interface ChatViewClassNames {\n root?: string\n banner?: string\n messageList?: string\n chatInput?: string\n}\n\nexport interface ChatViewRenderers {\n /** 自定义工具调用渲染;返回 null 走默认渲染。 */\n toolCall?: ToolCallRenderer\n}\n\nexport interface ChatViewSlots {\n /** 消息列表上方的自定义区域。 */\n header?: ReactNode\n /** 无消息时的空状态。 */\n emptyState?: ReactNode\n /** 输入框下方的自定义区域。 */\n footer?: ReactNode\n}\n\nexport interface ChatViewProps {\n /** 连接既有会话;不传则按 createOptions 自动新建。 */\n sessionId?: string\n createOptions?: CreateSessionRequest\n /** 自动创建出的 sessionId 通过此回调交还调用方持有。 */\n onSessionCreated?: (sessionId: string) => void\n /** 会话连接完成后回调(页面协作场景拿 AgentSession 实例用)。 */\n onSessionReady?: (session: AgentSession) => void\n /** 智能体下发给宿主页面的指令处理器(action → handler)。 */\n commands?: Record<string, (data: unknown) => void>\n classNames?: ChatViewClassNames\n renderers?: ChatViewRenderers\n slots?: ChatViewSlots\n placeholder?: string\n /** 配色主题,默认浅色。宿主已经在祖先元素上写了 data-theme 时不用传。 */\n theme?: \"light\" | \"dark\"\n}\n\n/** 主题落到聊天根节点上:深色变量挂在 [data-theme=\"dark\"] 上,由它继承给整棵子树。 */\nfunction themeAttr(theme: ChatViewProps[\"theme\"]): \"dark\" | undefined {\n return theme === \"dark\" ? \"dark\" : undefined\n}\n\nfunction isUnauthorizedError(error: Error | null): boolean {\n return error instanceof BladeApiError && error.status === 401\n}\n\n/** 登录引导卡片:未持有令牌或令牌失效时展示,按钮走弹窗授权。 */\nfunction LoginCard({ client, onLoggedIn }: { client: BladeClient; onLoggedIn: () => void }) {\n const [loggingIn, setLoggingIn] = useState(false)\n const [loginError, setLoginError] = useState<string | null>(null)\n\n const handleLogin = async () => {\n setLoggingIn(true)\n setLoginError(null)\n try {\n await client.login()\n onLoggedIn()\n } catch (error) {\n setLoginError(error instanceof Error && error.message ? error.message : \"登录失败,请重试\")\n } finally {\n setLoggingIn(false)\n }\n }\n\n return (\n <div className=\"blade-chat-login flex flex-1 items-center justify-center p-6\">\n <div className=\"flex w-full max-w-sm flex-col items-center gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-6 py-8 text-center\">\n <LockKeyhole size={28} className=\"text-[hsl(var(--muted-foreground))]\" />\n <div className=\"text-base font-medium text-[hsl(var(--foreground))]\">需要登录后使用</div>\n <div className=\"text-sm text-[hsl(var(--muted-foreground))]\">\n 登录后即可与智能体对话,你的会话内容仅自己可见。\n </div>\n <button\n type=\"button\"\n onClick={handleLogin}\n disabled={loggingIn}\n className=\"w-full rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-sm font-semibold text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:opacity-60\"\n >\n {loggingIn ? \"登录中…\" : \"登录\"}\n </button>\n {loginError && <div className=\"text-xs text-[hsl(var(--destructive))]\">{loginError}</div>}\n </div>\n </div>\n )\n}\n\n/**\n * 开箱即用的聊天界面:连接(或新建)一个会话,渲染消息流与输入框。\n * 状态全部来自 useAgentSession,不依赖任何全局 store。\n */\nexport function ChatView(props: ChatViewProps) {\n const client = useBladeClient()\n // attempt 作为会话子树的 key:登录成功后整体重挂载,重新走连接/创建流程\n const [attempt, setAttempt] = useState(0)\n const [needLogin, setNeedLogin] = useState(() => !client.hasToken())\n\n if (needLogin) {\n return (\n <div\n data-theme={themeAttr(props.theme)}\n className={cn(\"blade-chat flex min-h-0 flex-1 flex-col\", props.classNames?.root)}\n >\n <LoginCard\n client={client}\n onLoggedIn={() => {\n setNeedLogin(false)\n setAttempt((value) => value + 1)\n }}\n />\n </div>\n )\n }\n\n return (\n <ChatSessionView key={attempt} {...props} onUnauthorized={() => setNeedLogin(true)} />\n )\n}\n\nfunction ChatSessionView({\n sessionId,\n createOptions,\n onSessionCreated,\n onSessionReady,\n commands,\n classNames,\n renderers,\n slots,\n placeholder,\n theme,\n onUnauthorized,\n}: ChatViewProps & { onUnauthorized: () => void }) {\n const { session, state, error } = useAgentSession(sessionId, {\n createOptions,\n onSessionCreated,\n })\n const [stopRequested, setStopRequested] = useState(false)\n const [inputText, setInputText] = useState(\"\")\n\n // 会话就绪后交还实例\n useEffect(() => {\n if (session) {\n onSessionReady?.(session)\n }\n }, [session, onSessionReady])\n\n // session.attach() / insertText() 注入到输入框:页面把业务数据(如地图选中\n // 的点位)塞进输入框,随下一条消息发给智能体。\n useEffect(() => {\n if (!session) return\n const offAttach = session.on(\"attachRequested\", ({ label, content }) => {\n setInputText((prev) => `${prev ? `${prev}\\n\\n` : \"\"}[${label}]\\n${content}`)\n })\n const offInsert = session.on(\"insertTextRequested\", ({ text }) => {\n setInputText((prev) => prev + text)\n })\n return () => {\n offAttach()\n offInsert()\n }\n }, [session])\n\n // 令牌失效(401)时回到登录引导\n useEffect(() => {\n if (isUnauthorizedError(error)) {\n onUnauthorized()\n }\n }, [error, onUnauthorized])\n\n // 注册宿主页面指令:卸载或 commands 变化时反注册\n useEffect(() => {\n if (!session || !commands) return\n const unsubscribes = Object.entries(commands).map(([action, handler]) =>\n session.onCommand(action, (payload) => handler(payload)),\n )\n return () => {\n for (const unsubscribe of unsubscribes) unsubscribe()\n }\n }, [session, commands])\n\n const isStreaming = state?.isStreaming ?? false\n const isStopping = stopRequested && isStreaming\n const connectError =\n error && !isUnauthorizedError(error)\n ? error.message || \"连接失败,请稍后重试\"\n : null\n const errorMessage = connectError ?? state?.errorMessage ?? null\n\n const handleSend = (text: string): Promise<boolean> => {\n setStopRequested(false)\n return session?.send(text, { mode: state?.mode ?? undefined }) ?? Promise.resolve(false)\n }\n\n const handleStop = () => {\n setStopRequested(true)\n void session?.stop()\n }\n\n return (\n <div\n data-theme={themeAttr(theme)}\n className={cn(\n \"blade-chat flex min-h-0 flex-1 flex-col overflow-hidden\",\n classNames?.root,\n )}\n >\n <ConnectionBanner\n connection={state?.connection ?? \"connecting\"}\n className={classNames?.banner}\n />\n {/* 出错条的配色由 .blade-chat-error-bar 的 --destructive 变量给,别写死 red-*:\n Tailwind 的 dark: 变体跟的是系统偏好,会和 data-theme 主题打架。 */}\n {errorMessage && (\n <div className=\"blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm\">\n <CircleAlert size={16} className=\"mt-0.5 shrink-0\" />\n <span>{errorMessage}</span>\n </div>\n )}\n {slots?.header}\n <MessageList\n messages={state?.messages ?? []}\n isStreaming={isStreaming}\n sessionStatus={state?.status ?? undefined}\n askAnswers={state?.askAnswers}\n onAnswer={(answer, toolCallId, answerData) => {\n void session?.send(answer, {\n mode: state?.mode ?? undefined,\n askUserAnswer: { tool_call_id: toolCallId, ...answerData },\n })\n }}\n toolCallRenderer={renderers?.toolCall}\n emptyState={slots?.emptyState}\n className={classNames?.messageList}\n // 用 session 自己持有的 id,不是 sessionId prop——后者是可选的,\n // 自动建会话时一直是 undefined,文件卡片会永远不可用。\n sessionId={session?.sessionId}\n />\n <ChatInput\n value={inputText}\n onValueChange={setInputText}\n onSend={handleSend}\n onStop={handleStop}\n isStreaming={isStreaming}\n isStopping={isStopping}\n placeholder={placeholder}\n className={classNames?.chatInput}\n />\n {slots?.footer}\n </div>\n )\n}\n","import { CamelToPascal } from './utility-types';\n\n/**\n * Converts string to kebab case\n *\n * @param {string} string\n * @returns {string} A kebabized string\n */\nexport const toKebabCase = (string: string) =>\n string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Converts string to camel case\n *\n * @param {string} string\n * @returns {string} A camelized string\n */\nexport const toCamelCase = <T extends string>(string: T) =>\n string.replace(/^([A-Z])|[\\s-_]+(\\w)/g, (match, p1, p2) =>\n p2 ? p2.toUpperCase() : p1.toLowerCase(),\n );\n\n/**\n * Converts string to pascal case\n *\n * @param {string} string\n * @returns {string} A pascalized string\n */\nexport const toPascalCase = <T extends string>(string: T): CamelToPascal<T> => {\n const camelCase = toCamelCase(string);\n\n return (camelCase.charAt(0).toUpperCase() + camelCase.slice(1)) as CamelToPascal<T>;\n};\n\n/**\n * Merges classes into a single string\n *\n * @param {array} classes\n * @returns {string} A string of classes\n */\nexport const mergeClasses = <ClassType = string | undefined | null>(...classes: ClassType[]) =>\n classes\n .filter((className, index, array) => {\n return (\n Boolean(className) &&\n (className as string).trim() !== '' &&\n array.indexOf(className) === index\n );\n })\n .join(' ')\n .trim();\n","export default {\n xmlns: 'http://www.w3.org/2000/svg',\n width: 24,\n height: 24,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n};\n","import { createElement, forwardRef } from 'react';\nimport defaultAttributes from './defaultAttributes';\nimport { IconNode, LucideProps } from './types';\nimport { mergeClasses } from '@lucide/shared';\n\ninterface IconComponentProps extends LucideProps {\n iconNode: IconNode;\n}\n\n/**\n * Lucide icon component\n *\n * @component Icon\n * @param {object} props\n * @param {string} props.color - The color of the icon\n * @param {number} props.size - The size of the icon\n * @param {number} props.strokeWidth - The stroke width of the icon\n * @param {boolean} props.absoluteStrokeWidth - Whether to use absolute stroke width\n * @param {string} props.className - The class name of the icon\n * @param {IconNode} props.children - The children of the icon\n * @param {IconNode} props.iconNode - The icon node of the icon\n *\n * @returns {ForwardRefExoticComponent} LucideIcon\n */\nconst Icon = forwardRef<SVGSVGElement, IconComponentProps>(\n (\n {\n color = 'currentColor',\n size = 24,\n strokeWidth = 2,\n absoluteStrokeWidth,\n className = '',\n children,\n iconNode,\n ...rest\n },\n ref,\n ) => {\n return createElement(\n 'svg',\n {\n ref,\n ...defaultAttributes,\n width: size,\n height: size,\n stroke: color,\n strokeWidth: absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth,\n className: mergeClasses('lucide', className),\n ...rest,\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...(Array.isArray(children) ? children : [children]),\n ],\n );\n },\n);\n\nexport default Icon;\n","import { createElement, forwardRef } from 'react';\nimport { mergeClasses, toKebabCase } from '@lucide/shared';\nimport { IconNode, LucideProps } from './types';\nimport Icon from './Icon';\n\n/**\n * Create a Lucide icon component\n * @param {string} iconName\n * @param {array} iconNode\n * @returns {ForwardRefExoticComponent} LucideIcon\n */\nconst createLucideIcon = (iconName: string, iconNode: IconNode) => {\n const Component = forwardRef<SVGSVGElement, LucideProps>(({ className, ...props }, ref) =>\n createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(`lucide-${toKebabCase(iconName)}`, className),\n ...props,\n }),\n );\n\n Component.displayName = `${iconName}`;\n\n return Component;\n};\n\nexport default createLucideIcon;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name ArrowUp\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJtNSAxMiA3LTcgNyA3IiAvPgogIDxwYXRoIGQ9Ik0xMiAxOVY1IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/arrow-up\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ArrowUp = createLucideIcon('ArrowUp', [\n ['path', { d: 'm5 12 7-7 7 7', key: 'hav0vg' }],\n ['path', { d: 'M12 19V5', key: 'x0mq9r' }],\n]);\n\nexport default ArrowUp;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Bot\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTIgOFY0SDgiIC8+CiAgPHJlY3Qgd2lkdGg9IjE2IiBoZWlnaHQ9IjEyIiB4PSI0IiB5PSI4IiByeD0iMiIgLz4KICA8cGF0aCBkPSJNMiAxNGgyIiAvPgogIDxwYXRoIGQ9Ik0yMCAxNGgyIiAvPgogIDxwYXRoIGQ9Ik0xNSAxM3YyIiAvPgogIDxwYXRoIGQ9Ik05IDEzdjIiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/bot\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Bot = createLucideIcon('Bot', [\n ['path', { d: 'M12 8V4H8', key: 'hb8ula' }],\n ['rect', { width: '16', height: '12', x: '4', y: '8', rx: '2', key: 'enze0r' }],\n ['path', { d: 'M2 14h2', key: 'vft8re' }],\n ['path', { d: 'M20 14h2', key: '4cs60a' }],\n ['path', { d: 'M15 13v2', key: '1xurst' }],\n ['path', { d: 'M9 13v2', key: 'rq6x2g' }],\n]);\n\nexport default Bot;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Brain\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTIgNWEzIDMgMCAxIDAtNS45OTcuMTI1IDQgNCAwIDAgMC0yLjUyNiA1Ljc3IDQgNCAwIDAgMCAuNTU2IDYuNTg4QTQgNCAwIDEgMCAxMiAxOFoiIC8+CiAgPHBhdGggZD0iTTEyIDVhMyAzIDAgMSAxIDUuOTk3LjEyNSA0IDQgMCAwIDEgMi41MjYgNS43NyA0IDQgMCAwIDEtLjU1NiA2LjU4OEE0IDQgMCAxIDEgMTIgMThaIiAvPgogIDxwYXRoIGQ9Ik0xNSAxM2E0LjUgNC41IDAgMCAxLTMtNCA0LjUgNC41IDAgMCAxLTMgNCIgLz4KICA8cGF0aCBkPSJNMTcuNTk5IDYuNWEzIDMgMCAwIDAgLjM5OS0xLjM3NSIgLz4KICA8cGF0aCBkPSJNNi4wMDMgNS4xMjVBMyAzIDAgMCAwIDYuNDAxIDYuNSIgLz4KICA8cGF0aCBkPSJNMy40NzcgMTAuODk2YTQgNCAwIDAgMSAuNTg1LS4zOTYiIC8+CiAgPHBhdGggZD0iTTE5LjkzOCAxMC41YTQgNCAwIDAgMSAuNTg1LjM5NiIgLz4KICA8cGF0aCBkPSJNNiAxOGE0IDQgMCAwIDEtMS45NjctLjUxNiIgLz4KICA8cGF0aCBkPSJNMTkuOTY3IDE3LjQ4NEE0IDQgMCAwIDEgMTggMTgiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/brain\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Brain = createLucideIcon('Brain', [\n [\n 'path',\n {\n d: 'M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z',\n key: 'l5xja',\n },\n ],\n [\n 'path',\n {\n d: 'M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z',\n key: 'ep3f8r',\n },\n ],\n ['path', { d: 'M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4', key: '1p4c4q' }],\n ['path', { d: 'M17.599 6.5a3 3 0 0 0 .399-1.375', key: 'tmeiqw' }],\n ['path', { d: 'M6.003 5.125A3 3 0 0 0 6.401 6.5', key: '105sqy' }],\n ['path', { d: 'M3.477 10.896a4 4 0 0 1 .585-.396', key: 'ql3yin' }],\n ['path', { d: 'M19.938 10.5a4 4 0 0 1 .585.396', key: '1qfode' }],\n ['path', { d: 'M6 18a4 4 0 0 1-1.967-.516', key: '2e4loj' }],\n ['path', { d: 'M19.967 17.484A4 4 0 0 1 18 18', key: '159ez6' }],\n]);\n\nexport default Brain;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Check\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMjAgNiA5IDE3bC01LTUiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/check\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Check = createLucideIcon('Check', [['path', { d: 'M20 6 9 17l-5-5', key: '1gmf2c' }]]);\n\nexport default Check;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name ChevronDown\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJtNiA5IDYgNiA2LTYiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/chevron-down\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ChevronDown = createLucideIcon('ChevronDown', [\n ['path', { d: 'm6 9 6 6 6-6', key: 'qrunsl' }],\n]);\n\nexport default ChevronDown;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name ChevronRight\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJtOSAxOCA2LTYtNi02IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/chevron-right\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ChevronRight = createLucideIcon('ChevronRight', [\n ['path', { d: 'm9 18 6-6-6-6', key: 'mthhwq' }],\n]);\n\nexport default ChevronRight;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name CircleAlert\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIgLz4KICA8bGluZSB4MT0iMTIiIHgyPSIxMiIgeTE9IjgiIHkyPSIxMiIgLz4KICA8bGluZSB4MT0iMTIiIHgyPSIxMi4wMSIgeTE9IjE2IiB5Mj0iMTYiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/circle-alert\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst CircleAlert = createLucideIcon('CircleAlert', [\n ['circle', { cx: '12', cy: '12', r: '10', key: '1mglay' }],\n ['line', { x1: '12', x2: '12', y1: '8', y2: '12', key: '1pkeuh' }],\n ['line', { x1: '12', x2: '12.01', y1: '16', y2: '16', key: '4dfq90' }],\n]);\n\nexport default CircleAlert;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Copy\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cmVjdCB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHg9IjgiIHk9IjgiIHJ4PSIyIiByeT0iMiIgLz4KICA8cGF0aCBkPSJNNCAxNmMtMS4xIDAtMi0uOS0yLTJWNGMwLTEuMS45LTIgMi0yaDEwYzEuMSAwIDIgLjkgMiAyIiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/copy\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Copy = createLucideIcon('Copy', [\n ['rect', { width: '14', height: '14', x: '8', y: '8', rx: '2', ry: '2', key: '17jyea' }],\n ['path', { d: 'M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2', key: 'zix9uf' }],\n]);\n\nexport default Copy;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name FileText\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTUgMkg2YTIgMiAwIDAgMC0yIDJ2MTZhMiAyIDAgMCAwIDIgMmgxMmEyIDIgMCAwIDAgMi0yVjdaIiAvPgogIDxwYXRoIGQ9Ik0xNCAydjRhMiAyIDAgMCAwIDIgMmg0IiAvPgogIDxwYXRoIGQ9Ik0xMCA5SDgiIC8+CiAgPHBhdGggZD0iTTE2IDEzSDgiIC8+CiAgPHBhdGggZD0iTTE2IDE3SDgiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/file-text\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst FileText = createLucideIcon('FileText', [\n ['path', { d: 'M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z', key: '1rqfz7' }],\n ['path', { d: 'M14 2v4a2 2 0 0 0 2 2h4', key: 'tnqrlb' }],\n ['path', { d: 'M10 9H8', key: 'b1mrlr' }],\n ['path', { d: 'M16 13H8', key: 't4e002' }],\n ['path', { d: 'M16 17H8', key: 'z1uh3a' }],\n]);\n\nexport default FileText;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Layers\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTIuODMgMi4xOGEyIDIgMCAwIDAtMS42NiAwTDIuNiA2LjA4YTEgMSAwIDAgMCAwIDEuODNsOC41OCAzLjkxYTIgMiAwIDAgMCAxLjY2IDBsOC41OC0zLjlhMSAxIDAgMCAwIDAtMS44M3oiIC8+CiAgPHBhdGggZD0iTTIgMTJhMSAxIDAgMCAwIC41OC45MWw4LjYgMy45MWEyIDIgMCAwIDAgMS42NSAwbDguNTgtMy45QTEgMSAwIDAgMCAyMiAxMiIgLz4KICA8cGF0aCBkPSJNMiAxN2ExIDEgMCAwIDAgLjU4LjkxbDguNiAzLjkxYTIgMiAwIDAgMCAxLjY1IDBsOC41OC0zLjlBMSAxIDAgMCAwIDIyIDE3IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/layers\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Layers = createLucideIcon('Layers', [\n [\n 'path',\n {\n d: 'M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z',\n key: 'zw3jo',\n },\n ],\n [\n 'path',\n {\n d: 'M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12',\n key: '1wduqc',\n },\n ],\n [\n 'path',\n {\n d: 'M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17',\n key: 'kqbvx6',\n },\n ],\n]);\n\nexport default Layers;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Lightbulb\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTUgMTRjLjItMSAuNy0xLjcgMS41LTIuNSAxLS45IDEuNS0yLjIgMS41LTMuNUE2IDYgMCAwIDAgNiA4YzAgMSAuMiAyLjIgMS41IDMuNS43LjcgMS4zIDEuNSAxLjUgMi41IiAvPgogIDxwYXRoIGQ9Ik05IDE4aDYiIC8+CiAgPHBhdGggZD0iTTEwIDIyaDQiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/lightbulb\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Lightbulb = createLucideIcon('Lightbulb', [\n [\n 'path',\n {\n d: 'M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5',\n key: '1gvzjb',\n },\n ],\n ['path', { d: 'M9 18h6', key: 'x1upvd' }],\n ['path', { d: 'M10 22h4', key: 'ceow96' }],\n]);\n\nexport default Lightbulb;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name LoaderCircle\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMjEgMTJhOSA5IDAgMSAxLTYuMjE5LTguNTYiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/loader-circle\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst LoaderCircle = createLucideIcon('LoaderCircle', [\n ['path', { d: 'M21 12a9 9 0 1 1-6.219-8.56', key: '13zald' }],\n]);\n\nexport default LoaderCircle;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name LockKeyhole\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8Y2lyY2xlIGN4PSIxMiIgY3k9IjE2IiByPSIxIiAvPgogIDxyZWN0IHg9IjMiIHk9IjEwIiB3aWR0aD0iMTgiIGhlaWdodD0iMTIiIHJ4PSIyIiAvPgogIDxwYXRoIGQ9Ik03IDEwVjdhNSA1IDAgMCAxIDEwIDB2MyIgLz4KPC9zdmc+Cg==) - https://lucide.dev/icons/lock-keyhole\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst LockKeyhole = createLucideIcon('LockKeyhole', [\n ['circle', { cx: '12', cy: '16', r: '1', key: '1au0dj' }],\n ['rect', { x: '3', y: '10', width: '18', height: '12', rx: '2', key: '6s8ecr' }],\n ['path', { d: 'M7 10V7a5 5 0 0 1 10 0v3', key: '1pqi11' }],\n]);\n\nexport default LockKeyhole;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name MessageSquareMore\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMjEgMTVhMiAyIDAgMCAxLTIgMkg3bC00IDRWNWEyIDIgMCAwIDEgMi0yaDE0YTIgMiAwIDAgMSAyIDJ6IiAvPgogIDxwYXRoIGQ9Ik04IDEwaC4wMSIgLz4KICA8cGF0aCBkPSJNMTIgMTBoLjAxIiAvPgogIDxwYXRoIGQ9Ik0xNiAxMGguMDEiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/message-square-more\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst MessageSquareMore = createLucideIcon('MessageSquareMore', [\n ['path', { d: 'M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z', key: '1lielz' }],\n ['path', { d: 'M8 10h.01', key: '19clt8' }],\n ['path', { d: 'M12 10h.01', key: '1nrarc' }],\n ['path', { d: 'M16 10h.01', key: '1m94wz' }],\n]);\n\nexport default MessageSquareMore;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name MessageSquare\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMjEgMTVhMiAyIDAgMCAxLTIgMkg3bC00IDRWNWEyIDIgMCAwIDEgMi0yaDE0YTIgMiAwIDAgMSAyIDJ6IiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/message-square\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst MessageSquare = createLucideIcon('MessageSquare', [\n ['path', { d: 'M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z', key: '1lielz' }],\n]);\n\nexport default MessageSquare;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name Square\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cmVjdCB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHg9IjMiIHk9IjMiIHJ4PSIyIiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/square\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Square = createLucideIcon('Square', [\n ['rect', { width: '18', height: '18', x: '3', y: '3', rx: '2', key: 'afitv7' }],\n]);\n\nexport default Square;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name TriangleAlert\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJtMjEuNzMgMTgtOC0xNGEyIDIgMCAwIDAtMy40OCAwbC04IDE0QTIgMiAwIDAgMCA0IDIxaDE2YTIgMiAwIDAgMCAxLjczLTMiIC8+CiAgPHBhdGggZD0iTTEyIDl2NCIgLz4KICA8cGF0aCBkPSJNMTIgMTdoLjAxIiAvPgo8L3N2Zz4K) - https://lucide.dev/icons/triangle-alert\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst TriangleAlert = createLucideIcon('TriangleAlert', [\n [\n 'path',\n {\n d: 'm21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3',\n key: 'wmoenq',\n },\n ],\n ['path', { d: 'M12 9v4', key: 'juzpu7' }],\n ['path', { d: 'M12 17h.01', key: 'p32p05' }],\n]);\n\nexport default TriangleAlert;\n","import createLucideIcon from '../createLucideIcon';\n\n/**\n * @component @name X\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMTggNiA2IDE4IiAvPgogIDxwYXRoIGQ9Im02IDYgMTIgMTIiIC8+Cjwvc3ZnPgo=) - https://lucide.dev/icons/x\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst X = createLucideIcon('X', [\n ['path', { d: 'M18 6 6 18', key: '1bl5f8' }],\n ['path', { d: 'm6 6 12 12', key: 'd8bk6v' }],\n]);\n\nexport default X;\n","import { clsx, type ClassValue } from \"clsx\"\n\n/** 合并 className(SDK 内不引入 tailwind-merge,按序拼接即可)。 */\nexport function cn(...inputs: ClassValue[]): string {\n return clsx(inputs)\n}\n\n/** 复制文本到剪贴板,返回是否成功。 */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n try {\n await navigator.clipboard.writeText(text)\n return true\n } catch {\n return false\n }\n}\n","import { ArrowUp, Loader2, Square } from \"lucide-react\"\nimport type { KeyboardEvent } from \"react\"\nimport { cn } from \"../lib/utils\"\n\ninterface Props {\n /** 受控输入内容(由 ChatView 持有,便于 attach/insertText 注入)。 */\n value: string\n onValueChange: (value: string) => void\n onSend: (text: string) => boolean | Promise<boolean>\n onStop: () => void\n isStreaming: boolean\n isStopping?: boolean\n placeholder?: string\n className?: string\n}\n\n/**\n * 轻量聊天输入框:textarea(Enter 发送 / Shift+Enter 换行)+ 发送/停止按钮。\n * 不含第一方版本的富文本编辑、@ 补全、技能菜单、语音输入与模型选择。\n * 内容受控,session.attach() / insertText() 通过 ChatView 注入到这里。\n */\nexport function ChatInput({\n value,\n onValueChange,\n onSend,\n onStop,\n isStreaming,\n isStopping = false,\n placeholder = \"输入消息…\",\n className,\n}: Props) {\n const trimmed = value.trim()\n const canSend = trimmed.length > 0 && !isStreaming\n\n const handleSend = async () => {\n if (!canSend) return\n const accepted = await onSend(trimmed)\n if (!accepted) return\n onValueChange(\"\")\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n // 输入法组合中回车用于选字,不能触发发送\n if (event.key === \"Enter\" && !event.shiftKey && !event.nativeEvent.isComposing) {\n event.preventDefault()\n void handleSend()\n }\n }\n\n return (\n <div className={cn(\"blade-chat-input border-t border-[hsl(var(--border))] py-3\", className)}>\n <div className=\"blade-chat-input-inner mx-auto flex max-w-[748px] items-end gap-2 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2\">\n <textarea\n value={value}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={handleKeyDown}\n onInput={(event) => {\n // 内容驱动的高度自适应:先复位再按 scrollHeight 撑开,上限约 8 行\n const el = event.currentTarget\n el.style.height = \"auto\"\n el.style.height = `${Math.min(el.scrollHeight, 192)}px`\n }}\n rows={1}\n placeholder={placeholder}\n aria-label=\"聊天输入\"\n className=\"blade-chat-textarea max-h-48 min-h-[28px] flex-1 resize-none bg-transparent py-1 text-sm leading-6 text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.6)]\"\n />\n {isStreaming ? (\n <button\n type=\"button\"\n onClick={onStop}\n disabled={isStopping}\n aria-label={isStopping ? \"正在停止\" : \"停止回复\"}\n title={isStopping ? \"正在停止\" : \"停止回复\"}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--muted))] text-[hsl(var(--foreground))] transition-opacity hover:opacity-90 disabled:opacity-60\"\n >\n {isStopping ? (\n <Loader2 size={14} className=\"animate-spin\" />\n ) : (\n <Square size={12} fill=\"currentColor\" />\n )}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend}\n aria-label=\"发送消息\"\n title=\"发送消息\"\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ArrowUp size={15} />\n </button>\n )}\n </div>\n </div>\n )\n}\n","import type { ConnectionStatus } from \"@blade-hq/agent-client\"\nimport { AlertTriangle, LoaderCircle } from \"lucide-react\"\nimport { useEffect, useRef, useState } from \"react\"\nimport { cn } from \"../lib/utils\"\n\nconst CONNECTION_NOTICE_DELAY_MS = 3_000\nconst CONNECTION_ERROR_DELAY_MS = 15_000\n\ntype ConnectionNoticePhase = \"hidden\" | \"recovering\" | \"failed\"\n\ninterface Props {\n connection: ConnectionStatus\n className?: string\n}\n\n/** 与内置 Web 的 ConnectionBanner 保持同样的前台恢复容错时序。 */\nfunction useConnectionNoticePhase(connected: boolean): ConnectionNoticePhase {\n const [phase, setPhase] = useState<ConnectionNoticePhase>(\"hidden\")\n const connectedRef = useRef(connected)\n const timersRef = useRef<ReturnType<typeof setTimeout>[]>([])\n\n connectedRef.current = connected\n\n useEffect(() => {\n const clearTimers = () => {\n for (const timer of timersRef.current) clearTimeout(timer)\n timersRef.current = []\n }\n const startGracePeriod = () => {\n clearTimers()\n setPhase(\"hidden\")\n timersRef.current = [\n setTimeout(() => setPhase(\"recovering\"), CONNECTION_NOTICE_DELAY_MS),\n setTimeout(() => setPhase(\"failed\"), CONNECTION_ERROR_DELAY_MS),\n ]\n }\n\n if (connected) {\n clearTimers()\n setPhase(\"hidden\")\n } else {\n startGracePeriod()\n }\n\n const handleForeground = () => {\n if (!connectedRef.current) startGracePeriod()\n }\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"visible\") handleForeground()\n }\n\n window.addEventListener(\"blade:app-active\", handleForeground)\n window.addEventListener(\"focus\", handleForeground)\n window.addEventListener(\"pageshow\", handleForeground)\n document.addEventListener(\"visibilitychange\", handleVisibilityChange)\n return () => {\n clearTimers()\n window.removeEventListener(\"blade:app-active\", handleForeground)\n window.removeEventListener(\"focus\", handleForeground)\n window.removeEventListener(\"pageshow\", handleForeground)\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange)\n }\n }, [connected])\n\n return phase\n}\n\n/** 连接状态提示条:短暂断线静默,超过容错时间后再逐级提示。 */\nexport function ConnectionBanner({ connection, className }: Props) {\n const hasConnectedRef = useRef(connection === \"connected\" || connection === \"reconnecting\")\n if (connection === \"connected\") hasConnectedRef.current = true\n const connected = connection === \"connected\"\n const phase = useConnectionNoticePhase(connected)\n if (connected || phase === \"hidden\") return null\n\n const recovering = phase === \"recovering\"\n const firstConnection = !hasConnectedRef.current\n\n return (\n <div className={cn(\"blade-chat-banner bg-[hsl(var(--background))] px-5 pt-3\", className)}>\n <div\n className={cn(\n \"mx-auto flex max-w-3xl items-start gap-3 rounded-2xl border px-4 py-3\",\n recovering\n ? \"border-amber-500/25 bg-amber-500/10 text-amber-100\"\n : \"border-rose-500/25 bg-rose-500/10 text-rose-100\",\n )}\n >\n <span className=\"mt-0.5 shrink-0\">\n {recovering ? (\n <LoaderCircle size={14} className=\"animate-spin\" />\n ) : (\n <AlertTriangle size={14} />\n )}\n </span>\n <div className=\"min-w-0\">\n <div className=\"text-sm font-medium\">\n {recovering\n ? firstConnection\n ? \"正在连接…\"\n : \"正在恢复连接…\"\n : \"暂时无法连接\"}\n </div>\n <div className=\"text-xs opacity-80\">\n {recovering\n ? \"恢复后会自动同步最新消息,请稍候\"\n : \"请检查网络或服务状态,系统会继续自动重试\"}\n </div>\n </div>\n </div>\n </div>\n )\n}\n","import type { AskUserAnswerData, ChatMessage } from \"@blade-hq/agent-client\"\nimport { isHiddenInternalMessage } from \"@blade-hq/agent-client\"\nimport { ChevronDown, Layers, Lightbulb, MessageSquare } from \"lucide-react\"\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\"\nimport { StickToBottom, useStickToBottomContext } from \"use-stick-to-bottom\"\nimport { cn } from \"../lib/utils\"\nimport { AssistantTurnBlock } from \"./AssistantTurnBlock\"\nimport { RenderErrorBoundary } from \"./RenderErrorBoundary\"\nimport type { ToolCallRenderer } from \"./ToolCallBlock\"\nimport {\n ErrorMessageBlock,\n UserMessageBubble,\n isErrorMessage,\n isUserMessage,\n} from \"./UserMessageBubble\"\n\ntype RenderBlock =\n | { type: \"message\"; message: ChatMessage; key: string }\n | { type: \"assistant_turn\"; messages: ChatMessage[]; key: string; isStreaming: boolean }\n | { type: \"compaction\"; key: string }\n | { type: \"planning_divider\"; kind: \"enter\" | \"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): \"enter\" | \"exit\" | null {\n const modeChange = parseModeChange(message)\n if (modeChange?.to === \"planning\") return \"enter\"\n if (modeChange?.from === \"planning\") return \"exit\"\n return null\n}\n\nfunction getMessageResetSignature(messages: ChatMessage[]): string {\n return messages\n .map((message) => {\n const contentSize =\n typeof message.content === \"string\" ? message.content.length : message.content.length\n const toolSignature =\n message.tool_calls\n ?.map((toolCall) => `${toolCall.id}:${toolCall.status ?? \"\"}`)\n .join(\",\") ?? \"\"\n return [\n message.entry_id ?? message.timestamp ?? message.role,\n message.status ?? \"\",\n contentSize,\n toolSignature,\n ].join(\":\")\n })\n .join(\"|\")\n}\n\ninterface Props {\n messages: ChatMessage[]\n isStreaming: boolean\n sessionStatus?: string\n askAnswers?: Record<string, AskUserAnswerData>\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n toolCallRenderer?: ToolCallRenderer\n emptyState?: ReactNode\n className?: string\n /** 传给助手消息的 Markdown 渲染,用于把 MEDIA 行折叠成文件下载链接。 */\n sessionId?: string\n}\n\n/**\n * 消息列表:use-stick-to-bottom 自动滚动 + 按轮次分组渲染。\n * 相比第一方版本去掉了轮次导航栏、吸顶状态条与规划摘要卡片。\n */\nexport function MessageList({\n messages,\n isStreaming,\n sessionStatus,\n askAnswers,\n onAnswer,\n toolCallRenderer,\n emptyState,\n className,\n sessionId,\n}: Props) {\n const renderBlocks = useMemo(() => {\n const visible = messages.filter((message) => {\n if ((message.loop_name ?? \"root\") !== \"root\") 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\n const flushAssistant = () => {\n if (assistantBuffer.length === 0) return\n assistantTurnCount += 1\n const first = assistantBuffer[0]\n blocks.push({\n type: \"assistant_turn\",\n messages: assistantBuffer,\n key: first.entry_id ?? `assistant-${assistantTurnCount}`,\n isStreaming: assistantBuffer.some((message) => message.status === \"streaming\"),\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({ type: \"compaction\", key: message.entry_id ?? `compaction-${blocks.length}` })\n continue\n }\n\n if (message.role === \"assistant\") {\n assistantBuffer.push(message)\n continue\n }\n\n flushAssistant()\n blocks.push({\n type: \"message\",\n message,\n key: message.entry_id ?? `${message.role}-${blocks.length}`,\n })\n }\n\n flushAssistant()\n\n // 流式中但最后一块还是用户消息:补一个空的助手轮占位,立即出现\"正在生成\"\n const last = blocks[blocks.length - 1]\n if (isStreaming) {\n if (last?.type === \"assistant_turn\") {\n last.isStreaming = true\n } else if (last?.type === \"message\" && isUserMessage(last.message)) {\n blocks.push({\n type: \"assistant_turn\",\n messages: [\n {\n role: \"assistant\",\n content: \"\",\n entry_id: `pending-assistant-${last.key}`,\n status: \"streaming\",\n loop_name: \"root\",\n },\n ],\n key: `pending-assistant-${last.key}`,\n isStreaming: true,\n })\n }\n }\n\n return blocks\n }, [messages, isStreaming])\n\n return (\n <div className={cn(\"blade-chat-messages relative min-h-0 flex-1\", className)}>\n <StickToBottom className=\"h-full overflow-y-hidden\" initial=\"instant\" resize=\"instant\">\n <StickToBottom.Content className=\"blade-chat-messages-scroll\">\n <div className=\"blade-chat-messages-content mx-auto max-w-[748px]\">\n <div className=\"flex min-w-0 flex-col\">\n {renderBlocks.length === 0\n ? (emptyState ?? (\n <div className=\"blade-chat-empty\">\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 : renderBlocks.map((block) => {\n if (block.type === \"message\") {\n return (\n <div key={block.key} data-entry-id={block.message.entry_id}>\n {isUserMessage(block.message) ? (\n <UserMessageBubble message={block.message} />\n ) : isErrorMessage(block.message) ? (\n <ErrorMessageBlock message={block.message} />\n ) : null}\n </div>\n )\n }\n\n if (block.type === \"assistant_turn\") {\n return (\n <div key={block.key} data-entry-id={block.messages[0]?.entry_id}>\n <RenderErrorBoundary\n label=\"助手消息\"\n details={block.key}\n resetKey={getMessageResetSignature(block.messages)}\n >\n <AssistantTurnBlock\n messages={block.messages}\n isStreaming={block.isStreaming}\n askAnswers={askAnswers}\n onAnswer={onAnswer}\n sessionStatus={sessionStatus}\n toolCallRenderer={toolCallRenderer}\n sessionId={sessionId}\n />\n </RenderErrorBoundary>\n </div>\n )\n }\n\n if (block.type === \"compaction\") {\n return (\n <div\n key={block.key}\n className=\"flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]\"\n >\n <Layers size={12} />\n <span>上下文已压缩</span>\n </div>\n )\n }\n\n return <PlanningDivider key={block.key} kind={block.kind} />\n })}\n\n {sessionStatus === \"interrupted\" && !isStreaming ? (\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 </StickToBottom.Content>\n <AutoScrollOnUserSend userMessageCount={messages.filter((m) => isUserMessage(m)).length} />\n <ScrollToBottomButton />\n </StickToBottom>\n </div>\n )\n}\n\n/** 用户每发一条消息就滚到底部;流式期间用户向上翻阅历史则不打扰。 */\nfunction AutoScrollOnUserSend({ userMessageCount }: { userMessageCount: number }) {\n const { scrollToBottom } = useStickToBottomContext()\n const previousCountRef = useRef(userMessageCount)\n useEffect(() => {\n if (userMessageCount > previousCountRef.current) {\n scrollToBottom(\"instant\")\n }\n previousCountRef.current = userMessageCount\n }, [userMessageCount, scrollToBottom])\n return null\n}\n\nfunction ScrollToBottomButton() {\n const { isAtBottom, scrollToBottom } = useStickToBottomContext()\n const [visible, setVisible] = useState(false)\n const hideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n // 防抖:isAtBottom 变为 true 时不立即隐藏,等 300ms 确认稳定后再隐藏\n // 避免流式内容高度变化导致 isAtBottom 在 true/false 之间快速切换闪烁\n useEffect(() => {\n if (isAtBottom) {\n // 启动延迟隐藏定时器\n if (!hideTimerRef.current) {\n hideTimerRef.current = setTimeout(() => {\n setVisible(false)\n hideTimerRef.current = null\n }, 300)\n }\n } else {\n // 不在底部,取消所有待执行的隐藏,立即显示\n if (hideTimerRef.current) {\n clearTimeout(hideTimerRef.current)\n hideTimerRef.current = null\n }\n setVisible(true)\n }\n\n return () => {\n if (hideTimerRef.current) {\n clearTimeout(hideTimerRef.current)\n hideTimerRef.current = null\n }\n }\n }, [isAtBottom])\n\n // hook 必须在任何早退之前调用,否则 visible 变化时 hook 顺序不一致\n const handleClick = useCallback(() => {\n // 点击滚动到底部时立即隐藏按钮,避免闪烁\n if (hideTimerRef.current) {\n clearTimeout(hideTimerRef.current)\n hideTimerRef.current = null\n }\n setVisible(false)\n scrollToBottom()\n }, [scrollToBottom])\n\n if (!visible) return null\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n aria-label=\"滚动到底部\"\n className=\"blade-chat-scroll-bottom 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 {/* 窄容器里这行字会横跨近半个宽度,收起来只留图标;可访问名由 aria-label 保住。 */}\n <span className=\"blade-chat-scroll-bottom-label\">滚动到底部</span>\n </button>\n )\n}\n\nfunction PlanningDivider({ kind }: { kind: \"enter\" | \"exit\" }) {\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>{kind === \"enter\" ? \"进入规划模式\" : \"规划完成\"}</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 type { AskUserAnswerData, ChatMessage } from \"@blade-hq/agent-client\"\nimport { getTextContent, normalizeMessageContent } from \"@blade-hq/agent-client\"\nimport { Brain, ChevronDown } from \"lucide-react\"\nimport { useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { AgentLoopBlock } from \"./AgentLoopBlock\"\nimport { MarkdownContent } from \"./MarkdownContent\"\nimport { Shimmer } from \"./Shimmer\"\nimport { ToolCallBlock, type ToolCallRenderer } from \"./ToolCallBlock\"\nimport { formatToolName } from \"./display-utils\"\n\ninterface Props {\n messages: ChatMessage[]\n isStreaming?: boolean\n askAnswers?: Record<string, AskUserAnswerData>\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n sessionStatus?: string\n toolCallRenderer?: ToolCallRenderer\n /** 传给 Markdown 渲染,用于把 MEDIA 行折叠成文件下载链接。 */\n sessionId?: string\n}\n\n/** 思考折叠块:折叠状态归组件自身,不依赖全局 store。 */\nfunction ThinkingBlock({ reasoning, isStreaming }: { reasoning: string; isStreaming: boolean }) {\n const [open, setOpen] = useState(false)\n\n return (\n <div className=\"blade-chat-thinking ml-4 text-sm\">\n <button\n type=\"button\"\n onClick={() => setOpen(!open)}\n aria-expanded={open}\n className=\"inline-flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]\"\n >\n <Brain size={12} className=\"shrink-0\" />\n {isStreaming ? <Shimmer className=\"text-xs\">正在思考</Shimmer> : <span>思考过程</span>}\n <span className=\"text-[hsl(var(--muted-foreground))]/70\">\n · {new Intl.NumberFormat(\"zh-CN\").format(reasoning.length)} 字\n </span>\n <ChevronDown\n size={12}\n className={cn(\"shrink-0 transition-transform\", open && \"rotate-180\")}\n />\n </button>\n {open && (\n <div className=\"mt-1.5 whitespace-pre-wrap border-l-2 border-[hsl(var(--border))] pl-3 text-[11px] leading-5 text-[hsl(var(--muted-foreground))]\">\n {reasoning}\n </div>\n )}\n </div>\n )\n}\n\nfunction getMessageText(message: ChatMessage): string {\n return getTextContent(normalizeMessageContent(message.content)).trim()\n}\n\nfunction findLatestReasoningMessageIndex(messages: readonly ChatMessage[]): number {\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n if (messages[index].reasoning) return index\n }\n return -1\n}\n\n/**\n * 一轮助手回复:按消息顺序渲染 thinking 折叠块、正文 Markdown 与工具调用。\n * 相比第一方版本去掉了紧凑/详细模式切换、文件交付卡片与内联资源 iframe。\n */\nexport function AssistantTurnBlock({\n messages,\n isStreaming = false,\n askAnswers,\n onAnswer,\n sessionStatus,\n toolCallRenderer,\n sessionId,\n}: Props) {\n const hasInterrupted = messages.some((message) => message.status === \"interrupted\")\n const hasAnyContent = messages.some(\n (message) =>\n getMessageText(message) || message.reasoning || (message.tool_calls?.length ?? 0) > 0,\n )\n const latestReasoningIndex = isStreaming\n ? findLatestReasoningMessageIndex(messages)\n : -1\n\n return (\n <div className=\"blade-chat-assistant-turn flex flex-col gap-3\">\n {hasInterrupted && (\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 {messages.map((message, index) => {\n const isLast = index === messages.length - 1\n const streamingThis = isStreaming && isLast\n const text = getMessageText(message)\n const toolCalls = message.tool_calls ?? []\n const showReasoning =\n !!message.reasoning && (!isStreaming || index === latestReasoningIndex)\n\n return (\n <div\n key={message.entry_id ?? `${message.timestamp ?? \"assistant\"}-${index}`}\n className=\"flex flex-col gap-3\"\n >\n {showReasoning && message.reasoning && (\n <ThinkingBlock reasoning={message.reasoning} isStreaming={streamingThis && !text} />\n )}\n {text && (\n <div className=\"blade-chat-assistant-text text-[15px] leading-8 text-[hsl(var(--foreground))]\">\n <MarkdownContent\n mode={streamingThis ? \"streaming\" : \"static\"}\n className=\"blade-chat-prose\"\n sessionId={sessionId}\n >\n {text}\n </MarkdownContent>\n </div>\n )}\n {toolCalls.length > 0 && (\n <div className=\"flex flex-col gap-2\">\n {toolCalls.map((toolCall) =>\n formatToolName(toolCall.name) === \"Agent\" ? (\n <AgentLoopBlock key={toolCall.id} toolCall={toolCall} />\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 sessionStatus={sessionStatus}\n renderer={toolCallRenderer}\n />\n ),\n )}\n </div>\n )}\n </div>\n )\n })}\n {isStreaming && !hasAnyContent && <Shimmer className=\"ml-4\">正在生成...</Shimmer>}\n </div>\n )\n}\n","import type { ToolCallInfo } from \"@blade-hq/agent-client\"\nimport { Bot, Check, ChevronRight, Loader2, X } from \"lucide-react\"\nimport { useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { formatToolDuration, formatToolResult } from \"./display-utils\"\n\ninterface Props {\n toolCall: ToolCallInfo\n}\n\nfunction parseAgentDescription(argumentsJson: string): string {\n try {\n const parsed = JSON.parse(argumentsJson)\n return typeof parsed?.description === \"string\" && parsed.description\n ? parsed.description\n : \"子智能体\"\n } catch {\n return \"子智能体\"\n }\n}\n\n/**\n * 子智能体(fork Agent)状态块的 SDK 简化版:只展示描述、状态与最终结果,\n * 不再嵌套渲染子循环的完整消息流(那是第一方界面的能力)。\n */\nexport function AgentLoopBlock({ toolCall }: Props) {\n const [expanded, setExpanded] = useState(false)\n const description = parseAgentDescription(toolCall.arguments)\n const running = toolCall.status === \"pending\" || toolCall.status === \"awaiting_answer\"\n const failed = toolCall.status === \"error\" || toolCall.status === \"cancelled\"\n\n return (\n <div className=\"blade-chat-agent-loop ml-4 text-xs\">\n <div\n className={cn(\n \"border-l-[3px] flex items-center gap-2 px-3 py-2\",\n failed\n ? \"border-l-[hsl(var(--muted-foreground)/0.5)]\"\n : running\n ? \"border-l-blue-500\"\n : \"border-l-[hsl(var(--primary))]\",\n )}\n >\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 <Bot size={12} className=\"shrink-0 text-[hsl(var(--muted-foreground))]\" />\n <span\n className={cn(\n \"flex shrink-0 items-center gap-1 text-[10px]\",\n failed\n ? \"text-[hsl(var(--muted-foreground))]\"\n : running\n ? \"text-blue-300\"\n : \"text-[hsl(var(--primary))]\",\n )}\n >\n {running ? (\n <Loader2 size={11} className=\"animate-spin\" />\n ) : failed ? (\n <X size={11} />\n ) : (\n <Check size={11} />\n )}\n <span>{running ? \"执行中\" : failed ? \"已终止\" : \"完成\"}</span>\n </span>\n <span className=\"min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]\">\n 子智能体:{description}\n </span>\n </button>\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 </div>\n {expanded && toolCall.result != null && (\n <div className=\"ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3\">\n <div className=\"mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]\">\n 结果\n </div>\n <pre className=\"max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {formatToolResult(toolCall.result)}\n </pre>\n </div>\n )}\n </div>\n )\n}\n","import type { ToolCallInfo } from \"@blade-hq/agent-client\"\n\n/** 工具名归一化别名表:把后端各种命名风格统一为展示用的驼峰名。 */\nconst TOOL_NAME_ALIASES: Record<string, string> = {\n agent: \"Agent\",\n ask_user_question: \"AskUserQuestion\",\n bash: \"Bash\",\n bg_bash: \"BgBash\",\n edit: \"Edit\",\n exit_plan_mode: \"ExitPlanMode\",\n file_edit: \"Edit\",\n file_read: \"Read\",\n file_write: \"Write\",\n finish_task: \"FinishTask\",\n glob: \"Glob\",\n grep: \"Grep\",\n ls: \"Ls\",\n read: \"Read\",\n read_skill: \"ReadSkill\",\n web_fetch: \"WebFetch\",\n web_search: \"WebSearch\",\n write: \"Write\",\n}\n\n/** 系统工具的中文展示名。 */\nconst TOOL_DISPLAY_LABELS: Record<string, string> = {\n Bash: \"执行命令\",\n BgBash: \"后台执行命令\",\n Read: \"读取文件\",\n Write: \"写入文件\",\n Edit: \"编辑文件\",\n Ls: \"列出目录\",\n Glob: \"匹配文件\",\n Grep: \"搜索文本\",\n WebSearch: \"搜索网页\",\n WebFetch: \"整理网页内容\",\n Agent: \"派生子智能体\",\n AskUserQuestion: \"向用户提问\",\n ReadSkill: \"读取技能\",\n FinishTask: \"任务完成\",\n ExitPlanMode: \"提交计划\",\n ListSessions: \"列出历史会话\",\n GetSessionHistory: \"读取会话历史\",\n}\n\nexport type ToolTone = \"emerald\" | \"blue\" | \"amber\" | \"red\"\n\nfunction safeParseJson(value: string | null | undefined): unknown {\n if (!value) return null\n try {\n return JSON.parse(value)\n } catch {\n return null\n }\n}\n\nfunction getStringArgValue(args: Record<string, unknown> | null, key: string): string {\n const value = args?.[key]\n return typeof value === \"string\" ? value.trim() : \"\"\n}\n\n/** 归一化工具名:去掉命名空间前缀并映射到别名表(如 \"fork:Agent\" → \"Agent\")。 */\nexport function formatToolName(name: string): string {\n const trimmed = name.trim()\n if (!trimmed) return name\n\n const stripped = trimmed.split(\":\").pop()?.split(\"/\").pop()?.split(\".\").pop()?.trim() || trimmed\n const normalized = stripped\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/[^a-zA-Z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .toLowerCase()\n\n return TOOL_NAME_ALIASES[normalized] ?? stripped\n}\n\n/**\n * 返回工具调用的中文展示标签:优先取参数里的 description,\n * 其次取后端下发的 display_name / 系统工具中文名。\n */\nexport function getToolDisplayLabel(toolCall: ToolCallInfo): string {\n const normalized = formatToolName(toolCall.name)\n const args = safeParseJson(toolCall.arguments) as Record<string, unknown> | null\n const displayName = toolCall.display_name?.trim() ?? \"\"\n const baseLabel = displayName || TOOL_DISPLAY_LABELS[normalized] || normalized\n const metaDisplayName = getStringArgValue(args, \"_meta_display_name\")\n if (metaDisplayName) {\n return metaDisplayName\n }\n\n const description = getStringArgValue(args, \"description\")\n\n if (normalized === \"BgBash\") {\n return description ? `后台执行:${description}` : \"后台执行命令\"\n }\n if (normalized === \"ReadSkill\") {\n const skillName = getStringArgValue(args, \"skill\") || getStringArgValue(args, \"skill_name\")\n return skillName ? `${baseLabel}「${skillName}」` : baseLabel\n }\n if (normalized === \"FinishTask\") {\n const title = getStringArgValue(args, \"title\")\n return title ? `${baseLabel}:${title}` : baseLabel\n }\n\n return description || baseLabel\n}\n\nexport function getToolTone(status?: ToolCallInfo[\"status\"]): ToolTone {\n if (status === \"error\" || status === \"cancelled\") return \"red\"\n if (status === \"awaiting_answer\") return \"amber\"\n if (status === \"pending\") return \"blue\"\n return \"emerald\"\n}\n\nexport function getToolStatusLabel(status?: ToolCallInfo[\"status\"]): string {\n if (status === \"pending\") return \"运行中\"\n if (status === \"awaiting_answer\") return \"等待回答\"\n if (status === \"error\") return \"错误\"\n if (status === \"cancelled\") return \"已取消\"\n return \"完成\"\n}\n\nexport function 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\n/** 参数 JSON 美化:无法解析时按原文展示。 */\nexport function formatToolArgs(args: string): string {\n try {\n return JSON.stringify(JSON.parse(args), null, 2)\n } catch {\n return args\n }\n}\n\nconst RESULT_PREVIEW_LIMIT = 4000\n\n/** 工具结果的文本化 + 截断:长结果只在折叠面板里展示前若干字符。 */\nexport function formatToolResult(result: unknown): string {\n const text = typeof result === \"string\" ? result : JSON.stringify(result, null, 2)\n if (text == null) return \"\"\n if (text.length <= RESULT_PREVIEW_LIMIT) return text\n return `${text.slice(0, RESULT_PREVIEW_LIMIT)}\\n…(结果过长,已截断)`\n}\n","import { Check, Copy } from \"lucide-react\"\nimport {\n type ComponentProps,\n type ComponentPropsWithRef,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\"\nimport { type ExtraProps, Streamdown } from \"streamdown\"\nimport { FILE_CARD_TAG, collapseMediaTags } from \"../lib/media-tags\"\nimport { cn, copyToClipboard } from \"../lib/utils\"\nimport { FileCard, type FileCardProps } from \"./FileCard\"\n\ntype StreamdownProps = ComponentProps<typeof Streamdown>\n\n/** 平台内部提醒标记:不属于给用户看的内容,渲染前整段剥掉。 */\nconst SYSTEM_REMINDER_RE = /<system-reminder>[\\s\\S]*?<\\/system-reminder>/gi\n\ntype PreProps = ComponentPropsWithRef<\"pre\"> & ExtraProps\n\n/** 代码块外壳:常驻头部栏(语言标签 + 复制按钮),代码区浅底。 */\nfunction CodeBlockPre({ children, node: _node, ...props }: PreProps) {\n const preRef = useRef<HTMLPreElement>(null)\n const [copied, setCopied] = useState(false)\n const [language, setLanguage] = useState(\"\")\n\n // DOM 测量:语言标签写在内层 code 的 className 上,只能挂载后读取。\n useEffect(() => {\n const codeEl = preRef.current?.querySelector(\"code\")\n setLanguage(codeEl?.className.match(/language-(\\S+)/)?.[1] ?? \"\")\n }, [])\n\n const handleCopy = async () => {\n const ok = await copyToClipboard(preRef.current?.querySelector(\"code\")?.textContent ?? \"\")\n if (ok) {\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n }\n\n return (\n <div className=\"blade-chat-codeblock not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]\">\n <div className=\"blade-chat-codeblock-header flex h-[34px] items-center justify-between border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))/0.5] pl-3.5 pr-1.5\">\n <span className=\"font-mono text-[12px] text-[hsl(var(--muted-foreground))]\">\n {language || \"code\"}\n </span>\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n \"flex h-6 items-center gap-1 rounded-md px-1.5 text-[11px] transition-colors\",\n copied\n ? \"text-[hsl(var(--primary))]\"\n : \"text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\",\n )}\n >\n {copied ? <Check size={12} /> : <Copy size={12} />}\n <span>{copied ? \"已复制\" : \"复制\"}</span>\n </button>\n </div>\n <pre\n ref={preRef}\n {...props}\n className={cn(props.className, \"blade-chat-codeblock-body m-0 overflow-x-auto\")}\n >\n {children}\n </pre>\n </div>\n )\n}\n\ntype AnchorProps = ComponentPropsWithRef<\"a\"> & ExtraProps\n\n/** 链接一律新窗口打开并断开 opener,SDK 不接管站内跳转。 */\nfunction ExternalAnchor({ node: _node, children, ...props }: AnchorProps) {\n return (\n <a {...props} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n )\n}\n\nconst MARKDOWN_COMPONENTS = {\n pre: CodeBlockPre,\n a: ExternalAnchor,\n} as NonNullable<StreamdownProps[\"components\"]>\n\n/**\n * 文件下载链接标签要显式过 sanitize 白名单,否则标签和属性都会被消毒掉。属性名写的是 HAST\n * 形式(`data-path` 解析进 HAST 后叫 `dataPath`);kebab-case 那两个是防御性冗余,\n * 万一 streamdown 换了属性名的处理方式也不至于静默丢属性。\n *\n * 注意不要给 Streamdown 传自定义 rehypePlugins——那样 streamdown 就不会再自动把这里声明的\n * 标签合并进它的 sanitize schema,白名单会静默失效。\n */\nconst CUSTOM_ALLOWED_TAGS = {\n [FILE_CARD_TAG]: [\"dataPath\", \"dataName\", \"data-path\", \"data-name\"],\n} as NonNullable<StreamdownProps[\"allowedTags\"]>\n\nexport interface MarkdownContentProps {\n children: string\n className?: string\n /** 流式渲染传 \"streaming\",历史静态内容默认 \"static\"。 */\n mode?: \"streaming\" | \"static\"\n /**\n * 会话 id。传了才会把 `MEDIA:` 行折叠成文件下载链接——下载要用它。\n * 不要给用户消息传:用户自己在输入框打一行 `MEDIA:` 不该被当成平台产物。\n */\n sessionId?: string\n}\n\n/**\n * SDK 版 Markdown 渲染:附带代码块复制按钮、智能体产出文件的下载链接;\n * 相比第一方版本去掉了 mermaid、外链确认弹窗与文件预览。\n */\nexport function MarkdownContent({ children, className, mode, sessionId }: MarkdownContentProps) {\n const streaming = mode === \"streaming\"\n const resolvedChildren = useMemo(() => {\n const withoutReminders = children.replace(SYSTEM_REMINDER_RE, \"\")\n if (!sessionId) return withoutReminders\n return collapseMediaTags(withoutReminders, { streaming })\n }, [children, sessionId, streaming])\n\n const components = useMemo(\n () =>\n ({\n ...MARKDOWN_COMPONENTS,\n [FILE_CARD_TAG]: (fileCardProps: FileCardProps) => (\n <FileCard {...fileCardProps} sessionId={sessionId} />\n ),\n }) as NonNullable<StreamdownProps[\"components\"]>,\n [sessionId],\n )\n\n return (\n <Streamdown\n // Streamdown 外层 memo 不比较 components,光换 sessionId 可能留着旧闭包,\n // 链接就会拿旧会话去下载。挂 key 强制重建,切会话本来也要换内容。\n key={sessionId ?? \"no-session\"}\n className={cn(\"blade-chat-markdown break-words\", className)}\n mode={mode ?? \"static\"}\n components={components}\n allowedTags={CUSTOM_ALLOWED_TAGS}\n >\n {resolvedChildren}\n </Streamdown>\n )\n}\n","/**\n * MEDIA 行处理。后端提示词要求智能体产出文件时单独写一行 `MEDIA:<绝对路径>`\n * (见 host/src/blade_agent/host/orchestrator/prompt.py),界面必须把它折叠成文件下载链接——\n * 这是内部标记,直接摆给用户看就是 bug。\n */\n\nexport const FILE_CARD_TAG = \"blade-file-card\"\n\n/**\n * 模型经常给这一行加点装饰——写成列表项、加粗、包引号、末尾补句号,这些都还是同一个\n * 意思,识别不了就会把内部标记裸露给用户,所以一并放宽。\n *\n * 尾部的包裹符用反向引用要求和开头那组一模一样:没写开头装饰就一个字符都不剥,\n * 否则 `draft_`、`报表*` 这种本来就以这些字符结尾的文件名会被削掉最后一位,链接指向\n * 一个不存在的路径。行尾标点同理只认中文标点和逗号分号——英文句点是扩展名分隔符,\n * 不能碰。\n *\n * 路径部分用 `.+?` 而不是 `\\S+?`:文件名里带空格很常见(`季度 报告.xlsx`),用 `\\S`\n * 会在空格处截断、导致整行匹配不上,最后把 `MEDIA:` 原样暴露给用户。行尾的 `\\r?` 是给\n * CRLF 文本用的,不写会把 `\\r` 算进路径。\n */\nconst MEDIA_LINE_RE =\n /^[ \\t]*(?:[-*+][ \\t]+|\\d+\\.[ \\t]+)?(?<wrap>[`\"'*_]*)MEDIA:[ \\t]*(?<path>.+?)\\k<wrap>[ \\t]*[。,、;;,]?[ \\t]*\\r?$/gm\n\n/** 只判断「这行是不是正在写一个 MEDIA 行」,不要求路径已经写完。 */\nconst MEDIA_LINE_START_RE = /^[ \\t]*(?:[-*+][ \\t]+|\\d+\\.[ \\t]+)?[`\"'*_]*MEDIA:/\n\n/** 同时按 `/` 和 `\\` 取末段:daemon 可能跑在 Windows 上,路径是反斜杠分隔的。 */\nfunction basename(path: string): string {\n return path.split(/[/\\\\]/).filter(Boolean).pop() || path\n}\n\n/** 路径写成 `<...>` 的形式(Markdown 里包空格路径的写法)时剥掉尖括号。 */\nfunction unwrapMediaPath(path: string): string | null {\n if (!path.startsWith(\"<\")) return path\n const closingBracket = path.indexOf(\">\")\n // 流式输出里尖括号还没闭合,等后续 token 到齐再判断。\n if (closingBracket < 0) return null\n return `${path.slice(1, closingBracket)}${path.slice(closingBracket + 1)}`\n}\n\n/**\n * 能不能拿这个路径去下载。绝对路径原样交给服务端解析(它会把工作区路径映射进沙盒、\n * 并拒绝越界),所以这里只挡明显不该放过的:空路径和 `..`。\n */\nexport function isSafeMediaPath(path: string): boolean {\n if (!path) return false\n return !path.split(/[/\\\\]/).includes(\"..\")\n}\n\nfunction escapeAttribute(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n}\n\nfunction foldMediaLines(text: string): string {\n return text.replace(MEDIA_LINE_RE, (match: string, _wrap: string, rawPath: string) => {\n const path = unwrapMediaPath(rawPath)\n if (path === null) return match\n const name = basename(path)\n if (!isSafeMediaPath(path)) {\n // 路径没法用,但 MEDIA: 是内部标记,不能就这么摆给用户看——退化成文件名。\n return `\\`${name}\\``\n }\n return `<${FILE_CARD_TAG} data-path=\"${escapeAttribute(path)}\" data-name=\"${escapeAttribute(name)}\">${escapeAttribute(name)}</${FILE_CARD_TAG}>`\n })\n}\n\n/**\n * 把 MEDIA 行折叠成文件下载链接标签。\n *\n * `streaming` 时最后一行要特殊对待:MEDIA_LINE_RE 用 `$` 匹配行尾,而流式过程中最后一行\n * 随时都是「行尾」,逐 token 折叠会依次闪出 `MEDIA:`、半截路径的链接、再变成正确链接。\n * 所以正在写的那一行整行先不渲染,等它以换行结束、或消息转为 static 之后再折叠。\n *\n * 判据只能是 `streaming`,不能是「有没有尾随换行」:AssistantTurnBlock 传进来的文本是\n * trim 过的,静态消息永远没有尾随换行,那样判断会导致 MEDIA 行永远不折叠。\n */\nexport function collapseMediaTags(text: string, options?: { streaming?: boolean }): string {\n if (!text.includes(\"MEDIA:\")) return text\n if (!options?.streaming) return foldMediaLines(text)\n\n const newlineIndex = text.lastIndexOf(\"\\n\")\n const head = newlineIndex < 0 ? \"\" : text.slice(0, newlineIndex + 1)\n const lastLine = newlineIndex < 0 ? text : text.slice(newlineIndex + 1)\n\n if (MEDIA_LINE_START_RE.test(lastLine)) {\n return foldMediaLines(head)\n }\n return foldMediaLines(head) + lastLine\n}\n","import { type ComponentPropsWithRef, type MouseEvent, useState } from \"react\"\nimport type { ExtraProps } from \"streamdown\"\nimport { useBladeClient } from \"../context\"\nimport { cn } from \"../lib/utils\"\nimport { isSafeMediaPath } from \"../lib/media-tags\"\n\nexport type FileCardProps = ComponentPropsWithRef<\"span\"> &\n ExtraProps & {\n \"data-path\"?: string\n \"data-name\"?: string\n dataPath?: string\n dataName?: string\n sessionId?: string\n }\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined\n}\n\nfunction extractChildrenText(children: unknown): string {\n if (typeof children === \"string\") return children\n if (Array.isArray(children)) return children.map(extractChildrenText).join(\"\")\n if (children && typeof children === \"object\" && \"props\" in children) {\n return extractChildrenText((children as { props?: { children?: unknown } }).props?.children)\n }\n return \"\"\n}\n\n/**\n * 智能体产出文件的下载链接(由 MEDIA 行折叠而来)。\n *\n * href 让 Vue/纯 HTML 宿主看到标准的「文件名→URL」语义;普通点击仍交给\n * downloadFile,避免跨域时 download 属性被忽略,也确保使用点击时的最新 token。\n */\nexport function FileCard({\n node,\n \"data-path\": pathAttribute,\n \"data-name\": nameAttribute,\n dataPath,\n dataName,\n sessionId,\n children,\n className,\n ...props\n}: FileCardProps) {\n const client = useBladeClient()\n const [downloading, setDownloading] = useState(false)\n const [failed, setFailed] = useState(false)\n\n // sanitize 之后属性可能以 kebab-case prop、camelCase prop 或 HAST node 属性抵达,\n // 三种都读一遍;全都没有时退回标签内容(折叠时写的就是文件名)。\n const nodeProperties =\n node && typeof node === \"object\" && \"properties\" in node\n ? (node.properties as Record<string, unknown>)\n : undefined\n const path =\n pathAttribute ??\n dataPath ??\n stringValue(nodeProperties?.[\"data-path\"]) ??\n stringValue(nodeProperties?.dataPath) ??\n \"\"\n const name =\n nameAttribute ??\n dataName ??\n stringValue(nodeProperties?.[\"data-name\"]) ??\n stringValue(nodeProperties?.dataName) ??\n extractChildrenText(children) ??\n \"\"\n\n const disabled = !sessionId || !isSafeMediaPath(path)\n const downloadUrl = disabled\n ? undefined\n : client.buildAuthedUrl(\n `/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(path)}`,\n )\n\n const handleDownload = async (event: MouseEvent<HTMLAnchorElement>) => {\n // 修饰键点击保留浏览器的链接语义;普通点击走 SDK 下载,确保跨域可用。\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return\n event.preventDefault()\n if (disabled || downloading || !sessionId) return\n setDownloading(true)\n setFailed(false)\n try {\n await client.sessions.downloadFile(sessionId, path, name)\n } catch {\n setFailed(true)\n } finally {\n setDownloading(false)\n }\n }\n\n return (\n <span {...props} className={cn(\"blade-chat-file-card\", className)}>\n <a\n href={downloadUrl}\n download={name}\n onClick={handleDownload}\n aria-disabled={disabled || undefined}\n aria-busy={downloading || undefined}\n aria-label={`下载文件:${name}`}\n title={failed ? \"下载失败,点击重试\" : name}\n className=\"blade-chat-file-link\"\n >\n {name}\n </a>\n {failed && <span className=\"blade-chat-file-card-error\">下载失败</span>}\n </span>\n )\n}\n","import { cn } from \"../lib/utils\"\n\ninterface ShimmerProps {\n children?: string\n className?: string\n}\n\n/** 流式等待时的呼吸文字效果(样式见 style.css 的 .blade-shimmer-text)。 */\nexport function Shimmer({ children = \"正在思考...\", className }: ShimmerProps) {\n return (\n <span className={cn(\"blade-shimmer-text text-sm font-medium\", className)}>{children}</span>\n )\n}\n","import type { AskUserAnswerData, ToolCallInfo } from \"@blade-hq/agent-client\"\nimport { Check, ChevronRight, Loader2, MessageSquareMore, X } from \"lucide-react\"\nimport { useState, type ReactNode } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { AskUserQuestionBlock, parseAskUserQuestion } from \"./AskUserQuestionBlock\"\nimport {\n formatToolArgs,\n formatToolDuration,\n formatToolName,\n formatToolResult,\n getToolDisplayLabel,\n getToolStatusLabel,\n getToolTone,\n} from \"./display-utils\"\n\n/** 接入方自定义渲染器:返回 null 时回落到默认渲染。 */\nexport type ToolCallRenderer = (info: ToolCallInfo) => ReactNode | null\n\ninterface Props {\n toolCall: ToolCallInfo\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n answered?: boolean\n answerData?: AskUserAnswerData\n sessionStatus?: string\n renderer?: ToolCallRenderer\n}\n\n/**\n * 判断提问卡片该等待作答还是展示成已作答,只认工具状态。\n * 与 apps/web 的 ToolCallBlock 里同名函数保持一致:两处算出不同结果时,\n * 同一份会话在内置页面能点、在 SDK 里点不动。\n *\n * 不要再拿 sessionStatus 兜底。历史投影算错时用 waiting_for_input 补救,\n * 会同时把已经回答过的旧提问重新变成可作答(历史加载不会带回 answerData),\n * 而且会盖住投影层的错误——这个 bug 就是这么藏住的。\n */\nexport function resolveAskQuestionState({\n toolStatus,\n hasAnswerData,\n fallbackAnswered,\n}: {\n toolStatus: ToolCallInfo[\"status\"]\n hasAnswerData: boolean\n fallbackAnswered?: boolean\n}) {\n const awaitingAnswer = !hasAnswerData && toolStatus === \"awaiting_answer\"\n return {\n awaitingAnswer,\n answered:\n hasAnswerData ||\n (!awaitingAnswer &&\n (Boolean(fallbackAnswered) ||\n toolStatus === \"done\" ||\n toolStatus === \"cancelled\" ||\n toolStatus === \"error\")),\n }\n}\n\n/**\n * 极简工具调用块:状态 + 展示名一行,点开后是参数/结果的 <pre> 折叠展示。\n * AskUserQuestion 特殊处理为提问选项卡片。\n */\nexport function ToolCallBlock({\n toolCall,\n onAnswer,\n answered,\n answerData,\n sessionStatus,\n renderer,\n}: Props) {\n const [expanded, setExpanded] = useState(false)\n const normalizedName = formatToolName(toolCall.name)\n\n if (renderer) {\n const custom = renderer(toolCall)\n if (custom !== null && custom !== undefined) {\n return <>{custom}</>\n }\n }\n\n // AskUserQuestion:渲染成可作答的提问卡片\n if (normalizedName === \"AskUserQuestion\") {\n const askData =\n parseAskUserQuestion(typeof toolCall.result === \"string\" ? toolCall.result : null) ??\n parseAskUserQuestion(buildAskUserPayload(toolCall.arguments))\n const questionState = resolveAskQuestionState({\n toolStatus: toolCall.status,\n hasAnswerData: Boolean(answerData),\n fallbackAnswered: answered,\n })\n const canAnswer = questionState.awaitingAnswer && Boolean(onAnswer)\n if (askData) {\n return (\n <AskUserQuestionBlock\n data={askData}\n answered={questionState.answered}\n toolCallId={toolCall.id}\n sessionStatus={sessionStatus ?? \"\"}\n answerData={answerData}\n onAnswer={canAnswer ? onAnswer : undefined}\n />\n )\n }\n if (toolCall.status === \"pending\") {\n return (\n <div className=\"ml-4 flex max-w-lg items-center gap-2 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-4 text-sm text-[hsl(var(--muted-foreground))]\">\n <Loader2 size={14} className=\"animate-spin\" />\n <span>正在准备问题…</span>\n </div>\n )\n }\n return (\n <div className=\"ml-4 max-w-lg rounded-xl border border-amber-500/35 bg-amber-500/10 p-4 text-sm text-[hsl(var(--foreground))]\">\n <div className=\"font-semibold\">选择题内容暂时无法显示</div>\n <div className=\"mt-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]\">\n 收到的交互数据不完整。请让智能体重新提问。\n </div>\n </div>\n )\n }\n\n const tone = getToolTone(toolCall.status)\n const displayName = getToolDisplayLabel(toolCall)\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=\"blade-chat-tool ml-4 text-xs\">\n <div className={cn(\"border-l-[3px] flex items-center gap-2 px-3 py-2\", toneClass)}>\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 </span>\n </button>\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 </div>\n {expanded && (\n <div className=\"blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3\">\n <div className=\"mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]\">\n 工具\n </div>\n <div className=\"mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {normalizedName}\n </div>\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 {formatToolArgs(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 className=\"max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]\">\n {formatToolResult(toolCall.result)}\n </pre>\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction buildAskUserPayload(argumentsJson: string): string | null {\n try {\n const parsed = JSON.parse(argumentsJson)\n if (\n parsed &&\n typeof parsed === \"object\" &&\n Array.isArray((parsed as { questions?: unknown }).questions)\n ) {\n return JSON.stringify({ questions: (parsed as { questions: unknown[] }).questions })\n }\n } catch {\n return null\n }\n return null\n}\n","import type { AskUserAnswerData } from \"@blade-hq/agent-client\"\nimport { Check, Loader2, MessageSquareMore } from \"lucide-react\"\nimport { useEffect, useMemo, useState } from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { MarkdownContent } from \"./MarkdownContent\"\n\ninterface OptionItem {\n label: string\n description: string\n}\n\ninterface QuestionItem {\n question: string\n options: OptionItem[]\n multiSelect?: boolean\n}\n\ninterface SourceLoopInfo {\n loop_name: string\n description: string\n}\n\nexport interface AskUserQuestionData {\n questions: QuestionItem[]\n source_loop?: SourceLoopInfo | null\n}\n\ninterface Props {\n data: AskUserQuestionData\n answered: boolean\n toolCallId: string\n sessionStatus: string\n answerData?: AskUserAnswerData | undefined\n onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void\n}\n\n/** 提问选项卡片:单选/多选 + 自定义输入,回答通过 onAnswer 回调交还 ChatView。 */\nexport function AskUserQuestionBlock({\n data,\n answered,\n toolCallId,\n sessionStatus,\n answerData,\n onAnswer,\n}: Props) {\n // 每个问题独立的选择状态:选项下标集合或自定义文本\n const [selections, setSelections] = useState<Map<number, Set<number>>>(new Map())\n const [customTexts, setCustomTexts] = useState<Map<number, string>>(new Map())\n const [usingCustom, setUsingCustom] = useState<Set<number>>(new Set())\n const [submitted, setSubmitted] = useState(false)\n\n useEffect(() => {\n if (sessionStatus === \"failed\" || sessionStatus === \"interrupted\") {\n setSubmitted(false)\n }\n }, [sessionStatus])\n\n // 已作答时按历史答案展示,未作答时展示本地编辑状态\n const displayAnswerState = useMemo(() => {\n if (!(answered && answerData)) {\n return { selections, customTexts, usingCustom }\n }\n\n const nextSelections = new Map<number, Set<number>>()\n const nextCustomTexts = new Map<number, string>()\n const nextUsingCustom = new Set<number>()\n\n for (const [questionKey, optionIndexes] of Object.entries(answerData.selections)) {\n nextSelections.set(Number(questionKey), new Set(optionIndexes))\n }\n\n for (const [questionKey, text] of Object.entries(answerData.custom)) {\n const qIdx = Number(questionKey)\n nextCustomTexts.set(qIdx, text)\n nextUsingCustom.add(qIdx)\n }\n\n return {\n selections: nextSelections,\n customTexts: nextCustomTexts,\n usingCustom: nextUsingCustom,\n }\n }, [answerData, answered, customTexts, selections, usingCustom])\n\n const toggleOption = (qIdx: number, optIdx: number, multi: boolean) => {\n if (answered || submitted) return\n setSelections((prev) => {\n const next = new Map(prev)\n const current = new Set(next.get(qIdx) ?? [])\n if (multi) {\n if (current.has(optIdx)) current.delete(optIdx)\n else current.add(optIdx)\n } else {\n current.clear()\n current.add(optIdx)\n }\n next.set(qIdx, current)\n return next\n })\n setUsingCustom((prev) => {\n const next = new Set(prev)\n next.delete(qIdx)\n return next\n })\n }\n\n const handleCustomFocus = (qIdx: number) => {\n if (answered || submitted) return\n setSelections((prev) => {\n const next = new Map(prev)\n next.delete(qIdx)\n return next\n })\n setUsingCustom((prev) => new Set(prev).add(qIdx))\n }\n\n const setCustomText = (qIdx: number, text: string) => {\n if (answered || submitted) return\n setCustomTexts((prev) => new Map(prev).set(qIdx, text))\n }\n\n const getAnswer = (qIdx: number): string | null => {\n const q = data.questions[qIdx]\n if (usingCustom.has(qIdx)) {\n const text = (customTexts.get(qIdx) ?? \"\").trim()\n return text || null\n }\n const sel = selections.get(qIdx)\n if (!sel || sel.size === 0) return null\n return [...sel]\n .sort()\n .map((i) => q.options[i].label)\n .join(\", \")\n }\n\n const allAnswered = data.questions.every((_, i) => getAnswer(i) !== null)\n\n const handleSubmit = () => {\n if (answered || submitted || !allAnswered || !onAnswer) return\n\n const nextAnswerData: AskUserAnswerData = {\n selections: Object.fromEntries(\n Array.from(selections.entries()).map(([qIdx, optionIndexes]) => [\n qIdx,\n Array.from(optionIndexes).sort((a, b) => a - b),\n ]),\n ) as Record<number, number[]>,\n custom: Object.fromEntries(\n Array.from(usingCustom)\n .map((qIdx) => [qIdx, (customTexts.get(qIdx) ?? \"\").trim()] as const)\n .filter(([, text]) => text.length > 0),\n ) as Record<number, string>,\n }\n\n const parts = data.questions.map((q, i) => `- ${q.question} -> ${getAnswer(i)}`)\n const text = `关于需要确认的问题,用户的回答如下:\\n${parts.join(\"\\n\")}`\n setSubmitted(true)\n onAnswer(text, toolCallId, nextAnswerData)\n }\n\n return (\n <div\n className={cn(\n \"blade-chat-ask-card ml-4 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))]\",\n answered\n ? \"max-w-2xl space-y-3 p-3 text-xs text-[hsl(var(--muted-foreground))] opacity-80\"\n : \"max-w-lg space-y-5 p-4 text-sm\",\n )}\n >\n {data.source_loop?.description && (\n <div className=\"rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]\">\n 子智能体「{data.source_loop.description}」在等待你的回答\n </div>\n )}\n {data.questions.map((q, qIdx) => (\n <QuestionCard\n key={q.question}\n question={q}\n qIdx={qIdx}\n answered={answered}\n selected={displayAnswerState.selections.get(qIdx) ?? new Set()}\n isCustom={displayAnswerState.usingCustom.has(qIdx)}\n customText={displayAnswerState.customTexts.get(qIdx) ?? \"\"}\n onToggle={toggleOption}\n onCustomFocus={handleCustomFocus}\n onCustomChange={setCustomText}\n />\n ))}\n\n {!answered && !submitted && onAnswer && (\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!allAnswered}\n className=\"w-full rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {allAnswered ? \"确认\" : \"请先选择一个选项\"}\n </button>\n )}\n\n {submitted && !answered && (\n <button\n type=\"button\"\n disabled\n className=\"flex w-full items-center justify-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] opacity-80\"\n >\n <Loader2 size={14} className=\"animate-spin\" />\n 确认中\n </button>\n )}\n </div>\n )\n}\n\nfunction QuestionCard({\n question,\n qIdx,\n answered,\n selected,\n isCustom,\n customText,\n onToggle,\n onCustomFocus,\n onCustomChange,\n}: {\n question: QuestionItem\n qIdx: number\n answered: boolean\n selected: Set<number>\n isCustom: boolean\n customText: string\n onToggle: (qIdx: number, optIdx: number, multi: boolean) => void\n onCustomFocus: (qIdx: number) => void\n onCustomChange: (qIdx: number, text: string) => void\n}) {\n const multi = question.multiSelect ?? false\n\n return (\n <div>\n <div className={cn(\"flex items-start gap-2\", answered ? \"mb-2\" : \"mb-3\")}>\n <MessageSquareMore\n size={answered ? 12 : 13}\n className=\"mt-0.5 shrink-0 text-[hsl(var(--primary))]\"\n />\n <div\n className={cn(\n \"min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]\",\n answered ? \"text-xs\" : \"text-sm\",\n )}\n >\n <MarkdownContent className=\"blade-chat-prose\">{question.question}</MarkdownContent>\n </div>\n </div>\n\n <div className={cn(\"flex flex-col pl-5\", answered ? \"gap-1\" : \"gap-1.5\")}>\n {question.options.map((opt, optIdx) => {\n const isSel = selected.has(optIdx)\n return (\n <button\n key={opt.label}\n type=\"button\"\n disabled={answered}\n onClick={() => onToggle(qIdx, optIdx, multi)}\n className={cn(\n \"flex items-start gap-2.5 rounded-lg border text-left transition-all\",\n answered ? \"px-2.5 py-1.5\" : \"px-3 py-2.5\",\n isSel && !answered\n ? \"border-[hsl(var(--primary)/0.8)] bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]\"\n : isSel\n ? \"border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.08)] text-[hsl(var(--foreground))]\"\n : \"border-[hsl(var(--border))] bg-[hsl(var(--muted)/0.2)]\",\n !answered &&\n !isSel &&\n \"hover:border-[hsl(var(--ring)/0.4)] hover:bg-[hsl(var(--accent))]\",\n answered && \"cursor-default opacity-70\",\n )}\n >\n {multi && (\n <div\n className={cn(\n \"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors\",\n isSel && !answered\n ? \"border-[hsl(var(--primary-foreground)/0.6)] bg-[hsl(var(--primary-foreground)/0.2)]\"\n : isSel\n ? \"border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.12)]\"\n : \"border-[hsl(var(--border))]\",\n )}\n >\n {isSel && (\n <Check\n size={9}\n className={\n answered\n ? \"text-[hsl(var(--primary))]\"\n : \"text-[hsl(var(--primary-foreground))]\"\n }\n />\n )}\n </div>\n )}\n <div className=\"min-w-0\">\n <div className={cn(\"font-medium\", answered ? \"text-xs\" : \"text-[13px]\")}>\n {opt.label}\n </div>\n {opt.description && (\n <div\n className={cn(\n \"mt-0.5\",\n answered ? \"text-[11px]\" : \"text-xs\",\n isSel && !answered ? \"opacity-75\" : \"text-[hsl(var(--muted-foreground))]\",\n )}\n >\n {opt.description}\n </div>\n )}\n </div>\n </button>\n )\n })}\n\n {/* 「其他」内联输入 */}\n {answered && !isCustom ? null : (\n <div\n className={cn(\n \"flex items-center gap-2 rounded-lg border transition-all\",\n answered ? \"px-2.5 py-1.5\" : \"px-3 py-2.5\",\n isCustom\n ? \"border-[hsl(var(--ring)/0.6)] bg-[hsl(var(--accent))]\"\n : \"border-[hsl(var(--border))] hover:border-[hsl(var(--ring)/0.3)] hover:bg-[hsl(var(--accent))]\",\n answered && \"cursor-default opacity-70\",\n )}\n >\n <span className=\"shrink-0 text-xs text-[hsl(var(--muted-foreground))]\">其他:</span>\n <input\n type=\"text\"\n value={customText}\n disabled={answered}\n onChange={(e) => onCustomChange(qIdx, e.target.value)}\n onFocus={() => onCustomFocus(qIdx)}\n aria-label=\"自定义回答\"\n placeholder=\"输入你的答案...\"\n className={cn(\n \"min-w-0 flex-1 bg-transparent text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground)/0.5)]\",\n answered ? \"text-xs\" : \"text-sm\",\n )}\n />\n </div>\n )}\n </div>\n </div>\n )\n}\n\n/** 解析 AskUserQuestion 的工具结果/参数,容错 LLM 把 questions 输出为字符串的情况。 */\nexport function parseAskUserQuestion(\n toolResult: string | null | undefined,\n): AskUserQuestionData | null {\n if (!toolResult) return null\n try {\n const parsed = JSON.parse(toolResult)\n let questions = parsed?.questions\n if (typeof questions === \"string\") {\n try {\n questions = JSON.parse(questions)\n } catch {\n return null\n }\n }\n if (Array.isArray(questions) && questions.length > 0) {\n const normalized = questions.map(normalizeQuestionItem)\n if (normalized.every((question): question is QuestionItem => question !== null)) {\n return { ...parsed, questions: normalized } as AskUserQuestionData\n }\n }\n } catch {\n // 非 JSON,忽略\n }\n return null\n}\n\nfunction normalizeQuestionItem(value: unknown): QuestionItem | null {\n if (!value || typeof value !== \"object\") return null\n const item = value as {\n question?: unknown\n options?: unknown\n multiSelect?: unknown\n multi_select?: unknown\n }\n if (typeof item.question !== \"string\" || !Array.isArray(item.options)) return null\n const options = item.options.map(normalizeOptionItem)\n if (!options.every((option): option is OptionItem => option !== null)) return null\n return {\n question: item.question,\n options,\n multiSelect: item.multiSelect === true || item.multi_select === true,\n }\n}\n\nfunction normalizeOptionItem(value: unknown): OptionItem | null {\n if (typeof value === \"string\") return { label: value, description: \"\" }\n if (!value || typeof value !== \"object\") return null\n const option = value as { label?: unknown; description?: unknown }\n if (typeof option.label !== \"string\") return null\n return {\n label: option.label,\n description: typeof option.description === \"string\" ? option.description : \"\",\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\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=\"blade-chat-render-error 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 type { ChatMessage } from \"@blade-hq/agent-client\"\nimport { getFileParts, getImageParts, getTextContent } from \"@blade-hq/agent-client\"\nimport { FileText, Loader2 } from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\nimport { MarkdownContent } from \"./MarkdownContent\"\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\nconst isSending = (message: ChatMessage) => message.status === \"streaming\"\n\n/** 用户消息气泡:文本 + 图片/文件附件展示(不含第一方的预览弹窗与 what-if 徽章)。 */\nexport function UserMessageBubble({ message, className }: UserMessageProps) {\n const text = getTextContent(message.content).trim()\n const fileParts = getFileParts(message.content)\n const imageParts = getImageParts(message.content)\n\n return (\n <div className={cn(\"blade-chat-user-row flex justify-end\", className)}>\n <div className=\"blade-chat-user-col flex max-w-[72%] flex-col items-end 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-64 rounded-xl border border-[hsl(var(--user-msg-border))] object-cover\"\n />\n ))}\n </div>\n )}\n {fileParts.length > 0 && (\n <div className=\"flex flex-col items-end gap-1.5\">\n {fileParts.map((part) => (\n <div\n key={`${part.name}-${part.data.length}`}\n className=\"flex items-center gap-1.5 rounded-lg border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--muted)/0.3)] px-2.5 py-1.5 text-xs text-[hsl(var(--muted-foreground))]\"\n >\n <FileText size={12} className=\"shrink-0\" />\n <span className=\"max-w-56 truncate\" title={part.name}>\n {part.name}\n </span>\n </div>\n ))}\n </div>\n )}\n {text && (\n <div className=\"blade-chat-user-bubble max-w-full rounded-[20px] rounded-br-[6px] border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-[18px] py-[13px] text-sm leading-[1.65] text-[hsl(var(--user-msg-fg))]\">\n <MarkdownContent className=\"blade-chat-prose\">{text}</MarkdownContent>\n </div>\n )}\n {text && isSending(message) && (\n <div className=\"flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]\">\n <Loader2 size={11} className=\"animate-spin\" aria-hidden=\"true\" />\n <span>发送中</span>\n </div>\n )}\n </div>\n </div>\n )\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 return (\n <div className={cn(\"blade-chat-error-row flex justify-center\", className)}>\n {/* 与内置 Web 的 ErrorMessageBlock 保持一致:消息流里的错误不用红色。 */}\n <div className=\"blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--border))] px-4 py-1 text-sm leading-7 text-[hsl(var(--muted-foreground))]\">\n {text}\n </div>\n </div>\n )\n}\n","// ============================== React 绑定 ==============================\nexport { BladeProvider, useBladeClient } from \"./context\"\nexport type { BladeProviderProps } from \"./context\"\nexport { useAgentSession } from \"./hooks/use-agent-session\"\nexport type { UseAgentSessionOptions, UseAgentSessionResult } from \"./hooks/use-agent-session\"\n\n// ============================== 聊天界面 ==============================\nexport { ChatView } from \"./components/ChatView\"\nexport type {\n ChatViewClassNames,\n ChatViewProps,\n ChatViewRenderers,\n ChatViewSlots,\n} from \"./components/ChatView\"\nexport { MarkdownContent } from \"./components/MarkdownContent\"\nexport type { MarkdownContentProps } from \"./components/MarkdownContent\"\nexport type { ToolCallRenderer } from \"./components/ToolCallBlock\"\n\n// ============================== 客户端全量转出 ==============================\n// 方便接入方只装一个包:agent-client 的全部公共面从这里原样可用。\nexport * from \"@blade-hq/agent-client\"\n"],"mappings":"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","names":["Component","forwardRef","createElement","useEffect","useState","jsx","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useCallback","useEffect","useMemo","useRef","useState","useMemo","useRef","useState","isAtBottom","escapedFromLock","createContext","useContext","useEffect","useMemo","useRef","createContext","useEffect","useRef","useMemo","targetScrollTop","StickToBottom","useContext","useState","useState","jsx","jsxs","useState","useEffect","useMemo","useRef","useState","useState","jsx","jsxs","useState","jsx","jsxs","useRef","useState","useEffect","useMemo","jsx","useState","useEffect","useMemo","useState","jsx","jsxs","useState","useEffect","useMemo","text","jsx","jsxs","useState","jsx","jsxs","useState","jsx","jsxs","getTextContent","jsx","jsxs","getTextContent","jsx","jsxs","useMemo","useRef","useEffect","useState","useCallback","jsx","jsxs","useState","useEffect"]}