@webskill/chatbot 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,12 +1,19 @@
1
- import { AgentLoopConfig, ApprovalScope, BridgeCapabilities, DocxTextExtractor, ExternalSkillProvider, ExternalToolSource, FileSystemProvider, HookRunner, InteractionRequest, InteractionResponse, LifecycleEventInit, LinkedDocumentReader, LlmClient, NetworkPolicy, Page, PageQuery, RenderBlock, RenderResultRequest, RunSnapshot, RunSnapshotListEntry, RuntimePhase, RuntimeRun, ScriptExecutor, SessionStore, SkillCandidateMarker, SkillCatalogEntry, SkillIntegrityGuard, SkillOutcomeReporter, SkillStateGuard, UiBridge, UiSpecDrafts, UiSpecEvent, UiSpecSnapshot, UiSurfaceActionRequest, UiSurfaceActionResponse, UserProfile, UserProfileExport, WebSkillErrorCode, diffUserProfile } from "@webskill/sdk";
1
+ import { AgentLoopConfig, ApprovalScope, BridgeCapabilities, DataSourceInfo, DocxTextExtractor, ExternalSkillProvider, ExternalToolSource, FileSystemProvider, HookRunner, InteractionRequest, InteractionResponse, LifecycleEventInit, LinkedDocumentReader, LlmClient, NetworkPolicy, Page, PageQuery, PdfTextExtractor, RenderBlock, RenderResultRequest, RunSnapshot, RunSnapshotListEntry, RuntimePhase, RuntimeRun, ScriptExecutor, SessionStore, SkillCandidateMarker, SkillCatalogEntry, SkillIntegrityGuard, SkillOutcomeReporter, SkillStateGuard, UiBridge, UiSpecDrafts, UiSpecEvent, UiSpecSnapshot, UiSurfaceActionRequest, UiSurfaceActionResponse, UserProfile, UserProfileExport, WebSkillErrorCode, XlsxTextExtractor, diffUserProfile } from "@webskill/sdk";
2
2
  import { SandboxMode, TypeScriptSupportOptions } from "@webskill/sdk/browser";
3
3
  import { CustomSurfaceActionEvent, ReactBridgeState, SpecInteractionChannel, SurfaceRegistry, UiSurfaceActionEvent } from "@webskill/sdk/ui-react";
4
- import { PageActionPolicy, PagePerceptionPolicy, PerceptionRecord, SkillCandidateSink, TodoItem } from "@webskill/sdk/agent";
4
+ import { DownloadedFileConsent, DownloadedFileReader, PageActionPolicy, PagePerceptionPolicy, PerceptionPagingBudget, PerceptionRecord, SkillCandidateSink, TodoItem } from "@webskill/sdk/agent";
5
5
  import "react";
6
6
  import "react/jsx-runtime";
7
7
  //#region ../ui-kit/src/i18n/types.d.ts
8
8
  /** @stable */
9
9
  type Locale = 'zh' | 'en';
10
+ /**
11
+ * 宿主 / 用户提供的、随界面语言切换的短文案(0.13.0 分册 21 FR-21.1)。
12
+ * SDK 自己的界面文案走 `createI18n` 字典,不用这个类型。
13
+ * 允许只填部分语种,缺的语种由 `resolveLocalizedText` 借用已填的。
14
+ * @experimental
15
+ */
16
+ type LocalizedText = Partial<Record<Locale, string>>;
10
17
  /** 单语言词条:key → 文案(支持 {name} 占位插值) */
11
18
  type LocaleMessages = Record<string, string>;
12
19
  /** 双语字典:zh/en 两个 locale 的键集必须一致(见 assertDictionaryComplete) */
@@ -19,6 +26,37 @@ type InterpolationParams = Record<string, string | number>;
19
26
  /** t(key, params?):查当前 locale 词条并做 {name} 插值 */
20
27
  type TranslateFn<D extends Dictionary = Dictionary> = (key: DictionaryKey<D>, params?: InterpolationParams) => string;
21
28
  //#endregion
29
+ //#region ../core/src/attachment/kind.d.ts
30
+ /**
31
+ * 附件类型判据与文本形态。0.14.0 分册 20 从 `@webskill/chatbot` 迁入:
32
+ * 「用户上传」与「读取下载目录」两条入口必须给出同一结论(AC-20.17)、
33
+ * 产出同一份文本(AC-20.6),而后者住在 `@webskill/agent`,chatbot 依赖 agent,
34
+ * 判据只能落在两者共同的下游。纯字符串运算,无环境依赖。
35
+ */
36
+ /** 附件在模型侧的内容形态(0.6.0 FR-11.2) @experimental */
37
+ type ChatAttachmentKind = 'text' | 'image' | 'file' | 'document-text';
38
+ //#endregion
39
+ //#region ../runtime/src/tools/types.d.ts
40
+ /**
41
+ * 宿主声明的一个数据源的**可公开部分**(0.14.0 分册 19)。
42
+ *
43
+ * `target` 不在这里,且不得被加进来:这条通路的终点是模型上下文,
44
+ * 而「地址不由脚本提供」正是 0.11.0 分册 16 §2.2 授权面的全部依据。
45
+ * @experimental
46
+ */
47
+ interface DataSourceInfo$1 {
48
+ id: string;
49
+ description: string;
50
+ /**
51
+ * 非宿主声明时的出处(0.14.0 分册 21)。缺省即宿主声明,不带标注。
52
+ *
53
+ * 有值意味着 `description` **来自页面**,模型看到的清单里必须随之出现「可能不准确」的标注,
54
+ * 否则一段由站点控制的文本会以宿主口吻进上下文。
55
+ * @experimental
56
+ */
57
+ provenance?: 'page-declared' | 'tool-projection';
58
+ }
59
+ //#endregion
22
60
  //#region ../runtime/src/sandbox/bridgeProtocol.d.ts
23
61
  /**
24
62
  * 能力模式:true 直通 / false 关闭(TOOL_UNSUPPORTED)/ 'require-approval' 调用前强制授权
@@ -40,6 +78,43 @@ type NetworkPolicy$1 = 'deny-all' | 'allow-all' | {
40
78
  allow: string[];
41
79
  };
42
80
  //#endregion
81
+ //#region ../ui-kit/src/runtime-config/quickPrompts.d.ts
82
+ /**
83
+ * 快捷指令可选图标名(0.12.0 分册 21)。
84
+ * 用受控枚举而不是让宿主传组件:SDK 的图标集不进公开契约,
85
+ * 换实现(lucide → 别的)时宿主代码不用动。
86
+ *
87
+ * 0.13.0 分册 17 FR-17.1:真值源从 `@webskill/chatbot` 迁到这里,
88
+ * 让 console 的配置界面也能用同一份枚举;`@webskill/chatbot` 原样 re-export,
89
+ * 公开面逐字不变。
90
+ * @experimental
91
+ */
92
+ type QuickPromptIconName = 'chart' | 'document' | 'report' | 'search' | 'list' | 'bug' | 'test' | 'metric' | 'compare' | 'page' | 'run' | 'warn' | 'sparkles' | 'settings';
93
+ /**
94
+ * 带图标的快捷指令(0.12.0 分册 21)。
95
+ * @experimental
96
+ */
97
+ interface QuickPrompt {
98
+ /**
99
+ * 点击后发出的文本,同时作为按钮可见文案。
100
+ * 0.13.0 分册 21 FR-21.1:改为按语种取值,可只填部分语种。
101
+ */
102
+ text: LocalizedText;
103
+ /** 缺省或取值不在枚举内时按无图标渲染 */
104
+ icon?: QuickPromptIconName;
105
+ }
106
+ /**
107
+ * `RuntimeConfig` 里持久化的快捷指令条目(0.13.0 分册 17)。
108
+ * 比 `QuickPrompt` 多一个稳定 `id`:列表增删改需要它做定位,
109
+ * 用 `text` 当 key 在「两条同文案」时会塌陷。`id` 不进任何发给模型的字符串。
110
+ * @experimental
111
+ */
112
+ interface RuntimeQuickPrompt {
113
+ id: string;
114
+ text: LocalizedText;
115
+ icon?: QuickPromptIconName;
116
+ }
117
+ //#endregion
43
118
  //#region ../ui-kit/src/runtime-config/types.d.ts
44
119
  /**
45
120
  * 运行环境配置模型(P2):console Configure Tab 编辑、chatbot ChatEngine 装配应用,
@@ -73,6 +148,19 @@ interface RuntimeHooksConfig {
73
148
  }
74
149
  /** 浏览器宿主执行器档位;Node 宿主的 in-process/worker/process 由宿主侧扩展展示 */
75
150
  type RuntimeSandboxExecutor = 'auto' | 'blob-worker' | 'iframe-sandbox';
151
+ /**
152
+ * 用户自己声明的取数源(0.14.0 分册 19)。
153
+ *
154
+ * 存在的理由:从别的宿主导出的技能会声明本宿主没有的源 id,没有这一段就永远跑不起来。
155
+ * 它不放宽任何闸门——`url` 照过 `sandbox.remoteUrl` 判定,取数照受 `capabilities.fetchData` 管,
156
+ * 变的只是「谁来写这个地址」:宿主开发者,还是宿主的使用者。
157
+ */
158
+ interface RuntimeDataSourceEntry {
159
+ id: string;
160
+ /** 绝对 http(s) 地址 */
161
+ url: string;
162
+ description: string;
163
+ }
76
164
  interface RuntimeSandboxConfig {
77
165
  executor: RuntimeSandboxExecutor;
78
166
  networkPolicy: NetworkPolicy$1;
@@ -94,6 +182,11 @@ interface RuntimeSandboxConfig {
94
182
  * 所以不受 `toolResultMaxBytes` 约束。
95
183
  */
96
184
  maxDataSourceBytes: number;
185
+ /**
186
+ * 用户声明的取数源(0.14.0 分册 19);缺省空数组 = 只有宿主代码写死的那些。
187
+ * 与宿主源撞 id 时宿主的那条胜出——否则用户配置就能改写宿主的授权面。
188
+ */
189
+ dataSources: RuntimeDataSourceEntry[];
97
190
  /**
98
191
  * 出站 URL 准入策略(`RemoteUrlPolicy` 的可配置部分):技能安装、MCP 端点连接
99
192
  * 这类由宿主发起的取数都按它判定。两项都默认关,即 https-only 且拒绝内网/环回。
@@ -101,6 +194,13 @@ interface RuntimeSandboxConfig {
101
194
  remoteUrl: RuntimeRemoteUrlConfig;
102
195
  /** 浏览器沙箱的 TypeScript 支持;关闭时 `.ts` 脚本按 `TOOL_UNSUPPORTED` 拒绝 */
103
196
  typescript: RuntimeTypeScriptConfig;
197
+ /**
198
+ * 读取用户下载的文件(0.14.0 分册 20)。缺省 `false`。
199
+ *
200
+ * **不放进 `capabilities`**:那张表的语义是三态 `CapabilityMode`(关 / 需批准 / 开),
201
+ * 而本能力的「需批准」是恒定的,放进去会凭空多出一个「开且不批准」的非法组合。
202
+ */
203
+ downloadedFiles: boolean;
104
204
  }
105
205
  /**
106
206
  * 只做类型擦除,不做类型检查。`esbuildUrl` 为绝对 http(s) 地址时按 `remoteUrl` 判定;
@@ -225,6 +325,11 @@ interface RuntimeMultimodalConfig {
225
325
  maxImageBytes: number;
226
326
  /** 附件与取像共用 */
227
327
  maxImagesPerMessage: number;
328
+ /**
329
+ * 页面取像时小于该面积(平方像素)的元素视作工具图标,不占名额(0.13.0 FR-20.4)。
330
+ * `0` 是合法值,意为关闭过滤;只作用于页面取像,不管用户上传的附件。
331
+ */
332
+ minImageArea: number;
228
333
  }
