@blade-hq/agent-react 2610.0.1-alpha.1 → 2610.0.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 (76) hide show
  1. package/README.md +346 -8
  2. package/dist/chunk-G3PMV62Z.js +36 -0
  3. package/dist/components/AgentChat.d.ts +6 -0
  4. package/dist/components/AgentLoopBlock.d.ts +3 -5
  5. package/dist/components/AgentTaskCard.d.ts +12 -0
  6. package/dist/components/AskUserQuestionBlock.d.ts +12 -1
  7. package/dist/components/AssistantTurnBlock.d.ts +27 -9
  8. package/dist/components/BackgroundWakeNotice.d.ts +2 -0
  9. package/dist/components/ChatInput.d.ts +21 -1
  10. package/dist/components/ChatSurface.d.ts +143 -3
  11. package/dist/components/ChatView.d.ts +2 -1
  12. package/dist/components/ConnectionBanner.d.ts +1 -1
  13. package/dist/components/ConnectorPanel.d.ts +41 -0
  14. package/dist/components/ContextCard.d.ts +20 -0
  15. package/dist/components/MarkdownContent.d.ts +20 -6
  16. package/dist/components/McpAppCard.d.ts +14 -0
  17. package/dist/components/MessageImage.d.ts +9 -0
  18. package/dist/components/MessageList.d.ts +47 -6
  19. package/dist/components/PlanUpdateBlock.d.ts +32 -0
  20. package/dist/components/PluginConnectorList.d.ts +47 -0
  21. package/dist/components/PluginTriggerStack.d.ts +22 -0
  22. package/dist/components/PostChatFollowupBlock.d.ts +63 -0
  23. package/dist/components/SessionBranchPicker.d.ts +11 -0
  24. package/dist/components/SessionMemoryToggle.d.ts +19 -0
  25. package/dist/components/SessionPluginConfigDialog.d.ts +10 -0
  26. package/dist/components/SessionPluginConfigForm.d.ts +14 -0
  27. package/dist/components/SessionPluginIcon.d.ts +30 -0
  28. package/dist/components/SessionPluginSelector.d.ts +10 -0
  29. package/dist/components/SessionQueuePanel.d.ts +74 -0
  30. package/dist/components/ToolCallBlock.d.ts +10 -4
  31. package/dist/components/ToolUiCardView.d.ts +9 -0
  32. package/dist/components/TurnNavRail.d.ts +23 -0
  33. package/dist/components/UserMessageBubble.d.ts +7 -3
  34. package/dist/components/WhatIfUserBubble.d.ts +7 -0
  35. package/dist/components/connector-panel-types.d.ts +37 -0
  36. package/dist/components/display-utils.d.ts +0 -12
  37. package/dist/components/markdown/heal-incomplete.d.ts +7 -0
  38. package/dist/components/markdown/incremental.d.ts +73 -0
  39. package/dist/components/markdown/index.d.ts +18 -0
  40. package/dist/components/markdown/parse.d.ts +19 -0
  41. package/dist/components/markdown/render.d.ts +79 -0
  42. package/dist/components/markdown/sanitize.d.ts +50 -0
  43. package/dist/components/markdown/types.d.ts +53 -0
  44. package/dist/components/plugin-config-draft.d.ts +13 -0
  45. package/dist/components/plugin-config-schema.d.ts +6 -0
  46. package/dist/components/plugin-connector.d.ts +40 -0
  47. package/dist/components/queue-panel-adjacency.d.ts +1 -0
  48. package/dist/components/use-session-plugin-activation.d.ts +40 -0
  49. package/dist/context.d.ts +1 -0
  50. package/dist/embed/blade-chat-element.d.ts +4 -3
  51. package/dist/embed/entry.d.ts +54 -0
  52. package/dist/hooks/use-agent-session.d.ts +5 -0
  53. package/dist/hooks/use-message-pin.d.ts +28 -0
  54. package/dist/hooks/use-turn-navigation.d.ts +117 -0
  55. package/dist/hooks/use-typewriter-reveal.d.ts +32 -0
  56. package/dist/index.d.ts +57 -1
  57. package/dist/index.js +63199 -3019
  58. package/dist/index.js.map +1 -1
  59. package/dist/lib/agent-computer-command.d.ts +34 -0
  60. package/dist/lib/random-id.d.ts +10 -0
  61. package/dist/lib/utils.d.ts +17 -2
  62. package/dist/lib/whatif-prompt.d.ts +18 -0
  63. package/dist/style.css +509 -390
  64. package/dist/style.full.css +520 -394
  65. package/dist/webapi-W3IB5DO4.js +2481 -0
  66. package/dist/webapi-W3IB5DO4.js.map +1 -0
  67. package/package.json +5 -3
  68. package/public-api.md +2285 -92
  69. package/dist/chunk-ZXXLY4RM.js +0 -28255
  70. package/dist/chunk-ZXXLY4RM.js.map +0 -1
  71. package/dist/components/FileCard.d.ts +0 -16
  72. package/dist/highlighted-body-B3W2YXNL-YD7FAP6V.js +0 -27
  73. package/dist/highlighted-body-B3W2YXNL-YD7FAP6V.js.map +0 -1
  74. package/dist/lib/media-tags.d.ts +0 -24
  75. package/dist/mermaid-3ZIDBTTL-N7YKJ3SM.js +0 -8
  76. /package/dist/{mermaid-3ZIDBTTL-N7YKJ3SM.js.map → chunk-G3PMV62Z.js.map} +0 -0
