@blade-hq/agent-react 2610.0.0-beta.7 → 2610.0.0-beta.70

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 (59) hide show
  1. package/README.md +148 -3
  2. package/dist/chunk-G3PMV62Z.js +36 -0
  3. package/dist/{chunk-ZXXLY4RM.js → chunk-MAAMCOAU.js} +8 -32
  4. package/dist/{chunk-ZXXLY4RM.js.map → chunk-MAAMCOAU.js.map} +1 -1
  5. package/dist/components/AgentChat.d.ts +3 -0
  6. package/dist/components/AgentLoopBlock.d.ts +1 -4
  7. package/dist/components/AskUserQuestionBlock.d.ts +9 -0
  8. package/dist/components/AssistantTurnBlock.d.ts +20 -6
  9. package/dist/components/ChatInput.d.ts +15 -1
  10. package/dist/components/ChatSurface.d.ts +29 -2
  11. package/dist/components/ConnectorPanel.d.ts +41 -0
  12. package/dist/components/ContextCard.d.ts +20 -0
  13. package/dist/components/MarkdownContent.d.ts +2 -0
  14. package/dist/components/McpAppCard.d.ts +14 -0
  15. package/dist/components/MessageList.d.ts +26 -1
  16. package/dist/components/PlanUpdateBlock.d.ts +31 -0
  17. package/dist/components/PluginConnectorList.d.ts +47 -0
  18. package/dist/components/PluginTriggerStack.d.ts +22 -0
  19. package/dist/components/SessionMemoryToggle.d.ts +19 -0
  20. package/dist/components/SessionPluginConfigDialog.d.ts +10 -0
  21. package/dist/components/SessionPluginConfigForm.d.ts +14 -0
  22. package/dist/components/SessionPluginIcon.d.ts +30 -0
  23. package/dist/components/SessionPluginSelector.d.ts +10 -0
  24. package/dist/components/SessionQueuePanel.d.ts +74 -0
  25. package/dist/components/ToolCallBlock.d.ts +4 -2
  26. package/dist/components/ToolUiCardView.d.ts +9 -0
  27. package/dist/components/UserMessageBubble.d.ts +1 -1
  28. package/dist/components/WhatIfUserBubble.d.ts +7 -0
  29. package/dist/components/connector-panel-types.d.ts +37 -0
  30. package/dist/components/display-utils.d.ts +10 -0
  31. package/dist/components/plugin-config-draft.d.ts +13 -0
  32. package/dist/components/plugin-config-schema.d.ts +6 -0
  33. package/dist/components/plugin-connector.d.ts +40 -0
  34. package/dist/components/queue-panel-adjacency.d.ts +1 -0
  35. package/dist/components/use-session-plugin-activation.d.ts +40 -0
  36. package/dist/context.d.ts +1 -0
  37. package/dist/embed/entry.d.ts +46 -0
  38. package/dist/{highlighted-body-B3W2YXNL-YD7FAP6V.js → highlighted-body-B3W2YXNL-IASCZDV2.js} +3 -2
  39. package/dist/{highlighted-body-B3W2YXNL-YD7FAP6V.js.map → highlighted-body-B3W2YXNL-IASCZDV2.js.map} +1 -1
  40. package/dist/hooks/use-agent-session.d.ts +5 -0
  41. package/dist/hooks/use-message-pin.d.ts +28 -0
  42. package/dist/hooks/use-typewriter-reveal.d.ts +32 -0
  43. package/dist/index.d.ts +43 -0
  44. package/dist/index.js +44786 -1663
  45. package/dist/index.js.map +1 -1
  46. package/dist/lib/agent-computer-command.d.ts +34 -0
  47. package/dist/lib/random-id.d.ts +10 -0
  48. package/dist/lib/utils.d.ts +3 -1
  49. package/dist/lib/whatif-prompt.d.ts +18 -0
  50. package/dist/mermaid-3ZIDBTTL-BPVVWTVV.js +9 -0
  51. package/dist/mermaid-3ZIDBTTL-BPVVWTVV.js.map +1 -0
  52. package/dist/style.css +97 -5
  53. package/dist/style.full.css +98 -6
  54. package/dist/webapi-W3IB5DO4.js +2481 -0
  55. package/dist/webapi-W3IB5DO4.js.map +1 -0
  56. package/package.json +2 -2
  57. package/public-api.md +1287 -31
  58. package/dist/mermaid-3ZIDBTTL-N7YKJ3SM.js +0 -8
  59. /package/dist/{mermaid-3ZIDBTTL-N7YKJ3SM.js.map → chunk-G3PMV62Z.js.map} +0 -0
