@blade-hq/agent-client 2612.0.0-beta.0 → 2612.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,12 +2,11 @@
2
2
 
3
3
  Blade Agent 的框架无关客户端。浏览器和 Node.js 都能用;用 Vue、Svelte 或自建 UI 的团队直接用这个包,React 团队一般用上层的 `@blade-hq/agent-react`。
4
4
 
5
- 它做四件事:
5
+ 它做三件事:
6
6
 
7
7
  1. **实时会话**(`AgentSession`):把 Socket.IO 协议、历史加载、流式合流、断线重连全部封装掉,你只面对"状态快照 + 动作 + 事件"。
8
8
  2. **登录**:`client.auth.login()` 弹窗授权,用户点一下"许可授权"就拿到访问令牌,不用手工复制粘贴。
9
9
  3. **REST**:类型化会话和模型目录(`client.sessions.*`、`client.models.list()`)。其他长尾接口对照 Swagger 用原生 `fetch` + `client.token` 调用。
10
- 4. **部署端点**:从同源 `config.json` 读取其他 Blade 服务的公开地址,不根据主机名和固定端口猜测拓扑。
11
10
 
12
11
  ```bash
13
12
  npm install @blade-hq/agent-client
@@ -52,27 +51,6 @@ const client = new BladeClient({
52
51
  })
53
52
  ```
54
53
 
55
- ## 部署端点
56
-
57
- Blade 平台前端需要跳转其他服务时,读取当前 origin 的公开配置:
58
-
59
- ```ts
60
- import { loadPlatformEndpoints, resolveServiceUrl } from "@blade-hq/agent-client"
61
-
62
- const endpoints = await loadPlatformEndpoints()
63
- const hubUrl = resolveServiceUrl(endpoints, "hub", "/skills/42")
64
- if (hubUrl) window.open(hubUrl)
65
- ```
66
-
67
- `loadPlatformEndpoints()` 请求 `config.json`,超过 3 秒、网络失败或配置非法时返回空配置;
68
- 调用方应隐藏对应入口。文件只能放浏览器可访问的公开地址,不能写 Docker 服务名、令牌或
69
- 其他内部配置。应用部署在子路径时,通过 `baseUrl` 显式传入部署根路径。
70
- `resolveServiceUrl()` 的 `path` 只接受服务内相对路径;绝对 URL、反斜杠和越出服务
71
- base path 的路径返回 `null`。
72
-
73
- 公开类型为 `PlatformEndpoints`、`PlatformServiceName`、`LoadPlatformEndpointsOptions`;
74
- 需要同步初始化时可直接使用 `EMPTY_PLATFORM_ENDPOINTS`。
75
-
76
54
  ## BladeClient
77
55
 
78
56
  ### 构造
