@yumiai/chat-widget 0.1.2 → 0.2.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/README.md +119 -22
  3. package/dist/ExcelCore-DJOIVQMI.js +11 -0
  4. package/dist/ExcelCore-DJOIVQMI.js.map +1 -0
  5. package/dist/ExcelViewer-3YLLYYIQ.js +65 -0
  6. package/dist/ExcelViewer-3YLLYYIQ.js.map +1 -0
  7. package/dist/GerberViewerA2UI-7CNT7HX4.css +693 -0
  8. package/dist/GerberViewerA2UI-7CNT7HX4.css.map +1 -0
  9. package/dist/GerberViewerA2UI-X5FWAD5M.js +57 -0
  10. package/dist/GerberViewerA2UI-X5FWAD5M.js.map +1 -0
  11. package/dist/GraphStatsLegend-D5bPeXB_.d.cts +607 -0
  12. package/dist/GraphStatsLegend-D5bPeXB_.d.ts +607 -0
  13. package/dist/JsonRenderStandalone-EIZM62JU.js +18 -0
  14. package/dist/JsonRenderStandalone-EIZM62JU.js.map +1 -0
  15. package/dist/JsonRenderStandalone-POB4Q3N3.css +2384 -0
  16. package/dist/JsonRenderStandalone-POB4Q3N3.css.map +1 -0
  17. package/dist/JsonRenderStandalone-UsTcST4G.d.cts +23 -0
  18. package/dist/JsonRenderStandalone-UsTcST4G.d.ts +23 -0
  19. package/dist/KicadViewer-GV6ZC4AQ.js +124 -0
  20. package/dist/KicadViewer-GV6ZC4AQ.js.map +1 -0
  21. package/dist/KicadViewerCore-U7BWZHKJ.js +11 -0
  22. package/dist/KicadViewerCore-U7BWZHKJ.js.map +1 -0
  23. package/dist/PdfViewer-CHPDRK46.js +51 -0
  24. package/dist/PdfViewer-CHPDRK46.js.map +1 -0
  25. package/dist/PdfViewer-LPYGQETK.css +1899 -0
  26. package/dist/PdfViewer-LPYGQETK.css.map +1 -0
  27. package/dist/PdfViewerCore-HJPEHSRA.js +364 -0
  28. package/dist/PdfViewerCore-HJPEHSRA.js.map +1 -0
  29. package/dist/PowerPointCore-FPDR2BL4.js +11 -0
  30. package/dist/PowerPointCore-FPDR2BL4.js.map +1 -0
  31. package/dist/PowerPointViewer-LQTO6UCU.js +61 -0
  32. package/dist/PowerPointViewer-LQTO6UCU.js.map +1 -0
  33. package/dist/StepViewerCore-7W3L3R4E.js +285 -0
  34. package/dist/StepViewerCore-7W3L3R4E.js.map +1 -0
  35. package/dist/ThreeViewerCore-N3QJD5QI.js +161 -0
  36. package/dist/ThreeViewerCore-N3QJD5QI.js.map +1 -0
  37. package/dist/WordCore-JKSXK2XD.js +11 -0
  38. package/dist/WordCore-JKSXK2XD.js.map +1 -0
  39. package/dist/WordViewer-ZHCQMHOH.js +61 -0
  40. package/dist/WordViewer-ZHCQMHOH.js.map +1 -0
  41. package/dist/chunk-2SKA3F5U.js +88 -0
  42. package/dist/chunk-2SKA3F5U.js.map +1 -0
  43. package/dist/chunk-2UC7YLVX.js +318 -0
  44. package/dist/chunk-2UC7YLVX.js.map +1 -0
  45. package/dist/chunk-3R6T3LBR.js +24 -0
  46. package/dist/chunk-3R6T3LBR.js.map +1 -0
  47. package/dist/chunk-56WRZM3R.js +398 -0
  48. package/dist/chunk-56WRZM3R.js.map +1 -0
  49. package/dist/chunk-7A4FY6FK.js +10226 -0
  50. package/dist/chunk-7A4FY6FK.js.map +1 -0
  51. package/dist/chunk-7D4SUZUM.js +38 -0
  52. package/dist/chunk-7D4SUZUM.js.map +1 -0
  53. package/dist/chunk-7S67DOHQ.js +436 -0
  54. package/dist/chunk-7S67DOHQ.js.map +1 -0
  55. package/dist/chunk-CFKGNAJM.js +14013 -0
  56. package/dist/chunk-CFKGNAJM.js.map +1 -0
  57. package/dist/chunk-GAMA3VA7.js +99 -0
  58. package/dist/chunk-GAMA3VA7.js.map +1 -0
  59. package/dist/chunk-GYXTSY22.js +639 -0
  60. package/dist/chunk-GYXTSY22.js.map +1 -0
  61. package/dist/chunk-K4KGNVL5.js +77 -0
  62. package/dist/chunk-K4KGNVL5.js.map +1 -0
  63. package/dist/chunk-KQV7IKET.js +1621 -0
  64. package/dist/chunk-KQV7IKET.js.map +1 -0
  65. package/dist/chunk-O3NXUM6C.js +1871 -0
  66. package/dist/chunk-O3NXUM6C.js.map +1 -0
  67. package/dist/chunk-PZXSASDY.js +83 -0
  68. package/dist/chunk-PZXSASDY.js.map +1 -0
  69. package/dist/chunk-QLVPIM6R.js +595 -0
  70. package/dist/chunk-QLVPIM6R.js.map +1 -0
  71. package/dist/chunk-VXJWGLZ7.js +21 -0
  72. package/dist/chunk-VXJWGLZ7.js.map +1 -0
  73. package/dist/chunk-XQ562W7I.js +116 -0
  74. package/dist/chunk-XQ562W7I.js.map +1 -0
  75. package/dist/components/JsonRender/standalone.cjs +39368 -0
  76. package/dist/components/JsonRender/standalone.cjs.map +1 -0
  77. package/dist/components/JsonRender/standalone.css +2384 -0
  78. package/dist/components/JsonRender/standalone.css.map +1 -0
  79. package/dist/components/JsonRender/standalone.d.cts +16 -0
  80. package/dist/components/JsonRender/standalone.d.ts +16 -0
  81. package/dist/components/JsonRender/standalone.js +38 -0
  82. package/dist/components/JsonRender/standalone.js.map +1 -0
  83. package/dist/gerber-2d-entry-OQ4SQRBY.js +3950 -0
  84. package/dist/gerber-2d-entry-OQ4SQRBY.js.map +1 -0
  85. package/dist/gerber-3d-entry-DEHDBOO2.js +3679 -0
  86. package/dist/gerber-3d-entry-DEHDBOO2.js.map +1 -0
  87. package/dist/gerber-simulation-entry-EBDX72XE.js +1801 -0
  88. package/dist/gerber-simulation-entry-EBDX72XE.js.map +1 -0
  89. package/dist/index.cjs +60113 -2970
  90. package/dist/index.cjs.map +1 -1
  91. package/dist/index.css +11342 -1708
  92. package/dist/index.css.map +1 -1
  93. package/dist/index.d.cts +3275 -77
  94. package/dist/index.d.ts +3275 -77
  95. package/dist/index.js +18078 -2540
  96. package/dist/index.js.map +1 -1
  97. package/dist/provenance/index.cjs +2248 -0
  98. package/dist/provenance/index.cjs.map +1 -0
  99. package/dist/provenance/index.css +52 -0
  100. package/dist/provenance/index.css.map +1 -0
  101. package/dist/provenance/index.d.cts +12 -0
  102. package/dist/provenance/index.d.ts +12 -0
  103. package/dist/provenance/index.js +27 -0
  104. package/dist/provenance/index.js.map +1 -0
  105. package/dist/resolveToArrayBuffer-AQIDZHSQ.js +23 -0
  106. package/dist/resolveToArrayBuffer-AQIDZHSQ.js.map +1 -0
  107. package/package.json +98 -17
package/dist/index.d.cts CHANGED
@@ -1,7 +1,18 @@
1
- import React from 'react';
1
+ import * as React$1 from 'react';
2
+ import React__default, { RefObject } from 'react';
3
+ import { k as ProvenanceGraphSnapshot, a as ChatWidgetMessages, C as ChatWidgetLocale } from './GraphStatsLegend-D5bPeXB_.cjs';
4
+ export { E as EdgeType, F as FetchGraphOptions, b as FilterBar, G as GraphBuilder, c as GraphEdge, d as GraphFilter, e as GraphSSEPayload, f as GraphStatsLegend, g as GraphToolbar, N as NodeDetailPanel, h as NodeType, P as ProvenanceGraph3D, i as ProvenanceGraphDrawerContent, j as ProvenanceGraphFetcher, l as ProvenanceNode, m as fetchProvenanceGraph, r as resolveMessages, u as useProvenanceGraph } from './GraphStatsLegend-D5bPeXB_.cjs';
5
+ import * as react_jsx_runtime from 'react/jsx-runtime';
6
+ export { J as JsonRenderActionHandler, a as JsonRenderStandalone, b as JsonRenderStandaloneProps } from './JsonRenderStandalone-UsTcST4G.cjs';
2
7
 