package/README.md CHANGED
@@ -6,6 +6,10 @@ Blade Agent 的 React 绑定:`BladeProvider` + `useAgentSession` + 开箱即
6
6
  pnpm add @blade-hq/agent-client @blade-hq/agent-react
7
7
  ```
8
8
 
9
+ 默认装到的是当前长期支持版(LTS),厂内离线交付按它开发。要跟两周一发的公网版本,改用 `@next`。
10
+
11
+ 最稳妥的做法是先读目标 Server 的 `GET /api/version`,按返回的版本号在 `package.json` 里钉死——NPM 的 `latest` 不一定和目标环境跑的版本一致。
12
+
9
13
  > 注意两个包都要装:`agent-client` 是运行时依赖,只装 `agent-react` 在 pnpm 下会直接报错。
10
14
 
11
15
  ## 快速开始
@@ -28,7 +32,6 @@ export function App() {
28
32
 
29
33
  - 不传 `sessionId` 自动创建新会话;未登录时 `ChatView` 自己渲染登录按钮(弹窗授权,见 agent-client 的 `client.auth.login()`)。
30
34
  - 同一 `BladeProvider` 下可以放多个 `ChatView`,各自独立会话、互不干扰。
31
- - 宿主只需要完成态消息时,可在 `BladeClient` 构造参数中传 `streamTokens: false`,不订阅逐 token 增量。
32
35
 
33
36
  ## BladeProvider
34
37
 
@@ -54,6 +57,7 @@ const client = useBladeClient() // 当前 Provider 的 BladeClient
54
57
  const { session, state, error } = useAgentSession(sessionId, {
55
58
  createOptions, // 不传 sessionId 时的建会话配置(UseAgentSessionOptions)
56
59
  onSessionCreated: (id) => saveSomewhere(id),
60
+ onSessionConnected: (session) => session.on("toolResult", handleResult),
57
61
  })
58
62
 
59
63
  state?.messages // ChatMessage[],直接渲染
@@ -67,8 +71,29 @@ await session?.send("你好")
67
71
 
68
72
  - 优先级:`sessionId`(连接既有会话)> `createOptions`(按配置新建)> 默认新建。
69
73
  - 自动创建只发生一次(含 React StrictMode 双跑);创建出的 id 通过 `onSessionCreated` 交还,重挂载时把它作为 `sessionId` 传回即可复用会话。
74
+ - 必须覆盖连接窗口内事件时,用 `onSessionConnected` 在历史加载和房间订阅开始前完成订阅,并返回取消订阅函数。
70
75
  - 同一 `sessionId` 的多次调用复用同一 `AgentSession` 实例(引用计数);卸载后延迟释放,路由抖动不会断连。
71
76
 
77
+ ## SessionMemoryToggle
78
+
79
+ 把当前会话是否使用记忆放进宿主自己的会话设置面板:
80
+
81
+ ```tsx
82
+ const [memoryEnabled, setMemoryEnabled] = useState(session.memory_enabled !== false)
83
+
84
+ <SessionMemoryToggle
85
+ sessionId={session.id}
86
+ enabled={memoryEnabled}
87
+ onSaved={(_sessionId, enabled) => setMemoryEnabled(enabled)}
88
+ onError={(error) => toast.error(String(error))}
89
+ />
90
+ ```
91
+
92
+ 组件默认使用 `BladeProvider` 的 client;已有独立 client 装配层的宿主也可以显式传
93
+ `client={client}`。同一 client、同一会话的多个开关共享保存锁,即使切换会话或同时存在多个
94
+ 设置入口,也不会并发提交相互覆盖。服务端确认后的权威值通过 `onSaved` 返回。
95
+ 全部属性见 `SessionMemoryToggleProps`。
96
+
72
97
  ## useReplay
73
98
 
74
99
  会话回放(演示 / 彩排):拿一个已经聊完的会话当素材,重现当时的回复和工具调用,
@@ -133,6 +158,9 @@ await replay.exitToAutonomous() // 退出回放,之后真的运
133
158
 
134
159
  完整聊天界面:消息列表(Markdown、代码高亮、工具调用、提问卡片)+ 输入框 + 连接状态条 + 登录引导。
135
160
 
161
+ `ChatView` 固定使用普通展示模式。产品内置 Web 的精简/开发者模式不属于 SDK 公共能力,
162
+ 因此没有 `renderMode` 等切换属性。
163
+
136
164
  ```tsx
