@blade-hq/agent-react 2612.0.0-beta.0 → 2612.0.0-beta.2

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.
Files changed (180) hide show
  1. package/README.md +88 -258
  2. package/dist/chat/AgentLoopBlock.d.ts +14 -0
  3. package/dist/{components → chat}/AskUserQuestionBlock.d.ts +3 -7
  4. package/dist/chat/AssistantTurnBlock.d.ts +50 -0
  5. package/dist/chat/AttachmentPreviewDialog.d.ts +26 -0
  6. package/dist/chat/ChatPanel.d.ts +64 -0
  7. package/dist/chat/CompactionCard.d.ts +6 -0
  8. package/dist/chat/ConnectionBanner.d.ts +10 -0
  9. package/dist/chat/CurrentPlanPanel.d.ts +20 -0
  10. package/dist/chat/FileDeliveryCards.d.ts +26 -0
  11. package/dist/chat/FinalArtifactCards.d.ts +8 -0
  12. package/dist/chat/ImageLightbox.d.ts +11 -0
  13. package/dist/chat/LightComposer.d.ts +7 -0
  14. package/dist/chat/LiteMessageList.d.ts +82 -0
  15. package/dist/chat/MessageActions.d.ts +6 -0
  16. package/dist/chat/MessageContextPills.d.ts +6 -0
  17. package/dist/chat/MessageFileAttachmentList.d.ts +13 -0
  18. package/dist/chat/MessageList.d.ts +54 -0
  19. package/dist/chat/PostChatFollowupBlock.d.ts +11 -0
  20. package/dist/{components → chat}/RenderErrorBoundary.d.ts +0 -1
  21. package/dist/chat/ResultFeedback.d.ts +11 -0
  22. package/dist/chat/SessionReplayBar.d.ts +12 -0
  23. package/dist/chat/TextAttachmentPills.d.ts +10 -0
  24. package/dist/chat/ToolCallBlock.d.ts +48 -0
  25. package/dist/chat/ToolUiCard.d.ts +6 -0
  26. package/dist/chat/TurnNavRail.d.ts +17 -0
  27. package/dist/chat/UserMessageBubble.d.ts +20 -0
  28. package/dist/chat/WorkflowRunBlock.d.ts +13 -0
  29. package/dist/chat/ai-elements/reasoning.d.ts +32 -0
  30. package/dist/chat/ai-elements/shimmer.d.ts +15 -0
  31. package/dist/chat/assistant-turn-questions.d.ts +14 -0
  32. package/dist/chat/card/CardContext.d.ts +7 -0
  33. package/dist/chat/chat-theme.d.ts +19 -0
  34. package/dist/chat/customization.d.ts +214 -0
  35. package/dist/chat/display-utils.d.ts +48 -0
  36. package/dist/{components/PostChatFollowupBlock.d.ts → chat/followup-interaction.d.ts} +5 -17
  37. package/dist/chat/index.d.ts +100 -0
  38. package/dist/chat/lib/citations.d.ts +30 -0
  39. package/dist/chat/lib/code-language.d.ts +5 -0
  40. package/dist/chat/lib/loopback.d.ts +8 -0
  41. package/dist/chat/lib/markdown-asset-url.d.ts +5 -0
  42. package/dist/chat/lib/preview-dispatch.d.ts +24 -0
  43. package/dist/chat/lib/skill-name.d.ts +9 -0
  44. package/dist/chat/lib/skill-visibility.d.ts +8 -0
  45. package/dist/chat/lib/ui-meta.d.ts +5 -0
  46. package/dist/chat/lib/use-async-value.d.ts +8 -0
  47. package/dist/chat/markdown/ExternalAnchor.d.ts +9 -0
  48. package/dist/chat/markdown/MarkdownContent.d.ts +40 -0
  49. package/dist/chat/markdown/text.d.ts +11 -0
  50. package/dist/chat/message-list-blocks.d.ts +92 -0
  51. package/dist/chat/plan/PlanSummaryCard.d.ts +10 -0
  52. package/dist/chat/plan/extract-plan-messages.d.ts +4 -0
  53. package/dist/chat/plan/parse-plan-messages.d.ts +10 -0
  54. package/dist/chat/plan/parse-plan-tree.d.ts +16 -0
  55. package/dist/chat/plan/types.d.ts +56 -0
  56. package/dist/chat/reasoning-visibility.d.ts +2 -0
  57. package/dist/chat/runtime/actions.d.ts +22 -0
  58. package/dist/chat/runtime/background-task-dismissals.d.ts +10 -0
  59. package/dist/chat/runtime/composer-channels.d.ts +46 -0
  60. package/dist/chat/runtime/environment.d.ts +152 -0
  61. package/dist/chat/runtime/input-cache-reset.d.ts +8 -0
  62. package/dist/chat/runtime/input-services.d.ts +111 -0
  63. package/dist/chat/runtime/session-source.d.ts +49 -0
  64. package/dist/chat/runtime/use-chat-actions.d.ts +19 -0
  65. package/dist/chat/runtime/use-session-replay.d.ts +16 -0
  66. package/dist/chat/scroll-anchor.d.ts +46 -0
  67. package/dist/chat/tool-renderers/BashRenderer.d.ts +2 -0
  68. package/dist/chat/tool-renderers/FileEditRenderer.d.ts +2 -0
  69. package/dist/chat/tool-renderers/FileReadRenderer.d.ts +2 -0
  70. package/dist/chat/tool-renderers/KbSearchRenderer.d.ts +2 -0
  71. package/dist/chat/tool-renderers/SearchRenderer.d.ts +2 -0
  72. package/dist/chat/tool-renderers/SubmitResultRenderer.d.ts +2 -0
  73. package/dist/chat/tool-renderers/kb-search-result.d.ts +19 -0
  74. package/dist/chat/tool-renderers/registry.d.ts +5 -0
  75. package/dist/chat/tool-renderers/shared.d.ts +30 -0
  76. package/dist/chat/tool-renderers/write-preview-scroll.d.ts +5 -0
  77. package/dist/chat-OCLOVB3H.css +175 -0
  78. package/dist/chat.css +175 -0
  79. package/dist/chunk-6ZDOQEWK.js +49365 -0
  80. package/dist/chunk-6ZDOQEWK.js.map +1 -0
  81. package/dist/chunk-FQQJP2GJ.js +26986 -0
  82. package/dist/chunk-FQQJP2GJ.js.map +1 -0
  83. package/dist/{chunk-G3PMV62Z.js → chunk-PR4QN5HX.js} +9 -2
  84. package/dist/chunk-WCMGQJLE.js +258 -0
  85. package/dist/chunk-WCMGQJLE.js.map +1 -0
  86. package/dist/components/AgentChat.d.ts +3 -3
  87. package/dist/components/ChatView.d.ts +2 -2
  88. package/dist/components/ConnectorPanel.d.ts +1 -1
  89. package/dist/components/ContextCard.d.ts +1 -1
  90. package/dist/components/LlmChat.d.ts +1 -1
  91. package/dist/components/McpAppCard.d.ts +1 -1
  92. package/dist/components/PlanUpdateBlock.d.ts +0 -8
  93. package/dist/components/PluginConnectorList.d.ts +1 -1
  94. package/dist/components/ReplayBar.d.ts +1 -1
  95. package/dist/components/SessionPluginConfigDialog.d.ts +1 -1
  96. package/dist/components/SessionPluginConfigForm.d.ts +1 -1
  97. package/dist/components/SessionPluginIcon.d.ts +1 -1
  98. package/dist/components/SessionPluginSelector.d.ts +1 -1
  99. package/dist/components/SessionQueuePanel.d.ts +1 -1
  100. package/dist/components/ToolUiCardView.d.ts +1 -1
  101. package/dist/components/plugin-config-draft.d.ts +1 -1
  102. package/dist/components/plugin-config-schema.d.ts +1 -1
  103. package/dist/components/plugin-connector.d.ts +1 -1
  104. package/dist/components/use-session-plugin-activation.d.ts +1 -1
  105. package/dist/context.d.ts +11 -2
  106. package/dist/embed/blade-chat-element.d.ts +14 -1
  107. package/dist/embed/entry.d.ts +8 -78
  108. package/dist/hooks/use-replay.d.ts +1 -1
  109. package/dist/hooks/use-turn-navigation.d.ts +1 -1
  110. package/dist/host.d.ts +54 -0
  111. package/dist/index.d.ts +11 -69
  112. package/dist/index.js +12 -63525
  113. package/dist/index.js.map +1 -1
  114. package/dist/internal.d.ts +60 -0
  115. package/dist/internal.js +656 -0
  116. package/dist/internal.js.map +1 -0
  117. package/dist/lib/mount-renderers.d.ts +25 -0
  118. package/dist/lib/use-effect-event.d.ts +3 -0
  119. package/dist/rich-input/BackgroundTasksPill.d.ts +3 -0
  120. package/dist/rich-input/ChatInput.d.ts +59 -0
  121. package/dist/rich-input/ComposerAttachmentViewport.d.ts +3 -0
  122. package/dist/rich-input/ConnectButton.d.ts +24 -0
  123. package/dist/rich-input/FileCompletionMenu.d.ts +44 -0
  124. package/dist/rich-input/FileSizeLimitDialog.d.ts +9 -0
  125. package/dist/rich-input/ModelSelector.d.ts +10 -0
  126. package/dist/rich-input/PlanningToggle.d.ts +7 -0
  127. package/dist/rich-input/ProgressCircle.d.ts +12 -0
  128. package/dist/rich-input/ReasoningModeSelect.d.ts +9 -0
  129. package/dist/rich-input/SkillCompletionMenu.d.ts +9 -0
  130. package/dist/rich-input/SkillStatusBar.d.ts +15 -0
  131. package/dist/rich-input/extensions/file-mention.d.ts +12 -0
  132. package/dist/rich-input/extensions/kb-mention.d.ts +18 -0
  133. package/dist/rich-input/extensions/skill-mention.d.ts +48 -0
  134. package/dist/rich-input/extensions/workflow-mention.d.ts +10 -0
  135. package/dist/rich-input/index.d.ts +48 -0
  136. package/dist/rich-input/input-keyboard.d.ts +13 -0
  137. package/dist/rich-input/lib/attachment-upload.d.ts +10 -0
  138. package/dist/rich-input/lib/background-tasks-view.d.ts +31 -0
  139. package/dist/rich-input/lib/client-query.d.ts +32 -0
  140. package/dist/rich-input/lib/composer-content.d.ts +42 -0
  141. package/dist/rich-input/lib/image-input-availability.d.ts +3 -0
  142. package/dist/rich-input/lib/kb-suggestions.d.ts +37 -0
  143. package/dist/rich-input/lib/reasoning-levels.d.ts +1 -0
  144. package/dist/rich-input/lib/session-data.d.ts +20 -0
  145. package/dist/rich-input/lib/skill-suggestions.d.ts +19 -0
  146. package/dist/rich-input/lib/token-estimate.d.ts +2 -0
  147. package/dist/rich-input/lib/token-pressure.d.ts +8 -0
  148. package/dist/rich-input/lib/upload-results.d.ts +8 -0
  149. package/dist/rich-input/lib/user-home.d.ts +33 -0
  150. package/dist/rich-input/model/model-data.d.ts +6 -0
  151. package/dist/rich-input/model/resolve-model.d.ts +59 -0
  152. package/dist/rich-input/model/use-composer-model.d.ts +24 -0
  153. package/dist/rich-input/services.d.ts +22 -0
  154. package/dist/rich-input/use-dismiss-skill-suggestions-on-mode-change.d.ts +3 -0
  155. package/dist/rich-input/use-input-history.d.ts +14 -0
  156. package/dist/rich-input/voice/VoiceWaveform.d.ts +10 -0
  157. package/dist/rich-input/voice/use-tiptap-voice-input.d.ts +47 -0
  158. package/dist/rich-input/voice/use-voice-input.d.ts +2 -0
  159. package/dist/rich-input/voice/voice-input-support.d.ts +5 -0
  160. package/dist/rich-input.js +29853 -0
  161. package/dist/rich-input.js.map +1 -0
  162. package/dist/style.css +30 -64
  163. package/dist/style.full.css +210 -65
  164. package/dist/{webapi-W3IB5DO4.js → webapi-E7K2CNM7.js} +2 -2
  165. package/package.json +12 -3
  166. package/public-api.md +206 -3603
  167. package/dist/components/AgentLoopBlock.d.ts +0 -8
  168. package/dist/components/AgentTaskCard.d.ts +0 -12
  169. package/dist/components/AssistantTurnBlock.d.ts +0 -36
  170. package/dist/components/ChatSurface.d.ts +0 -199
  171. package/dist/components/ConnectionBanner.d.ts +0 -8
  172. package/dist/components/MarkdownContent.d.ts +0 -30
  173. package/dist/components/MessageList.d.ts +0 -62
  174. package/dist/components/Shimmer.d.ts +0 -7
  175. package/dist/components/ToolCallBlock.d.ts +0 -41
  176. package/dist/components/TurnNavRail.d.ts +0 -23
  177. package/dist/components/UserMessageBubble.d.ts +0 -25
  178. package/dist/components/display-utils.d.ts +0 -4
  179. /package/dist/{chunk-G3PMV62Z.js.map → chunk-PR4QN5HX.js.map} +0 -0
  180. /package/dist/{webapi-W3IB5DO4.js.map → webapi-E7K2CNM7.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal.ts","../src/lib/mount-renderers.tsx","../src/components/SessionMemoryToggle.tsx","../src/lib/agent-computer-command.ts","../src/components/SessionBranchPicker.tsx"],"sourcesContent":["// 第一方内部入口(`@blade-hq/agent-react/internal`):内置 Web、浏览器插件用的聊天内部块、\n// 判定逻辑与连接器组件。包含公开入口的全部内容;不进 public-api.md、README 不写,\n// 版本之间不做任何兼容保证。\nexport * from \"./index\"\n// 迁入的聊天组件、会话来源、聊天环境与宿主桥接(内置 Web、插件共用同一份)\nexport * from \"./chat\"\nexport { useBladeHost, useOptionalBladeClient } from \"./context\"\nexport { MountHostContext, MountSlot, mountRenderersToReact } from \"./lib/mount-renderers\"\n\nexport { useLlmChat } from \"./hooks/use-llm-chat\"\nexport { useMessagePin } from \"./hooks/use-message-pin\"\nexport type { UseMessagePinOptions } from \"./hooks/use-message-pin\"\nexport { useTypewriterReveal } from \"./hooks/use-typewriter-reveal\"\nexport type { UseTypewriterRevealResult } from \"./hooks/use-typewriter-reveal\"\nexport {\n latestUserSpeechEntryId,\n TURN_NAV_HIGHLIGHT_CLASS,\n turnNavItemsFromMessages,\n useTurnNavigation,\n} from \"./hooks/use-turn-navigation\"\nexport type {\n TurnNavigationOptions,\n TurnNavigationResult,\n TurnNavigationSource,\n} from \"./hooks/use-turn-navigation\"\nexport type { UseLlmChatResult } from \"./hooks/use-llm-chat\"\n\n// ============================== 连接器与插件 ==============================\nexport { ConnectorPanel } from \"./components/ConnectorPanel\"\nexport type { ConnectorPanelProps } from \"./components/ConnectorPanel\"\nexport { PluginConnectorList } from \"./components/PluginConnectorList\"\nexport type { ConfiguringPlugin, PluginConnectorListProps } from \"./components/PluginConnectorList\"\nexport { useSessionPluginActivation } from \"./components/use-session-plugin-activation\"\nexport type { UseSessionPluginActivationResult } from \"./components/use-session-plugin-activation\"\nexport {\n catalogToConnectorItems,\n filterConnectorItems,\n mergeConnectorItems,\n} from \"./components/plugin-connector\"\nexport type { PluginConnectorItem } from \"./components/plugin-connector\"\nexport { selectionFromItem, triggerSummary, TRIGGER_ICON_LIMIT } from \"./components/connector-panel-types\"\nexport type {\n PluginConnectorSelection,\n TriggerSummary,\n} from \"./components/connector-panel-types\"\nexport { SessionPluginSelector } from \"./components/SessionPluginSelector\"\nexport type { SessionPluginSelectorProps } from \"./components/SessionPluginSelector\"\nexport { SessionPluginIcon, sessionPluginLabel } from \"./components/SessionPluginIcon\"\nexport type { SessionPluginIconProps, SessionPluginLabelProps } from \"./components/SessionPluginIcon\"\nexport { PluginTriggerStack } from \"./components/PluginTriggerStack\"\nexport type { PluginTriggerStackProps } from \"./components/PluginTriggerStack\"\nexport { SessionPluginConfigDialog } from \"./components/SessionPluginConfigDialog\"\nexport type { SessionPluginConfigDialogProps } from \"./components/SessionPluginConfigDialog\"\nexport { SessionPluginConfigForm } from \"./components/SessionPluginConfigForm\"\nexport type {\n SessionPluginConfigDraft,\n SessionPluginConfigFormProps,\n} from \"./components/SessionPluginConfigForm\"\nexport { AgentChat } from \"./components/AgentChat\"\nexport type { AgentChatProps } from \"./components/AgentChat\"\nexport { LlmChat } from \"./components/LlmChat\"\nexport type { LlmChatProps } from \"./components/LlmChat\"\nexport type { LlmAdvancedSettings, LlmOverride } from \"./components/LlmAdvancedSettings\"\nexport { DEFAULT_ALLOWED_TAGS, MarkdownRenderer } from \"./components/markdown\"\nexport type {\n AllowedTags,\n CodeBlockOverrides,\n LinkSafetyConfig,\n MarkdownComponents,\n MarkdownRendererProps,\n RawHtmlPlugin,\n} from \"./components/markdown\"\nexport { WhatIfUserBubble } from \"./components/WhatIfUserBubble\"\nexport type { WhatIfUserBubbleProps } from \"./components/WhatIfUserBubble\"\nexport { parseWhatIfPrompt } from \"./lib/whatif-prompt\"\nexport type { ParsedWhatIfPrompt, WhatIfQuote } from \"./lib/whatif-prompt\"\nexport {\n getPlanUpdateDisplayState,\n isPlanUpdateTool,\n PLAN_AUTO_COLLAPSE_MS,\n parsePlanUpdate,\n pickCurrentPlanStep,\n PlanUpdateBlock,\n} from \"./components/PlanUpdateBlock\"\nexport type { PlanUpdateDisplayState } from \"./components/PlanUpdateBlock\"\nexport { ContextCard, ContextGroupCard } from \"./components/ContextCard\"\nexport type { ContextCardProps, ContextGroupCardProps } from \"./components/ContextCard\"\nexport { ToolUiCardView } from \"./components/ToolUiCardView\"\nexport { McpAppCard } from \"./components/McpAppCard\"\nexport type { McpAppMessage } from \"./components/McpAppCard\"\nexport { SessionMemoryToggle } from \"./components/SessionMemoryToggle\"\nexport type { SessionMemoryToggleProps } from \"./components/SessionMemoryToggle\"\nexport { SessionQueuePanel, isQueuePanelVisible } from \"./components/SessionQueuePanel\"\nexport type { SessionQueuePanelProps } from \"./components/SessionQueuePanel\"\n\n// ============================== 判定逻辑(不许各写一份) ==============================\n// apps/web 已开始按能力逐步消费这个包(见仓库 CLAUDE.md「聊天界面的能力先进\n// SDK」一节),但两端 UI 尚未整体收敛。这里先把电脑镜像的判定规则导出,让它可以被\n// SDK 接入方真正拿到、而不是完全不可达的死代码;接入方要自己实现「电脑镜像」\n// 标签页 UI 时可以直接复用这份判定,不用重新猜一遍规则。\n//\n// `isAgentComputerCommand`/`isAgentComputerToolCall` 只回答\"是不是一次 launch\n// 尝试\",`classifyAgentComputerLaunchOutcome` 才回答\"这次 launch 最终成不成功\"\n// ——只导出前者会让接入方把\"尝试过\"当成\"已经展示\",对失败/待定的 launch 也\n// 展示出电脑镜像面板,跟内置 Web 的实际行为不一致(Codex review 指出),所以\n// 完整判定也要一并导出。\nexport {\n isAgentComputerCommand,\n isAgentComputerToolCall,\n classifyAgentComputerLaunchOutcome,\n} from \"./lib/agent-computer-command\"\nexport type { AgentComputerLaunchOutcome } from \"./lib/agent-computer-command\"\n\n\nexport { SessionBranchPicker } from \"./components/SessionBranchPicker\"\nexport type { SessionBranchPickerProps } from \"./components/SessionBranchPicker\"\n\nexport { MessageImage, type MessageImageProps } from \"./components/MessageImage\"\n\nexport { BackgroundWakeNotice } from \"./components/BackgroundWakeNotice\"\n","import type {\n BladeChatMountRenderers,\n MountHandle,\n MountRenderer,\n MountRendererObject,\n MountResult,\n} from \"@blade-hq/agent-client\"\nimport { createContext, useContext, useId, useLayoutEffect, useRef, type ReactNode } from \"react\"\nimport type { ChatViewRenderers } from \"../chat/customization\"\n\n/**\n * 挂载节点放在哪里。\n *\n * `<blade-chat>` 把它设成元素本身:挂载节点作为元素的 light DOM 子节点,经 Shadow DOM\n * 里的 `<slot>` 显示在区块位置,宿主页面的样式(包括 Vue 的 scoped 样式)直接生效。\n * 没有设置时(npm 包里),挂载节点就是组件内的一个 div。\n */\nexport const MountHostContext = createContext<HTMLElement | null>(null)\n\nfunction normalizeResult<T>(result: MountResult<T>): MountHandle<T> {\n if (typeof result === \"function\") return { destroy: result }\n if (result && typeof result === \"object\") return result\n return { destroy: () => {} }\n}\n\nfunction toObject<T>(renderer: MountRenderer<T>): MountRendererObject<T> {\n return typeof renderer === \"function\" ? { mount: renderer } : renderer\n}\n\n/** 两份数据的顶层字段逐个相同时不必通知宿主(渲染器每次都会新建数据对象)。 */\nfunction sameData(a: object, b: object): boolean {\n const aKeys = Object.keys(a)\n if (aKeys.length !== Object.keys(b).length) return false\n return aKeys.every((key) => Object.is((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]))\n}\n\ninterface MountSlotProps<T extends object> {\n renderer: MountRendererObject<T>\n data: T\n}\n\n/** 给宿主一个 DOM 节点挂自己的内容;数据变化时原地更新或清理后重挂,卸载时清理。 */\nexport function MountSlot<T extends object>({ renderer, data }: MountSlotProps<T>) {\n const host = useContext(MountHostContext)\n const slotName = `blade-mount-${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`\n const localRef = useRef<HTMLDivElement>(null)\n const dataRef = useRef(data)\n const mountedRef = useRef<{ target: HTMLElement; handle: MountHandle<T>; data: T } | null>(null)\n\n useLayoutEffect(() => {\n dataRef.current = data\n })\n\n // 与外部系统(宿主挂载的 DOM)同步:挂载一次,渲染器或挂载位置变了才重挂\n useLayoutEffect(() => {\n let target: HTMLElement\n if (host) {\n target = document.createElement(\"div\")\n target.slot = slotName\n host.appendChild(target)\n } else {\n if (!localRef.current) return\n target = localRef.current\n }\n const initial = dataRef.current\n mountedRef.current = { target, handle: normalizeResult(renderer.mount(target, initial)), data: initial }\n return () => {\n const mounted = mountedRef.current\n mountedRef.current = null\n mounted?.handle.destroy()\n if (host) target.remove()\n else target.replaceChildren()\n }\n }, [host, renderer, slotName])\n\n useLayoutEffect(() => {\n const mounted = mountedRef.current\n if (!mounted || sameData(mounted.data, data)) return\n mounted.data = data\n if (mounted.handle.update) {\n mounted.handle.update(data)\n return\n }\n mounted.handle.destroy()\n mounted.target.replaceChildren()\n mounted.handle = normalizeResult(renderer.mount(mounted.target, data))\n }, [data, renderer])\n\n return host ? <slot name={slotName} /> : <div ref={localRef} data-blade-mount=\"\" />\n}\n\nfunction slotFor<T extends object>(renderer: MountRendererObject<T>, data: T): ReactNode | null {\n if (renderer.match && !renderer.match(data)) return null\n return <MountSlot renderer={renderer} data={data} />\n}\n\n/**\n * 把挂载式渲染器转成普通 React 渲染器:两种写法走同一条渲染路径,`match` 返回\n * false 等于 React 渲染器返回 null(走默认渲染)。调用方要按 `renderers` 对象缓存结果,\n * 否则每次渲染都会得到新的渲染器、挂载内容被反复重建。\n */\nexport function mountRenderersToReact(\n renderers: BladeChatMountRenderers | null | undefined,\n context: { sessionId?: string } = {},\n): ChatViewRenderers | undefined {\n if (!renderers) return undefined\n const result: ChatViewRenderers = {}\n if (renderers.toolCall) {\n const renderer = toObject(renderers.toolCall)\n result.toolCall = (toolCall) => slotFor(renderer, { toolCall, sessionId: context.sessionId })\n }\n if (renderers.userMessage) {\n const renderer = toObject(renderers.userMessage)\n result.userMessage = ({ message }) => slotFor(renderer, { message })\n }\n if (renderers.assistantText) {\n const renderer = toObject(renderers.assistantText)\n result.assistantText = ({ message, streaming, compact, sessionId }) =>\n slotFor(renderer, { message, streaming, compact, sessionId })\n }\n return result\n}\n","import type { BladeClient } from \"@blade-hq/agent-client\"\nimport { useCallback, useEffect, useRef, useState, useSyncExternalStore } from \"react\"\nimport { useOptionalBladeClient } from \"../context\"\nimport { cn } from \"../lib/utils\"\n\ninterface SaveState {\n saving: boolean\n listeners: Set<() => void>\n}\n\nconst saveStates = new WeakMap<BladeClient, Map<string, SaveState>>()\n\nfunction getSaveState(client: BladeClient, sessionId: string): SaveState {\n let clientStates = saveStates.get(client)\n if (!clientStates) {\n clientStates = new Map()\n saveStates.set(client, clientStates)\n }\n let state = clientStates.get(sessionId)\n if (!state) {\n state = { saving: false, listeners: new Set() }\n clientStates.set(sessionId, state)\n }\n return state\n}\n\nfunction notify(state: SaveState) {\n for (const listener of state.listeners) listener()\n}\n\nfunction cleanupSaveState(client: BladeClient, sessionId: string, state: SaveState) {\n if (state.saving || state.listeners.size > 0) return\n const clientStates = saveStates.get(client)\n if (clientStates?.get(sessionId) === state) clientStates.delete(sessionId)\n}\n\nexport interface SessionMemoryToggleProps {\n sessionId: string\n enabled: boolean\n /** 不在 BladeProvider 内使用时显式传入,与宿主现有 BladeClient 复用连接和鉴权。 */\n client?: BladeClient\n disabled?: boolean\n label?: string\n className?: string\n labelClassName?: string\n inputClassName?: string\n onSaved?: (sessionId: string, enabled: boolean) => void\n onError?: (error: unknown) => void\n}\n\n/**\n * 当前会话记忆开关。同一 client + sessionId 的所有实例共享保存锁,避免多个聊天入口\n * 或会话切换时发出乱序更新;服务端成功后才通过 onSaved 交还权威值。\n */\nexport function SessionMemoryToggle({\n sessionId,\n enabled,\n client: clientProp,\n disabled = false,\n label = \"当前会话使用记忆\",\n className,\n labelClassName,\n inputClassName,\n onSaved,\n onError,\n}: SessionMemoryToggleProps) {\n const contextClient = useOptionalBladeClient()\n const client = clientProp ?? contextClient\n if (!client) {\n throw new Error(\"SessionMemoryToggle 必须在 <BladeProvider> 内使用或显式传入 client\")\n }\n\n const saveState = getSaveState(client, sessionId)\n const subscribe = useCallback(\n (listener: () => void) => {\n saveState.listeners.add(listener)\n return () => {\n saveState.listeners.delete(listener)\n cleanupSaveState(client, sessionId, saveState)\n }\n },\n [client, saveState, sessionId],\n )\n const getSaving = useCallback(() => saveState.saving, [saveState])\n const saving = useSyncExternalStore(\n subscribe,\n getSaving,\n getSaving,\n )\n const [draftEnabled, setDraftEnabled] = useState(enabled)\n const activeSessionIdRef = useRef(sessionId)\n activeSessionIdRef.current = sessionId\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: a new session must discard this component instance's optimistic value even when both sessions share the same enabled prop\n useEffect(() => {\n setDraftEnabled(enabled)\n }, [enabled, sessionId])\n\n const update = useCallback(\n (nextEnabled: boolean) => {\n const currentSaveState = getSaveState(client, sessionId)\n if (currentSaveState.saving) return\n currentSaveState.saving = true\n notify(currentSaveState)\n setDraftEnabled(nextEnabled)\n\n void client.sessions.updateSessionMemory(sessionId, nextEnabled).then(\n (updated) => {\n if (activeSessionIdRef.current === sessionId) {\n setDraftEnabled(updated.memory_enabled)\n }\n onSaved?.(sessionId, updated.memory_enabled)\n },\n (error) => {\n if (activeSessionIdRef.current === sessionId) setDraftEnabled(enabled)\n onError?.(error)\n },\n ).finally(() => {\n currentSaveState.saving = false\n notify(currentSaveState)\n cleanupSaveState(client, sessionId, currentSaveState)\n })\n },\n [client, enabled, onError, onSaved, sessionId],\n )\n\n return (\n <label className={cn(\"flex items-center justify-between\", className)}>\n <span className={labelClassName}>{label}</span>\n <input\n type=\"checkbox\"\n checked={draftEnabled}\n onChange={(event) => update(event.target.checked)}\n disabled={disabled || saving}\n className={inputClassName}\n />\n </label>\n )\n}\n","/** 智能体是否在沙盒里启动了通用应用镜像(computer launch)。\n *\n * 只认「命令位置」上的 `computer launch`(行首 / `;` / `&&` / `|` / 换行 / 子 shell\n * 之后),避免路径、参数里恰好含 computer 的误判。\n *\n * 只认 `launch` 子命令,不认 `status`/`screenshot`/`click` 等——判据是「agent 启动过\n * 一个目标」,不是「agent 调用过任意 computer 子命令」。\n *\n * 与 apps/web/src/agent/lib/agent-computer-command.ts 保持同名同签名(判定逻辑不许\n * 各写一份,见仓库 CLAUDE.md),从 src/index.ts 导出给 SDK 接入方直接用。\n *\n * 注意:`isAgentComputerCommand`/`isAgentComputerToolCall` 只回答\"这条命令是不是\n * 一次 launch 尝试\",不回答\"这次 launch 最终成不成功\"——待处理/已失败的 launch\n * 也会命中这两个判定。SDK 接入方如果只用这两个函数就决定要不要展示自己的「电脑\n * 镜像」UI,会在启动失败/还没跑完时也展示出来,跟内置 Web 的实际行为不一致\n * (Codex review 指出:内置 Web 用下面的 `classifyAgentComputerLaunchOutcome`\n * 做完整判定,SDK 侧之前只导出了弱判据,等于把这道判断题的一半留给接入方自己\n * 猜)。下面把完整判定也一并导出,接入方要自己实现「电脑镜像」面板时不用重新\n * 猜一遍这条规则。\n */\nconst COMPUTER_LAUNCH_COMMAND_PATTERN = /(?:^|[\\n;&|(]\\s*)computer\\s+launch(?:\\s|$)/\n\nexport function isAgentComputerCommand(command: string): boolean {\n return COMPUTER_LAUNCH_COMMAND_PATTERN.test(command)\n}\n\n/** 工具调用的 JSON 参数里是不是一条 computer launch 命令。 */\nexport function isAgentComputerToolCall(argumentsJson: string | null | undefined): boolean {\n if (!argumentsJson) return false\n let command: unknown\n try {\n const parsed: unknown = JSON.parse(argumentsJson)\n if (typeof parsed !== \"object\" || parsed === null) return false\n command = (parsed as { command?: unknown }).command\n } catch {\n return false\n }\n return typeof command === \"string\" && isAgentComputerCommand(command)\n}\n\nexport type AgentComputerLaunchOutcome = \"pending\" | \"succeeded\" | \"failed\" | \"unknown\"\n\n// computer launch 自己成功时唯一打印的这行文本(见 appmirrord/cmd/computer/\n// launch.go 的 cmdLaunch),不会被任何其它 computer 子命令打印。判定\"launch\n// 是不是真的成功了\"首选看这个标记有没有出现在输出里,而不是看整条 Bash\n// 命令的最终退出码——同一次 Bash 调用可能是 `computer launch ... && computer\n// screenshot` 这种复合命令,launch 自己成功、后面的 screenshot 失败时,整条\n// 命令的退出码是非零,但 launch 明明是成功的。这个标记不受复合命令后半段成\n// 不成功的影响,直接对应 launch 自己有没有跑到成功打印那一步。\n//\n// 与 apps/web/src/agent/lib/agent-computer-command.ts 保持同名同签名——两边\n// 内容目前完全一致,改一处记得同步另一处。\nconst LAUNCH_SUCCESS_MARKER = \"已启动 \"\n\nfunction resultContainsLaunchSuccessMarker(result: unknown, depth = 0): boolean {\n if (depth > 2) return false // 防止极端嵌套结构把这段扫描拖成性能问题,正常数据不会嵌这么深\n if (typeof result === \"string\") {\n if (result.includes(LAUNCH_SUCCESS_MARKER)) return true\n try {\n return resultContainsLaunchSuccessMarker(JSON.parse(result), depth + 1)\n } catch {\n return false\n }\n }\n if (typeof result === \"object\" && result !== null) {\n for (const value of Object.values(result as Record<string, unknown>)) {\n if (typeof value === \"string\" && value.includes(LAUNCH_SUCCESS_MARKER)) return true\n }\n }\n return false\n}\n\n/** `computer launch` 这条 Bash 工具调用最终是不是真的启动成功了——不能只看\n * `isAgentComputerToolCall` 命中参数就当作成功:可执行文件缺失/不可执行、\n * 启动后随即退出这些 appmirrord 侧的失败,Bash 工具调用本身仍然会走完\n * `status: \"done\"`(Bash 工具的职责是\"跑完这条命令\",命令自己返回非零退出码\n * 不算工具调用失败)。\n *\n * 唯一的判据是输出里有没有出现 `LAUNCH_SUCCESS_MARKER`——launch.go 的\n * cmdLaunch 只要走到成功分支就一定会打印这行文本,不存在\"成功了但没打印\"\n * 的路径。标记缺失就等价于没有走到那条成功路径,不再退回看 `result.exit_code`\n * 当兜底:那样会给 `computer launch ... || echo failed` 这类复合命令开口子,\n * 让真实失败的 launch 被误判成 succeeded。\n *\n * \"pending\":还没跑完(status 既不是终态失败也不是 done),调用方不该现在\n * 就下结论,也不该把这次调用标记成\"已处理\"——等下一次状态更新再重新判断。\n *\n * \"unknown\":`status: \"done\"` 但 `result` 本身缺失(不是\"有 result、没有标记\",\n * 是根本没有 result 这个字段)——历史会话被整理(compaction)之后,归档的\n * 工具调用只保留 `arguments`/`status` 这类摘要字段,完整 `result` payload 不\n * 会重新序列化进历史投影,这是已知且刻意的压缩形状,不是数据丢失异常。这种\n * 情况下\"没看到成功标记\"不能说明\"这次 launch 失败了\",只能说明\"证据被裁剪\n * 了\"——跟\"result 确实回来了、里面就是没有这行文本\"是两种不同性质的证据,\n * 前者不能定性为 failed,接入方要按自己的场景(标签页展示可以偏宽松,自动\n * 跳转/替用户做决定的场景应该偏保守)自己决定怎么用。\n *\n * 与 apps/web/src/agent/lib/agent-computer-command.ts 保持同名同签名——两边\n * 内容目前完全一致,改一处记得同步另一处。 */\nexport function classifyAgentComputerLaunchOutcome(toolCall: {\n status?: string\n result?: unknown\n}): AgentComputerLaunchOutcome {\n if (toolCall.status === \"error\" || toolCall.status === \"cancelled\") return \"failed\"\n if (toolCall.status !== \"done\") return \"pending\"\n if (toolCall.result === undefined || toolCall.result === null) return \"unknown\"\n return resultContainsLaunchSuccessMarker(toolCall.result) ? \"succeeded\" : \"failed\"\n}\n","import type { BladeClient } from \"@blade-hq/agent-client\"\nimport * as Tooltip from \"@radix-ui/react-tooltip\"\nimport { useMemo, useState } from \"react\"\nimport { cn } from \"../lib/utils\"\n\ntype CheckpointTree = Awaited<ReturnType<BladeClient[\"sessions\"][\"getSessionCheckpoints\"]>>\ntype CheckpointNode = CheckpointTree[\"nodes\"][number]\n\nexport interface SessionBranchPickerProps {\n tree: CheckpointTree\n /** Disable changes while this session is running or read-only. */\n disabled?: boolean\n /** Restore only the conversation; the host owns history refresh and composer drafts. */\n onCheckout: (checkpointId: string, position: \"before\" | \"turn_end\") => Promise<void>\n}\n\nconst ROW_HEIGHT = 32\nconst SVG_WIDTH = 44\n\ninterface LayoutNode {\n id: string\n column: number\n row: number\n parentRow: number | null\n parentColumn: number | null\n isActive: boolean\n isCurrent: boolean\n isVirtual: boolean\n preview: string\n content: string\n}\n\ninterface LayoutGraph {\n nodes: LayoutNode[]\n hasCycle: boolean\n maxColumn: number\n maxRow: number\n}\n\nexport function SessionBranchPicker({\n tree,\n disabled = false,\n onCheckout,\n}: SessionBranchPickerProps) {\n const [checkoutError, setCheckoutError] = useState<string | null>(null)\n const [pendingNodeId, setPendingNodeId] = useState<string | null>(null)\n const hasHistory = tree.nodes.length > 0\n const layout = useMemo(() => buildLayoutNodes(tree), [tree])\n const nodeMap = useMemo(() => new Map(tree.nodes.map((node) => [node.id, node])), [tree])\n const isBusy = disabled || pendingNodeId !== null\n const graphHeight = Math.max((layout.maxRow + 1) * ROW_HEIGHT, ROW_HEIGHT)\n const graphWidth = Math.max(SVG_WIDTH, getColumnX(layout.maxColumn) + 12)\n\n async function checkoutNode(node: CheckpointNode, position: \"before\" | \"turn_end\") {\n if (isBusy) return\n setCheckoutError(null)\n setPendingNodeId(node.id)\n try {\n await onCheckout(node.id, position)\n } catch (error) {\n setCheckoutError(error instanceof Error ? error.message : \"切换失败,请稍后重试\")\n } finally {\n setPendingNodeId(null)\n }\n }\n\n async function handleVirtualClick(node: LayoutNode) {\n if (isBusy || !node.isVirtual || node.isActive) return\n const sourceNode = nodeMap.get(node.content)\n if (sourceNode) await checkoutNode(sourceNode, \"turn_end\")\n }\n\n async function handleNodeSelect(node: LayoutNode) {\n if (isBusy) return\n const sourceNode = nodeMap.get(node.id)\n if (sourceNode) await checkoutNode(sourceNode, \"before\")\n }\n\n if (!hasHistory) return null\n\n return (\n <Tooltip.Provider delayDuration={200}>\n {checkoutError ? (\n <p role=\"alert\" className=\"mb-2 text-xs text-destructive\">\n {checkoutError}\n </p>\n ) : null}\n <div className=\"flex max-h-52 justify-center overflow-x-auto overflow-y-auto\">\n <div className=\"relative\" style={{ height: graphHeight, width: graphWidth }}>\n <svg\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute left-0 top-0 z-10 overflow-visible\"\n width={graphWidth}\n height={graphHeight}\n viewBox={`0 0 ${graphWidth} ${graphHeight}`}\n fill=\"none\"\n >\n {layout.nodes.map((node) => {\n if (node.parentRow == null || node.parentColumn == null) {\n return null\n }\n\n const childStroke = node.isActive\n ? \"hsl(var(--primary))\"\n : \"hsl(var(--muted-foreground))\"\n\n return (\n <path\n key={`path-${node.id}`}\n d={buildEdgePath(\n getColumnX(node.parentColumn),\n getRowY(node.parentRow),\n getColumnX(node.column),\n getRowY(node.row),\n )}\n stroke={childStroke}\n strokeOpacity={node.isActive ? 0.95 : 0.45}\n strokeWidth={node.isActive ? 1.8 : 1.4}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeDasharray={node.isVirtual ? \"3 3\" : undefined}\n />\n )\n })}\n </svg>\n\n <div className=\"relative z-0 h-full\">\n {layout.nodes.map((node) => {\n const isPendingNode = pendingNodeId === node.id\n const color = node.isActive ? \"hsl(var(--primary))\" : \"hsl(var(--muted-foreground))\"\n const previewText = node.isVirtual\n ? isPendingNode\n ? \"切换中...\"\n : \"\"\n : isPendingNode\n ? \"切换中...\"\n : node.preview\n const shouldShowTooltip = !node.isVirtual || Boolean(previewText)\n const button = (\n <button\n type=\"button\"\n onClick={() =>\n void (node.isVirtual ? handleVirtualClick(node) : handleNodeSelect(node))\n }\n disabled={isBusy}\n aria-current={!node.isVirtual && node.isCurrent ? \"step\" : undefined}\n aria-label={node.isVirtual ? \"切换到该分支\" : node.preview}\n className={cn(\n \"absolute z-20 m-0 h-8 w-6 overflow-visible border-0 bg-transparent p-0\",\n isBusy ? \"cursor-not-allowed opacity-60\" : \"cursor-pointer\",\n )}\n style={{\n top: node.row * ROW_HEIGHT,\n left: getColumnX(node.column) - 12,\n }}\n >\n <span aria-hidden=\"true\" className=\"absolute left-0 top-0 h-8 w-6\">\n <svg\n aria-hidden=\"true\"\n role=\"img\"\n className=\"pointer-events-none absolute left-0 top-0 h-full w-full overflow-visible\"\n width={24}\n height={ROW_HEIGHT}\n viewBox={`0 0 24 ${ROW_HEIGHT}`}\n fill=\"none\"\n >\n {node.isVirtual ? (\n <circle\n cx={12}\n cy={ROW_HEIGHT / 2}\n r={3.5}\n fill=\"none\"\n stroke={color}\n strokeWidth={1.2}\n strokeDasharray=\"2 2\"\n opacity={0.7}\n />\n ) : (\n <g>\n {node.isCurrent ? (\n <circle cx={12} cy={ROW_HEIGHT / 2} r={9} fill={color} opacity={0.18} />\n ) : null}\n <circle\n cx={12}\n cy={ROW_HEIGHT / 2}\n r={node.isCurrent ? 5.5 : 4}\n fill={color}\n />\n </g>\n )}\n </svg>\n </span>\n </button>\n )\n\n if (!shouldShowTooltip) {\n return <div key={node.id}>{button}</div>\n }\n\n return (\n <Tooltip.Root key={node.id}>\n <Tooltip.Trigger asChild>{button}</Tooltip.Trigger>\n <Tooltip.Portal>\n <Tooltip.Content\n side=\"right\"\n sideOffset={8}\n className={cn(\n // z-[60]:这张图会被放进回溯弹层(z-50 且背景不透明),\n // 消息预览不抬到弹层之上就会被它的背景吃掉。\n \"z-[60] rounded-md border border-border bg-popover px-2 py-1 text-xs text-foreground shadow-md\",\n !node.isVirtual && node.isCurrent && \"font-semibold\",\n )}\n >\n {previewText}\n </Tooltip.Content>\n </Tooltip.Portal>\n </Tooltip.Root>\n )\n })}\n </div>\n </div>\n </div>\n </Tooltip.Provider>\n )\n}\nfunction buildLayoutNodes(tree: CheckpointTree | undefined): LayoutGraph {\n if (!tree || tree.nodes.length === 0) {\n return { nodes: [], hasCycle: false, maxColumn: 0, maxRow: 0 }\n }\n\n const nodeMap = new Map(tree.nodes.map((node) => [node.id, node]))\n const order = new Map(tree.nodes.map((node, index) => [node.id, index]))\n const childrenMap = new Map<string | null, CheckpointNode[]>()\n\n for (const node of tree.nodes) {\n const parentId = node.parent_id && nodeMap.has(node.parent_id) ? node.parent_id : null\n const siblings = childrenMap.get(parentId) ?? []\n siblings.push(node)\n childrenMap.set(parentId, siblings)\n }\n\n const activeIds = new Set<string>()\n const activeVisited = new Set<string>()\n const leafId = tree.leaf_id\n let current = tree.leaf_id\n\n while (current && nodeMap.has(current) && !activeVisited.has(current)) {\n activeIds.add(current)\n activeVisited.add(current)\n current = nodeMap.get(current)?.parent_id ?? null\n }\n\n const layoutNodes: LayoutNode[] = []\n const placed = new Set<string>()\n const visiting = new Set<string>()\n let nextColumn = 1\n let maxColumn = 0\n let maxRow = 0\n let hasCycle = false\n\n const rootSort = (a: CheckpointNode, b: CheckpointNode) =>\n (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)\n\n const childSort = (a: CheckpointNode, b: CheckpointNode) =>\n (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)\n\n const allocateColumn = () => {\n const fresh = nextColumn\n nextColumn += 1\n return fresh\n }\n\n function walk(node: CheckpointNode, parent: LayoutNode | null, column: number, row: number) {\n if (visiting.has(node.id)) {\n hasCycle = true\n return\n }\n\n if (placed.has(node.id)) {\n return\n }\n\n visiting.add(node.id)\n maxColumn = Math.max(maxColumn, column)\n maxRow = Math.max(maxRow, row)\n\n const layoutNode: LayoutNode = {\n id: node.id,\n column,\n row,\n parentRow: parent?.row ?? null,\n parentColumn: parent?.column ?? null,\n isActive: activeIds.has(node.id),\n isCurrent: node.id === leafId,\n isVirtual: false,\n preview: formatPreview(node.content_preview),\n content: node.content,\n }\n\n layoutNodes.push(layoutNode)\n placed.add(node.id)\n\n const children = [...(childrenMap.get(node.id) ?? [])].sort(childSort)\n\n if (children.length === 0) {\n const virtualRow = row + 1\n maxRow = Math.max(maxRow, virtualRow)\n layoutNodes.push({\n id: `__virtual__${node.id}`,\n column,\n row: virtualRow,\n parentRow: layoutNode.row,\n parentColumn: layoutNode.column,\n isActive: activeIds.has(node.id),\n isCurrent: false,\n isVirtual: true,\n preview: \"\",\n content: node.id,\n })\n } else {\n for (const [index, child] of children.entries()) {\n if (visiting.has(child.id)) {\n hasCycle = true\n continue\n }\n\n const childColumn = index === 0 ? column : allocateColumn()\n walk(child, layoutNode, childColumn, row + 1)\n }\n }\n\n visiting.delete(node.id)\n }\n\n const roots = [...(childrenMap.get(null) ?? [])].sort(rootSort)\n for (const [index, root] of roots.entries()) {\n const rootColumn = index === 0 ? 0 : allocateColumn()\n walk(root, null, rootColumn, 0)\n }\n\n for (const node of [...tree.nodes].sort(rootSort)) {\n if (!placed.has(node.id)) {\n hasCycle = true\n const rootColumn = layoutNodes.length === 0 ? 0 : allocateColumn()\n walk(node, null, rootColumn, 0)\n }\n }\n\n return {\n nodes: layoutNodes,\n hasCycle,\n maxColumn,\n maxRow,\n }\n}\n\nfunction formatPreview(preview: string): string {\n const normalized = preview.replace(/\\s+/g, \" \").trim()\n return normalized.length > 0 ? normalized : \"(空消息)\"\n}\n\nfunction getColumnX(column: number): number {\n return 12 + column * 24\n}\n\nfunction getRowY(row: number): number {\n return row * ROW_HEIGHT + ROW_HEIGHT / 2\n}\n\nfunction buildEdgePath(fromX: number, fromY: number, toX: number, toY: number): string {\n if (fromX === toX || fromY === toY) {\n return `M ${fromX} ${fromY} L ${toX} ${toY}`\n }\n\n // Branch line: horizontal from parent to child column, then vertical down\n const r = Math.min(5, Math.abs(toX - fromX), Math.abs(toY - fromY))\n const dx = toX > fromX ? 1 : -1\n\n return [\n `M ${fromX} ${fromY}`,\n `H ${toX - dx * r}`,\n `A ${r} ${r} 0 0 ${dx > 0 ? 1 : 0} ${toX} ${fromY + r}`,\n `V ${toY}`,\n ].join(\" \")\n}\n"],"mappings":"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","names":["useRef","jsx","useRef","useState","jsx","jsxs","useState"]}
@@ -0,0 +1,25 @@
1
+ import type { BladeChatMountRenderers, MountRendererObject } from "@blade-hq/agent-client";
2
+ import type { ChatViewRenderers } from "../chat/customization";
3
+ /**
4
+ * 挂载节点放在哪里。
5
+ *
6
+ * `<blade-chat>` 把它设成元素本身:挂载节点作为元素的 light DOM 子节点,经 Shadow DOM
7
+ * 里的 `<slot>` 显示在区块位置,宿主页面的样式(包括 Vue 的 scoped 样式)直接生效。
8
+ * 没有设置时(npm 包里),挂载节点就是组件内的一个 div。
9
+ */
10
+ export declare const MountHostContext: import("react").Context<HTMLElement | null>;
11
+ interface MountSlotProps<T extends object> {
12
+ renderer: MountRendererObject<T>;
13
+ data: T;
14
+ }
15
+ /** 给宿主一个 DOM 节点挂自己的内容;数据变化时原地更新或清理后重挂,卸载时清理。 */
16
+ export declare function MountSlot<T extends object>({ renderer, data }: MountSlotProps<T>): import("react/jsx-runtime").JSX.Element;
17
+ /**
18
+ * 把挂载式渲染器转成普通 React 渲染器:两种写法走同一条渲染路径,`match` 返回
19
+ * false 等于 React 渲染器返回 null(走默认渲染)。调用方要按 `renderers` 对象缓存结果,
20
+ * 否则每次渲染都会得到新的渲染器、挂载内容被反复重建。
21
+ */
22
+ export declare function mountRenderersToReact(renderers: BladeChatMountRenderers | null | undefined, context?: {
23
+ sessionId?: string;
24
+ }): ChatViewRenderers | undefined;
25
+ export {};
@@ -0,0 +1,3 @@
1
+ type AnyFunction = (...args: never[]) => unknown;
2
+ export declare const useEffectEvent: <T extends AnyFunction>(callback: T) => T;
3
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare function BackgroundTasksPill({ sessionId }: {
2
+ sessionId: string;
3
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,59 @@
1
+ import { type ReactNode } from "react";
2
+ import type { ChatSendOptions, ComposerProps } from "../chat/customization";
3
+ import { type MessageContent } from "@blade-hq/agent-client/internal";
4
+ export type { ChatSendOptions };
5
+ export interface EnsureSessionResult {
6
+ sessionId: string;
7
+ pendingFilesHandled?: boolean;
8
+ }
9
+ export interface ChatInputProps extends ComposerProps {
10
+ /**
11
+ * Creates (or returns) a session to upload pending attachments into when
12
+ * the composer has files but no active session yet. The returned id is
13
+ * used for the upload, and is also passed back to `onSend` so the send
14
+ * path reaches exactly the session the files landed in — independent of
15
+ * whatever the current chat session is at that moment.
16
+ */
17
+ ensureSession?: (draftText: string, options?: Pick<ChatSendOptions, "model" | "thinkingOverride" | "reasoningLevel">) => Promise<string | EnsureSessionResult>;
18
+ /** Optional slot rendered directly above the textarea (below any file-pill bar). */
19
+ slotAboveTextarea?: ReactNode;
20
+ /** Optional business context rendered immediately before the send button. */
21
+ slotBeforeSend?: ReactNode;
22
+ /**
23
+ * Optional external draft channel. When provided, the composer initializes
24
+ * from `value` on mount and mirrors every internal `setInput` call into
25
+ * `setValue` (a persistence side-channel, the editor stays the source of truth).
26
+ */
27
+ externalDraft?: {
28
+ value: string;
29
+ setValue: (v: string) => void;
30
+ };
31
+ /** Optional external attachments channel. Same mirror semantics as externalDraft. */
32
+ externalAttachments?: {
33
+ value: FileComposerAttachment[];
34
+ setValue: (a: FileComposerAttachment[]) => void;
35
+ };
36
+ /** 首屏打字机效果:占位符挂载后逐字打出一遍,只在真正的"首页入口"用。 */
37
+ typewriterPlaceholder?: boolean;
38
+ }
39
+ export type FileComposerAttachment = {
40
+ id: string;
41
+ kind: "file";
42
+ name: string;
43
+ size: number;
44
+ mimeType: string;
45
+ status: "pending" | "uploading" | "uploaded" | "failed";
46
+ file?: File;
47
+ uploadedPath?: string;
48
+ textContent?: string | null;
49
+ uploadProgress?: number | null;
50
+ };
51
+ export type ComposerAttachment = FileComposerAttachment;
52
+ export declare function buildSubmitPayload(text: string, attachments: ComposerAttachment[], pendingContexts: {
53
+ label: string;
54
+ content: string;
55
+ imageUrl?: string;
56
+ }[], onBeforeSend?: (content: MessageContent) => MessageContent | Promise<MessageContent>): Promise<MessageContent>;
57
+ export declare function isSubmittedComposerStillCurrent(submittedSessionId: string | null, currentSessionId: string | null, submittedEditorJson: unknown, currentEditorJson: unknown, submittedAttachmentIds: string[], currentAttachmentIds: string[]): boolean;
58
+ export declare function mergeSubmittedAttachmentUpdates(current: ComposerAttachment[], updated: ComposerAttachment[], submittedAttachmentIds: string[]): ComposerAttachment[];
59
+ export declare function ChatInput({ sessionId: sessionIdProp, onSend, onStop, isStreaming, queueWhileRunning, isCompacting, isStopping, mode, onToggleMode, renderAttachments, onBeforeSend, ensureSession, onCommand, canShareSession, slotAboveTextarea, slotBeforeSend, planPanel, externalDraft, externalAttachments, maxWidthClassName, mergesWithPanelAbove, className, innerClassName, SkillStatusBarComponent: SkillStatusBarOverride, skillStatusBarClassName, skillStatusBarInnerClassName, onResyncSkills, isResyncingSkills, onOpenSkills, inputLabel, placeholderText, typewriterPlaceholder, onDoubleEscape, composerHint, statusBarAddon, slotBelowActions, initialDraft, initialDraftKey, lite, canCreateBoardTask, }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import type { ComponentProps } from "react";
2
+ /** Keep large attachment sets scrollable without pushing the editor off screen. */
3
+ export declare function ComposerAttachmentViewport({ className, ...props }: ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { type PluginConnectorSelection } from "../components/connector-panel-types";
2
+ /**
3
+ * 输入框工具条的「连接器」入口。
4
+ *
5
+ * 一处入口、一个面板:电脑 / 插件 / 外部账号分区,底部是添加与管理。插件列表与
6
+ * 启用判定来自 `@blade-hq/agent-react` 的共享组件,内置 Web 不各写一份。
7
+ *
8
+ * 需要宿主能力的动作(打开设置、跳市场与技能页)一律走回调。
9
+ *
10
+ * 手机端不再隐藏:窄屏下面板宽度受视口约束,入口本身照常可用。
11
+ */
12
+ export declare function ConnectButton({ sessionId, open, onOpenChange, pendingPlugins, onPendingPluginsChange, pendingPluginsDisabledReason, pendingComputers, onPendingComputersChange, onPluginsChanged, }: {
13
+ sessionId: string | null;
14
+ open?: boolean;
15
+ onOpenChange?: (open: boolean) => void;
16
+ /** 首页待选插件:只记下本次输入的待选,不激活任何东西。 */
17
+ pendingPlugins?: PluginConnectorSelection[];
18
+ onPendingPluginsChange?: (next: PluginConnectorSelection[]) => void;
19
+ pendingPluginsDisabledReason?: string | null;
20
+ /** 首页待选电脑:待会话创建后再通过会话接口提交。 */
21
+ pendingComputers?: string[];
22
+ onPendingComputersChange?: (ids: string[]) => void;
23
+ onPluginsChanged?: () => void;
24
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,44 @@
1
+ import type { SuggestionProps } from "@tiptap/suggestion";
2
+ import type { BladeClient, FileEntry } from "@blade-hq/agent-client";
3
+ import { type UserHomeRuntime } from "./lib/user-home";
4
+ import type { FileSuggestionItem } from "./extensions/file-mention";
5
+ import { type KbSuggestionItem } from "./extensions/kb-mention";
6
+ /**
7
+ * `session` 浏览当前会话的工作空间(相对路径,需要会话);`userHome` 浏览用户
8
+ * 云电脑的 HOME(`/root/...` 绝对路径),首页还没有会话时用这一种。两种模式
9
+ * 的条目由调用方拉好后传进来,这里只负责过滤和渲染。
10
+ */
11
+ export type FileBrowseScope = "session" | "userHome";
12
+ /** `@` 菜单选中的条目:文件(插 fileMention)或知识库(插 kbMention)。 */
13
+ export type MentionSuggestionItem = FileSuggestionItem | KbSuggestionItem;
14
+ /**
15
+ * `items` 里可以混着知识库候选(`kind: "kb"`)和文件条目:知识库来自 blade_hub
16
+ * `/api/kb`,文件来自会话工作区或云电脑 HOME。菜单把两者拆成「知识库 / 文件」
17
+ * 两组渲染,键盘上下键跨组连续移动。
18
+ */
19
+ export interface FileCompletionMenuProps extends Omit<SuggestionProps<FileSuggestionItem, FileSuggestionItem>, "command" | "items"> {
20
+ items: Array<FileEntry | KbSuggestionItem>;
21
+ command: (props: MentionSuggestionItem) => void;
22
+ onExit?: () => void;
23
+ sessionId?: string | null;
24
+ scope?: FileBrowseScope;
25
+ }
26
+ export interface FileCompletionMenuRef {
27
+ onKeyDown: (event: KeyboardEvent) => boolean;
28
+ }
29
+ /** Close the body-mounted suggestion menu when the user taps outside it. */
30
+ export declare function installSuggestionOutsideDismiss(container: HTMLElement, onDismiss: () => void): () => void;
31
+ interface ParsedQuery {
32
+ dirPath: string;
33
+ filterQuery: string;
34
+ }
35
+ export declare function getFileSuggestionItems(client: BladeClient, sessionId: string | null, query: string): Promise<FileEntry[]>;
36
+ /**
37
+ * 云电脑 HOME 模式下的 query 解析。和会话模式不同,这里的路径始终是绝对
38
+ * 路径:选中目录后编辑器插入的是 `@/root/文档/`,下一次补全就从这个绝对
39
+ * 路径继续往下走。不在 HOME 之下的输入一律当成在 HOME 根目录里按名字过滤。
40
+ */
41
+ export declare function parseUserHomeQuery(query: string, { homePath, separator }: UserHomeRuntime): ParsedQuery;
42
+ export declare function getUserHomeSuggestionItems(client: BladeClient, query: string): Promise<FileEntry[]>;
43
+ export declare const FileCompletionMenu: import("react").ForwardRefExoticComponent<FileCompletionMenuProps & import("react").RefAttributes<FileCompletionMenuRef>>;
44
+ export {};
@@ -0,0 +1,9 @@
1
+ import { type OversizedFileInfo } from "./lib/attachment-upload";
2
+ interface Props {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ files: OversizedFileInfo[];
6
+ limitBytes?: number;
7
+ }
8
+ export declare function FileSizeLimitDialog({ open, onOpenChange, files, limitBytes, }: Props): import("react/jsx-runtime").JSX.Element | null;
9
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { InputModelOption as ModelOption } from "../chat/runtime/input-services";
2
+ export type ModelSelectorProps = {
3
+ value: string;
4
+ onValueChange: (model: string) => void;
5
+ disabled?: boolean;
6
+ compact?: boolean;
7
+ placement?: "top" | "bottom";
8
+ };
9
+ export declare function getInputModalities(model: ModelOption): string[];
10
+ export declare function ModelSelector({ value, onValueChange, disabled, compact, placement, }: ModelSelectorProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ interface PlanningToggleProps {
2
+ enabled: boolean;
3
+ onChange: (enabled: boolean) => void;
4
+ disabled?: boolean;
5
+ }
6
+ export declare function PlanningToggle({ enabled, onChange, disabled }: PlanningToggleProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from "react";
2
+ import type { TokenPressureLevel } from "./lib/token-pressure";
3
+ interface ProgressCircleProps {
4
+ percentage: number;
5
+ level: TokenPressureLevel;
6
+ size?: number;
7
+ strokeWidth?: number;
8
+ detail?: ReactNode;
9
+ className?: string;
10
+ }
11
+ export declare function ProgressCircle({ percentage, level, size, strokeWidth, detail, className, }: ProgressCircleProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,9 @@
1
+ interface ReasoningModeSelectProps {
2
+ level: string;
3
+ levels: string[];
4
+ disabled?: boolean;
5
+ disabledReason?: string;
6
+ onChange: (level: string) => void;
7
+ }
8
+ export declare function ReasoningModeSelect({ level, levels, disabled, disabledReason, onChange, }: ReasoningModeSelectProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { SkillSuggestionItem } from "./extensions/skill-mention";
2
+ export interface SkillCompletionMenuProps {
3
+ items: SkillSuggestionItem[];
4
+ command: (item: SkillSuggestionItem) => void;
5
+ }
6
+ export interface SkillCompletionMenuRef {
7
+ onKeyDown: (event: KeyboardEvent) => boolean;
8
+ }
9
+ export declare const SkillCompletionMenu: import("react").ForwardRefExoticComponent<SkillCompletionMenuProps & import("react").RefAttributes<SkillCompletionMenuRef>>;
@@ -0,0 +1,15 @@
1
+ export declare function SkillStatusBar({ sessionId, onResync, isResyncing, vertical, className, innerClassName, onOpenSkills, }: {
2
+ sessionId: string;
3
+ onResync?: () => void;
4
+ isResyncing?: boolean;
5
+ vertical?: boolean;
6
+ className?: string;
7
+ innerClassName?: string;
8
+ /**
9
+ * 打开技能页。「已安装 N 个技能」是一条可点的导航,不是状态。
10
+ *
11
+ * 只有「已安装」可点:「已加载 N 个技能」是本次会话实际生效的技能,它的
12
+ * 详情与同步是另一件事,两者不能因为长得像就合成同一个动作。
13
+ */
14
+ onOpenSkills?: () => void;
15
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { PluginKey } from "@tiptap/pm/state";
2
+ export interface FileMentionAttrs {
3
+ path: string;
4
+ name: string;
5
+ }
6
+ export interface FileSuggestionItem {
7
+ path: string;
8
+ name: string;
9
+ is_dir: boolean;
10
+ }
11
+ export declare const fileMentionSuggestionKey: PluginKey<any>;
12
+ export declare const FileMention: import("@tiptap/core").Node<import("@tiptap/extension-mention").MentionOptions<any, import("@tiptap/extension-mention").MentionNodeAttrs>, any>;
@@ -0,0 +1,18 @@
1
+ export interface KbMentionAttrs {
2
+ kbId: number;
3
+ name: string;
4
+ }
5
+ /** `@` 补全菜单里的知识库候选;和文件条目共用一个菜单,用 `kind` 区分。 */
6
+ export interface KbSuggestionItem {
7
+ kind: "kb";
8
+ kbId: number;
9
+ name: string;
10
+ description: string;
11
+ }
12
+ export declare function isKbSuggestionItem(value: unknown): value is KbSuggestionItem;
13
+ /**
14
+ * 输入框里的「@知识库」药丸。触发字符 `@` 由 FileMention 的补全菜单负责
15
+ * (知识库和文件是同一个菜单的两个分组),所以这里不再挂自己的 suggestion
16
+ * 插件——挂了会和文件补全抢同一个 `@`。
17
+ */
18
+ export declare const KbMention: import("@tiptap/core").Node<import("@tiptap/extension-mention").MentionOptions<any, import("@tiptap/extension-mention").MentionNodeAttrs>, any>;
@@ -0,0 +1,48 @@
1
+ import { PluginKey } from "@tiptap/pm/state";
2
+ export interface SkillMentionAttrs {
3
+ skillId: string;
4
+ displayName: string;
5
+ description: string;
6
+ /** 本地已有 = 直接可用;Hub 技能还要先加载,未安装的还要先装。 */
7
+ local: boolean;
8
+ installed: boolean;
9
+ }
10
+ export interface SkillOnlySuggestionItem {
11
+ skillId: string;
12
+ displayName?: string;
13
+ description: string;
14
+ local?: boolean;
15
+ installed?: boolean;
16
+ }
17
+ export interface SkillCommandSuggestionItem {
18
+ type: "command";
19
+ id: string;
20
+ label: string;
21
+ description: string;
22
+ }
23
+ export interface SkillSuggestionSkillItem extends SkillOnlySuggestionItem {
24
+ type: "skill";
25
+ }
26
+ export interface WorkflowInputSummary {
27
+ name: string;
28
+ description?: string | null;
29
+ required?: boolean;
30
+ /** flow.json 里原样的 JSON 默认值:0 / false / "" 都是合法默认值,不止字符串 */
31
+ default?: unknown;
32
+ }
33
+ /** 已安装的工作流:选中后往输入框填「运行工作流 X」,由主智能体调 workflow:run 前台执行。 */
34
+ export interface SkillWorkflowSuggestionItem {
35
+ type: "workflow";
36
+ name: string;
37
+ displayName: string;
38
+ description: string;
39
+ /** 声明的输入参数:插入文本带上「参数名=」模板,用户补值、模型照传 inputs。 */
40
+ inputs?: WorkflowInputSummary[];
41
+ }
42
+ export type SkillSuggestionItem = SkillSuggestionSkillItem | SkillCommandSuggestionItem | SkillWorkflowSuggestionItem;
43
+ /** 工作流胶囊后跟的参数模板文本:用户把「=」后补上值,模型按 key=value 填 inputs。 */
44
+ export declare function workflowParamsTail(item: SkillWorkflowSuggestionItem): string;
45
+ export declare function workflowRunText(item: SkillWorkflowSuggestionItem): string;
46
+ export declare const COMMANDS: SkillCommandSuggestionItem[];
47
+ export declare const skillMentionSuggestionKey: PluginKey<any>;
48
+ export declare const SkillMention: import("@tiptap/core").Node<import("@tiptap/extension-mention").MentionOptions<any, import("@tiptap/extension-mention").MentionNodeAttrs>, any>;
@@ -0,0 +1,10 @@
1
+ import { Node } from "@tiptap/react";
2
+ /**
3
+ * 工作流胶囊:/ 菜单选中工作流后插入的高亮 mention。
4
+ *
5
+ * 刻意不是 skillMention——那个节点序列化成 <skill>id</skill>,且行首会被判定为
6
+ * 「本条消息绑定哪个技能」(composer-content.ts 的 LeadingSkillMention),工作流
7
+ * 塞进去会被当成技能加载。本节点只负责显示胶囊,序列化回「运行工作流 X」纯文本,
8
+ * 模型侧行为与手打文本完全一致。参数模板作为胶囊后的普通文本,用户可直接编辑。
9
+ */
10
+ export declare const WorkflowMention: Node<any, any>;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 富输入子入口(`@blade-hq/agent-react/rich-input`):Tiptap 编辑器、@ 提及、`/` 菜单、
3
+ * 语音、模型选择等只给内置 Web 与浏览器插件用的输入能力都住在这个入口。
4
+ *
5
+ * 约束:这里的依赖闭包不得被主入口或 `<blade-chat>` 的 IIFE 入口静态引用——IIFE 会把
6
+ * 能到达的模块全部内联(动态 import 也一样),重依赖一旦被引到就会进 blade-agent.js。
7
+ * `scripts/check-embed-deps.mjs` 在 build:embed 时检查。
8
+ */
9
+ export * from "./BackgroundTasksPill";
10
+ export * from "./ChatInput";
11
+ export * from "./ConnectButton";
12
+ export * from "./ModelSelector";
13
+ export * from "./ProgressCircle";
14
+ export * from "./SkillStatusBar";
15
+ export * from "./ComposerAttachmentViewport";
16
+ export * from "./FileCompletionMenu";
17
+ export * from "./FileSizeLimitDialog";
18
+ export * from "./PlanningToggle";
19
+ export * from "./ReasoningModeSelect";
20
+ export * from "./SkillCompletionMenu";
21
+ export * from "./extensions/file-mention";
22
+ export * from "./extensions/kb-mention";
23
+ export * from "./extensions/skill-mention";
24
+ export * from "./extensions/workflow-mention";
25
+ export * from "./input-keyboard";
26
+ export * from "./lib/attachment-upload";
27
+ export * from "./lib/background-tasks-view";
28
+ export * from "./lib/client-query";
29
+ export * from "./lib/composer-content";
30
+ export * from "./lib/image-input-availability";
31
+ export * from "./lib/kb-suggestions";
32
+ export * from "./lib/reasoning-levels";
33
+ export * from "./lib/session-data";
34
+ export * from "./lib/skill-suggestions";
35
+ export * from "./lib/token-estimate";
36
+ export * from "./lib/token-pressure";
37
+ export * from "./lib/upload-results";
38
+ export * from "./lib/user-home";
39
+ export * from "./model/model-data";
40
+ export * from "./model/resolve-model";
41
+ export * from "./model/use-composer-model";
42
+ export * from "./services";
43
+ export * from "./use-dismiss-skill-suggestions-on-mode-change";
44
+ export * from "./use-input-history";
45
+ export * from "./voice/VoiceWaveform";
46
+ export * from "./voice/use-tiptap-voice-input";
47
+ export * from "./voice/use-voice-input";
48
+ export * from "./voice/voice-input-support";
@@ -0,0 +1,13 @@
1
+ export interface ChatInputKeyboardEvent {
2
+ key: string;
3
+ shiftKey: boolean;
4
+ isComposing: boolean;
5
+ keyCode?: number;
6
+ }
7
+ /**
8
+ * Browsers differ: some IME implementations expose only keyCode 229.
9
+ * Keep these predicates in sync with packages/agent-react/src/components/ChatInput.tsx.
10
+ */
11
+ export declare function isImeCompositionKey(event: ChatInputKeyboardEvent): boolean;
12
+ export declare function shouldSubmitChatInput(event: ChatInputKeyboardEvent, menuOpen: boolean): boolean;
13
+ export declare function shouldHandleHistoryKey(event: ChatInputKeyboardEvent, menuOpen: boolean): boolean;
@@ -0,0 +1,10 @@
1
+ export declare const ATTACHMENT_SIZE_LIMIT_BYTES: number;
2
+ export type OversizedFileInfo = {
3
+ name: string;
4
+ size: number;
5
+ };
6
+ export declare function formatFileSize(size: number): string;
7
+ export declare function splitFilesBySize(files: FileList | File[], limitBytes?: number): {
8
+ accepted: File[];
9
+ rejected: OversizedFileInfo[];
10
+ };
@@ -0,0 +1,31 @@
1
+ import type { BackgroundTask } from "@blade-hq/agent-client/internal";
2
+ /** 还没有结论的状态,永远留在主区。 */
3
+ export declare const LIVE_STATUSES: Set<string>;
4
+ /** 结束了但用户需要知道的状态,也留在主区,直到用户点「隐藏」。 */
5
+ export declare const ATTENTION_STATUSES: Set<string>;
6
+ /** 只有这两个状态还来得及停:cancelling 已经在停了。 */
7
+ export declare const STOPPABLE_STATUSES: Set<string>;
8
+ /**
9
+ * 后端 BgStatus 的全部取值,一个都不能漏——漏掉的会原样露出英文。
10
+ * Record 而不是 if 链:加了新状态但忘了文案时,这里会直接编译失败。
11
+ */
12
+ export declare const STATUS_LABELS: Record<BackgroundTask["status"], string>;
13
+ export declare function statusLabel(status: string): string;
14
+ export declare function statusClass(status: string): "border-[hsl(var(--border))] bg-[hsl(var(--muted))]/40 text-[hsl(var(--muted-foreground))]" | "border-[hsl(var(--swf-border-strong))] bg-[hsl(var(--muted))] text-[hsl(var(--secondary-foreground))]" | "border-[hsl(var(--swf-danger)/0.35)] bg-[hsl(var(--swf-danger-soft))] text-[hsl(var(--swf-danger))]" | "border-[hsl(var(--swf-warning)/0.35)] bg-[hsl(var(--swf-warning-soft))] text-[hsl(var(--swf-warning))]";
15
+ /**
16
+ * 主区只放需要用户现在关心的:还在跑的,加上结束了但出了问题的。
17
+ *
18
+ * 「隐藏」只是把它挪进历史,不让它凭空消失——刷新一下就全回来的清除没有意义。
19
+ */
20
+ export declare function splitTasks(tasks: readonly BackgroundTask[], dismissed: readonly string[]): {
21
+ activeTasks: BackgroundTask[];
22
+ historyTasks: BackgroundTask[];
23
+ runningCount: number;
24
+ attentionCount: number;
25
+ };
26
+ export declare function entryLabel(runningCount: number, attentionCount: number, historyCount: number): string;
27
+ /**
28
+ * 历史里跨天是常态,只给 HH:mm 分不出昨天还是今天,所以非当天补上日期。
29
+ * `now` 可注入,测试才不用跟着真实时钟走。
30
+ */
31
+ export declare function formatStartedAt(value: number | null | undefined, now?: Date): string;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 富输入默认实现用的小型请求缓存(按 BladeClient 隔离):同一个键在有效期内只请求一次,
3
+ * 并发请求合并成一个,多个组件共享结果。内置 Web 在需要和 React Query 缓存打通的地方
4
+ * 用自己的实现覆盖(见 `RichInputServices`),插件等其他宿主直接用这里。
5
+ */
6
+ import type { BladeClient } from "@blade-hq/agent-client";
7
+ export interface ClientQueryState<T> {
8
+ data: T | undefined;
9
+ error: unknown;
10
+ /** 还没有任何结果(首次加载中)。 */
11
+ isLoading: boolean;
12
+ /** 正在请求(含已有结果时的刷新)。 */
13
+ isFetching: boolean;
14
+ }
15
+ /** 请求(有效期内且已有结果时直接复用);失败不留结果,下次重试。 */
16
+ export declare function fetchClientQuery<T>(client: BladeClient, key: string, load: (client: BladeClient) => Promise<T>, { staleMs, force }?: {
17
+ staleMs?: number;
18
+ force?: boolean;
19
+ }): Promise<T>;
20
+ /** 直接改缓存里的值(乐观更新);还没有结果时不凭空造一份。 */
21
+ export declare function setClientQueryData<T>(client: BladeClient, key: string, updater: (current: T) => T): void;
22
+ /**
23
+ * 读一个键的缓存,挂载(或键变化、过期)时自动请求。`key` 为 null 时不请求。
24
+ * `load` 只在真正发请求时调用,不必是稳定引用。
25
+ */
26
+ export declare function useClientQuery<T>(key: string | null, load: (client: BladeClient) => Promise<T>, { staleMs }?: {
27
+ staleMs?: number;
28
+ }): ClientQueryState<T> & {
29
+ refetch: () => Promise<T | undefined>;
30
+ };
31
+ /** 让缓存过期并用登记的加载函数重新请求(有组件在用时)。 */
32
+ export declare function refreshClientQuery(client: BladeClient, key: string): void;