@@ -6,13 +6,33 @@ interface Props {
6
6
  onStop: () => void;
7
7
  isStreaming: boolean;
8
8
  isStopping?: boolean;
9
+ /**
10
+ * 宿主是否渲染了队列面板。没有面板时不给"运行中提交"入口:消息进了队列却看不见,
11
+ * 比明确提示用户等一等更糟。ChatSurface 按 queuePanel 是否存在传入。
12
+ */
13
+ queueWhileRunning?: boolean;
14
+ /**
15
+ * 上方紧贴着一个比自己窄的面板(队列面板)时置 true:上两角改直角。
16
+ *
17
+ * 面板比输入框窄一圈,输入框上角留圆弧的话,那两段弧会从面板两侧露出来,
18
+ * 看着就是两个尖角。跟内置 Web 的 ChatInput 是同一个判据。
19
+ */
20
+ mergesWithPanelAbove?: boolean;
9
21
  placeholder?: string;
10
22
  className?: string;
23
+ /** 输入框卡片(`.blade-chat-input-inner`):边框、圆角、底色在这里。 */
24
+ innerClassName?: string;
25
+ /** 文本输入框(`.blade-chat-textarea`)。 */
26
+ textareaClassName?: string;
27
+ /** 右侧按钮组(`.blade-chat-input-toolbar`)。 */
28
+ toolbarClassName?: string;
29
+ queueKey?: string;
30
+ hasAttachments?: boolean;
11
31
  }
12
32
  /**
13
33
  * 轻量聊天输入框:textarea(Enter 发送 / Shift+Enter 换行)+ 发送/停止按钮。
14
34
  * 不含第一方版本的富文本编辑、@ 补全、技能菜单、语音输入与模型选择。
15
35
  * 内容受控,session.attach() / insertText() 通过 ChatView 注入到这里。
16
36
  */
17
- export declare function ChatInput({ value, onValueChange, onSend, onStop, isStreaming, isStopping, placeholder, className, }: Props): import("react/jsx-runtime").JSX.Element;
37
+ export declare function ChatInput({ value, onValueChange, onSend, onStop, isStreaming, isStopping, queueWhileRunning, mergesWithPanelAbove, placeholder, className, innerClassName, textareaClassName, toolbarClassName, queueKey, hasAttachments, }: Props): import("react/jsx-runtime").JSX.Element;
18
38
  export {};
@@ -1,15 +1,119 @@
1
- import type { AskUserAnswerData, ChatMessage, ConnectionStatus } from "@blade-hq/agent-client";
2
- import type { ReactNode } from "react";
1
+ import type { AskUserAnswerData, ChatMessage, ConnectionStatus, PostChatFollowup } from "@blade-hq/agent-client";
2
+ import { type ReactNode } from "react";
3
+ import type { TurnNavigationSource } from "../hooks/use-turn-navigation";
3
4
  import type { ToolCallRenderer } from "./ToolCallBlock";
5
+ import type { FollowupInteractionEvent } from "./PostChatFollowupBlock";
6
+ import type { ResultFeedback } from "@blade-hq/agent-client";
7
+ import { type PlanUpdateData } from "./PlanUpdateBlock";
8
+ import type { AskUserQuestionData } from "./AskUserQuestionBlock";
9
+ /**
10
+ * 每个可见区块的 className 落点,键名与元素上的 `blade-chat-*` 语义锚点一一对应。
11
+ *
12
+ * 传进来的类会与 SDK 自己的类一起经过 `cn`(clsx + tailwind-merge),放在
13
+ * 最后一个参数,因此 `classNames={{ chatInput: "p-0" }}` 能盖掉组件内部的 `p-4`,
14
+ * 不依赖 CSS 输出顺序、也不需要 `!important`。锚点本身不带视觉规则(清单见
15
+ * README「样式定制」与 src/style.css 顶部),用普通 CSS 选它们同样稳定生效。
16
+ */
4
17
  export interface ChatViewClassNames {
18
+ /** 聊天根容器(`.blade-chat`)。 */
5
19
  root?: string;
20
+ /** 连接状态提示条(`.blade-chat-banner`)。 */
6
21
  banner?: string;
22
+ /** 顶部出错条(`.blade-chat-error-bar`)。 */
23
+ errorBar?: string;
24
+ /** 消息区(`.blade-chat-messages`)。 */
7
25
  messageList?: string;
26
+ /** 消息区滚动内容(`.blade-chat-messages-scroll`):内边距在这里。 */
27
+ messagesScroll?: string;
28
+ /** 消息内容列(`.blade-chat-messages-content`):居中与最大宽度在这里。 */
29
+ messagesContent?: string;
30
+ /** 无消息时的空状态(`.blade-chat-empty`)。 */
31
+ empty?: string;
32
+ /** 「滚动到底部」按钮(`.blade-chat-scroll-bottom`)。 */
33
+ scrollToBottom?: string;
34
+ /** 用户消息行(`.blade-chat-user-row`)。 */
35
+ userMessage?: string;
36
+ /** 用户气泡(`.blade-chat-user-bubble`)。 */
37
+ userBubble?: string;
38
+ /** 消息里的文件附件卡(`.blade-chat-file-card`)。 */
39
+ fileCard?: string;
40
+ /** 消息流里的出错块(`.blade-chat-error-row`)。 */
41
+ errorMessage?: string;
42
+ /** 一轮助手回复(`.blade-chat-assistant-turn`)。 */
43
+ assistantTurn?: string;
44
+ /** 思考过程(`.blade-chat-thinking`)。 */
45
+ thinking?: string;
46
+ /** 助手正文(`.blade-chat-assistant-text`)。 */
47
+ assistantText?: string;
48
+ /** 记忆引用(`.blade-chat-memory-refs`)。 */
49
+ memoryRefs?: string;
50
+ /** 执行过程里的工具行(`.blade-chat-tool-row`):智能体模式下工具调用都走这条路径。 */
51
+ toolRow?: string;
52
+ /** 子智能体行(`.blade-chat-agent-loop`)。 */
53
+ agentLoop?: string;
54
+ /** 提问卡(`.blade-chat-ask-card`)。 */
55
+ askCard?: string;
56
+ /** 提问卡的每个选项(`.blade-chat-ask-option`)。 */
57
+ askOption?: string;
58
+ /** 计划面板(`.blade-chat-plan`)。 */
59
+ planPanel?: string;
60
+ /** 会话队列面板(`.blade-chat-queue`)。 */
61
+ queuePanel?: string;
62
+ /** 本轮小结与跟进区(`.blade-chat-followup`)。 */
63
+ followup?: string;
64
+ /** 跟进建议按钮(`.blade-chat-followup-action`)。 */
65
+ followupAction?: string;
66
+ /** 输入区外层(`.blade-chat-input`)。 */
8
67
  chatInput?: string;
68
+ /** 输入框卡片(`.blade-chat-input-inner`):边框、圆角、底色在这里。 */
69
+ inputInner?: string;
70
+ /** 文本输入框(`.blade-chat-textarea`)。 */
71
+ textarea?: string;
72
+ /** 输入框右侧按钮组(`.blade-chat-input-toolbar`)。 */
73
+ inputToolbar?: string;
74
+ }
75
+ /** 用户消息渲染器:`message` 是投影层给出的用户消息。 */
76
+ export interface UserMessageRendererProps {
77
+ message: ChatMessage;
9
78
  }