137
165
  <ChatView
138
166
  sessionId={id} // 可选;不传自动建会话
@@ -150,7 +178,19 @@ await replay.exitToAutonomous() // 退出回放,之后真的运
150
178
 
151
179
  全部 props 见 `ChatViewProps`。样式说明:
152
180
 
153
- `onFollowupInteraction` 使用 `FollowupInteractionEvent`,覆盖下一步建议展示/采纳、成果展示/打开/下载以及结果评分。SDK 不内置 PostHog 等分析厂商;宿主回调抛错也不会中断用户点击或下载。
181
+ 智能体调用 `update_plan` 新增或更新任务时,`ChatView` 会在输入框上方自动展开最新任务进度,
182
+ 5 秒后平滑收起;连续更新会重新计时,用户手动展开或收起后以用户选择为准。自建聊天布局可直接
183
+ 使用 `CurrentPlanPanel` / `PlanUpdateBlock`,或用 `getPlanUpdateDisplayState`、
184
+ `parsePlanUpdate` 和 `pickCurrentPlanStep` 复用同一套判定。
185
+
186
+ `ChatView` 的普通展示模式不显示只供诊断的项目说明、可用能力和当前工作环境。需要自建诊断界面时,可直接使用独立的 `ContextCard`,属性见 `ContextCardProps`;状态到文案的映射来自 agent-client 的 `getContextDisplayState`,不需要接入方重复判断。一次输入通常会同时注入十几项上下文,把渲染序列里连续的几项用 `ContextGroupCard`(属性见 `ContextGroupCardProps`)折成一行更合适;哪几项算一组由 agent-client 的 `groupAdjacentContextRuns` 判定,折叠行文案来自 `getContextGroupDisplayState` / `ContextGroupDisplayState`。底层数据类型为 `ContextProjectionData` / `ContextProjectionFields`,展示结果为 `ContextDisplayState`,并保留 `ContextAction`、`ContextSourceInfo` 和 `contextProjectionData` 给 headless 消费方。
187
+
188
+ 记忆引用提示可通过 `MemoryRefsHint` 展示,`collectMemoryRefs` 用于从一轮消息中聚合引用,保证宿主自定义消息布局与 SDK 默认界面保持一致。
189
+
190
+ MCP App 卡片(`tool_ui` block)在默认消息流里自动渲染,无需配置;自建消息布局时可用 `ToolUiCardView` 渲染单个卡片,并传入 `sessionId` 启用共享 AppBridge。卡片的实例、内容解析与终态(archived 留档不重放)判定来自 agent-client 的共享层(`collectInlineToolUiCards` / `resolveToolUiCardContent` 等)。preview 卡片不进消息流,由 `toolPreview` 事件推给宿主自建面板。
191
+
192
+ `onFollowupInteraction` 使用 `FollowupInteractionEvent`,覆盖下一步建议展示/采纳、成果展示/打开/下载以及结果评分。SDK 不内置分析服务;宿主回调抛错也不会中断用户点击或下载。
193
+ 文件成果以文件名为文本的标准下载链接展示;Vue / 纯 HTML 使用的 `<blade-chat>` 与 `ChatView` 行为一致。
154
194
 
155
195
  - 必须引入一份样式,按宿主有没有 Tailwind 二选一:
156
196
  - **`style.full.css`**(默认选它):布局兜底 + 编译好的 Tailwind 产物,自包含,宿主没装 Tailwind 也是完整视觉。
@@ -170,6 +210,9 @@ Blade。这时把 `ChatView` 切到 `mode="llm"`,或者直接用下层的 `Llm
170
210
  <ChatView mode="llm" llm={{ baseURL: "/api/llm", model }} /> // 切成纯 LLM
171
211
  <LlmChat baseURL="/api/llm" model={model} /> // 或者直接用(LlmChatProps)
172
212
  <AgentChat sessionId={id} /> // 智能体那侧同样可以直接用(AgentChatProps)
213
+
214
+ `AgentChat` 还支持 `sessionPluginControls(sessionId)` 插槽,宿主可复用
215
+ `@blade-hq/agent-client` 的会话插件状态与激活控制。
173
216
  ```
174
217
 
175
218
  **协议就是 OpenAI 的**:`POST {baseURL}/chat/completions`,`stream: true`,读