229
334
  /**
230
335
  * 用户画像配置(0.6.0 FR-19.6)。`enabled` 默认**关**(AC-G5):
@@ -270,6 +375,19 @@ interface RuntimeConfig {
270
375
  documentSurface: RuntimeDocumentSurfaceConfig;
271
376
  userProfile: RuntimeUserProfileConfig;
272
377
  skillState: RuntimeSkillStateConfig;
378
+ /**
379
+ * 快捷指令的**唯一权威**(0.13.0 分册 21 FR-21.5)。
380
+ * `ChatbotConfig.quickPrompts` 降级为一次性种子源,不再参与渲染判断。
381
+ */
382
+ quickPrompts: readonly RuntimeQuickPrompt[];
383
+ /**
384
+ * 宿主种子是否已注入过(FR-21.6)。
385
+ * 不得用 `quickPrompts.length === 0` 推断:「从未配置」与「用户删光了」都是空数组,
386
+ * 靠数组本身分不开——这正是 D-17-3 当年绕不过去的地方。
387
+ */
388
+ quickPromptsSeeded: boolean;
389
+ /** 空态与动态指令条最多展示多少条;超出的部分截断。取值 1..{@link MAX_QUICK_PROMPT_LIMIT} */
390
+ quickPromptLimit: number;
273
391
  /** 被用户删掉的自动模型条目 id(FR-14.3):删一次就不该再自己长回来 */
274
392
  dismissedAutoEntries: readonly string[];
275
393
  }