3
- type MessageContentType = 'text' | 'think' | 'plan' | 'artifact' | 'json_schema' | 'html_schema' | 'json_schema_wait';
4
- type NotificationType = 'user_input' | 'node_notification' | 'start' | 'model_start' | 'model_result' | 'model_end' | 'agent_start' | 'agent_result' | 'agent_end' | 'artifact_start' | 'artifact_result' | 'artifact_end' | 'plan_start' | 'plan_result' | 'plan_end' | 'mcp_generating' | 'mcp_start' | 'mcp_result' | 'mcp_end' | 'finish' | 'canceled' | 'error' | 'human_input_request' | 'human_input_received' | 'human_input_timeout' | 'human_input_completed' | 'session_title' | 'compression_started' | 'compression_completed' | 'node_summary';
8
+ type MessageContentType = 'text' | 'think' | 'plan' | 'artifact' | 'json_schema' | 'html_schema' | 'json_schema_wait' | 'gen_ui_card' | 'gen_ui_page' | 'gen_ui_meta';
9
+ type NotificationType = 'user_input' | 'node_notification' | 'start' | 'model_start' | 'model_result' | 'model_end' | 'agent_start' | 'agent_result' | 'agent_end' | 'artifact_start' | 'artifact_result' | 'artifact_end' | 'plan_start' | 'plan_result' | 'plan_end' | 'mcp_generating' | 'mcp_start' | 'mcp_result' | 'mcp_end' | 'finish' | 'canceled' | 'error' | 'human_input_request' | 'human_input_received' | 'human_input_timeout' | 'human_input_completed'
10
+ /** [DEPRECATED 起 JETP-073] session 级 LLM 起名;仅在兼容期 dual-write 中复用,
11
+ * 新代码请改用 'client_title'。 */
12
+ | 'session_title'
13
+ /** JETP-073:client("办公室")级 LLM 起名 notification。controller 派发为
14
+ * ``ClientTitleEvent``;上游消费方按 ``client_id`` 增量更新本地 cache。 */
15
+ | 'client_title' | 'compression_started' | 'compression_completed' | 'node_summary';
5
16
  interface UiConfig {
6
17
  display_type: 'content' | 'command' | 'browser' | 'query' | 'path' | 'trigger' | 'thinking' | 'params';
7
18
  icon?: string;
@@ -28,6 +39,37 @@ interface SSEMessage {
28
39
  content_type: MessageContentType;
29
40
  content: string;
30
41
  timestamp?: string;
42
+ spec_id?: string;
43
+ render_mode?: 'card' | 'page';
44
+ /** JETP-045 Layer 1:客户端连接子空间标识;后端 Notification.client_id 透传下来。 */
45
+ client_id?: string;
46
+ /**
47
+ * JETP-045 Phase 2 P2-T03:与所属 LLM 物理流对齐的边界 ID。
48
+ * MODEL_START / 中间 chunk / MODEL_END 共享同一 stream_uuid。
49
+ * 前端 useMessageAggregator.messageKey 主分支按此聚合 → 彻底解决 Bug 1
50
+ * (撞键导致 think2 头部错合到 think1)。
51
+ * 旧后端不下发 → undefined → useMessageAggregator 走兜底分支保持向后兼容。
52
+ */
53
+ stream_uuid?: string;
54
+ /**
55
+ * JETP-045 Phase 2 P2-T08/T10:所属 turn 在 (interaction_id, callee_instance_id)
56
+ * 内的单调序号;与 db-writer ``MAX(turn_index)+1`` 同算法。
57
+ * 前端 ``turnCursorRef`` 用 ``${iid}::${callee}`` 为 key 推进;断线重连发
58
+ * subscribe 时按 (iid, callee, max_turn_index) 形式上报,服务端只补
59
+ * ``turn_index > max_turn_index`` 的 turn(AC-TURN-002/005)。
60
+ */
61
+ turn_index?: number;
62
+ /**
63
+ * JETP-045:被叫 agent 实例 ID。AC-TURN-003 多 callee 独立 cursor 必需。
64
+ * 旧后端可能直接把 ``agent_instance_id`` 当 callee 用 → adapter 透传。
65
+ */
66
+ callee_instance_id?: number;
67
+ /**
68
+ * JETP-045 Phase 6 — 触发该 notification 的源连接 ID(后端 Notification.connection_id_from)。
69
+ * 前端 ``useMessageAggregator`` 用 ``connection_id_from === my_connection_id`` 识别 echo。
70
+ * 旧后端不下发 → undefined → 不做 echo 抑制,回退到 Phase 1-5 行为 (AC-CONN-008)。
71
+ */
72
+ connection_id_from?: string;
31
73
  }
32
74
  interface PlanItem {
33
75
  text: string;
@@ -84,6 +126,9 @@ interface Artifact {
84
126
  id: string;
85
127
  name: string;
86
128
  type: string;
129
+ /** 后端资源 ID,与附件/工作区文件关联 */
130
+ resource_id?: string;
131
+ mime_type?: string;
87
132
  size?: string;
88
133
  content?: string;
89
134
  preview?: string;
@@ -105,7 +150,98 @@ interface HITLResponse {
105
150
  await_command_uuid: string;
106
151
  data: unknown;
107
152
  confirmed: boolean;
153
+ /** JETP-040: Optional attached files for multipart HITL upload */
154
+ files?: File[];
155
+ session_id?: number;
156
+ agent_instance_id?: number;
157
+ text?: string;
158
+ /**
159
+ * JETP-003 ADR-006 v1.1.2 / WS2.6 — V2 ``c_<22 base62>`` window/conversation
160
+ * identifier for the chat-widget instance that produced this response.
161
+ *
162
+ * Stage A grayscale (current): when omitted on A2UI payloads, jetagents
163
+ * /api/human-response increments ``hip_client_id_missing_total`` Counter
164
+ * + WARN log and falls back to session-wide routing.
165
+ *
166
+ * Stage B strict cutover (post-grayscale): A2UI payloads (data with
167
+ * ``__action`` + ``spec_id``) without client_id will be rejected.
168
+ *
169
+ * The chat-widget always knows its own client_id (from useClientIdAllocator
170
+ * → ``currentClientId``); GenUIProvider injects it into GenUIContext, and
171
+ * ActionBridge / handleHITLSubmit auto-fill this field when not set by
172
+ * the caller.
173
+ */
174
+ client_id?: string;
108
175
  }
176
+ /**
177
+ * JETP-083 WS3.7.6 — pending HIL Entity projection returned by
178
+ * ``GET /api/genui/pending``.
179
+ *
180
+ * Shape mirrors `jetagents/main.py:get_genui_pending` 1:1; fields are
181
+ * derived from `HilEntity` + the principal-scoped projection helper.
182
+ *
183
+ * Phase 1 invariants:
184
+ * - The returned list contains *only* HILs whose `resolved_recipients`
185
+ * include the connecting principal — backend ACL via the registry's
186
+ * principal index. No client-side filter is needed (or sufficient).
187
+ * - `recipientsSummary.recipientCount` is intentionally a count, not a
188
+ * list of co-recipients, to avoid leaking other users' identities.
189
+ * Phase 2 multi-recipient delivery may extend this with masked
190
+ * summaries.
191
+ * - `state` is always a non-terminal state (registry filters out
192
+ * resolved/cancelled/expired before returning).
193
+ */
194
+ interface PendingHIL {
195
+ hilId: string;
196
+ specId: string;
197
+ /** Note: backend stores as string even when the URL `session_id` is int. */
198
+ sessionId: string;
199
+ state: 'pending' | 'delivered' | 'in_progress' | 'partially_resolved';
200
+ schemaVersion: 'v1';
201
+ createdAt: string | null;
202
+ lastUpdatedAt: string | null;
203
+ origin: {
204
+ agentId: string | null;
205
+ /** Originating client_id; audit-only after WS3.7.4. */
206
+ clientId: string | null;
207
+ /** Compact origin principal — drops null fields. */
208
+ principal: {
209
+ principalKind?: string;
210
+ principalKey?: string;
211
+ realmId?: string;
212
+ authInstanceId?: string;
213
+ } | null;
214
+ };
215
+ recipientsSummary: {
216
+ delivery: 'first_wins' | 'all_must' | 'quorum' | 'broadcast_first_wins';
217
+ selectorKind: 'literal' | 'role' | 'group' | 'realm';
218
+ recipientCount: number;
219
+ /** Whether the connecting principal is a recipient (sanity flag). */
220
+ includeSelf: boolean;
221
+ };
222
+ }
223
+ /**
224
+ * Terminal lifecycle marker for a spec, emitted by the backend via the
225
+ * `gen_ui_meta` channel as either:
226
+ *
227
+ * - `{op:"replace", path:"/_meta/cancelled", value:{reason}}` — HIL on the
228
+ * spec was cancelled (user, agent, or system-initiated; see WS3.7.5).
229
+ * - `{op:"replace", path:"/_meta/error", value:{error_code, payload}}`
230
+ * or legacy flat `{error, payload}` — terminal error such as
231
+ * `patch_rounds_exceeded` (ADR-012 D1).
232
+ *
233
+ * The aggregator surfaces this in `specLifecycleMap` keyed by spec_id; the
234
+ * host UI can disable the form, dim the card, or show a banner. Once a spec
235
+ * has a lifecycle entry, further patches for it should be visually muted.
236
+ */
237
+ type SpecLifecycleEntry = {
238
+ state: 'cancelled';
239
+ reason: string;
240
+ } | {
241
+ state: 'error';
242
+ errorCode: string;
243
+ payload?: Record<string, unknown>;
244
+ };
109
245
  interface AggregatedMessage {
110
246
  id: string;
111
247
  agentInstanceId: number;
@@ -129,18 +265,39 @@ interface AggregatedMessage {
129
265
  artifact?: Artifact;
130
266
  artifacts?: Artifact[];
131
267
  hitlRequest?: HITLRequest;
268
+ specId?: string;
269
+ uiPatches?: string[];
270
+ renderMode?: 'card' | 'page';
271
+ /** JETP-045 Layer 1:客户端连接子空间标识。 */
272
+ clientId?: string;
273
+ /**
274
+ * JETP-045 Phase 6 — 触发该消息的源连接 ID;与 ``SSEMessage.connection_id_from`` 透传。
275
+ * 仅用于 UI 调试/数据回放;echo 的渲染策略由 ``isEcho`` 决定。
276
+ */
277
+ connectionIdFrom?: string;
278
+ /**
279
+ * JETP-045 Phase 6 (AC-CONN-006/007) — 该消息是否由"我这条连接"自己回环触发。
280
+ * - true:UI 应抑制 user_input 的重复渲染(已由 round.userMessage optimistic 显示);
281
+ * 其余非 user_input 类型仍照常渲染,仅可作为视觉淡化提示。
282
+ * - false / undefined:来自其他 tab/连接 或旧后端无 ``connection_id_from`` ⇒ 视为远端。
283
+ */
284
+ isEcho?: boolean;
132
285
  }
133
286
  interface Round {
134
287
  interactionId: string;
135
288
  index: number;
136
289
  userMessage: string;
137
290
  timestamp: string;
291
+ /** 用户消息时间戳(毫秒),可选;缺省时可用 `timestamp` 解析 */
292
+ startedAt?: number;
138
293
  status: 'running' | 'completed' | 'error';
139
294
  plan?: TaskPlan;
140
295
  messages: AggregatedMessage[];
141
296
  topPosition?: number;
142
297
  /** 本轮次内已收到 agent_end 的 agent_instance_id 集合,与 notification_turns 的 agent start/stop 对齐,用于子 Agent 卡片「已完成」判断 */
143
298
  endedAgentInstanceIds?: Set<number>;
299
+ /** JETP-045 Layer 1:客户端连接子空间标识。 */
300
+ clientId?: string;
144
301
  }
145
302
  type ExecutionStatus = 'idle' | 'running' | 'compressing' | 'completed' | 'error';
146
303
  interface ChatWidgetConfig {
@@ -150,8 +307,33 @@ interface ChatWidgetConfig {
150
307
  typewriterSpeed?: number;
151
308
  autoScroll?: boolean;
152
309
  childAgentMaxHeight?: number;
153
- theme?: 'light' | 'dark' | 'auto';
310
+ theme?: 'light' | 'dark' | 'midnight' | 'neumorphism' | 'auto';
154
311
  displayLevels?: number[];
312
+ /**
313
+ * Whether to reuse agent_instance_id from session history when restoring a session.
314
+ *
315
+ * - `true` (default): cache the historical agent_instance_id and send it with
316
+ * new messages, ensuring the same agent executor handles follow-up requests.
317
+ * Best for single-user continuation of an existing conversation.
318
+ *
319
+ * - `false`: do NOT cache the historical agent_instance_id; each new message
320
+ * lets the backend create a fresh agent executor. This avoids InstanceTaskQueue
321
+ * contention and is required for multi-user collaboration on a shared session.
322
+ */
323
+ reuseAgentInstance?: boolean;
324
+ transport?: 'ws' | 'sse';
325
+ /**
326
+ * 是否在 ChatWidget mount 时立即调用 ``adapter.createSession`` 预分配 session+workspace。
327
+ *
328
+ * - ``true``(默认):保留原 SDK 行为,让首次 ``sendMessage`` 不必等会话创建。
329
+ * 适合"嵌入式单会话"场景(host 始终给确定 sessionId 或希望开局立即就绪)。
330
+ *
331
+ * - ``false``:不在 mount 时建会话;只有用户调用 ``api.sendMessage`` 或 host 显式
332
+ * 传入 sessionId 时才进入会话流程。适合"多会话侧栏 + 选择/新建"的 host
333
+ * (如 Demo App、JetForge Console),避免每次刷新都在后端 page 列表里
334
+ * 留下空 session。
335
+ */
336
+ eagerSessionCreation?: boolean;
155
337
  }
156
338
  declare const DEFAULT_CONFIG: Required<ChatWidgetConfig>;
157
339
  interface ChatWidgetProps {
@@ -159,25 +341,304 @@ interface ChatWidgetProps {
159
341
  sessionId?: string | number;
160
342
  initialMessages?: Round[];
161
343
  config?: ChatWidgetConfig;
162
- renderHeaderExtra?: (sessionId: string | number) => React.ReactNode;
163
- renderFooter?: (api: ChatWidgetAPI | null) => React.ReactNode;
164
- renderToolResult?: (displayType: string, data: ToolCallData) => React.ReactNode | null;
344
+ renderHeaderExtra?: (sessionId: string | number) => React__default.ReactNode;
345
+ renderFooter?: (api: ChatWidgetAPI | null) => React__default.ReactNode;
346
+ renderToolResult?: (displayType: string, data: ToolCallData) => React__default.ReactNode | null;
165
347
  locale?: 'zh-CN' | 'en-US';
348
+ messages?: Partial<ChatWidgetMessages>;
166
349
  onArtifactClick?: (artifact: Artifact) => void;
350
+ onSelectionAsk?: (reference: FileReference) => void;
351
+ onBeforeCopy?: (reference: FileReference) => void;
167
352
  onHITLSubmit?: (response: HITLResponse) => Promise<void>;
353
+ onConnectionChange?: (connected: boolean) => void;
354
+ onRoundChange?: (rounds: Round[]) => void;
355
+ onMessageAppended?: (message: AggregatedMessage) => void;
356
+ onRoundStart?: (interactionId: string, userMessage: string) => void;
357
+ onRoundEnd?: (interactionId: string) => void;
168
358
  onStatusChange?: (status: ExecutionStatus) => void;
169
359
  onError?: (error: Error) => void;
360
+ onInteraction?: (event: ChatWidgetInteractionEvent) => void;
170
361
  onReady?: (api: ChatWidgetAPI) => void;
171
362
  className?: string;
172
- style?: React.CSSProperties;
363
+ style?: React__default.CSSProperties;
173
364
  height?: number | string;
365
+ /** 自建 jp-kicanvas 脚本 URL;未设则用 VITE_KICANVAS_SCRIPT_URL 或官方 CDN */
366
+ kicanvasScriptUrl?: string;
367
+ /** JETP-038: Current human user alias for discussion participation (e.g. "user:alice"). Defaults to "user". */
368
+ currentUserAlias?: string;
369
+ }
370
+ interface SkillSummary {
371
+ id: string;
372
+ name: string;
373
+ displayName: string;
374
+ description: string;
375
+ version?: string;
376
+ category?: string;
377
+ tags?: string[];
378
+ }
379
+ interface SkillListParams {
380
+ search?: string;
381
+ page?: number;
382
+ pageSize?: number;
383
+ }
384
+ interface SkillListResponse {
385
+ skills: SkillSummary[];
386
+ total: number;
387
+ page: number;
388
+ pageSize: number;
389
+ }
390
+ interface SelectedSkillRef {
391
+ id: string;
392
+ name: string;
393
+ version?: string;
394
+ }
395
+ type InteractionEventType = 'child-agent-toggle' | 'tool-result-toggle' | 'think-toggle' | 'todo-toggle' | 'todo-item-click' | 'link-click' | 'xref-navigate' | 'file-download' | 'artifact-click' | 'plan-step-click' | 'reference-add' | 'reference-remove' | 'viewer-open' | 'viewer-close' | 'immersive-toggle' | 'message-copy' | 'hitl-submit' | 'skill-select' | 'skill-remove' | 'skill-popup-open' | 'skill-popup-close' | 'skill-search'
396
+ /**
397
+ * 会话生命周期:controller 真新建出 session 后触发(adapter.createSession 成功 /
398
+ * 后端通过 SSE ``session_info`` 推回新 session_id 都算)。从 ``sessionId`` prop
399
+ * 恢复历史会话不会触发本事件。
400
+ * metadata: ``{ sessionId: number, agentId?: string }``
401
+ */
402
+ | 'session-created'
403
+ /**
404
+ * 会话信息更新:当前以 session_title 变化为唯一来源——SSE ``session_title`` 通知到达、
405
+ * loadHistory 取 detail / 兜底 sessionDetail 拿到非空 title 都会触发一次。
406
+ * metadata: ``{ sessionId: number, sessionTitle?: string }``
407
+ */
408
+ | 'session-updated';
409
+ interface ChatWidgetInteractionEvent {
410
+ type: InteractionEventType;
411
+ target: string;
412
+ metadata?: Record<string, unknown>;
413
+ timestamp: number;
414
+ }
415
+ /**
416
+ * Controller 对外暴露的"会话生命周期事件"——比 InteractionEvent 更窄:
417
+ * 只关心"创建" / "信息更新",不耦合 UI 交互层。ChatWidget 默认把它转译成
418
+ * ``'session-created' / 'session-updated'`` 这两条 InteractionEvent;高级宿主
419
+ * 也可以直接拿 controller 的 ``onSessionEvent`` 自己处理,绕开 InteractionContext。
420
+ */
421
+ interface SessionLifecycleEvent {
422
+ type: 'created' | 'updated';
423
+ sessionId: number;
424
+ /** updated 时携带最新 session_title;created 一般为空。 */
425
+ sessionTitle?: string;
426
+ /** created 时携带 agentId,便于宿主统计 / 路由。 */
427
+ agentId?: string;
428
+ /** created 的来源:显式 createSession vs 后端 SSE 推回。 */
429
+ source?: 'explicit' | 'sse';
430
+ }
431
+ /**
432
+ * JETP-073:client("办公室")级 title 解析事件。
433
+ *
434
+ * controller 在以下时机各 emit 一次:
435
+ * - SSE/WS ``client_title`` notification 到达(backend `node_title_agent`
436
+ * 基于 first_agent_start 派生出 LLM 起名后通过 redis stream 推下来)。
437
+ *
438
+ * 与 ``SessionLifecycleEvent.updated`` 关键区别:
439
+ * - SessionLifecycleEvent 绑定 ``sessionId``;一个 session 一次。
440
+ * - ClientTitleEvent 绑定 ``clientId``;多 client session 下每个 client 一次。
441
+ *
442
+ * sessionId 字段仅作上下文 hint,可能为 -1(loadHistory 中 session 未敲定时)。
443
+ * 真正的 routing key 是 ``clientId``。
444
+ */
445
+ interface ClientTitleEvent {
446
+ type: 'client_title';
447
+ /** controller 当时持有的 currentSessionId;-1 表示未知(loadHistory 阶段)。 */
448
+ sessionId: number;
449
+ /** v2 client_id:``c_<22 base62>``。后端保证非空。 */
450
+ clientId: string;
451
+ /** LLM 派生的 client title(已被 backend 截到 ≤24 字)。 */
452
+ clientTitle: string;
453
+ }
454
+ /**
455
+ * 前端在发送一条消息时显式指定要用的模型,覆盖该 agent 在后端注册的默认 ``ModelMeta``。
456
+ *
457
+ * 设计:
458
+ * - ``name`` 必须是后端 fusion 能识别的 model 标识;前端不做白名单(后端校验)。
459
+ * - ``scope`` 决定是否透传到此次调用派生出的所有子 agent:
460
+ * - ``'root'`` 只覆盖入口 agent 自己;子 agent 仍按各自 ``AgentMeta.model``。
461
+ * - ``'all'``(默认)父 → 子 → 孙都用同一个 model,便于"指定模型跑完一棵任务树"。
462
+ * - ``settings`` 是增量字段,会浅合并进 ``ModelMeta.settings``(如 ``{ temperature: 0.3 }``)。
463
+ *
464
+ * 不在第一版做的事:按 role 映射 (`{ ask: 'haiku', deliver: 'opus' }`)、
465
+ * 自动降级到 agent 默认模型(语义上"用户授权使用且仅使用这个 model")。
466
+ */
467
+ interface ModelOverride {
468
+ name: string;
469
+ scope?: 'root' | 'all';
470
+ settings?: Record<string, unknown>;
471
+ }
472
+ /**
473
+ * 单条模型记录,等价于 hip ``Model`` DTO。每条 = 一个 (channel, model_name) 对。
474
+ *
475
+ * 何时用:上层希望让用户显式挑渠道(高阶面板 / 调试视图)。
476
+ * 想法是稳定 ``id`` 直接映射到 ``ModelOverride.name``——若上层需要传渠道路由,
477
+ * 就传完整 id(``channel/name``);想让后端按账号策略选渠道,就传 ``name``。
478
+ */
479
+ interface ModelListItemRaw {
480
+ id: string;
481
+ name: string;
482
+ channel: string;
483
+ created: number;
484
+ /**
485
+ * 该 (channel, model_name) 当前是否可用——hip-server 联表 model-lake
486
+ * ``/internal/model-status`` 的判定结果。
487
+ *
488
+ * **fail-safe 默认 true**:当 hip 端 status 接口拉不到 / 该 id 不在结果集时
489
+ * 都视为可用,避免一个内部接口故障让 picker 整体空列表。前端按"显式 false 才隐藏"
490
+ * 处理,**不要**对未定义状态做特殊兜底(与后端契约一致)。
491
+ *
492
+ * 字段为 optional 是为了兼容尚未升级到带 availability 的 hip 老版本:
493
+ * 解析方未拿到字段时按 true 处理(``ModelPicker`` 已经实现该兜底)。
494
+ */
495
+ available?: boolean;
496
+ }
497
+ /**
498
+ * 聚合形态(``group_by=name``),等价于 hip ``GroupedModel`` DTO。
499
+ * 每条 = 一个 model_name + 该 name 下所有可用渠道。
500
+ *
501
+ * 用法:picker 直接展示 ``name`` / ``displayName``,用户挑后把 ``name``
502
+ * 灌入 ``ModelOverride.name``,后端自行按账号策略选渠道。
503
+ */
504
+ interface ModelListItemGrouped {
505
+ name: string;
506
+ channels: string[];
507
+ /**
508
+ * Channels 的子集,只含 ``available=true`` 的渠道。
509
+ * 前端不展示渠道时直接消费 ``defaultChannel``;
510
+ * 展示渠道时可用此把不可用的置灰。Optional 兼容老版本 hip。
511
+ */
512
+ availableChannels?: string[];
513
+ /**
514
+ * 该 name 下默认选中的渠道。
515
+ * 选取规则(hip 端):**先 available 再 created** —— 即优先在 available
516
+ * 渠道里选注册时间最早的;全不可用才 fallback 到整体最早。
517
+ */
518
+ defaultChannel: string;
519
+ created: number;
520
+ /**
521
+ * 该 name 下是否至少有一个渠道可用。前端可用此快速决定"整行隐藏"。
522
+ * Optional 兼容老版本 hip:未定义时按 true 处理。
523
+ */
524
+ anyAvailable?: boolean;
525
+ }
526
+ /**
527
+ * Basename 聚合形态下的"渠道-完整 name"组合,等价于 hip ``BasenameVariant``。
528
+ *
529
+ * 关键约束:``name`` 字段是 model-lake 视角的**完整 model_name**
530
+ * (``anthropic__claude-opus-4`` / ``claude-opus-4-6`` / ``qwen__qwen3-max`` 等),
531
+ * 必须原样回传给后端 ``ModelOverride.name``。``basename`` 仅是 UI 标签,**不能**
532
+ * 替代 name —— 否则会丢失渠道路由信息(同 basename 不同渠道 = 不同账号 / 不同价格)。
533
+ */
534
+ interface ModelListVariant {
535
+ name: string;
536
+ channel: string;
537
+ created: number;
538
+ /**
539
+ * 该 variant 当前是否可用,语义同 ``ModelListItemRaw.available``。
540
+ * fail-safe 默认 true(optional + 未定义按 true 处理)。
541
+ */
542
+ available?: boolean;
543
+ }
544
+ /**
545
+ * Basename 聚合形态(``group_by=basename``),等价于 hip ``BasenameGrouped``。
546
+ *
547
+ * 设计动机:model-lake 入库时 openrouter 渠道把 ``provider/model``
548
+ * (如 ``qwen/qwen3-max``)反规范化为 ``provider__model``(``qwen__qwen3-max``),
549
+ * 与 ali 渠道的 ``qwen3-max`` 在 ``ModelListItemGrouped`` 视角下被识别为不同 name,
550
+ * 实际上是同一物理模型。Basename 聚合再合并一层,给 picker 一个"无重复"的列表。
551
+ *
552
+ * 用法:picker 列表 = ``basename``;点开后展开 ``variants``,让用户挑渠道;
553
+ * 选定后把对应 variant 的 ``name`` 灌入 ``ModelOverride.name``。
554
+ */
555
+ interface ModelListItemBasenameGrouped {
556
+ basename: string;
557
+ variants: ModelListVariant[];
558
+ /**
559
+ * 默认选中的 variant。
560
+ * 选取规则(hip 端):**先 available 再 created** —— 即优先在 available
561
+ * variant 里选注册时间最早的;全不可用才 fallback 到整体最早。
562
+ */
563
+ defaultVariant: ModelListVariant;
564
+ created: number;
565
+ /**
566
+ * 该 basename 下是否至少有一个 variant 可用。前端可据此整行隐藏,
567
+ * 让运营态 picker 不出现"全部下游挂掉"的死项。Optional 兼容老版本 hip:
568
+ * 未定义时按 true 处理。
569
+ */
570
+ anyAvailable?: boolean;
571
+ }
572
+ interface ListModelsResponse<TItem = ModelListItemBasenameGrouped> {
573
+ items: TItem[];
574
+ total: number;
575
+ }
576
+ /**
577
+ * adapter.listModels 入参;保持极简、不引入 channel 之外的过滤维度——
578
+ * 进一步的"按租户/角色"过滤应在 backend 端做(hip 后续可加 query 参数),
579
+ * 而不是让前端自己穿配置文件。
580
+ */
581
+ interface ListModelsParams {
582
+ /**
583
+ * 默认 ``'basename'``:按物理模型 basename 聚合,picker 默认形态。
584
+ * - ``'name'`` → 按完整 model_name 聚合(不归一 ``__`` ↔ ``/``);
585
+ * - ``'none'`` → 返回 raw(按 channel/name 对)。
586
+ */
587
+ groupBy?: 'basename' | 'name' | 'none';
174
588
  }
175
589
  interface ChatWidgetAPI {
176
- sendMessage: (message: string, agentId?: string) => void;
590
+ sendMessage: (message: string, agentId?: string, inlineRefs?: FileReference[], selectedSkills?: SelectedSkillRef[], overrideInstanceId?: number | null, clientId?: string, fileAttachments?: FileAttachment[], modelOverride?: ModelOverride | null) => void | Promise<void>;
177
591
  getCurrentRound: () => Round | null;
178
592
  getAllRounds: () => Round[];
179
593
  scrollToBottom: () => void;
180
594
  getStatus: () => ExecutionStatus;
595
+ /** Register a handler to receive references inline (e.g. insert into RichInput). When set, references bypass the external chip list. */
596
+ setReferenceInsertHandler: (handler: ((ref: FileReference) => void) | null) => void;
597
+ /**
598
+ * JETP-052 F-3c:在当前 session 内"开一个新对话流的浮动窗"。
599
+ *
600
+ * 编排:
601
+ * 1. 调用后端 ``POST /api/session/{sid}/clients`` 拿到 v2 ``c_<22>`` client_id
602
+ * 2. 把它加入 ``useFloatingWindows`` 浮动窗列表(``openWith``,附 title + contextPreloads 元数据)
603
+ * 3. 乐观更新到 ``useSessionClients`` 列表(sidebar 立刻可见)
604
+ *
605
+ * 失败时 reject;调用方 catch 后可以走 toast 或重试。
606
+ * 返回新分配的 v2 client_id(业务层可用来后续 sendMessage(clientId=...))。
607
+ */
608
+ openClientWindow?: (opts: {
609
+ title?: string;
610
+ contextPreloads?: unknown[];
611
+ }) => Promise<string>;
612
+ /**
613
+ * 协作式停止当前 session 的 Agent 执行 —— 通过 `adapter.stopAgent` 走
614
+ * `POST /api/session/stop`,由后端写 Redis stop 信号;运行时检查点会在下一个
615
+ * tick 退出。详细机制见 `ChatWidgetAdapter.stopAgent` 注释。
616
+ *
617
+ * 设计要点(与 `useAgentControl().stop` 共享同一底层路径):
618
+ * - **HTTP 单通道**:不依赖 WS 是否在线;跨 Pod 仍能命中;与 pause/resume 走 WS
619
+ * 的策略解耦(pause/resume 修改 pool 进程内状态,必须 WS 直送对应 Pod)。
620
+ * - **幂等**:后端键已存在时返回 `success(data={})`,连点两次安全。
621
+ * - **可选**:自定义 adapter 未实现 `stopAgent` 时本字段为 `undefined`,UI 应
622
+ * 据此降级(例如 DefaultComposer 在没有 stopAgent 时仍走旧 disabled 行为)。
623
+ *
624
+ * 何时存在:
625
+ * - `currentSessionId` 已就绪 **且** `adapter.stopAgent` 是函数 → 暴露此方法;
626
+ * - 否则为 `undefined`,避免给 UI 带来"按了没反应"的错觉。
627
+ *
628
+ * 失败语义:内部已 catch 网络错误并 `console.warn`,不向上抛 —— 让按钮 UI 不必
629
+ * 写自己的 try/catch;如宿主需要错误回调,请自行包一层 `try { await api.stopAgent() }`。
630
+ */
631
+ stopAgent?: () => Promise<void>;
632
+ /** JETP-040: File upload state and actions. Undefined when adapter does not support uploads. */
633
+ fileUpload?: {
634
+ attachments: UploadedFileInfo[];
635
+ readyFiles: FileAttachment[];
636
+ isUploading: boolean;
637
+ addFiles: (files: File[]) => void;
638
+ removeFile: (resourceId: string) => void;
639
+ clear: () => void;
640
+ enabled: boolean;
641
+ };
181
642
  }
182
643
  interface ToolCallData {
183
644
  tool_name: string;
@@ -213,6 +674,14 @@ interface NotificationTurn {
213
674
  status: string;
214
675
  timestamp_start: number | null;
215
676
  timestamp_end: number | null;
677
+ raw_message_count?: number;
678
+ /** JETP-045 Layer 1:客户端连接子空间标识。 */
679
+ client_id?: string;
680
+ }
681
+ interface PaginatedHistoryResponse {
682
+ turns: NotificationTurn[];
683
+ has_more: boolean;
684
+ next_cursor: string | null;
216
685
  }
217
686
  interface ResourceContent {
218
687
  resource_id: string;
@@ -223,6 +692,34 @@ interface ResourceContent {
223
692
  file_size: number | null;
224
693
  is_binary: boolean;
225
694
  content: string;
695
+ /** Direct URL for binary content (e.g. MinIO presigned URL), avoids base64 transfer for large files */
696
+ content_url?: string;
697
+ /** Language hint for syntax highlighting (e.g. "python", "go"); inferred from extension when absent */
698
+ language?: string;
699
+ }
700
+ /** Result of resolving a resource_id via ResourceProvider (CWRF-008) */
701
+ interface ResourceResolveResult {
702
+ url?: string;
703
+ content?: string;
704
+ contentUrl?: string;
705
+ mimeType?: string;
706
+ fileName?: string;
707
+ isText?: boolean;
708
+ gitPath?: string;
709
+ }
710
+ /** File entry returned by listDirectoryFiles (CWRF-009) */
711
+ interface DirectoryFileEntry {
712
+ resource_id: string;
713
+ file_name: string;
714
+ git_path: string;
715
+ download_url?: string;
716
+ node_type: string;
717
+ }
718
+ /** Options for listDirectoryFiles (CWRF-009) */
719
+ interface ListDirectoryFilesOptions {
720
+ extensions?: string[];
721
+ recursive?: boolean;
722
+ generateUrls?: boolean;
226
723
  }
227
724
  interface SessionDetail {
228
725
  session_id: number;
@@ -230,20 +727,594 @@ interface SessionDetail {
230
727
  status?: string;
231
728
  created_at?: string;
232
729
  }
730
+ interface PoolAgentAction {
731
+ tool_call_id: string;
732
+ tool: string;
733
+ purpose: string;
734
+ status: 'running' | 'completed' | 'failed' | string;
735
+ ts: number;
736
+ }
737
+ interface PoolAgent {
738
+ agent_instance_id: number;
739
+ agent_id: string;
740
+ agent_alias?: string;
741
+ /**
742
+ * JETP-083 WS3.7.7 follow-up: ``PAUSED`` is emitted by the backend
743
+ * ``RuntimeMonitor.agent_pool_status`` projection when the agent
744
+ * instance is blocked in ``_await_genui_blocking`` waiting on a HIL
745
+ * reply. ``PoolStatusPopover`` maps it to the ``paused`` state-key
746
+ * (label "等待人工" / "Awaiting human"); previously it fell through to
747
+ * the ``unknown`` bucket and the popover rendered "未知".
748
+ */
749
+ state: 'RUNNING' | 'PAUSED' | 'COMPLETED' | 'LOST' | string;
750
+ task_purpose?: string;
751
+ recent_actions?: PoolAgentAction[];
752
+ /**
753
+ * JETP-074(无退化路径版):agent 归属到的 client("办公室"),**必填**。
754
+ * backend MonitorRegistry.register 已严格化(缺 cid → ValueError),到达前端的
755
+ * 每个 PoolAgent 都必须有 cid;usePoolObservation 在 push/poll 路径上对缺 cid
756
+ * 的 patch 直接 console.error + drop,不让无 cid 的 agent 污染 observation。
757
+ */
758
+ client_id: string;
759
+ }
760
+ interface PoolStatusResponse {
761
+ session_id: number;
762
+ total: number;
763
+ agents: PoolAgent[];
764
+ }
765
+ interface MentionTarget {
766
+ identifier: string;
767
+ agent_id?: string;
768
+ agent_instance_id?: number;
769
+ }
770
+ interface PostDiscussionMessageRequest {
771
+ discussion_path: string;
772
+ speaker: string;
773
+ message_type: string;
774
+ mentions: string[];
775
+ mention_targets?: MentionTarget[];
776
+ body: string;
777
+ title?: string;
778
+ }
779
+ interface PostDiscussionMessageResponse {
780
+ ok: boolean;
781
+ message_index: number;
782
+ status: string;
783
+ remaining_messages: number;
784
+ participants_changed: boolean;
785
+ error?: string;
786
+ unresolved_mentions?: string[];
787
+ }
788
+ /**
789
+ * JETP-075: User-initiated discussion creation (POST /api/session/{sid}/discussion/create).
790
+ *
791
+ * Field shape mirrors backend Pydantic ``PostDiscussionCreateRequest`` 1:1
792
+ * (jetagents/runtime/discuss/api.py). 详见
793
+ * doc/proposals/JETP-075-user-initiated-discussion/00_protocol.md §2.
794
+ *
795
+ * 必填字段(pydantic ``Field(...)`` 强制):
796
+ * - ``topic`` : 1..100 chars, 进 YAML front-matter ``topic:``
797
+ * - ``creator`` : ``user:<id>``,必须出现在 participants 内
798
+ * - ``participants`` : 2..20 alias,第一位 = creator
799
+ *
800
+ * 可选字段:
801
+ * - ``max_messages`` : 5..500,默认 50
802
+ * - ``initial_body`` : ≤ 4000 chars;非空时同步写入首条消息并触发 ``_run_write_hook``
803
+ * - ``initial_mentions`` : 必须是 participants 子集(service-level guard)
804
+ * - ``initial_mention_targets``: 与 ``/message`` 端点同形态,用于 pin agent_instance_id
805
+ */
806
+ interface CreateDiscussionRequest {
807
+ topic: string;
808
+ creator: string;
809
+ participants: string[];
810
+ max_messages?: number;
811
+ initial_body?: string;
812
+ initial_mentions?: string[];
813
+ initial_mention_targets?: MentionTarget[];
814
+ }
815
+ /**
816
+ * JETP-075: Response of POST /api/session/{sid}/discussion/create。
817
+ *
818
+ * 字段含义见 doc/proposals/JETP-075-user-initiated-discussion/00_protocol.md §2/§5:
819
+ * - ``ok`` : false 时 error 非空
820
+ * - ``discussion_path`` : ``discussions/<slug>-<unix_ms>.disc.md`` 相对 workspace_root
821
+ * - ``status`` : 创建后恒为 ``'active'``;schema 上对齐 DiscussionMeta.status
822
+ * - ``message_count`` : 0 if no initial_body, 1 otherwise
823
+ * - ``participants`` : echo 回完整列表(前端可用来 hydrate 浮窗 metadata)
824
+ * - ``error`` : 错误时填,如 ``"creator must appear in participants"``
825
+ * - ``unresolved_mentions``: initial_mentions 中无法在 session pool 解析的 alias 子集
826
+ */
827
+ interface CreateDiscussionResponse {
828
+ ok: boolean;
829
+ discussion_path: string;
830
+ status: 'active' | 'converging' | 'resolved';
831
+ message_count: number;
832
+ participants: string[];
833
+ error: string;
834
+ unresolved_mentions: string[];
835
+ }
836
+ /**
837
+ * JETP-057:``getSessionHistory`` 入参契约。
838
+ *
839
+ * 设计:doc/proposals/JETP-057-history-by-client-id/chat-widget/01_adapter_design.md
840
+ *
841
+ * - ``clientIds`` 必传:禁止前端忘传 → 后端走 session-only 全表扫的退化路径。
842
+ * 常见取值:``['main']`` / ``['main', 'file:abc.txt', 'sel:section-1']``。
843
+ * - ``includeInFlight`` 默认 false(与后端默认对齐);前端控制器层默认传 true,
844
+ * 避免 in-flight 子 agent 卡刷新后消失。
845
+ * - ``pageSize`` / ``beforeCursor`` 用于 keyset 分页(可选)。
846
+ */
847
+ interface GetSessionHistoryOptions {
848
+ clientIds: string[];
849
+ pageSize?: number;
850
+ beforeCursor?: string;
851
+ includeInFlight?: boolean;
852
+ }
853
+ /**
854
+ * Session 列表项(用于侧栏 / 会话切换面板)。
855
+ *
856
+ * 字段优先级(用于 title 显示):
857
+ * 1. ``sessionTitle`` —— 后端 SESSION_TITLE 通知落库的"对话标题",最权威。
858
+ * 2. ``summary`` —— 首轮模型摘要,作为 fallback。
859
+ * 3. 都无 → 调用方自行兜底(如 "会话 {id}")。
860
+ *
861
+ * 历史背景:JETP-058 之前 demo 误用 ``title`` 字段名,永远拿不到值;
862
+ * 现在 SDK 强制规范化为 ``sessionTitle``,adapter 层负责把后端各种字段名
863
+ * 翻译过来。
864
+ */
865
+ interface SessionListItem {
866
+ id: number;
867
+ sessionTitle?: string | null;
868
+ summary?: string | null;
869
+ createdAt?: string | null;
870
+ updatedAt?: string | null;
871
+ /** 可选:会话累计运行时长(秒),后端有则透传。 */
872
+ runningTime?: number | null;
873
+ }
874
+ interface ListSessionsParams {
875
+ /** 1-based 页码;默认 1。 */
876
+ page?: number;
877
+ /** 每页大小;默认 20。 */
878
+ pageSize?: number;
879
+ }
880
+ interface ListSessionsResponse {
881
+ items: SessionListItem[];
882
+ total: number;
883
+ page: number;
884
+ pageSize: number;
885
+ }
233
886
  interface ChatWidgetAdapter {
234
887
  createSession(agentId: string): Promise<{
235
888
  sessionId: number;
236
889
  instanceId: number;
237
890
  }>;
238
891
  getSessionDetail(sessionId: number): Promise<SessionDetail>;
239
- getSessionHistory(sessionId: number): Promise<NotificationTurn[]>;
892
+ /**
893
+ * List sessions belonging to the current user (paged).
894
+ *
895
+ * 用于宿主侧栏 / `<SessionListPanel>`。当 adapter 不实现该方法时,
896
+ * `<SessionListPanel>` 显示"unsupported"空态,`useSessionList().supported`
897
+ * 返回 false。adapter 应负责字段名规范化(snake_case → SDK 标准)。
898
+ */
899
+ listSessions?(params?: ListSessionsParams): Promise<ListSessionsResponse>;
900
+ /**
901
+ * Delete a session by id.
902
+ *
903
+ * 当 adapter 不实现该方法时,`<SessionListPanel>` 隐藏每行的删除按钮,
904
+ * `useSessionList().canDelete` 返回 false。
905
+ */
906
+ deleteSession?(sessionId: number): Promise<void>;
907
+ getSessionHistory(sessionId: number, options: GetSessionHistoryOptions): Promise<NotificationTurn[] | PaginatedHistoryResponse>;
240
908
  getResourceContent(sessionId: number, resourceId: string): Promise<ResourceContent>;
241
909
  submitHITLResponse(response: HITLResponse): Promise<void>;
910
+ /**
911
+ * JETP-083 WS3.7.6 — fetch pending Collaborative HIL entities for the
912
+ * connecting principal.
913
+ *
914
+ * Used by `useGenUIPending(sessionId)` on session connect / reconnect
915
+ * (e.g. fresh client, reload, hot-failover). Returns *only* HILs whose
916
+ * `resolved_recipients` include the connecting principal — the backend
917
+ * applies the ACL via the registry's principal-scoped index, so this
918
+ * endpoint cannot leak across users.
919
+ *
920
+ * When absent, JETP-083 connect-time hydration is disabled and the
921
+ * widget falls back to live-only behaviour: a HIL pause is only seen
922
+ * by the originating client. (Same as pre-WS3.7.6 behaviour.)
923
+ *
924
+ * Backend: `GET /api/genui/pending?session_id=...` (jetagents `main.py`).
925
+ */
926
+ getPendingHILs?(sessionId: number): Promise<PendingHIL[]>;
927
+ /**
928
+ * 触发"协作式停止"信号:直接 `POST /api/session/stop`,由后端 handler 把
929
+ * `agent:signal:stop:{session_id}:{interaction_id}=stop` 写入 Redis;运行时
930
+ * 各检查点(agent_state_machine_v2 / simple_agent_pool / agent_executor /
931
+ * base_pusher)轮询同一 key 后 yield `StoppedAgentCommand` 优雅退出,并由
932
+ * pusher 推送 `CANCELED` 通知。
933
+ *
934
+ * 设计要点:
935
+ * - **不依赖 WS 活性**:HTTP 任意 Pod 接到都能写入共享 Redis,跨 Pod 一致;
936
+ * 而 WS `control_agent` 必须命中持有该 session pool 的同一进程。
937
+ * - **后端幂等**:键已为 `"stop"` 时直接返回 `success(data={})`,不会重复发
938
+ * `CANCELED`,前端连点两次安全。
939
+ * - **与 pause/resume 解耦**:pause/resume 修改 pool 进程内状态,必须 WS 直送;
940
+ * stop 只是写一个全局 Redis 标志,HTTP 更稳。
941
+ *
942
+ * 参数说明:
943
+ * - `sessionId`:必填;后端从 DB 取该 session 的最新 event 来定位 stop key。
944
+ * - `agentInstanceId`:保留参数,**当前后端 handler 不读**(仅 session 维度
945
+ * 停止整轮交互);保留是为了未来若引入实例级停止时调用方无需变更签名。
946
+ *
947
+ * 失败语义:401 由 adapter 的 `authedFetch` 自动 refresh + 重试;其它非 200
948
+ * 应抛 `ChatWidgetNetworkError`(含后端 `error("no event in session")` 等业务
949
+ * 失败码),上层据此 toast / 解锁按钮,避免吞错。
950
+ *
951
+ * 可选实现:自定义 adapter 未实现时,`useAgentControl.stop` 会回退到原 WS
952
+ * `control_agent { action: 'stop' }` 路径以保持向后兼容。
953
+ */
954
+ stopAgent?(params: {
955
+ sessionId: number;
956
+ agentInstanceId?: number;
957
+ }): Promise<void>;
242
958
  getStreamUrl(): string;
959
+ /**
960
+ * WebSocket URL for persistent session-level downlink (CWRF-010 S3 architecture).
961
+ * When provided and the session is active, the controller prefers WS over SSE.
962
+ * Messages are sent via fire-and-confirm POST; responses arrive through this WS channel.
963
+ * Falls back to SSE when absent or WS connection fails.
964
+ */
965
+ getWsUrl?(sessionId: number): string;
243
966
  getAuthHeaders(): Record<string, string>;
244
967
  getExtraHeaders?(): Record<string, string>;
968
+ /**
969
+ * Build the SSE request body for the stream endpoint.
970
+ * If implemented, ChatWidget uses the returned object as the POST body.
971
+ * If absent, ChatWidget sends the default simplified format {message, agent_id, ...}.
972
+ */
973
+ buildStreamBody?(params: {
974
+ message: string;
975
+ agentId: string;
976
+ sessionId: number | null;
977
+ interactionId: string;
978
+ agentInstanceId?: number;
979
+ callerInstanceId?: number;
980
+ selectedSkills?: SelectedSkillRef[];
981
+ activeSpecIds?: string[];
982
+ /**
983
+ * JETP-045 Layer 1:客户端连接子空间标识。
984
+ * 推荐由 `useClientId` hook 派生;不传时 adapter 兜底为 'main'。
985
+ */
986
+ clientId?: string;
987
+ /**
988
+ * JETP-045 Phase 6 — Layer 1.5 物理连接 ID(前端 ``useConnectionId`` 派生)。
989
+ * adapter 应把它写入 body 的 ``connection_id`` 字段;缺省时不写入,后端按
990
+ * "未知连接" 处理(不做 echo 抑制,等同 Phase 1-5 行为)。
991
+ */
992
+ connectionId?: string;
993
+ fileAttachments?: FileAttachment[];
994
+ /**
995
+ * 前端指定的"本次调用使用的模型",覆盖 agent 的默认 ``ModelMeta``。
996
+ * 缺省 / null 时维持原行为(agent 自己的注册模型),与历史版本完全兼容。
997
+ * 详见 ``ModelOverride``。
998
+ */
999
+ modelOverride?: ModelOverride | null;
1000
+ }): object;
1001
+ listSkills?(params?: SkillListParams): Promise<SkillListResponse>;
245
1002
  onAuthFailure?(): void;
246
1003
  refreshAuth?(): Promise<boolean>;
1004
+ /**
1005
+ * Batch-resolve @xref RID references to file metadata.
1006
+ * When absent, ResourceChip falls back to displaying the @xref description text.
1007
+ */
1008
+ resolveXrefs?(refs: XrefRef[]): Promise<XrefMeta[]>;
1009
+ /**
1010
+ * Obtain a direct URL for a resource (e.g. MinIO/S3 presigned URL) for streaming large binary files.
1011
+ * When absent, falls back to base64 decoding from ResourceContent.content.
1012
+ */
1013
+ getResourceUrl?(sessionId: number, resourceId: string): Promise<string>;
1014
+ /**
1015
+ * Obtain a server-rendered preview URL for office/legacy files (CWRF-008).
1016
+ * Backend converts the file (e.g. via LibreOffice headless) and returns a URL to the converted HTML/PDF.
1017
+ * When absent, office viewers fall back to client-side rendering or download link.
1018
+ */
1019
+ getPreviewUrl?(sessionId: number, resourceId: string, format?: 'html' | 'pdf'): Promise<string>;
1020
+ /**
1021
+ * Transform a raw SSE JSON object into ChatWidget SSEMessage format.
1022
+ * Used when connecting directly to backends that emit a different SSE schema
1023
+ * (e.g. JetAgents Notification format vs ChatWidget flat format).
1024
+ * Returns an array of SSEMessage objects (one notification may expand to multiple messages).
1025
+ * Return null/undefined to drop the message.
1026
+ */
1027
+ transformSSEMessage?(raw: Record<string, unknown>): SSEMessage[] | null;
1028
+ /**
1029
+ * Fetch provenance graph snapshot for a session.
1030
+ * When absent, provenance features are disabled.
1031
+ */
1032
+ getProvenanceGraph?(sessionId: number, params?: {
1033
+ since_turn_id?: number;
1034
+ limit?: number;
1035
+ }): Promise<ProvenanceGraphSnapshot>;
1036
+ /**
1037
+ * List files in a directory, filtered by extensions (CWRF-009).
1038
+ * Used by KiCad project viewer to discover all design files in a project directory.
1039
+ * When absent, project-level multi-file viewing is unavailable.
1040
+ */
1041
+ listDirectoryFiles?(sessionId: number, dirPrefix: string, options?: ListDirectoryFilesOptions): Promise<DirectoryFileEntry[]>;
1042
+ /**
1043
+ * Create an artifact share link (JETP-034).
1044
+ * When absent, Share button is hidden in jr-page viewer.
1045
+ */
1046
+ shareArtifact?(params: {
1047
+ artifactId: string;
1048
+ sessionId: number;
1049
+ title?: string;
1050
+ artifactType?: 'file' | 'jr-page';
1051
+ shareType?: 1 | 2;
1052
+ }): Promise<{
1053
+ shareCode: string;
1054
+ shareUrl: string;
1055
+ password?: string;
1056
+ } | null>;
1057
+ /**
1058
+ * Query the agent pool observation status for a session.
1059
+ * Returns the list of agent instances and their states from MonitorRegistry.
1060
+ * When absent, observation-driven status is disabled and the widget falls
1061
+ * back to event-driven status tracking.
1062
+ */
1063
+ getPoolStatus?(sessionId: number): Promise<PoolStatusResponse>;
1064
+ /**
1065
+ * 拉取"用户可选模型清单"。**唯一来源**是 hip-server,**不走 fusion**。
1066
+ *
1067
+ * 当 adapter 不实现该方法时,上层 ModelPicker 应隐藏自身(fall back 到 agent
1068
+ * 注册的默认模型,行为与历史版本完全一致)。
1069
+ *
1070
+ * URL 拼接规则:
1071
+ * ``${hipBaseUrl}/api/v1/models?...``,``hipBaseUrl`` 缺省时退化为相对 URL,
1072
+ * 交给开发态 vite proxy / 生产态网关接管,与本 adapter 其他 hip 调用一致。
1073
+ *
1074
+ * 三态 vs. 抛错:
1075
+ * - 网络/服务故障 → 抛 ``ChatWidgetNetworkError``,让 UI 决定降级(toast + 隐藏);
1076
+ * - 清单为空(数组长度 0) → 正常返回,UI 表现为"暂无可选模型",不弹错;
1077
+ * - 不同 ``groupBy`` 返回不同的 item 形态,靠泛型在编译期收敛。
1078
+ */
1079
+ listModels?<TGroup extends 'basename' | 'name' | 'none' = 'basename'>(params?: ListModelsParams & {
1080
+ groupBy?: TGroup;
1081
+ }): Promise<ListModelsResponse<TGroup extends 'basename' ? ModelListItemBasenameGrouped : TGroup extends 'name' ? ModelListItemGrouped : ModelListItemRaw>>;
1082
+ /**
1083
+ * 按 ``agentId`` 查询该 agent 在后端注册的默认模型,**仅用于 picker 展示态**。
1084
+ *
1085
+ * 与 ``listModels`` 一样唯一走 hip-server(``GET /api/v1/agents/{agent_id}/default-model``),
1086
+ * 不绕 fusion。该端点是后续 hip 全量代理 jetagents 的入口之一。
1087
+ *
1088
+ * 三态约定:
1089
+ * - 命中:返回 ``{ name, displayName?, version? }``,picker 把展示态自动定位到该 model;
1090
+ * - 业务找不到 / 上游 404:返回 ``null``(**不抛**),picker 退化到"显示默认模型"标签;
1091
+ * - 网络/超时/5xx:返回 ``null``(**不抛**),同上兜底;调用方真的关心错误时
1092
+ * 可以观察 ``console.warn``。
1093
+ *
1094
+ * 这种"全部失败都吞成 null"的策略是有意为之:
1095
+ * 该方法是"展示性的人因优化",**不能因为它失败就阻塞用户输入**——
1096
+ * 失败时 picker 仍可正常工作,只是少一个细节。所以 adapter 这一层吃掉异常,
1097
+ * 而不是把它推给 UI 层做 try/catch。
1098
+ *
1099
+ * 当 adapter 不实现该方法时,picker 永远只显示"默认模型"占位,不报错。
1100
+ */
1101
+ getAgentDefaultModel?(agentId: string): Promise<{
1102
+ name: string;
1103
+ displayName?: string;
1104
+ version?: string;
1105
+ } | null>;
1106
+ /**
1107
+ * JETP-038: Post a human message to a discussion file.
1108
+ * When absent, DiscussionComposer is hidden.
1109
+ */
1110
+ postDiscussionMessage?(sessionId: number, req: PostDiscussionMessageRequest): Promise<PostDiscussionMessageResponse>;
1111
+ /**
1112
+ * JETP-075: Create a new discussion file (user-initiated).
1113
+ *
1114
+ * 调用后端 ``POST /api/session/{sid}/discussion/create``:
1115
+ * - 在 workspace 下生成 ``discussions/<slug>-<unix_ms>.disc.md``
1116
+ * - YAML front-matter 持久化 topic / participants / created_by 等元数据
1117
+ * - 若 ``initial_body`` 非空,同时写入首条消息并触发 ``DiscussionWriteHook``
1118
+ * (进而 reinvoke @ 中的 agent / 投递 inbox notification)
1119
+ *
1120
+ * **当 adapter 不实现该方法时**:宿主端"创建讨论"入口必须隐藏或禁用,
1121
+ * 否则会出现"前端开了浮窗但 .disc.md 不存在 → DiscussionViewer 一直显示
1122
+ * 占位"的退化症(即 JETP-075 修复的 bug 形态)。
1123
+ *
1124
+ * 协议契约:``CreateDiscussionRequest`` / ``CreateDiscussionResponse``
1125
+ * 与后端 Pydantic schema 1:1 对齐,详见
1126
+ * doc/proposals/JETP-075-user-initiated-discussion/00_protocol.md §2。
1127
+ *
1128
+ * 错误处理(adapter 应原样抛出供上层 try/catch):
1129
+ * - 400 → ``CreateDiscussionResponse.error`` 非空(topic empty / creator
1130
+ * not in participants / mentions not subset)
1131
+ * - 404 → workspace 未 onboard,宿主侧应 toast 提示
1132
+ * - 409 → 同毫秒 slug 碰撞,宿主侧建议重试一次(带新 ts)
1133
+ * - 5xx → 网络/持久化失败,按 ChatWidgetNetworkError 风格抛出
1134
+ */
1135
+ createDiscussion?(sessionId: number, body: CreateDiscussionRequest): Promise<CreateDiscussionResponse>;
1136
+ /**
1137
+ * JETP-038: List agents in the session pool (for @mention autocomplete).
1138
+ * When absent, MentionAutocomplete only shows current participants.
1139
+ */
1140
+ getPoolAgents?(sessionId: number): Promise<PoolAgent[]>;
1141
+ /**
1142
+ * Download all visible workspace files as a single .zip archive.
1143
+ * When absent, the download button is hidden in WorkspacePanel.
1144
+ */
1145
+ downloadWorkspaceZip?(sessionId: number): Promise<void>;
1146
+ /**
1147
+ * JETP-040 / JETP-058: Upload files to the knowledge base (batch).
1148
+ * Returns resource_ids for use in send_message file contents.
1149
+ * When sessionId is provided, files are also registered in the workspace.
1150
+ * When absent, file attachment UI is hidden.
1151
+ *
1152
+ * `clientId` (JETP-058, v2 `^c_[A-Za-z0-9]{22}$`) 必填:服务端 ARTIFACT_* 通知的
1153
+ * Layer-1 子空间标识。整 batch 复用同一 cid;retry 必须传同一 cid,让
1154
+ * `_aggregate_turn` 走 `interaction_id` 幂等键合并到同一序列。
1155
+ */
1156
+ uploadFiles?(files: File[], sessionId: number | undefined, clientId: string): Promise<FileUploadResult>;
1157
+ /**
1158
+ * JETP-040: Poll upload processing status for previously uploaded files.
1159
+ */
1160
+ getUploadStatus?(resourceIds: string[]): Promise<FileUploadStatusResult>;
1161
+ /**
1162
+ * JETP-040 / JETP-058: Upload files directly to the workspace file system.
1163
+ * When absent, the upload button is hidden in WorkspacePanel.
1164
+ *
1165
+ * `options.clientId` (JETP-058, v2) 必填,理由同 `uploadFiles`。
1166
+ */
1167
+ uploadWorkspaceFiles?(sessionId: number, files: File[], options: {
1168
+ targetDirectory?: string;
1169
+ clientId: string;
1170
+ }): Promise<WorkspaceUploadResult>;
1171
+ createWorkspaceDirectory?(sessionId: number, dirName: string, parentPath?: string): Promise<{
1172
+ code: number;
1173
+ message: string;
1174
+ }>;
1175
+ renameWorkspaceItem?(sessionId: number, oldPath: string, newName: string): Promise<{
1176
+ code: number;
1177
+ message: string;
1178
+ }>;
1179
+ deleteWorkspaceItems?(sessionId: number, paths: string[]): Promise<{
1180
+ code: number;
1181
+ message: string;
1182
+ }>;
1183
+ moveWorkspaceItems?(sessionId: number, sourcePaths: string[], targetDir: string): Promise<{
1184
+ code: number;
1185
+ message: string;
1186
+ }>;
1187
+ copyWorkspaceItems?(sessionId: number, sourcePaths: string[], targetDir: string): Promise<{
1188
+ code: number;
1189
+ message: string;
1190
+ }>;
1191
+ }
1192
+ /** Input parameter for @xref reference resolution */
1193
+ interface XrefRef {
1194
+ /** Raw URI, e.g. "rid://res-abc123#§3.2" or "url://docs.example.com/api" */
1195
+ uri: string;
1196
+ /** Description parameter from the @xref markup */
1197
+ description: string;
1198
+ /** Relationship type */
1199
+ relation: 'cites' | 'implements' | 'extends' | 'derived_from' | 'supersedes' | 'related';
1200
+ }
1201
+ /** Return value from resolveXrefs */
1202
+ interface XrefMeta {
1203
+ /** Corresponding original URI */
1204
+ uri: string;
1205
+ /** Resolved file name */
1206
+ file_name?: string;
1207
+ /** File MIME type */
1208
+ mime_type?: string;
1209
+ /** File path in workspace */
1210
+ git_path?: string;
1211
+ /** Resource ID usable with getResourceContent */
1212
+ resource_id?: string;
1213
+ /** File size in bytes */
1214
+ file_size?: number;
1215
+ }
1216
+ /** Frontend @xref parse result — aligned with backend xref_parser.py XrefRecord format */
1217
+ interface XrefRecord {
1218
+ relation: string;
1219
+ target_resource: string;
1220
+ target_file_id: string | null;
1221
+ target_location: string | null;
1222
+ description: string;
1223
+ source_line: number;
1224
+ }
1225
+ /** File category enum — routes to the correct viewer */
1226
+ type FileCategory$1 = 'markdown' | 'code' | 'text' | 'image' | 'video' | 'audio' | 'html' | 'json' | 'pdf' | 'kicad' | '3d' | 'step' | 'gerber' | 'word' | 'excel' | 'powerpoint' | 'unknown';
1227
+ /** KiCad 画布点选(需 jp-kicanvas 透出 kicanvas:select + detail.jp) */
1228
+ interface KicadCanvasSelectionPayload {
1229
+ uuid: string | null;
1230
+ snippet: string | null;
1231
+ /** 为 true 表示收到画布选中事件但无 detail.jp(当前为官方 KiCanvas) */
1232
+ noJp?: boolean;
1233
+ /** 点击位置相对于画布容器的坐标,用于浮动工具栏定位 */
1234
+ anchorRect?: {
1235
+ top: number;
1236
+ left: number;
1237
+ width: number;
1238
+ height: number;
1239
+ };
1240
+ /** 多选时的所有 uuid+snippet 列表 */
1241
+ items?: Array<{
1242
+ uuid: string;
1243
+ snippet: string | null;
1244
+ }>;
1245
+ }
1246
+ interface FileReference {
1247
+ resourceId: string;
1248
+ sessionId: number;
1249
+ fileName: string;
1250
+ mimeType?: string | null;
1251
+ specId?: string;
1252
+ selection?: {
1253
+ text: string;
1254
+ startLine?: number;
1255
+ endLine?: number;
1256
+ /** PDF page number (1-based) */
1257
+ page?: number;
1258
+ /** End page when selection spans pages */
1259
+ endPage?: number;
1260
+ /** Base64 data-url when an image was selected */
1261
+ imageSrc?: string;
1262
+ };
1263
+ }
1264
+ interface UploadedFileInfo {
1265
+ resourceId: string;
1266
+ fileName: string;
1267
+ gitPath?: string;
1268
+ localFile?: File;
1269
+ status: 'uploading' | 'processing' | 'ready' | 'error';
1270
+ progress?: string;
1271
+ error?: string;
1272
+ }
1273
+ interface FileUploadResult {
1274
+ status?: 'accepted' | 'partial_success' | 'failed';
1275
+ code?: number;
1276
+ message: string;
1277
+ data: {
1278
+ files: Array<{
1279
+ resource_id: string;
1280
+ original_filename: string;
1281
+ status: number;
1282
+ message: string;
1283
+ git_path?: string;
1284
+ git_commit_hash?: string;
1285
+ }>;
1286
+ errors?: Array<{
1287
+ original_filename: string;
1288
+ error: string;
1289
+ }>;
1290
+ total_files: number;
1291
+ successful_uploads: number;
1292
+ failed_uploads: number;
1293
+ };
1294
+ }
1295
+ interface FileUploadStatusResult {
1296
+ status: string;
1297
+ data: {
1298
+ files: Array<{
1299
+ resource_id: string;
1300
+ status: number;
1301
+ progress?: string | null;
1302
+ }>;
1303
+ successful_count: number;
1304
+ failed_count: number;
1305
+ not_found_resource_ids: string[];
1306
+ total_requested: number;
1307
+ };
1308
+ }
1309
+ interface WorkspaceUploadResult {
1310
+ code: number;
1311
+ message: string;
1312
+ data?: unknown;
1313
+ }
1314
+ interface FileAttachment {
1315
+ resourceId: string;
1316
+ fileName: string;
1317
+ gitPath?: string;
247
1318
  }
248
1319
  declare function mergeConsecutiveThinkMessages(messages: AggregatedMessage[]): AggregatedMessage[];
249
1320
  interface TodoCardProps {
@@ -267,6 +1338,9 @@ interface MessageContentProps {
267
1338
  enableTypewriter?: boolean;
268
1339
  typewriterSpeed?: number;
269
1340
  onArtifactClick?: (artifact: Artifact) => void;
1341
+ onHITLSubmit?: (response: HITLResponse) => Promise<void>;
1342
+ renderToolResult?: (displayType: string, data: ToolCallData) => React__default.ReactNode | null;
1343
+ observedInstanceStates?: Map<number, PoolAgent>;
270
1344
  }
271
1345
  interface ChildAgentCardProps {
272
1346
  message: AggregatedMessage;
@@ -279,6 +1353,9 @@ interface ChildAgentCardProps {
279
1353
  endedAgentInstanceIds?: Set<number>;
280
1354
  /** 本轮次全部消息,用于判断该 agent 是否有未完成的工具(子 agent 的 MCP 消息可能挂在别的 parent 下,不在此卡片的 children 里) */
281
1355
  allRoundMessages?: AggregatedMessage[];
1356
+ onHITLSubmit?: (response: HITLResponse) => Promise<void>;
1357
+ /** Observation-driven instance states from MonitorRegistry (pool observation). */
1358
+ observedInstanceStates?: Map<number, PoolAgent>;
282
1359
  }
283
1360
  interface PlanCardProps {
284
1361
  plan: TaskPlan;
@@ -287,24 +1364,90 @@ interface PlanCardProps {
287
1364
  }
288
1365
 
289
1366
  /**
290
- * ChatWidget 主组件
1367
+ * ChatWidget 主组件 — UI Shell
291
1368
  *
292
- * 严格按照设计文档实现:
293
- * - SSE 消息流处理
294
- * - 动态置顶(滚动切换,带防抖和滞后阈值)
295
- * - 多轮对话展示
296
- * - 平滑过渡动画(淡入淡出)
297
- * - 子 Agent 卡片
298
- * - Human-in-the-loop 支持
1369
+ * Business logic (SSE, aggregation, session, status) is delegated to
1370
+ * useChatWidgetController. This file only owns DOM/scroll/viewer/animation.
299
1371
  */
300
1372
 
301
- declare const ChatWidget: React.FC<ChatWidgetProps>;
1373
+ declare const ChatWidget: React__default.FC<ChatWidgetProps>;
1374
+
1375
+ type IconName = 'robot' | 'chat' | 'clipboard' | 'paperclip' | 'chart' | 'notepad' | 'warning' | 'check' | 'checkCircle' | 'hourglass' | 'spinner' | 'x' | 'xCircle' | 'circle' | 'caretDown' | 'caretRight' | 'lightning' | 'gear' | 'play' | 'brain' | 'list' | 'file' | 'fileText' | 'fileCode' | 'filePdf' | 'filePlus' | 'fileXls' | 'fileDoc' | 'filePpt' | 'fileCsv' | 'fileZip' | 'download' | 'arrowsOut' | 'arrowsIn' | 'arrowUp' | 'minus' | 'magnifyingGlass' | 'globe' | 'code' | 'terminal' | 'package' | 'copy' | 'link' | 'share' | 'arrowLeft' | 'info' | 'compress' | 'eye' | 'circuitry' | 'user' | 'image' | 'folder' | 'folderOpen' | 'house' | 'pencilSimple' | 'chatCircleDots' | 'pushPin' | 'pause' | 'stop' | 'table' | 'layers' | 'brackets' | 'usersThree' | 'uploadSimple' | 'plus' | 'folderPlus' | 'arrowRight' | 'dotsThree' | 'cpu' | 'sparkle' | 'chevronDown';
1376
+
1377
+ type IconWeight = 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone';
1378
+ interface IconProps {
1379
+ name: IconName;
1380
+ size?: number;
1381
+ weight?: IconWeight;
1382
+ className?: string;
1383
+ color?: string;
1384
+ style?: React__default.CSSProperties;
1385
+ 'aria-hidden'?: boolean;
1386
+ 'aria-label'?: string;
1387
+ }
1388
+ declare const Icon: React__default.FC<IconProps>;
1389
+
1390
+ type TransportMode = 'ws' | 'sse';
1391
+ interface AgentInstanceState {
1392
+ agentInstanceId: number;
1393
+ status: 'running' | 'paused' | 'finished' | 'stopped' | 'error';
1394
+ name?: string;
1395
+ interactionId?: string;
1396
+ }
1397
+ interface SessionChannelMessage {
1398
+ type: string;
1399
+ data: unknown;
1400
+ interactionId?: string;
1401
+ agentInstanceId?: number;
1402
+ seq?: number;
1403
+ }
1404
+ interface AgentControlFrame {
1405
+ action: 'pause' | 'resume' | 'stop';
1406
+ agentInstanceId: number;
1407
+ }
1408
+ interface UseSessionChannelOptions {
1409
+ sessionId: number | null;
1410
+ wsUrl?: string | null;
1411
+ token?: string | null;
1412
+ transport?: TransportMode;
1413
+ enabled?: boolean;
1414
+ /**
1415
+ * JETP-045 P5 (P2-T11/T13):cursor 形态升级为 ``Map<"${iid}::${callee}", max_turn_index>``。
1416
+ * 多 callee fan-out 场景下不再撞 key(旧 ``Record<iid, max>`` 会丢一个 callee
1417
+ * 的记录)。subscribe 时序列化为 array of (interaction_id, callee_instance_id,
1418
+ * max_turn_index);后端 ``/ws/session/{id}`` handler (PR-8 P2-T14) 同时支持
1419
+ * 旧 dict 形态以兼容老前端。
1420
+ */
1421
+ turnCursorRef?: RefObject<Map<string, number>>;
1422
+ onMessage?: (msg: SessionChannelMessage) => void;
1423
+ onStatusEvent?: (event: SessionChannelMessage) => void;
1424
+ /** Fired when the server sends DB-sourced recovery turns after detecting
1425
+ * that Redis Streams have been trimmed past the client's cursor. */
1426
+ onRecoveryTurns?: (turns: unknown[]) => void;
1427
+ }
1428
+ interface UseSessionChannelReturn {
1429
+ connected: boolean;
1430
+ transport: TransportMode;
1431
+ agentStates: Map<number, AgentInstanceState>;
1432
+ sendControlFrame: (frame: AgentControlFrame) => void;
1433
+ lastSeq: number;
1434
+ /** Force reconnect if WS is not connected; resolves when connected or rejects on timeout. */
1435
+ ensureConnected: () => Promise<void>;
1436
+ }
1437
+ declare function useSessionChannel(options: UseSessionChannelOptions): UseSessionChannelReturn;
302
1438
 
303
1439
  /**
304
1440
  * SSE 连接 Hook (SDK version)
305
1441
  *
306
- * Auth and headers are fully delegated to ChatWidgetAdapter,
307
- * eliminating direct localStorage / env-var coupling.
1442
+ * JETP-056 P2 收敛:
1443
+ * - 全链路统一 ``fetch + ReadableStream``:废弃浏览器 ``EventSource``。
1444
+ * 原因:``EventSource`` API 不支持自定义 header,无法注入 ``Authorization``,
1445
+ * 在 Bearer-only 部署下完全跳过鉴权(依赖 cookie 兜底是错的)。
1446
+ * - 鉴权 / 401 重试 / onAuthFailure 全部收敛到 ``useAuthedFetch``:
1447
+ * - useSSE 不再手写 401 重试逻辑;
1448
+ * - 与 useChatWidgetController 等其他鉴权入口共用同一条策略链。
1449
+ * - 下游 SSE 解析逻辑(reader loop / data: 解析 / transformSSEMessage)保持不变,
1450
+ * 行为兼容;GET 与 POST 仅在 ``method`` / ``body`` 上有差异。
308
1451
  */
309
1452
 
310
1453
  type ConnectionStatus = 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error';
@@ -324,6 +1467,132 @@ interface UseSSEReturn {
324
1467
  }
325
1468
  declare function useSSE(options: UseSSEOptions): UseSSEReturn;
326
1469
 
1470
+ /**
1471
+ * usePoolObservation — observation-driven agent pool status
1472
+ *
1473
+ * Hybrid push+poll strategy:
1474
+ * Push: pool_snapshot events from the WS status stream give near-instant updates.
1475
+ * Poll: GET /api/monitor/pool/{session_id} at adaptive intervals as a reliable fallback.
1476
+ *
1477
+ * Consumers:
1478
+ * - Top bar: sessionBusy (any RUNNING agent in the session)
1479
+ * - Child agent cards: instanceStates.get(agentInstanceId)
1480
+ * - Input box: caller checks the primary agent instance via instanceStates
1481
+ */
1482
+
1483
+ interface PoolObservation {
1484
+ sessionBusy: boolean;
1485
+ instanceStates: Map<number, PoolAgent>;
1486
+ poolAgents: PoolAgent[];
1487
+ }
1488
+
1489
+ interface ChatWidgetControllerOptions {
1490
+ adapter: ChatWidgetAdapter;
1491
+ sessionId?: string | number;
1492
+ reuseAgentInstance?: boolean;
1493
+ activeSpecIdsRef?: React.RefObject<string[]>;
1494
+ /** Transport mode: 'ws' uses WebSocket, 'sse' uses Server-Sent Events. No fallback between them. */
1495
+ transport?: 'ws' | 'sse';
1496
+ /**
1497
+ * JETP-058:拉历史时透传给 adapter 的 v2 ``c_<22>`` client_ids 列表。
1498
+ *
1499
+ * - **不再有 legacy "main" 默认值**:v2-only 强约束下,调用方未派生出任何 v2 cid 之前
1500
+ * controller 不会发起 history 请求(避免 silent fallback 写脏数据);
1501
+ * - 由 ChatWidget 内部派生为该 session 全部任务话池 cid 列表后再下传;
1502
+ * - 空数组 / undefined → controller skip 调 adapter,等下一轮派生到非空 list 时自动重拉。
1503
+ */
1504
+ historyClientIds?: string[];
1505
+ /**
1506
+ * JETP-057:拉历史时是否包含 status='building' 的 in-flight turns。
1507
+ * 前端默认 ``true`` —— 否则刷新后正在跑的子 agent 卡片会暂时消失。
1508
+ */
1509
+ historyIncludeInFlight?: boolean;
1510
+ /**
1511
+ * 是否在 mount 时立即调用 ``adapter.createSession`` 预分配 session+workspace。
1512
+ * 默认 ``true`` 保持原 SDK 行为;多会话宿主(如 Demo / Console)应传 ``false``,
1513
+ * 避免每次刷新(无 ``sessionId`` prop 的 mount)都在后端 page 列表里插入空 session。
1514
+ */
1515
+ eagerSessionCreation?: boolean;
1516
+ onStatusChange?: (status: ExecutionStatus) => void;
1517
+ onConnectionChange?: (connected: boolean) => void;
1518
+ onRoundChange?: (rounds: Round[]) => void;
1519
+ onMessageAppended?: (message: AggregatedMessage, round?: Round) => void;
1520
+ onRoundStart?: (interactionId: string, userMessage: string) => void;
1521
+ onRoundEnd?: (interactionId: string) => void;
1522
+ onError?: (error: Error) => void;
1523
+ onDiscussionUpdate?: (event: Record<string, unknown>) => void;
1524
+ /**
1525
+ * 会话生命周期事件回调。controller 在以下时机各 emit 一次:
1526
+ *
1527
+ * - `created` :``adapter.createSession`` 成功 / 后端通过 SSE ``session_info`` 推回新 session_id;
1528
+ * 从 ``sessionId`` prop 恢复历史会话不会触发本事件。
1529
+ * - `updated` :当前以 ``session_title`` 变化为唯一来源 —— SSE ``session_title`` 通知 /
1530
+ * ``loadHistory`` 取 detail / 兜底 ``getSessionDetail`` 拿到非空 title 都会各触发一次。
1531
+ *
1532
+ * ChatWidget 默认会把这两条 emit 转译成 ``'session-created' / 'session-updated'``
1533
+ * InteractionEvent;如果宿主不走 InteractionContext,可以直接读这个回调。
1534
+ */
1535
+ onSessionEvent?: (event: SessionLifecycleEvent) => void;
1536
+ /**
1537
+ * JETP-073:client("办公室")级 title 解析事件回调。
1538
+ *
1539
+ * 触发时机:SSE/WS 收到 ``notification_type: 'client_title'`` 消息(backend
1540
+ * `node_title_agent` 在 first agent start 后基于 LLM 派生出的客户端标题)。
1541
+ *
1542
+ * 与 ``onSessionEvent`` 关键区别:
1543
+ * - ``onSessionEvent.updated`` 一个 session 触发一次;
1544
+ * - ``onClientTitleEvent`` 一个 session 内每个 client 各触发一次(多 client 场景常见)。
1545
+ *
1546
+ * 上层(如 yumiai-web ``WorkspaceCore``)把 ``clientId → clientTitle`` 累加到本地 map,
1547
+ * 下游派生(如 ``useDeriveCubicleClients``)优先使用 backend 真值,缺值时再 fallback。
1548
+ *
1549
+ * 本回调不会被 controller 内部消化掉;message 也不会进入 rounds(被
1550
+ * ``LIFECYCLE_TURN_TYPES`` 过滤)。
1551
+ */
1552
+ onClientTitleEvent?: (event: ClientTitleEvent) => void;
1553
+ }
1554
+ interface ChatWidgetControllerState {
1555
+ executionStatus: ExecutionStatus;
1556
+ connectionStatus: ConnectionStatus;
1557
+ /** Effective transport mode: 'ws' when WebSocket is active, 'sse' otherwise */
1558
+ activeTransport: 'ws' | 'sse';
1559
+ rounds: Round[];
1560
+ /** Interaction IDs owned by this tab (sent locally or loaded from history). */
1561
+ localInteractionIds: ReadonlySet<string>;
1562
+ currentSessionId: number | null;
1563
+ sessionTitle: string;
1564
+ todoMap: Map<string, TodoData>;
1565
+ specMetaMap: Map<string, {
1566
+ resourceId: string;
1567
+ gitPath: string;
1568
+ }>;
1569
+ /** JETP-083 WS3.7.5 — terminal lifecycle markers (cancelled/error) by spec_id. */
1570
+ specLifecycleMap: Map<string, SpecLifecycleEntry>;
1571
+ sendMessage: (message: string, agentId?: string, inlineRefs?: FileReference[], selectedSkills?: SelectedSkillRef[], overrideInstanceId?: number | null, clientId?: string, fileAttachments?: FileAttachment[], modelOverride?: ModelOverride | null) => Promise<void>;
1572
+ widgetAPI: ChatWidgetAPI;
1573
+ /** Agent instance states tracked via WS status stream. Empty map when SSE transport. */
1574
+ agentStates: Map<number, AgentInstanceState>;
1575
+ /** Send agent control frame (pause/resume/stop) via WS. No-op when SSE. */
1576
+ sendControlFrame: UseSessionChannelReturn['sendControlFrame'];
1577
+ /** Whether any agent is RUNNING in the session (observation-driven, for top bar). */
1578
+ sessionBusy: boolean;
1579
+ /** Whether the WebSocket is connected (for useDiscussions polling adjustment). */
1580
+ wsConnected: boolean;
1581
+ /** Whether the primary (level-0) agent instance is RUNNING (observation-driven, for input box). */
1582
+ primaryAgentBusy: boolean;
1583
+ /** Full pool observation data (for child agent cards). */
1584
+ poolObservation: PoolObservation;
1585
+ /** JETP-037: whether more older pages are available */
1586
+ hasMore: boolean;
1587
+ /** JETP-037: whether an older page is currently loading */
1588
+ loadingMore: boolean;
1589
+ /** JETP-037: trigger loading of the next older page */
1590
+ loadOlderPage: () => Promise<void>;
1591
+ /** Ensure a session exists, creating one with retries if needed. */
1592
+ ensureSession: () => Promise<number>;
1593
+ }
1594
+ declare function useChatWidgetController(options: ChatWidgetControllerOptions): ChatWidgetControllerState;
1595
+
327
1596
  /**
328
1597
  * 消息聚合 Hook
329
1598
  *
@@ -343,95 +1612,1427 @@ interface MessageAggregatorState {
343
1612
  interface UseMessageAggregatorReturn {
344
1613
  state: MessageAggregatorState;
345
1614
  todoMap: Map<string, TodoData>;
1615
+ specMetaMap: Map<string, {
1616
+ resourceId: string;
1617
+ gitPath: string;
1618
+ }>;
1619
+ /** JETP-083 WS3.7.5 — terminal lifecycle markers (cancelled / error) keyed by spec_id. */
1620
+ specLifecycleMap: Map<string, SpecLifecycleEntry>;
346
1621
  processMessage: (message: SSEMessage) => void;
347
1622
  getRoundsList: () => Round[];
348
1623
  getCurrentRound: () => Round | null;
349
- startNewRound: (interactionId: string, userMessage: string) => void;
1624
+ startNewRound: (interactionId: string, userMessage: string, clientId?: string) => void;
350
1625
  loadRounds: (rounds: Round[]) => void;
1626
+ prependRounds: (olderRounds: Round[]) => void;
1627
+ mergeRecoveryRounds: (rounds: Round[]) => void;
351
1628
  finalizeRound: (interactionId: string) => void;
1629
+ loadTodoMap: (entries: Map<string, TodoData>) => void;
1630
+ loadSpecMetaMap: (entries: Map<string, {
1631
+ resourceId: string;
1632
+ gitPath: string;
1633
+ }>) => void;
1634
+ loadSpecLifecycleMap: (entries: Map<string, SpecLifecycleEntry>) => void;
352
1635
  clear: () => void;
1636
+ /**
1637
+ * JETP-045 Phase 6 (P6-T07) — 设置当前 tab 的物理连接 ID。
1638
+ * Aggregator 用 ``msg.connection_id_from === myConnectionId`` 识别 echo (AC-CONN-006/007)。
1639
+ * Controller 在 mount 期间用 ``useConnectionId()`` 派生后调用一次即可;多次调用幂等。
1640
+ * 不传或传 undefined ⇒ 关闭 echo 检测,行为退化到 Phase 1-5 (AC-CONN-008)。
1641
+ */
1642
+ setMyConnectionId: (id: string | undefined) => void;
353
1643
  }
354
1644
  declare function useMessageAggregator(): UseMessageAggregatorReturn;
355
1645
 
1646
+ interface ProjectFile {
1647
+ name: string;
1648
+ url?: string;
1649
+ content?: string;
1650
+ }
1651
+ interface UseProjectFilesOptions {
1652
+ gitPath: string;
1653
+ extensions: string[];
1654
+ enabled: boolean;
1655
+ recursive?: boolean;
1656
+ generateUrls?: boolean;
1657
+ /** Extra deps that trigger re-discovery (e.g. file content for project files). */
1658
+ deps?: unknown[];
1659
+ }
1660
+ interface UseProjectFilesResult {
1661
+ files: ProjectFile[];
1662
+ loading: boolean;
1663
+ error: string | null;
1664
+ }
356
1665
  /**
357
- * 置顶区域组件
358
- * 显示当前置顶轮次的用户消息、任务计划和 Todo
1666
+ * Generic hook: discover and load all files matching given extensions
1667
+ * under the directory derived from `gitPath`.
1668
+ *
1669
+ * Works for any viewer that needs sibling-file discovery:
1670
+ * KiCad (.kicad_sch/.kicad_pcb), Gerber (.gbr/.drl), etc.
359
1671
  */
1672
+ declare function useProjectFiles(opts: UseProjectFilesOptions): UseProjectFilesResult;
360
1673
 
361
- declare const PinnedArea: React.FC<PinnedAreaProps>;
1674
+ interface ViewerTab {
1675
+ id: string;
1676
+ resourceId: string;
1677
+ fileName: string;
1678
+ mimeType?: string;
1679
+ isNew?: boolean;
1680
+ isDirty?: boolean;
1681
+ annotationCount?: number;
1682
+ openedAt: number;
1683
+ }
1684
+ interface UseViewerTabsReturn {
1685
+ tabs: ViewerTab[];
1686
+ activeTabId: string | null;
1687
+ addTab: (tab: Omit<ViewerTab, 'id' | 'openedAt' | 'isNew'>) => string;
1688
+ removeTab: (tabId: string) => void;
1689
+ switchTab: (tabId: string) => void;
1690
+ updateTab: (tabId: string, updates: Partial<ViewerTab>) => void;
1691
+ getActiveTab: () => ViewerTab | null;
1692
+ markSeen: (tabId: string) => void;
1693
+ findByResourceId: (resourceId: string) => ViewerTab | undefined;
1694
+ clearAll: () => void;
1695
+ }
1696
+ declare function useViewerTabs(): UseViewerTabsReturn;
362
1697
 
363
- /**
364
- * 轮次标题组件
365
- * 在消息流中显示非置顶轮次的用户消息和计划
366
- */
1698
+ type EscHandler = () => boolean | void;
1699
+ declare const ESC_PRIORITY: {
1700
+ readonly INLINE_INPUT: 60;
1701
+ readonly FLOATING_TOOLBAR: 50;
1702
+ readonly ANNOTATION_FAB: 40;
1703
+ readonly OVERLAY: 30;
1704
+ readonly EXIT_IMMERSIVE: 10;
1705
+ };
1706
+ declare function useEscStack(handler: EscHandler, active: boolean, priority?: number): void;
367
1707
 
368
- declare const RoundHeader: React.FC<RoundHeaderProps>;
1708
+ interface ArtifactRef {
1709
+ resourceId: string;
1710
+ fileName: string;
1711
+ mimeType?: string;
1712
+ }
1713
+ interface UseAutoTabOptions {
1714
+ artifacts: ArtifactRef[];
1715
+ tabs: UseViewerTabsReturn;
1716
+ enabled?: boolean;
1717
+ autoOpenSplit?: () => void;
1718
+ }
1719
+ declare function useAutoTab({ artifacts, tabs, enabled, autoOpenSplit, }: UseAutoTabOptions): void;
369
1720
 
370
- /**
371
- * 消息内容组件
372
- * 根据消息类型渲染不同的内容
373
- * 文本类型使用 Streamdown 渲染 Markdown(代码高亮、Mermaid、数学公式、CJK)
374
- * 保留逐字打字机效果:将逐步展开的文本交给 Streamdown 渲染
375
- */
1721
+ interface WorkspaceFile {
1722
+ resourceId: string;
1723
+ fileName: string;
1724
+ gitPath: string;
1725
+ mimeType?: string;
1726
+ downloadUrl?: string;
1727
+ nodeType: string;
1728
+ timestamp?: number;
1729
+ }
1730
+ interface WorkspaceTreeNode {
1731
+ id: string;
1732
+ name: string;
1733
+ path: string;
1734
+ type: 'file' | 'dir';
1735
+ children?: WorkspaceTreeNode[];
1736
+ file?: WorkspaceFile;
1737
+ }
1738
+ interface UseWorkspaceFilesOptions {
1739
+ adapter: ChatWidgetAdapter;
1740
+ sessionId: number | null;
1741
+ pollIntervalMs?: number;
1742
+ /** When this flips from false→true (WS reconnect), trigger an immediate refresh. */
1743
+ wsConnected?: boolean;
1744
+ }
1745
+ interface UseWorkspaceFilesReturn {
1746
+ files: WorkspaceFile[];
1747
+ tree: WorkspaceTreeNode[];
1748
+ recentChanges: WorkspaceFile[];
1749
+ fileCount: number;
1750
+ loading: boolean;
1751
+ error: Error | null;
1752
+ refresh: () => void;
1753
+ }
1754
+ declare function useWorkspaceFiles({ adapter, sessionId, pollIntervalMs, wsConnected, }: UseWorkspaceFilesOptions): UseWorkspaceFilesReturn;
376
1755
 
377
- declare const MessageContent: React.FC<MessageContentProps>;
1756
+ interface TreePersistState {
1757
+ expandedPaths: string[];
1758
+ scrollTop: number;
1759
+ }
1760
+ declare function useTreePersist(sessionId: number | null): {
1761
+ load: () => TreePersistState | null;
1762
+ save: (state: TreePersistState) => void;
1763
+ };
378
1764
 
379
- /**
380
- * Agent 卡片组件
381
- * 可折叠,固定高度,内部滚动
382
- */
1765
+ interface UseAgentControlOptions {
1766
+ channel: UseSessionChannelReturn | null;
1767
+ adapter: ChatWidgetAdapter;
1768
+ sessionId: number | null;
1769
+ }
1770
+ declare function useAgentControl({ channel, adapter, sessionId, }: UseAgentControlOptions): {
1771
+ pause: (agentInstanceId: number) => Promise<void>;
1772
+ resume: (agentInstanceId: number) => Promise<void>;
1773
+ stop: (agentInstanceId: number) => Promise<void>;
1774
+ };
383
1775
 
384
- declare const ChildAgentCard: React.FC<ChildAgentCardProps & {
385
- onArtifactClick?: (artifact: Artifact) => void;
386
- }>;
1776
+ type AnnotationKind = 'file-level' | 'anchored';
1777
+ interface AnnotationAnchor {
1778
+ text: string;
1779
+ startLine?: number;
1780
+ endLine?: number;
1781
+ elementId?: string;
1782
+ }
1783
+ interface AnnotationInteraction {
1784
+ id: string;
1785
+ interactionIds: string[];
1786
+ resourceId: string;
1787
+ kind: AnnotationKind;
1788
+ anchor?: AnnotationAnchor;
1789
+ createdAt: number;
1790
+ lastMessageAt: number;
1791
+ preview?: string;
1792
+ lastRoundCompleted?: boolean;
1793
+ agentInstanceId?: number;
1794
+ /** JETP-045 P3-T01:Layer 1 子空间标识;旧名 channelId。 */
1795
+ clientId?: string;
1796
+ }
1797
+ interface AnnotationMessage {
1798
+ role: 'user' | 'assistant';
1799
+ text: string;
1800
+ interactionId: string;
1801
+ timestamp?: number;
1802
+ }
387
1803
 
1804
+ interface AnnotationAllocateOpts {
1805
+ /** 'file' for file-level, 'selection' for anchored. */
1806
+ kind: 'file' | 'selection';
1807
+ /** 资源 ID(必填,作为 context_preloads.source_uri / refId)。 */
1808
+ resourceId: string;
1809
+ /** 选区 anchor(仅 selection 用,作为 context_preloads.rangeHash 的源数据)。 */
1810
+ anchor?: AnnotationAnchor;
1811
+ /** 用于人类可读标题(如文件名 + 选区文本片段)。 */
1812
+ title?: string;
1813
+ }
388
1814
  /**
389
- * 任务计划卡片组件
1815
+ * JETP-058 v2-only:批注/选区对话流的 v2 cid 分配器。
1816
+ * ChatWidget 注入闭包,内部组装 contextPreloads 后调 allocator.createClient。
1817
+ * 返回的 cid 必须是 v2 ``c_<22>``。
390
1818
  */
1819
+ type AnnotationClientIdAllocator = (opts: AnnotationAllocateOpts) => Promise<string>;
1820
+ interface UseAnnotationsOptions {
1821
+ sendMessage: (message: string, agentId?: string, inlineRefs?: any[], selectedSkills?: any[], overrideInstanceId?: number | null, clientId?: string) => Promise<void>;
1822
+ rounds: Round[];
1823
+ activeResourceId: string | null;
1824
+ /**
1825
+ * JETP-058:分配 v2 cid。每个 (resourceId + anchor) 维度懒分配一次,缓存复用;
1826
+ * 失败时直接抛错(ChatWidget 通过 toast 暴露),不再静默 fallback `file:`/`sel:` 字面量。
1827
+ */
1828
+ allocateClientId: AnnotationClientIdAllocator;
1829
+ }
1830
+ interface UseAnnotationsReturn {
1831
+ interactions: AnnotationInteraction[];
1832
+ activeInteractions: AnnotationInteraction[];
1833
+ fileLevelForResource: AnnotationInteraction | null;
1834
+ anchoredForResource: AnnotationInteraction[];
1835
+ getMessages: (interactionId: string) => AnnotationMessage[];
1836
+ startFileLevelAnnotation: (resourceId: string, message: string) => Promise<void>;
1837
+ startAnchoredAnnotation: (resourceId: string, anchor: AnnotationAnchor, message: string) => Promise<void>;
1838
+ sendFollowUp: (interactionId: string, message: string) => Promise<void>;
1839
+ isCreating: boolean;
1840
+ }
1841
+ declare function useAnnotations({ sendMessage, rounds, activeResourceId, allocateClientId, }: UseAnnotationsOptions): UseAnnotationsReturn;
391
1842
 
392
- declare const PlanCard: React.FC<PlanCardProps>;
393
-
394
- declare const TodoCard: React.FC<TodoCardProps>;
1843
+ interface ShortcutDef {
1844
+ key: string;
1845
+ meta?: boolean;
1846
+ shift?: boolean;
1847
+ handler: () => void;
1848
+ }
1849
+ interface UseShortcutsOptions {
1850
+ shortcuts: ShortcutDef[];
1851
+ enabled?: boolean;
1852
+ }
1853
+ declare function useShortcuts({ shortcuts, enabled }: UseShortcutsOptions): void;
395
1854
 
396
- /**
397
- * Schema 表单渲染器
398
- * 根据 JSON schema 动态生成表单 UI
399
- */
1855
+ declare function useNarrowMode(containerRef: React.RefObject<HTMLElement | null>, breakpoint?: number): boolean;
400
1856
 
401
- interface SchemaNode {
402
- type: string;
403
- key?: string;
404
- name?: string;
405
- props?: Record<string, unknown>;
406
- children?: SchemaNode[];
407
- options?: Array<{
408
- label: string;
409
- value: string;
410
- }>;
411
- rules?: Array<{
412
- required?: boolean;
413
- message?: string;
414
- }>;
415
- schema?: SchemaNode;
1857
+ interface ReadReceipt {
1858
+ agent: string;
1859
+ read: boolean;
416
1860
  }
417
- interface SchemaFormRendererProps {
418
- schema: SchemaNode;
419
- onSubmit?: (values: Record<string, unknown>) => void | Promise<void>;
420
- awaitCommandUuid?: string;
1861
+ interface DiscussionMessage {
1862
+ speaker: string;
1863
+ timestamp: string;
1864
+ type: 'message' | 'finding' | 'question' | 'proposal' | 'decision' | 'action_item';
1865
+ mentions: string[];
1866
+ title?: string;
1867
+ body: string;
1868
+ readReceipts?: ReadReceipt[];
1869
+ }
1870
+ interface DiscussionMeta {
1871
+ topic: string;
1872
+ created: string;
1873
+ status: 'active' | 'converging' | 'resolved' | 'archived';
1874
+ participants: string[];
1875
+ max_messages?: number;
1876
+ discussion_mode?: string;
1877
+ converge_grace?: number;
1878
+ tags?: string[];
1879
+ }
1880
+ interface DiscussionFile {
1881
+ resourceId: string;
1882
+ fileName: string;
1883
+ gitPath: string;
1884
+ meta: DiscussionMeta;
1885
+ messages: DiscussionMessage[];
1886
+ messageCount: number;
1887
+ pendingReceiptCount: number;
1888
+ }
1889
+ interface UseDiscussionsOptions {
1890
+ adapter: ChatWidgetAdapter;
1891
+ sessionId: number | null;
1892
+ currentUser?: string;
1893
+ pollIntervalMs?: number;
1894
+ wsConnected?: boolean;
1895
+ poolAgents?: PoolAgent[];
421
1896
  }
422
- declare const SchemaFormRenderer: React.FC<SchemaFormRendererProps>;
1897
+ interface UseDiscussionsReturn {
1898
+ discussions: DiscussionFile[];
1899
+ totalCount: number;
1900
+ activeCount: number;
1901
+ newDiscussionIds: Set<string>;
1902
+ loading: boolean;
1903
+ refresh: () => void;
1904
+ refreshSingleDiscussion: (gitPath: string) => Promise<void>;
1905
+ postMessage: (discussionPath: string, body: string, messageType: string, mentions: string[]) => Promise<PostDiscussionMessageResponse>;
1906
+ discussionUnread: number;
1907
+ clearDiscussionUnread: () => void;
1908
+ handleWsDiscussionUpdate: (event: Record<string, unknown>) => void;
1909
+ }
1910
+ declare function parseDiscussionMessages(raw: string): {
1911
+ meta: DiscussionMeta | null;
1912
+ messages: DiscussionMessage[];
1913
+ };
1914
+ declare function useDiscussions({ adapter, sessionId, currentUser, pollIntervalMs, wsConnected, poolAgents, }: UseDiscussionsOptions): UseDiscussionsReturn;
423
1915
 
424
- interface ToolCardBufferingProps {
425
- message: AggregatedMessage;
1916
+ interface UseFileUploadOptions {
1917
+ adapter: ChatWidgetAdapter;
1918
+ sessionId?: number | null;
1919
+ ensureSession?: () => Promise<number>;
1920
+ pollIntervalMs?: number;
1921
+ maxFileSize?: number;
1922
+ onUploadSuccess?: () => void;
1923
+ /**
1924
+ * JETP-058: ChatWidget 当前活跃的 v2 client_id(用户正在看的话池)。
1925
+ * 当 batch 第一次入队时被快照到 batch;后续 retry 复用同一 cid,
1926
+ * 让后端 _aggregate_turn 走 interaction_id 幂等键合并到同一 ARTIFACT_* 序列。
1927
+ * `null` 表示当前没有活跃话池(例如刚切到老 session 还未选择话池),
1928
+ * 此时 hook 会调 `ensureClientId()` 现场创建一个 v2 cid。
1929
+ */
1930
+ currentClientId?: string | null;
1931
+ /**
1932
+ * JETP-058: 当 `currentClientId` 缺失时调用,返回一个新的 v2 client_id。
1933
+ * 通常来自 `useClientIdAllocator.createClient(sessionId, ...)`。
1934
+ * 若未提供且 `currentClientId` 也为 null,则上传立即失败(早失败 > 半成品入库)。
1935
+ */
1936
+ ensureClientId?: () => Promise<string>;
426
1937
  }
427
- declare const ToolCardBuffering: React.FC<ToolCardBufferingProps>;
1938
+ interface UseFileUploadReturn {
1939
+ attachments: UploadedFileInfo[];
1940
+ readyFiles: FileAttachment[];
1941
+ isUploading: boolean;
1942
+ addFiles: (files: File[]) => void;
1943
+ removeFile: (resourceId: string) => void;
1944
+ clear: () => void;
1945
+ }
1946
+ /**
1947
+ * JETP-040: Shared hook managing the two-step file upload lifecycle.
1948
+ * 1. Upload files via adapter.uploadFiles() -> get resource IDs
1949
+ * 2. Poll adapter.getUploadStatus() until all files are 'ready' or 'error'
1950
+ */
1951
+ declare function useFileUpload(options: UseFileUploadOptions): UseFileUploadReturn;
1952
+
1953
+ interface ContextPreload {
1954
+ /** 上下文类型,例如 ``'file'``、``'selection'``、``'manual'``。 */
1955
+ kind: string;
1956
+ /** 资源路径(文件对话) */
1957
+ refPath?: string;
1958
+ /** 资源 ID(已落库的文件) */
1959
+ refId?: string;
1960
+ /** 选区哈希(选区对话) */
1961
+ rangeHash?: string;
1962
+ /** 任意附加元数据(被后端透传,不参与路由) */
1963
+ meta?: Record<string, unknown>;
1964
+ }
1965
+ interface CreateClientOptions {
1966
+ /** 客户端建议标题;后端会再做模型识别覆盖。 */
1967
+ title?: string;
1968
+ /** 初始上下文(不参与 client_id 派生,仅元数据)。 */
1969
+ contextPreloads?: ContextPreload[];
1970
+ }
1971
+ interface CreateClientResponse {
1972
+ id: string;
1973
+ title: string;
1974
+ context_preloads: ContextPreload[];
1975
+ is_legacy: boolean;
1976
+ archived: boolean;
1977
+ last_active_at: number;
1978
+ }
1979
+ interface UseClientIdAllocatorReturn {
1980
+ /**
1981
+ * 创建新 client;返回后端分配的 v2 client_id。
1982
+ * 双击防抖:相同 (sessionId, title, preloads) 内联 Promise 复用。
1983
+ */
1984
+ createClient: (sessionId: string | number, opts?: CreateClientOptions) => Promise<string>;
1985
+ /**
1986
+ * 兼容期:把一个 legacy client_id 导入到后端 v2 `clients` 表(best-effort,不抛错)。
1987
+ */
1988
+ ensureLegacy: (sessionId: string | number, legacyId: string) => Promise<void>;
1989
+ }
1990
+ /**
1991
+ * 公开 HttpError,便于上层 ChatWidget 用 ``err instanceof HttpError`` +
1992
+ * ``err.code === 'BUSINESS_ERROR'`` 区分网络错 vs 业务错(如 Session not allowed),
1993
+ * 给出对症的 UI 提示。
1994
+ */
1995
+ declare class HttpError extends Error {
1996
+ status: number;
1997
+ code: string | null;
1998
+ constructor(status: number, code: string | null, message: string);
1999
+ }
2000
+ /**
2001
+ * 创建一个 client allocator hook。
2002
+ *
2003
+ * @param apiBase 可选 API 基地址(如 ``'https://api.example.com'``);缺省走同源相对路径。
2004
+ * @param opts.adapter JETP-056:完整 ChatWidgetAdapter;优先级最高,走 useAuthedFetch
2005
+ * 统一处理 Authorization / 401 → refreshAuth 重试 / onAuthFailure 通知。
2006
+ * @param opts.getAuthHeaders JETP-054 hotfix(兼容期保留):仅注入 JWT/Bearer 头。
2007
+ * adapter 未提供时使用;两者都未提供时退化为只走 cookie(向后兼容旧测试)。
2008
+ */
2009
+ declare function useClientIdAllocator(apiBase?: string, opts?: {
2010
+ adapter?: ChatWidgetAdapter | null;
2011
+ getAuthHeaders?: () => Record<string, string>;
2012
+ }): UseClientIdAllocatorReturn;
2013
+
2014
+ interface ClientItem {
2015
+ id: string;
2016
+ title: string;
2017
+ contextPreloads: unknown[];
2018
+ isLegacy: boolean;
2019
+ archived: boolean;
2020
+ lastActiveAt: number;
2021
+ }
2022
+ interface UseSessionClientsReturn {
2023
+ items: ClientItem[];
2024
+ loading: boolean;
2025
+ error: Error | null;
2026
+ refresh: () => Promise<void>;
2027
+ /** 局部更新(新建后乐观插入);按 id 去重并置顶。 */
2028
+ prependLocal: (it: ClientItem) => void;
2029
+ /**
2030
+ * 已成功拉到 ``items`` 的 sessionId(成功或失败均更新;失败时 ``items`` 保留旧值,但本字段仍前推
2031
+ * → 上层可据此判断"对当前 sid 至少完成过一次拉取",避免 React useEffect 闭包时序坑:
2032
+ * 同 commit 内 hook 的 setLoading(true) 还没生效时,上层 useEffect 看到的是上一渲染的 false,
2033
+ * 仅靠 ``loading`` 守门会被绕过 → 误判该 session 是空 session 而 POST 创建新 cid。
2034
+ * 必须改用 ``loadedSessionId === currentSessionId`` 的正向断言。
2035
+ */
2036
+ loadedSessionId: string | number | null;
2037
+ }
2038
+ /**
2039
+ * 业务错误:HTTP 200 但 jetagents ResponseModel.code !== 200 时由 refresh 抛出。
2040
+ *
2041
+ * 上层(如 ChatWidget init-effect)可以 ``err instanceof BusinessError`` 区分:
2042
+ * - 网络/服务故障(普通 Error) → 可重试
2043
+ * - 业务级拒绝(如 "Session not allowed")→ 不应自动重试或自动建空 client
2044
+ */
2045
+ declare class BusinessError extends Error {
2046
+ code: number;
2047
+ constructor(code: number, message: string);
2048
+ }
2049
+ /**
2050
+ * @param sessionId 当前 session ID;为 `null` 时不发起请求。
2051
+ * @param apiBase 可选 API 基地址(如 ``'https://api.example.com'``);缺省走同源相对路径。
2052
+ * @param opts.adapter JETP-056:完整 ChatWidgetAdapter;走 useAuthedFetch 统一鉴权。
2053
+ * @param opts.getAuthHeaders JETP-054 hotfix(兼容期保留):仅注入 JWT/Bearer 头。
2054
+ */
2055
+ declare function useSessionClients(sessionId: string | number | null, apiBase?: string, opts?: {
2056
+ adapter?: ChatWidgetAdapter | null;
2057
+ getAuthHeaders?: () => Record<string, string>;
2058
+ }): UseSessionClientsReturn;
2059
+
2060
+ interface UseSessionListOptions {
2061
+ adapter: ChatWidgetAdapter | null | undefined;
2062
+ /** 每页大小;默认 20。 */
2063
+ pageSize?: number;
2064
+ /** 周期重拉间隔(毫秒);不传则不开启轮询。 */
2065
+ pollMs?: number;
2066
+ /**
2067
+ * 外部触发重拉的版本号;任何递增即触发一次刷新。
2068
+ * 用于把"会话发了第一条消息 / 接收到 SESSION_TITLE 通知"等外部事件
2069
+ * 转译为列表刷新,无需调用方手工持有 ref。
2070
+ */
2071
+ refreshKey?: number;
2072
+ /** 当前激活的会话 id;用于在删除时通知调用方"激活的那条没了"。 */
2073
+ activeSessionId?: number;
2074
+ /**
2075
+ * 删除当前激活会话后的回调;典型用法是把 ChatWidget.sessionId 置 null
2076
+ * 并触发新会话或显示空态。
2077
+ */
2078
+ onActiveSessionRemoved?: (id: number) => void;
2079
+ /** Adapter 抛 401 时的钩子;通常对接 LoginPage / tokenStore.clear。 */
2080
+ onAuthFailure?: () => void;
2081
+ /** 通用错误回调;只在最近一次拉取失败时回调一次。 */
2082
+ onError?: (err: unknown) => void;
2083
+ }
2084
+ interface UseSessionListReturn {
2085
+ sessions: SessionListItem[];
2086
+ loading: boolean;
2087
+ page: number;
2088
+ totalPages: number;
2089
+ setPage: (page: number) => void;
2090
+ refresh: () => void;
2091
+ deleteSession: (id: number) => Promise<void>;
2092
+ /** adapter 是否实现了 listSessions。 */
2093
+ supported: boolean;
2094
+ /** adapter 是否实现了 deleteSession。 */
2095
+ canDelete: boolean;
2096
+ /** 最近一次拉取/删除的错误对象;成功后清空。 */
2097
+ error: unknown;
2098
+ }
2099
+ /**
2100
+ * 通用会话列表 hook:负责拉取、分页、轮询、可见性恢复、删除与认证失败处理。
2101
+ *
2102
+ * 设计原则:
2103
+ * 1. 不耦合 UI——只暴露状态与命令,便于宿主自行渲染(侧栏 / 抽屉 / 命令面板等)。
2104
+ * 2. Adapter 能力可选——`supported / canDelete` 透传 adapter 是否实现对应方法,
2105
+ * 让 UI 决定显示空态还是隐藏按钮。
2106
+ * 3. 删除操作乐观更新——先从本地列表移除再触发后台请求;失败则强制重拉拉回真值。
2107
+ */
2108
+ declare function useSessionList(options: UseSessionListOptions): UseSessionListReturn;
2109
+
2110
+ interface NotificationConfig {
2111
+ sound: boolean;
2112
+ toast: boolean;
2113
+ toastDuration: number;
2114
+ badgeAnimation: boolean;
2115
+ }
2116
+ interface AttentionToast {
2117
+ id: string;
2118
+ text: string;
2119
+ agentName?: string;
2120
+ timestamp: number;
2121
+ }
2122
+ interface UseAttentionManagerOptions {
2123
+ fileViewerOpen: boolean;
2124
+ immersive: boolean;
2125
+ config?: Partial<NotificationConfig>;
2126
+ }
2127
+ declare function useAttentionManager({ fileViewerOpen, immersive, config: configOverrides, }: UseAttentionManagerOptions): {
2128
+ unreadCount: number;
2129
+ toasts: AttentionToast[];
2130
+ trackNewMessage: (agentName?: string, preview?: string) => void;
2131
+ clearUnread: () => void;
2132
+ dismissToast: (id: string) => void;
2133
+ pauseToast: (id: string) => void;
2134
+ resumeToast: (id: string) => void;
2135
+ notificationConfig: NotificationConfig;
2136
+ };
2137
+
2138
+ /**
2139
+ * 置顶区域组件
2140
+ * 显示当前置顶轮次的用户消息、任务计划和 Todo
2141
+ */
2142
+
2143
+ declare const PinnedArea: React__default.FC<PinnedAreaProps>;
2144
+
2145
+ /**
2146
+ * 轮次标题组件
2147
+ * 在消息流中显示非置顶轮次的用户消息和计划
2148
+ */
2149
+
2150
+ declare const RoundHeader: React__default.FC<RoundHeaderProps>;
2151
+
2152
+ interface RoundMessageListProps {
2153
+ round: Round;
2154
+ config: Required<ChatWidgetConfig>;
2155
+ onArtifactClick?: (artifact: any) => void;
2156
+ onHITLSubmit?: (response: HITLResponse) => Promise<void>;
2157
+ renderToolResult?: (displayType: string, data: ToolCallData) => React__default.ReactNode | null;
2158
+ observedInstanceStates?: Map<number, PoolAgent>;
2159
+ }
2160
+ declare const RoundMessageList: React__default.FC<RoundMessageListProps>;
2161
+
2162
+ /**
2163
+ * RoundsView ── ChatWidget 主对话流的可复用渲染组件
2164
+ *
2165
+ * 设计目标:
2166
+ * 把 ChatWidget.tsx 里 `localRounds.map(...)` + RoundHeader + RoundMessageList
2167
+ * 的内联 markup 抽成单一组件,让:
2168
+ * 1. ChatWidget 内部两处(overlay / immersive 主区)共享同一份渲染逻辑;
2169
+ * 2. 外部消费者(如 yumiai-web 工作空间浮窗)能直接 import SDK 主流的"对话气泡 +
2170
+ * 子 agent 卡 + 工具卡 + plan / todo 头"完整一套,而不再自造样式。
2171
+ *
2172
+ * 不变量:
2173
+ * - 不依赖 ChatWidget 上下文,只接受 props(rounds + config + 可选 callback)。
2174
+ * - 调用方需保证某个祖先节点带 `.ycw` 主题 class(color/spacing token 的来源)。
2175
+ * - 只渲染 round 列表本身,不负责 header / sidebar / composer / 加载状态等。
2176
+ * scroll 容器、自动滚动到底部、上拉分页等也由调用方决定(保持组件原子)。
2177
+ *
2178
+ * 与 ChatWidget 主流的等价性:
2179
+ * markup 与 ChatWidget.tsx#1457-1474 / #1700-1722 完全一致:
2180
+ * <div class="ycw-message-list-container">
2181
+ * <div class="ycw-message-list">
2182
+ * {rounds.map(round => (
2183
+ * <Fragment>
2184
+ * {index > 0 && <div class="ycw-round-separator">…</div>}
2185
+ * <div class="ycw-round-container">
2186
+ * <RoundHeader … todoMap={todoMap} />
2187
+ * <RoundMessageList … observedInstanceStates={…} />
2188
+ * </div>
2189
+ * </Fragment>
2190
+ * ))}
2191
+ * </div>
2192
+ * </div>
2193
+ */
2194
+
2195
+ interface RoundsViewProps {
2196
+ /** 待渲染的轮次列表(顺序 = 时间正序)。 */
2197
+ rounds: Round[];
2198
+ /** ChatWidget 配置;不传则用 DEFAULT_CONFIG。 */
2199
+ config?: ChatWidgetConfig;
2200
+ /** controller.todoMap,传入则 RoundHeader 会显示 todo 进度。 */
2201
+ todoMap?: Map<string, TodoData>;
2202
+ /** controller.poolObservation.instanceStates,子 Agent 卡用它判断 running/ended。 */
2203
+ observedInstanceStates?: Map<number, PoolAgent>;
2204
+ /** Artifact 点击回调(chip 等位置打开预览时使用)。 */
2205
+ onArtifactClick?: (artifact: Artifact) => void;
2206
+ /** HITL 表单提交回调。 */
2207
+ onHITLSubmit?: (response: HITLResponse) => Promise<void>;
2208
+ /** 自定义 tool 渲染。 */
2209
+ renderToolResult?: (displayType: string, data: ToolCallData) => React__default.ReactNode | null;
2210
+ /** 空态自定义;不传则不渲染任何东西(让外层贴自己的空态)。 */
2211
+ emptyFallback?: React__default.ReactNode;
2212
+ /** 容器自定义 className(追加在 .ycw-message-list-container 上)。 */
2213
+ className?: string;
2214
+ /** 测试钩子。 */
2215
+ testId?: string;
2216
+ }
2217
+ /**
2218
+ * RoundsView ──「per-round Header + RoundMessageList」批量渲染。
2219
+ *
2220
+ * 注意:本组件只负责渲染当前传入的 rounds,**不做过滤 / 排序 / 去重**。
2221
+ * 调用方(如 ChatWidget per-cid 视图、yumiai-web 浮窗)自己根据
2222
+ * cid / sid / scope 把 controller.rounds 切片后再传进来。
2223
+ */
2224
+ declare const RoundsView: React__default.FC<RoundsViewProps>;
2225
+
2226
+ declare const MessageContent: React__default.FC<MessageContentProps>;
2227
+
2228
+ /**
2229
+ * 子 Agent 卡片组件
2230
+ * 可折叠,固定高度,内部滚动
2231
+ */
2232
+
2233
+ declare const ChildAgentCard: React__default.FC<ChildAgentCardProps & {
2234
+ onArtifactClick?: (artifact: Artifact) => void;
2235
+ }>;
2236
+
2237
+ /**
2238
+ * 任务计划卡片组件
2239
+ */
2240
+
2241
+ declare const PlanCard: React__default.FC<PlanCardProps>;
2242
+
2243
+ declare const TodoCard: React__default.FC<TodoCardProps>;
2244
+
2245
+ interface SchemaNode {
2246
+ type: string;
2247
+ key?: string;
2248
+ name?: string;
2249
+ props?: Record<string, unknown>;
2250
+ children?: SchemaNode[];
2251
+ options?: Array<{
2252
+ label: string;
2253
+ value: string;
2254
+ }>;
2255
+ rules?: Array<{
2256
+ required?: boolean;
2257
+ message?: string;
2258
+ }>;
2259
+ schema?: SchemaNode;
2260
+ }
2261
+
2262
+ interface SchemaFormRendererProps {
2263
+ schema: SchemaNode;
2264
+ onSubmit?: (values: Record<string, unknown>) => void | Promise<void>;
2265
+ awaitCommandUuid?: string;
2266
+ }
2267
+ declare const SchemaFormRenderer: React__default.FC<SchemaFormRendererProps>;
2268
+
2269
+ interface ToolCardBufferingProps {
2270
+ message: AggregatedMessage;
2271
+ observedInstanceStates?: Map<number, PoolAgent>;
2272
+ }
2273
+ declare const ToolCardBuffering: React__default.FC<ToolCardBufferingProps>;
2274
+
2275
+ interface PdfImageSelection {
2276
+ page: number;
2277
+ imageIndex: number;
2278
+ imageSrc: string;
2279
+ rect: DOMRect;
2280
+ }
2281
+
2282
+ interface GerberLayerSelectPayload {
2283
+ snippet: string;
2284
+ anchorRect: {
2285
+ top: number;
2286
+ left: number;
2287
+ } | null;
2288
+ }
2289
+
2290
+ type KicanvasJpTheme = 'jp-light' | 'jp-dark' | 'jp-midnight' | 'jp-neu';
2291
+ interface KicadFile {
2292
+ name: string;
2293
+ content?: string;
2294
+ url?: string;
2295
+ }
2296
+
2297
+ /**
2298
+ * Type contract for the multi-file HTML project viewer.
2299
+ *
2300
+ * Spec: docs/proposals/CWRF-011-html-project-viewer/00_protocol/01_html_file_contract.md
2301
+ *
2302
+ * Invariants enforced by `useHtmlProject`:
2303
+ * - `HtmlFile.name` is a normalized POSIX path relative to the project root
2304
+ * (no leading `/`, no `..` segments, no backslashes).
2305
+ * - At least one of `content` / `url` is present.
2306
+ */
2307
+ /**
2308
+ * One file inside an HTML project.
2309
+ *
2310
+ * Selection rules:
2311
+ * - Text resources (HTML/CSS/JS/JSON/SVG) ship as `content` (UTF-8).
2312
+ * - Binary resources (images/fonts/audio/video) ship as `url`
2313
+ * (already a `https:` presigned URL or a `blob:` URL).
2314
+ * - When both are present, `url` wins (saves memory in Blob strategy).
2315
+ */
2316
+ interface HtmlFile {
2317
+ /** Normalized POSIX path relative to the project root (e.g. `"index.html"`, `"css/layout.css"`). */
2318
+ name: string;
2319
+ /** UTF-8 text content. Required when `url` is missing. */
2320
+ content?: string;
2321
+ /** Presigned or blob URL. Required when `content` is missing. */
2322
+ url?: string;
2323
+ /** MIME type used to construct the right Blob. Defaults to extension lookup if absent. */
2324
+ mime?: string;
2325
+ }
2326
+ /**
2327
+ * Strategy used to render the HTML project inside the iframe.
2328
+ *
2329
+ * - `'auto'`: pick `'inline'` or `'blob'` from `detectHtmlProjectFeatures`.
2330
+ * ESM `import` / dynamic `import()` / `fetch('./...')` → `'blob'`; otherwise `'inline'`.
2331
+ * - `'inline'`: force inline; `sandbox="allow-scripts"`.
2332
+ * - `'blob'`: force blob; `sandbox="allow-scripts allow-same-origin"`.
2333
+ */
2334
+ type HtmlProjectStrategy = 'auto' | 'inline' | 'blob';
2335
+ /**
2336
+ * State machine reported via `HtmlProjectOptions.onStateChange`.
2337
+ */
2338
+ type HtmlViewerState = {
2339
+ kind: 'idle';
2340
+ } | {
2341
+ kind: 'loading';
2342
+ } | {
2343
+ kind: 'rendering';
2344
+ strategy: 'inline' | 'blob';
2345
+ entryName: string;
2346
+ } | {
2347
+ kind: 'fallback-single';
2348
+ reason: string;
2349
+ } | {
2350
+ kind: 'error';
2351
+ message: string;
2352
+ };
2353
+ /**
2354
+ * Caller-controlled options that opt the viewer into multi-file project mode.
2355
+ *
2356
+ * When omitted (or when `files` is empty) the viewer falls back to the
2357
+ * legacy single-file `srcDoc` rendering path, preserving prior behaviour.
2358
+ */
2359
+ interface HtmlProjectOptions {
2360
+ /** Project file tree. The entry HTML may or may not be present here; when absent it is provided by `content`. */
2361
+ files?: HtmlFile[];
2362
+ /** Entry file name (relative to project root). Defaults to `basename(props.fileName ?? 'index.html')`. */
2363
+ entryName?: string;
2364
+ /** True while the host is still discovering project files; viewer shows loading state and skips strategy selection. */
2365
+ projectLoading?: boolean;
2366
+ /** Render strategy. Defaults to `'auto'`. */
2367
+ strategy?: HtmlProjectStrategy;
2368
+ /** Project byte budget. Above this the viewer warns and falls back to single-file. Default: 16 MiB. */
2369
+ maxBytes?: number;
2370
+ /** Per-file inline budget. Larger text files are routed through Blob URLs even in inline mode (mixed mode). Default: 256 KiB. */
2371
+ inlineFileMaxBytes?: number;
2372
+ /** Notification of state machine transitions, useful for surfacing loading / strategy badges in the host UI. */
2373
+ onStateChange?: (state: HtmlViewerState) => void;
2374
+ /**
2375
+ * Enable the runtime ESM/asset resolver shim (CWRF-012) for blob
2376
+ * strategy. When `true` (default), runtime-evaluated imports such as
2377
+ * `` import(`../games/${name}`) ``, `fetch('./data.json')`,
2378
+ * `new Worker('./w.js')`, and `new URL(rel, import.meta.url)` are
2379
+ * routed through `window.__YCW_RESOLVE__` so they resolve to the
2380
+ * matching blob URL at call time.
2381
+ *
2382
+ * Set to `false` to opt out and restore the strict CWRF-011 behaviour
2383
+ * (only literal specifiers are rewritten; runtime forms throw).
2384
+ */
2385
+ runtimeShim?: boolean;
2386
+ }
2387
+
2388
+ /**
2389
+ * `HtmlViewer` is the entry dispatcher for the multi-file HTML project viewer.
2390
+ *
2391
+ * Spec: docs/proposals/CWRF-011-html-project-viewer/05_integration/01_html_viewer_dispatch.md
2392
+ *
2393
+ * Responsibilities:
2394
+ * - Decide between three rendering paths based on `htmlOptions`:
2395
+ * 1. Single-file fallback (`htmlOptions` absent / `files` empty)
2396
+ * → behaviour identical to the legacy `HtmlViewer.tsx`.
2397
+ * 2. Loading placeholder (`htmlOptions.projectLoading === true`)
2398
+ * → display loading text, no iframe yet.
2399
+ * 3. Project mode (`files` present) → run `chooseStrategy` and
2400
+ * render `<InlineRenderer>` or `<BlobRenderer>` accordingly.
2401
+ * - Wire selection / link / xref postMessage bridge for *all* paths so
2402
+ * consumer callbacks behave identically regardless of strategy.
2403
+ * - Emit `htmlOptions.onStateChange` transitions so the host UI can
2404
+ * surface a strategy badge / fallback warning.
2405
+ * - Hard-cap project size via `htmlOptions.maxBytes` (default 16 MiB).
2406
+ *
2407
+ * Re-export shim: `viewers/HtmlViewer.tsx` exposes this default to keep
2408
+ * external `import HtmlViewer from '@yumiai/chat-widget/.../HtmlViewer'`
2409
+ * paths intact (AC-HTMLP-096).
2410
+ */
2411
+ interface HtmlViewerSelectionState {
2412
+ text: string;
2413
+ rect: DOMRect;
2414
+ }
2415
+
2416
+ interface FileViewerKicadOptions {
2417
+ /** 覆盖默认 KiCanvas 脚本 URL(也可用构建时 VITE_KICANVAS_SCRIPT_URL) */
2418
+ kicanvasScriptUrl?: string;
2419
+ onKicadCanvasSelection?: (payload: KicadCanvasSelectionPayload) => void;
2420
+ /** Sync kicanvas UI chrome + canvas background with chat-widget theme */
2421
+ kicanvasTheme?: KicanvasJpTheme;
2422
+ /** Controlled view mode for external toggle */
2423
+ view?: 'canvas' | 'source';
2424
+ onViewChange?: (v: 'canvas' | 'source') => void;
2425
+ /** Multi-file project files (CWRF-009) */
2426
+ files?: KicadFile[];
2427
+ /** True while project files are still being discovered */
2428
+ projectLoading?: boolean;
2429
+ }
2430
+ interface FileViewerGerberOptions {
2431
+ onGerberSelection?: (payload: GerberLayerSelectPayload) => void;
2432
+ }
2433
+ interface FileViewerPdfOptions {
2434
+ onImageSelect?: (sel: PdfImageSelection | null) => void;
2435
+ }
2436
+ interface FileViewerProps {
2437
+ content: ResourceContent;
2438
+ onXrefClick?: (xref: XrefRecord) => void;
2439
+ onLinkClick?: (url: string) => void;
2440
+ onHtmlSelectionChange?: (selection: HtmlViewerSelectionState | null) => void;
2441
+ className?: string;
2442
+ kicadOptions?: FileViewerKicadOptions;
2443
+ gerberOptions?: FileViewerGerberOptions;
2444
+ pdfOptions?: FileViewerPdfOptions;
2445
+ /** CWRF-011: passthrough for multi-file HTML project options. */
2446
+ htmlOptions?: HtmlProjectOptions;
2447
+ }
2448
+ declare const FileViewer: React__default.FC<FileViewerProps>;
2449
+
2450
+ interface FileViewerModalProps {
2451
+ open: boolean;
2452
+ onClose: () => void;
2453
+ initialResource: ResourceContent | null;
2454
+ initialArtifact?: Artifact | null;
2455
+ loading?: boolean;
2456
+ error?: string | null;
2457
+ adapter?: ChatWidgetAdapter;
2458
+ sessionId?: number | null;
2459
+ }
2460
+ declare const FileViewerModal: React__default.FC<FileViewerModalProps>;
2461
+
2462
+ interface FileViewerPanelProps {
2463
+ initialResource: ResourceContent | null;
2464
+ initialArtifact?: Artifact | null;
2465
+ loading?: boolean;
2466
+ error?: string | null;
2467
+ adapter?: ChatWidgetAdapter;
2468
+ sessionId?: number | null;
2469
+ onReference?: (ref: FileReference) => void;
2470
+ onSelectionAsk?: (ref: FileReference) => void;
2471
+ onBeforeCopy?: (ref: FileReference) => void;
2472
+ onClose?: () => void;
2473
+ onFullscreen?: () => void;
2474
+ kicanvasScriptUrl?: string;
2475
+ kicanvasTheme?: KicanvasJpTheme;
2476
+ }
2477
+ declare const FileViewerPanel: React__default.FC<FileViewerPanelProps>;
2478
+
2479
+ declare function getFileCategory(ext: string, mimeType: string | null): FileCategory$1;
2480
+ declare function getExtension(fileName: string | undefined | null): string;
2481
+ declare function inferLanguage(ext: string): string;
2482
+
2483
+ /**
2484
+ * Convert ResourceContent to a renderable source URL.
2485
+ * Priority: content_url > data URI (small binary) > Blob URL (large binary) > raw text.
2486
+ */
2487
+ declare function contentToSrc(res: ResourceContent): string;
2488
+ declare function formatFileSize(bytes: number): string;
2489
+
2490
+ declare function parseXrefs(content: string): XrefRecord[];
2491
+
2492
+ interface LinkCardProps {
2493
+ xref: XrefRecord;
2494
+ className?: string;
2495
+ }
2496
+ declare const LinkCard: React__default.FC<LinkCardProps>;
2497
+
2498
+ interface ResourceChipProps {
2499
+ xref: XrefRecord;
2500
+ meta?: XrefMeta;
2501
+ onClick?: () => void;
2502
+ className?: string;
2503
+ }
2504
+ declare const ResourceChip: React__default.FC<ResourceChipProps>;
2505
+
2506
+ interface HoverPreviewProps {
2507
+ fileName: string;
2508
+ mimeType?: string | null;
2509
+ previewText?: string;
2510
+ rect: DOMRect | null;
2511
+ visible: boolean;
2512
+ }
2513
+ declare const HoverPreview: React__default.FC<HoverPreviewProps>;
2514
+
2515
+ interface UseHoverPreviewOptions {
2516
+ containerRef: React__default.RefObject<HTMLElement | null>;
2517
+ onHover?: (artifactId: string) => void;
2518
+ delay?: number;
2519
+ }
2520
+ declare function useHoverPreview({ containerRef, onHover, delay, }: UseHoverPreviewOptions): {
2521
+ previewVisible: boolean;
2522
+ previewFileName: string;
2523
+ previewMimeType: string | undefined;
2524
+ previewRect: DOMRect | null;
2525
+ dismissPreview: () => void;
2526
+ };
2527
+
2528
+ interface SelectionData {
2529
+ text: string;
2530
+ startLine?: number;
2531
+ endLine?: number;
2532
+ sectionId?: string;
2533
+ jsonPath?: string;
2534
+ timestamp?: number;
2535
+ componentRef?: string;
2536
+ }
2537
+ interface SnapshotData {
2538
+ dataUrl: string;
2539
+ width: number;
2540
+ height: number;
2541
+ label?: string;
2542
+ }
2543
+ interface ViewerInteractionAdapter {
2544
+ canSelectText: boolean;
2545
+ canSelectRegion: boolean;
2546
+ canCaptureSnapshot: boolean;
2547
+ canReferenceByLine: boolean;
2548
+ canReferenceBySection: boolean;
2549
+ canReferenceByPath: boolean;
2550
+ canReferenceByTimestamp: boolean;
2551
+ canReferenceByComponent: boolean;
2552
+ minPanelWidth: number;
2553
+ preferredRatio: number;
2554
+ getSelection(): SelectionData | null;
2555
+ createSnapshot?(): SnapshotData;
2556
+ createReference(selection: SelectionData): FileReference;
2557
+ }
2558
+ declare const VIEWER_CAPABILITIES: Record<string, Partial<ViewerInteractionAdapter>>;
2559
+ declare function getViewerCapabilities(category: string): Partial<ViewerInteractionAdapter>;
2560
+
2561
+ interface SplitPanelProps {
2562
+ open: boolean;
2563
+ position?: 'left' | 'right';
2564
+ defaultRatio?: number;
2565
+ minPrimaryWidth?: number;
2566
+ minSecondaryWidth?: number;
2567
+ onClose: () => void;
2568
+ children: React__default.ReactNode;
2569
+ primaryContent: React__default.ReactNode;
2570
+ immersive?: boolean;
2571
+ onImmersiveChange?: (immersive: boolean) => void;
2572
+ unreadCount?: number;
2573
+ onChatFocus?: () => void;
2574
+ references?: FileReference[];
2575
+ onImmersiveSend?: (text: string) => void;
2576
+ onRemoveReference?: (index: number) => void;
2577
+ toasts?: AttentionToast[];
2578
+ onDismissToast?: (id: string) => void;
2579
+ onPauseToast?: (id: string) => void;
2580
+ onResumeToast?: (id: string) => void;
2581
+ tabs?: ViewerTab[];
2582
+ activeTabId?: string | null;
2583
+ onTabSwitch?: (tabId: string) => void;
2584
+ onTabClose?: (tabId: string) => void;
2585
+ onRailHome?: () => void;
2586
+ onRailWorkspace?: () => void;
2587
+ onRailAnnotation?: () => void;
2588
+ annotationCount?: number;
2589
+ activeOverlay?: 'home' | 'workspace' | 'discussion' | 'annotation' | null;
2590
+ overlayContent?: React__default.ReactNode;
2591
+ fabContent?: React__default.ReactNode;
2592
+ contextLabel?: string;
2593
+ /** v2: Channel sidebar (replaces rail when provided) */
2594
+ sidebarContent?: React__default.ReactNode;
2595
+ /** v2: Floating conversation windows layer */
2596
+ floatingLayerContent?: React__default.ReactNode;
2597
+ }
2598
+ declare const SplitPanel: React__default.FC<SplitPanelProps>;
2599
+
2600
+ interface AttentionToastListProps {
2601
+ toasts: AttentionToast[];
2602
+ onDismiss: (id: string) => void;
2603
+ onPause?: (id: string) => void;
2604
+ onResume?: (id: string) => void;
2605
+ onClick?: () => void;
2606
+ }
2607
+ declare const AttentionToastList: React__default.FC<AttentionToastListProps>;
2608
+
2609
+ interface SelectionState {
2610
+ text: string;
2611
+ rect: DOMRect;
2612
+ startLine?: number;
2613
+ endLine?: number;
2614
+ /** PDF page number (1-based) from data-page attribute */
2615
+ page?: number;
2616
+ endPage?: number;
2617
+ }
2618
+ interface SelectionBridgeOptions {
2619
+ containerRef: React.RefObject<HTMLElement | null>;
2620
+ resourceContext: {
2621
+ resourceId: string;
2622
+ sessionId: number;
2623
+ fileName: string;
2624
+ mimeType?: string | null;
2625
+ specId?: string;
2626
+ };
2627
+ enabled?: boolean;
2628
+ }
2629
+ declare function useSelectionBridge({ containerRef, resourceContext, enabled, }: SelectionBridgeOptions): {
2630
+ selection: SelectionState | null;
2631
+ buildReference: () => FileReference;
2632
+ clearSelection: () => void;
2633
+ };
2634
+
2635
+ interface FloatingToolbarProps {
2636
+ selection: SelectionState | null;
2637
+ onAsk: () => void;
2638
+ onCopy?: () => void;
2639
+ anchorRef: React__default.RefObject<HTMLElement | null>;
2640
+ }
2641
+ declare const FloatingToolbar: React__default.FC<FloatingToolbarProps>;
2642
+
2643
+ interface ContextChipProps {
2644
+ reference: FileReference;
2645
+ onRemove?: () => void;
2646
+ }
2647
+ declare const ContextChip: React__default.FC<ContextChipProps>;
2648
+
2649
+ interface FloatingInputProps {
2650
+ visible: boolean;
2651
+ references: FileReference[];
2652
+ onSend: (text: string) => void;
2653
+ onRemoveReference: (index: number) => void;
2654
+ onClose: () => void;
2655
+ placeholder?: string;
2656
+ contextLabel?: string;
2657
+ }
2658
+ declare const FloatingInput: React__default.FC<FloatingInputProps>;
2659
+
2660
+ interface SmartPasteOptions {
2661
+ enabled: boolean;
2662
+ onReference: (ref: FileReference) => void;
2663
+ }
2664
+ declare function useSmartPaste({ enabled, onReference }: SmartPasteOptions): void;
2665
+
2666
+ interface RichInputHandle {
2667
+ insertChip: (ref: FileReference) => void;
2668
+ insertSkillChip: (skill: SkillSummary) => void;
2669
+ focus: () => void;
2670
+ clear: () => void;
2671
+ getText: () => string;
2672
+ getReferences: () => FileReference[];
2673
+ getSkills: () => SkillSummary[];
2674
+ }
2675
+ interface RichInputProps {
2676
+ placeholder?: string;
2677
+ disabled?: boolean;
2678
+ onSubmit?: (text: string, references: FileReference[], skills: SkillSummary[]) => void;
2679
+ onChipRemove?: (ref: FileReference) => void;
2680
+ onSkillChipRemove?: (skill: SkillSummary) => void;
2681
+ onSlashTrigger?: (prefix: string) => void;
2682
+ onSlashDismiss?: () => void;
2683
+ removeAriaLabel?: string;
2684
+ skillRemoveAriaLabel?: string;
2685
+ className?: string;
2686
+ /** JETP-040: Callback when user selects local files for upload */
2687
+ onFilesSelected?: (files: File[]) => void;
2688
+ /** JETP-040: Currently attached/uploading files */
2689
+ attachments?: UploadedFileInfo[];
2690
+ /** JETP-040: Remove an uploaded file attachment */
2691
+ onRemoveAttachment?: (resourceId: string) => void;
2692
+ /** JETP-040: Whether file upload is supported (controls attach button visibility) */
2693
+ enableFileUpload?: boolean;
2694
+ /** JETP-040: True while files are still uploading/processing — blocks send */
2695
+ isUploading?: boolean;
2696
+ /**
2697
+ * 插在附件按钮(+)左侧的控件,例如 Agent 选择器。
2698
+ * 与 ``enableFileUpload`` 独立,保证顺序为:leading → 附件 → 输入区。
2699
+ */
2700
+ leadingControls?: React__default.ReactNode;
2701
+ /**
2702
+ * 用于 ``getText()`` 序列化 skill chip 时的包裹模板。
2703
+ * 模板中的 ``{{name}}`` 会被替换为 ``{{SKILL:<displayName>}}`` 占位符,
2704
+ * 这样前端 ``parseUserMessage`` 仍能识别 chip 位置,
2705
+ * 同时上行 message text 自带模板前后缀(用户气泡 + 后端 prompt 同步)。
2706
+ * 不传则退化为只输出裸 ``{{SKILL:<displayName>}}``。
2707
+ */
2708
+ skillTextTemplate?: string;
2709
+ }
2710
+ declare const RichInput: React__default.ForwardRefExoticComponent<RichInputProps & React__default.RefAttributes<RichInputHandle>>;
2711
+
2712
+ /**
2713
+ * Model 注册表 / 持久化 helpers
2714
+ * --------------------------------------------------
2715
+ * 仅负责 "AUTO sentinel + 持久化 + 校验 + basename 归一化",
2716
+ * 真正的列表数据由 ``useModels`` hook 从 adapter 拉。
2717
+ *
2718
+ * 持久化语义(**per-agent**,key = ``chat_widget_last_model_name:${agentId}``):
2719
+ * · 空 / null → AUTO(跟随该 agent 注册的默认模型,不传 ``modelOverride``)
2720
+ * · 非空字符串 → 该 agent 下用户上次选择的 model name;进入 composer 时若该 name
2721
+ * 仍在清单内 → 复用,否则降级回 AUTO(不弹错,避免运维下线 model
2722
+ * 反向骚扰用户)
2723
+ *
2724
+ * 为什么按 agent 分桶(v2):
2725
+ * v1 用了一个全局 key,问题是切 agent 时残留上一个 agent 的选择,
2726
+ * ModelPicker 的"value != null → 显示用户选择"分支永远比"value == null →
2727
+ * 定位 agent 默认"分支优先,结果切 agent 完全看不到新 agent 的默认 model。
2728
+ * 按 agent 存储后,切到没选过的 agent → value=null → picker 自动定位 agent 默认;
2729
+ * 切回选过的 agent → value 复原 → picker 显示用户上次的选择。
2730
+ */
2731
+ /** AUTO 的字面量 sentinel;null 也等价 AUTO,但显式常量更便于代码对比。 */
2732
+ declare const MODEL_AUTO: null;
2733
+ type ModelChoice = string | null;
2734
+ /**
2735
+ * 把 model_name 归一为 "物理模型 basename",**必须与 hip-server
2736
+ * ``internal/remote/modellake/service.go::modelBasename`` 保持等价**。
2737
+ *
2738
+ * 规则:
2739
+ * 1. 把 ``__`` 视作 ``/``(model-lake 入库时 openrouter 渠道做的反规范化);
2740
+ * 2. 取归一化后最末段(``/`` 之后的部分)。
2741
+ *
2742
+ * 示例:
2743
+ * ``anthropic/claude-opus-4-6`` → ``claude-opus-4-6`` ← agent 配里的写法
2744
+ * ``anthropic__claude-opus-4-6`` → ``claude-opus-4-6`` ← model-lake openrouter 渠道
2745
+ * ``claude-opus-4-6`` → ``claude-opus-4-6`` ← model-lake 直连 anthropic
2746
+ * ``qwen__qwen3-max`` → ``qwen3-max``
2747
+ * ``gpt-5-mini`` → ``gpt-5-mini``
2748
+ *
2749
+ * 用途:让 ModelPicker 能把 jetagents 那侧的 ``vendor/model`` 命名跟
2750
+ * model-lake 列表里的各种渠道命名对齐,否则 agent 默认模型永远命中不了清单。
2751
+ *
2752
+ * 不能替代真正发后端的 ``ModelOverride.name`` —— 那是用户在 picker 里点中的
2753
+ * variant.name 原值,basename 仅作 UI 标签 / 反查 key。
2754
+ */
2755
+ declare function modelBasename(name: string): string;
2756
+ declare function isShowModelChannels(): boolean;
2757
+ /**
2758
+ * 读取该 agent 上次选择的 model name;返回 ``null`` 表示 AUTO(无 override)。
2759
+ * · 不做"是否仍在清单内"的校验 —— 那是 ``useModels`` 拉到清单后才能判定,
2760
+ * 在这一层强校验会把"网络挂了但用户希望恢复"的可恢复链路一并切断。
2761
+ * · ``agentId`` 为空时直接返回 AUTO,避免拼出 "chat_widget_last_model_name:" 这样的脏 key。
2762
+ * · 新 key 未命中时尝试旧 key(yumiai_*),命中则视为继承(不主动迁移写入,
2763
+ * 交给下次 saveLastModelName 顺手落到新 key)。
2764
+ */
2765
+ declare function loadLastModelName(agentId: string): ModelChoice;
2766
+ /**
2767
+ * 写入该 agent 当前选择。``null`` / 空串 → 删除 key(恢复 AUTO)。
2768
+ * 静默失败(隐私模式 / 配额满都不应让 UI 崩)。
2769
+ *
2770
+ * **副作用**:第一次写入新 key 时顺便清掉旧的 v1 全局 key 与 yumiai 旧前缀 key,
2771
+ * 避免不同浏览器下用户看到不同行为。幂等,重复执行无副作用。
2772
+ */
2773
+ declare function saveLastModelName(agentId: string, name: ModelChoice): void;
2774
+
2775
+ interface ModelPickerProps {
2776
+ /** 当前选择;null = AUTO(跟随 agent 默认) */
2777
+ value: ModelChoice;
2778
+ onChange: (next: ModelChoice) => void;
2779
+ adapter: ChatWidgetAdapter;
2780
+ disabled?: boolean;
2781
+ compact?: boolean;
2782
+ /**
2783
+ * 当前 agent 在后端注册的默认模型 ``name`` —— **仅用于 picker 展示态**。
2784
+ *
2785
+ * 行为分两条线,必须分清:
2786
+ * · **展示态**:``value == null`` 且本字段命中清单时,trigger 文案 + AUTO 行 hint
2787
+ * 都自动定位到该模型,让用户一眼看到"当前 agent 实际会用哪个 model"。
2788
+ * · **发送态**:``value == null`` 时**永远**不带 ``modelOverride``,由后端按 agent 默认走。
2789
+ *
2790
+ * null / undefined / 没命中清单 → picker 退化为"显示『默认模型』占位"。
2791
+ */
2792
+ agentDefaultModelName?: string | null;
2793
+ /**
2794
+ * 是否允许触发 listModels 请求。默认 true。
2795
+ * 游客态(未登录)使用:传 false → 内部 useModels enabled=false 不发请求,
2796
+ * 同时 trigger 走 inert 分支,hover 提示"登录后可选模型"。
2797
+ */
2798
+ enabled?: boolean;
2799
+ }
2800
+ declare function ModelPicker({ value, onChange, adapter, disabled, compact, agentDefaultModelName, enabled, }: ModelPickerProps): react_jsx_runtime.JSX.Element;
2801
+
2802
+ interface UseModelsResult {
2803
+ items: ModelListItemBasenameGrouped[];
2804
+ loading: boolean;
2805
+ /** null = 没出过错 */
2806
+ error: string | null;
2807
+ /** 手动强制重拉(如登录态切换、tenant 切换) */
2808
+ refresh: () => void;
2809
+ }
2810
+ interface UseModelsOptions {
2811
+ /**
2812
+ * 是否允许触发 listModels 请求。默认 true(保持向后兼容)。
2813
+ *
2814
+ * 主要使用场景:游客态 marketing hero。访客没有 access_token,
2815
+ * 调 hip `GET /api/v1/models` 必然 401。把 enabled 显式设为 false → 完全跳过请求,
2816
+ * UI 自然走 inert 占位。
2817
+ */
2818
+ enabled?: boolean;
2819
+ }
2820
+ declare function useModels(adapter: ChatWidgetAdapter, options?: UseModelsOptions): UseModelsResult;
2821
+
2822
+ interface AgentDefaultModelInfo {
2823
+ name: string;
2824
+ displayName?: string;
2825
+ version?: string;
2826
+ }
2827
+ interface UseAgentDefaultModelResult {
2828
+ /** null = 没查到 / 还没拉 / adapter 不支持 / 拉失败(任何一种) */
2829
+ info: AgentDefaultModelInfo | null;
2830
+ loading: boolean;
2831
+ }
2832
+ interface UseAgentDefaultModelOptions {
2833
+ /**
2834
+ * 是否允许触发后端请求。默认 true(保持向后兼容)。
2835
+ *
2836
+ * 主要使用场景:游客态。访客没有 access_token,调 hip 必然 401;
2837
+ * 把 enabled 显式设为 false 完全跳过请求。
2838
+ *
2839
+ * enabled === false 时:内部强制 setInfo(null) + loading 不动,行为等价于 agentId 为空。
2840
+ */
2841
+ enabled?: boolean;
2842
+ }
2843
+ declare function useAgentDefaultModel(adapter: ChatWidgetAdapter, agentId: string | undefined, options?: UseAgentDefaultModelOptions): UseAgentDefaultModelResult;
2844
+
2845
+ /**
2846
+ * DefaultComposer — SDK 默认的对话输入组件。
2847
+ *
2848
+ * 把 RichInput + SkillSelector + useSkillOrchestration + 文件上传 + InteractionContext
2849
+ * 拼装成开箱即用的 footer composer。宿主只需要:
2850
+ *
2851
+ * <ChatWidget
2852
+ * ...
2853
+ * renderFooter={(api) => <DefaultComposer api={api} adapter={adapter} agentId={agentId} />}
2854
+ * />
2855
+ *
2856
+ * 之前 demo 端通过 deep import 内部模块自己拼装,现已收回为 SDK 公共组件,
2857
+ * 同时保留 deep import 路径不破坏既有调用方。
2858
+ */
2859
+
2860
+ interface DefaultComposerProps {
2861
+ /** ChatWidget 通过 onReady 暴露的 API;DefaultComposer 内部据此发消息、订阅文件上传状态。 */
2862
+ api: ChatWidgetAPI | null;
2863
+ /** 当前生效的 adapter,传给 useSkillOrchestration 拉取技能列表。 */
2864
+ adapter: ChatWidgetAdapter | null;
2865
+ /**
2866
+ * 当用户提交时使用的 agentId。如果业务允许动态切换,请用 controlled props 在外层维护并传入。
2867
+ * 不传则不带 agentId(让 SDK 走默认)。
2868
+ */
2869
+ agentId?: string;
2870
+ /**
2871
+ * 在输入行最前(「+」附件左侧)展示 Agent 下拉;与 ``agentId`` / ``onAgentIdChange`` 搭配使用。
2872
+ * 不传或空数组则不展示。
2873
+ */
2874
+ agentSelectOptions?: readonly {
2875
+ value: string;
2876
+ label: string;
2877
+ }[];
2878
+ /** Agent 下拉变更时回调;提供 ``agentSelectOptions`` 时应传入以便受控更新。 */
2879
+ onAgentIdChange?: (agentId: string) => void;
2880
+ /**
2881
+ * 是否处于忙碌态(running / compressing),决定 placeholder 与按钮是否可发送。
2882
+ * 通常由宿主从 ``onStatusChange`` 同步过来。
2883
+ */
2884
+ loading?: boolean;
2885
+ /** 完全禁用输入。 */
2886
+ disabled?: boolean;
2887
+ /**
2888
+ * 自定义提交 hook:返回 false 表示拦截发送(业务可在此做敏感词或字数校验等)。
2889
+ * 不传则直接调用 ``api.sendMessage``。
2890
+ */
2891
+ onBeforeSend?: (text: string, skills: SelectedSkillRef[]) => boolean | void;
2892
+ /** 发送按钮文案;默认 'Send' / 加载中 '…'。 */
2893
+ sendLabel?: React__default.ReactNode;
2894
+ /** 自定义 className,便于宿主套主题。 */
2895
+ className?: string;
2896
+ /**
2897
+ * 是否启用 ModelPicker —— 在 agent 下拉旁边渲染一个"本次发送使用的模型"切换器。
2898
+ *
2899
+ * 三态:
2900
+ * · ``true``:始终渲染(adapter 不支持 ``listModels`` 时 ModelPicker 自身会降级到 inert 占位);
2901
+ * · ``false`` / 缺省:完全不渲染(向后兼容,老调用方零侵入);
2902
+ * · ``'auto'``:``adapter.listModels`` 为函数时渲染,否则不渲染。
2903
+ *
2904
+ * 数据&发送链路:
2905
+ * · 用 ``adapter.listModels({ groupBy:'basename' })`` 拉清单;
2906
+ * · 用 ``adapter.getAgentDefaultModel(agentId)`` 做"agent 默认"展示态定位;
2907
+ * · 用户选定后调 ``api.sendMessage(... , modelOverride={ name })``,
2908
+ * 由 adapter buildStreamBody 写入 body.model_override。
2909
+ *
2910
+ * 受控/非受控:见 ``modelValue`` / ``onModelChange``。
2911
+ */
2912
+ enableModelPicker?: boolean | 'auto';
2913
+ /**
2914
+ * 受控 modelChoice。``null`` = AUTO(不传 modelOverride,跟随 agent 默认)。
2915
+ * 不传时 DefaultComposer 走非受控模式,内部用 useState 管理,并按 ``agentId``
2916
+ * 持久化到 ``localStorage`` (``chat_widget_last_model_name:<agentId>``)。
2917
+ */
2918
+ modelValue?: ModelChoice;
2919
+ onModelChange?: (next: ModelChoice) => void;
2920
+ /**
2921
+ * 是否查询 ``adapter.getAgentDefaultModel`` 用于 ModelPicker 展示态定位。
2922
+ * 默认 true;游客态宿主可置 false 完全跳过请求。
2923
+ */
2924
+ enableAgentDefaultModelLookup?: boolean;
2925
+ }
2926
+ declare const DefaultComposer: React__default.FC<DefaultComposerProps>;
2927
+
2928
+ interface SessionListPanelProps {
2929
+ adapter: ChatWidgetAdapter | null | undefined;
2930
+ /** 当前激活会话;用于高亮 + 删除时的"激活态消失"判定。 */
2931
+ activeSessionId?: number;
2932
+ /** 选中某条会话的回调。 */
2933
+ onSelectSession: (id: number) => void;
2934
+ /** 点击"新建会话"按钮的回调;不传则不显示该按钮。 */
2935
+ onNewSession?: () => void;
2936
+ /** 点击"退出"按钮的回调;不传则不显示该按钮。 */
2937
+ onLogout?: () => void;
2938
+ /** 删除当前激活会话后的回调(典型用法是 setSessionId(undefined))。 */
2939
+ onActiveSessionRemoved?: (id: number) => void;
2940
+ /** 401 钩子;缺省时由调用方在 adapter.onAuthFailure 里处理。 */
2941
+ onAuthFailure?: () => void;
2942
+ /** 外部触发刷新的版本号;任何递增即重拉。 */
2943
+ refreshKey?: number;
2944
+ /** 周期重拉间隔;不传不轮询。 */
2945
+ pollMs?: number;
2946
+ /** 每页大小;默认 20。 */
2947
+ pageSize?: number;
2948
+ /** 自定义标题;默认走 i18n。 */
2949
+ title?: React__default.ReactNode;
2950
+ /** 删除前确认;返回 false 中止。默认走 window.confirm。 */
2951
+ confirmDelete?: (item: SessionListItem) => boolean | Promise<boolean>;
2952
+ /** 自定义条目渲染(保留 onClick / 删除按钮包裹由组件负责)。 */
2953
+ renderItemTitle?: (item: SessionListItem) => React__default.ReactNode;
2954
+ className?: string;
2955
+ }
2956
+ /**
2957
+ * 通用会话侧栏。可直接挂载,也可作为参考实现:复杂场景下推荐
2958
+ * 调用方自己用 `useSessionList` + 自有 UI 拼装。
2959
+ */
2960
+ declare const SessionListPanel: React__default.FC<SessionListPanelProps>;
428
2961
 
429
2962
  interface DefaultJetAgentsAdapterOptions {
430
2963
  baseUrl: string;
431
2964
  getToken: () => string | null;
432
2965
  refreshToken?: () => Promise<string | null>;
433
2966
  getOrgId?: () => string | null;
2967
+ getUserId?: () => string | null;
2968
+ hipBaseUrl?: string;
434
2969
  onAuthFailure?: () => void;
2970
+ /**
2971
+ * 可选:每次请求前由上层动态返回额外 header。
2972
+ *
2973
+ * 设计目的:让宿主应用(例如 yumiai-web)把 i18n locale、tenant、feature flag 等
2974
+ * 横切关注点统一注入到 adapter 的所有 HTTP 出口(fetchJSON / fetchHipJSON /
2975
+ * fetchMultipart / SSE startStream),而无需修改 adapter 内部任何端点。
2976
+ *
2977
+ * 调用时机:每次构造请求 headers 时同步调用一次(在 `getAuthHeaders()` 中合并),
2978
+ * 因此实现侧可以读取最新的可变状态(如 currentLocale)而不需要重建 adapter。
2979
+ *
2980
+ * 优先级:同名 key 时,本钩子返回值会被 `getAuthHeaders()` 内已设置的鉴权字段覆盖
2981
+ * (Authorization / X-User-ID / X-User-Roles / X-Org-Id),但会高于 caller 在
2982
+ * fetchJSON(init.headers) 里传入的同名字段(caller 仍可通过显式传 header 覆盖)。
2983
+ *
2984
+ * 典型用法:
2985
+ * ```ts
2986
+ * new DefaultJetAgentsAdapter({
2987
+ * ...,
2988
+ * getExtraHeaders: () => ({
2989
+ * 'Accept-Language': getCurrentLocale(),
2990
+ * 'X-Locale': getCurrentLocale(),
2991
+ * }),
2992
+ * })
2993
+ * ```
2994
+ */
2995
+ getExtraHeaders?: () => Record<string, string> | undefined;
2996
+ /**
2997
+ * 可选:每次构造 send_message body 时由上层动态返回客户端环境上下文。
2998
+ *
2999
+ * 设计目的:让宿主应用注入用户的 IANA 时区 / UTC offset / locale 等
3000
+ * **随消息一起上行**的元数据,与 `body.catalog_fragment` 走完全相同的
3001
+ * 路径(`buildStreamBody` 内部直接组装、不经过 params)。后端就能在
3002
+ * 生成提示词、日志、个性化回复时使用这些信息(例如"按你的当地时间提醒"
3003
+ * 或"这条消息发自 Asia/Shanghai")。
3004
+ *
3005
+ * 与 `getExtraHeaders` 的分工:
3006
+ * · header(getExtraHeaders):横切给所有 HTTP 端点,后端中间件统一处理。
3007
+ * · body.client_context(本钩子):仅 send_message 上行,与对话内容
3008
+ * 绑定持久化,便于后端 / Prompt 引擎在生成时引用。
3009
+ *
3010
+ * 调用时机:每次 `buildStreamBody()` 调用时同步执行一次,因此实现可以
3011
+ * 实时读取当前 locale / 系统时区,无需重建 adapter。
3012
+ *
3013
+ * 默认行为:钩子未提供 / 返回 `undefined` 字段时,由 SDK 内部用
3014
+ * `Intl.DateTimeFormat().resolvedOptions().timeZone` 兜底自动检测,
3015
+ * 保证 body.client_context 永远有合法字段(与 catalog_fragment 一样自治)。
3016
+ *
3017
+ * 典型用法:
3018
+ * ```ts
3019
+ * new DefaultJetAgentsAdapter({
3020
+ * ...,
3021
+ * getClientContext: () => snapshotClientContext(getCurrentLocale()),
3022
+ * })
3023
+ * ```
3024
+ *
3025
+ * 字段含义:
3026
+ * · timezone IANA tz name,如 'Asia/Shanghai'。
3027
+ * · timezoneOffsetMinutes 当前 UTC 偏移分钟(正东负西,与 ECMA
3028
+ * getTimezoneOffset 符号相反)。
3029
+ * · locale 当前 BCP47 locale,如 'zh-CN'。
3030
+ */
3031
+ getClientContext?: () => Partial<{
3032
+ timezone: string;
3033
+ timezoneOffsetMinutes: number;
3034
+ locale: string;
3035
+ }> | undefined;
435
3036
  }
436
3037
  declare class DefaultJetAgentsAdapter implements ChatWidgetAdapter {
437
3038
  private readonly baseUrl;
@@ -443,14 +3044,196 @@ declare class DefaultJetAgentsAdapter implements ChatWidgetAdapter {
443
3044
  instanceId: number;
444
3045
  }>;
445
3046
  getSessionDetail(sessionId: number): Promise<SessionDetail>;
446
- getSessionHistory(sessionId: number): Promise<NotificationTurn[]>;
3047
+ /**
3048
+ * 后端 ``GET /api/session/page`` 返回 ``{ items: DbSession[], total }``,
3049
+ * DbSession.to_dict() 字段名是 snake_case + ``session_title`` 而非 ``title``。
3050
+ * adapter 在这一层做规范化,向上层暴露统一的 ``SessionListItem``。
3051
+ */
3052
+ listSessions(params?: ListSessionsParams): Promise<ListSessionsResponse>;
3053
+ deleteSession(sessionId: number): Promise<void>;
3054
+ getSessionHistory(sessionId: number, options: GetSessionHistoryOptions): Promise<NotificationTurn[] | PaginatedHistoryResponse>;
3055
+ /**
3056
+ * JETP-058 v2-only — clientIds 参数规范化 + 严格校验。
3057
+ *
3058
+ * 与 JETP-057 差异:
3059
+ * - 旧实现允许 ``[A-Za-z0-9._:\\-/]+`` 字符集(兼容 ``main`` / ``file:*`` / ``sel:*``);
3060
+ * - 新实现仅接受 ``^c_[A-Za-z0-9]{22}$``,其它一律 ``RangeError`` fail-fast。
3061
+ *
3062
+ * 任何不合法都立刻抛错(fail-fast,不发请求);
3063
+ * 对调用方意味着:未派生出 v2 cid 之前不要调 getSessionHistory(与 controller skip 配合)。
3064
+ */
3065
+ private _normalizeClientIdsOrThrow;
447
3066
  getResourceContent(sessionId: number, resourceId: string): Promise<ResourceContent>;
3067
+ getResourceUrl(sessionId: number, resourceId: string): Promise<string>;
3068
+ getPreviewUrl(sessionId: number, resourceId: string, format?: 'html' | 'pdf'): Promise<string>;
448
3069
  submitHITLResponse(response: HITLResponse): Promise<void>;
3070
+ /**
3071
+ * JETP-083 WS3.7.6 — fetch pending Collaborative HIL entities for the
3072
+ * connecting principal (scoped to one session).
3073
+ *
3074
+ * Wire shape (jetagents `main.py:get_genui_pending`):
3075
+ * ```
3076
+ * GET /api/genui/pending?session_id=<int>
3077
+ * → { code: 200, data: { session_id, pending: [...PendingHIL...] } }
3078
+ * ```
3079
+ *
3080
+ * Field-name normalisation (snake_case → camelCase) is done here so
3081
+ * the SDK type surface stays idiomatic TS and `useGenUIPending` can
3082
+ * consume `PendingHIL[]` directly.
3083
+ *
3084
+ * Failure modes:
3085
+ * - HTTP error → throws (caller decides to toast / retry / silent drop).
3086
+ * - Empty list → returns `[]` (legitimate state — no pending HILs).
3087
+ * - Malformed payload → returns `[]` and logs warn (defensive; never
3088
+ * surfaces "endpoint exists but data unusable" as a hard error to
3089
+ * the widget reconnect path).
3090
+ */
3091
+ getPendingHILs(sessionId: number): Promise<PendingHIL[]>;
3092
+ /**
3093
+ * 触发协作式停止:`POST /api/session/stop`,由 jetagents handler 把
3094
+ * `agent:signal:stop:{session_id}:{interaction_id}=stop` 写入 Redis;
3095
+ * 运行时检查点(agent_state_machine_v2 / simple_agent_pool /
3096
+ * agent_executor / base_pusher)轮询同一 key 后 yield `StoppedAgentCommand`
3097
+ * 优雅退出,并由 pusher 推送 `CANCELED` 通知。详见 `ChatWidgetAdapter.stopAgent`。
3098
+ *
3099
+ * 实现细节:
3100
+ * - 复用 `fetchJSON`,自带 15s 超时、Bearer JWT 注入、401 单次 refresh 重试、
3101
+ * `ChatWidgetNetworkError` 抛出;与 widget 内其它 HTTP 出口策略对齐。
3102
+ * - body 必须包含 `command: 'stop'`:后端 `AgentControlRequest` 是
3103
+ * `Literal["pause","resume","stop"]`,缺字段会被 Pydantic 拒为 422,即便
3104
+ * handler 实际只读 `session_id`。
3105
+ * - `agent_instance_id` 上行只是为了后端日志/未来兼容;当前 handler 不读。
3106
+ * - 业务码(如 `error("no event in session")`)走 `code != 200` 分支,
3107
+ * 显式抛 `ChatWidgetNetworkError`,避免上层吞错;幂等场景(已停过)后端
3108
+ * 返回 `code: 200, data: {}`,本方法 resolve 不抛。
3109
+ */
3110
+ stopAgent(params: {
3111
+ sessionId: number;
3112
+ agentInstanceId?: number;
3113
+ }): Promise<void>;
449
3114
  getStreamUrl(): string;
3115
+ getWsUrl(sessionId: number): string;
450
3116
  getAuthHeaders(): Record<string, string>;
3117
+ listSkills(params?: SkillListParams): Promise<SkillListResponse>;
3118
+ buildStreamBody(params: {
3119
+ message: string;
3120
+ agentId: string;
3121
+ sessionId: number | null;
3122
+ interactionId: string;
3123
+ agentInstanceId?: number;
3124
+ callerInstanceId?: number;
3125
+ selectedSkills?: SelectedSkillRef[];
3126
+ activeSpecIds?: string[];
3127
+ /** JETP-045 Layer 1:客户端连接子空间标识(前端 owned)。 */
3128
+ clientId?: string;
3129
+ /**
3130
+ * JETP-045 Phase 6 — Layer 1.5 物理连接 ID(``useConnectionId`` 派生)。
3131
+ * 用于后端 echo 抑制;缺省(旧调用方)时不写入 body,后端按"未知连接"处理。
3132
+ */
3133
+ connectionId?: string;
3134
+ fileAttachments?: FileAttachment[];
3135
+ /**
3136
+ * 前端"本次调用使用的模型"覆盖项;缺省 / null 时不写入 body,
3137
+ * 后端按 agent 注册的默认 ``ModelMeta`` 走(与历史完全一致)。
3138
+ */
3139
+ modelOverride?: ModelOverride | null;
3140
+ }): object;
3141
+ /**
3142
+ * Convert raw JetAgents Notification SSE to ChatWidget flat SSEMessage format.
3143
+ * Mirrors JetForge's AIStreamEvent.to_chat_widget_messages() logic.
3144
+ */
3145
+ transformSSEMessage(raw: Record<string, unknown>): SSEMessage[] | null;
3146
+ shareArtifact(params: {
3147
+ artifactId: string;
3148
+ sessionId: number;
3149
+ title?: string;
3150
+ artifactType?: 'file' | 'jr-page';
3151
+ shareType?: 1 | 2;
3152
+ }): Promise<{
3153
+ shareCode: string;
3154
+ shareUrl: string;
3155
+ password?: string;
3156
+ } | null>;
3157
+ listDirectoryFiles(sessionId: number, dirPrefix: string, options?: ListDirectoryFilesOptions): Promise<DirectoryFileEntry[]>;
3158
+ getPoolStatus(sessionId: number): Promise<PoolStatusResponse>;
3159
+ /**
3160
+ * 拉取可选模型清单。**走 hip-server,不走 fusion**(见 ChatWidgetAdapter.listModels 注释)。
3161
+ *
3162
+ * - hipBaseUrl 缺省时直接抛错(拒绝 fall back 到 ``baseUrl``,避免误把 jetagents
3163
+ * 当成模型注册表);这种配置下上层 picker 应表现为"未启用模型选择"。
3164
+ * - 后端约定:响应体 ``{ success, data: { items, total } }``;这里把内层 data 拆出来
3165
+ * 给上层,与其他 adapter 方法风格一致。
3166
+ * - hip 端字段是 snake_case(``default_channel``);在这一层做一次转 camelCase,
3167
+ * 上游业务永远只见 camelCase。
3168
+ */
3169
+ listModels<TGroup extends 'basename' | 'name' | 'none' = 'basename'>(params?: ListModelsParams & {
3170
+ groupBy?: TGroup;
3171
+ }): Promise<ListModelsResponse<TGroup extends 'basename' ? ModelListItemBasenameGrouped : TGroup extends 'name' ? ModelListItemGrouped : ModelListItemRaw>>;
3172
+ /**
3173
+ * 拉取 agent 在后端注册的默认模型,仅供 picker 展示态使用。
3174
+ *
3175
+ * 三态全部吞成 null(详见 ChatWidgetAdapter.getAgentDefaultModel 注释):
3176
+ * - 业务找不到:hip 返回 ``{ success: false, error.code: 'NOT_FOUND' }``(HTTP 200);
3177
+ * - 上游异常 / 网络 / 超时 / 5xx:fetchHipJSON 抛 ChatWidgetNetworkError,这里 catch 后返回 null;
3178
+ * - 200 但 ``data.name`` 缺失:当作脏数据,返回 null。
3179
+ *
3180
+ * 这种策略避免"agent 默认模型查不到"阻塞用户输入;实在需要追错的话看 ``console.warn``。
3181
+ */
3182
+ getAgentDefaultModel(agentId: string): Promise<{
3183
+ name: string;
3184
+ displayName?: string;
3185
+ version?: string;
3186
+ } | null>;
3187
+ postDiscussionMessage(sessionId: number, req: PostDiscussionMessageRequest): Promise<PostDiscussionMessageResponse>;
3188
+ createDiscussion(sessionId: number, req: CreateDiscussionRequest): Promise<CreateDiscussionResponse>;
3189
+ getPoolAgents(sessionId: number): Promise<PoolAgent[]>;
3190
+ downloadWorkspaceZip(sessionId: number): Promise<void>;
3191
+ private _saveBlobResponse;
3192
+ uploadFiles(files: File[], sessionId: number | undefined, clientId: string): Promise<FileUploadResult>;
3193
+ getUploadStatus(resourceIds: string[]): Promise<FileUploadStatusResult>;
3194
+ uploadWorkspaceFiles(sessionId: number, files: File[], options: {
3195
+ targetDirectory?: string;
3196
+ clientId: string;
3197
+ }): Promise<WorkspaceUploadResult>;
3198
+ createWorkspaceDirectory(sessionId: number, dirName: string, parentPath?: string): Promise<{
3199
+ code: number;
3200
+ message: string;
3201
+ }>;
3202
+ private _wsPost;
3203
+ renameWorkspaceItem(sessionId: number, oldPath: string, newName: string): Promise<{
3204
+ code: number;
3205
+ message: string;
3206
+ }>;
3207
+ deleteWorkspaceItems(sessionId: number, paths: string[]): Promise<{
3208
+ code: number;
3209
+ message: string;
3210
+ }>;
3211
+ moveWorkspaceItems(sessionId: number, sourcePaths: string[], targetDir: string): Promise<{
3212
+ code: number;
3213
+ message: string;
3214
+ }>;
3215
+ copyWorkspaceItems(sessionId: number, sourcePaths: string[], targetDir: string): Promise<{
3216
+ code: number;
3217
+ message: string;
3218
+ }>;
451
3219
  onAuthFailure(): void;
452
3220
  refreshAuth(): Promise<boolean>;
3221
+ private fetchHipJSON;
3222
+ private fetchMultipart;
3223
+ private static readonly FETCH_TIMEOUT_MS;
453
3224
  private fetchJSON;
3225
+ /**
3226
+ * JETP-056 P2 — adapter 内部所有 HTTP 出口统一走这一条路径:
3227
+ * - 自动注入 `getAuthHeaders()`(caller header 优先级更高,可覆盖);
3228
+ * - 401 → `refreshAuth()` 单次重试;重试仍非 401 直接返回(让 caller 处理 200/4xx/5xx);
3229
+ * - refresh 失败或重试仍 401 → `onAuthFailure()` + 抛 `ChatWidgetAuthError`;
3230
+ * - 不消费 body,返回 raw `Response`,让 caller 决定 `.json()` / `.blob()` / 错误处理。
3231
+ *
3232
+ * 这是 adapter 侧"统一鉴权 + 401 兜底"的唯一出口,等价于 React 侧的 `useAuthedFetch`。
3233
+ * 散落 fetch(HITL upload / artifact-share / mkdir / wsPost / resource raw / download zip)
3234
+ * 都已收敛到此方法,避免漏注 401 处理与 token 漂移。
3235
+ */
3236
+ private authedFetch;
454
3237
  }
455
3238
 
456
3239
  declare class ChatWidgetAuthError extends Error {
@@ -462,5 +3245,420 @@ declare class ChatWidgetNetworkError extends Error {
462
3245
  readonly name: "ChatWidgetNetworkError";
463
3246
  constructor(message: string, statusCode: number);
464
3247
  }
3248
+ /**
3249
+ * JETP-054 — `client_id` 协议守门错误。
3250
+ *
3251
+ * 抛出场景(前端硬错误,不再 silent fallback 'main'):
3252
+ * 1. session 已就绪但 v2 client_id 分配在 N 次重试后仍失败;
3253
+ * 2. 调用方(adapter / controller)在到达发送层时仍未拿到合法 cid;
3254
+ * 3. 后端在 strict 模式下返回 `CLIENT_ID_REQUIRED` 4xx(统一映射到本错误)。
3255
+ *
3256
+ * 设计意图:
3257
+ * - 把"路径异常"显式化,便于上层 toast / retry / 上报;
3258
+ * - 与后端 `ClientIdRequiredError` 形成端到端契约对齐;
3259
+ * - 与 `ChatWidgetAuthError` / `ChatWidgetNetworkError` 同级别,可被业务统一捕获。
3260
+ */
3261
+ declare class InvalidClientIdError extends Error {
3262
+ readonly reason: 'missing' | 'session_not_ready' | 'allocation_failed' | 'legacy_main' | 'legacy_format' | 'session_forbidden';
3263
+ readonly sessionId?: string | number | null | undefined;
3264
+ readonly name: "InvalidClientIdError";
3265
+ constructor(message: string, reason: 'missing' | 'session_not_ready' | 'allocation_failed' | 'legacy_main' | 'legacy_format' | 'session_forbidden', sessionId?: string | number | null | undefined);
3266
+ }
3267
+
3268
+ declare const I18nContext: React$1.Context<ChatWidgetMessages>;
3269
+ declare function useChatWidgetI18n(): {
3270
+ messages: ChatWidgetMessages;
3271
+ t: (key: keyof ChatWidgetMessages, params?: Record<string, string | number>) => string;
3272
+ locale: ChatWidgetLocale;
3273
+ };
3274
+
3275
+ declare function organizeMessagesByLevel(messages: Round['messages']): {
3276
+ rootMessages: Round['messages'];
3277
+ childrenMap: Map<string, Round['messages']>;
3278
+ };
3279
+
3280
+ declare function getStatusDisplay(sessionBusy: boolean, connectionStatus: string, executionStatus: ExecutionStatus, i18n: ChatWidgetMessages): {
3281
+ icon: string;
3282
+ iconName: IconName;
3283
+ text: string;
3284
+ };
3285
+
3286
+ declare function fileTypeIcon(mimeOrExt: string): IconName;
3287
+
3288
+ type FileCategory = 'sch' | 'pcb' | 'pro' | 'gerber' | 'pdf' | 'excel' | 'code' | 'image' | 'text' | 'json' | 'other';
3289
+ declare function fileTypeCategory(mimeOrExt: string): FileCategory;
3290
+ declare function fileTypeColor(mimeOrExt: string): string;
3291
+
3292
+ interface WorkspacePanelProps {
3293
+ open: boolean;
3294
+ onClose: () => void;
3295
+ tree: WorkspaceTreeNode[];
3296
+ recentChanges?: WorkspaceFile[];
3297
+ onSelectFile: (file: WorkspaceFile) => void;
3298
+ highlightedIds?: Set<string>;
3299
+ fileCount?: number;
3300
+ initialExpandedPaths?: string[];
3301
+ onExpandStateChange?: (paths: string[]) => void;
3302
+ onDownloadAll?: () => Promise<void>;
3303
+ onUploadFiles?: (files: File[], targetDirectory?: string) => Promise<void>;
3304
+ onCreateFolder?: (folderName: string, parentPath?: string) => Promise<void>;
3305
+ onRename?: (oldPath: string, newName: string) => Promise<void>;
3306
+ onDelete?: (paths: string[]) => Promise<void>;
3307
+ onMove?: (sourcePaths: string[], targetDir: string) => Promise<void>;
3308
+ onCopy?: (sourcePaths: string[], targetDir: string) => Promise<void>;
3309
+ }
3310
+ declare const WorkspacePanel: React__default.FC<WorkspacePanelProps>;
3311
+
3312
+ interface DiscussionPanelProps {
3313
+ open: boolean;
3314
+ onClose: () => void;
3315
+ discussions: DiscussionFile[];
3316
+ newDiscussionIds?: Set<string>;
3317
+ currentUserAlias?: string;
3318
+ sessionId?: number;
3319
+ adapter?: ChatWidgetAdapter;
3320
+ poolAgents?: PoolAgent[];
3321
+ onRefresh?: () => void;
3322
+ onPostMessage?: (discussionPath: string, body: string, messageType: string, mentions: string[]) => Promise<PostDiscussionMessageResponse>;
3323
+ }
3324
+ declare const DiscussionPanel: React__default.FC<DiscussionPanelProps>;
3325
+
3326
+ interface DiscussionViewerProps {
3327
+ discussion: DiscussionFile;
3328
+ currentUserAlias?: string;
3329
+ sessionId?: number;
3330
+ adapter?: ChatWidgetAdapter;
3331
+ poolAgents?: PoolAgent[];
3332
+ onClose: () => void;
3333
+ onRefresh?: () => void;
3334
+ onPostMessage?: (discussionPath: string, body: string, messageType: string, mentions: string[]) => Promise<PostDiscussionMessageResponse>;
3335
+ }
3336
+ declare const DiscussionViewer: React__default.FC<DiscussionViewerProps>;
3337
+
3338
+ interface DiscussionComposerProps {
3339
+ discussion: DiscussionFile;
3340
+ sessionId: number;
3341
+ currentUser: string;
3342
+ adapter: ChatWidgetAdapter;
3343
+ onMessageSent: () => void;
3344
+ onPostMessage?: (discussionPath: string, body: string, messageType: string, mentions: string[]) => Promise<PostDiscussionMessageResponse>;
3345
+ disabled?: boolean;
3346
+ allowedTypes?: string[];
3347
+ poolAgents?: PoolAgent[];
3348
+ }
3349
+ declare const DiscussionComposer: React__default.FC<DiscussionComposerProps>;
3350
+
3351
+ interface MentionAutocompleteProps {
3352
+ trigger: string;
3353
+ participants: string[];
3354
+ poolAgents: PoolAgent[];
3355
+ onSelect: (alias: string, isNewParticipant: boolean) => void;
3356
+ onClose: () => void;
3357
+ }
3358
+ declare const MentionAutocomplete: React__default.FC<MentionAutocompleteProps>;
3359
+
3360
+ interface AnnotationFABProps {
3361
+ resourceId: string | null;
3362
+ fileName: string;
3363
+ onSend: (message: string) => void;
3364
+ visible: boolean;
3365
+ expanded?: boolean;
3366
+ onToggle?: (expanded: boolean) => void;
3367
+ disabled?: boolean;
3368
+ }
3369
+ declare const AnnotationFAB: React__default.FC<AnnotationFABProps>;
3370
+
3371
+ interface AnnotationPanelMessage {
3372
+ role: 'user' | 'assistant';
3373
+ text: string;
3374
+ timestamp?: number;
3375
+ }
3376
+ interface AnnotationPanelProps {
3377
+ open: boolean;
3378
+ onClose: () => void;
3379
+ fileLevelConversation: {
3380
+ id: string;
3381
+ messages: AnnotationPanelMessage[];
3382
+ preview?: string;
3383
+ } | null;
3384
+ anchoredAnnotations: Array<{
3385
+ id: string;
3386
+ anchor?: {
3387
+ text: string;
3388
+ startLine?: number;
3389
+ endLine?: number;
3390
+ };
3391
+ messages: AnnotationPanelMessage[];
3392
+ preview?: string;
3393
+ }>;
3394
+ activeAnnotationId: string | null;
3395
+ onSetActive: (id: string | null) => void;
3396
+ onSendFollowUp: (annotationId: string, text: string) => void;
3397
+ isCreating?: boolean;
3398
+ }
3399
+ declare const AnnotationPanel: React__default.FC<AnnotationPanelProps>;
3400
+
3401
+ interface AnnotationAnchorRect {
3402
+ top: number;
3403
+ left: number;
3404
+ width: number;
3405
+ height: number;
3406
+ }
3407
+ interface InlineAnnotationInputProps {
3408
+ anchorRect: AnnotationAnchorRect;
3409
+ anchorText?: string;
3410
+ onSend: (message: string) => void;
3411
+ onClose: () => void;
3412
+ onFallback?: () => void;
3413
+ placeholder?: string;
3414
+ containerRect?: DOMRect;
3415
+ }
3416
+ declare const InlineAnnotationInput: React__default.FC<InlineAnnotationInputProps>;
3417
+
3418
+ interface AgentGroupPanelProps {
3419
+ open: boolean;
3420
+ onClose: () => void;
3421
+ agents: Map<number, AgentInstanceState>;
3422
+ onPause: (agentInstanceId: number) => void;
3423
+ onResume: (agentInstanceId: number) => void;
3424
+ onStop: (agentInstanceId: number) => void;
3425
+ }
3426
+ declare const AgentGroupPanel: React__default.FC<AgentGroupPanelProps>;
3427
+
3428
+ interface RailAction {
3429
+ id: string;
3430
+ icon: React__default.ReactNode;
3431
+ label: string;
3432
+ badge?: number;
3433
+ onClick: () => void;
3434
+ active?: boolean;
3435
+ }
3436
+ interface ImmersiveShellProps {
3437
+ children: React__default.ReactNode;
3438
+ tabBar?: React__default.ReactNode;
3439
+ /** v2: Channel sidebar replaces rail + overlays */
3440
+ sidebar?: React__default.ReactNode;
3441
+ /** v2: Floating conversation windows layer */
3442
+ floatingLayer?: React__default.ReactNode;
3443
+ /** v1 (legacy): overlay content — only rendered when sidebar is not provided */
3444
+ overlay?: React__default.ReactNode;
3445
+ fab?: React__default.ReactNode;
3446
+ unreadCount?: number;
3447
+ annotationCount?: number;
3448
+ onRailHome?: () => void;
3449
+ onRailWorkspace?: () => void;
3450
+ onRailAnnotation?: () => void;
3451
+ onExitImmersive?: () => void;
3452
+ activeOverlay?: 'home' | 'workspace' | 'discussion' | 'annotation' | null;
3453
+ extraRailActions?: RailAction[];
3454
+ }
3455
+ declare const ImmersiveShell: React__default.FC<ImmersiveShellProps>;
3456
+
3457
+ interface TabBarProps {
3458
+ tabs: ViewerTab[];
3459
+ activeTabId: string | null;
3460
+ onTabClick: (tabId: string) => void;
3461
+ onTabClose: (tabId: string) => void;
3462
+ maxVisible?: number;
3463
+ }
3464
+ declare const TabBar: React__default.FC<TabBarProps>;
3465
+
3466
+ interface ChatOverlayProps {
3467
+ children: React__default.ReactNode;
3468
+ open: boolean;
3469
+ onClose: () => void;
3470
+ unreadCount?: number;
3471
+ }
3472
+ declare const ChatOverlay: React__default.FC<ChatOverlayProps>;
3473
+
3474
+ /**
3475
+ * SkillSelector — pure rendering component (JETP-032).
3476
+ *
3477
+ * Receives all data and callbacks as props; contains zero business logic.
3478
+ * All state management lives in useSkillOrchestration.
3479
+ */
3480
+
3481
+ interface SkillSelectorProps {
3482
+ visible: boolean;
3483
+ skills: SkillSummary[];
3484
+ loading: boolean;
3485
+ error: string | null;
3486
+ selectedIndex: number;
3487
+ hasMore: boolean;
3488
+ emptyText: string;
3489
+ loadingText: string;
3490
+ errorText: string;
3491
+ loadMoreText: string;
3492
+ selectorLabel: string;
3493
+ onSelect: (skill: SkillSummary) => void;
3494
+ onClose: () => void;
3495
+ onLoadMore: () => void;
3496
+ renderSkillIcon?: (skill: SkillSummary) => React__default.ReactNode;
3497
+ }
3498
+ declare const SkillSelector: React__default.FC<SkillSelectorProps>;
3499
+
3500
+ /**
3501
+ * useSkillData — data-fetching layer for skill selector (JETP-032).
3502
+ *
3503
+ * Manages: API calls to adapter.listSkills, debounced search,
3504
+ * pagination (append + dedupe), loading/error states.
3505
+ * Does NOT manage: UI visibility, keyboard navigation, or DOM.
3506
+ */
3507
+
3508
+ interface UseSkillDataOptions {
3509
+ adapter: ChatWidgetAdapter | null;
3510
+ debounceMs?: number;
3511
+ }
3512
+ interface UseSkillDataReturn {
3513
+ skills: SkillSummary[];
3514
+ loading: boolean;
3515
+ error: string | null;
3516
+ total: number;
3517
+ hasMore: boolean;
3518
+ search: (text: string) => void;
3519
+ loadMore: () => void;
3520
+ reset: () => void;
3521
+ }
3522
+ declare function useSkillData(options: UseSkillDataOptions): UseSkillDataReturn;
3523
+
3524
+ /**
3525
+ * useSkillSelectorState — UI-state layer for skill selector (JETP-032).
3526
+ *
3527
+ * Manages: popup visibility, selected item index, keyboard navigation.
3528
+ * Does NOT manage: data fetching, adapter calls, or DOM insertion.
3529
+ */
3530
+ interface UseSkillSelectorStateReturn {
3531
+ visible: boolean;
3532
+ selectedIndex: number;
3533
+ open: (itemCount: number) => void;
3534
+ close: () => void;
3535
+ moveDown: (itemCount: number) => void;
3536
+ moveUp: (itemCount: number) => void;
3537
+ setSelectedIndex: (idx: number) => void;
3538
+ }
3539
+ declare function useSkillSelectorState(): UseSkillSelectorStateReturn;
3540
+
3541
+ /**
3542
+ * useSkillOrchestration — orchestration layer for skill selector (JETP-032).
3543
+ *
3544
+ * Composes useSkillData + useSkillSelectorState, connects to RichInput
3545
+ * (via ref), and dispatches InteractionEvents through the provided dispatch.
3546
+ */
3547
+
3548
+ interface UseSkillOrchestrationOptions {
3549
+ adapter: ChatWidgetAdapter | null;
3550
+ dispatch?: ((event: ChatWidgetInteractionEvent) => void) | null;
3551
+ }
3552
+ interface UseSkillOrchestrationReturn {
3553
+ data: UseSkillDataReturn;
3554
+ state: UseSkillSelectorStateReturn;
3555
+ handleSlashTrigger: (prefix: string) => void;
3556
+ handleSkillSelect: (skill: SkillSummary) => void;
3557
+ handleClose: (reason: 'escape' | 'blur' | 'select') => void;
3558
+ handleSearch: (text: string) => void;
3559
+ buildEnrichedText: (rawText: string) => string;
3560
+ selectedSkillsRef: React.MutableRefObject<SkillSummary[]>;
3561
+ }
3562
+ declare function useSkillOrchestration(options: UseSkillOrchestrationOptions): UseSkillOrchestrationReturn;
3563
+
3564
+ interface ResourceProviderProps {
3565
+ adapter: ChatWidgetAdapter;
3566
+ sessionId?: number;
3567
+ children: React__default.ReactNode;
3568
+ }
3569
+ declare const ResourceProvider: React__default.FC<ResourceProviderProps>;
3570
+
3571
+ interface ShareResourceProviderProps {
3572
+ /** Base URL for the share API (e.g., "https://api.example.com/share") */
3573
+ shareBaseUrl: string;
3574
+ /** Share token for authentication */
3575
+ shareToken?: string;
3576
+ children: React__default.ReactNode;
3577
+ }
3578
+ declare const ShareResourceProvider: React__default.FC<ShareResourceProviderProps>;
3579
+
3580
+ interface ResourceContextValue {
3581
+ resolveResource(resourceId: string): Promise<ResourceResolveResult>;
3582
+ resolvePreviewUrl?(resourceId: string, format: 'html' | 'pdf'): Promise<string>;
3583
+ listDirectoryFiles?(dirPrefix: string, options?: ListDirectoryFilesOptions): Promise<DirectoryFileEntry[]>;
3584
+ sessionId?: number;
3585
+ }
3586
+ declare const ResourceContext: React$1.Context<ResourceContextValue | null>;
3587
+ declare function useResourceContext(): ResourceContextValue | null;
3588
+
3589
+ interface ResourceInput {
3590
+ resource_id?: string;
3591
+ url?: string;
3592
+ content?: string;
3593
+ }
3594
+ interface ResourceState {
3595
+ loading: boolean;
3596
+ error?: string;
3597
+ url?: string;
3598
+ content?: string;
3599
+ mimeType?: string;
3600
+ fileName?: string;
3601
+ gitPath?: string;
3602
+ }
3603
+ /**
3604
+ * Resolve a resource from url, resource_id, or inline content.
3605
+ * Priority: url > resource_id > content.
3606
+ */
3607
+ declare function useResource(input: ResourceInput): ResourceState;
3608
+
3609
+ /**
3610
+ * prepareJsonRenderSpec — 把"老格式"的 GenUI spec 标准化到 @json-render 当前
3611
+ * 预期的形态。
3612
+ *
3613
+ * 历史背景:
3614
+ * 后端较早期吐出的 spec 用了两种与 @json-render 当前规范不一致的写法,
3615
+ * share viewer / 任何离线消费方都需要在喂给 Renderer 之前做一次翻译,
3616
+ * 否则要么报 schema 错,要么模板插值不生效。之前这套翻译只散落在 demo
3617
+ * 的 ``share-app.tsx`` 里,每个嵌入方都要复制一份;现在收回 SDK 作为
3618
+ * 公共工具。
3619
+ *
3620
+ * 处理项:
3621
+ * 1. ``{$cond: [c, t, e]}`` →
3622
+ * ``{$cond: c, $then: t, $else: e?}``
3623
+ * 2. ``{$state|$item|$index, op, value}`` (op ∈ eq/neq/gt/gte/lt/lte)→
3624
+ * ``{$state|$item|$index, [op]: value}``
3625
+ * 3. ``$template`` 字符串里的占位翻译(沿用早期 share viewer 的行为):
3626
+ * - ``{{/state/x}}`` → ``${/x}`` (剥掉 ``/state/`` 前缀,因为新版
3627
+ * ``$template`` 解析器自身的 root 就是 state,再带 ``/state/`` 会
3628
+ * 双层路径)
3629
+ * - ``{{x}}`` 或 ``{{user/age}}`` → ``${/x}`` / ``${/user/age}``
3630
+ * (相对路径自动补 ``/`` 前缀变绝对路径)
3631
+ * - ``{{/x}}`` → ``${/x}`` (已是绝对路径,原样保留)
3632
+ * 4. CWRF-013 Phase 0 spec migrator (``./migrator``) — strip protocol-lie
3633
+ * fields (Item 01 DataTable filterable/groupBy/expandable) before the
3634
+ * renderer sees them, with LRU caching + warning de-dup so repeat
3635
+ * renders of the same spec are silent. See
3636
+ * ``docs/proposals/CWRF-013-a2ui-systematic-upgrade/00_protocol/04_spec_migrator.md``.
3637
+ *
3638
+ * 输入会原样深拷贝,不修改入参。无法识别的结构原样保留。
3639
+ */
3640
+ /**
3641
+ * 接受任意 spec 形态(含老格式),返回标准化后的可直接喂给 ``@json-render``
3642
+ * Renderer / SDK ``<JsonRenderStandalone>`` 的对象。
3643
+ *
3644
+ * 不处理 ``null`` / 非对象 —— 原样返回,方便链式调用。
3645
+ *
3646
+ * Pipeline order:
3647
+ * 1. CWRF-013 spec migrator (Phase 0) — strip protocol-lie fields with
3648
+ * cached + dedupe-warned ``migrateSpecCached``. Runs FIRST so later
3649
+ * template / expression normalisation only sees honest specs.
3650
+ * Idempotent: same spec on second render hits the LRU cache and
3651
+ * emits no extra console.warn (see ``./migrator/dry-run.ts``).
3652
+ * 2. Expression normalisation (``$cond`` array → triplet, ``op``/``value``
3653
+ * → key-shorthand).
3654
+ * 3. Template rewriting (``{{...}}`` → ``${/...}``).
3655
+ */
3656
+ declare function prepareJsonRenderSpec<T = Record<string, unknown>>(raw: unknown): T;
3657
+
3658
+ /**
3659
+ * 在 KiCad S-expression 正文中定位包含指定 uuid 的最外层括号表(通常为 symbol/footprint 等图元块)。
3660
+ * 纯函数,无 DOM 依赖 — CWRF-003 §1.3 Compound Value。
3661
+ */
3662
+ declare function extractKicadSexprByUuid(content: string, uuid: string): string | null;
465
3663
 
466
- export { type AggregatedMessage, type Artifact, ChatWidget, type ChatWidgetAPI, type ChatWidgetAdapter, ChatWidgetAuthError, type ChatWidgetConfig, ChatWidgetNetworkError, type ChatWidgetProps, ChildAgentCard, type ConnectionStatus, DEFAULT_CONFIG, DefaultJetAgentsAdapter, type DefaultJetAgentsAdapterOptions, type ExecutionStatus, type HITLRequest, type HITLResponse, MessageContent, type MessageContentType, type NotificationTurn, type NotificationType, PinnedArea, PlanCard, type PlanItem, type ResourceContent, type Round, RoundHeader, type SSEMessage, SchemaFormRenderer, type SessionDetail, type TaskPlan, TodoCard, type TodoData, type TodoGroup, type TodoPhase, type TodoStats, type TodoTask, type ToolCallData, ToolCardBuffering, type UiConfig, isTodoNotificationContent, mergeConsecutiveThinkMessages, useMessageAggregator, useSSE };
3664
+ export { type AgentControlFrame, type AgentDefaultModelInfo, AgentGroupPanel, type AgentGroupPanelProps, type AgentInstanceState, type AggregatedMessage, type AnnotationAnchor, type AnnotationAnchorRect, AnnotationFAB, type AnnotationFABProps, type AnnotationInteraction, type AnnotationKind, type AnnotationMessage, AnnotationPanel, type AnnotationPanelMessage, type AnnotationPanelProps, type Artifact, type ArtifactRef, type AttentionToast, AttentionToastList, type AttentionToastListProps, ChatOverlay, type ChatOverlayProps, ChatWidget, type ChatWidgetAPI, type ChatWidgetAdapter, ChatWidgetAuthError, type ChatWidgetConfig, type ChatWidgetControllerOptions, type ChatWidgetControllerState, type ChatWidgetInteractionEvent, ChatWidgetLocale, ChatWidgetMessages, ChatWidgetNetworkError, type ChatWidgetProps, ChildAgentCard, HttpError as ClientAllocatorHttpError, type ClientTitleEvent, type ConnectionStatus, ContextChip, type ContextChipProps, type ContextPreload, type CreateClientOptions, type CreateClientResponse, type CreateDiscussionRequest, type CreateDiscussionResponse, DEFAULT_CONFIG, DefaultComposer, type DefaultComposerProps, DefaultJetAgentsAdapter, type DefaultJetAgentsAdapterOptions, type DirectoryFileEntry, DiscussionComposer, type DiscussionComposerProps, type DiscussionFile, type DiscussionMessage, type DiscussionMeta, DiscussionPanel, type DiscussionPanelProps, DiscussionViewer, type DiscussionViewerProps, ESC_PRIORITY, type EscHandler, type ExecutionStatus, type FileAttachment, type FileCategory$1 as FileCategory, type FileReference, type FileUploadResult, type FileUploadStatusResult, FileViewer, FileViewerModal, type FileViewerModalProps, FileViewerPanel, type FileViewerPanelProps, type FileViewerProps, FloatingInput, type FloatingInputProps, FloatingToolbar, type FloatingToolbarProps, type HITLRequest, type HITLResponse, HoverPreview, type HoverPreviewProps, I18nContext, Icon, type IconName, type IconProps, type IconWeight, ImmersiveShell, type ImmersiveShellProps, InlineAnnotationInput, type InlineAnnotationInputProps, type InteractionEventType, InvalidClientIdError, type KicadCanvasSelectionPayload, LinkCard, type ListDirectoryFilesOptions, type ListModelsParams, type ListModelsResponse, type ListSessionsParams, type ListSessionsResponse, MODEL_AUTO, MentionAutocomplete, type MentionAutocompleteProps, type MentionTarget, MessageContent, type MessageContentType, type ModelChoice, type ModelListItemBasenameGrouped, type ModelListItemGrouped, type ModelListItemRaw, type ModelListVariant, type ModelOverride, ModelPicker, type ModelPickerProps, type NotificationConfig, type NotificationTurn, type NotificationType, type PendingHIL, PinnedArea, PlanCard, type PlanItem, type PoolAgent, type PoolAgentAction, type PoolStatusResponse, type PostDiscussionMessageRequest, type PostDiscussionMessageResponse, type ProjectFile, ProvenanceGraphSnapshot, type RailAction, type ReadReceipt, ResourceChip, type ResourceContent, ResourceContext, type ResourceContextValue, type ResourceInput, ResourceProvider, type ResourceState, RichInput, type RichInputHandle, type RichInputProps, type Round, RoundHeader, RoundMessageList, RoundsView, type RoundsViewProps, type SSEMessage, SchemaFormRenderer, type SelectedSkillRef, type SelectionBridgeOptions, type SelectionData, type SelectionState, type SessionChannelMessage, type ClientItem as SessionClientItem, BusinessError as SessionClientsBusinessError, type SessionDetail, type SessionLifecycleEvent, type SessionListItem, SessionListPanel, type SessionListPanelProps, ShareResourceProvider, type ShortcutDef, type SkillListParams, type SkillListResponse, SkillSelector, type SkillSelectorProps, type SkillSummary, type SmartPasteOptions, type SnapshotData, type SpecLifecycleEntry, SplitPanel, type SplitPanelProps, TabBar, type TabBarProps, type TaskPlan, TodoCard, type TodoData, type TodoGroup, type TodoPhase, type TodoStats, type TodoTask, type ToolCallData, ToolCardBuffering, type TransportMode, type TreePersistState, type UiConfig, type UploadedFileInfo, type UseAgentControlOptions, type UseAgentDefaultModelOptions, type UseAgentDefaultModelResult, type UseAnnotationsOptions, type UseAnnotationsReturn, type UseAttentionManagerOptions, type UseAutoTabOptions, type UseClientIdAllocatorReturn, type UseDiscussionsOptions, type UseDiscussionsReturn, type UseFileUploadOptions, type UseFileUploadReturn, type UseHoverPreviewOptions, type UseModelsOptions, type UseModelsResult, type UseProjectFilesOptions, type UseProjectFilesResult, type UseSessionChannelOptions, type UseSessionChannelReturn, type UseSessionClientsReturn, type UseSessionListOptions, type UseSessionListReturn, type UseShortcutsOptions, type UseSkillDataOptions, type UseSkillDataReturn, type UseSkillOrchestrationOptions, type UseSkillOrchestrationReturn, type UseSkillSelectorStateReturn, type UseViewerTabsReturn, type UseWorkspaceFilesOptions, type UseWorkspaceFilesReturn, VIEWER_CAPABILITIES, type ViewerInteractionAdapter, type ViewerTab, type WorkspaceFile, WorkspacePanel, type WorkspacePanelProps, type WorkspaceTreeNode, type WorkspaceUploadResult, type XrefMeta, type XrefRecord, type XrefRef, contentToSrc, extractKicadSexprByUuid, fileTypeCategory, fileTypeColor, fileTypeIcon, formatFileSize, getExtension, getFileCategory, getStatusDisplay, getViewerCapabilities, inferLanguage, isShowModelChannels, isTodoNotificationContent, loadLastModelName, mergeConsecutiveThinkMessages, modelBasename, organizeMessagesByLevel, parseDiscussionMessages, parseXrefs, prepareJsonRenderSpec, saveLastModelName, useAgentControl, useAgentDefaultModel, useAnnotations, useAttentionManager, useAutoTab, useChatWidgetController, useChatWidgetI18n, useClientIdAllocator, useDiscussions, useEscStack, useFileUpload, useHoverPreview, useMessageAggregator, useModels, useNarrowMode, useProjectFiles, useResource, useResourceContext, useSSE, useSelectionBridge, useSessionChannel, useSessionClients, useSessionList, useShortcuts, useSkillData, useSkillOrchestration, useSkillSelectorState, useSmartPaste, useTreePersist, useViewerTabs, useWorkspaceFiles };