@@ -261,6 +304,43 @@ models.filter((m) => m.serviceModelId)
261
304
  <MarkdownContent sessionId={sessionId}>{markdownText}</MarkdownContent>
262
305
  ```
263
306
 
307
+ `normalizeAdjacentUrlFormatting` 可在复用其他 Markdown 渲染器前,保护紧贴行内格式标记的 URL。
308
+
309
+ ## Canonical 引用消息
310
+
311
+ `ChatView` 会自动识别 ship-attack 会话中的 `[引用]` / `[用户输入]` canonical
312
+ 消息,并按原顺序展示引用来源、快照和用户输入。自建消息列表时可用
313
+ `parseWhatIfPrompt` 解析同一格式,再交给 `WhatIfUserBubble` 渲染;
314
+ `onQuoteClick` 可接入宿主的步骤跳转。
315
+
316
+ ```tsx
317
+ const parsed = parseWhatIfPrompt(messageText)
318
+ return parsed ? (
319
+ <WhatIfUserBubble parsed={parsed} onQuoteClick={jumpToStep} />
320
+ ) : null
321
+ ```
322
+
323
+ ## isAgentComputerCommand / isAgentComputerToolCall / classifyAgentComputerLaunchOutcome
324
+
325
+ 判断智能体是否在沙盒里启动了通用 GUI 应用镜像(`computer launch`)——后端 blade-agent 通过 `computer` CLI 驱动一块虚拟屏幕运行任意 GUI 软件,这些函数用于自行接入方判断要不要展示对应的实时画面入口(比如自建一个类似「电脑镜像」的标签页)。当前 SDK 侧还没有内置这块 UI,只导出判定规则,避免各接入方重新猜一遍匹配逻辑。
326
+
327
+ `isAgentComputerCommand`/`isAgentComputerToolCall` 只回答"这条命令是不是一次 launch 尝试",不回答"这次 launch 最终成不成功"——待处理、已失败的 launch 也会命中。要判断真实结果(比如决定要不要展示画面入口),用 `classifyAgentComputerLaunchOutcome`:它会解析工具调用的 `status`/`result`,返回 `"pending" | "succeeded" | "failed" | "unknown"`。`"unknown"` 表示 `status` 已经是终态但 `result` 字段本身缺失(常见于会话整理/compaction 之后的历史投影,归档时不会重新序列化完整 result),跟"result 回来了、里面确实没有成功标记"的 `"failed"` 是两种不同性质的证据——接入方要按自己的场景决定怎么处理(展示类场景可以偏宽松,当作足够展示;自动跳转/替用户做决定的场景应该偏保守,当作跟 `"failed"` 一样处理)。
328
+
329
+ ```ts
330
+ import {
331
+ isAgentComputerCommand,
332
+ isAgentComputerToolCall,
333
+ classifyAgentComputerLaunchOutcome,
334
+ } from "@blade-hq/agent-react"
335
+
336
+ isAgentComputerCommand("computer launch --exec /opt/apps/foo/bar") // true
337
+ isAgentComputerCommand("computer status") // false(只认 launch,不认查询类子命令)
338
+
339
+ isAgentComputerToolCall(toolCall.arguments) // 工具调用的 JSON 参数版本
340
+
341
+ classifyAgentComputerLaunchOutcome(toolCall) // "pending" | "succeeded" | "failed" | "unknown"
342
+ ```
343
+
264
344
  ## 选择模型
265
345
 
266
346
  SDK 的 ChatView / `<blade-chat>` 不内置模型选择器(默认用后端配置的模型)。指定模型有两种方式:
@@ -296,12 +376,77 @@ blade-chat { --primary: 262 83% 58%; height: 640px; }
296
376
  </blade-chat>
297
377
  ```
298
378
 