@@ -316,144 +434,457 @@ declare function createLocalStorageRuntimeConfigStore(options?: LocalStorageRunt
316
434
  /** 内存实现:测试、SSR、以及宿主明确不想持久化时使用。 @experimental */
317
435
  declare function createMemoryRuntimeConfigStore(initial?: Partial<RuntimeConfig>): RuntimeConfigStore;
318
436
  //#endregion
319
- //#region src/core/attachmentKind.d.ts
320
- /** 附件在模型侧的内容形态(0.6.0 FR-11.2) @experimental */
321
- type ChatAttachmentKind = 'text' | 'image' | 'file' | 'document-text';
322
- //#endregion
323
- //#region src/core/types.d.ts
437
+ //#region src/core/hostAdapter.d.ts
324
438
  /**
325
- * 治理 port 集合(F1):宿主把 `SkillStatePolicy` 的适配器交给 chatbot,
326
- * 由它接到内部装配的 `WebSkillRuntime` 上。字段名与 `WebSkillRuntimeDeps` 逐个对齐,
327
- * 不做重命名:中间多一层映射只会让宿主多记一套名字。
328
- * @experimental
439
+ * 宿主装配口:chatbot 不感知环境(浏览器/Node),全部能力经此注入。
440
+ * 页面动态技能来源同时是外部工具来源与外部技能提供者(同一对象两个 port)。
441
+ * LLM 配置不在这里——它统一由 `RuntimeConfigStore` 承载(0.5.0 起)。
442
+ * @stable
329
443
  */
330
- interface ChatbotGovernancePorts {
331
- /** `SkillStatePolicy.toSkillStateGuard()`:read/activate/execute 三入口拦截 */
332
- skillStateGuard?: SkillStateGuard;
333
- /** `SkillStatePolicy.toSkillIntegrityGuard(verify)`:激活期验签,失败即隔离 */
334
- skillIntegrityGuard?: SkillIntegrityGuard;
335
- /** `SkillStatePolicy.toSkillOutcomeReporter()`:执行失败计数,达阈值即隔离 */
336
- skillOutcomeReporter?: SkillOutcomeReporter;
337
- /** `SkillStatePolicy.catalogFilter()`:非 active 技能不进路由候选集 */
338
- catalogFilter?: (entries: SkillCatalogEntry[]) => SkillCatalogEntry[] | Promise<SkillCatalogEntry[]>;
444
+ interface ChatbotHostAdapter {
445
+ storage: FileSystemProvider;
446
+ skillRoots: string[];
447
+ pageSkillSource?: ExternalToolSource & ExternalSkillProvider;
448
+ navigation: {
449
+ openConsole(): void;
450
+ /** 跳 console Traces 面板并定位该 run(v1.1;缺省时消息不渲染 View trace 入口) */
451
+ openConsoleTrace?(runId: string): void;
452
+ /** 打开治理面的审批队列并定位该候选(FR-24.2);宿主未接治理面时不提供,入口随之不渲染 */
453
+ openConsoleCandidate?(candidateId: string): void;
454
+ };
455
+ /** 缺省 BrowserWorkerScriptExecutor(@webskill/browser);Node 宿主可注入自己的执行器 */
456
+ executor?: ScriptExecutor;
339
457
  /**
340
- * run 未激活任何技能时的钩子(如 `createMissHook`)。
458
+ * 页面只读感知策略(需求 10)。**只能在这里注入**:启用与否是宿主侧配置,
459
+ * 设置抽屉里没有也不会有开关(FR-10.1)——风险由部署方承担,
460
+ * 不应交给终端用户随手勾选。
461
+ * @experimental
462
+ */
463
+ pagePerception?: PagePerceptionPolicy;
464
+ /**
465
+ * 感知结果的分段预算(0.14.0 分册 22 FR-22.4 / FR-22.8)。
341
466
  *
342
- * 开关存在 `GovernanceFacade.missHook`(属 console),chatbot 读不到也不该依赖它;
343
- * 所以读开关是**宿主**的责任。宿主应传一个**每次触发时才读开关**的闭包,
344
- * 而不是装配时把布尔值算好——`#assemble()` 不是每次 run 都跑,
345
- * 算好了会导致「开着启动 → 中途关闭」不生效(AC-17.11)。
467
+ * `pagePerception` 同一条装配规矩:只能在这里给,设置抽屉里没有开关。
468
+ * **不给即不分段,但地板照样生效**——不开启不等于允许引擎盲切,
469
+ * 超预算时仍然是「读到预算为止 + 一条原位说明」,只是没有续读的入口。
470
+ * @experimental
346
471
  */
347
- onSkillMiss?: (input: {
348
- prompt: string;
349
- run: RuntimeRun;
350
- }) => Promise<void>;
351
- }
352
- /** 分配式交叉:直接写 `信封 & LifecycleEventInit` 会把联合压成一个对象,`phase` 的判别性就没了 */
353
- type WithChatMeta<T> = T extends unknown ? {
354
- type: 'lifecycle';
355
- runId: string;
356
- at: number;
357
- } & T : never;
358
- /**
359
- * 生命周期步进事件:`data` 随 `phase` 判别,与 runtime 的 `LifecycleEvent` 同一套契约。
360
- * 旧的 `Record<string, unknown>` 等于没有契约:消费方只能硬编码键名。
361
- */
362
- type LifecycleChatEvent = WithChatMeta<LifecycleEventInit>;
363
- /**
364
- * 交互渲染框架档位:native(React InteractionCard)/ a2ui(@a2ui/lit Lit 渲染)/
365
- * openui(@openuidev/react-lang Renderer,ui-kit Library)/ vercel(@json-render/react
366
- * Registry 渲染 catalog 声明树)
367
- * @experimental
368
- */
369
- type RendererKind = 'native' | 'a2ui' | 'openui' | 'vercel';
370
- /** assistant 消息所属 run 的一次工具调用(终态:completed/failed) @stable */
371
- interface ChatToolCall {
372
- callId: string;
373
- name: string;
374
- status: 'completed' | 'failed';
375
- /** 参数摘要(JSON 截断 100 字符;trace 重放无 args 时留空,卡片展开详情有则显示) */
376
- args?: string;
377
- /** 执行耗时(trace completed/failed 回填;live 由 started→终态计时) */
378
- durationMs?: number;
472
+ pagePerceptionPaging?: PerceptionPagingBudget;
379
473
  /**
380
- * 开始时刻(epoch ms,0.10.0 UI-UX5 #32)。与思考段按时间穿插需要共同时钟;
381
- * 旧会话消息没有该字段时工具卡片保持原有相对顺序。
474
+ * 页面操作能力(需求 23)。**不注入即完全关闭**,与 `pagePerception` 分开:
475
+ * 可读不等于可操作。同样只能在这里注入——给终端用户一个「打开代操作」的开关
476
+ * 等于把安全边界交给最不了解它的人。
477
+ * @experimental
382
478
  */
383
- at?: number;
479
+ pageActions?: PageActionPolicy;
384
480
  /**
385
- * failed 时的结构化错误码(如 `TOOL_NOT_ALLOWED`)。
386
- * 「被策略拒绝」与「执行失败」在 UI 上是两回事,靠错误码区分而不是解析文案。
481
+ * 读页面链接指向的文档(分册 22)。实现住在 `@webskill/browser`,
482
+ * chatbot 不依赖它 —— 与 `pagePerception` 同一条装配规矩:宿主注入。
483
+ * 不注入即 `read_linked_document` 不注册。
387
484
  */
388
- errorCode?: string;
389
- /** failed 时的错误说明(拒绝时即「被哪条策略拒绝」) */
390
- errorMessage?: string;
391
- }
392
- /** 已落盘的待发送附件(composer 附件适配器产出) @experimental */
393
- interface ChatAttachmentInput {
394
- id: string;
395
- name: string;
396
- contentType: string;
397
- /** 相对 `attachmentsRoot` 的路径 */
398
- path: string;
399
- size: number;
400
- /** 注入模型的内容形态;决定 send 时读文本还是读二进制 */
401
- kind: ChatAttachmentKind;
402
- /** 图片经压缩时的原始字节数,供 UI 显示「3.2 MB → 1.8 MB」(FR-11.3) */
403
- originalSize?: number;
485
+ linkedDocuments?: LinkedDocumentReader;
486
+ /** docx 文本(`extractDocxText`);不注入即 Word 文档明确报「本环境不支持」 */
487
+ docxExtractor?: DocxTextExtractor;
488
+ /** xlsx → 文本(`extractXlsxText`);不注入即 Excel 工作簿明确报「本环境不支持」 */
489
+ xlsxExtractor?: XlsxTextExtractor;
490
+ /**
491
+ * PDF → 文本;**只用于直传被端点拒后的回退**(0.13.0 FR-22.1)。
492
+ * PDF 仍然默认直传,能读的端点拿到的还是原件;不注入即没有回退能力。
493
+ */
494
+ pdfExtractor?: PdfTextExtractor;
495
+ /** 文档读取留痕出口(FR-22.6) */
496
+ documentAudit?: {
497
+ append(event: {
498
+ type: string;
499
+ target: string;
500
+ data?: Record<string, unknown>;
501
+ }): Promise<unknown>;
502
+ };
503
+ /**
504
+ * 读用户本机下载的文件(0.14.0 分册 20)。**不注入即两个工具都不注册**,
505
+ * 与 `sandbox.downloadedFiles` 开关是「与」的关系:宿主没接通路,用户开了也没用。
506
+ *
507
+ * 只收端口,不收策略:授权卡出口、能力开关、模型读图能力、docx/xlsx 抽取器
508
+ * 全在引擎这一侧,宿主自己拼一个策略必然要重复这四项判断。
509
+ * @experimental
510
+ */
511
+ downloads?: {
512
+ reader: DownloadedFileReader;
513
+ /** 「不再询问」的记忆端口;不注入即每次都问 */
514
+ consent?: DownloadedFileConsent;
515
+ };
404
516
  }
405
- /** 随消息持久化的附件元数据 @experimental */
406
- type ChatAttachmentMeta = ChatAttachmentInput;
517
+ //#endregion
518
+ //#region src/core/chatEngine.d.ts
407
519
  /**
408
- * 归并后的显示相位。进行中通道与历史通道共用这一个结构:
409
- * 各存一份正是「运行细节首轮后消失」的根因(需求 17 条目 10-6)。
520
+ * 条目能否真的发请求:云端要有端点或密钥,浏览器内置两者都不需要。
521
+ *
522
+ * 导出给 UI:选择器不用同一份判据的话,用户能选中一个空配置条目,
523
+ * 而引擎静默回退到另一条——界面说在用 A、实际跑的是 B(UI-UX8 D1)。
410
524
  * @experimental
411
525
  */
412
- interface ChatRunPhase {
413
- phase: RuntimePhase;
414
- at: number;
415
- /** 下一个步进到达时回填 */
416
- endedAt?: number;
417
- /** 由结构化 `LifecycleEvent.data` 派生的一句摘要 */
418
- note?: string;
419
- /** fail 相位的具体说明:`reason` 只有七种取值,说不出「哪个上限、哪个模型」 */
420
- detail?: string;
421
- }
422
- /** 本轮发生的一次已提交交互(FR-17.8:提交后表单保留所填值) @experimental */
423
- interface ChatInteractionRecord {
424
- id: string;
425
- request: InteractionRequest;
426
- /** 提交时的表单值;文件类字段已在引擎侧脱敏 */
427
- submittedValues?: unknown;
428
- }
526
+ declare const isLlmEntryUsable: (entry: RuntimeLlmEntry) => boolean;
429
527
  /**
430
- * run 内模型产出的一段思考正文(0.10.0 UI-UX5 #32)。
431
- * 每次模型调用的思考算一段;随消息持久化,重开会话仍能看到。
432
- * 模型不支持思考输出时整个数组缺省——不产空壳卡片。
528
+ * 选中条目 默认条目 首条;命中不可用条目时**回退到下一个可用条目**
529
+ * (0.10.0 复核:选中项失效时宁可静默换用可用模型,也不能把 UI 锁死成
530
+ * 「未配置」死胡同——引擎与 UI 共用同一判据,两边必须同进退)。
531
+ * 全部不可用才 undefined(引擎走内置演示)。
532
+ *
533
+ * 导出给 UI 复用同一判据:composer 的「未配置模型」引导判定必须与引擎的
534
+ * 实际挑选结果一致,否则会出现「UI 说有模型、引擎却走演示档」的错位(0.10.0 UI-UX5 #49-1)。
433
535
  * @experimental
434
536
  */
435
- interface ChatThinking {
436
- text: string;
437
- /** 首个思考增量到达时刻(epoch ms;与工具卡片按时间穿插的排序依据) */
438
- at: number;
537
+ declare function pickUsableLlmEntry(entries: readonly RuntimeLlmEntry[], defaultId: string | undefined, selectedId: string | undefined): RuntimeLlmEntry | undefined;
538
+ /** 默认沙箱执行器的构造参数(adapter.executor 未注入时;executorFactory 替换点可见同一形状) @stable */
539
+ interface SandboxExecutorDeps {
540
+ fs: FileSystemProvider;
541
+ sandbox?: SandboxMode;
542
+ networkPolicy?: NetworkPolicy;
543
+ capabilities?: BridgeCapabilities;
544
+ approvalScope?: ApprovalScope;
545
+ uiBridge?: UiBridge;
546
+ /** 缺省时 `.ts` 脚本按 `TOOL_UNSUPPORTED` 拒绝 */
547
+ typescript?: TypeScriptSupportOptions;
439
548
  }
440
549
  /**
441
- * run 的大模型用量(0.10.0 UI-UX5 #47):随消息持久化,重开会话仍可见。
442
- * 上游不回报 token 用量时整个字段缺省——不显示假数据。
443
- * @experimental
550
+ * 装配时(而非执行时)把 `sandbox.typescript` 转成执行器参数,让配置错误早暴露。
551
+ * 只对绝对 URL 走 `RemoteUrlPolicy`:同源相对路径与打包器 specifier 不是出站请求。
444
552
  */
445
- interface ChatTokenUsage {
446
- inputTokens: number;
447
- outputTokens: number;
448
- /** 本 run 向大模型发送请求的次数(模型调用轮数) */
449
- llmCalls: number;
450
- }
451
553
  /**
452
- * 助手消息的有序内容段(分册 17 FR-17.1):文字与 surface / 结果块按生成顺序排列。
453
- * 冗余记账——删掉本字段消息内容不缺失,只退化成「正文在上、扩展在下」(FR-17.11)。
454
- * @experimental
455
- */
456
- type ChatContentPart = {
554
+ * `RuntimeConfig` 装出沙箱执行器依赖。
555
+ *
556
+ * 主链路与**评估链路**共用这一处(T-17-H):此前评估侧只传 `fs`,
557
+ * 于是评估里跑的技能不受沙箱、网络策略、能力与授权范围约束——
558
+ * 那比「.ts 跑不了」严重得多(设计 17 §1.1a)。
559
+ *
560
+ * @experimental
561
+ */
562
+ declare function sandboxExecutorDeps(fs: FileSystemProvider, rc?: RuntimeConfig, uiBridge?: SandboxExecutorDeps['uiBridge']): SandboxExecutorDeps;
563
+ /** @stable */
564
+ interface ChatEngineOptions {
565
+ llm?: LlmClient;
566
+ loopConfig?: AgentLoopConfig;
567
+ chatRoot?: string;
568
+ /** 运行环境配置存储(P2):#ensureReady 装配时 load()(默认值兜底)并按映射应用 */
569
+ runtimeConfig?: RuntimeConfigStore;
570
+ /** 初始渲染框架档(默认 'native';运行中可 setRenderer 热切换) */
571
+ renderer?: RendererKind;
572
+ /**
573
+ * 注入 `render_ui` 工具,让模型面向 AI Component Catalog 生成声明式 UI。
574
+ *
575
+ * 注入了 `runtimeConfig` 时**以 `RuntimeConfig.agentCapabilities.generativeUi` 为准**,
576
+ * 本字段只在未接配置存储的宿主上生效(否则设置面板里的开关点了不算数)。
577
+ */
578
+ generativeUi?: boolean;
579
+ /** 沙箱执行器替换点(测试注入 spy 断言构造参数;缺省 BrowserWorkerScriptExecutor) */
580
+ executorFactory?: (deps: SandboxExecutorDeps) => ScriptExecutor;
581
+ /**
582
+ * 宿主声明的数据源取数入口(分册 16)。不注入即脚本上下文没有 `fetchData` 这个键。
583
+ *
584
+ * 装配点必须在宿主:策略本体 `DataSourcePolicy` 住在 `@webskill/agent`,
585
+ * 而数据源的目标地址是宿主自己的业务知识,chatbot 无从代为声明。
586
+ * 能力开关 `sandbox.capabilities.fetchData` 缺省关,注入了也还要宿主在配置里打开。
587
+ */
588
+ fetchData?: (sourceId: string, params?: Record<string, unknown>) => Promise<unknown>;
589
+ /**
590
+ * 宿主声明的数据源清单(0.14.0 分册 19),取自 `DataSourcePolicy.publicSources`。
591
+ * 技能声明了本宿主没有的源时,引擎在激活回执里说明缺什么;不注入即不说。
592
+ */
593
+ dataSources?: readonly DataSourceInfo$1[] | (() => readonly DataSourceInfo$1[]);
594
+ /**
595
+ * 会话落盘替换点(缺省 `FsSessionStore`,落在 `<chatRoot>/sessions`)。
596
+ * 宕主换自己的实现(如 IndexedDB)与测试统计端口读写量都走这里。
597
+ */
598
+ sessionStore?: SessionStore<ChatMessage>;
599
+ /**
600
+ * 宿主已注册好钩子的执行器;装配时把 `RuntimeConfig.hooks` 应用到它再交给 runtime。
601
+ * 不注入即不挂钩子(与 0.0.2 行为一致)。
602
+ */
603
+ hooks?: HookRunner;
604
+ /**
605
+ * 治理 port 注入(F1):把 `SkillStatePolicy` 的三个适配器接到本引擎装配的 runtime 上。
606
+ *
607
+ * 不注入即完全关闭,行为与 0.0.2 一致。装配点必须在宿主:chatbot 不能依赖
608
+ * `@webskill/governance`(它是可选治理层,且要求宿主提供治理根与审计存储)。
609
+ *
610
+ * 三个一起给才形成闭环——只给 `skillOutcomeReporter` 会把技能标成 `quarantined`
611
+ * 却仍旧照常路由和执行,降级形同虚设。
612
+ */
613
+ governance?: ChatbotGovernancePorts;
614
+ /**
615
+ * 技能自动生成的候选收货端(需求 12 号)。与 `governance` 同理,装配点在宿主:
616
+ * `@webskill/governance` 的 `createCandidateSink()` 是现成实现。
617
+ *
618
+ * 开关另在 `RuntimeConfig.agentCapabilities.skillGeneration`(默认关);
619
+ * 开关开但未注入本端口时,工具会把 `SKILL_GENERATION_DISABLED` 回给模型。
620
+ */
621
+ skillCandidates?: SkillCandidateSink;
622
+ }
623
+ /**
624
+ * 对话框引擎:装配 WebSkillRuntime + 会话持久化 + 事件分发。
625
+ * RuntimeConfig 的 load() 是异步的,runtime 在首次 send 前懒装配(#ensureReady)。
626
+ * @stable
627
+ */
628
+ declare class ChatEngine {
629
+ #private;
630
+ readonly bridge: ReactBridgeState;
631
+ constructor(adapter: ChatbotHostAdapter, options?: ChatEngineOptions);
632
+ /** 当前待办清单快照(宿主可直读;实时更新订阅 `todo-changed` 事件) */
633
+ get todos(): readonly TodoItem[];
634
+ /** 当前渲染框架档 */
635
+ get renderer(): RendererKind;
636
+ /** 当前会话选中的模型条目 id;未显式切换过时为 undefined(走 `RuntimeConfig.llm.defaultId`) */
637
+ get modelId(): string | undefined;
638
+ /**
639
+ * 切换本会话后续消息使用的模型条目(需求 4)。传 `undefined` 回到配置里的默认项。
640
+ * 重装配 runtime 以换掉客户端;已落盘的消息不受影响。
641
+ */
642
+ setModel(entryId: string | undefined): void;
643
+ /** 会话文件所在目录:「存储未初始化」提示要把路径写给用户看 @experimental */
644
+ get sessionsRoot(): string;
645
+ /** 渲染框架热切换:复合桥按档分发,无需重装配 runtime(会话句柄保留) */
646
+ setRenderer(renderer: RendererKind): void;
647
+ /** 非 native 三档共用的交互通道(Chatbot 的 SpecInteraction 订阅/attach;core 只产出 catalog 节点树) */
648
+ get interactionChannel(): SpecInteractionChannel;
649
+ /** 探测 @a2ui/lit 是否安装(Appearance/设置区 A2UI 档置灰判定) */
650
+ probeA2uiAvailability(): Promise<boolean>;
651
+ onEvent(listener: (event: ChatEvent) => void): () => void;
652
+ /**
653
+ * 配置源变更后调用(LLM 设置 / RuntimeConfigStore 内容变化):丢弃缓存的
654
+ * runtime/llm/会话句柄,下次 send 重新装配(RuntimeConfig 重新 load() 应用)
655
+ */
656
+ reloadConfig(): void;
657
+ /**
658
+ * 技能仓变更后调用(安装/卸载/发布):作废 runtime 缓存的技能目录,下次 send 重新扫描。
659
+ *
660
+ * 比 `reloadConfig()` 轻,因为它不清 `#handles`——那会连带丢掉每个会话的模型上下文。
661
+ * 装技能的界面与对话不在同一个页面时(如扩展的 options 页 vs side panel),
662
+ * 宿主必须自己把变更通知过来,否则新技能要等页面重载才出现在 catalog 里。
663
+ * @experimental
664
+ */
665
+ invalidateSkills(): void;
666
+ /**
667
+ * 会话列表页。归档会话也返回:UI 自己分区展示。
668
+ * `limit` 不给默认值——缺省属于 `SessionStore` 实现,在这里兜底就等于只下推了一半。
669
+ */
670
+ listSessions(options?: PageQuery): Promise<ChatSessionListResult>;
671
+ /** `title` 缺省时会话先无标题,首条消息发出时再按内容补(FR-21.8) */
672
+ createSession(options?: {
673
+ title?: string;
674
+ }): Promise<ChatSessionMeta>;
675
+ /**
676
+ * 选中会话并取**最新**一页历史(页内时间升序)。
677
+ * 返回全量 `ChatMessage[]` 的旧签名已移除:长会话下它强迫每个调用方拿全量。
678
+ */
679
+ selectSession(id: string, options?: PageQuery): Promise<Page<ChatMessage>>;
680
+ /** 向历史方向再取一页;`cursor` 只能来自上一页的 `nextCursor` */
681
+ loadMoreMessages(cursor: string, options?: {
682
+ limit?: number;
683
+ }): Promise<Page<ChatMessage>>;
684
+ deleteSession(id: string): Promise<void>;
685
+ /** 重命名会话:写入 title 并锁定(后续 send 不再用首条消息覆盖) */
686
+ renameSession(id: string, title: string): Promise<void>;
687
+ /** 归档会话(仅标记,消息与 trace 不动) */
688
+ archiveSession(id: string): Promise<void>;
689
+ /** 取消归档 */
690
+ unarchiveSession(id: string): Promise<void>;
691
+ /** 重发语义:取该 user 消息文本重新 send(assistant 应答新起一轮;不重写历史) */
692
+ retry(messageId: string): Promise<void>;
693
+ /**
694
+ * 编辑重发:截断该 user 消息(含自身)之后的持久化历史,再用新文本重跑一轮。
695
+ * runtime session 句柄自带的对话历史不受影响(与 retry 同口径)。
696
+ */
697
+ editAndResend(messageId: string, text: string): Promise<void>;
698
+ /** 从当前会话消息列表删除指定消息并持久化(消息不存在/无当前会话时静默跳过) */
699
+ deleteMessage(messageId: string): Promise<void>;
700
+ /**
701
+ * 驱动当前 session 的一轮 run。同 session 并发由 runtime session handle 内部
702
+ * 队列串行化(此处直接 await);UI 层应在 send 期间禁用输入。
703
+ * 附件按 `attachmentsRoot` 内的路径读回并构造 `LlmContentPart[]`(FR-11.2)。
704
+ */
705
+ send(text: string, attachments?: readonly ChatAttachmentInput[]): Promise<void>;
706
+ /** 附件落盘根目录(composer 附件适配器写入,send 时读回) */
707
+ get attachmentsRoot(): string;
708
+ /** 取消进行中的 run(Composer Stop 按钮);run 未找到/已结束返回 false */
709
+ cancel(runId: string): boolean;
710
+ /**
711
+ * 释放引擎:取消进行中的 run、退订全部事件、丢弃装配缓存。
712
+ * 宿主重挂组件时用它收尾;只是换配置的话用 `reloadConfig()`,不要 dispose。
713
+ */
714
+ dispose(): Promise<void>;
715
+ /** 列出 interrupted run(InterruptedBanner 数据源);版本不受支持的项带 unsupported 标记 */
716
+ listInterrupted(): Promise<RunSnapshotListEntry[]>;
717
+ /**
718
+ * 恢复 interrupted run:等待中的交互重新进入 bridge.pending(UI 复用 InteractionForm),
719
+ * 完成后与 send 同路径(assistant 消息持久化 + run-completed + trace 落盘)。
720
+ */
721
+ resume(runId: string): Promise<void>;
722
+ /** 读取当前画像(FR-19.3:可见) @experimental */
723
+ readUserProfile(): Promise<UserProfile>;
724
+ /** 已记录的行为条数;设置面板用它告诉用户「清除」会删掉什么 @experimental */
725
+ countBehaviorRecords(): Promise<number>;
726
+ /** 删除单条画像结论(FR-19.3:可编辑可删除) @experimental */
727
+ deleteUserProfileEntry(id: string): Promise<UserProfile>;
728
+ /** 清除全部行为记录(FR-19.8)。与清除画像是两个独立操作 @experimental */
729
+ clearBehaviorRecords(): Promise<void>;
730
+ /** 清除提炼出的画像(FR-19.8) @experimental */
731
+ clearUserProfile(): Promise<void>;
732
+ /**
733
+ * 一并清除记录与画像,并销毁加密密钥(FR-19.8:关闭总开关时的「一并清除」)。
734
+ * 密钥留着就等于给残留密文留了一把能解开的钥匙。
735
+ * @experimental
736
+ */
737
+ clearUserProfileData(): Promise<void>;
738
+ /**
739
+ * 手动提炼(FR-19.3)。与会话结束后的自动提炼同一条路径,
740
+ * 区别只在于这里的失败会抛给调用方——用户点了按钮就该看到结果。
741
+ * @experimental
742
+ */
743
+ refineUserProfile(): Promise<UserProfile>;
744
+ /** 导出画像(FR-19.7)。`excludeIds` 来自导出前的审阅界面 @experimental */
745
+ exportUserProfile(excludeIds?: readonly string[]): Promise<UserProfileExport>;
746
+ /** 导入前的差异(FR-19.7):由 UI 展示并确认后才调用 `applyUserProfileImport` @experimental */
747
+ diffUserProfileImport(incoming: UserProfileExport): Promise<ReturnType<typeof diffUserProfile> & {
748
+ origin: string;
749
+ }>;
750
+ /** 确认后落库(FR-19.7) @experimental */
751
+ applyUserProfileImport(incoming: UserProfileExport): Promise<UserProfile>;
752
+ }
753
+ //#endregion
754
+ //#region src/core/types.d.ts
755
+ /**
756
+ * 治理 port 集合(F1):宿主把 `SkillStatePolicy` 的适配器交给 chatbot,
757
+ * 由它接到内部装配的 `WebSkillRuntime` 上。字段名与 `WebSkillRuntimeDeps` 逐个对齐,
758
+ * 不做重命名:中间多一层映射只会让宿主多记一套名字。
759
+ * @experimental
760
+ */
761
+ interface ChatbotGovernancePorts {
762
+ /** `SkillStatePolicy.toSkillStateGuard()`:read/activate/execute 三入口拦截 */
763
+ skillStateGuard?: SkillStateGuard;
764
+ /** `SkillStatePolicy.toSkillIntegrityGuard(verify)`:激活期验签,失败即隔离 */
765
+ skillIntegrityGuard?: SkillIntegrityGuard;
766
+ /** `SkillStatePolicy.toSkillOutcomeReporter()`:执行失败计数,达阈值即隔离 */
767
+ skillOutcomeReporter?: SkillOutcomeReporter;
768
+ /** `SkillStatePolicy.catalogFilter()`:非 active 技能不进路由候选集 */
769
+ catalogFilter?: (entries: SkillCatalogEntry[]) => SkillCatalogEntry[] | Promise<SkillCatalogEntry[]>;
770
+ /**
771
+ * run 未激活任何技能时的钩子(如 `createMissHook`)。
772
+ *
773
+ * 开关存在 `GovernanceFacade.missHook`(属 console),chatbot 读不到也不该依赖它;
774
+ * 所以读开关是**宿主**的责任。宿主应传一个**每次触发时才读开关**的闭包,
775
+ * 而不是装配时把布尔值算好——`#assemble()` 不是每次 run 都跑,
776
+ * 算好了会导致「开着启动 → 中途关闭」不生效(AC-17.11)。
777
+ */
778
+ onSkillMiss?: (input: {
779
+ prompt: string;
780
+ run: RuntimeRun;
781
+ }) => Promise<void>;
782
+ }
783
+ /** 分配式交叉:直接写 `信封 & LifecycleEventInit` 会把联合压成一个对象,`phase` 的判别性就没了 */
784
+ type WithChatMeta<T> = T extends unknown ? {
785
+ type: 'lifecycle';
786
+ runId: string;
787
+ at: number;
788
+ } & T : never;
789
+ /**
790
+ * 生命周期步进事件:`data` 随 `phase` 判别,与 runtime 的 `LifecycleEvent` 同一套契约。
791
+ * 旧的 `Record<string, unknown>` 等于没有契约:消费方只能硬编码键名。
792
+ */
793
+ type LifecycleChatEvent = WithChatMeta<LifecycleEventInit>;
794
+ /**
795
+ * 交互渲染框架档位:native(React InteractionCard)/ a2ui(@a2ui/lit Lit 渲染)/
796
+ * openui(@openuidev/react-lang Renderer,ui-kit Library)/ vercel(@json-render/react
797
+ * Registry 渲染 catalog 声明树)
798
+ * @experimental
799
+ */
800
+ type RendererKind = 'native' | 'a2ui' | 'openui' | 'vercel';
801
+ /** assistant 消息所属 run 的一次工具调用(终态:completed/failed) @stable */
802
+ interface ChatToolCall {
803
+ callId: string;
804
+ name: string;
805
+ status: 'completed' | 'failed';
806
+ /** 参数摘要(JSON 截断 100 字符;trace 重放无 args 时留空,卡片展开详情有则显示) */
807
+ args?: string;
808
+ /** 执行耗时(trace completed/failed 回填;live 由 started→终态计时) */
809
+ durationMs?: number;
810
+ /**
811
+ * 开始时刻(epoch ms,0.10.0 UI-UX5 #32)。与思考段按时间穿插需要共同时钟;
812
+ * 旧会话消息没有该字段时工具卡片保持原有相对顺序。
813
+ */
814
+ at?: number;
815
+ /**
816
+ * failed 时的结构化错误码(如 `TOOL_NOT_ALLOWED`)。
817
+ * 「被策略拒绝」与「执行失败」在 UI 上是两回事,靠错误码区分而不是解析文案。
818
+ */
819
+ errorCode?: string;
820
+ /** failed 时的错误说明(拒绝时即「被哪条策略拒绝」) */
821
+ errorMessage?: string;
822
+ }
823
+ /** 已落盘的待发送附件(composer 附件适配器产出) @experimental */
824
+ interface ChatAttachmentInput {
825
+ id: string;
826
+ name: string;
827
+ contentType: string;
828
+ /** 相对 `attachmentsRoot` 的路径 */
829
+ path: string;
830
+ size: number;
831
+ /** 注入模型的内容形态;决定 send 时读文本还是读二进制 */
832
+ kind: ChatAttachmentKind;
833
+ /** 图片经压缩时的原始字节数,供 UI 显示「3.2 MB → 1.8 MB」(FR-11.3) */
834
+ originalSize?: number;
835
+ }
836
+ /** 随消息持久化的附件元数据 @experimental */
837
+ type ChatAttachmentMeta = ChatAttachmentInput;
838
+ /**
839
+ * 归并后的显示相位。进行中通道与历史通道共用这一个结构:
840
+ * 各存一份正是「运行细节首轮后消失」的根因(需求 17 条目 10-6)。
841
+ * @experimental
842
+ */
843
+ interface ChatRunPhase {
844
+ phase: RuntimePhase;
845
+ at: number;
846
+ /** 下一个步进到达时回填 */
847
+ endedAt?: number;
848
+ /** 由结构化 `LifecycleEvent.data` 派生的一句摘要 */
849
+ note?: string;
850
+ /** fail 相位的具体说明:`reason` 只有七种取值,说不出「哪个上限、哪个模型」 */
851
+ detail?: string;
852
+ }
853
+ /** 本轮发生的一次已提交交互(FR-17.8:提交后表单保留所填值) @experimental */
854
+ interface ChatInteractionRecord {
855
+ id: string;
856
+ request: InteractionRequest;
857
+ /** 提交时的表单值;文件类字段已在引擎侧脱敏 */
858
+ submittedValues?: unknown;
859
+ }
860
+ /**
861
+ * 该 run 内模型产出的一段思考正文(0.10.0 UI-UX5 #32)。
862
+ * 每次模型调用的思考算一段;随消息持久化,重开会话仍能看到。
863
+ * 模型不支持思考输出时整个数组缺省——不产空壳卡片。
864
+ * @experimental
865
+ */
866
+ interface ChatThinking {
867
+ text: string;
868
+ /** 首个思考增量到达时刻(epoch ms;与工具卡片按时间穿插的排序依据) */
869
+ at: number;
870
+ }
871
+ /**
872
+ * 该 run 的大模型用量(0.10.0 UI-UX5 #47):随消息持久化,重开会话仍可见。
873
+ * 上游不回报 token 用量时整个字段缺省——不显示假数据。
874
+ * @experimental
875
+ */
876
+ interface ChatTokenUsage {
877
+ inputTokens: number;
878
+ outputTokens: number;
879
+ /** 本 run 向大模型发送请求的次数(模型调用轮数) */
880
+ llmCalls: number;
881
+ }
882
+ /**
883
+ * 助手消息的有序内容段(分册 17 FR-17.1):文字与 surface / 结果块按生成顺序排列。
884
+ * 冗余记账——删掉本字段消息内容不缺失,只退化成「正文在上、扩展在下」(FR-17.11)。
885
+ * @experimental
886
+ */
887
+ type ChatContentPart = {
457
888
  type: 'text';
458
889
  text: string;
459
890
  at: number;
@@ -618,405 +1049,150 @@ type ChatEvent = {
618
1049
  name: string;
619
1050
  args?: string;
620
1051
  } | {
621
- type: 'tool-failed';
622
- runId: string;
623
- callId: string;
624
- name: string;
625
- args?: string;
626
- errorCode?: string;
627
- } | {
628
- type: 'run-completed';
629
- runId: string;
630
- status: 'completed' | 'failed' | 'cancelled';
631
- output: string;
632
- activeSkillNames: string[];
633
- /** 终止原因对应的稳定错误码(仅非正常结束时):UI 据此分类提示,不再压平为 RUN_FAILED */
634
- code?: WebSkillErrorCode;
635
- } | {
636
- type: 'todo-changed';
637
- runId: string;
638
- items: readonly TodoItem[];
639
- } | {
640
- type: 'page-perceived';
641
- runId: string;
642
- record: PerceptionRecord;
643
- } | {
644
- type: 'interaction-requested';
645
- id: string;
646
- requestType: InteractionRequest['type'];
647
- /** 等待对象的可读名称(表单标题 / 问题正文):等待指示器要说清在等什么(FR-21.3) */
648
- label?: string;
649
- } | {
650
- type: 'interaction-resolved';
651
- id: string;
652
- requestType: InteractionRequest['type'];
653
- cancelled?: boolean;
654
- } | LifecycleChatEvent | {
655
- type: 'session-updated';
656
- session: ChatSessionMeta;
657
- } |
658
- /**
659
- * 会话结束(需求 19 FR-19.3):切换、删除、归档、引擎释放各算一次。
660
- * 用户画像的自动提炼挂在这个事件上——没有它就只能靠定时器猜「聊完了没」。
661
- * @experimental
662
- */
663
- {
664
- type: 'session-ended';
665
- sessionId: string;
666
- reason: 'switched' | 'deleted' | 'archived' | 'closed';
667
- } |
668
- /** 画像提炼完成(需求 19 FR-19.3):设置面板据此刷新列表 @experimental */
669
- {
670
- type: 'user-profile-updated';
671
- profile: UserProfile;
672
- } | {
673
- type: 'warning';
674
- message: string;
675
- } | {
676
- type: 'error';
677
- message: string;
678
- code?: string;
679
- };
680
- /**
681
- * 快捷指令可选图标名(0.12.0 分册 21)。
682
- * 用受控枚举而不是让宿主传组件:SDK 的图标集不进公开契约,
683
- * 换实现(lucide → 别的)时宿主代码不用动。
684
- * @experimental
685
- */
686
- type QuickPromptIconName = 'chart' | 'document' | 'report' | 'search' | 'list' | 'bug' | 'test' | 'metric' | 'compare' | 'page' | 'run' | 'warn' | 'sparkles' | 'settings';
687
- /**
688
- * 带图标的快捷指令(0.12.0 分册 21)。
689
- * @experimental
690
- */
691
- interface QuickPrompt {
692
- /** 点击后发出的文本,同时作为按钮可见文案 */
693
- text: string;
694
- /** 缺省或取值不在枚举内时按无图标渲染 */
695
- icon?: QuickPromptIconName;
696
- }
697
- /** @stable */
698
- interface ChatbotConfig {
699
- /** header 标题,默认 'WebSkill Chat' */
700
- title?: string;
701
- /** 输入框占位文本 */
702
- placeholder?: string;
703
- /** 会话/trace/artifact 存储根,默认 '/chat' */
704
- chatRoot?: string;
705
- /** 覆盖 LLM(缺省走 `RuntimeConfig.llm` → 内置演示 LLM 的选择链) */
706
- llm?: LlmClient;
707
- /** AgentLoop 调参(maxTurns、超时等) */
708
- loopConfig?: AgentLoopConfig;
709
- /**
710
- * 运行环境配置存储(P2):装配时 load() 并应用 loop/interaction/router/streaming/
711
- * renderResult/sandbox/llm 映射;与 console Configure Tab 共用同一 store(宿主接线)
712
- */
713
- runtimeConfig?: RuntimeConfigStore;
714
- /** WelcomeScreen 快捷 prompt 覆盖(缺省用内置双语示例);给字符串即无图标 */
715
- quickPrompts?: readonly (string | QuickPrompt)[];
716
- /**
717
- * 开启后模型多一个 `render_ui` 工具,可面向 AI Component Catalog 直接生成声明式 UI。
718
- * 默认关:工具描述 + 入参 schema 约 34 KB,会计入每一次请求。
719
- * 数字的单一来源是 `@webskill/ui` 的 `catalog/budget.ts`(实测终态 12 744 + 21 470)。
720
- *
721
- * 接了 `runtimeConfig` 时以 `RuntimeConfig.agentCapabilities.generativeUi` 为准
722
- * (设置抽屉里的开关就是它),本字段只在未接配置存储的宿主上生效。
723
- */
724
- generativeUi?: boolean;
725
- /** 宿主注册好钩子的 `HookRunner`;执行策略(超时/严格模式)按 `RuntimeConfig.hooks` 应用 */
726
- hooks?: HookRunner;
727
- /**
728
- * 治理 port 注入(F1):透传给 `ChatEngineOptions.governance`。
729
- * 不注入即完全关闭,行为与 0.0.2 一致。
730
- */
731
- governance?: ChatbotGovernancePorts;
732
- /**
733
- * 技能自动生成的候选收货端(需求 9):透传给 `ChatEngineOptions.skillCandidates`。
734
- * 开关只决定工具进不进列表,候选往哪存由宙主注入;不注入时工具返回
735
- * `SKILL_GENERATION_DISABLED`,不弹确认框、不产生候选。
736
- */
737
- skillCandidates?: SkillCandidateSink;
738
- /**
739
- * 宿主声明的数据源取数入口(分册 16):透传给 `ChatEngineOptions.fetchData`。
740
- * 不注入即脚本上下文没有 `fetchData` 这个键。
741
- *
742
- * **必须是稳定引用**(模块级或 `useMemo`):它进 `ChatEngine` 的 `useMemo`
743
- * 依赖表,每次渲染新建一个箭头函数会把整个引擎重建掉。
744
- */
745
- fetchData?: (sourceId: string, params?: Record<string, unknown>) => Promise<unknown>;
746
- }
747
- //#endregion
748
- //#region src/core/hostAdapter.d.ts
749
- /**
750
- * 宿主装配口:chatbot 不感知环境(浏览器/Node),全部能力经此注入。
751
- * 页面动态技能来源同时是外部工具来源与外部技能提供者(同一对象两个 port)。
752
- * LLM 配置不在这里——它统一由 `RuntimeConfigStore` 承载(0.5.0 起)。
753
- * @stable
754
- */
755
- interface ChatbotHostAdapter {
756
- storage: FileSystemProvider;
757
- skillRoots: string[];
758
- pageSkillSource?: ExternalToolSource & ExternalSkillProvider;
759
- navigation: {
760
- openConsole(): void;
761
- /** 跳 console Traces 面板并定位该 run(v1.1;缺省时消息不渲染 View trace 入口) */
762
- openConsoleTrace?(runId: string): void;
763
- /** 打开治理面的审批队列并定位该候选(FR-24.2);宿主未接治理面时不提供,入口随之不渲染 */
764
- openConsoleCandidate?(candidateId: string): void;
765
- };
766
- /** 缺省 BrowserWorkerScriptExecutor(@webskill/browser);Node 宿主可注入自己的执行器 */
767
- executor?: ScriptExecutor;
768
- /**
769
- * 页面只读感知策略(需求 10)。**只能在这里注入**:启用与否是宿主侧配置,
770
- * 设置抽屉里没有也不会有开关(FR-10.1)——风险由部署方承担,
771
- * 不应交给终端用户随手勾选。
772
- * @experimental
773
- */
774
- pagePerception?: PagePerceptionPolicy;
775
- /**
776
- * 页面操作能力(需求 23)。**不注入即完全关闭**,与 `pagePerception` 分开:
777
- * 可读不等于可操作。同样只能在这里注入——给终端用户一个「打开代操作」的开关
778
- * 等于把安全边界交给最不了解它的人。
779
- * @experimental
780
- */
781
- pageActions?: PageActionPolicy;
782
- /**
783
- * 读页面链接指向的文档(分册 22)。实现住在 `@webskill/browser`,
784
- * 而 chatbot 不依赖它 —— 与 `pagePerception` 同一条装配规矩:宿主注入。
785
- * 不注入即 `read_linked_document` 不注册。
786
- */
787
- linkedDocuments?: LinkedDocumentReader;
788
- /** docx → 文本(`extractDocxText`);不注入即 Word 文档明确报「本环境不支持」 */
789
- docxExtractor?: DocxTextExtractor;
790
- /** 文档读取留痕出口(FR-22.6) */
791
- documentAudit?: {
792
- append(event: {
793
- type: string;
794
- target: string;
795
- data?: Record<string, unknown>;
796
- }): Promise<unknown>;
797
- };
798
- }
799
- //#endregion
800
- //#region src/core/chatEngine.d.ts
801
- /**
802
- * 条目能否真的发请求:云端要有端点或密钥,浏览器内置两者都不需要。
803
- *
804
- * 导出给 UI:选择器不用同一份判据的话,用户能选中一个空配置条目,
805
- * 而引擎静默回退到另一条——界面说在用 A、实际跑的是 B(UI-UX8 D1)。
806
- * @experimental
807
- */
808
- declare const isLlmEntryUsable: (entry: RuntimeLlmEntry) => boolean;
809
- /**
810
- * 选中条目 → 默认条目 → 首条;命中不可用条目时**回退到下一个可用条目**
811
- * (0.10.0 复核:选中项失效时宁可静默换用可用模型,也不能把 UI 锁死成
812
- * 「未配置」死胡同——引擎与 UI 共用同一判据,两边必须同进退)。
813
- * 全部不可用才 undefined(引擎走内置演示)。
814
- *
815
- * 导出给 UI 复用同一判据:composer 的「未配置模型」引导判定必须与引擎的
816
- * 实际挑选结果一致,否则会出现「UI 说有模型、引擎却走演示档」的错位(0.10.0 UI-UX5 #49-1)。
817
- * @experimental
818
- */
819
- declare function pickUsableLlmEntry(entries: readonly RuntimeLlmEntry[], defaultId: string | undefined, selectedId: string | undefined): RuntimeLlmEntry | undefined;
820
- /** 默认沙箱执行器的构造参数(adapter.executor 未注入时;executorFactory 替换点可见同一形状) @stable */
821
- interface SandboxExecutorDeps {
822
- fs: FileSystemProvider;
823
- sandbox?: SandboxMode;
824
- networkPolicy?: NetworkPolicy;
825
- capabilities?: BridgeCapabilities;
826
- approvalScope?: ApprovalScope;
827
- uiBridge?: UiBridge;
828
- /** 缺省时 `.ts` 脚本按 `TOOL_UNSUPPORTED` 拒绝 */
829
- typescript?: TypeScriptSupportOptions;
830
- }
831
- /**
832
- * 装配时(而非执行时)把 `sandbox.typescript` 转成执行器参数,让配置错误早暴露。
833
- * 只对绝对 URL 走 `RemoteUrlPolicy`:同源相对路径与打包器 specifier 不是出站请求。
834
- */
1052
+ type: 'tool-failed';
1053
+ runId: string;
1054
+ callId: string;
1055
+ name: string;
1056
+ args?: string;
1057
+ errorCode?: string;
1058
+ } | {
1059
+ type: 'run-completed';
1060
+ runId: string;
1061
+ status: 'completed' | 'failed' | 'cancelled';
1062
+ output: string;
1063
+ activeSkillNames: string[];
1064
+ /** 终止原因对应的稳定错误码(仅非正常结束时):UI 据此分类提示,不再压平为 RUN_FAILED */
1065
+ code?: WebSkillErrorCode;
1066
+ } | {
1067
+ type: 'todo-changed';
1068
+ runId: string;
1069
+ items: readonly TodoItem[];
1070
+ } | {
1071
+ type: 'page-perceived';
1072
+ runId: string;
1073
+ record: PerceptionRecord;
1074
+ } | {
1075
+ type: 'interaction-requested';
1076
+ id: string;
1077
+ requestType: InteractionRequest['type'];
1078
+ /** 等待对象的可读名称(表单标题 / 问题正文):等待指示器要说清在等什么(FR-21.3) */
1079
+ label?: string;
1080
+ } | {
1081
+ type: 'interaction-resolved';
1082
+ id: string;
1083
+ requestType: InteractionRequest['type'];
1084
+ cancelled?: boolean;
1085
+ } | LifecycleChatEvent | {
1086
+ type: 'session-updated';
1087
+ session: ChatSessionMeta;
1088
+ } |
835
1089
  /**
836
- * `RuntimeConfig` 装出沙箱执行器依赖。
837
- *
838
- * 主链路与**评估链路**共用这一处(T-17-H):此前评估侧只传 `fs`,
839
- * 于是评估里跑的技能不受沙箱、网络策略、能力与授权范围约束——
840
- * 那比「.ts 跑不了」严重得多(设计 17 §1.1a)。
841
- *
1090
+ * 会话结束(需求 19 FR-19.3):切换、删除、归档、引擎释放各算一次。
1091
+ * 用户画像的自动提炼挂在这个事件上——没有它就只能靠定时器猜「聊完了没」。
842
1092
  * @experimental
843
1093
  */
844
- declare function sandboxExecutorDeps(fs: FileSystemProvider, rc?: RuntimeConfig, uiBridge?: SandboxExecutorDeps['uiBridge']): SandboxExecutorDeps;
1094
+ {
1095
+ type: 'session-ended';
1096
+ sessionId: string;
1097
+ reason: 'switched' | 'deleted' | 'archived' | 'closed';
1098
+ } |
1099
+ /** 画像提炼完成(需求 19 FR-19.3):设置面板据此刷新列表 @experimental */
1100
+ {
1101
+ type: 'user-profile-updated';
1102
+ profile: UserProfile;
1103
+ } | {
1104
+ type: 'warning';
1105
+ message: string;
1106
+ } | {
1107
+ type: 'error';
1108
+ message: string;
1109
+ code?: string;
1110
+ };
845
1111
  /** @stable */
846
- interface ChatEngineOptions {
1112
+ interface ChatbotConfig {
1113
+ /** header 标题,默认 'WebSkill Chat' */
1114
+ title?: string;
1115
+ /** 输入框占位文本 */
1116
+ placeholder?: string;
1117
+ /** 会话/trace/artifact 存储根,默认 '/chat' */
1118
+ chatRoot?: string;
1119
+ /** 覆盖 LLM(缺省走 `RuntimeConfig.llm` → 内置演示 LLM 的选择链) */
847
1120
  llm?: LlmClient;
1121
+ /** AgentLoop 调参(maxTurns、超时等) */
848
1122
  loopConfig?: AgentLoopConfig;
849
- chatRoot?: string;
850
- /** 运行环境配置存储(P2):#ensureReady 装配时 load()(默认值兜底)并按映射应用 */
851
- runtimeConfig?: RuntimeConfigStore;
852
- /** 初始渲染框架档(默认 'native';运行中可 setRenderer 热切换) */
853
- renderer?: RendererKind;
854
1123
  /**
855
- * 注入 `render_ui` 工具,让模型面向 AI Component Catalog 生成声明式 UI。
856
- *
857
- * 注入了 `runtimeConfig` 时**以 `RuntimeConfig.agentCapabilities.generativeUi` 为准**,
858
- * 本字段只在未接配置存储的宿主上生效(否则设置面板里的开关点了不算数)。
1124
+ * 运行环境配置存储(P2):装配时 load() 并应用 loop/interaction/router/streaming/
1125
+ * renderResult/sandbox/llm 映射;与 console Configure Tab 共用同一 store(宿主接线)
859
1126
  */
860
- generativeUi?: boolean;
861
- /** 沙箱执行器替换点(测试注入 spy 断言构造参数;缺省 BrowserWorkerScriptExecutor) */
862
- executorFactory?: (deps: SandboxExecutorDeps) => ScriptExecutor;
1127
+ runtimeConfig?: RuntimeConfigStore;
863
1128
  /**
864
- * 宿主声明的数据源取数入口(分册 16)。不注入即脚本上下文没有 `fetchData` 这个键。
1129
+ * WelcomeScreen 快捷 prompt 的**一次性种子**(0.13.0 分册 21 FR-21.5);给字符串即无图标、不分语种。
865
1130
  *
866
- * 装配点必须在宿主:策略本体 `DataSourcePolicy` 住在 `@webskill/agent`,
867
- * 而数据源的目标地址是宿主自己的业务知识,chatbot 无从代为声明。
868
- * 能力开关 `sandbox.capabilities.fetchData` 缺省关,注入了也还要宿主在配置里打开。
1131
+ * 接了 `runtimeConfig` 时,本字段只在该存储**从未种子化过**时被注入一次
1132
+ * (之后 `RuntimeConfig.quickPrompts` 是唯一权威,console 的「快捷指令」页改的就是它);
1133
+ * 用户在 console 里删光清单后本字段**不会**自行回填,除非用户点「恢复宿主默认」。
1134
+ * 未接 `runtimeConfig` 的宿主上,本字段仍是直接的静态清单。
869
1135
  */
870
- fetchData?: (sourceId: string, params?: Record<string, unknown>) => Promise<unknown>;
1136
+ quickPrompts?: readonly (string | QuickPrompt)[];
871
1137
  /**
872
- * 会话落盘替换点(缺省 `FsSessionStore`,落在 `<chatRoot>/sessions`)。
873
- * 宕主换自己的实现(如 IndexedDB)与测试统计端口读写量都走这里。
1138
+ * 按当前上下文动态下发的快捷指令(FR-17.4)。宿主可以随用户所在页面随时换一批。
1139
+ *
1140
+ * 与静态清单**拼接**而不是覆盖(动态在前,同文案去重)——用户在 console 里配的
1141
+ * 不该被宿主惄惄吞掉。不同于静态清单,它在**对话进行中**也会渲染(FR-17.6)。
1142
+ * @experimental
874
1143
  */
875
- sessionStore?: SessionStore<ChatMessage>;
1144
+ dynamicQuickPrompts?: readonly (string | QuickPrompt)[];
876
1145
  /**
877
- * 宿主已注册好钩子的执行器;装配时把 `RuntimeConfig.hooks` 应用到它再交给 runtime
878
- * 不注入即不挂钩子(与 0.0.2 行为一致)。
1146
+ * 开启后模型多一个 `render_ui` 工具,可面向 AI Component Catalog 直接生成声明式 UI
1147
+ * 默认关:工具描述 + 入参 schema 约 34 KB,会计入每一次请求。
1148
+ * 数字的单一来源是 `@webskill/ui` 的 `catalog/budget.ts`(实测终态 12 744 + 21 470)。
1149
+ *
1150
+ * 接了 `runtimeConfig` 时以 `RuntimeConfig.agentCapabilities.generativeUi` 为准
1151
+ * (设置抽屉里的开关就是它),本字段只在未接配置存储的宿主上生效。
879
1152
  */
1153
+ generativeUi?: boolean;
1154
+ /** 宿主注册好钩子的 `HookRunner`;执行策略(超时/严格模式)按 `RuntimeConfig.hooks` 应用 */
880
1155
  hooks?: HookRunner;
881
1156
  /**
882
- * 治理 port 注入(F1):把 `SkillStatePolicy` 的三个适配器接到本引擎装配的 runtime 上。
883
- *
884
- * 不注入即完全关闭,行为与 0.0.2 一致。装配点必须在宿主:chatbot 不能依赖
885
- * `@webskill/governance`(它是可选治理层,且要求宿主提供治理根与审计存储)。
886
- *
887
- * 三个一起给才形成闭环——只给 `skillOutcomeReporter` 会把技能标成 `quarantined`
888
- * 却仍旧照常路由和执行,降级形同虚设。
1157
+ * 治理 port 注入(F1):透传给 `ChatEngineOptions.governance`。
1158
+ * 不注入即完全关闭,行为与 0.0.2 一致。
889
1159
  */
890
1160
  governance?: ChatbotGovernancePorts;
891
1161
  /**
892
- * 技能自动生成的候选收货端(需求 12 号)。与 `governance` 同理,装配点在宿主:
893
- * `@webskill/governance` 的 `createCandidateSink()` 是现成实现。
894
- *
895
- * 开关另在 `RuntimeConfig.agentCapabilities.skillGeneration`(默认关);
896
- * 开关开但未注入本端口时,工具会把 `SKILL_GENERATION_DISABLED` 回给模型。
1162
+ * 技能自动生成的候选收货端(需求 9):透传给 `ChatEngineOptions.skillCandidates`。
1163
+ * 开关只决定工具进不进列表,候选往哪存由宙主注入;不注入时工具返回
1164
+ * `SKILL_GENERATION_DISABLED`,不弹确认框、不产生候选。
897
1165
  */
898
1166
  skillCandidates?: SkillCandidateSink;
899
- }
900
- /**
901
- * 对话框引擎:装配 WebSkillRuntime + 会话持久化 + 事件分发。
902
- * RuntimeConfig 的 load() 是异步的,runtime 在首次 send 前懒装配(#ensureReady)。
903
- * @stable
904
- */
905
- declare class ChatEngine {
906
- #private;
907
- readonly bridge: ReactBridgeState;
908
- constructor(adapter: ChatbotHostAdapter, options?: ChatEngineOptions);
909
- /** 当前待办清单快照(宿主可直读;实时更新订阅 `todo-changed` 事件) */
910
- get todos(): readonly TodoItem[];
911
- /** 当前渲染框架档 */
912
- get renderer(): RendererKind;
913
- /** 当前会话选中的模型条目 id;未显式切换过时为 undefined(走 `RuntimeConfig.llm.defaultId`) */
914
- get modelId(): string | undefined;
915
- /**
916
- * 切换本会话后续消息使用的模型条目(需求 4)。传 `undefined` 回到配置里的默认项。
917
- * 重装配 runtime 以换掉客户端;已落盘的消息不受影响。
918
- */
919
- setModel(entryId: string | undefined): void;
920
- /** 会话文件所在目录:「存储未初始化」提示要把路径写给用户看 @experimental */
921
- get sessionsRoot(): string;
922
- /** 渲染框架热切换:复合桥按档分发,无需重装配 runtime(会话句柄保留) */
923
- setRenderer(renderer: RendererKind): void;
924
- /** 非 native 三档共用的交互通道(Chatbot 的 SpecInteraction 订阅/attach;core 只产出 catalog 节点树) */
925
- get interactionChannel(): SpecInteractionChannel;
926
- /** 探测 @a2ui/lit 是否安装(Appearance/设置区 A2UI 档置灰判定) */
927
- probeA2uiAvailability(): Promise<boolean>;
928
- onEvent(listener: (event: ChatEvent) => void): () => void;
929
- /**
930
- * 配置源变更后调用(LLM 设置 / RuntimeConfigStore 内容变化):丢弃缓存的
931
- * runtime/llm/会话句柄,下次 send 重新装配(RuntimeConfig 重新 load() 应用)
932
- */
933
- reloadConfig(): void;
934
- /**
935
- * 会话列表页。归档会话也返回:UI 自己分区展示。
936
- * `limit` 不给默认值——缺省属于 `SessionStore` 实现,在这里兜底就等于只下推了一半。
937
- */
938
- listSessions(options?: PageQuery): Promise<ChatSessionListResult>;
939
- /** `title` 缺省时会话先无标题,首条消息发出时再按内容补(FR-21.8) */
940
- createSession(options?: {
941
- title?: string;
942
- }): Promise<ChatSessionMeta>;
943
- /**
944
- * 选中会话并取**最新**一页历史(页内时间升序)。
945
- * 返回全量 `ChatMessage[]` 的旧签名已移除:长会话下它强迫每个调用方拿全量。
946
- */
947
- selectSession(id: string, options?: PageQuery): Promise<Page<ChatMessage>>;
948
- /** 向历史方向再取一页;`cursor` 只能来自上一页的 `nextCursor` */
949
- loadMoreMessages(cursor: string, options?: {
950
- limit?: number;
951
- }): Promise<Page<ChatMessage>>;
952
- deleteSession(id: string): Promise<void>;
953
- /** 重命名会话:写入 title 并锁定(后续 send 不再用首条消息覆盖) */
954
- renameSession(id: string, title: string): Promise<void>;
955
- /** 归档会话(仅标记,消息与 trace 不动) */
956
- archiveSession(id: string): Promise<void>;
957
- /** 取消归档 */
958
- unarchiveSession(id: string): Promise<void>;
959
- /** 重发语义:取该 user 消息文本重新 send(assistant 应答新起一轮;不重写历史) */
960
- retry(messageId: string): Promise<void>;
961
- /**
962
- * 编辑重发:截断该 user 消息(含自身)之后的持久化历史,再用新文本重跑一轮。
963
- * runtime session 句柄自带的对话历史不受影响(与 retry 同口径)。
964
- */
965
- editAndResend(messageId: string, text: string): Promise<void>;
966
- /** 从当前会话消息列表删除指定消息并持久化(消息不存在/无当前会话时静默跳过) */
967
- deleteMessage(messageId: string): Promise<void>;
968
- /**
969
- * 驱动当前 session 的一轮 run。同 session 并发由 runtime session handle 内部
970
- * 队列串行化(此处直接 await);UI 层应在 send 期间禁用输入。
971
- * 附件按 `attachmentsRoot` 内的路径读回并构造 `LlmContentPart[]`(FR-11.2)。
972
- */
973
- send(text: string, attachments?: readonly ChatAttachmentInput[]): Promise<void>;
974
- /** 附件落盘根目录(composer 附件适配器写入,send 时读回) */
975
- get attachmentsRoot(): string;
976
- /** 取消进行中的 run(Composer Stop 按钮);run 未找到/已结束返回 false */
977
- cancel(runId: string): boolean;
978
- /**
979
- * 释放引擎:取消进行中的 run、退订全部事件、丢弃装配缓存。
980
- * 宿主重挂组件时用它收尾;只是换配置的话用 `reloadConfig()`,不要 dispose。
981
- */
982
- dispose(): Promise<void>;
983
- /** 列出 interrupted run(InterruptedBanner 数据源);版本不受支持的项带 unsupported 标记 */
984
- listInterrupted(): Promise<RunSnapshotListEntry[]>;
985
1167
  /**
986
- * 恢复 interrupted run:等待中的交互重新进入 bridge.pending(UI 复用 InteractionForm),
987
- * 完成后与 send 同路径(assistant 消息持久化 + run-completed + trace 落盘)。
1168
+ * 宿主声明的数据源取数入口(分册 16):透传给 `ChatEngineOptions.fetchData`。
1169
+ * 不注入即脚本上下文没有 `fetchData` 这个键。
1170
+ *
1171
+ * **必须是稳定引用**(模块级或 `useMemo`):它进 `ChatEngine` 的 `useMemo`
1172
+ * 依赖表,每次渲染新建一个箭头函数会把整个引擎重建掉。
988
1173
  */
989
- resume(runId: string): Promise<void>;
990
- /** 读取当前画像(FR-19.3:可见) @experimental */
991
- readUserProfile(): Promise<UserProfile>;
992
- /** 已记录的行为条数;设置面板用它告诉用户「清除」会删掉什么 @experimental */
993
- countBehaviorRecords(): Promise<number>;
994
- /** 删除单条画像结论(FR-19.3:可编辑可删除) @experimental */
995
- deleteUserProfileEntry(id: string): Promise<UserProfile>;
996
- /** 清除全部行为记录(FR-19.8)。与清除画像是两个独立操作 @experimental */
997
- clearBehaviorRecords(): Promise<void>;
998
- /** 清除提炼出的画像(FR-19.8) @experimental */
999
- clearUserProfile(): Promise<void>;
1174
+ fetchData?: (sourceId: string, params?: Record<string, unknown>) => Promise<unknown>;
1000
1175
  /**
1001
- * 一并清除记录与画像,并销毁加密密钥(FR-19.8:关闭总开关时的「一并清除」)。
1002
- * 密钥留着就等于给残留密文留了一把能解开的钥匙。
1003
- * @experimental
1176
+ * 宿主声明的数据源清单(0.14.0 分册 19):透传给 `ChatEngineOptions.dataSources`。
1177
+ * 用 `DataSourcePolicy.publicSources` 取,不要改传 `sources`——后者带 `target`,
1178
+ * 结构子类型让这个赋值的类型检查能过,接口地址就静默进了模型上下文。
1179
+ *
1180
+ * **必须是稳定引用**(模块级或 `useMemo`):同 `fetchData`,它进 `ChatEngine` 的依赖表。
1181
+ * 源清单随用户配置变动的宿主传函数形式,引擎在每次激活时求值,改配置无须重建引擎。
1004
1182
  */
1005
- clearUserProfileData(): Promise<void>;
1183
+ dataSources?: readonly DataSourceInfo[] | (() => readonly DataSourceInfo[]);
1006
1184
  /**
1007
- * 手动提炼(FR-19.3)。与会话结束后的自动提炼同一条路径,
1008
- * 区别只在于这里的失败会抛给调用方——用户点了按钮就该看到结果。
1185
+ * 沙箱执行器替换点(分册 12):透传给 `ChatEngineOptions.executorFactory`。
1186
+ *
1187
+ * 需要自定义执行器的宿主**必须走这里,而不是 `ChatbotHostAdapter.executor`**:
1188
+ * 后者是一个构造期就定死的实例,装配时会整个跳过 `RuntimeConfig.sandbox` 映射,
1189
+ * 于是设置面板里的能力开关、网络策略、TypeScript 与授权范围全部点了不算数。
1190
+ * 本替换点拿到的 `deps` 已由引擎按当前配置算好,宿主只需覆盖自己要换的那几项。
1191
+ *
1192
+ * **必须是稳定引用**(模块级或 `useMemo`):同 `fetchData`,它进 `ChatEngine` 的依赖表。
1009
1193
  * @experimental
1010
1194
  */
1011
- refineUserProfile(): Promise<UserProfile>;
1012
- /** 导出画像(FR-19.7)。`excludeIds` 来自导出前的审阅界面 @experimental */
1013
- exportUserProfile(excludeIds?: readonly string[]): Promise<UserProfileExport>;
1014
- /** 导入前的差异(FR-19.7):由 UI 展示并确认后才调用 `applyUserProfileImport` @experimental */
1015
- diffUserProfileImport(incoming: UserProfileExport): Promise<ReturnType<typeof diffUserProfile> & {
1016
- origin: string;
1017
- }>;
1018
- /** 确认后落库(FR-19.7) @experimental */
1019
- applyUserProfileImport(incoming: UserProfileExport): Promise<UserProfile>;
1195
+ executorFactory?: (deps: SandboxExecutorDeps) => ScriptExecutor;
1020
1196
  }
1021
1197
  //#endregion
1022
1198
  //#region src/core/interactionBridge.d.ts
@@ -1123,6 +1299,9 @@ declare const chatbotDictionary: {
1123
1299
  'app.title': string;
1124
1300
  'header.sessions': string;
1125
1301
  'header.settings': string;
1302
+ 'header.dock': string;
1303
+ 'header.undock': string;
1304
+ 'header.close': string;
1126
1305
  'header.console': string;
1127
1306
  'header.theme.light': string;
1128
1307
  'header.theme.dark': string;
@@ -1168,10 +1347,6 @@ declare const chatbotDictionary: {
1168
1347
  'welcome.capability.transparency.title': string;
1169
1348
  'welcome.capability.transparency.description': string;
1170
1349
  'welcome.quickPrompts': string;
1171
- 'welcome.prompt.1': string;
1172
- 'welcome.prompt.2': string;
1173
- 'welcome.prompt.3': string;
1174
- 'welcome.prompt.4': string;
1175
1350
  'message.copy': string;
1176
1351
  'message.copied': string;
1177
1352
  'message.retry': string;
@@ -1257,11 +1432,20 @@ declare const chatbotDictionary: {
1257
1432
  'interaction.pageAction.click': string;
1258
1433
  'interaction.pageAction.fill': string;
1259
1434
  'interaction.pageAction.submit': string;
1435
+ 'interaction.pageAction.select': string;
1436
+ 'interaction.pageAction.set': string;
1437
+ 'interaction.pageAction.attach': string;
1260
1438
  'interaction.pageAction.role.click': string;
1261
1439
  'interaction.pageAction.role.fill': string;
1262
1440
  'interaction.pageAction.role.submit': string;
1441
+ 'interaction.pageAction.role.select': string;
1442
+ 'interaction.pageAction.role.set': string;
1443
+ 'interaction.pageAction.role.attach': string;
1444
+ 'interaction.pageAction.remember': string;
1263
1445
  'interaction.pageAction.frame': string;
1264
1446
  'interaction.pageAction.elevated': string;
1447
+ 'interaction.downloadedFile.file': string;
1448
+ 'interaction.downloadedFile.remember': string;
1265
1449
  'interaction.traceEvidence.title': string;
1266
1450
  'interaction.traceEvidence.columnDraft': string;
1267
1451
  'interaction.traceEvidence.columnTrace': string;
@@ -1326,9 +1510,6 @@ declare const chatbotDictionary: {
1326
1510
  'composer.noModel.description': string;
1327
1511
  'composer.noModel.configure': string;
1328
1512
  'capability.group': string;
1329
- 'composer.pageCapture': string;
1330
- 'composer.pageCapture.disabled.setting': string;
1331
- 'composer.pageCapture.disabled.model': string;
1332
1513
  'composer.addAttachment.imagesOff': string;
1333
1514
  'composer.addAttachment.modelNoImages': string;
1334
1515
  'attachment.imagesDropped': string;
@@ -1479,6 +1660,9 @@ declare const chatbotDictionary: {
1479
1660
  'app.title': string;
1480
1661
  'header.sessions': string;
1481
1662
  'header.settings': string;
1663
+ 'header.dock': string;
1664
+ 'header.undock': string;
1665
+ 'header.close': string;
1482
1666
  'header.console': string;
1483
1667
  'header.theme.light': string;
1484
1668
  'header.theme.dark': string;
@@ -1524,10 +1708,6 @@ declare const chatbotDictionary: {
1524
1708
  'welcome.capability.transparency.title': string;
1525
1709
  'welcome.capability.transparency.description': string;
1526
1710
  'welcome.quickPrompts': string;
1527
- 'welcome.prompt.1': string;
1528
- 'welcome.prompt.2': string;
1529
- 'welcome.prompt.3': string;
1530
- 'welcome.prompt.4': string;
1531
1711
  'message.copy': string;
1532
1712
  'message.copied': string;
1533
1713
  'message.edit': string;
@@ -1613,11 +1793,20 @@ declare const chatbotDictionary: {
1613
1793
  'interaction.pageAction.click': string;
1614
1794
  'interaction.pageAction.fill': string;
1615
1795
  'interaction.pageAction.submit': string;
1796
+ 'interaction.pageAction.select': string;
1797
+ 'interaction.pageAction.set': string;
1798
+ 'interaction.pageAction.attach': string;
1616
1799
  'interaction.pageAction.role.click': string;
1617
1800
  'interaction.pageAction.role.fill': string;
1618
1801
  'interaction.pageAction.role.submit': string;
1802
+ 'interaction.pageAction.role.select': string;
1803
+ 'interaction.pageAction.role.set': string;
1804
+ 'interaction.pageAction.role.attach': string;
1805
+ 'interaction.pageAction.remember': string;
1619
1806
  'interaction.pageAction.frame': string;
1620
1807
  'interaction.pageAction.elevated': string;
1808
+ 'interaction.downloadedFile.file': string;
1809
+ 'interaction.downloadedFile.remember': string;
1621
1810
  'interaction.traceEvidence.title': string;
1622
1811
  'interaction.traceEvidence.columnDraft': string;
1623
1812
  'interaction.traceEvidence.columnTrace': string;
@@ -1682,9 +1871,6 @@ declare const chatbotDictionary: {
1682
1871
  'composer.noModel.description': string;
1683
1872
  'composer.noModel.configure': string;
1684
1873
  'capability.group': string;
1685
- 'composer.pageCapture': string;
1686
- 'composer.pageCapture.disabled.setting': string;
1687
- 'composer.pageCapture.disabled.model': string;
1688
1874
  'composer.addAttachment.imagesOff': string;
1689
1875
  'composer.addAttachment.modelNoImages': string;
1690
1876
  'attachment.imagesDropped': string;
@@ -1838,6 +2024,9 @@ declare const useT: () => TranslateFn<{
1838
2024
  'app.title': string;
1839
2025
  'header.sessions': string;
1840
2026
  'header.settings': string;
2027
+ 'header.dock': string;
2028
+ 'header.undock': string;
2029
+ 'header.close': string;
1841
2030
  'header.console': string;
1842
2031
  'header.theme.light': string;
1843
2032
  'header.theme.dark': string;
@@ -1883,10 +2072,6 @@ declare const useT: () => TranslateFn<{
1883
2072
  'welcome.capability.transparency.title': string;
1884
2073
  'welcome.capability.transparency.description': string;
1885
2074
  'welcome.quickPrompts': string;
1886
- 'welcome.prompt.1': string;
1887
- 'welcome.prompt.2': string;
1888
- 'welcome.prompt.3': string;
1889
- 'welcome.prompt.4': string;
1890
2075
  'message.copy': string;
1891
2076
  'message.copied': string;
1892
2077
  'message.retry': string;
@@ -1972,11 +2157,20 @@ declare const useT: () => TranslateFn<{
1972
2157
  'interaction.pageAction.click': string;
1973
2158
  'interaction.pageAction.fill': string;
1974
2159
  'interaction.pageAction.submit': string;
2160
+ 'interaction.pageAction.select': string;
2161
+ 'interaction.pageAction.set': string;
2162
+ 'interaction.pageAction.attach': string;
1975
2163
  'interaction.pageAction.role.click': string;
1976
2164
  'interaction.pageAction.role.fill': string;
1977
2165
  'interaction.pageAction.role.submit': string;
2166
+ 'interaction.pageAction.role.select': string;
2167
+ 'interaction.pageAction.role.set': string;
2168
+ 'interaction.pageAction.role.attach': string;
2169
+ 'interaction.pageAction.remember': string;
1978
2170
  'interaction.pageAction.frame': string;
1979
2171
  'interaction.pageAction.elevated': string;
2172
+ 'interaction.downloadedFile.file': string;
2173
+ 'interaction.downloadedFile.remember': string;
1980
2174
  'interaction.traceEvidence.title': string;
1981
2175
  'interaction.traceEvidence.columnDraft': string;
1982
2176
  'interaction.traceEvidence.columnTrace': string;
@@ -2041,9 +2235,6 @@ declare const useT: () => TranslateFn<{
2041
2235
  'composer.noModel.description': string;
2042
2236
  'composer.noModel.configure': string;
2043
2237
  'capability.group': string;
2044
- 'composer.pageCapture': string;
2045
- 'composer.pageCapture.disabled.setting': string;
2046
- 'composer.pageCapture.disabled.model': string;
2047
2238
  'composer.addAttachment.imagesOff': string;
2048
2239
  'composer.addAttachment.modelNoImages': string;
2049
2240
  'attachment.imagesDropped': string;
@@ -2194,6 +2385,9 @@ declare const useT: () => TranslateFn<{
2194
2385
  'app.title': string;
2195
2386
  'header.sessions': string;
2196
2387
  'header.settings': string;
2388
+ 'header.dock': string;
2389
+ 'header.undock': string;
2390
+ 'header.close': string;
2197
2391
  'header.console': string;
2198
2392
  'header.theme.light': string;
2199
2393
  'header.theme.dark': string;
@@ -2239,10 +2433,6 @@ declare const useT: () => TranslateFn<{
2239
2433
  'welcome.capability.transparency.title': string;
2240
2434
  'welcome.capability.transparency.description': string;
2241
2435
  'welcome.quickPrompts': string;
2242
- 'welcome.prompt.1': string;
2243
- 'welcome.prompt.2': string;
2244
- 'welcome.prompt.3': string;
2245
- 'welcome.prompt.4': string;
2246
2436
  'message.copy': string;
2247
2437
  'message.copied': string;
2248
2438
  'message.edit': string;
@@ -2328,11 +2518,20 @@ declare const useT: () => TranslateFn<{
2328
2518
  'interaction.pageAction.click': string;
2329
2519
  'interaction.pageAction.fill': string;
2330
2520
  'interaction.pageAction.submit': string;
2521
+ 'interaction.pageAction.select': string;
2522
+ 'interaction.pageAction.set': string;
2523
+ 'interaction.pageAction.attach': string;
2331
2524
  'interaction.pageAction.role.click': string;
2332
2525
  'interaction.pageAction.role.fill': string;
2333
2526
  'interaction.pageAction.role.submit': string;
2527
+ 'interaction.pageAction.role.select': string;
2528
+ 'interaction.pageAction.role.set': string;
2529
+ 'interaction.pageAction.role.attach': string;
2530
+ 'interaction.pageAction.remember': string;
2334
2531
  'interaction.pageAction.frame': string;
2335
2532
  'interaction.pageAction.elevated': string;
2533
+ 'interaction.downloadedFile.file': string;
2534
+ 'interaction.downloadedFile.remember': string;
2336
2535
  'interaction.traceEvidence.title': string;
2337
2536
  'interaction.traceEvidence.columnDraft': string;
2338
2537
  'interaction.traceEvidence.columnTrace': string;
@@ -2397,9 +2596,6 @@ declare const useT: () => TranslateFn<{
2397
2596
  'composer.noModel.description': string;
2398
2597
  'composer.noModel.configure': string;
2399
2598
  'capability.group': string;
2400
- 'composer.pageCapture': string;
2401
- 'composer.pageCapture.disabled.setting': string;
2402
- 'composer.pageCapture.disabled.model': string;
2403
2599
  'composer.addAttachment.imagesOff': string;
2404
2600
  'composer.addAttachment.modelNoImages': string;
2405
2601
  'attachment.imagesDropped': string;
@@ -2576,7 +2772,7 @@ interface AppearanceChange {
2576
2772
  * 不在其中(AC-20.7 按「无未覆盖的配置类 leaf」执行,见偏差 D-15)。
2577
2773
  * @experimental
2578
2774
  */
2579
- type SettingsSectionId = 'settings.runtime' | 'settings.sandbox' | 'settings.genui' | 'settings.trust' | 'settings.privacy' | 'settings.appearance' | 'connections.models' | 'connections.webmcp' | 'connections.page' | 'connections.mcp';
2775
+ type SettingsSectionId = 'settings.runtime' | 'settings.sandbox' | 'settings.genui' | 'settings.prompts' | 'settings.trust' | 'settings.privacy' | 'settings.appearance' | 'connections.models' | 'connections.webmcp' | 'connections.page' | 'connections.mcp';
2580
2776
  //#endregion
2581
2777
  //#region src/react/useChatLayout.d.ts
2582
2778
  /** 宿主可指定的布局档;auto 按容器尺寸判定 @stable */
@@ -2613,6 +2809,21 @@ interface ChatbotProps {
2613
2809
  * `section` 可选(FR-16.5):齿轮不带分区(→ Overview),带诉求的入口(错误卡等)才传分区。
2614
2810
  */
2615
2811
  onOpenSettings?(section?: SettingsSectionId): void;
2812
+ /**
2813
+ * 当前是否已「固定」到宿主页面(下沉占宽)。**受控**:SDK 只用它决定图标与
2814
+ * `aria-pressed`,自身布局与样式一概不因它改变——悬浮/下沉的容器归宿主外壳(FR-16.2)。
2815
+ */
2816
+ docked?: boolean;
2817
+ /**
2818
+ * 用户请求切换固定态(FR-16.1)。宿主不接就不渲染这个按钮。
2819
+ * 入参是用户**请求切换到**的目标态;宿主改完布局后把新的 `docked` 传回来。
2820
+ */
2821
+ onDock?(next: boolean): void;
2822
+ /**
2823
+ * 用户请求关闭对话框(FR-16.3)。宿主不接就不渲染这个按钮。
2824
+ * SDK 只发出意图,不卸载自己、不清理任何状态。
2825
+ */
2826
+ onClose?(): void;
2616
2827
  /**
2617
2828
  * 装配完成后把引擎交给宿主,用于接线跨界面动作(例如 console 的快照恢复入口
2618
2829
  * 需要调 `engine.resume(runId)`)。每次重新装配都会再调一次。
@@ -2624,7 +2835,7 @@ interface ChatbotProps {
2624
2835
  * presentation shell and accessible thread primitives.
2625
2836
  * @stable
2626
2837
  */
2627
- declare function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, renderer: rendererProp, dictationLang: dictationLangProp, surfaceRegistry, layout, sessionList, onOpenSettings, onEngineReady }: ChatbotProps): import("react").JSX.Element;
2838
+ declare function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, renderer: rendererProp, dictationLang: dictationLangProp, surfaceRegistry, layout, sessionList, onOpenSettings, docked, onDock, onClose, onEngineReady }: ChatbotProps): import("react").JSX.Element;
2628
2839
  //#endregion
2629
2840
  //#region src/react/A2uiSurfaceHost.d.ts
2630
2841
  /** @experimental */
@@ -2808,6 +3019,6 @@ declare function ErrorCard({ code, message, loopLimits, onOpenSettings, onDismis
2808
3019
  * Version of the published `@webskill/chatbot` package, injected at build time.
2809
3020
  * @stable
2810
3021
  */
2811
- declare const CHATBOT_VERSION = "0.8.0";
3022
+ declare const CHATBOT_VERSION = "0.11.0";
2812
3023
  //#endregion
2813
- export { A2uiSurfaceHost, type A2uiSurfaceHostProps, A2uiSurfaceSnapshotHost, type A2uiSurfaceSnapshotHostProps, type AppearanceChange, CHATBOT_VERSION, type ChatAttachmentInput, type ChatAttachmentMeta, type ChatContentPart, ChatEngine, type ChatEngineOptions, type ChatEvent, type ChatInteractionRecord, type ChatLayout, type ChatMessage, type ChatRunPhase, type ChatSessionListResult, type ChatSessionMeta, type ChatTheme, type ChatThinking, type ChatTokenUsage, type ChatToolCall, Chatbot, type ChatbotConfig, type ChatbotGovernancePorts, type ChatbotHostAdapter, type ChatbotProps, CompositeUiBridge, type CompositeUiBridgeDeps, DEFAULT_RENDERER_CAPABILITIES, DEFAULT_RUNTIME_CONFIG_STORAGE_KEY, type DownloadableFile, ErrorCard, type ErrorCardProps, InteractionCard, type InteractionCardProps, InterruptedBanner, type InterruptedBannerProps, type Locale, OpenUiSurfaceHost, type OpenUiSurfaceHostProps, OpenUiSurfaceSnapshotHost, type OpenUiSurfaceSnapshotHostProps, type QuickPrompt, type QuickPromptIconName, type RendererCapability, type RendererKind, type ResolvedChatLayout, ResultBlockList, type ResultBlockListProps, ResultBlocksPro, type ResultBlocksProProps, type RunSnapshot, type RuntimeAppearanceConfig, type RuntimeConfig, type RuntimeConfigStore, type RuntimeRendererId, type SandboxExecutorDeps, type SettingsSectionId, SkillBadges, SpecInteraction, type SpecInteractionProps, VercelPayloadPreview, type VercelPayloadPreviewProps, VercelSurfaceHost, type VercelSurfaceHostProps, VercelSurfaceSnapshotHost, type VercelSurfaceSnapshotHostProps, chatbotDictionary, configureA2uiMarkdown, createLocalStorageRuntimeConfigStore, createMemoryRuntimeConfigStore, isLlmEntryUsable, pickUsableLlmEntry, probeA2uiAvailability, probeOpenUiAvailability, sandboxExecutorDeps, useT };
3024
+ export { A2uiSurfaceHost, type A2uiSurfaceHostProps, A2uiSurfaceSnapshotHost, type A2uiSurfaceSnapshotHostProps, type AppearanceChange, CHATBOT_VERSION, type ChatAttachmentInput, type ChatAttachmentMeta, type ChatContentPart, ChatEngine, type ChatEngineOptions, type ChatEvent, type ChatInteractionRecord, type ChatLayout, type ChatMessage, type ChatRunPhase, type ChatSessionListResult, type ChatSessionMeta, type ChatTheme, type ChatThinking, type ChatTokenUsage, type ChatToolCall, Chatbot, type ChatbotConfig, type ChatbotGovernancePorts, type ChatbotHostAdapter, type ChatbotProps, CompositeUiBridge, type CompositeUiBridgeDeps, DEFAULT_RENDERER_CAPABILITIES, DEFAULT_RUNTIME_CONFIG_STORAGE_KEY, type DownloadableFile, ErrorCard, type ErrorCardProps, InteractionCard, type InteractionCardProps, InterruptedBanner, type InterruptedBannerProps, type Locale, type LocalizedText, OpenUiSurfaceHost, type OpenUiSurfaceHostProps, OpenUiSurfaceSnapshotHost, type OpenUiSurfaceSnapshotHostProps, type QuickPrompt, type QuickPromptIconName, type RendererCapability, type RendererKind, type ResolvedChatLayout, ResultBlockList, type ResultBlockListProps, ResultBlocksPro, type ResultBlocksProProps, type RunSnapshot, type RuntimeAppearanceConfig, type RuntimeConfig, type RuntimeConfigStore, type RuntimeQuickPrompt, type RuntimeRendererId, type SandboxExecutorDeps, type SettingsSectionId, SkillBadges, SpecInteraction, type SpecInteractionProps, VercelPayloadPreview, type VercelPayloadPreviewProps, VercelSurfaceHost, type VercelSurfaceHostProps, VercelSurfaceSnapshotHost, type VercelSurfaceSnapshotHostProps, chatbotDictionary, configureA2uiMarkdown, createLocalStorageRuntimeConfigStore, createMemoryRuntimeConfigStore, isLlmEntryUsable, pickUsableLlmEntry, probeA2uiAvailability, probeOpenUiAvailability, sandboxExecutorDeps, useT };