79
+ /** 助手正文渲染器:`compact` 为真时正文在执行过程里,字号更小。 */
80
+ export interface AssistantTextRendererProps {
81
+ message: ChatMessage;
82
+ streaming: boolean;
83
+ compact: boolean;
84
+ sessionId?: string;
85
+ }
86
+ /** 提问卡渲染器:字段与 `AskUserQuestionBlock` 的 props 一致。 */
87
+ export interface AskUserQuestionRendererProps {
88
+ data: AskUserQuestionData;
89
+ answered: boolean;
90
+ toolCallId: string;
91
+ sessionStatus: string;
92
+ answerData?: AskUserAnswerData;
93
+ onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void;
94
+ }
95
+ /** 计划面板渲染器:`plan` 是最近一次成功的 update_plan 解析结果。 */
96
+ export interface PlanUpdateRendererProps {
97
+ plan: PlanUpdateData;
98
+ running: boolean;
99
+ sessionId?: string;
100
+ }
101
+ /**
102
+ * 区块级渲染器:每个都返回 `ReactNode`,返回 `null` 走 SDK 默认渲染。
103
+ *
104
+ * 与 `toolCall` 的老签名一致:参数是一个描述该区块的对象,而不是裸数据。
105
+ */
10
106
  export interface ChatViewRenderers {
11
107
  /** 自定义工具调用渲染;返回 null 走默认渲染。 */
12
108
  toolCall?: ToolCallRenderer;
109
+ /** 自定义用户消息渲染;返回 null 走默认渲染。 */
110
+ userMessage?: (props: UserMessageRendererProps) => ReactNode | null;
111
+ /** 自定义助手正文渲染;返回 null 走默认渲染。 */
112
+ assistantText?: (props: AssistantTextRendererProps) => ReactNode | null;
113
+ /** 自定义提问卡渲染;返回 null 走默认渲染。 */
114
+ askUserQuestion?: (props: AskUserQuestionRendererProps) => ReactNode | null;
115
+ /** 自定义计划面板渲染;返回 null 走默认渲染。 */
116
+ planUpdate?: (props: PlanUpdateRendererProps) => ReactNode | null;
13
117
  }