379
+ ## 自定义消息列表滚动
380
+
381
+ `ChatView`、`AgentChat` 和 `LlmChat` 已经处理好用户发言顶置,不用额外配置。自建消息列表时可用 `useMessagePin` 复用同一套触发、补白、视口 resize 和手动滚动接管逻辑;调用方只需提供滚动容器、目标消息与 spacer 的读写函数。完整参数见 [public-api.md](./public-api.md#usemessagepin-function)。
382
+
383
+ ## 打字机式显示节流
384
+
385
+ `ChatView`、`AgentChat` 和 `LlmChat` 已经内置这套节流,不用额外配置。服务端到达速率天然不均匀(一次推 5 个字、一次推 20 个字),直接原样渲染会显得忽快忽慢;`useTypewriterReveal(targetText, isLive, resetKey)` 按估算到达速度、留一个很小的固定滞后量匀速播放,返回 `{ displayedText, isRevealing, flushNow }`——自建消息列表时可以直接复用。`isLive` 传 `false`(历史加载 / 回放)时永远整段直接显示;`resetKey`(比如消息的 `entry_id`)变化时播放状态从头开始;`flushNow()` 用于用户点了停止时立即整段显示已到达内容。完整参数见 [public-api.md](./public-api.md#usetypewriterreveal-function)。
386
+
299
387
  ## 纯静态 HTML / Vue?
300
388
 
301
389
  不需要本包——用后端托管的单文件产物 `<script src=".../sdk/blade-agent.js">` + `<blade-chat>` 自定义元素,行为与 `ChatView` 一致;详见 agent-client README 与接入文档。
302
390
 
391
+ ## 附录:连接器与插件选择
392
+
393
+ - **连接器面板**:`ConnectorPanel`、`ConnectorPanelProps`、`PluginConnectorList`、`PluginConnectorListProps`、`ConfiguringPlugin`
394
+ - **插件行与触发器**:`PluginConnectorItem`、`PluginConnectorSelection`、`selectionFromItem`、`triggerSummary`、`TriggerSummary`、`TRIGGER_ICON_LIMIT`、`mergeConnectorItems`、`catalogToConnectorItems`、`filterConnectorItems`
395
+ - **触发器上的头像堆叠**:`PluginTriggerStack`、`PluginTriggerStackProps`(前三枚插件头像 + `+N`,宿主自己画触发器时用它,不要另写一份折叠)
396
+ - **启用时序**:`useSessionPluginActivation`、`UseSessionPluginActivationResult`
397
+
303
398
  ## 附录:re-export 自 @blade-hq/agent-client
304
399
 
305
400
  为方便单包引入,本包 re-export 了 agent-client 的全部公开声明(`BladeClient`、`AgentSession`、`SessionState`、协议类型等),文档一律见 [agent-client 的 README](../agent-client/README.md)。完整签名见 [public-api.md](./public-api.md)。
306
401
 
307
- 本包自有声明:`BladeProvider`、`BladeProviderProps`、`useBladeClient`、`useAgentSession`、`UseAgentSessionOptions`、`UseAgentSessionResult`、`useReplay`、`UseReplayResult`、`ReplayMismatch`、`ReplayBar`、`ReplayBarProps`、`ReplayMismatchPrompt`、`ReplayMismatchPromptProps`、`ChatView`、`ChatViewProps`、`ChatViewClassNames`、`ChatViewRenderers`、`ChatViewSlots`、`FollowupInteractionEvent`、`ToolCallRenderer`、`MarkdownContent`、`MarkdownContentProps`。
402
+ 本包自有声明:`BladeProvider`、`BladeProviderProps`、`useBladeClient`、`useAgentSession`、`UseAgentSessionOptions`、`UseAgentSessionResult`、`useMessagePin`、`UseMessagePinOptions`、`useTypewriterReveal`、`UseTypewriterRevealResult`、`useReplay`、`UseReplayResult`、`ReplayMismatch`、`ReplayBar`、`ReplayBarProps`、`ReplayMismatchPrompt`、`ReplayMismatchPromptProps`、`ChatView`、`ChatViewProps`、`ChatViewClassNames`、`ChatViewRenderers`、`ChatViewSlots`、`FollowupInteractionEvent`、`ToolCallRenderer`、`CurrentPlanPanel`、`PlanUpdateBlock`、`PlanUpdateData`、`PlanUpdateDisplayState`、`PlanStepStatus`、`getPlanUpdateDisplayState`、`isPlanUpdateTool`、`parsePlanUpdate`、`pickCurrentPlanStep`、`PLAN_AUTO_COLLAPSE_MS`、`MarkdownContent`、`MarkdownContentProps`、`parseWhatIfPrompt`、`ParsedWhatIfPrompt`、`WhatIfQuote`、`WhatIfUserBubble`、`WhatIfUserBubbleProps`、`SessionQueuePanel`、`SessionQueuePanelProps`、`isQueuePanelVisible`。
403
+
404
+ ## 会话消息队列
405
+
406
+ 智能体会话的等待消息由服务端持久化,`ChatView` / `AgentChat` 已在输入框上方渲染队列区域(空队列不占位,条目数超过三条可折叠)。输入框不再有「直接插入 / 排队执行」开关:会话空闲时提交直接开始处理,运行中提交默认入队;暂停时在面板上显示原因和「继续执行」。面板数据来自 `useAgentSession` 状态里的 `queue`(`SessionQueueSnapshot`),可编辑/删除/立即补充的判定来自 agent-client 的 `canEditQueuedMessage` / `canCancelQueuedMessage` / `canDeliverQueuedMessage`,文案用 `queuedMessageStatusLabel` / `queuePauseReasonLabel`。
407
+
408
+ 自建布局可直接使用 `<SessionQueuePanel>`,属性类型为 `SessionQueuePanelProps`:传 `snapshot`、`canDeliver`、可选的 `pendingItemId`(提交中的条目禁用操作)与 `notice`(冲突/失败说明),以及 `onResume` / `onCancel` / `onEdit` / `onMove` / `onReorder` / `onDeliver` 回调。上移/下移与拖动排序最终都提交当前 pending 条目的完整 id 顺序。冲突时队列由服务端快照刷新,`ChatView` 会把未保存的正文放回输入框,不会静默丢掉用户编辑的内容。
409
+
410
+ 面板比输入框窄一圈、贴在它上方,所以宽度必须跟输入框一致:用可选属性 `contentWidthClassName` 传入输入框内层的宽度类(不传则按本包输入框的 `max-w-[748px]`)。左右内边距同理——默认值对应本包输入框的 `--blade-chat-gutter`;如果你给输入框根节点换了左右 padding(例如改成 `px-10`),必须用 `rootClassName` 在面板根节点重设 `--blade-chat-queue-gutter` 成同一个值,否则面板会跟输入框错开一圈、在两者相接的缝上露出来。
411
+
412
+ 输入框的 `mergesWithPanelAbove` 为 true 时上两角改直角,跟面板拼成一条完整轮廓;否则输入框的上角圆弧会从较窄的面板两侧露出来,形成两个尖角。**这个值要取面板上报的状态,不要在宿主侧用 `isQueuePanelVisible` 复算**:面板有本地编辑态(编辑到一半、那条等待消息被服务端拿走时仍要留在原地保住草稿,见 `detachedEdit`),这时 snapshot 里没有条目、宿主复算会得到 false,输入框就会在面板还显示着的时候把上角恢复成圆角。用 `onVisibleChange` 拿到面板的真实占位状态,再传给输入框或 `ChatSurface` 的 `queuePanelVisible`。本包的 `AgentChat` 已按这条接好,自建布局照做即可。
413
+
414
+ 拼轮廓的前提是两者**真的相邻**。中间夹着别的内容时(本包的 MCP 暂存内容、内置 Web 的 `composerBanner`),面板下两角与输入框上两角都要圆起来——直角是"被对方接住"的表示,露出直角却中间空着一块,看起来像被削掉一角。面板的 `mergesWithInputBelow` 与输入框的 `mergesWithPanelAbove` 要取同一个判据;`ChatSurface` 会用 context 把这一位传给面板,自建布局直接传即可。
415
+
416
+ `PollingBackoff` 从 agent-client 重导出,供自定义只读轮询计算退避时间;它不发送或重放请求。用法见 [agent-client 轮询说明](../agent-client/README.md#只读轮询退避)。
417
+
418
+ ### 会话插件
419
+
420
+ 默认 `AgentChat` / 智能体模式 `ChatView` 自带会话插件选择器,展开时查询 BH,选择按当前会话保存。准备失败会保留勾选并提供重试。独立嵌入可使用 `<SessionPluginSelector client={client} sessionId={id} />`;`sessionPluginControls` 可覆盖默认控件。组件参数类型为 `SessionPluginSelectorProps`。
421
+
422
+ 列表项用插件声明的业务名称与随包本地图标展示(`sessionPluginLabel(plugin)` 与 `<SessionPluginIcon client={client} sessionId={id} plugin={plugin} />`,两者都可单独复用,参数类型为 `SessionPluginLabelProps` / `SessionPluginIconProps`);没有声明或图标不可用时回退技术 ID 与通用占位。授权、缓存、调用一律仍用 `plugin.name`。
423
+
424
+ 插件的账号、token 等配置由包内 JSON Schema 声明,选择器就地提供填写入口:首次激活缺配置的插件会直接弹出表单(`<SessionPluginConfigDialog client={client} sessionId={id} plugin={plugin} />`),已配置的插件在行内提供「配置」按钮。表单本体是 `<SessionPluginConfigForm>`,参数与提交类型为 `SessionPluginConfigFormProps` / `SessionPluginConfigDraft`,也可单独嵌入;`SessionPluginConfigDialogProps` 是对话框的参数类型。
425
+
426
+ 表单只呈现它确定能呈现的 JSON Schema 构造(字符串/数值/布尔/null、对象与数组、枚举、`properties` 内的 `writeOnly`,以及用同一字段的 `const` 固定的 `oneOf` 分支);遇到无法安全呈现的写法直接说明原因,不降级成手写 JSON、不静默丢字段。`writeOnly` 字段永不回显:留空表示保持不变,输入表示修改,显式「清除」才会删除。
427
+ ### 连接器面板
428
+
429
+ 首页与对话输入框共用同一个连接器面板:`<ConnectorPanel client={client} sessionId={id} />`,
430
+ 参数类型为 `ConnectorPanelProps`。面板本身只管插件分区,电脑与外部账号由宿主通过
431
+ `renderComputerSection` / `renderExternalAccounts` / `renderFooterActions` 注入——那些入口
432
+ 要跳宿主自己的路由,SDK 不硬编码内部路径。`sessionId` 传 `null` 表示"首页":此时开关只记录
433
+ 本次输入的待选(`PluginConnectorSelection`、`onPendingPluginsChange`),不激活任何东西、
434
+ 不建会话、不启沙盒;`pendingDisabledReason` 用于说明该模式下为什么用不了待选。
435
+
436
+ 插件行的渲染交给 `<PluginConnectorList>`(`PluginConnectorListProps`),它只负责样式与排版:
437
+ "该显示成什么"全部来自 `PluginConnectorItem`、`mergeConnectorItems`、`catalogToConnectorItems`、
438
+ `filterConnectorItems`,判定不各写一份。`sessionPluginLabel` 决定
439
+ 一行读起来是什么名字。
440
+
441
+ 启用时序由 `useSessionPluginActivation` 收口(返回值类型 `UseSessionPluginActivationResult`):
442
+ **先准备配置、再提交激活**。缺必填配置时开关不落到已启用、立刻弹表单,保存由服务端确认配置
443
+ 完整才提交;取消、校验失败、读取失败都保持关闭,不会先写 `active=true` 再补偿。慢准备/慢激活
444
+ 期间开关仍可点,语义是取消这次意图而不是再排一次队。配置弹窗由 `ConfiguringPlugin` 描述。
445
+
446
+ 触发器要在不打开面板时就能显示"选了哪几个、几个":用 `selectionFromItem` 把一行转成
447
+ `PluginConnectorSelection`,再用 `triggerSummary` 折成 `TriggerSummary`(最多 `TRIGGER_ICON_LIMIT`
448
+ 个图标,其余折成数量;没有图标 token 的项不占图标位但仍计数)。
449
+
450
+ ### MCP Apps
451
+
452
+ `McpAppCard` 使用官方 AppBridge 渲染归档卡片,内置 Web 消费同一组件。在 `BladeProvider` 下传入会话 ID 与来源 ID,也可直接提供 `BladeClient`。`McpAppMessage` 表示 App 提供的文本;`McpAppMessageContext` 将其交给当前对话的待发送区。用户可在 `ChatView` 查看、移除并确认发送。`update-model-context` 会把 App 提交的当前状态经 `sessions.updateMcpAppContext` 存为会话上下文:只落库、不追加聊天、不启动 agent turn,正在运行的一轮保持启动时版本,下一个新的运行才读取;冲突(409)时重读最新 revision 后重提同一份状态一次。
@@ -0,0 +1,36 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+
31
+ export {
32
+ __commonJS,
33
+ __export,
34
+ __toESM
35
+ };
36
+ //# sourceMappingURL=chunk-G3PMV62Z.js.map
@@ -1,32 +1,8 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __export = (target, all5) => {
11
- for (var name2 in all5)
12
- __defProp(target, name2, { get: all5[name2], enumerable: true });
13
- };
14
- var __copyProps = (to2, from, except, desc) => {
15
- if (from && typeof from === "object" || typeof from === "function") {
16
- for (let key of __getOwnPropNames(from))
17
- if (!__hasOwnProp.call(to2, key) && key !== except)
18
- __defProp(to2, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
- }
20
- return to2;
21
- };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
- // If the importer is in node compatibility mode or this is not an ESM
24
- // file that has been converted to a CommonJS file using a Babel-
25
- // compatible transform (i.e. "__esModule" has not been set), then set
26
- // "default" to the CommonJS "module.exports" for node compatibility.
27
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
- mod
29
- ));
1
+ import {
2
+ __commonJS,
3
+ __export,
4
+ __toESM
5
+ } from "./chunk-G3PMV62Z.js";
30
6
 
31
7
  // ../../node_modules/.pnpm/inline-style-parser@0.2.7/node_modules/inline-style-parser/cjs/index.js
32
8
  var require_cjs = __commonJS({
@@ -27409,7 +27385,7 @@ var Se2 = createContext({ code: "" });
27409
27385
  var de2 = () => useContext(Se2);
27410
27386
  var ot = ({ language: e }) => jsx("div", { className: "flex h-8 items-center text-muted-foreground text-xs", "data-language": e, "data-streamdown": "code-block-header", children: jsx("span", { className: "ml-1 font-mono lowercase", children: e }) });
27411
27387
  var cn2 = /\n+$/;
27412
- var dn2 = lazy(() => import("./highlighted-body-B3W2YXNL-YD7FAP6V.js").then((e) => ({ default: e.HighlightedCodeBlockBody })));
27388
+ var dn2 = lazy(() => import("./highlighted-body-B3W2YXNL-IASCZDV2.js").then((e) => ({ default: e.HighlightedCodeBlockBody })));
27413
27389
  var rt2 = ({ code: e, language: t, className: o, children: n, isIncomplete: s2 = false, ...r2 }) => {
27414
27390
  let i = useMemo(() => e.replace(cn2, ""), [e]), c = useMemo(() => ({ bg: "transparent", fg: "inherit", tokens: i.split(`
27415
27391
  `).map((a2) => [{ content: a2, color: "inherit", bgColor: "transparent", htmlStyle: {}, offset: 0 }]) }), [i]);
@@ -27756,7 +27732,7 @@ var Dt = ({ children: e, className: t, onDownload: o, onError: n }) => {
27756
27732
  }, []), jsxs("div", { className: "relative", ref: i, children: [jsx("button", { className: f2("cursor-pointer p-1 text-muted-foreground transition-all hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50", t), disabled: c, onClick: () => r2(!s2), title: "Download table", type: "button", children: e != null ? e : jsx(Z3, { size: 14 }) }), s2 ? jsxs("div", { className: "absolute top-full right-0 z-10 mt-1 min-w-[120px] overflow-hidden rounded-md border border-border bg-background shadow-lg", children: [jsx("button", { className: "w-full px-3 py-2 text-left text-sm transition-colors hover:bg-muted/40", onClick: () => a2("csv"), title: "Download table as CSV", type: "button", children: "CSV" }), jsx("button", { className: "w-full px-3 py-2 text-left text-sm transition-colors hover:bg-muted/40", onClick: () => a2("markdown"), title: "Download table as Markdown", type: "button", children: "Markdown" })] }) : null] });
27757
27733
  };
27758
27734
  var Vt = ({ children: e, className: t, showControls: o, ...n }) => jsxs("div", { className: "my-4 flex flex-col gap-2 rounded-lg border border-border bg-sidebar p-2", "data-streamdown": "table-wrapper", children: [o ? jsxs("div", { className: "flex items-center justify-end gap-1", children: [jsx(Ht, {}), jsx(Dt, {})] }) : null, jsx("div", { className: "border-collapse overflow-x-auto overscroll-y-auto rounded-md border border-border bg-background", children: jsx("table", { className: f2("w-full divide-y divide-border", t), "data-streamdown": "table", ...n, children: e }) })] });
27759
- var Jn = lazy(() => import("./mermaid-3ZIDBTTL-N7YKJ3SM.js").then((e) => ({ default: e.Mermaid })));
27735
+ var Jn = lazy(() => import("./mermaid-3ZIDBTTL-BPVVWTVV.js").then((e) => ({ default: e.Mermaid })));
27760
27736
  var Kn2 = /language-([^\s]+)/;
27761
27737
  function ke2(e, t) {
27762
27738
  if (!(e != null && e.position || t != null && t.position)) return true;
@@ -28252,4 +28228,4 @@ export {
28252
28228
  _r,
28253
28229
  Nt
28254
28230
  };
28255
- //# sourceMappingURL=chunk-ZXXLY4RM.js.map
28231
+ //# sourceMappingURL=chunk-MAAMCOAU.js.map