@@ -87,8 +65,6 @@ new BladeClient({
87
65
 
88
66
  高级宿主可通过 `BladeClientOptions.commandTransport(event, payload, send)` 接管带回执的命令传输,例如浏览器插件让后台持有发送请求,面板关闭后仍能等待请求结束并停止任务。返回原始服务端 ack,失败时抛错;不接管的命令调用 `send()` 使用默认 Socket.IO。事件订阅仍使用原 socket。`client.requestCommand(event, payload, timeoutMs)` 是同一通道的低层入口,普通应用继续使用类型化的 `AgentSession` 方法。
89
67
 
90
- 底层 `createSocket` 允许指定 `transports`;MV3 service worker 没有 XMLHttpRequest,可使用 `["websocket"]`。不指定时保持 Socket.IO 默认选择。
91
-
92
68
  SDK 会固定订阅普通聊天所需的完整实时事件。产品内置 Web 的精简/开发者展示模式不属于
93
69
  公共 SDK 契约,也没有对应的构造参数或 Socket.IO 字段。
94
70
 
@@ -272,7 +248,7 @@ session.getState().replay
272
248
  ```
273
249
 
274
250
  不传倍速时用 `DEFAULT_REPLAY_SPEED`;所有创建入口都该用它,免得同一个源对话
275
- 从不同入口开出来速度不一样。
251
+ 从不同入口开出来速度不一样。倍速类型是 `ReplaySpeed`,会话详情里的 `replay_state` 是 `ReplayState`。
276
252
 
277
253
  **连上之后不会自动播——它跟用户对台词**(下面的 `session` 都是第 3 步连上的**回放会话**):
278
254
 
@@ -392,33 +368,6 @@ await client.computers.setEnabled(sessionId, computer.id, false) // 停用
392
368
  `is_primary` 表示这次会话本身就跑在这台电脑上。这种电脑恒为可用,也不能停用——
393
369
  那是会话自己的工作目录所在。
394
370
 
395
- 做电脑选择器时用这几个纯函数,别自己重算状态:
396
-
397
- ```ts
398
- import {
399
- canToggleComputer, computerState, sortComputers,
400
- computerOS, computerPlatformLabel, computerDaemonVersion,
401
- } from "@blade-hq/agent-client"
402
-
403
- sortComputers(computers) // 按接入时间,顺序稳定不随状态变化
404
- computerState(computer) // ComputerState: "primary" | "enabled" | "offline" | "idle"
405
- canToggleComputer(computer) // 主运行时返回 false
406
-
407
- computerOS(computer) // ComputerOS: "macos" | "windows" | "linux" | "unknown"
408
- computerPlatformLabel(computer) // "darwin/arm64"
409
- computerDaemonVersion(computer) // "dev (bc3ad71d1)",未知时是空串
410
- ```
411
-
412
- `sortComputers` **刻意不按在线/可用排序**:那样排看着"手边的在前面",代价是电脑
413
- 上下线、勾选状态一变整个列表就重排,用户正要点的那一项会在手指底下跑掉。改名也
414
- 不会挪位置,新接入的稳定排在末尾。
415
-
416
- `computerOS` 判定的是 daemon 上报的 `runtime.GOOS`,各处自己 `startsWith` 一遍必然会分叉;
417
- 图标怎么画交给界面,这里只回答"是哪一类系统"。
418
-
419
- `computerDaemonVersion` 返回的是服务端存的完整串——dev 构建带 commit,
420
- 因为 dev 的版本号全都是 `dev`,光看它分不出是哪次构建的二进制。**不要在前端另拼一套格式。**
421
-
422
371
  `ComputersResource` 是 `client.computers` 的类型。
423
372
 
424
373
  ## AgentSession
@@ -484,8 +433,6 @@ await chat.refreshQueue() // 手动拉一份权威快照(首次连接与每
484
433
  `chat.getState().queue` 是 `SessionQueueSnapshot`:`{ session_id, revision, paused, pause_reason, items }`。它只会被 revision 更新的快照替换——乱序到达的旧广播不会把新状态顶回去。`items` 只包含 `pending`(待执行)与 `delivering`(等待接收)。
485
434
 
486
435
  - **冲突处理**:`conflict` 表示乐观并发或状态校验失败,服务端快照已自动刷新到本地,此时保留用户草稿并说明原因即可;`ok=false` 且 `snapshot` 为 null(例如鉴权失败)时不要改动本地队列。`queueMessage` 结果未知(ack 超时)时会用同一个 `client_request_id` 重试一次,不会制造第二条。
487
- - **可操作性判定**:`canEditQueuedMessage` / `canCancelQueuedMessage` / `canDeliverQueuedMessage` 只对 `pending` 返回 true;文案用 `queuedMessageStatusLabel` 与 `queuePauseReasonLabel`。
488
- - **自己处理广播**:需要绕过状态机时用 `isSessionQueueSnapshot` + `shouldApplySnapshot` + `EMPTY_SESSION_QUEUE`;解析自定义 ack 用 `parseQueueAck`,返回统一的 `QueueOperationResult`(`QueueAck` 是 ack 的线格式;`code` 是路由失败原因,供调用方决定是否重试)。
489
436
 
490
437
  ### 页面协作:让智能体和你的页面互动
491
438
 
@@ -558,29 +505,7 @@ chat.on("error", (e) => console.error(e.message, e.code))
558
505
 
559
506
  完整事件表见 `AgentSessionEvents` 类型定义(含 `modeChange` / `workspaceChanged` / `artifact` / `notification` / `backgroundTask` / `taskListUpdated` / `rewind` / `replayMismatch` 等)。`toolResult.source` 区分实时结果、首次连接回放和断线重连回放;`on()` 返回取消函数,handler 抛异常只告警、不影响会话。
560
507
 
561
- 分页响应是 `SessionTurnsPage`,其中 `nextBefore: string | null` 是唯一的“还有更早历史”真值。历史页面指令通过独立的 `HistoricalCommand` 日志恢复,不混进展示页。自定义状态容器可复用 `prependOlder`、`replaceWindow` 与 `LiveRevisionState`,但一般直接使用 `AgentSession` 即可。
562
-
563
- ## iframe 嵌入形态:connectEmbedded
564
-
565
- 如果你不是嵌组件,而是把 **Blade 的聊天页面整个用 iframe 嵌进自己系统**,宿主页面用 `connectEmbedded` 拿到同构的协作 API:
566
-
567
- ```ts
568
- import { connectEmbedded } from "@blade-hq/agent-client"
569
-
570
- const chat = connectEmbedded({
571
- iframe: document.querySelector<HTMLIFrameElement>("#blade")!,
572
- allowedOrigins: ["https://blade.example.com"], // 必填:Blade 页面的来源,防伪造
573
- })
574
- chat.onCommand("map.highlight", (payload) => {
575
- const { points } = payload as { points: Array<{ lng: number; lat: number }> }
576
- map.highlight(points)
577
- })
578
- chat.attach("选中点位", { lng: 116.4, lat: 39.9 })
579
- chat.send("这里适合开店吗?")
580
- chat.dispose() // 页面卸载时
581
- ```
582
-
583
- 同页组件形态和 iframe 形态的协作 API 完全一致,业务代码可以原样复用。
508
+ 分页响应是 `SessionTurnsPage`,其中 `nextBefore: string | null` 是唯一的“还有更早历史”真值。历史页面指令通过独立的 `HistoricalCommand` 日志恢复,不混进展示页。
584
509
 
585
510
  ## 长尾 REST:用原生 fetch
586
511
 
@@ -603,15 +528,6 @@ PATCH / query / FormData / AbortSignal 等完整 HTTP 语义(否则不够用
603
528
  > **安全约束**:`client.token` 只应发往 `baseUrl` 同源的接口。不要把它附加到
604
529
  > 第三方域名的请求上——那等于把用户的访问凭据交给别人。
605
530
 
606
- ### 只读轮询退避
607
-
608
- `new PollingBackoff(3000)` 为轮询维护独立退避状态,参数为正常间隔(大于 0、不超过 60 秒)。
609
- 请求成功后调用 `reset()`,失败后调用 `failed(error)`;`waitMs()` 返回剩余等待毫秒数,
610
- `0` 表示可以请求,`false` 表示停止。HTTP 错误应传入保留响应头的 `BladeApiError`。
611
- 401/403 等确定性错误停止,网络/5xx 指数退避带抖动且最高 60 秒;`Retry-After`
612
- 可以要求更长等待,超出浏览器定时器范围时停止。策略自身不发送请求,调度器须传递
613
- AbortSignal、在卸载时停止,并避免将它用于自动重放 POST 等有副作用的操作。
614
-
615
531
  ## headless:一次性问答
616
532
 
617
533
  ```ts
@@ -697,41 +613,16 @@ transformSlashCommand(skillId, prompt, { local: false, installed: false })
697
613
 
698
614
  不传第三个参数时按本地已有处理,和不带这个参数的老用法结果一致。
699
615
 
700
- ### MCP App 卡片
616
+ ## 运行错误说明:userFacingErrorText
701
617
 
702
- MCP 工具可以通过 `_meta.ui` 在消息流里产出交互卡片(`tool_ui` block)。卡片的
703
- 实例、守卫、可见性、身份和终态规则全部收敛在这一份共享判定里——内置 Web 与
704
- SDK 渲染的是同一批卡片,不要自己再写一份判断:
618
+ 运行失败时,服务端通过 `system:error` 推送错误说明,同一段说明也会随失败回合写进历史(回合上的 `error_message`)。自己渲染消息时,实时与历史两条路径都应经过 `userFacingErrorText(message)`:沙盒内存超限(退出码 137)的原始报错会换成统一的友好说明,其余原样返回。`AgentSession` 自带的状态已经做了这一转换,只用 `getState()` 时不需要再调用。
705
619
 
706
620
  ```ts
707
- import {
708
- collectInlineToolUiCards,
709
- collectPreviewToolUiCards,
710
- resolveToolUiCardContent,
711
- buildToolUiCardKey,
712
- isToolUiCard,
713
- } from "@blade-hq/agent-client"
621
+ import { userFacingErrorText } from "@blade-hq/agent-client"
714
622
 
715
- // 按可见性分类:inline 进消息流,preview 交给你的侧栏/面板(也随 toolPreview 事件推送)
716
- const inlineCards = collectInlineToolUiCards(messages) // [{ key, toolCallId, card }]
717
- const previewCards = collectPreviewToolUiCards(messages) // [{ key, toolCall, card, blocks }]
718
-
719
- // 渲染前解析实际内容;archived 留档卡片只用留档 HTML,绝不回退 resourceUri
720
- // (历史恢复/刷新不会因此重放一次 MCP 资源读取)
721
- const resolved = resolveToolUiCardContent(card) // { type: "resource-html" | "resource-uri" | "resource-file", content } | null
722
-
723
- // 文件卡片按 sourcePath、URI 按地址、无来源 HTML 按 toolCallId 去重。
724
- // 宿主可先按会话 workspace 将 sourcePath 归一,和文件树中的身份对齐。
725
- const key = buildToolUiCardKey(toolCallId, resolved.type, resolved.content, card.sourcePath)
623
+ const text = userFacingErrorText(turn.error_message ?? "")
726
624
  ```
727
625
 
728
- `resource-file` 来自 `blade ui --html 文件 --preview`:`content`/`sourcePath` 是文件路径,不是 HTML。打开时通过带鉴权的会话文件接口读取当前文件;历史引用也读取最新文件。每次新工具调用都会发 `toolPreview` 通知文件有更新,宿主仍按路径复用一个页签;同次调用的重复事件不重复发送。已打开的 HTML 应保留当前页面和交互状态,提供醒目的“刷新”按钮,让用户决定何时读取最新内容。内联卡片继续使用 HTML 快照。
729
-
730
- 单个 block 判有效用 `isToolUiCard`(严格守卫:`target`/`height` 缺失、archived 无留档
731
- HTML 一律判无效);`isInternalStatusToolUiCard` 识别内部「阶段进度」卡片(不对用户展示),
732
- `isAppDevToolUiCard` 识别应用开发会话的预览卡。相关类型:`ToolUiCard`、
733
- `ToolUiCardContentType`、`InlineToolUiCardEntry`、`PreviewToolUiCardEntry`。
734
-
735
626
  ## 常见问题
736
627
 
737
628
  | 现象 | 原因与解法 |
@@ -744,39 +635,44 @@ HTML 一律判无效);`isInternalStatusToolUiCard` 识别内部「阶段进
744
635
 
745
636
  更多接入教程(Vue 完整示例、GIS 协作闭环、AI 助手接入指南)见 [public-skills 文档站](https://github.com/blade-hq/public-skills)。
746
637
 
638
+ ## `<blade-chat>` 的挂载式渲染器
639
+
640
+ `<blade-chat>` 与 Vue 接入方拿不到 React,所以区块定制用「挂载式渲染器」:SDK 给一个 DOM 节点和这个区块的数据,你自己把内容挂上去,返回清理函数(或 `{ update, destroy }`,数据变化时原地更新)。
641
+
642
+ ```js
643
+ const chat = document.querySelector("blade-chat")
644
+ chat.renderers = {
645
+ toolCall: {
646
+ // 返回 false 的区块走默认渲染
647
+ match: ({ toolCall }) => toolCall.name === "draw_chart",
648
+ mount(target, { toolCall }) {
649
+ target.textContent = `图表参数:${toolCall.arguments}`
650
+ return () => { target.textContent = "" }
651
+ },
652
+ },
653
+ }
654
+ ```
655
+
656
+ 挂载节点位于 `<blade-chat>` 元素自己的子节点里(通过 `<slot>` 显示在对应位置),所以页面上的普通样式对它生效。可定制的区块与数据形状见 `BladeChatMountRenderers`(`toolCall`、`userMessage`、`assistantText`);相关类型:`MountRenderer`、`MountRendererObject`、`MountResult`、`MountHandle`。Vue 项目用 `@blade-hq/agent-vue` 的 `defineMountRenderer` 直接包装 Vue 组件。
657
+
658
+ ## 第一方内部入口
659
+
660
+ `@blade-hq/agent-client/internal` 是内置 Web、浏览器插件与 `@blade-hq/agent-react` 共用的内部件(状态机细节、判定逻辑、低层通道)。它随包发布,但**不属于公开面**:不写进本文档与 `public-api.md`,版本之间可以随时改动或删除。接入方只用主入口。
661
+
747
662
  ## 附录:公开类型索引
748
663
 
749
664
  完整签名见 [public-api.md](./public-api.md)(由 `scripts/public-api-report.mjs` 生成并在 CI 校验)。
750
665
 
751
- - **客户端与登录**:`BladeClientOptions`、`LoginOptions`、`LoginResult`、`TokenStorageMode`、`UploadProgress`、`BladeApiError`、`AuthResource`、`ProvidersResponse`、`UserInfo`
666
+ - **客户端与登录**:`BladeClient`、`BladeClientOptions`、`UploadProgress`、`BladeApiError`、`LoginOptions`、`LoginResult`、`TokenStorageMode`、`AuthResource`、`ExchangeCodeParams`、`ExchangeCodeResult`、`ProvidersResponse`、`UserInfo`
752
667
  - **SDK 身份**:`SDK_NAME`、`SDK_VERSION`
668
+ - **实时会话**:`AgentSession`、`AgentSessionError`、`AgentSessionEvents`、`AgentSessionEventName`、`SessionState`、`WorkflowRunState`、`WorkflowRunEntry`(`SessionState.workflowRuns` 的形态)、`ConnectionStatus`、`SendOptions`、`AttachAppOptions`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`ReplaySnapshot`
753
669
  - **声明式会话**:`SessionDefinition`、`SolutionDefinition`、`SkillDefinition`、`SkillFile`、`SessionConfig`、`TextFile`、`SessionSetupError`、`SessionSetupStage`
754
- - **会话错误**:`AgentSessionError`(`code` 是服务端路由失败原因,供调用方决定是否重试)
670
+ - **会话消息队列**:`SessionQueueSnapshot`、`QueuedMessage`、`QueuedMessageStatus`、`QueueOperationResult`
671
+ - **页面协作**:`CommandHandler`、`BladeChatMountRenderers`、`MountRenderer`、`MountRendererObject`、`MountResult`、`MountHandle`
672
+ - **会话资源(REST)**:`SessionsResource`、`CreateSessionRequest`、`PaginatedSessionsResult`、`SessionInfo`、`SessionStatus`、`SessionDetail`、`DEFAULT_REPLAY_SPEED`、`ReplaySpeed`、`ReplayState`、`SessionTurnsPage`、`SessionTurnsQuery`、`FileEntry`、`UploadFileEntry`、`UploadFilesOptions`、`AppCliDefinition`、`AppCliAttachment`
755
673
  - **模型目录**:`ModelsResource`、`ModelCatalog`、`ModelOption`
756
- - **聊天分组资源(REST)**:`ChatGroupsResource`、`ChatGroup`(含 `delete` 永久删除);`client.chatGroups`。旧名 `ChatProjectsResource`、`ChatProject`、`client.chatProjects` 与 `chat_project_id` 字段已随分组改名一并移除,接入方请改用 `chatGroups` 与 `chat_group_id`
757
- - **插件目录(REST,无会话)**:`PluginsResource`、`PluginCatalogEntry`(`client.plugins`)。首页这类还没有会话的界面用它读名称、业务名与图标 token
758
- - **账号电脑目录**:`AccountComputer`、`AccountComputerList`(`client.computers.listAccount()`,只读账号事实,不含会话授权)
759
- - **全站访问统计(REST)**:`SiteVisitsResource`、`SiteVisitsSummary`(`client.siteVisits.record()` 上报一次页面访问、`client.siteVisits.summary()` 只读快照)。这两个操作走独立匿名传输:不带 bearer、不触发 401 登录刷新,只依赖匿名访客 Cookie,供内置 Web 同源使用。
760
- - **会话资源(REST)**:`SessionsResource`、`CreateSessionRequest`、`ImportSessionOptions`、`AppCliDefinition`、`AppCliAttachment`、`AttachAppOptions`、`PaginatedSessionsResult`、`GlobalSearchResult`、`GlobalSearchResultItem`、`GlobalSearchConversationResult`、`GlobalSearchFileResult`、`SessionHistory`、`SessionContextStats`、`ResultFeedback`、`ResultFeedbackReason`、`ShareLinkResult`、`FileEntry`、`UploadFileEntry`、`UploadFilesOptions`、`SessionProfile`、`SessionDetail`、`SessionInfo`、`SessionStatus`、`SessionPortMapping`、`ModeId`、`TemplateId`、`PrimarySkillSnapshot`、`PrimarySkillParallelMode`、`PrimarySkillStageSpec`、`PrimarySkillStepSpec`、`SkillEditorTemplateId`、`SessionSearchMatch`
761
- - **会话历史取数**:`SessionTurnsQuery`、`SessionTurnsPage`、`SessionTurnIndex`、`SessionTurnIndexItem`、`isEntryGoneError`(`isEntryGoneError` 区分"这条发言已经不在当前分支上"与"这次没取到":前者说明 `fromEntryId` 定位目标失效,后者只说明本次请求失败)
762
- - **会话回放**:`ReplayState`、`ReplaySpeed`、`ReplayPreview`、`ReplaySnapshot`、`toReplaySnapshot`、`DEFAULT_REPLAY_SPEED`
763
- - **会话状态机**:`SessionHub`、`SessionConnectOptions`、`SessionState`、`SendOptions`、`ConnectionStatus`、`AskUserAnswerData`、`AgentLoopInfo`、`ActiveCompactionState`、`createInitialSessionState`、`AgentSessionEventName`
764
- - **静态历史会话**:`AgentSession.fromTurns(sessionId, turns)` 构造的会话 `isStatic` 为 true——它没有目录接口,宿主拿已加载窗口推导航条目(`turnNavItemsFromMessages`);真实会话不要这么做,timeline 被重写后窗口里还是旧分支的发言,那些 entry id 已经点不到了
765
- - **长会话跨页定位**:`AgentSession.locateEntry(entryId)`(按稳定 `entry_id` 取"从它往后"的窗口)、`AgentSession.cancelPendingLocate()`(作废在途的那次定位;它只中止定位自己的请求,不牵动运行结束 / 重连的权威刷新)。权威刷新(运行结束 / 重连补数 / 翻页之后的对账)不另记状态:一律按**当前窗口第一条发言**取窗口,那条已经不在分支上(404 / 409)时回落最新一页;`sessions.getSessionTurnIndex(sessionId)` 给出可导航的用户发言目录(`SessionTurnIndex` / `SessionTurnIndexItem`),`getSessionTurnsPage({ fromEntryId })` 与它共用同一份分支投影
766
- - **会话消息队列**:`SessionQueueSnapshot`、`QueuedMessage`、`QueuedMessageStatus`、`QueueAck`、`QueueOperationResult`、`EMPTY_SESSION_QUEUE`、`isSessionQueueSnapshot`、`shouldApplySnapshot`、`parseQueueAck`、`canEditQueuedMessage`、`canCancelQueuedMessage`、`canDeliverQueuedMessage`、`queuedMessageStatusLabel`、`queuePauseReasonLabel`
767
- - **页面协作**:`EmbeddedChat`、`EmbeddedChatOptions`、`CommandHandler`、`CommandEnvelope`、`InboundAction`、`InboundEnvelope`、`isCommandEnvelope`、`isInboundEnvelope`
768
- - **流式 wire 事件(自定义渲染用)**:`ContentDelta`、`ToolCallCreated`、`ToolCallArgumentsDelta`、`ToolResultDelta`、`ToolResultDone`、`LlmResponseDone`、`ChatEnd`、`SystemError`、`SessionStatusEvent`。它们描述 socket 上一帧帧到达的内容,只有自己接管流式拼装时才需要
769
- - **消息与投影协议**:`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`ToolBridgeContent`、`CompactionInfo`、`ContextProjectionData`、`ContextProjectionFields`、`ContextDisplayState`、`ContextGroupDisplayState`、`ContextAction`、`ContextSourceInfo`、`MemoryRefInfo`、`ArchivedFileInfo`、`ArchivedToolCallInfo`、`TurnProjection`、`ContentBlock`、`PatchEnvelope`、`MemoryRef`、`PostChatFollowup`、`FinalArtifact`、`ToolCallProjection`、`PendingQuestionRef`、`RunTiming`、`inferToolStatus`、`contextProjectionData`、`getContextDisplayState`、`getContextGroupDisplayState`、`groupAdjacentContextRuns`、`latestPostChatFollowup`、`buildMessageContent`、`normalizeMessageContent`、`isHiddenInternalMessage`、`transformSlashCommand`、`SkillMentionAvailability`、`extractTextAttachments`、`ParsedTextAttachment`、`ParsedTextContext`
770
- - **MCP Apps 留档与卡片判定**:`McpAppData`、`isMcpAppData`、`McpAppContextState`、`McpAppContextUpdate`、`ToolUiCard`、`ToolUiCardContentType`、`InlineToolUiCardEntry`、`PreviewToolUiCardEntry`、`isToolUiCard`、`resolveToolUiCardContent`、`buildToolUiCardKey`、`isInternalStatusToolUiCard`、`isAppDevToolUiCard`、`collectInlineToolUiCards`、`collectPreviewToolUiCards`(`McpAppContextState` / `McpAppContextUpdate` 配合 `sessions.getMcpAppContext` / `sessions.updateMcpAppContext`:App 保存的状态在下一个新运行才进入模型上下文)
771
- - **Solution / 任务协议**:`Solution`、`SolutionAppField`、`SolutionAppState`、`SolutionAppUiConfig`、`SolutionRef`、`PublishedSolutionRef`、`ExistingSolutionRef`、`PreparedSolution`、`PreparedSolutionAsset`、`LayoutType`、`BizRole`、`TaskStatus`、`BackgroundTask`、`BackgroundTaskStopResult`
674
+ - **远程电脑**:`ComputersResource`、`SessionComputer`、`AccountComputer`
772
675
  - **Headless**:`HeadlessResource`、`RunOptions`、`RunResult`、`RunTrace`
773
- - **低层通道(apps/web 等高级集成)**:`createSocket`、`CreateSocketOptions`、`TypedSocket`、`AsrAudioPayload`、`AuthBusyReconnect`、`authBusyRetryDelayMs`、`ClientProjectionBuilder`、`RawEvent`、`acknowledgeTurnEvents`、`hasChatRunEvent`、`acceptedPostChatFollowupCompletesLatestRun`、`reconcileOptimisticUserTurns`、`reconcileHistoricalUserTurns`
774
- ### MCP App 留档
775
-
776
- `McpAppArchive` 是 `client.sessions.getMcpApp(sessionId, sourceId)` 经鉴权返回的归档,包含保存的 HTML 与最新留档输入/结果。`callMcpApp` 在会话 sandbox 内调用该卡片的归档能力;`onMcpAppChanged` 订阅结果变化,返回取消订阅函数。
777
-
778
- 最新调用失败或完成状态未知时,归档同时提供 `previousToolInput` / `previousToolResult`,用于先恢复最后成功的界面再展示错误。读取这些留档不会重新执行工具。
676
+ - **消息**:`ChatMessage`、`MessageContent`、`MessageContentPart`、`TextContentPart`、`ImageUrlContentPart`、`FileContentPart`、`ToolCallInfo`、`MemoryRefInfo`、`getTextContent`、`getImageParts`、`getFileParts`、`contentPreview`、`groupMessagesByLoop`、`chatErrorForDisplay`、`transformSlashCommand`、`SkillMentionAvailability`、`userFacingErrorText`
779
677
 
780
678
  会话列表和详情的 `SessionInfo.initiator` 表示首次发起来源:`ui` 为界面,`sdk` 为 SDK;旧会话缺少可靠记录时为 `unknown`,尚未发起会话时为 `null` 或未提供。它不等同于后台运行标记 `is_headless`,后续继续会话不会改变来源。
781
-
782
- 后台唤醒输入可用 `isBackgroundWakeMessage(message)` 识别,它读取消息的结构化通知 block。自定义 UI 应为这类输入显示说明卡片;`isHiddenInternalMessage` 仍将其视为内部输入,避免作为用户发言或回溯导航点。