14
118
  export interface ChatViewSlots {
15
119
  /** 消息列表上方的自定义区域。 */
@@ -31,23 +135,59 @@ export interface ChatPresentationProps {
31
135
  /** 主题落到聊天根节点上:深色变量挂在 [data-theme="dark"] 上,由它继承给整棵子树。 */
32
136
  export declare function themeAttr(theme: ChatPresentationProps["theme"]): "dark" | undefined;
33
137
  interface ChatSurfaceProps extends ChatPresentationProps {
138
+ /** follow-up、成果和评分交互;SDK 不绑定任何分析厂商。 */
139
+ onFollowupInteraction?: (event: FollowupInteractionEvent) => void;
34
140
  connection: ConnectionStatus;
35
141
  errorMessage: string | null;
36
142
  messages: ChatMessage[];
143
+ postChatFollowup?: PostChatFollowup | null;
37
144
  isStreaming: boolean;
38
145
  isStopping: boolean;
39
146
  inputText: string;
40
147
  onInputChange: (value: string) => void;
148
+ onSuggestion?: (value: string) => void;
41
149
  onSend: (text: string) => Promise<boolean>;
42
150
  onStop: () => void;
43
151
  sessionStatus?: string;
44
152
  askAnswers?: Record<string, AskUserAnswerData>;
45
153
  onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void;
46
154
  sessionId?: string;
155
+ isViewer?: boolean;
156
+ resultFeedbackByEntry?: ReadonlyMap<string, ResultFeedback>;
157
+ onResultFeedbackSaved?: (feedback: ResultFeedback) => void;
47
158
  /** 输入框上方的内部区域(纯 LLM 模式的高级设置用)。不传时不渲染任何节点。 */
48
159
  beforeInput?: ReactNode;
160
+ /** 输入框上方的会话队列面板(智能体模式用)。不传时不渲染任何节点。 */
161
+ queuePanel?: ReactNode;
162
+ /**
163
+ * 队列面板此刻是否真的占位(由面板的 `onVisibleChange` 上报)。
164
+ *
165
+ * 不能用 `queuePanel != null` 代替:面板有本地编辑态(编辑到一半、那条等待
166
+ * 消息被服务端拿走时仍留在原地保住草稿),这时它显示但 snapshot 里没有条目,
167
+ * 光看节点是否存在判不出来,输入框上两角就会在面板还开着的时候恢复成圆角。
168
+ */
169
+ queuePanelVisible?: boolean;
170
+ /** 仅 Agent 模式启用 Blade 的 update_plan 面板。 */
171
+ showPlanUpdates?: boolean;
172
+ /** 仅实时成功的 update_plan 递增;历史 hydration 不得改变。 */
173
+ planRevealRevision?: number;
174
+ historyPaging?: {
175
+ hasOlder: boolean;
176
+ loading: boolean;
177
+ /** Resolves true only when the paging cursor advanced. */
178
+ loadOlder: (beforeCommit?: () => void) => Promise<boolean>;
179
+ };
180
+ /** 消息导航的数据源(目录 + 定位);不传就没有导航轨道。 */
181
+ turnNavigation?: TurnNavigationSource;
49
182
  /** 连接状态条下方的横幅(回放模式条用)。不传时不渲染任何节点。 */
50
183
  banner?: ReactNode;
184
+ /**
185
+ * 打字机式显示节流是否还没追平目标全文——调用方需要跟 isStreaming 做
186
+ * `||` 判断输入框"运行中"状态。
187
+ */
188
+ onRevealingChange?: (revealing: boolean) => void;
189
+ /** 是否正在回放(演示 / 彩排)而非真正的实时直播——透传给 MessageList。 */
190
+ isReplay?: boolean;
51
191
  }
52
192
  /**
53
193
  * 消息流 + 输入框:智能体模式与纯 LLM 模式共用同一套外观,差别只在谁喂数据。
@@ -55,5 +195,5 @@ interface ChatSurfaceProps extends ChatPresentationProps {
55
195
  * 这里的 DOM 结构受 tests/chat-view-compat.test.tsx 的快照保护——接入方拿
56
196
  * .blade-chat-* 类名写了自己的样式,结构一动他们的页面就歪。
57
197
  */
58
- export declare function ChatSurface({ theme, classNames, renderers, slots, placeholder, connection, errorMessage, messages, isStreaming, isStopping, inputText, onInputChange, onSend, onStop, sessionStatus, askAnswers, onAnswer, sessionId, beforeInput, banner, }: ChatSurfaceProps): import("react/jsx-runtime").JSX.Element;
198
+ export declare function ChatSurface({ theme, classNames, renderers, slots, placeholder, connection, errorMessage, messages, postChatFollowup, isStreaming, isStopping, inputText, onInputChange, onSuggestion, onSend, onStop, sessionStatus, askAnswers, onAnswer, sessionId, isViewer, resultFeedbackByEntry, onResultFeedbackSaved, onFollowupInteraction, beforeInput, queuePanel, queuePanelVisible, showPlanUpdates, planRevealRevision, historyPaging, turnNavigation, banner, onRevealingChange, isReplay, }: ChatSurfaceProps): import("react/jsx-runtime").JSX.Element;
59
199
  export {};
@@ -2,7 +2,8 @@ import { type AgentChatProps } from "./AgentChat";
2
2
  import { type LlmChatHandle } from "./LlmChat";
3
3
  import type { LlmAdvancedSettings, LlmOverride } from "./LlmAdvancedSettings";
4
4
  import type { LlmChatOptions } from "../hooks/use-llm-chat";
5
- export type { ChatViewClassNames, ChatViewRenderers, ChatViewSlots, } from "./ChatSurface";
5
+ export type { AssistantTextRendererProps, AskUserQuestionRendererProps, ChatViewClassNames, ChatViewRenderers, ChatViewSlots, PlanUpdateRendererProps, UserMessageRendererProps, } from "./ChatSurface";
6
+ export type { FollowupInteractionEvent } from "./PostChatFollowupBlock";
6
7
  export interface ChatViewProps extends AgentChatProps {
7
8
  /** 挂哪个下层组件。默认 `agent`——不传就是接 Blade 智能体会话的原有行为。 */
8
9
  mode?: "agent" | "llm";
@@ -3,6 +3,6 @@ interface Props {
3
3
  connection: ConnectionStatus;
4
4
  className?: string;
5
5
  }
6
- /** 连接状态提示条:数据来自 SessionState.connection,正常连接时不渲染。 */
6
+ /** 连接状态提示条:短暂断线静默,超过容错时间后再逐级提示。 */
7
7
  export declare function ConnectionBanner({ connection, className }: Props): import("react/jsx-runtime").JSX.Element | null;
8
8
  export {};
@@ -0,0 +1,41 @@
1
+ import type { BladeClient, SessionPluginActivation } from "@blade-hq/agent-client";
2
+ import { type ReactNode } from "react";
3
+ import { type PluginConnectorItem } from "./plugin-connector";
4
+ import { type PluginConnectorSelection } from "./connector-panel-types";
5
+ export interface ConnectorPanelProps {
6
+ client: BladeClient;
7
+ /**
8
+ * `null` 表示首页:插件开关只记下本次输入的待选,不激活任何东西、不建会话、
9
+ * 不启动沙盒或 MCP。待选项随首条消息一起交给宿主处理。
10
+ */
11
+ sessionId: string | null;
12
+ /** 首页待选插件;`sessionId` 为 null 时使用。 */
13
+ pendingPlugins?: PluginConnectorSelection[];
14
+ onPendingPluginsChange?: (next: PluginConnectorSelection[]) => void;
15
+ /** 首页候选开关不可用时的说明(例如软件工厂模式会先建项目再启动)。 */
16
+ pendingDisabledReason?: string | null;
17
+ /** 会话内插件启用/停用结果;宿主据此刷新技能统计。 */
18
+ onPluginsChanged?: (plugin: SessionPluginActivation) => void;
19
+ /**
20
+ * 当前已选(首页待选 / 会话内已启用)的插件,按行原样报给宿主。
21
+ *
22
+ * 触发器要在不打开面板时就能显示「选了哪几个、几个」,它自己拿不到这份状态,
23
+ * 所以由面板单向汇报;面板未挂载时宿主保留上一次的结果。
24
+ */
25
+ onSelectedChange?: (items: PluginConnectorItem[]) => void;
26
+ /** 宿主注入:电脑分区。参数是搜索词,宿主自己决定怎么过滤。 */
27
+ renderComputerSection?: (query: string) => ReactNode;
28
+ /** 宿主注入:外部账号分区(飞书 / GitHub 等固定连接入口)。 */
29
+ renderExternalAccounts?: (query: string) => ReactNode;
30
+ /** 宿主注入:底部操作区;不注入就不渲染这一块。 */
31
+ renderFooterActions?: () => ReactNode;
32
+ className?: string;
33
+ }
34
+ /**
35
+ * 统一连接器面板:顶部搜索、按「电脑 / 插件 / 外部账号」分区、底部添加与管理。
36
+ *
37
+ * 插件分区是这一层唯一的共享实现:首页和会话用同一个列表、同一套启用判定,
38
+ * 判定不各写一份。电脑与外部账号由宿主注入——那些入口需要宿主的路由与 CLI
39
+ * 引导,SDK 不硬编码内部路径,也不替第三方决定跳到哪里。
40
+ */
41
+ export declare function ConnectorPanel({ client, sessionId, pendingPlugins, onPendingPluginsChange, pendingDisabledReason, onPluginsChanged, onSelectedChange, renderComputerSection, renderExternalAccounts, renderFooterActions, className, }: ConnectorPanelProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { type ContextProjectionData } from "@blade-hq/agent-client";
2
+ export interface ContextCardProps {
3
+ context: ContextProjectionData;
4
+ className?: string;
5
+ }
6
+ /** Business-facing Context summary. Native details keeps every card collapsed by default. */
7
+ export declare function ContextCard({ context, className }: ContextCardProps): import("react/jsx-runtime").JSX.Element;
8
+ export interface ContextGroupCardProps {
9
+ contexts: readonly ContextProjectionData[];
10
+ className?: string;
11
+ }
12
+ /**
13
+ * 一批上下文注入折叠成一行。会话首轮会一次注入十几个原子,一条一张卡片会把
14
+ * 真正的对话挤出屏幕。
15
+ *
16
+ * 单条和多条**共用同一个 details 外壳**,不在数量变化时切换组件:流式时第二条
17
+ * 到达会让这一行从单条变成多条,组件类型一换 React 就重挂 <details>,
18
+ * 用户刚展开的行会被收起来。同理,key 由调用方按组内第一条给,不能带数量。
19
+ */
20
+ export declare function ContextGroupCard({ contexts, className }: ContextGroupCardProps): import("react/jsx-runtime").JSX.Element | null;
@@ -1,16 +1,30 @@
1
+ import { type ComponentPropsWithRef } from "react";
2
+ /** 内置 Web(`apps/web/src/agent/components/markdown/MarkdownContent.tsx`)
3
+ * 有一份同名同签名的实现,两处共用同一套"跳过代码区间"的判定逻辑,改动
4
+ * 时要一起确认。这里作为 SDK 侧的规范实现导出,内置 Web 直接复用,不要
5
+ * 各写一份(对齐 CLAUDE.md"判定逻辑不许各写一份")。 */
6
+ export declare function stripSystemReminders(text: string): string;
7
+ /** Keep inline formatting markers from being consumed by URL autolinking. */
8
+ export declare function normalizeAdjacentUrlFormatting(value: string): string;
9
+ type AnchorProps = ComponentPropsWithRef<"a">;
10
+ /** 链接一律新窗口打开并断开 opener,SDK 不接管站内跳转。
11
+ * 页内锚点(脚注引用/回链这类 `href="#fn-note"`)不能套"新窗口打开"这套
12
+ * 逻辑——新开一个标签页访问 `#片段` 只是把整篇文档重新打开一次,不是
13
+ * 滚动到页内位置,会破坏脚注的跳转体验。只有真正的外部链接才需要新窗口
14
+ * + 断开 opener。导出给内置 Web 直接复用——两处原来各写了一份完全相同的
15
+ * 判定逻辑,对齐 CLAUDE.md"判定逻辑不允许两处各写一份"。 */
16
+ export declare function ExternalAnchor({ children, href, ...props }: AnchorProps): import("react/jsx-runtime").JSX.Element;
1
17
  export interface MarkdownContentProps {
2
18
  children: string;
3
19
  className?: string;
4
20
  /** 流式渲染传 "streaming",历史静态内容默认 "static"。 */
5
21
  mode?: "streaming" | "static";
6
- /**
7
- * 会话 id。传了才会把 `MEDIA:` 行折叠成文件下载卡片——下载要用它。
8
- * 不要给用户消息传:用户自己在输入框打一行 `MEDIA:` 不该被当成平台产物。
9
- */
22
+ /** 会话 id;保留给聊天组件统一透传上下文。 */
10
23
  sessionId?: string;
11
24
  }
12
25
  /**
13
- * SDK 版 Markdown 渲染:附带代码块复制按钮、智能体产出文件的下载卡片;
14
- * 相比第一方版本去掉了 mermaid、外链确认弹窗与文件预览。
26
+ * SDK 版 Markdown 渲染:附带代码块复制按钮;相比第一方版本去掉了
27
+ * mermaid、外链确认弹窗与文件预览。
15
28
  */
16
29
  export declare function MarkdownContent({ children, className, mode, sessionId }: MarkdownContentProps): import("react/jsx-runtime").JSX.Element;
30
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { BladeClient } from "@blade-hq/agent-client";
2
+ export interface McpAppMessage {
3
+ sessionId: string;
4
+ sourceId: string;
5
+ label: string;
6
+ content: string;
7
+ }
8
+ export declare const McpAppMessageContext: import("react").Context<((message: McpAppMessage) => void) | null>;
9
+ export declare function McpAppCard({ sessionId, sourceId, client: suppliedClient, onMessage: suppliedOnMessage }: {
10
+ sessionId: string;
11
+ sourceId: string;
12
+ client?: BladeClient;
13
+ onMessage?: (message: McpAppMessage) => void;
14
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import type { BladeClient } from "@blade-hq/agent-client";
2
+ import { type ImgHTMLAttributes } from "react";
3
+ export interface MessageImageProps extends ImgHTMLAttributes<HTMLImageElement> {
4
+ client?: BladeClient | null;
5
+ /** Load the original only when explicitly requested, such as a lightbox. */
6
+ original?: boolean;
7
+ }
8
+ /** Shared image transport for live messages, history, tool results and lightboxes. */
9
+ export declare const MessageImage: import("react").ForwardRefExoticComponent<MessageImageProps & import("react").RefAttributes<HTMLImageElement>>;
@@ -1,21 +1,62 @@
1
- import type { AskUserAnswerData, ChatMessage } from "@blade-hq/agent-client";
1
+ import type { AskUserAnswerData, ChatMessage, PostChatFollowup, ResultFeedback } from "@blade-hq/agent-client";
2
2
  import { type ReactNode } from "react";
3
- import type { ToolCallRenderer } from "./ToolCallBlock";
3
+ import { type TurnNavigationSource } from "../hooks/use-turn-navigation";
4
+ import { type FollowupInteractionEvent } from "./PostChatFollowupBlock";
5
+ import type { ChatViewClassNames, ChatViewRenderers } from "./ChatSurface";
4
6
  interface Props {
5
7
  messages: ChatMessage[];
8
+ postChatFollowup?: PostChatFollowup | null;
9
+ onSuggestion?: (value: string) => void;
6
10
  isStreaming: boolean;
7
11
  sessionStatus?: string;
8
12
  askAnswers?: Record<string, AskUserAnswerData>;
9
13
  onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void;
10
- toolCallRenderer?: ToolCallRenderer;
14
+ hidePlanUpdateTools?: boolean;
15
+ /** 无消息时替换默认空状态。 */
11
16
  emptyState?: ReactNode;
12
- className?: string;
13
- /** 传给助手消息的 Markdown 渲染,用于把 MEDIA 行折叠成文件下载卡片。 */
17
+ /** 各可见区块的 className 落点;键与元素上的 `blade-chat-*` 锚点一一对应。 */
18
+ classNames?: ChatViewClassNames;
19
+ /** 区块级渲染器;返回 null 走默认渲染。 */
20
+ renderers?: ChatViewRenderers;
21
+ /** 会话 id;传给助手消息的统一上下文。 */
14
22
  sessionId?: string;
23
+ isViewer?: boolean;
24
+ onFollowupInteraction?: (event: FollowupInteractionEvent) => void;
25
+ resultFeedbackByEntry?: ReadonlyMap<string, ResultFeedback>;
26
+ onResultFeedbackSaved?: (feedback: ResultFeedback) => void;
27
+ historyPaging?: {
28
+ hasOlder: boolean;
29
+ loading: boolean;
30
+ /** Resolves true only when the paging cursor advanced. */
31
+ loadOlder: (beforeCommit?: () => void) => Promise<boolean>;
32
+ };
33
+ /**
34
+ * 消息导航的数据源(目录 + 定位)。不传就没有导航轨道,也不会请求目录——
35
+ * 纯 LLM 会话与自带入口的宿主都属于这种。
36
+ */
37
+ turnNavigation?: TurnNavigationSource;
38
+ /**
39
+ * 用户点了停止(还没等服务端确认)——打字机式显示节流要在这一刻立刻整段
40
+ * 显示已到达内容,不能等 chat:stop 的服务端回包才响应。跟 isStreaming
41
+ * 翻转成 false 不是一回事:那个信号来得晚,点击到服务端确认之间有一段
42
+ * 网络往返,这段时间里节流动画不该继续播。
43
+ */
44
+ isStopping?: boolean;
45
+ /**
46
+ * 打字机式显示节流是否还没追平目标全文——调用方需要跟 isStreaming 做
47
+ * `||` 判断输入框"运行中"状态,否则输入框会先于文字播完就翻回可输入。
48
+ */
49
+ onRevealingChange?: (revealing: boolean) => void;
50
+ /**
51
+ * 是否正在回放(演示 / 彩排)而非真正的实时直播——回放期间即使内容在
52
+ * 增长也不进入打字机式节流,直接整段显示:这是"流式与历史必须产生相同
53
+ * 结果"这条硬规则的一部分,节流只在真正的实时直播里生效。
54
+ */
55
+ isReplay?: boolean;
15
56
  }
16
57
  /**
17
58
  * 消息列表:use-stick-to-bottom 自动滚动 + 按轮次分组渲染。
18
59
  * 相比第一方版本去掉了轮次导航栏、吸顶状态条与规划摘要卡片。
19
60
  */
20
- export declare function MessageList({ messages, isStreaming, sessionStatus, askAnswers, onAnswer, toolCallRenderer, emptyState, className, sessionId, }: Props): import("react/jsx-runtime").JSX.Element;
61
+ export declare function MessageList({ messages, postChatFollowup, onSuggestion, isStreaming, sessionStatus, askAnswers, onAnswer, hidePlanUpdateTools, emptyState, classNames, renderers, sessionId, isViewer, onFollowupInteraction, resultFeedbackByEntry, onResultFeedbackSaved, historyPaging, turnNavigation, isStopping, onRevealingChange, isReplay, }: Props): import("react/jsx-runtime").JSX.Element;
21
62
  export {};
@@ -0,0 +1,32 @@
1
+ import type { ChatMessage, ToolCallInfo } from "@blade-hq/agent-client";
2
+ export type PlanStepStatus = "pending" | "in_progress" | "completed";
3
+ export interface PlanUpdateData {
4
+ plan: Array<{
5
+ step: string;
6
+ status: PlanStepStatus;
7
+ }>;
8
+ }
9
+ export declare const PLAN_AUTO_COLLAPSE_MS = 5000;
10
+ export declare function isPlanUpdateTool(toolCall: Pick<ToolCallInfo, "name">): boolean;
11
+ export interface PlanUpdateDisplayState {
12
+ current: ToolCallInfo | null;
13
+ updating: boolean;
14
+ }
15
+ export declare function getPlanUpdateDisplayState(messages: ChatMessage[]): PlanUpdateDisplayState;
16
+ export declare function parsePlanUpdate(argumentsJson: string): PlanUpdateData | null;
17
+ export declare function pickCurrentPlanStep(plan: PlanUpdateData["plan"]): PlanUpdateData["plan"][number] | null;
18
+ export declare function PlanUpdateBlock({ toolCall, running, autoReveal, className, }: {
19
+ toolCall: ToolCallInfo;
20
+ running?: boolean;
21
+ /** 实时收到的新进度短暂展开;加载历史时保持默认收起。 */
22
+ autoReveal?: boolean;
23
+ className?: string;
24
+ }): import("react/jsx-runtime").JSX.Element | null;
25
+ export declare function CurrentPlanPanel({ messages, running, revealRevision, sessionId, className, }: {
26
+ messages: ChatMessage[];
27
+ running?: boolean;
28
+ /** 仅实时成功的 update_plan 递增;历史 hydration 不得改变。 */
29
+ revealRevision?: number;
30
+ sessionId?: string;
31
+ className?: string;
32
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,47 @@
1
+ import type { BladeClient, SessionPluginConfigState } from "@blade-hq/agent-client";
2
+ import type { PluginConnectorItem } from "./plugin-connector";
3
+ export interface ConfiguringPlugin {
4
+ name: string;
5
+ /**
6
+ * 这次打开表单是不是「为了启用它」。
7
+ *
8
+ * 只有用户在开关上表达了启用意图时才为 true:已经跑起来的插件再保存配置
9
+ * 不应该顺手重启 / 重新激活(见 SessionPluginSelector 的历史约定)。
10
+ */
11
+ pendingActivation: boolean;
12
+ }
13
+ export interface PluginConnectorListProps {
14
+ client: BladeClient;
15
+ /** 会话内插件用会话接口取图标;首页候选(null)用账号级目录。 */
16
+ sessionId: string | null;
17
+ items: PluginConnectorItem[];
18
+ /** 正在提交意图的行;开关转圈,但仍然可点(点是取消)。 */
19
+ inFlight: Record<string, true>;
20
+ /** 有启用/停用请求在飞,会写服务端的行先锁住次要操作。 */
21
+ busy: boolean;
22
+ /** 上一次操作失败,给出重试入口。 */
23
+ mutationError: boolean;
24
+ onToggle: (item: PluginConnectorItem, next: boolean) => void;
25
+ onRetry: (item: PluginConnectorItem) => void;
26
+ onEditConfig: (item: PluginConnectorItem) => void;
27
+ configuring: ConfiguringPlugin | null;
28
+ onConfigSaved: (state: SessionPluginConfigState) => void;
29
+ onConfigClose: () => void;
30
+ /** 开关不可用时说明原因,而不是静默禁用。 */
31
+ disabledReason?: string | null;
32
+ /**
33
+ * 列表本身不可用(读取失败 / 搜索无结果)时的说明;有值时不再叠加「还没装插件」,
34
+ * 否则会把一次故障或一次没搜到说成「你这个账号没装东西」。
35
+ */
36
+ unavailableText?: string | null;
37
+ emptyText: string;
38
+ /** 首页待选模式:开关的语义是"待选",不是"已经启用"。 */
39
+ draft?: boolean;
40
+ }
41
+ /**
42
+ * 连接器面板里的插件列表。
43
+ *
44
+ * 首页与会话共用同一份渲染:开关是开关,候选是候选,行的存在与状态无关——
45
+ * 没启用、没图标也要显示名称和占位,不隐藏整行。
46
+ */
47
+ export declare function PluginConnectorList({ client, sessionId, items, inFlight, busy, mutationError, onToggle, onRetry, onEditConfig, configuring, onConfigSaved, onConfigClose, disabledReason, unavailableText, emptyText, draft, }: PluginConnectorListProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import type { BladeClient } from "@blade-hq/agent-client";
2
+ import type { TriggerSummary } from "./connector-panel-types";
3
+ export interface PluginTriggerStackProps {
4
+ client: BladeClient;
5
+ /** 会话内图标走会话接口;首页待选传 `null`(走账号级目录图标)。 */
6
+ sessionId: string | null;
7
+ /** 折叠结果,来自 `triggerSummary`——折叠规则只有那一处。 */
8
+ summary: TriggerSummary;
9
+ className?: string;
10
+ }
11
+ /**
12
+ * 触发器上的插件头像堆叠:前三枚圆形头像 + 其余折成 `+N`。
13
+ *
14
+ * 没有图标 token 的插件也用显示名首字占一枚圆——它和别的插件长得不一样,
15
+ * 「我选过它」就看得见;早先把这类项直接剔掉,选中后入口毫无变化。
16
+ *
17
+ * 圆环色取 `--background`(盖住被压住的那枚),与整站头像堆叠同一约定,见
18
+ * `apps/web/src/components/agent-board/ProjectMembers.tsx`:容器没有自己的底色时,
19
+ * 环就等于容器露出来的那层底。图标裁成圆形:插件 logo 多是方的,套在圆按钮里
20
+ * 「方套圆」才是那个视觉冲突的来源。
21
+ */
22
+ export declare function PluginTriggerStack({ client, sessionId, summary, className }: PluginTriggerStackProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,63 @@
1
+ import type { FinalArtifact, PostChatFollowup, ResultFeedback as SavedResultFeedback, ResultFeedbackReason } from "@blade-hq/agent-client";
2
+ export type FollowupInteractionEvent = {
3
+ type: "suggestions_shown";
4
+ sessionId?: string;
5
+ assistantEntryId: string;
6
+ count: number;
7
+ } | {
8
+ type: "suggestion_adopted";
9
+ sessionId?: string;
10
+ assistantEntryId: string;
11
+ suggestionIndex: number;
12
+ } | {
13
+ type: "artifact_shown";
14
+ sessionId?: string;
15
+ assistantEntryId: string;
16
+ artifactIndex: number;
17
+ artifactKind: FinalArtifact["kind"];
18
+ } | {
19
+ type: "artifact_opened";
20
+ sessionId?: string;
21
+ assistantEntryId: string;
22
+ artifactIndex: number;
23
+ artifactKind: FinalArtifact["kind"];
24
+ } | {
25
+ type: "artifact_download_started";
26
+ sessionId?: string;
27
+ assistantEntryId: string;
28
+ artifactIndex: number;
29
+ artifactKind: "file";
30
+ } | {
31
+ type: "artifact_download_succeeded";
32
+ sessionId?: string;
33
+ assistantEntryId: string;
34
+ artifactIndex: number;
35
+ artifactKind: "file";
36
+ } | {
37
+ type: "result_feedback_shown";
38
+ sessionId?: string;
39
+ assistantEntryId: string;
40
+ } | {
41
+ type: "result_feedback_submitted";
42
+ sessionId?: string;
43
+ assistantEntryId: string;
44
+ helpful: boolean;
45
+ reason: ResultFeedbackReason | null;
46
+ updatedAt: string;
47
+ };
48
+ export declare function HistoricalResultFeedback({ feedback }: {
49
+ feedback: SavedResultFeedback;
50
+ }): import("react/jsx-runtime").JSX.Element;
51
+ export declare function PostChatFollowupBlock({ followup, sessionId, onSuggestion, isViewer, onInteraction, savedFeedback, onFeedbackSaved, className, suggestionClassName, }: {
52
+ followup: PostChatFollowup;
53
+ sessionId?: string;
54
+ onSuggestion?: (value: string) => void;
55
+ isViewer?: boolean;
56
+ onInteraction?: (event: FollowupInteractionEvent) => void;
57
+ savedFeedback?: SavedResultFeedback;
58
+ onFeedbackSaved?: (feedback: SavedResultFeedback) => void;
59
+ /** 追加到跟进区根节点的类(`ChatViewClassNames.followup`)。 */
60
+ className?: string;
61
+ /** 追加到每个「下一步」建议按钮的类(`ChatViewClassNames.followupAction`)。 */
62
+ suggestionClassName?: string;
63
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,11 @@
1
+ import type { BladeClient } from "@blade-hq/agent-client";
2
+ type CheckpointTree = Awaited<ReturnType<BladeClient["sessions"]["getSessionCheckpoints"]>>;
3
+ export interface SessionBranchPickerProps {
4
+ tree: CheckpointTree;
5
+ /** Disable changes while this session is running or read-only. */
6
+ disabled?: boolean;
7
+ /** Restore only the conversation; the host owns history refresh and composer drafts. */
8
+ onCheckout: (checkpointId: string, position: "before" | "turn_end") => Promise<void>;
9
+ }
10
+ export declare function SessionBranchPicker({ tree, disabled, onCheckout, }: SessionBranchPickerProps): import("react/jsx-runtime").JSX.Element | null;
11
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { BladeClient } from "@blade-hq/agent-client";
2
+ export interface SessionMemoryToggleProps {
3
+ sessionId: string;
4
+ enabled: boolean;
5
+ /** 不在 BladeProvider 内使用时显式传入,与宿主现有 BladeClient 复用连接和鉴权。 */
6
+ client?: BladeClient;
7
+ disabled?: boolean;
8
+ label?: string;
9
+ className?: string;
10
+ labelClassName?: string;
11
+ inputClassName?: string;
12
+ onSaved?: (sessionId: string, enabled: boolean) => void;
13
+ onError?: (error: unknown) => void;
14
+ }
15
+ /**
16
+ * 当前会话记忆开关。同一 client + sessionId 的所有实例共享保存锁,避免多个聊天入口
17
+ * 或会话切换时发出乱序更新;服务端成功后才通过 onSaved 交还权威值。
18
+ */
19
+ export declare function SessionMemoryToggle({ sessionId, enabled, client: clientProp, disabled, label, className, labelClassName, inputClassName, onSaved, onError, }: SessionMemoryToggleProps): import("react/jsx-runtime").JSX.Element;