@blade-hq/agent-react 1.2.1-beta.5 → 1.2.1-beta.7

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 CHANGED
@@ -1597,7 +1597,12 @@ function ThinkingBlock({ reasoning, isStreaming }) {
1597
1597
  className: "inline-flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
1598
1598
  children: [
1599
1599
  /* @__PURE__ */ jsx9(Brain, { size: 12, className: "shrink-0" }),
1600
- isStreaming ? /* @__PURE__ */ jsx9(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003..." }) : /* @__PURE__ */ jsx9("span", { children: "\u601D\u8003\u8FC7\u7A0B" }),
1600
+ isStreaming ? /* @__PURE__ */ jsx9(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }) : /* @__PURE__ */ jsx9("span", { children: "\u601D\u8003\u8FC7\u7A0B" }),
1601
+ /* @__PURE__ */ jsxs7("span", { className: "text-[hsl(var(--muted-foreground))]/70", children: [
1602
+ "\xB7 ",
1603
+ new Intl.NumberFormat("zh-CN").format(reasoning.length),
1604
+ " \u5B57"
1605
+ ] }),
1601
1606
  /* @__PURE__ */ jsx9(
1602
1607
  ChevronDown,
1603
1608
  {
@@ -1614,6 +1619,12 @@ function ThinkingBlock({ reasoning, isStreaming }) {
1614
1619
  function getMessageText(message) {
1615
1620
  return getTextContent(normalizeMessageContent(message.content)).trim();
1616
1621
  }
1622
+ function findLatestReasoningMessageIndex(messages) {
1623
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
1624
+ if (messages[index].reasoning) return index;
1625
+ }
1626
+ return -1;
1627
+ }
1617
1628
  function AssistantTurnBlock({
1618
1629
  messages,
1619
1630
  isStreaming = false,
@@ -1626,6 +1637,7 @@ function AssistantTurnBlock({
1626
1637
  const hasAnyContent = messages.some(
1627
1638
  (message) => getMessageText(message) || message.reasoning || (message.tool_calls?.length ?? 0) > 0
1628
1639
  );
1640
+ const latestReasoningIndex = isStreaming ? findLatestReasoningMessageIndex(messages) : -1;
1629
1641
  return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
1630
1642
  hasInterrupted && /* @__PURE__ */ jsx9("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", children: "\u5DF2\u4E2D\u65AD" }),
1631
1643
  messages.map((message, index) => {
@@ -1633,12 +1645,13 @@ function AssistantTurnBlock({
1633
1645
  const streamingThis = isStreaming && isLast;
1634
1646
  const text = getMessageText(message);
1635
1647
  const toolCalls = message.tool_calls ?? [];
1648
+ const showReasoning = !!message.reasoning && (!isStreaming || index === latestReasoningIndex);
1636
1649
  return /* @__PURE__ */ jsxs7(
1637
1650
  "div",
1638
1651
  {
1639
1652
  className: "flex flex-col gap-3",
1640
1653
  children: [
1641
- message.reasoning && /* @__PURE__ */ jsx9(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }),
1654
+ showReasoning && message.reasoning && /* @__PURE__ */ jsx9(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }),
1642
1655
  text && /* @__PURE__ */ jsx9("div", { className: "blade-chat-assistant-text text-[15px] leading-8 text-[hsl(var(--foreground))]", children: /* @__PURE__ */ jsx9(
1643
1656
  MarkdownContent,
1644
1657
  {
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/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/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}\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 className={cn(\"blade-chat flex min-h-0 flex-1 flex-col\", props.classNames?.root)}>\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 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 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 {errorMessage && (\n <div className=\"blade-chat-error-bar flex items-start gap-2 border-b border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800 dark:border-red-800/30 dark:bg-red-950/30 dark:text-red-300\">\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 />\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))] px-4 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 { useEffect, useMemo, useRef, 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}\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}: 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=\"px-5 pb-7 pt-8 sm:px-10 sm:pt-10\">\n <div className=\"blade-chat-messages-content mx-auto max-w-[748px]\">\n <div className=\"flex min-w-0 flex-col gap-9\">\n {renderBlocks.length === 0\n ? (emptyState ?? (\n <div className=\"flex flex-col items-center justify-center gap-3 py-24 text-[hsl(var(--muted-foreground))]\">\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 />\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 if (isAtBottom) return null\n\n return (\n <button\n type=\"button\"\n onClick={() => scrollToBottom()}\n className=\"absolute bottom-4 right-4 flex items-center gap-1 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-1.5 text-xs text-[hsl(var(--muted-foreground))] shadow-lg transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <ChevronDown size={14} />\n <span>滚动到底部</span>\n </button>\n )\n}\n\nfunction PlanningDivider({ kind }: { kind: \"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}\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 <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\n/**\n * 一轮助手回复:按消息顺序渲染 thinking 折叠块、正文 Markdown 与工具调用。\n * 相比第一方版本去掉了紧凑/详细模式切换、文件交付卡片与内联资源 iframe。\n */\nexport function AssistantTurnBlock({\n messages,\n isStreaming = false,\n askAnswers,\n onAnswer,\n sessionStatus,\n toolCallRenderer,\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\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\n return (\n <div\n key={message.entry_id ?? `${message.timestamp ?? \"assistant\"}-${index}`}\n className=\"flex flex-col gap-3\"\n >\n {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 >\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 { cn, copyToClipboard } from \"../lib/utils\"\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\nexport interface MarkdownContentProps {\n children: string\n className?: string\n /** 流式渲染传 \"streaming\",历史静态内容默认 \"static\"。 */\n mode?: \"streaming\" | \"static\"\n}\n\n/**\n * SDK 版 Markdown 渲染:Streamdown 默认转义/消毒(不开启任何 raw HTML),\n * 附带代码块复制按钮;相比第一方版本去掉了 mermaid、外链确认弹窗、\n * 会话文件卡片等第一方能力。\n */\nexport function MarkdownContent({ children, className, mode }: MarkdownContentProps) {\n const resolvedChildren = useMemo(() => children.replace(SYSTEM_REMINDER_RE, \"\"), [children])\n\n return (\n <Streamdown\n className={cn(\"blade-chat-markdown break-words\", className)}\n mode={mode ?? \"static\"}\n components={MARKDOWN_COMPONENTS}\n >\n {resolvedChildren}\n </Streamdown>\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 * 极简工具调用块:状态 + 展示名一行,点开后是参数/结果的 <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 canAnswer =\n toolCall.status === \"awaiting_answer\" &&\n Boolean(onAnswer)\n if (askData) {\n return (\n <AskUserQuestionBlock\n data={askData}\n answered={\n toolCall.status === \"awaiting_answer\"\n ? false\n : Boolean(answered) || toolCall.status === \"done\"\n }\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 <div className=\"blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--destructive))] px-4 py-1 text-sm leading-7 text-[hsl(var(--destructive))]\">\n {text}\n </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","useEffect","useMemo","useRef","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","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","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/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}\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 className={cn(\"blade-chat flex min-h-0 flex-1 flex-col\", props.classNames?.root)}>\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 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 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 {errorMessage && (\n <div className=\"blade-chat-error-bar flex items-start gap-2 border-b border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800 dark:border-red-800/30 dark:bg-red-950/30 dark:text-red-300\">\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 />\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))] px-4 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 { useEffect, useMemo, useRef, 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}\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}: 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=\"px-5 pb-7 pt-8 sm:px-10 sm:pt-10\">\n <div className=\"blade-chat-messages-content mx-auto max-w-[748px]\">\n <div className=\"flex min-w-0 flex-col gap-9\">\n {renderBlocks.length === 0\n ? (emptyState ?? (\n <div className=\"flex flex-col items-center justify-center gap-3 py-24 text-[hsl(var(--muted-foreground))]\">\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 />\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 if (isAtBottom) return null\n\n return (\n <button\n type=\"button\"\n onClick={() => scrollToBottom()}\n className=\"absolute bottom-4 right-4 flex items-center gap-1 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-1.5 text-xs text-[hsl(var(--muted-foreground))] shadow-lg transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]\"\n >\n <ChevronDown size={14} />\n <span>滚动到底部</span>\n </button>\n )\n}\n\nfunction PlanningDivider({ kind }: { kind: \"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}\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}: 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 >\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 { cn, copyToClipboard } from \"../lib/utils\"\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\nexport interface MarkdownContentProps {\n children: string\n className?: string\n /** 流式渲染传 \"streaming\",历史静态内容默认 \"static\"。 */\n mode?: \"streaming\" | \"static\"\n}\n\n/**\n * SDK 版 Markdown 渲染:Streamdown 默认转义/消毒(不开启任何 raw HTML),\n * 附带代码块复制按钮;相比第一方版本去掉了 mermaid、外链确认弹窗、\n * 会话文件卡片等第一方能力。\n */\nexport function MarkdownContent({ children, className, mode }: MarkdownContentProps) {\n const resolvedChildren = useMemo(() => children.replace(SYSTEM_REMINDER_RE, \"\"), [children])\n\n return (\n <Streamdown\n className={cn(\"blade-chat-markdown break-words\", className)}\n mode={mode ?? \"static\"}\n components={MARKDOWN_COMPONENTS}\n >\n {resolvedChildren}\n </Streamdown>\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 * 极简工具调用块:状态 + 展示名一行,点开后是参数/结果的 <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 canAnswer =\n toolCall.status === \"awaiting_answer\" &&\n Boolean(onAnswer)\n if (askData) {\n return (\n <AskUserQuestionBlock\n data={askData}\n answered={\n toolCall.status === \"awaiting_answer\"\n ? false\n : Boolean(answered) || toolCall.status === \"done\"\n }\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 <div className=\"blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--destructive))] px-4 py-1 text-sm leading-7 text-[hsl(var(--destructive))]\">\n {text}\n </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","useEffect","useMemo","useRef","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","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","jsx","jsxs","useState","useEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blade-hq/agent-react",
3
- "version": "1.2.1-beta.5",
3
+ "version": "1.2.1-beta.7",
4
4
  "description": "Blade Agent React 绑定:BladeProvider、useAgentSession、开箱即用的 ChatView 聊天界面。",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@blade-hq/agent-client": "1.2.1-beta.5"
31
+ "@blade-hq/agent-client": "1.2.1-beta.7"
32
32
  },
33
33
  "bundledDependencies": [],
34
34
  "peerDependencies": {