@webskill/chatbot 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,10 +6,10 @@ import { t as yaml } from "./yaml-C888tCbJ.js";
6
6
  import { t as json } from "./json-BOcU6nei.js";
7
7
  import { t as typescript } from "./typescript-DAau_Qyl.js";
8
8
  import { t as jsx$1 } from "./jsx-D2Jv0wvt.js";
9
- import { AnthropicClient, FsArtifactStore, FsMemoryStore, FsRunSnapshotStore, FsRunTraceStore, FsSessionStore, FullDisclosureRouter, GoogleGenAiClient, OpenAiCompatibleClient, SkillDiscovery, WebSkillError, WebSkillRuntime, messageOf, summarizeToolCalls } from "@webskill/sdk";
9
+ import { AnthropicClient, FsArtifactStore, FsMemoryStore, FsRunSnapshotStore, FsRunTraceStore, FsSessionStore, FullDisclosureRouter, GoogleGenAiClient, OpenAiCompatibleClient, SkillDiscovery, WebSkillError, WebSkillRuntime, isUnsupportedRunSnapshot, messageOf, summarizeToolCalls, textParts } from "@webskill/sdk";
10
10
  import { BrowserWorkerScriptExecutor } from "@webskill/sdk/browser";
11
- import { JsonRenderSpecSurface, NativeSpecSurface, OpenUiSpecSurface, ReactBridgeState, UiSurfaceList, UiSurfaceSnapshotList } from "@webskill/sdk/ui-react";
12
- import { A2UI_SPEC_FORM_PATH, LitRendererBridge, OPENUI_SURFACE_ACTION, VERCEL_SURFACE_ACTION_DATA_PART_TYPE, collectValues, createUiCatalogToolSource, fromA2uiSpecAction, fromA2uiSurfaceAction, fromOpenUiAction, fromOpenUiSurfaceAction, fromVercelSurfaceAction, interactionToFormModel, isUiSpecSurface, loadOpenUiPeers, loadWebSkillLitCatalog, renderMiniChart, shapeInteractionValue, toA2uiSpecMessages, toA2uiSurfaceAction, toA2uiSurfaceMessages, toOpenUiLang, toOpenUiSurfaceLang, toVercelSurfaceDataPart, toVercelToolInvocation, uiCatalog } from "@webskill/sdk/ui";
11
+ import { JsonRenderSpecSurface, NativeSpecSurface, OpenUiSpecSurface, ReactBridgeState, SpecInteractionChannel, UiSurfaceList, UiSurfaceSnapshotList, probeJsonRenderAvailability } from "@webskill/sdk/ui-react";
12
+ import { A2UI_SPEC_FORM_PATH, createUiCatalogToolSource, fromA2uiSpecAction, fromA2uiSurfaceAction, interactionToFormModel, interactionToUiSpec, loadOpenUiPeers, loadWebSkillLitCatalog, renderMiniChart, shapeInteractionValue, toA2uiSpecMessages, toA2uiSurfaceAction, toVercelToolInvocation, uiCatalog } from "@webskill/sdk/ui";
13
13
  import * as React$1 from "react";
14
14
  import React, { Children, Component, Fragment, createContext, createElement, forwardRef, isValidElement, memo, useCallback, useContext, useDeferredValue, useEffect, useEffectEvent, useId, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
15
15
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -183,6 +183,70 @@ const createLucideIcon = (iconName, iconNode) => {
183
183
  return Component;
184
184
  };
185
185
 
186
+ //#endregion
187
+ //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/archive-restore.mjs
188
+ /**
189
+ * @license lucide-react v1.27.0 - ISC
190
+ *
191
+ * This source code is licensed under the ISC license.
192
+ * See the LICENSE file in the root directory of this source tree.
193
+ */
194
+ const __iconNode$33 = [
195
+ ["rect", {
196
+ width: "20",
197
+ height: "5",
198
+ x: "2",
199
+ y: "3",
200
+ rx: "1",
201
+ key: "1wp1u1"
202
+ }],
203
+ ["path", {
204
+ d: "M4 8v11a2 2 0 0 0 2 2h2",
205
+ key: "tvwodi"
206
+ }],
207
+ ["path", {
208
+ d: "M20 8v11a2 2 0 0 1-2 2h-2",
209
+ key: "1gkqxj"
210
+ }],
211
+ ["path", {
212
+ d: "m9 15 3-3 3 3",
213
+ key: "1pd0qc"
214
+ }],
215
+ ["path", {
216
+ d: "M12 12v9",
217
+ key: "192myk"
218
+ }]
219
+ ];
220
+ const ArchiveRestore = createLucideIcon("archive-restore", __iconNode$33);
221
+
222
+ //#endregion
223
+ //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/archive.mjs
224
+ /**
225
+ * @license lucide-react v1.27.0 - ISC
226
+ *
227
+ * This source code is licensed under the ISC license.
228
+ * See the LICENSE file in the root directory of this source tree.
229
+ */
230
+ const __iconNode$32 = [
231
+ ["rect", {
232
+ width: "20",
233
+ height: "5",
234
+ x: "2",
235
+ y: "3",
236
+ rx: "1",
237
+ key: "1wp1u1"
238
+ }],
239
+ ["path", {
240
+ d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8",
241
+ key: "1s80jp"
242
+ }],
243
+ ["path", {
244
+ d: "M10 12h4",
245
+ key: "a56b0p"
246
+ }]
247
+ ];
248
+ const Archive = createLucideIcon("archive", __iconNode$32);
249
+
186
250
  //#endregion
187
251
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/arrow-up.mjs
188
252
  /**
@@ -191,14 +255,14 @@ const createLucideIcon = (iconName, iconNode) => {
191
255
  * This source code is licensed under the ISC license.
192
256
  * See the LICENSE file in the root directory of this source tree.
193
257
  */
194
- const __iconNode$30 = [["path", {
258
+ const __iconNode$31 = [["path", {
195
259
  d: "m5 12 7-7 7 7",
196
260
  key: "hav0vg"
197
261
  }], ["path", {
198
262
  d: "M12 19V5",
199
263
  key: "x0mq9r"
200
264
  }]];
201
- const ArrowUp = createLucideIcon("arrow-up", __iconNode$30);
265
+ const ArrowUp = createLucideIcon("arrow-up", __iconNode$31);
202
266
 
203
267
  //#endregion
204
268
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/check.mjs
@@ -208,11 +272,11 @@ const ArrowUp = createLucideIcon("arrow-up", __iconNode$30);
208
272
  * This source code is licensed under the ISC license.
209
273
  * See the LICENSE file in the root directory of this source tree.
210
274
  */
211
- const __iconNode$29 = [["path", {
275
+ const __iconNode$30 = [["path", {
212
276
  d: "M20 6 9 17l-5-5",
213
277
  key: "1gmf2c"
214
278
  }]];
215
- const Check = createLucideIcon("check", __iconNode$29);
279
+ const Check = createLucideIcon("check", __iconNode$30);
216
280
 
217
281
  //#endregion
218
282
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/chevron-down.mjs
@@ -222,11 +286,11 @@ const Check = createLucideIcon("check", __iconNode$29);
222
286
  * This source code is licensed under the ISC license.
223
287
  * See the LICENSE file in the root directory of this source tree.
224
288
  */
225
- const __iconNode$28 = [["path", {
289
+ const __iconNode$29 = [["path", {
226
290
  d: "m6 9 6 6 6-6",
227
291
  key: "qrunsl"
228
292
  }]];
229
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$28);
293
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$29);
230
294
 
231
295
  //#endregion
232
296
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/circle-check.mjs
@@ -236,7 +300,7 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$28);
236
300
  * This source code is licensed under the ISC license.
237
301
  * See the LICENSE file in the root directory of this source tree.
238
302
  */
239
- const __iconNode$27 = [["circle", {
303
+ const __iconNode$28 = [["circle", {
240
304
  cx: "12",
241
305
  cy: "12",
242
306
  r: "10",
@@ -245,7 +309,7 @@ const __iconNode$27 = [["circle", {
245
309
  d: "m9 12 2 2 4-4",
246
310
  key: "dzmm74"
247
311
  }]];
248
- const CircleCheck = createLucideIcon("circle-check", __iconNode$27);
312
+ const CircleCheck = createLucideIcon("circle-check", __iconNode$28);
249
313
 
250
314
  //#endregion
251
315
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/circle-question-mark.mjs
@@ -255,7 +319,7 @@ const CircleCheck = createLucideIcon("circle-check", __iconNode$27);
255
319
  * This source code is licensed under the ISC license.
256
320
  * See the LICENSE file in the root directory of this source tree.
257
321
  */
258
- const __iconNode$26 = [
322
+ const __iconNode$27 = [
259
323
  ["circle", {
260
324
  cx: "12",
261
325
  cy: "12",
@@ -271,7 +335,7 @@ const __iconNode$26 = [
271
335
  key: "p32p05"
272
336
  }]
273
337
  ];
274
- const CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode$26);
338
+ const CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode$27);
275
339
 
276
340
  //#endregion
277
341
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/circle-x.mjs
@@ -281,7 +345,7 @@ const CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode$2
281
345
  * This source code is licensed under the ISC license.
282
346
  * See the LICENSE file in the root directory of this source tree.
283
347
  */
284
- const __iconNode$25 = [
348
+ const __iconNode$26 = [
285
349
  ["circle", {
286
350
  cx: "12",
287
351
  cy: "12",
@@ -297,7 +361,7 @@ const __iconNode$25 = [
297
361
  key: "z0biqf"
298
362
  }]
299
363
  ];
300
- const CircleX = createLucideIcon("circle-x", __iconNode$25);
364
+ const CircleX = createLucideIcon("circle-x", __iconNode$26);
301
365
 
302
366
  //#endregion
303
367
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/clipboard-list.mjs
@@ -307,7 +371,7 @@ const CircleX = createLucideIcon("circle-x", __iconNode$25);
307
371
  * This source code is licensed under the ISC license.
308
372
  * See the LICENSE file in the root directory of this source tree.
309
373
  */
310
- const __iconNode$24 = [
374
+ const __iconNode$25 = [
311
375
  ["rect", {
312
376
  width: "8",
313
377
  height: "4",
@@ -338,7 +402,7 @@ const __iconNode$24 = [
338
402
  key: "18s6g9"
339
403
  }]
340
404
  ];
341
- const ClipboardList = createLucideIcon("clipboard-list", __iconNode$24);
405
+ const ClipboardList = createLucideIcon("clipboard-list", __iconNode$25);
342
406
 
343
407
  //#endregion
344
408
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/copy.mjs
@@ -348,7 +412,7 @@ const ClipboardList = createLucideIcon("clipboard-list", __iconNode$24);
348
412
  * This source code is licensed under the ISC license.
349
413
  * See the LICENSE file in the root directory of this source tree.
350
414
  */
351
- const __iconNode$23 = [["rect", {
415
+ const __iconNode$24 = [["rect", {
352
416
  width: "14",
353
417
  height: "14",
354
418
  x: "8",
@@ -360,7 +424,7 @@ const __iconNode$23 = [["rect", {
360
424
  d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",
361
425
  key: "zix9uf"
362
426
  }]];
363
- const Copy = createLucideIcon("copy", __iconNode$23);
427
+ const Copy = createLucideIcon("copy", __iconNode$24);
364
428
 
365
429
  //#endregion
366
430
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/download.mjs
@@ -370,7 +434,7 @@ const Copy = createLucideIcon("copy", __iconNode$23);
370
434
  * This source code is licensed under the ISC license.
371
435
  * See the LICENSE file in the root directory of this source tree.
372
436
  */
373
- const __iconNode$22 = [
437
+ const __iconNode$23 = [
374
438
  ["path", {
375
439
  d: "M12 15V3",
376
440
  key: "m9g1x1"
@@ -384,7 +448,7 @@ const __iconNode$22 = [
384
448
  key: "brsn70"
385
449
  }]
386
450
  ];
387
- const Download = createLucideIcon("download", __iconNode$22);
451
+ const Download = createLucideIcon("download", __iconNode$23);
388
452
 
389
453
  //#endregion
390
454
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/external-link.mjs
@@ -394,7 +458,7 @@ const Download = createLucideIcon("download", __iconNode$22);
394
458
  * This source code is licensed under the ISC license.
395
459
  * See the LICENSE file in the root directory of this source tree.
396
460
  */
397
- const __iconNode$21 = [
461
+ const __iconNode$22 = [
398
462
  ["path", {
399
463
  d: "M15 3h6v6",
400
464
  key: "1q9fwt"
@@ -408,7 +472,7 @@ const __iconNode$21 = [
408
472
  key: "a6xqqp"
409
473
  }]
410
474
  ];
411
- const ExternalLink = createLucideIcon("external-link", __iconNode$21);
475
+ const ExternalLink = createLucideIcon("external-link", __iconNode$22);
412
476
 
413
477
  //#endregion
414
478
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/file.mjs
@@ -418,14 +482,14 @@ const ExternalLink = createLucideIcon("external-link", __iconNode$21);
418
482
  * This source code is licensed under the ISC license.
419
483
  * See the LICENSE file in the root directory of this source tree.
420
484
  */
421
- const __iconNode$20 = [["path", {
485
+ const __iconNode$21 = [["path", {
422
486
  d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
423
487
  key: "1oefj6"
424
488
  }], ["path", {
425
489
  d: "M14 2v5a1 1 0 0 0 1 1h5",
426
490
  key: "wfsgrz"
427
491
  }]];
428
- const File = createLucideIcon("file", __iconNode$20);
492
+ const File = createLucideIcon("file", __iconNode$21);
429
493
 
430
494
  //#endregion
431
495
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/list-checks.mjs
@@ -435,7 +499,7 @@ const File = createLucideIcon("file", __iconNode$20);
435
499
  * This source code is licensed under the ISC license.
436
500
  * See the LICENSE file in the root directory of this source tree.
437
501
  */
438
- const __iconNode$19 = [
502
+ const __iconNode$20 = [
439
503
  ["path", {
440
504
  d: "M13 5h8",
441
505
  key: "a7qcls"
@@ -457,7 +521,7 @@ const __iconNode$19 = [
457
521
  key: "1obspn"
458
522
  }]
459
523
  ];
460
- const ListChecks = createLucideIcon("list-checks", __iconNode$19);
524
+ const ListChecks = createLucideIcon("list-checks", __iconNode$20);
461
525
 
462
526
  //#endregion
463
527
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/loader-circle.mjs
@@ -467,11 +531,11 @@ const ListChecks = createLucideIcon("list-checks", __iconNode$19);
467
531
  * This source code is licensed under the ISC license.
468
532
  * See the LICENSE file in the root directory of this source tree.
469
533
  */
470
- const __iconNode$18 = [["path", {
534
+ const __iconNode$19 = [["path", {
471
535
  d: "M21 12a9 9 0 1 1-6.219-8.56",
472
536
  key: "13zald"
473
537
  }]];
474
- const LoaderCircle = createLucideIcon("loader-circle", __iconNode$18);
538
+ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$19);
475
539
 
476
540
  //#endregion
477
541
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/menu.mjs
@@ -481,7 +545,7 @@ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$18);
481
545
  * This source code is licensed under the ISC license.
482
546
  * See the LICENSE file in the root directory of this source tree.
483
547
  */
484
- const __iconNode$17 = [
548
+ const __iconNode$18 = [
485
549
  ["path", {
486
550
  d: "M4 5h16",
487
551
  key: "1tepv9"
@@ -495,7 +559,7 @@ const __iconNode$17 = [
495
559
  key: "1djgab"
496
560
  }]
497
561
  ];
498
- const Menu = createLucideIcon("menu", __iconNode$17);
562
+ const Menu = createLucideIcon("menu", __iconNode$18);
499
563
 
500
564
  //#endregion
501
565
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/message-circle-question-mark.mjs
@@ -505,7 +569,7 @@ const Menu = createLucideIcon("menu", __iconNode$17);
505
569
  * This source code is licensed under the ISC license.
506
570
  * See the LICENSE file in the root directory of this source tree.
507
571
  */
508
- const __iconNode$16 = [
572
+ const __iconNode$17 = [
509
573
  ["path", {
510
574
  d: "M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",
511
575
  key: "1sd12s"
@@ -519,7 +583,7 @@ const __iconNode$16 = [
519
583
  key: "p32p05"
520
584
  }]
521
585
  ];
522
- const MessageCircleQuestionMark = createLucideIcon("message-circle-question-mark", __iconNode$16);
586
+ const MessageCircleQuestionMark = createLucideIcon("message-circle-question-mark", __iconNode$17);
523
587
 
524
588
  //#endregion
525
589
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/panel-right-open.mjs
@@ -529,7 +593,7 @@ const MessageCircleQuestionMark = createLucideIcon("message-circle-question-mark
529
593
  * This source code is licensed under the ISC license.
530
594
  * See the LICENSE file in the root directory of this source tree.
531
595
  */
532
- const __iconNode$15 = [
596
+ const __iconNode$16 = [
533
597
  ["rect", {
534
598
  width: "18",
535
599
  height: "18",
@@ -547,7 +611,7 @@ const __iconNode$15 = [
547
611
  key: "1pgupc"
548
612
  }]
549
613
  ];
550
- const PanelRightOpen = createLucideIcon("panel-right-open", __iconNode$15);
614
+ const PanelRightOpen = createLucideIcon("panel-right-open", __iconNode$16);
551
615
 
552
616
  //#endregion
553
617
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/paperclip.mjs
@@ -557,11 +621,28 @@ const PanelRightOpen = createLucideIcon("panel-right-open", __iconNode$15);
557
621
  * This source code is licensed under the ISC license.
558
622
  * See the LICENSE file in the root directory of this source tree.
559
623
  */
560
- const __iconNode$14 = [["path", {
624
+ const __iconNode$15 = [["path", {
561
625
  d: "m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551",
562
626
  key: "1miecu"
563
627
  }]];
564
- const Paperclip = createLucideIcon("paperclip", __iconNode$14);
628
+ const Paperclip = createLucideIcon("paperclip", __iconNode$15);
629
+
630
+ //#endregion
631
+ //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/pencil.mjs
632
+ /**
633
+ * @license lucide-react v1.27.0 - ISC
634
+ *
635
+ * This source code is licensed under the ISC license.
636
+ * See the LICENSE file in the root directory of this source tree.
637
+ */
638
+ const __iconNode$14 = [["path", {
639
+ d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
640
+ key: "1a8usu"
641
+ }], ["path", {
642
+ d: "m15 5 4 4",
643
+ key: "1mk7zo"
644
+ }]];
645
+ const Pencil = createLucideIcon("pencil", __iconNode$14);
565
646
 
566
647
  //#endregion
567
648
  //#region ../../node_modules/.pnpm/lucide-react@1.27.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/play.mjs
@@ -913,8 +994,8 @@ function Label({ className = "", ...props }) {
913
994
 
914
995
  //#endregion
915
996
  //#region ../../node_modules/.pnpm/@radix-ui+react-compose-refs@1.1.5_@types+react@19.2.17_react@19.2.8/node_modules/@radix-ui/react-compose-refs/dist/index.mjs
916
- var __defProp$22 = Object.defineProperty;
917
- var __name$22 = (target, value) => __defProp$22(target, "name", {
997
+ var __defProp$21 = Object.defineProperty;
998
+ var __name$21 = (target, value) => __defProp$21(target, "name", {
918
999
  value,
919
1000
  configurable: true
920
1001
  });
@@ -922,7 +1003,7 @@ function setRef$2(ref, value) {
922
1003
  if (typeof ref === "function") return ref(value);
923
1004
  else if (ref !== null && ref !== void 0) ref.current = value;
924
1005
  }
925
- __name$22(setRef$2, "setRef");
1006
+ __name$21(setRef$2, "setRef");
926
1007
  function composeRefs$1(...refs) {
927
1008
  return (node) => {
928
1009
  let hasCleanup = false;
@@ -940,16 +1021,16 @@ function composeRefs$1(...refs) {
940
1021
  };
941
1022
  };
942
1023
  }
943
- __name$22(composeRefs$1, "composeRefs");
1024
+ __name$21(composeRefs$1, "composeRefs");
944
1025
  function useComposedRefs$1(...refs) {
945
1026
  return React$1.useCallback(composeRefs$1(...refs), refs);
946
1027
  }
947
- __name$22(useComposedRefs$1, "useComposedRefs");
1028
+ __name$21(useComposedRefs$1, "useComposedRefs");
948
1029
 
949
1030
  //#endregion
950
1031
  //#region ../../node_modules/.pnpm/@radix-ui+react-context@1.2.2_@types+react@19.2.17_react@19.2.8/node_modules/@radix-ui/react-context/dist/index.mjs
951
- var __defProp$21 = Object.defineProperty;
952
- var __name$21 = (target, value) => __defProp$21(target, "name", {
1032
+ var __defProp$20 = Object.defineProperty;
1033
+ var __name$20 = (target, value) => __defProp$20(target, "name", {
953
1034
  value,
954
1035
  configurable: true
955
1036
  });
@@ -957,7 +1038,7 @@ var __name$21 = (target, value) => __defProp$21(target, "name", {
957
1038
  function createContext2(rootComponentName, defaultContext) {
958
1039
  const Context = React$1.createContext(defaultContext);
959
1040
  Context.displayName = rootComponentName + "Context";
960
- const Provider = /* @__PURE__ */ __name$21((props) => {
1041
+ const Provider = /* @__PURE__ */ __name$20((props) => {
961
1042
  const { children, ...context } = props;
962
1043
  const value = React$1.useMemo(() => context, Object.values(context));
963
1044
  return /* @__PURE__ */ jsx(Context.Provider, {
@@ -974,10 +1055,10 @@ function createContext2(rootComponentName, defaultContext) {
974
1055
  if (optional) return void 0;
975
1056
  throw new Error(`\`${consumerName}\` must be used within \`${rootComponentName}\``);
976
1057
  }
977
- __name$21(useContext2, "useContext");
1058
+ __name$20(useContext2, "useContext");
978
1059
  return [Provider, useContext2];
979
1060
  }
980
- __name$21(createContext2, "createContext");
1061
+ __name$20(createContext2, "createContext");
981
1062
  // @__NO_SIDE_EFFECTS__
982
1063
  function createContextScope(scopeName, createContextScopeDeps = []) {
983
1064
  let defaultContexts = [];
@@ -986,7 +1067,7 @@ function createContextScope(scopeName, createContextScopeDeps = []) {
986
1067
  BaseContext.displayName = rootComponentName + "Context";
987
1068
  const index = defaultContexts.length;
988
1069
  defaultContexts = [...defaultContexts, defaultContext];
989
- const Provider = /* @__PURE__ */ __name$21((props) => {
1070
+ const Provider = /* @__PURE__ */ __name$20((props) => {
990
1071
  const { scope, children, ...context } = props;
991
1072
  const Context = scope?.[scopeName]?.[index] || BaseContext;
992
1073
  const value = React$1.useMemo(() => context, Object.values(context));
@@ -1005,15 +1086,15 @@ function createContextScope(scopeName, createContextScopeDeps = []) {
1005
1086
  if (optional) return void 0;
1006
1087
  throw new Error(`\`${consumerName}\` must be used within \`${rootComponentName}\``);
1007
1088
  }
1008
- __name$21(useContext2, "useContext");
1089
+ __name$20(useContext2, "useContext");
1009
1090
  return [Provider, useContext2];
1010
1091
  }
1011
- __name$21(createContext3, "createContext");
1012
- const createScope = /* @__PURE__ */ __name$21(() => {
1092
+ __name$20(createContext3, "createContext");
1093
+ const createScope = /* @__PURE__ */ __name$20(() => {
1013
1094
  const scopeContexts = defaultContexts.map((defaultContext) => {
1014
1095
  return React$1.createContext(defaultContext);
1015
1096
  });
1016
- return /* @__PURE__ */ __name$21(function useScope(scope) {
1097
+ return /* @__PURE__ */ __name$20(function useScope(scope) {
1017
1098
  const contexts = scope?.[scopeName] || scopeContexts;
1018
1099
  return React$1.useMemo(() => ({ [`__scope${scopeName}`]: {
1019
1100
  ...scope,
@@ -1024,16 +1105,16 @@ function createContextScope(scopeName, createContextScopeDeps = []) {
1024
1105
  createScope.scopeName = scopeName;
1025
1106
  return [createContext3, composeContextScopes(createScope, ...createContextScopeDeps)];
1026
1107
  }
1027
- __name$21(createContextScope, "createContextScope");
1108
+ __name$20(createContextScope, "createContextScope");
1028
1109
  function composeContextScopes(...scopes) {
1029
1110
  const baseScope = scopes[0];
1030
1111
  if (scopes.length === 1) return baseScope;
1031
- const createScope = /* @__PURE__ */ __name$21(() => {
1112
+ const createScope = /* @__PURE__ */ __name$20(() => {
1032
1113
  const scopeHooks = scopes.map((createScope2) => ({
1033
1114
  useScope: createScope2(),
1034
1115
  scopeName: createScope2.scopeName
1035
1116
  }));
1036
- return /* @__PURE__ */ __name$21(function useComposedScopes(overrideScopes) {
1117
+ return /* @__PURE__ */ __name$20(function useComposedScopes(overrideScopes) {
1037
1118
  const nextScopes = scopeHooks.reduce((nextScopes2, { useScope, scopeName }) => {
1038
1119
  const currentScope = useScope(overrideScopes)[`__scope${scopeName}`];
1039
1120
  return {
@@ -1047,33 +1128,33 @@ function composeContextScopes(...scopes) {
1047
1128
  createScope.scopeName = baseScope.scopeName;
1048
1129
  return createScope;
1049
1130
  }
1050
- __name$21(composeContextScopes, "composeContextScopes");
1131
+ __name$20(composeContextScopes, "composeContextScopes");
1051
1132
 
1052
1133
  //#endregion
1053
1134
  //#region ../../node_modules/.pnpm/@radix-ui+primitive@1.1.7/node_modules/@radix-ui/primitive/dist/index.mjs
1054
- var __defProp$20 = Object.defineProperty;
1055
- var __name$20 = (target, value) => __defProp$20(target, "name", {
1135
+ var __defProp$19 = Object.defineProperty;
1136
+ var __name$19 = (target, value) => __defProp$19(target, "name", {
1056
1137
  value,
1057
1138
  configurable: true
1058
1139
  });
1059
1140
  var canUseDOM = !!(typeof window !== "undefined" && window.document && window.document.createElement);
1060
1141
  function composeEventHandlers(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
1061
- return /* @__PURE__ */ __name$20(function handleEvent(event) {
1142
+ return /* @__PURE__ */ __name$19(function handleEvent(event) {
1062
1143
  originalEventHandler?.(event);
1063
1144
  if (checkForDefaultPrevented === false || !event || !event.defaultPrevented) return ourEventHandler?.(event);
1064
1145
  }, "handleEvent");
1065
1146
  }
1066
- __name$20(composeEventHandlers, "composeEventHandlers");
1147
+ __name$19(composeEventHandlers, "composeEventHandlers");
1067
1148
  function getOwnerWindow(element) {
1068
1149
  if (!canUseDOM) throw new Error("Cannot access window outside of the DOM");
1069
1150
  return element?.ownerDocument?.defaultView ?? window;
1070
1151
  }
1071
- __name$20(getOwnerWindow, "getOwnerWindow");
1152
+ __name$19(getOwnerWindow, "getOwnerWindow");
1072
1153
  function getOwnerDocument(element) {
1073
1154
  if (!canUseDOM) throw new Error("Cannot access document outside of the DOM");
1074
1155
  return element?.ownerDocument ?? document;
1075
1156
  }
1076
- __name$20(getOwnerDocument, "getOwnerDocument");
1157
+ __name$19(getOwnerDocument, "getOwnerDocument");
1077
1158
  function getActiveElement(node, activeDescendant = false) {
1078
1159
  const { activeElement } = getOwnerDocument(node);
1079
1160
  if (!activeElement?.nodeName) return null;
@@ -1087,11 +1168,11 @@ function getActiveElement(node, activeDescendant = false) {
1087
1168
  }
1088
1169
  return activeElement;
1089
1170
  }
1090
- __name$20(getActiveElement, "getActiveElement");
1171
+ __name$19(getActiveElement, "getActiveElement");
1091
1172
  function isFrame(element) {
1092
1173
  return element.tagName === "IFRAME";
1093
1174
  }
1094
- __name$20(isFrame, "isFrame");
1175
+ __name$19(isFrame, "isFrame");
1095
1176
 
1096
1177
  //#endregion
1097
1178
  //#region ../../node_modules/.pnpm/@radix-ui+react-use-layout-effect@1.1.4_@types+react@19.2.17_react@19.2.8/node_modules/@radix-ui/react-use-layout-effect/dist/index.mjs
@@ -1099,8 +1180,8 @@ var useLayoutEffect2 = globalThis?.document ? React$1.useLayoutEffect : () => {}
1099
1180
 
1100
1181
  //#endregion
1101
1182
  //#region ../../node_modules/.pnpm/@radix-ui+react-use-effect-event@0.0.5_@types+react@19.2.17_react@19.2.8/node_modules/@radix-ui/react-use-effect-event/dist/index.mjs
1102
- var __defProp$19 = Object.defineProperty;
1103
- var __name$19 = (target, value) => __defProp$19(target, "name", {
1183
+ var __defProp$18 = Object.defineProperty;
1184
+ var __name$18 = (target, value) => __defProp$18(target, "name", {
1104
1185
  value,
1105
1186
  configurable: true
1106
1187
  });
@@ -1119,17 +1200,17 @@ function useEffectEvent$1(callback) {
1119
1200
  });
1120
1201
  return React$1.useMemo(() => ((...args) => ref.current?.(...args)), []);
1121
1202
  }
1122
- __name$19(useEffectEvent$1, "useEffectEvent");
1203
+ __name$18(useEffectEvent$1, "useEffectEvent");
1123
1204
 
1124
1205
  //#endregion
1125
1206
  //#region ../../node_modules/.pnpm/@radix-ui+react-use-controllable-state@1.2.6_@types+react@19.2.17_react@19.2.8/node_modules/@radix-ui/react-use-controllable-state/dist/index.mjs
1126
- var __defProp$18 = Object.defineProperty;
1127
- var __name$18 = (target, value) => __defProp$18(target, "name", {
1207
+ var __defProp$17 = Object.defineProperty;
1208
+ var __name$17 = (target, value) => __defProp$17(target, "name", {
1128
1209
  value,
1129
1210
  configurable: true
1130
1211
  });
1131
1212
  var useInsertionEffect$1 = React$1[" useInsertionEffect ".trim().toString()] || useLayoutEffect2;
1132
- function useControllableState({ prop, defaultProp, onChange = /* @__PURE__ */ __name$18(() => {}, "onChange"), caller }) {
1213
+ function useControllableState({ prop, defaultProp, onChange = /* @__PURE__ */ __name$17(() => {}, "onChange"), caller }) {
1133
1214
  const [uncontrolledProp, setUncontrolledProp, onChangeRef] = useUncontrolledState({
1134
1215
  defaultProp,
1135
1216
  onChange
@@ -1146,7 +1227,7 @@ function useControllableState({ prop, defaultProp, onChange = /* @__PURE__ */ __
1146
1227
  }
1147
1228
  return [value, React$1.useCallback((nextValue) => {
1148
1229
  if (isControlled) {
1149
- const value2 = isFunction$2(nextValue) ? nextValue(prop) : nextValue;
1230
+ const value2 = isFunction$1(nextValue) ? nextValue(prop) : nextValue;
1150
1231
  if (value2 !== prop) onChangeRef.current?.(value2);
1151
1232
  } else setUncontrolledProp(nextValue);
1152
1233
  }, [
@@ -1156,7 +1237,7 @@ function useControllableState({ prop, defaultProp, onChange = /* @__PURE__ */ __
1156
1237
  onChangeRef
1157
1238
  ])];
1158
1239
  }
1159
- __name$18(useControllableState, "useControllableState");
1240
+ __name$17(useControllableState, "useControllableState");
1160
1241
  function useUncontrolledState({ defaultProp, onChange }) {
1161
1242
  const [value, setValue] = React$1.useState(defaultProp);
1162
1243
  const prevValueRef = React$1.useRef(value);
@@ -1176,11 +1257,11 @@ function useUncontrolledState({ defaultProp, onChange }) {
1176
1257
  onChangeRef
1177
1258
  ];
1178
1259
  }
1179
- __name$18(useUncontrolledState, "useUncontrolledState");
1180
- function isFunction$2(value) {
1260
+ __name$17(useUncontrolledState, "useUncontrolledState");
1261
+ function isFunction$1(value) {
1181
1262
  return typeof value === "function";
1182
1263
  }
1183
- __name$18(isFunction$2, "isFunction");
1264
+ __name$17(isFunction$1, "isFunction");
1184
1265
  var SYNC_STATE = Symbol("RADIX:SYNC_STATE");
1185
1266
  function useControllableStateReducer(reducer, userArgs, initialArg, init) {
1186
1267
  const { prop: controlledState, defaultProp, onChange: onChangeProp, caller } = userArgs;
@@ -1239,12 +1320,12 @@ function useControllableStateReducer(reducer, userArgs, initialArg, init) {
1239
1320
  ]);
1240
1321
  return [state, dispatch];
1241
1322
  }
1242
- __name$18(useControllableStateReducer, "useControllableStateReducer");
1323
+ __name$17(useControllableStateReducer, "useControllableStateReducer");
1243
1324
 
1244
1325
  //#endregion
1245
1326
  //#region ../../node_modules/.pnpm/@radix-ui+react-use-size@1.1.4_@types+react@19.2.17_react@19.2.8/node_modules/@radix-ui/react-use-size/dist/index.mjs
1246
- var __defProp$17 = Object.defineProperty;
1247
- var __name$17 = (target, value) => __defProp$17(target, "name", {
1327
+ var __defProp$16 = Object.defineProperty;
1328
+ var __name$16 = (target, value) => __defProp$16(target, "name", {
1248
1329
  value,
1249
1330
  configurable: true
1250
1331
  });
@@ -1282,12 +1363,12 @@ function useSize(element) {
1282
1363
  }, [element]);
1283
1364
  return size;
1284
1365
  }
1285
- __name$17(useSize, "useSize");
1366
+ __name$16(useSize, "useSize");
1286
1367
 
1287
1368
  //#endregion
1288
1369
  //#region ../../node_modules/.pnpm/@radix-ui+react-presence@1.1.10_@types+react-dom@19.2.3_@types+react@19.2.17__@types+re_138587ba593102bdcf335a5673d92068/node_modules/@radix-ui/react-presence/dist/index.mjs
1289
- var __defProp$16 = Object.defineProperty;
1290
- var __name$16 = (target, value) => __defProp$16(target, "name", {
1370
+ var __defProp$15 = Object.defineProperty;
1371
+ var __name$15 = (target, value) => __defProp$15(target, "name", {
1291
1372
  value,
1292
1373
  configurable: true
1293
1374
  });
@@ -1296,8 +1377,8 @@ function useStateMachine(initialState, machine) {
1296
1377
  return machine[state][event] ?? state;
1297
1378
  }, initialState);
1298
1379
  }
1299
- __name$16(useStateMachine, "useStateMachine");
1300
- var Presence = /* @__PURE__ */ __name$16((props) => {
1380
+ __name$15(useStateMachine, "useStateMachine");
1381
+ var Presence = /* @__PURE__ */ __name$15((props) => {
1301
1382
  const { present, children } = props;
1302
1383
  const presence = usePresence$1(present);
1303
1384
  const child = typeof children === "function" ? children({ present: presence.isPresent }) : React$1.Children.only(children);
@@ -1346,7 +1427,7 @@ function usePresence$1(present) {
1346
1427
  if (node) {
1347
1428
  let timeoutId;
1348
1429
  const ownerWindow = node.ownerDocument.defaultView ?? window;
1349
- const handleAnimationEnd = /* @__PURE__ */ __name$16((event) => {
1430
+ const handleAnimationEnd = /* @__PURE__ */ __name$15((event) => {
1350
1431
  const isCurrentAnimation = getAnimationName(stylesRef.current).includes(CSS.escape(event.animationName));
1351
1432
  if (event.target === node && isCurrentAnimation) {
1352
1433
  send("ANIMATION_END");
@@ -1359,7 +1440,7 @@ function usePresence$1(present) {
1359
1440
  }
1360
1441
  }
1361
1442
  }, "handleAnimationEnd");
1362
- const handleAnimationStart = /* @__PURE__ */ __name$16((event) => {
1443
+ const handleAnimationStart = /* @__PURE__ */ __name$15((event) => {
1363
1444
  if (event.target === node) prevAnimationNameRef.current = getAnimationName(stylesRef.current);
1364
1445
  }, "handleAnimationStart");
1365
1446
  node.addEventListener("animationstart", handleAnimationStart);
@@ -1385,12 +1466,12 @@ function usePresence$1(present) {
1385
1466
  }, [])
1386
1467
  };
1387
1468
  }
1388
- __name$16(usePresence$1, "usePresence");
1469
+ __name$15(usePresence$1, "usePresence");
1389
1470
  function setRef$1(ref, value) {
1390
1471
  if (typeof ref === "function") return ref(value);
1391
1472
  else if (ref !== null && ref !== void 0) ref.current = value;
1392
1473
  }
1393
- __name$16(setRef$1, "setRef");
1474
+ __name$15(setRef$1, "setRef");
1394
1475
  function useStableComposedRefs(...refs) {
1395
1476
  const refsRef = React$1.useRef(refs);
1396
1477
  refsRef.current = refs;
@@ -1411,11 +1492,11 @@ function useStableComposedRefs(...refs) {
1411
1492
  };
1412
1493
  }, []);
1413
1494
  }
1414
- __name$16(useStableComposedRefs, "useStableComposedRefs");
1495
+ __name$15(useStableComposedRefs, "useStableComposedRefs");
1415
1496
  function getAnimationName(styles) {
1416
1497
  return styles?.animationName || "none";
1417
1498
  }
1418
- __name$16(getAnimationName, "getAnimationName");
1499
+ __name$15(getAnimationName, "getAnimationName");
1419
1500
  function getElementRef$1(element) {
1420
1501
  let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
1421
1502
  let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
@@ -1425,12 +1506,12 @@ function getElementRef$1(element) {
1425
1506
  if (mayWarn) return element.props.ref;
1426
1507
  return element.props.ref || element.ref;
1427
1508
  }
1428
- __name$16(getElementRef$1, "getElementRef");
1509
+ __name$15(getElementRef$1, "getElementRef");
1429
1510
 
1430
1511
  //#endregion
1431
1512
  //#region ../../node_modules/.pnpm/@radix-ui+react-slot@1.3.3_@types+react@19.2.17_react@19.2.8/node_modules/@radix-ui/react-slot/dist/index.mjs
1432
- var __defProp$15 = Object.defineProperty;
1433
- var __name$15 = (target, value) => __defProp$15(target, "name", {
1513
+ var __defProp$14 = Object.defineProperty;
1514
+ var __name$14 = (target, value) => __defProp$14(target, "name", {
1434
1515
  value,
1435
1516
  configurable: true
1436
1517
  });
@@ -1467,17 +1548,17 @@ function createSlot(ownerName) {
1467
1548
  Slot2.displayName = `${ownerName}.Slot`;
1468
1549
  return Slot2;
1469
1550
  }
1470
- __name$15(createSlot, "createSlot");
1551
+ __name$14(createSlot, "createSlot");
1471
1552
  var SLOTTABLE_IDENTIFIER = Symbol.for("radix.slottable");
1472
1553
  // @__NO_SIDE_EFFECTS__
1473
1554
  function createSlottable(ownerName) {
1474
- const Slottable2 = /* @__PURE__ */ __name$15((props) => "child" in props ? props.children(props.child) : props.children, "Slottable");
1555
+ const Slottable2 = /* @__PURE__ */ __name$14((props) => "child" in props ? props.children(props.child) : props.children, "Slottable");
1475
1556
  Slottable2.displayName = `${ownerName}.Slottable`;
1476
1557
  Slottable2.__radixId = SLOTTABLE_IDENTIFIER;
1477
1558
  return Slottable2;
1478
1559
  }
1479
- __name$15(createSlottable, "createSlottable");
1480
- var getSlottableElementFromSlottable = /* @__PURE__ */ __name$15((slottable, child) => {
1560
+ __name$14(createSlottable, "createSlottable");
1561
+ var getSlottableElementFromSlottable = /* @__PURE__ */ __name$14((slottable, child) => {
1481
1562
  if ("child" in slottable.props) {
1482
1563
  const child2 = slottable.props.child;
1483
1564
  if (!React$1.isValidElement(child2)) return null;
@@ -1508,7 +1589,7 @@ function mergeProps(slotProps, childProps) {
1508
1589
  ...overrideProps
1509
1590
  };
1510
1591
  }
1511
- __name$15(mergeProps, "mergeProps");
1592
+ __name$14(mergeProps, "mergeProps");
1512
1593
  function getElementRef(element) {
1513
1594
  let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
1514
1595
  let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
@@ -1518,32 +1599,32 @@ function getElementRef(element) {
1518
1599
  if (mayWarn) return element.props.ref;
1519
1600
  return element.props.ref || element.ref;
1520
1601
  }
1521
- __name$15(getElementRef, "getElementRef");
1602
+ __name$14(getElementRef, "getElementRef");
1522
1603
  function isSlottable(child) {
1523
1604
  return React$1.isValidElement(child) && typeof child.type === "function" && "__radixId" in child.type && child.type.__radixId === SLOTTABLE_IDENTIFIER;
1524
1605
  }
1525
- __name$15(isSlottable, "isSlottable");
1606
+ __name$14(isSlottable, "isSlottable");
1526
1607
  var REACT_LAZY_TYPE = Symbol.for("react.lazy");
1527
1608
  function isLazyComponent(element) {
1528
1609
  return element != null && typeof element === "object" && "$$typeof" in element && element.$$typeof === REACT_LAZY_TYPE && "_payload" in element && isPromiseLike(element._payload);
1529
1610
  }
1530
- __name$15(isLazyComponent, "isLazyComponent");
1611
+ __name$14(isLazyComponent, "isLazyComponent");
1531
1612
  function isPromiseLike(value) {
1532
1613
  return typeof value === "object" && value !== null && "then" in value;
1533
1614
  }
1534
- __name$15(isPromiseLike, "isPromiseLike");
1535
- var createSlotError = /* @__PURE__ */ __name$15((ownerName) => {
1615
+ __name$14(isPromiseLike, "isPromiseLike");
1616
+ var createSlotError = /* @__PURE__ */ __name$14((ownerName) => {
1536
1617
  return `${ownerName} failed to slot onto its children. Expected a single React element child or \`Slottable\`.`;
1537
1618
  }, "createSlotError");
1538
- var createSlottableError = /* @__PURE__ */ __name$15((ownerName) => {
1619
+ var createSlottableError = /* @__PURE__ */ __name$14((ownerName) => {
1539
1620
  return `${ownerName} failed to slot onto its \`Slottable\`. Expected \`Slottable\` to receive a single React element child.`;
1540
1621
  }, "createSlottableError");
1541
1622
  var use = React$1[" use ".trim().toString()];
1542
1623
 
1543
1624
  //#endregion
1544
1625
  //#region ../../node_modules/.pnpm/@radix-ui+react-primitive@2.1.10_@types+react-dom@19.2.3_@types+react@19.2.17__@types+r_be17283a23f513d7b972453cc36e2a96/node_modules/@radix-ui/react-primitive/dist/index.mjs
1545
- var __defProp$14 = Object.defineProperty;
1546
- var __name$14 = (target, value) => __defProp$14(target, "name", {
1626
+ var __defProp$13 = Object.defineProperty;
1627
+ var __name$13 = (target, value) => __defProp$13(target, "name", {
1547
1628
  value,
1548
1629
  configurable: true
1549
1630
  });
@@ -1585,230 +1666,7 @@ var Primitive = [
1585
1666
  function dispatchDiscreteCustomEvent(target, event) {
1586
1667
  if (target) ReactDOM.flushSync(() => target.dispatchEvent(event));
1587
1668
  }
1588
- __name$14(dispatchDiscreteCustomEvent, "dispatchDiscreteCustomEvent");
1589
-
1590
- //#endregion
1591
- //#region ../../node_modules/.pnpm/@radix-ui+react-checkbox@1.3.11_@types+react-dom@19.2.3_@types+react@19.2.17__@types+re_f6e0f4835f2e28dbd2e5cb3844d005eb/node_modules/@radix-ui/react-checkbox/dist/index.mjs
1592
- var __defProp$13 = Object.defineProperty;
1593
- var __name$13 = (target, value) => __defProp$13(target, "name", {
1594
- value,
1595
- configurable: true
1596
- });
1597
- var CHECKBOX_NAME = "Checkbox";
1598
- var [createCheckboxContext, createCheckboxScope] = createContextScope(CHECKBOX_NAME);
1599
- var [CheckboxProviderImpl, useCheckboxContext] = createCheckboxContext(CHECKBOX_NAME);
1600
- function CheckboxProvider(props) {
1601
- const { __scopeCheckbox, checked: checkedProp, children, defaultChecked, disabled, form, name, onCheckedChange, required, value = "on", internal_do_not_use_render } = props;
1602
- const [checked, setChecked] = useControllableState({
1603
- prop: checkedProp,
1604
- defaultProp: defaultChecked ?? false,
1605
- onChange: onCheckedChange,
1606
- caller: CHECKBOX_NAME
1607
- });
1608
- const [control, setControl] = React$1.useState(null);
1609
- const [bubbleInput, setBubbleInput] = React$1.useState(null);
1610
- const hasConsumerStoppedPropagationRef = React$1.useRef(false);
1611
- const [userInteractionCount, onUserInteraction] = React$1.useReducer((count) => count + 1, 0);
1612
- const isFormControl = control ? !!form || !!control.closest("form") : true;
1613
- const context = {
1614
- checked,
1615
- disabled,
1616
- setChecked,
1617
- control,
1618
- setControl,
1619
- name,
1620
- form,
1621
- value,
1622
- hasConsumerStoppedPropagationRef,
1623
- userInteractionCount,
1624
- onUserInteraction,
1625
- required,
1626
- defaultChecked: isIndeterminate(defaultChecked) ? false : defaultChecked,
1627
- isFormControl,
1628
- bubbleInput,
1629
- setBubbleInput
1630
- };
1631
- return /* @__PURE__ */ jsx(CheckboxProviderImpl, {
1632
- scope: __scopeCheckbox,
1633
- ...context,
1634
- children: isFunction$1(internal_do_not_use_render) ? internal_do_not_use_render(context) : children
1635
- });
1636
- }
1637
- __name$13(CheckboxProvider, "CheckboxProvider");
1638
- var TRIGGER_NAME$3 = "CheckboxTrigger";
1639
- var CheckboxTrigger = /* @__PURE__ */ React$1.forwardRef(/* @__PURE__ */ __name$13(function CheckboxTrigger2({ __scopeCheckbox, onKeyDown, onClick, ...checkboxProps }, forwardedRef) {
1640
- const { control, value, disabled, checked, required, setControl, setChecked, hasConsumerStoppedPropagationRef, onUserInteraction, isFormControl, bubbleInput } = useCheckboxContext(TRIGGER_NAME$3, __scopeCheckbox);
1641
- const composedRefs = useComposedRefs$1(forwardedRef, setControl);
1642
- const initialCheckedStateRef = React$1.useRef(checked);
1643
- React$1.useEffect(() => {
1644
- const form = control?.form;
1645
- if (form) {
1646
- const reset = /* @__PURE__ */ __name$13(() => setChecked(initialCheckedStateRef.current), "reset");
1647
- form.addEventListener("reset", reset);
1648
- return () => form.removeEventListener("reset", reset);
1649
- }
1650
- }, [control, setChecked]);
1651
- return /* @__PURE__ */ jsx(Primitive.button, {
1652
- type: "button",
1653
- role: "checkbox",
1654
- "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
1655
- "aria-required": required,
1656
- "data-state": getState$3(checked),
1657
- "data-disabled": disabled ? "" : void 0,
1658
- disabled,
1659
- value,
1660
- ...checkboxProps,
1661
- ref: composedRefs,
1662
- onKeyDown: composeEventHandlers(onKeyDown, (event) => {
1663
- if (event.key === "Enter") event.preventDefault();
1664
- }),
1665
- onClick: composeEventHandlers(onClick, (event) => {
1666
- onUserInteraction();
1667
- setChecked((prevChecked) => isIndeterminate(prevChecked) ? true : !prevChecked);
1668
- if (bubbleInput && isFormControl) {
1669
- hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
1670
- if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation();
1671
- }
1672
- })
1673
- });
1674
- }, "CheckboxTrigger"));
1675
- var Checkbox$1 = /* @__PURE__ */ React$1.forwardRef(/* @__PURE__ */ __name$13(function Checkbox2(props, forwardedRef) {
1676
- const { __scopeCheckbox, name, checked, defaultChecked, required, disabled, value, onCheckedChange, form, ...checkboxProps } = props;
1677
- return /* @__PURE__ */ jsx(CheckboxProvider, {
1678
- __scopeCheckbox,
1679
- checked,
1680
- defaultChecked,
1681
- disabled,
1682
- required,
1683
- onCheckedChange,
1684
- name,
1685
- form,
1686
- value,
1687
- internal_do_not_use_render: ({ isFormControl }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(CheckboxTrigger, {
1688
- ...checkboxProps,
1689
- ref: forwardedRef,
1690
- __scopeCheckbox
1691
- }), isFormControl && /* @__PURE__ */ jsx(CheckboxBubbleInput, { __scopeCheckbox })] })
1692
- });
1693
- }, "Checkbox"));
1694
- var INDICATOR_NAME = "CheckboxIndicator";
1695
- var CheckboxIndicator = /* @__PURE__ */ React$1.forwardRef(/* @__PURE__ */ __name$13(function CheckboxIndicator2(props, forwardedRef) {
1696
- const { __scopeCheckbox, forceMount, ...indicatorProps } = props;
1697
- const context = useCheckboxContext(INDICATOR_NAME, __scopeCheckbox);
1698
- return /* @__PURE__ */ jsx(Presence, {
1699
- present: forceMount || isIndeterminate(context.checked) || context.checked === true,
1700
- children: /* @__PURE__ */ jsx(Primitive.span, {
1701
- "data-state": getState$3(context.checked),
1702
- "data-disabled": context.disabled ? "" : void 0,
1703
- ...indicatorProps,
1704
- ref: forwardedRef,
1705
- style: {
1706
- pointerEvents: "none",
1707
- ...props.style
1708
- }
1709
- })
1710
- });
1711
- }, "CheckboxIndicator"));
1712
- var BUBBLE_INPUT_NAME$1 = "CheckboxBubbleInput";
1713
- var CheckboxBubbleInput = /* @__PURE__ */ React$1.forwardRef(/* @__PURE__ */ __name$13(function CheckboxBubbleInput2({ __scopeCheckbox, onClick, ...props }, forwardedRef) {
1714
- const { control, hasConsumerStoppedPropagationRef, userInteractionCount, checked, defaultChecked, required, disabled, name, value, form, bubbleInput, setBubbleInput } = useCheckboxContext(BUBBLE_INPUT_NAME$1, __scopeCheckbox);
1715
- const composedRefs = useComposedRefs$1(forwardedRef, setBubbleInput);
1716
- const controlSize = useSize(control);
1717
- const shouldStopClickPropagationRef = React$1.useRef(false);
1718
- const prevCheckedRef = React$1.useRef(checked);
1719
- const prevUserInteractionCountRef = React$1.useRef(userInteractionCount);
1720
- React$1.useEffect(() => {
1721
- const input = bubbleInput;
1722
- if (!input) return;
1723
- const inputProto = window.HTMLInputElement.prototype;
1724
- const setChecked = Object.getOwnPropertyDescriptor(inputProto, "checked").set;
1725
- const isUserInteraction = userInteractionCount !== prevUserInteractionCountRef.current;
1726
- prevUserInteractionCountRef.current = userInteractionCount;
1727
- const checkedChanged = prevCheckedRef.current !== checked;
1728
- prevCheckedRef.current = checked;
1729
- const bubbles = !(isUserInteraction && hasConsumerStoppedPropagationRef.current);
1730
- if (checkedChanged && setChecked) {
1731
- shouldStopClickPropagationRef.current = !isUserInteraction;
1732
- const event = new Event("click", { bubbles });
1733
- input.indeterminate = isIndeterminate(checked);
1734
- setChecked.call(input, isIndeterminate(checked) ? false : checked);
1735
- input.dispatchEvent(event);
1736
- shouldStopClickPropagationRef.current = false;
1737
- }
1738
- }, [
1739
- bubbleInput,
1740
- checked,
1741
- hasConsumerStoppedPropagationRef,
1742
- userInteractionCount
1743
- ]);
1744
- const defaultCheckedRef = React$1.useRef(isIndeterminate(checked) ? false : checked);
1745
- return /* @__PURE__ */ jsx(Primitive.input, {
1746
- type: "checkbox",
1747
- "aria-hidden": true,
1748
- defaultChecked: defaultChecked ?? defaultCheckedRef.current,
1749
- required,
1750
- disabled,
1751
- name,
1752
- value,
1753
- form,
1754
- ...props,
1755
- tabIndex: -1,
1756
- ref: composedRefs,
1757
- onClick: composeEventHandlers(onClick, (event) => {
1758
- if (shouldStopClickPropagationRef.current) event.stopPropagation();
1759
- }),
1760
- style: {
1761
- ...props.style,
1762
- ...controlSize,
1763
- position: "absolute",
1764
- pointerEvents: "none",
1765
- opacity: 0,
1766
- margin: 0,
1767
- transform: "translateX(-100%)"
1768
- }
1769
- });
1770
- }, "CheckboxBubbleInput"));
1771
- function isFunction$1(value) {
1772
- return typeof value === "function";
1773
- }
1774
- __name$13(isFunction$1, "isFunction");
1775
- function isIndeterminate(checked) {
1776
- return checked === "indeterminate";
1777
- }
1778
- __name$13(isIndeterminate, "isIndeterminate");
1779
- function getState$3(checked) {
1780
- return isIndeterminate(checked) ? "indeterminate" : checked ? "checked" : "unchecked";
1781
- }
1782
- __name$13(getState$3, "getState");
1783
-
1784
- //#endregion
1785
- //#region ../ui-kit/src/components/Checkbox.tsx
1786
- /** Source-owned shadcn-style checkbox backed by Radix for keyboard semantics. */
1787
- function Checkbox({ className = "", invalid = false, "aria-invalid": ariaInvalid, ...props }) {
1788
- return /* @__PURE__ */ jsx(Checkbox$1, {
1789
- "aria-invalid": invalid ? true : ariaInvalid,
1790
- className: `inline-flex size-4 shrink-0 items-center justify-center rounded-sm border bg-surface shadow-xs outline-none transition-colors disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground ${invalid ? "border-destructive focus-visible:ring-destructive/20" : "border-input focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/20"} ${className}`,
1791
- ...props,
1792
- children: /* @__PURE__ */ jsx(CheckboxIndicator, {
1793
- className: "flex items-center justify-center",
1794
- children: /* @__PURE__ */ jsx(Check, {
1795
- className: "size-3",
1796
- "aria-hidden": true
1797
- })
1798
- })
1799
- });
1800
- }
1801
-
1802
- //#endregion
1803
- //#region ../ui-kit/src/components/Textarea.tsx
1804
- /** Source-owned textarea with the same form-control states as Input. */
1805
- function Textarea({ className = "", invalid = false, "aria-invalid": ariaInvalid, ...props }) {
1806
- return /* @__PURE__ */ jsx("textarea", {
1807
- "aria-invalid": invalid ? true : ariaInvalid,
1808
- className: `min-h-20 w-full resize-y rounded-md border bg-surface px-3 py-2 text-sm text-ink shadow-xs outline-none transition-colors placeholder:text-muted disabled:cursor-not-allowed disabled:opacity-50 ${invalid ? "border-destructive focus-visible:ring-destructive/20" : "border-input focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/20"} ${className}`,
1809
- ...props
1810
- });
1811
- }
1669
+ __name$13(dispatchDiscreteCustomEvent, "dispatchDiscreteCustomEvent");
1812
1670
 
1813
1671
  //#endregion
1814
1672
  //#region ../../node_modules/.pnpm/@radix-ui+react-switch@1.3.7_@types+react-dom@19.2.3_@types+react@19.2.17__@types+react_e96baf15833549650471eefa4ffd78d0/node_modules/@radix-ui/react-switch/dist/index.mjs
@@ -40690,6 +40548,10 @@ function defaultRuntimeConfig() {
40690
40548
  approvalScope: "once-per-run"
40691
40549
  },
40692
40550
  router: { strategy: "progressive" },
40551
+ hooks: {
40552
+ timeoutMs: 5e3,
40553
+ failOnHookError: false
40554
+ },
40693
40555
  streaming: true,
40694
40556
  renderResult: true,
40695
40557
  sandbox: {
@@ -40699,6 +40561,10 @@ function defaultRuntimeConfig() {
40699
40561
  readReference: true,
40700
40562
  writeArtifact: true,
40701
40563
  confirm: true
40564
+ },
40565
+ remoteUrl: {
40566
+ allowHttp: false,
40567
+ allowPrivateHosts: false
40702
40568
  }
40703
40569
  },
40704
40570
  llm: {
@@ -40719,6 +40585,7 @@ function mergeRuntimeConfigDefaults(partial) {
40719
40585
  loop: sub("loop", d.loop),
40720
40586
  interaction: sub("interaction", d.interaction),
40721
40587
  router: sub("router", d.router),
40588
+ hooks: sub("hooks", d.hooks),
40722
40589
  streaming: typeof p["streaming"] === "boolean" ? p["streaming"] : d.streaming,
40723
40590
  renderResult: typeof p["renderResult"] === "boolean" ? p["renderResult"] : d.renderResult,
40724
40591
  sandbox: {
@@ -40726,6 +40593,10 @@ function mergeRuntimeConfigDefaults(partial) {
40726
40593
  capabilities: {
40727
40594
  ...d.sandbox.capabilities,
40728
40595
  ...p["sandbox"]?.["capabilities"] ?? {}
40596
+ },
40597
+ remoteUrl: {
40598
+ ...d.sandbox.remoteUrl,
40599
+ ...p["sandbox"]?.["remoteUrl"] ?? {}
40729
40600
  }
40730
40601
  },
40731
40602
  llm: sub("llm", d.llm)
@@ -40747,8 +40618,36 @@ function withRuntimeConfigDefaults(store) {
40747
40618
  //#endregion
40748
40619
  //#region src/core/interactionBridge.ts
40749
40620
  /**
40621
+ * 渲染档 → 能力集。四档在 0.4.0 起 interaction/surface 全部等价,
40622
+ * 差别只剩「是否依赖 optional peer」。作为可注入值传入 CompositeUiBridge,
40623
+ * 便于宿主按实际装配情况覆盖(例如已确认某 peer 不可用)。
40624
+ * @experimental
40625
+ */
40626
+ const DEFAULT_RENDERER_CAPABILITIES = {
40627
+ native: {
40628
+ interaction: true,
40629
+ surface: true
40630
+ },
40631
+ a2ui: {
40632
+ interaction: true,
40633
+ surface: true,
40634
+ requiresPeer: "@a2ui/lit"
40635
+ },
40636
+ openui: {
40637
+ interaction: true,
40638
+ surface: true,
40639
+ requiresPeer: "@openuidev/react-lang"
40640
+ },
40641
+ vercel: {
40642
+ interaction: true,
40643
+ surface: true,
40644
+ requiresPeer: "@json-render/react"
40645
+ }
40646
+ };
40647
+ /**
40750
40648
  * 探测 A2UI Lit 渲染器是否可用(@a2ui/lit 为 optional peer,未安装时 import 失败)。
40751
40649
  * Appearance/设置区据此对 A2UI 档置灰;仅动态 import,不强依赖。
40650
+ * @experimental
40752
40651
  */
40753
40652
  async function probeA2uiAvailability() {
40754
40653
  try {
@@ -40763,6 +40662,7 @@ async function probeA2uiAvailability() {
40763
40662
  * 经 @lit/context 向 surface 子树注入 renderMarkdown(markdown-it + dompurify),
40764
40663
  * 消除 "[MarkdownDirective] can't render markdown" 降级。
40765
40664
  * 未安装时返回 false(宿主可据此保留产品化限制说明)。
40665
+ * @experimental
40766
40666
  */
40767
40667
  async function configureA2uiMarkdown(mount) {
40768
40668
  let deps;
@@ -40790,6 +40690,7 @@ async function configureA2uiMarkdown(mount) {
40790
40690
  /**
40791
40691
  * 探测 OpenUI 渲染器是否可用(@openuidev/react-lang 为 optional peer)。
40792
40692
  * Appearance/设置区据此对 OpenUI 档置灰;仅动态 import,不强依赖。
40693
+ * @experimental
40793
40694
  */
40794
40695
  async function probeOpenUiAvailability() {
40795
40696
  try {
@@ -40799,135 +40700,52 @@ async function probeOpenUiAvailability() {
40799
40700
  return false;
40800
40701
  }
40801
40702
  }
40802
- /**
40803
- * OpenUI 交互通道(core 层,不 import react):
40804
- * - request() 把 InteractionRequest 转成 openui-lang 文本并挂起,react 层
40805
- * (OpenUiInteraction)订阅 current 后动态加载 @openuidev/react-lang 渲染;
40806
- * - 动作事件经 handleAction → fromOpenUiAction(含 authorize Allow/Deny 语义)回传;
40807
- * - react 层初始化失败调 fail():挂起请求 reject(桥据此粘性降级 native)并记录原因;
40808
- * - attach/detach 标记渲染视图是否挂载(未挂载时桥直接降级 native,不悬挂请求)。
40809
- */
40810
- var OpenUiChannel = class {
40811
- #current;
40812
- #listeners = /* @__PURE__ */ new Set();
40813
- #attached = 0;
40814
- #failure;
40815
- /** React useSyncExternalStore 兼容订阅 */
40816
- subscribe = (listener) => {
40817
- this.#listeners.add(listener);
40818
- return () => this.#listeners.delete(listener);
40819
- };
40820
- get current() {
40821
- return this.#current?.session;
40822
- }
40823
- get isAttached() {
40824
- return this.#attached > 0;
40825
- }
40826
- /** react 层初始化失败原因(未安装 @openuidev/react-lang 等);记录后粘性生效 */
40827
- get failure() {
40828
- return this.#failure;
40829
- }
40830
- attach() {
40831
- this.#attached += 1;
40832
- }
40833
- detach() {
40834
- this.#attached = Math.max(0, this.#attached - 1);
40835
- }
40836
- request(input) {
40837
- if (this.#current) this.#settle({
40838
- id: this.#current.session.request.id,
40839
- cancelled: true
40840
- });
40841
- return new Promise((resolve, reject) => {
40842
- this.#current = {
40843
- session: {
40844
- request: input,
40845
- lang: toOpenUiLang(input)
40846
- },
40847
- resolve,
40848
- reject
40849
- };
40850
- this.#emit();
40851
- });
40852
- }
40853
- /** runtime 交互超时/取消:以 cancelled resolve 挂起的 request(防悬挂 + 残留) */
40854
- cancel(id) {
40855
- if (this.#current?.session.request.id === id) this.#settle({
40856
- id,
40857
- cancelled: true
40858
- });
40859
- }
40860
- /** react 层 OpenUI 动作回传(fromOpenUiAction:Allow → value:true;Deny/Cancel → cancelled:true) */
40861
- handleAction(action) {
40862
- if (!this.#current) return;
40863
- this.#settle(fromOpenUiAction(action));
40864
- }
40865
- /** react 层初始化失败:挂起请求 reject 并记录原因(桥读取后降级 native) */
40866
- fail(message) {
40867
- this.#failure = message;
40868
- const pending = this.#current;
40869
- this.#current = void 0;
40870
- this.#emit();
40871
- pending?.reject(new Error(message));
40872
- }
40873
- #settle(response) {
40874
- const pending = this.#current;
40875
- this.#current = void 0;
40876
- this.#emit();
40877
- pending?.resolve(response);
40878
- }
40879
- #emit() {
40880
- for (const listener of [...this.#listeners]) listener();
40881
- }
40703
+ /** 渲染档在告警文案里的显示名(面向用户,不用内部 kind 字面量) */
40704
+ const RENDERER_LABEL = {
40705
+ native: "native",
40706
+ a2ui: "A2UI",
40707
+ openui: "OpenUI",
40708
+ vercel: "json-render"
40882
40709
  };
40883
40710
  /**
40884
40711
  * 复合 UiBridge(P2/P3 渲染框架档):
40885
40712
  * - streamingText / renderResult 始终委托 ReactBridgeState(结果块数据源不变);
40886
40713
  * - 交互 request/cancel 按渲染档分发:native → ReactBridgeState(InteractionCard),
40887
- * a2uiLitRendererBridge(@a2ui/lit,容器由 Chatbot 提供),
40888
- * openui OpenUiChannel(@openuidev/react-lang Renderer react 层装配),
40889
- * vercel ReactBridgeState(payload 预览卡消费 bridge.pending,仅可取消);
40890
- * - 每次交互开始/结束发 interaction-requested/resolved 事件(UI 据此显隐 a2ui 容器);
40891
- * - a2ui/openui 初始化失败(optional peer 未安装等)降级 native + warning 事件,不阻断 run。
40714
+ * 其余三档SpecInteractionChannel(core 产出 catalog 节点树,react 层交给本档
40715
+ * 已有的 spec 渲染路径:A2uiSpecSurface / OpenUiSpecSurface / JsonRenderSpecSurface);
40716
+ * - 每次交互开始/结束发 interaction-requested/resolved 事件;
40717
+ * - native 档初始化失败(optional peer 未安装等)降级 native + warning 事件,不阻断 run。
40718
+ * @stable
40892
40719
  */
40893
40720
  var CompositeUiBridge = class {
40894
40721
  #deps;
40895
- #a2ui;
40896
- /** a2ui 失败/无容器后粘性降级 native(同一引擎内不逐请求重复告警) */
40722
+ #capabilities;
40723
+ /** native 档失败/未挂载后粘性降级 native(同一引擎内不逐请求重复告警) */
40897
40724
  #downgraded = false;
40898
40725
  constructor(deps) {
40899
40726
  this.#deps = deps;
40727
+ this.#capabilities = deps.capabilities ?? DEFAULT_RENDERER_CAPABILITIES;
40900
40728
  }
40901
- /** 渲染档热切换:丢弃已建的 a2ui 桥与降级状态(新档立即生效,无需重装配 runtime) */
40729
+ /** 渲染档热切换:清降级状态(新档立即生效,无需重装配 runtime) */
40902
40730
  reset() {
40903
- this.#a2ui = void 0;
40904
40731
  this.#downgraded = false;
40905
40732
  }
40906
40733
  async request(input) {
40907
40734
  const renderer = this.#deps.getRenderer();
40908
- if (renderer === "a2ui" && !this.#downgraded) {
40909
- const bridge = this.#a2uiBridge();
40910
- if (bridge === void 0) this.#downgrade("The A2UI renderer is selected but its interaction container is not attached; falling back to native interaction cards");
40911
- else return this.#requestA2ui(bridge, input);
40912
- }
40913
- if (renderer === "openui" && !this.#downgraded) {
40914
- const channel = this.#deps.getOpenUiChannel();
40735
+ if (this.#inTier(renderer)) {
40736
+ const channel = this.#deps.getInteractionChannel();
40737
+ const label = RENDERER_LABEL[renderer];
40915
40738
  const failure = channel.failure;
40916
- if (failure !== void 0) this.#downgrade(`The OpenUI renderer failed to initialize (${failure}); falling back to native interaction cards`);
40917
- else if (!channel.isAttached) this.#downgrade("The OpenUI renderer is selected but its interaction view is not attached; falling back to native interaction cards");
40918
- else return this.#requestOpenUi(channel, input);
40739
+ if (failure !== void 0) this.#downgrade(`The ${label} renderer failed to initialize (${failure}); falling back to native interaction cards`);
40740
+ else if (!channel.isAttached) this.#downgrade(`The ${label} renderer is selected but its interaction view is not attached; falling back to native interaction cards`);
40741
+ else return this.#requestInTier(channel, label, input);
40919
40742
  }
40920
40743
  return this.#requestNative(input);
40921
40744
  }
40922
- /** runtime 交互超时/取消:按档委托(a2ui/openui cancel 会以 cancelled resolve 挂起的 request) */
40745
+ /** runtime 交互超时/取消:按档委托(通道 cancel 会以 cancelled resolve 挂起的 request) */
40923
40746
  cancel(id) {
40924
- const renderer = this.#deps.getRenderer();
40925
- if (renderer === "a2ui" && this.#a2ui && !this.#downgraded) {
40926
- this.#a2ui.bridge.cancel(id);
40927
- return;
40928
- }
40929
- if (renderer === "openui" && !this.#downgraded) {
40930
- this.#deps.getOpenUiChannel().cancel(id);
40747
+ if (this.#inTier(this.#deps.getRenderer())) {
40748
+ this.#deps.getInteractionChannel().cancel(id);
40931
40749
  return;
40932
40750
  }
40933
40751
  this.#deps.reactBridge.cancel(id);
@@ -40947,36 +40765,11 @@ var CompositeUiBridge = class {
40947
40765
  onTextDelta(runId, delta) {
40948
40766
  return this.#deps.reactBridge.onTextDelta(runId, delta);
40949
40767
  }
40950
- /** 懒建 a2ui 桥(容器元素变化时重建);未挂载返回 undefined */
40951
- #a2uiBridge() {
40952
- const mount = this.#deps.getInteractionMount();
40953
- if (!mount) return void 0;
40954
- if (!this.#a2ui || this.#a2ui.mount !== mount) this.#a2ui = {
40955
- mount,
40956
- bridge: new LitRendererBridge({ mount })
40957
- };
40958
- return this.#a2ui.bridge;
40959
- }
40960
- async #requestA2ui(bridge, input) {
40961
- this.#deps.emit({
40962
- type: "interaction-requested",
40963
- id: input.id,
40964
- requestType: input.type
40965
- });
40966
- try {
40967
- const response = await bridge.request(input);
40968
- this.#emitResolved(input, response);
40969
- return response;
40970
- } catch (e) {
40971
- this.#emitResolved(input, {
40972
- id: input.id,
40973
- cancelled: true
40974
- });
40975
- this.#downgrade(`The A2UI renderer failed to initialize (${messageOf(e)}); falling back to native interaction cards`);
40976
- return this.#requestNative(input);
40977
- }
40768
+ /** 本档能否自行渲染交互(能力表允许且未粘性降级) */
40769
+ #inTier(renderer) {
40770
+ return renderer !== "native" && this.#capabilities[renderer].interaction && !this.#downgraded;
40978
40771
  }
40979
- async #requestOpenUi(channel, input) {
40772
+ async #requestInTier(channel, label, input) {
40980
40773
  this.#deps.emit({
40981
40774
  type: "interaction-requested",
40982
40775
  id: input.id,
@@ -40991,7 +40784,7 @@ var CompositeUiBridge = class {
40991
40784
  id: input.id,
40992
40785
  cancelled: true
40993
40786
  });
40994
- this.#downgrade(`The OpenUI renderer failed to initialize (${messageOf(e)}); falling back to native interaction cards`);
40787
+ this.#downgrade(`The ${label} renderer failed to initialize (${messageOf(e)}); falling back to native interaction cards`);
40995
40788
  return this.#requestNative(input);
40996
40789
  }
40997
40790
  }
@@ -41056,7 +40849,7 @@ function createDemoLlm() {
41056
40849
  return reply ?? "";
41057
40850
  };
41058
40851
  return {
41059
- complete: async () => ({ content: nextReply() }),
40852
+ complete: async () => ({ content: textParts(nextReply()) }),
41060
40853
  async *stream() {
41061
40854
  const content = nextReply();
41062
40855
  const chunkSize = Math.max(1, Math.ceil(content.length / 3));
@@ -41103,6 +40896,7 @@ function createRuntimeLlm(config) {
41103
40896
  /**
41104
40897
  * 对话框引擎:装配 WebSkillRuntime + 会话持久化 + 事件分发。
41105
40898
  * llmConfig.load() 是异步的,runtime 在首次 send 前懒装配(#ensureReady)。
40899
+ * @stable
41106
40900
  */
41107
40901
  var ChatEngine = class {
41108
40902
  bridge;
@@ -41119,10 +40913,8 @@ var ChatEngine = class {
41119
40913
  #runSkills = /* @__PURE__ */ new Map();
41120
40914
  /** 当前渲染框架档(复合 uiBridge 分发;setRenderer 热切换) */
41121
40915
  #renderer;
41122
- /** a2ui 档交互容器(Chatbot ref 回调注入) */
41123
- #interactionMount;
41124
- /** openui 档交互通道(Chatbot 的 OpenUiInteraction attach 后生效) */
41125
- #openUiChannel = new OpenUiChannel();
40916
+ /** native 三档共用的交互通道(Chatbot SpecInteraction attach 后生效) */
40917
+ #interactionChannel = new SpecInteractionChannel();
41126
40918
  /** 装配时按 RuntimeConfig 应用(interaction 分发 + renderResult/streaming 透传 ReactBridgeState) */
41127
40919
  #uiBridge;
41128
40920
  /** RuntimeConfig.loop.maxHistoryMessages(装配时捕获,createSession 透传) */
@@ -41131,7 +40923,7 @@ var ChatEngine = class {
41131
40923
  #surfaceDraftWrites = /* @__PURE__ */ new Map();
41132
40924
  /** run trace 落盘(写失败降级 warn,不阻断对话) */
41133
40925
  #traceStore;
41134
- /** 会话落盘:本包内引用 `FsSessionStore` 的唯一处 */
40926
+ /** 会话落盘;缺省是本包内引用 `FsSessionStore` 的唯一处 */
41135
40927
  #sessions;
41136
40928
  constructor(adapter, options = {}) {
41137
40929
  this.#adapter = adapter;
@@ -41141,7 +40933,7 @@ var ChatEngine = class {
41141
40933
  root: `${this.#chatRoot}/traces`,
41142
40934
  fs: adapter.storage
41143
40935
  });
41144
- this.#sessions = new FsSessionStore({
40936
+ this.#sessions = options.sessionStore ?? new FsSessionStore({
41145
40937
  root: `${this.#chatRoot}/sessions`,
41146
40938
  fs: adapter.storage
41147
40939
  });
@@ -41159,8 +40951,7 @@ var ChatEngine = class {
41159
40951
  this.#uiBridge = new CompositeUiBridge({
41160
40952
  reactBridge: this.bridge,
41161
40953
  getRenderer: () => this.#renderer,
41162
- getInteractionMount: () => this.#interactionMount,
41163
- getOpenUiChannel: () => this.#openUiChannel,
40954
+ getInteractionChannel: () => this.#interactionChannel,
41164
40955
  emit: (event) => this.#emit(event)
41165
40956
  });
41166
40957
  }
@@ -41174,13 +40965,9 @@ var ChatEngine = class {
41174
40965
  this.#renderer = renderer;
41175
40966
  this.#uiBridge.reset();
41176
40967
  }
41177
- /** a2ui 档交互容器注入(Chatbot ref 回调;卸载传 null) */
41178
- setInteractionMount(el) {
41179
- this.#interactionMount = el ?? void 0;
41180
- }
41181
- /** openui 档交互通道(Chatbot 的 OpenUiInteraction 订阅/attach;core 只产出 lang 文本) */
41182
- get openUiChannel() {
41183
- return this.#openUiChannel;
40968
+ /** native 三档共用的交互通道(Chatbot SpecInteraction 订阅/attach;core 只产出 catalog 节点树) */
40969
+ get interactionChannel() {
40970
+ return this.#interactionChannel;
41184
40971
  }
41185
40972
  /** 探测 @a2ui/lit 是否安装(Appearance/设置区 A2UI 档置灰判定) */
41186
40973
  probeA2uiAvailability() {
@@ -41207,8 +40994,19 @@ var ChatEngine = class {
41207
40994
  reloadLlm() {
41208
40995
  this.reloadConfig();
41209
40996
  }
41210
- async listSessions() {
41211
- return (await this.#sessions.list({ includeArchived: true })).map(toSessionMeta);
40997
+ /**
40998
+ * 会话列表页。归档会话也返回:UI 自己分区展示。
40999
+ * `limit` 不给默认值——缺省属于 `SessionStore` 实现,在这里兜底就等于只下推了一半。
41000
+ */
41001
+ async listSessions(options = {}) {
41002
+ const page = await this.#sessions.list({
41003
+ includeArchived: true,
41004
+ ...options
41005
+ });
41006
+ return {
41007
+ items: page.items.map(toSessionMeta),
41008
+ ...page.nextCursor !== void 0 ? { nextCursor: page.nextCursor } : {}
41009
+ };
41212
41010
  }
41213
41011
  async createSession() {
41214
41012
  const session = await this.#sessions.create({ id: newId("session") });
@@ -41218,10 +41016,23 @@ var ChatEngine = class {
41218
41016
  createdAt: session.createdAt
41219
41017
  };
41220
41018
  }
41221
- async selectSession(id) {
41222
- const session = await this.#requireSession(id);
41019
+ /**
41020
+ * 选中会话并取**最新**一页历史(页内时间升序)。
41021
+ * 返回全量 `ChatMessage[]` 的旧签名已移除:长会话下它强迫每个调用方拿全量。
41022
+ */
41023
+ async selectSession(id, options = {}) {
41024
+ const page = await this.#sessions.listMessages(id, options);
41223
41025
  this.#currentSessionId = id;
41224
- return session.messages;
41026
+ return page;
41027
+ }
41028
+ /** 向历史方向再取一页;`cursor` 只能来自上一页的 `nextCursor` */
41029
+ async loadMoreMessages(cursor, options = {}) {
41030
+ const sessionId = this.#currentSessionId;
41031
+ if (!sessionId) throw new WebSkillError("VALIDATION_FAILED", "Cannot load more messages: no active session");
41032
+ return this.#sessions.listMessages(sessionId, {
41033
+ cursor,
41034
+ ...options
41035
+ });
41225
41036
  }
41226
41037
  async deleteSession(id) {
41227
41038
  await this.#sessions.delete(id);
@@ -41338,7 +41149,7 @@ var ChatEngine = class {
41338
41149
  cancel(runId) {
41339
41150
  return this.#runtime?.cancel(runId) ?? false;
41340
41151
  }
41341
- /** 列出可恢复的 interrupted run(InterruptedBanner 数据源) */
41152
+ /** 列出 interrupted run(InterruptedBanner 数据源);版本不受支持的项带 unsupported 标记 */
41342
41153
  async listInterrupted() {
41343
41154
  return this.#snapshotStore().list();
41344
41155
  }
@@ -41444,6 +41255,21 @@ var ChatEngine = class {
41444
41255
  return this.#wrappedRuntimeConfig;
41445
41256
  }
41446
41257
  #wrappedRuntimeConfig;
41258
+ /**
41259
+ * 治理 port → `WebSkillRuntimeDeps` 的逐字段透传(F1)。
41260
+ * 逐字段展开而不是整体 spread:`exactOptionalPropertyTypes` 下把 `undefined`
41261
+ * 显式传给可选字段与不传不等价,而「不传」才是关闭。
41262
+ */
41263
+ #governanceDeps() {
41264
+ const g = this.#options.governance;
41265
+ if (g === void 0) return {};
41266
+ return {
41267
+ ...g.skillStateGuard !== void 0 ? { skillStateGuard: g.skillStateGuard } : {},
41268
+ ...g.skillIntegrityGuard !== void 0 ? { skillIntegrityGuard: g.skillIntegrityGuard } : {},
41269
+ ...g.skillOutcomeReporter !== void 0 ? { skillOutcomeReporter: g.skillOutcomeReporter } : {},
41270
+ ...g.catalogFilter !== void 0 ? { catalogFilter: g.catalogFilter } : {}
41271
+ };
41272
+ }
41447
41273
  async #assemble() {
41448
41274
  const fs = this.#adapter.storage;
41449
41275
  const rc = await this.#runtimeConfigStore()?.load();
@@ -41482,8 +41308,10 @@ var ChatEngine = class {
41482
41308
  root: `${this.#chatRoot}/memory`,
41483
41309
  fs
41484
41310
  }),
41311
+ ...this.#options.hooks ? { hooks: this.#applyHooksConfig(this.#options.hooks, rc) } : {},
41485
41312
  externalTools: [...pageSkillSource ? [pageSkillSource] : [], ...this.#options.generativeUi ? [createUiCatalogToolSource()] : []],
41486
41313
  skillProviders: pageSkillSource ? [pageSkillSource] : [],
41314
+ ...this.#governanceDeps(),
41487
41315
  ...Object.keys(loopConfig).length > 0 ? { config: loopConfig } : {},
41488
41316
  ...model ? { model } : {}
41489
41317
  });
@@ -41495,33 +41323,26 @@ var ChatEngine = class {
41495
41323
  runId: event.runId
41496
41324
  });
41497
41325
  }
41498
- if (event.data?.["type"] !== "tool") this.#emit({
41326
+ const toolData = event.phase === "execute" && event.data.kind === "tool" ? event.data : void 0;
41327
+ if (!toolData) this.#emit({
41499
41328
  type: "lifecycle",
41500
41329
  runId: event.runId,
41501
- phase: event.phase,
41502
41330
  at: Date.parse(event.ts),
41331
+ phase: event.phase,
41503
41332
  ...event.data ? { data: event.data } : {}
41504
41333
  });
41505
41334
  if (event.phase === "activate") {
41506
- const skillName = event.data?.["skillName"];
41507
- if (typeof skillName === "string") {
41508
- const skills = this.#runSkills.get(event.runId) ?? /* @__PURE__ */ new Set();
41509
- skills.add(skillName);
41510
- this.#runSkills.set(event.runId, skills);
41511
- this.#emit({
41512
- type: "skill-activated",
41513
- runId: event.runId,
41514
- skills: [...skills].sort()
41515
- });
41516
- }
41517
- } else if (event.phase === "execute") {
41518
- const data = event.data;
41519
- if (data?.["type"] !== "tool") return;
41520
- const status = data["status"];
41521
- const name = data["name"];
41522
- const callId = data["callId"];
41523
- if (typeof name !== "string" || typeof callId !== "string") return;
41524
- const args = typeof data["args"] === "string" ? { args: data["args"] } : {};
41335
+ const skills = this.#runSkills.get(event.runId) ?? /* @__PURE__ */ new Set();
41336
+ skills.add(event.data.skillName);
41337
+ this.#runSkills.set(event.runId, skills);
41338
+ this.#emit({
41339
+ type: "skill-activated",
41340
+ runId: event.runId,
41341
+ skills: [...skills].sort()
41342
+ });
41343
+ } else if (toolData) {
41344
+ const { status, callId, name } = toolData;
41345
+ const args = toolData.args === "" ? {} : { args: toolData.args };
41525
41346
  if (status === "started") this.#emit({
41526
41347
  type: "tool-started",
41527
41348
  runId: event.runId,
@@ -41529,7 +41350,7 @@ var ChatEngine = class {
41529
41350
  name,
41530
41351
  ...args
41531
41352
  });
41532
- else if (status === "completed" || status === "failed") this.#emit({
41353
+ else this.#emit({
41533
41354
  type: status === "completed" ? "tool-completed" : "tool-failed",
41534
41355
  runId: event.runId,
41535
41356
  callId,
@@ -41581,6 +41402,14 @@ var ChatEngine = class {
41581
41402
  fs: this.#adapter.storage
41582
41403
  });
41583
41404
  }
41405
+ /** 钩子执行策略来自 console 编辑的 RuntimeConfig;钩子本身由宿主注册,UI 不碰函数 */
41406
+ #applyHooksConfig(hooks, rc) {
41407
+ if (rc) {
41408
+ hooks.timeoutMs = rc.hooks.timeoutMs;
41409
+ hooks.failOnHookError = rc.hooks.failOnHookError;
41410
+ }
41411
+ return hooks;
41412
+ }
41584
41413
  /** 每个 session 一个 runtime session 句柄(跨 run 历史延续),Map 缓存 */
41585
41414
  #sessionHandle(runtime, sessionId) {
41586
41415
  let handle = this.#handles.get(sessionId);
@@ -41606,6 +41435,7 @@ var ChatEngine = class {
41606
41435
  * chatbot 双语字典:全部 UI 文案的单一来源(英文为主,zh 条目齐全)。
41607
41436
  * 特性区块(WelcomeScreen / SettingsDrawer 各节 / authorize 说明等)必须含
41608
41437
  * title + description 双语条目——"会说话的 UI"的文案底座。
41438
+ * @stable
41609
41439
  */
41610
41440
  const chatbotDictionary = defineDictionary({
41611
41441
  en: {
@@ -41618,6 +41448,14 @@ const chatbotDictionary = defineDictionary({
41618
41448
  "session.searchPlaceholder": "Search sessions…",
41619
41449
  "session.empty": "No conversations yet.",
41620
41450
  "session.delete": "Delete session: {title}",
41451
+ "session.rename": "Rename session: {title}",
41452
+ "session.renameInput": "New title for session: {title}",
41453
+ "session.archive": "Archive session: {title}",
41454
+ "session.unarchive": "Unarchive session: {title}",
41455
+ "session.archived": "Archived",
41456
+ "session.loadEarlier": "Load earlier sessions",
41457
+ "session.loading": "Loading…",
41458
+ "message.loadEarlier": "Load earlier messages",
41621
41459
  "welcome.title": "The official WebSkill SDK chat",
41622
41460
  "welcome.assistantTitle": "How can I help?",
41623
41461
  "welcome.description": "This chat is the reference implementation of the WebSkill SDK. Ask in natural language: the agent routes your request to installed skills, asks for missing details with native forms, and shows you every step of the run.",
@@ -41737,6 +41575,7 @@ const chatbotDictionary = defineDictionary({
41737
41575
  "vercel.preview.title": "Vercel AI SDK data contract",
41738
41576
  "vercel.preview.badge": "Preview",
41739
41577
  "vercel.preview.description": "This is the data contract for integrating the Vercel AI SDK — a payload preview, not a full runtime. The interaction renders as JSON instead of a form; cancel to end it.",
41578
+ "surface.legacy.placeholder": "Generative UI from an earlier version is no longer rendered.",
41740
41579
  "error.title": "Something went wrong",
41741
41580
  "error.suggestion": "Check the model configuration in Settings, or try again.",
41742
41581
  "error.dismiss": "Dismiss"
@@ -41751,6 +41590,14 @@ const chatbotDictionary = defineDictionary({
41751
41590
  "session.searchPlaceholder": "搜索会话…",
41752
41591
  "session.empty": "暂无会话。",
41753
41592
  "session.delete": "删除会话:{title}",
41593
+ "session.rename": "重命名会话:{title}",
41594
+ "session.renameInput": "会话新标题:{title}",
41595
+ "session.archive": "归档会话:{title}",
41596
+ "session.unarchive": "取消归档:{title}",
41597
+ "session.archived": "已归档",
41598
+ "session.loadEarlier": "加载更早的会话",
41599
+ "session.loading": "加载中…",
41600
+ "message.loadEarlier": "加载更早的消息",
41754
41601
  "welcome.title": "WebSkill SDK 官方对话框",
41755
41602
  "welcome.assistantTitle": "我可以帮你做什么?",
41756
41603
  "welcome.description": "本对话框是 WebSkill SDK 的官方参考实现。用自然语言提问:Agent 会把请求路由到已安装的技能,用原生表单补齐缺失信息,并实时展示运行的每一步。",
@@ -41870,23 +41717,18 @@ const chatbotDictionary = defineDictionary({
41870
41717
  "vercel.preview.title": "Vercel AI SDK 数据契约",
41871
41718
  "vercel.preview.badge": "预览",
41872
41719
  "vercel.preview.description": "这是接入 Vercel AI SDK 时的数据契约——payload 预览,非完整运行时。交互以 JSON 而非表单呈现;点击取消结束本次交互。",
41720
+ "surface.legacy.placeholder": "旧版本生成的界面已不再渲染。",
41873
41721
  "error.title": "出错了",
41874
41722
  "error.suggestion": "请检查设置中的模型配置,或重试。",
41875
41723
  "error.dismiss": "关闭"
41876
41724
  }
41877
41725
  });
41878
41726
  const i18n = createI18n(chatbotDictionary);
41879
- /** chatbot 组件取文案:t('welcome.title') / t('tool.summary.other', { count: 3 }) */
41727
+ /** chatbot 组件取文案:t('welcome.title') / t('tool.summary.other', { count: 3 }) @stable */
41880
41728
  const useT = i18n.useT;
41881
41729
 
41882
41730
  //#endregion
41883
41731
  //#region src/react/A2uiSurfaceHost.tsx
41884
- function usesBasicCatalog(snapshot) {
41885
- return snapshot.surface.kind === "metric" || snapshot.surface.kind === "file" && !snapshot.surface.actions?.length;
41886
- }
41887
- function specProps(snapshot) {
41888
- return snapshot.surface.props;
41889
- }
41890
41732
  /**
41891
41733
  * A2UI 回落原因(0.2.8 G2)。
41892
41734
  * 之前这里是裸 `catch {}`:缺 optional peer 与真实渲染崩溃表现完全一致——都是静默回落、
@@ -41905,17 +41747,20 @@ function fallbackReason(error) {
41905
41747
  return typeof code === "string" && code !== "" ? code : "a2ui-render-failed";
41906
41748
  }
41907
41749
  /**
41908
- * catalog 声明树经 BYOC catalog 的 Lit 元素渲染。
41750
+ * `a2ui` 档:catalog 声明树经 BYOC catalog 的 Lit 元素渲染。
41909
41751
  * 元素与协议里公布的 `catalog_definition` 派生自同一份 shape,因此这里
41910
41752
  * 不需要第二套映射;缺 optional peer 时回落到 native 渲染而不是留白。
41753
+ *
41754
+ * 交互请求(路径 A)与模型产出的 surface(路径 B)共用本组件——这是 0.4.0 B4
41755
+ * 「同一档下命中同一个渲染入口」的落点,`data-testid` 因此对两条路径一致。
41911
41756
  */
41912
- function A2uiSpecSurface({ snapshot, onAction }) {
41757
+ function A2uiSpecSurface({ spec, surfaceId, actions, onAction, registry, runId, draft, onDraftChange }) {
41913
41758
  const mountRef = useRef(null);
41914
41759
  const [fallback, setFallback] = useState();
41915
41760
  const emit = useEffectEvent((actionId, value) => {
41916
- const declared = ((snapshot.surface.kind === "custom" ? snapshot.surface.actions : void 0) ?? []).find((action) => action.id === actionId);
41761
+ const declared = (actions ?? []).find((action) => action.id === actionId);
41917
41762
  onAction?.({
41918
- surfaceId: snapshot.surface.id,
41763
+ surfaceId,
41919
41764
  actionId,
41920
41765
  intent: declared?.intent ?? "select",
41921
41766
  ...declared?.nonce ? { nonce: declared.nonce } : {},
@@ -41925,7 +41770,7 @@ function A2uiSpecSurface({ snapshot, onAction }) {
41925
41770
  useEffect(() => {
41926
41771
  let disposed = false;
41927
41772
  let surfaceElement;
41928
- const surfaceId = `webskill-spec-${snapshot.surface.id}`;
41773
+ const a2uiSurfaceId = `webskill-spec-${surfaceId}`;
41929
41774
  (async () => {
41930
41775
  try {
41931
41776
  const [{ MessageProcessor }, lit, catalog] = await Promise.all([
@@ -41936,10 +41781,11 @@ function A2uiSpecSurface({ snapshot, onAction }) {
41936
41781
  lit.A2uiSurface;
41937
41782
  const mount = mountRef.current;
41938
41783
  if (disposed || !mount) return;
41784
+ configureA2uiMarkdown(mount);
41939
41785
  const processor = new MessageProcessor([catalog, lit.basicCatalog], (action) => {
41940
41786
  const decoded = fromA2uiSpecAction(action);
41941
41787
  if (!decoded) return;
41942
- const values = processor.getClientDataModel("v0.9.1")?.surfaces?.[surfaceId]?.[A2UI_SPEC_FORM_PATH.slice(1)];
41788
+ const values = processor.getClientDataModel("v0.9.1")?.surfaces?.[a2uiSurfaceId]?.[A2UI_SPEC_FORM_PATH.slice(1)];
41943
41789
  emit(decoded.actionId, values ?? {});
41944
41790
  }, { version: "v0.9.1" });
41945
41791
  processor.onSurfaceCreated((surface) => {
@@ -41948,58 +41794,9 @@ function A2uiSpecSurface({ snapshot, onAction }) {
41948
41794
  surfaceElement.surface = surface;
41949
41795
  mount.replaceChildren(surfaceElement);
41950
41796
  });
41951
- processor.processMessages(toA2uiSpecMessages(uiCatalog, specProps(snapshot).spec, { surfaceId }));
41952
- } catch (error) {
41953
- reportA2uiFallback(snapshot.surface.id, "spec", error);
41954
- if (!disposed) setFallback(fallbackReason(error));
41955
- }
41956
- })();
41957
- return () => {
41958
- disposed = true;
41959
- surfaceElement?.remove();
41960
- };
41961
- }, [snapshot]);
41962
- if (fallback) {
41963
- const surface = snapshot.surface;
41964
- return /* @__PURE__ */ jsx("div", {
41965
- "data-testid": "a2ui-spec-surface",
41966
- "data-renderer": "native-fallback",
41967
- "data-fallback-reason": fallback,
41968
- children: /* @__PURE__ */ jsx(NativeSpecSurface, {
41969
- surfaceId: surface.id,
41970
- spec: specProps(snapshot).spec,
41971
- actions: surface.actions ?? [],
41972
- ...onAction ? { onAction } : {}
41973
- })
41974
- });
41975
- }
41976
- return /* @__PURE__ */ jsx("div", {
41977
- ref: mountRef,
41978
- "data-testid": "a2ui-spec-surface",
41979
- "data-webskill-provenance": "a2ui-catalog"
41980
- });
41981
- }
41982
- function A2uiStandardSurface({ snapshot, registry }) {
41983
- const mountRef = useRef(null);
41984
- const [fallback, setFallback] = useState();
41985
- useEffect(() => {
41986
- let disposed = false;
41987
- let surfaceElement;
41988
- (async () => {
41989
- try {
41990
- const [{ MessageProcessor }, { A2uiSurface, basicCatalog }] = await Promise.all([import("@a2ui/web_core/v0_9"), import("@a2ui/lit/v0_9")]);
41991
- const mount = mountRef.current;
41992
- if (disposed || !mount) return;
41993
- const processor = new MessageProcessor([basicCatalog], () => void 0, { version: "v0.9.1" });
41994
- processor.onSurfaceCreated((surface) => {
41995
- if (disposed) return;
41996
- surfaceElement = mount.ownerDocument.createElement("a2ui-surface");
41997
- surfaceElement.surface = surface;
41998
- mount.replaceChildren(surfaceElement);
41999
- });
42000
- processor.processMessages(toA2uiSurfaceMessages(snapshot));
41797
+ processor.processMessages(toA2uiSpecMessages(uiCatalog, spec, { surfaceId: a2uiSurfaceId }));
42001
41798
  } catch (error) {
42002
- reportA2uiFallback(snapshot.surface.id, "standard", error);
41799
+ reportA2uiFallback(surfaceId, "spec", error);
42003
41800
  if (!disposed) setFallback(fallbackReason(error));
42004
41801
  }
42005
41802
  })();
@@ -42007,65 +41804,52 @@ function A2uiStandardSurface({ snapshot, registry }) {
42007
41804
  disposed = true;
42008
41805
  surfaceElement?.remove();
42009
41806
  };
42010
- }, [snapshot]);
41807
+ }, [spec, surfaceId]);
42011
41808
  if (fallback) return /* @__PURE__ */ jsx("div", {
42012
- "data-testid": "a2ui-standard-surface",
41809
+ "data-testid": "a2ui-spec-surface",
42013
41810
  "data-renderer": "native-fallback",
42014
41811
  "data-fallback-reason": fallback,
42015
- children: /* @__PURE__ */ jsx(UiSurfaceSnapshotList, {
42016
- snapshots: [snapshot],
42017
- ...registry ? { registry } : {}
41812
+ children: /* @__PURE__ */ jsx(NativeSpecSurface, {
41813
+ surfaceId,
41814
+ spec,
41815
+ actions: actions ?? [],
41816
+ ...registry ? { registry } : {},
41817
+ ...runId ? { runId } : {},
41818
+ ...draft ? { draft } : {},
41819
+ ...onAction ? { onAction } : {},
41820
+ ...onDraftChange ? { onDraftChange } : {}
42018
41821
  })
42019
41822
  });
42020
41823
  return /* @__PURE__ */ jsx("div", {
42021
41824
  ref: mountRef,
42022
- "data-testid": "a2ui-standard-surface",
42023
- "data-webskill-provenance": "a2ui-standard"
41825
+ "data-testid": "a2ui-spec-surface",
41826
+ "data-webskill-provenance": "a2ui-catalog"
42024
41827
  });
42025
41828
  }
42026
- /** Renders persisted A2UI Basic Catalog surfaces and controlled WebSkill extensions without a live bridge. @experimental */
41829
+ /** Renders persisted WebSkill UI spec snapshots through the A2UI BYOC catalog. @experimental */
42027
41830
  function A2uiSurfaceSnapshotHost({ snapshots, registry, onAction, drafts, onDraftChange }) {
42028
- const specSnapshots = snapshots.filter((snapshot) => isUiSpecSurface(snapshot.surface));
42029
- const rest = snapshots.filter((snapshot) => !isUiSpecSurface(snapshot.surface));
42030
- const standardSnapshots = rest.filter(usesBasicCatalog);
42031
- const extensionSnapshots = rest.filter((snapshot) => !usesBasicCatalog(snapshot));
42032
41831
  if (snapshots.length === 0) return null;
42033
- return /* @__PURE__ */ jsxs("div", {
41832
+ return /* @__PURE__ */ jsx("div", {
42034
41833
  "data-testid": "a2ui-surface-host",
42035
- children: [
42036
- specSnapshots.map((snapshot) => /* @__PURE__ */ jsx(A2uiSpecSurface, {
42037
- snapshot,
42038
- onAction
42039
- }, snapshot.surface.id)),
42040
- standardSnapshots.map((snapshot) => /* @__PURE__ */ jsx(A2uiStandardSurface, {
42041
- snapshot,
42042
- ...registry ? { registry } : {}
42043
- }, snapshot.surface.id)),
42044
- extensionSnapshots.length > 0 ? /* @__PURE__ */ jsxs("div", {
42045
- "data-testid": "a2ui-surface-extension",
42046
- "data-webskill-provenance": "a2ui-extension",
42047
- children: [/* @__PURE__ */ jsx("span", {
42048
- className: "sr-only",
42049
- children: "WebSkill extension"
42050
- }), /* @__PURE__ */ jsx(UiSurfaceSnapshotList, {
42051
- snapshots: extensionSnapshots,
42052
- ...registry ? { registry } : {},
42053
- ...onAction ? { onAction } : {},
42054
- ...drafts ? { drafts } : {},
42055
- ...onDraftChange ? { onDraftChange } : {}
42056
- })]
42057
- }) : null
42058
- ]
41834
+ children: snapshots.map((snapshot) => /* @__PURE__ */ jsx(A2uiSpecSurface, {
41835
+ surfaceId: snapshot.id,
41836
+ spec: snapshot.node,
41837
+ actions: snapshot.actions ?? [],
41838
+ registry,
41839
+ onAction,
41840
+ runId: snapshot.runId,
41841
+ draft: drafts?.[snapshot.id],
41842
+ onDraftChange
41843
+ }, snapshot.id))
42059
41844
  });
42060
41845
  }
42061
- /** Renders A2UI Basic Catalog surfaces and controlled WebSkill extensions from live bridge snapshots. @experimental */
41846
+ /** Renders WebSkill UI spec snapshots from live bridge state through the A2UI BYOC catalog. @experimental */
42062
41847
  function A2uiSurfaceHost({ bridge, runId, registry }) {
42063
41848
  const snapshots = useSyncExternalStore(bridge.subscribe, () => bridge.surfaceSnapshots);
42064
41849
  const visibleSnapshots = runId === void 0 ? snapshots : snapshots.filter((snapshot) => snapshot.runId === runId);
42065
- const actionableSnapshots = visibleSnapshots.filter((snapshot) => isUiSpecSurface(snapshot.surface) || !usesBasicCatalog(snapshot));
42066
41850
  const handleAction = (event) => {
42067
- const snapshot = actionableSnapshots.find((candidate) => candidate.surface.id === event.surfaceId);
42068
- const action = snapshot && "actions" in snapshot.surface ? snapshot.surface.actions?.find((candidate) => candidate.id === event.actionId) : void 0;
41851
+ const snapshot = visibleSnapshots.find((candidate) => candidate.id === event.surfaceId);
41852
+ const action = snapshot?.actions?.find((candidate) => candidate.id === event.actionId);
42069
41853
  if (!snapshot || !action) return;
42070
41854
  const decoded = fromA2uiSurfaceAction(toA2uiSurfaceAction(snapshot, action, event.value));
42071
41855
  if (!decoded?.runId || !decoded.nonce) return;
@@ -42246,7 +42030,7 @@ function lifecyclePart(step) {
42246
42030
  phase: step.phase,
42247
42031
  at: step.at,
42248
42032
  ...step.endedAt !== void 0 ? { endedAt: step.endedAt } : {},
42249
- ...step.data ? { detail: step.data } : {}
42033
+ ...step.note !== void 0 ? { note: step.note } : {}
42250
42034
  }
42251
42035
  };
42252
42036
  }
@@ -42441,7 +42225,7 @@ function useWebSkillAui({ messages, live, sessions, currentSessionId, sessionsLo
42441
42225
  //#region src/react/AssistantUiShell.tsx
42442
42226
  /**
42443
42227
  * assistant-ui only owns the React thread primitives. WebSkill remains the
42444
- * source of truth for messages, sessions, Runtime actions, and UiSurface data.
42228
+ * source of truth for messages, sessions, Runtime actions, and UI spec surface data.
42445
42229
  */
42446
42230
  function AssistantUiShellProvider({ children, ...props }) {
42447
42231
  return /* @__PURE__ */ jsx(AuiProvider, {
@@ -42452,15 +42236,23 @@ function AssistantUiShellProvider({ children, ...props }) {
42452
42236
  children: /* @__PURE__ */ jsx(ThreadPrimitive.ViewportProvider, { children })
42453
42237
  });
42454
42238
  }
42455
- function AssistantUiMessageList({ messages, renderMessage }) {
42239
+ function AssistantUiMessageList({ messages, earlier, renderMessage }) {
42240
+ const t = useT();
42456
42241
  const byId = useMemo(() => new Map(messages.map((message) => [message.id, message])), [messages]);
42457
- return /* @__PURE__ */ jsx(ThreadPrimitive.Root, {
42242
+ return /* @__PURE__ */ jsxs(ThreadPrimitive.Root, {
42458
42243
  "data-testid": "assistant-ui-thread",
42459
42244
  className: "flex w-full min-w-0 flex-col gap-4",
42460
- children: /* @__PURE__ */ jsx(ThreadPrimitive.Messages, { children: ({ message }) => /* @__PURE__ */ jsx(MessagePrimitive.Root, {
42245
+ children: [earlier ? /* @__PURE__ */ jsx("button", {
42246
+ type: "button",
42247
+ "data-testid": "load-earlier-messages",
42248
+ disabled: earlier.loading,
42249
+ onClick: earlier.onLoad,
42250
+ className: "self-center rounded-md border border-border px-3 py-1.5 text-sm text-muted transition-colors hover:bg-subtle hover:text-ink disabled:opacity-60",
42251
+ children: earlier.loading ? t("session.loading") : t("message.loadEarlier")
42252
+ }) : null, /* @__PURE__ */ jsx(ThreadPrimitive.Messages, { children: ({ message }) => /* @__PURE__ */ jsx(MessagePrimitive.Root, {
42461
42253
  "data-webskill-message-role": message.role,
42462
42254
  children: renderMessage(byId.get(message.id))
42463
- }) })
42255
+ }) })]
42464
42256
  });
42465
42257
  }
42466
42258
  /** Uses assistant-ui's scroll and accessibility viewport for the controlled external thread. */
@@ -42550,12 +42342,85 @@ function AssistantUiComposer({ running, disabled = false, placeholder, attachmen
42550
42342
  })
42551
42343
  });
42552
42344
  }
42345
+ /**
42346
+ * 一行会话。归档区与常规区共用:两边只差 archive/unarchive 一个按钮,
42347
+ * 各写一份迟早会漂。重命名走 `aui.threads.item()`——assistant-ui 没有 Rename primitive,
42348
+ * 但 threads 客户端有 `rename` 方法(ChatEngine.renameSession 的入口)。
42349
+ */
42350
+ function SessionRow({ id, title, active, archived, renaming, onNavigate, onStartRename, onEndRename }) {
42351
+ const t = useT();
42352
+ const aui = useAui();
42353
+ const iconButton = "inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100 hover:bg-subtle hover:text-ink";
42354
+ const commitRename = (next) => {
42355
+ const trimmed = next.trim();
42356
+ if (trimmed !== "" && trimmed !== title) aui.threads.item({ id }).rename(trimmed);
42357
+ onEndRename();
42358
+ };
42359
+ return /* @__PURE__ */ jsxs(ThreadListItemPrimitive.Root, {
42360
+ role: "listitem",
42361
+ "data-webskill-session-archived": archived ? "true" : void 0,
42362
+ className: "group flex items-center gap-1",
42363
+ children: [renaming ? /* @__PURE__ */ jsx("input", {
42364
+ autoFocus: true,
42365
+ "aria-label": t("session.renameInput", { title }),
42366
+ defaultValue: title,
42367
+ onBlur: (event) => commitRename(event.target.value),
42368
+ onKeyDown: (event) => {
42369
+ if (event.key === "Enter") commitRename(event.currentTarget.value);
42370
+ if (event.key === "Escape") onEndRename();
42371
+ },
42372
+ className: "min-w-0 flex-1 rounded-md border border-input bg-background px-2.5 py-2 text-sm text-ink outline-none focus:border-ring"
42373
+ }) : /* @__PURE__ */ jsx(ThreadListItemPrimitive.Trigger, {
42374
+ "data-webskill-thread-id": id,
42375
+ "aria-current": active ? "page" : void 0,
42376
+ onClick: onNavigate,
42377
+ className: `min-w-0 flex-1 truncate rounded-md px-2.5 py-2 text-left text-sm transition-colors ${active ? "bg-subtle font-medium text-ink" : "text-muted hover:bg-subtle hover:text-ink"}`,
42378
+ children: /* @__PURE__ */ jsx(ThreadListItemPrimitive.Title, { fallback: id })
42379
+ }), renaming ? null : /* @__PURE__ */ jsxs(Fragment$1, { children: [
42380
+ /* @__PURE__ */ jsx("button", {
42381
+ type: "button",
42382
+ "aria-label": t("session.rename", { title }),
42383
+ onClick: onStartRename,
42384
+ className: iconButton,
42385
+ children: /* @__PURE__ */ jsx(Pencil, {
42386
+ className: "size-3.5",
42387
+ "aria-hidden": true
42388
+ })
42389
+ }),
42390
+ archived ? /* @__PURE__ */ jsx(ThreadListItemPrimitive.Unarchive, {
42391
+ "aria-label": t("session.unarchive", { title }),
42392
+ className: iconButton,
42393
+ children: /* @__PURE__ */ jsx(ArchiveRestore, {
42394
+ className: "size-3.5",
42395
+ "aria-hidden": true
42396
+ })
42397
+ }) : /* @__PURE__ */ jsx(ThreadListItemPrimitive.Archive, {
42398
+ "aria-label": t("session.archive", { title }),
42399
+ className: iconButton,
42400
+ children: /* @__PURE__ */ jsx(Archive, {
42401
+ className: "size-3.5",
42402
+ "aria-hidden": true
42403
+ })
42404
+ }),
42405
+ /* @__PURE__ */ jsx(ThreadListItemPrimitive.Delete, {
42406
+ "aria-label": t("session.delete", { title }),
42407
+ className: `${iconButton} hover:bg-danger-soft hover:text-danger`,
42408
+ children: /* @__PURE__ */ jsx(Trash2, {
42409
+ className: "size-3.5",
42410
+ "aria-hidden": true
42411
+ })
42412
+ })
42413
+ ] })]
42414
+ });
42415
+ }
42553
42416
  /** Sessions are read through the assistant-ui threads client, which ChatEngine drives. */
42554
- function AssistantUiSessionList({ className = "", onNavigate }) {
42417
+ function AssistantUiSessionList({ className = "", onNavigate, hasEarlier = false, loadingEarlier = false, onLoadEarlier }) {
42555
42418
  const t = useT();
42556
42419
  const [query, setQuery] = useState("");
42420
+ const [renamingId, setRenamingId] = useState();
42557
42421
  const normalizedQuery = query.trim().toLocaleLowerCase();
42558
42422
  const threadIds = useAuiState((s) => s.threads.threadIds);
42423
+ const archivedThreadIds = useAuiState((s) => s.threads.archivedThreadIds);
42559
42424
  const threadItems = useAuiState((s) => s.threads.threadItems);
42560
42425
  const mainThreadId = useAuiState((s) => s.threads.mainThreadId);
42561
42426
  const matches = useMemo(() => {
@@ -42565,6 +42430,7 @@ function AssistantUiSessionList({ className = "", onNavigate }) {
42565
42430
  };
42566
42431
  }, [threadItems, normalizedQuery]);
42567
42432
  const visibleCount = threadIds.filter(matches).length;
42433
+ const visibleArchivedCount = archivedThreadIds.filter(matches).length;
42568
42434
  return /* @__PURE__ */ jsxs(ThreadListPrimitive.Root, {
42569
42435
  "data-testid": "assistant-ui-thread-list",
42570
42436
  "aria-label": t("session.title"),
@@ -42600,32 +42466,53 @@ function AssistantUiSessionList({ className = "", onNavigate }) {
42600
42466
  /* @__PURE__ */ jsxs("div", {
42601
42467
  className: "min-h-0 flex-1 overflow-y-auto px-2 pb-3",
42602
42468
  role: "list",
42603
- children: [visibleCount === 0 ? /* @__PURE__ */ jsx("p", {
42604
- className: "px-2 py-4 text-sm text-muted",
42605
- children: t("session.empty")
42606
- }) : null, /* @__PURE__ */ jsx(ThreadListPrimitive.Items, { children: ({ threadListItem }) => {
42607
- if (!matches(threadListItem.id)) return null;
42608
- const title = threadListItem.title ?? threadListItem.id;
42609
- const active = threadListItem.id === mainThreadId;
42610
- return /* @__PURE__ */ jsxs(ThreadListItemPrimitive.Root, {
42611
- role: "listitem",
42612
- className: "group flex items-center gap-1",
42613
- children: [/* @__PURE__ */ jsx(ThreadListItemPrimitive.Trigger, {
42614
- "data-webskill-thread-id": threadListItem.id,
42615
- "aria-current": active ? "page" : void 0,
42616
- onClick: onNavigate,
42617
- className: `min-w-0 flex-1 truncate rounded-md px-2.5 py-2 text-left text-sm transition-colors ${active ? "bg-subtle font-medium text-ink" : "text-muted hover:bg-subtle hover:text-ink"}`,
42618
- children: /* @__PURE__ */ jsx(ThreadListItemPrimitive.Title, { fallback: threadListItem.id })
42619
- }), /* @__PURE__ */ jsx(ThreadListItemPrimitive.Delete, {
42620
- "aria-label": t("session.delete", { title }),
42621
- className: "inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100 hover:bg-danger-soft hover:text-danger",
42622
- children: /* @__PURE__ */ jsx(Trash2, {
42623
- className: "size-3.5",
42624
- "aria-hidden": true
42625
- })
42626
- })]
42627
- });
42628
- } })]
42469
+ children: [
42470
+ hasEarlier && onLoadEarlier ? /* @__PURE__ */ jsx("button", {
42471
+ type: "button",
42472
+ "data-testid": "load-earlier-sessions",
42473
+ disabled: loadingEarlier,
42474
+ onClick: onLoadEarlier,
42475
+ className: "mb-1 w-full rounded-md px-2.5 py-2 text-sm text-muted transition-colors hover:bg-subtle hover:text-ink disabled:opacity-60",
42476
+ children: loadingEarlier ? t("session.loading") : t("session.loadEarlier")
42477
+ }) : null,
42478
+ visibleCount === 0 ? /* @__PURE__ */ jsx("p", {
42479
+ className: "px-2 py-4 text-sm text-muted",
42480
+ children: t("session.empty")
42481
+ }) : null,
42482
+ /* @__PURE__ */ jsx(ThreadListPrimitive.Items, { children: ({ threadListItem }) => {
42483
+ if (!matches(threadListItem.id)) return null;
42484
+ return /* @__PURE__ */ jsx(SessionRow, {
42485
+ id: threadListItem.id,
42486
+ title: threadListItem.title ?? threadListItem.id,
42487
+ active: threadListItem.id === mainThreadId,
42488
+ archived: false,
42489
+ renaming: renamingId === threadListItem.id,
42490
+ onNavigate,
42491
+ onStartRename: () => setRenamingId(threadListItem.id),
42492
+ onEndRename: () => setRenamingId(void 0)
42493
+ });
42494
+ } }),
42495
+ visibleArchivedCount > 0 ? /* @__PURE__ */ jsx("p", {
42496
+ className: "px-2.5 pb-1 pt-4 text-xs font-medium uppercase tracking-wide text-muted",
42497
+ children: t("session.archived")
42498
+ }) : null,
42499
+ /* @__PURE__ */ jsx(ThreadListPrimitive.Items, {
42500
+ archived: true,
42501
+ children: ({ threadListItem }) => {
42502
+ if (!matches(threadListItem.id)) return null;
42503
+ return /* @__PURE__ */ jsx(SessionRow, {
42504
+ id: threadListItem.id,
42505
+ title: threadListItem.title ?? threadListItem.id,
42506
+ active: threadListItem.id === mainThreadId,
42507
+ archived: true,
42508
+ renaming: renamingId === threadListItem.id,
42509
+ onNavigate,
42510
+ onStartRename: () => setRenamingId(threadListItem.id),
42511
+ onEndRename: () => setRenamingId(void 0)
42512
+ });
42513
+ }
42514
+ })
42515
+ ]
42629
42516
  })
42630
42517
  ]
42631
42518
  });
@@ -42805,8 +42692,7 @@ function LifecycleStep({ data }) {
42805
42692
  const at = typeof data["at"] === "number" ? data["at"] : void 0;
42806
42693
  const endedAt = typeof data["endedAt"] === "number" ? data["endedAt"] : void 0;
42807
42694
  const duration = at !== void 0 && endedAt !== void 0 ? formatDuration(endedAt - at) : void 0;
42808
- const detail = data["detail"];
42809
- const note = readString(detail, "strategy") ?? readString(detail, "type") ?? readString(detail, "reason");
42695
+ const note = readString(data, "note");
42810
42696
  const label = t(key);
42811
42697
  return /* @__PURE__ */ jsxs("li", {
42812
42698
  "aria-label": duration ? `${label}, ${duration}` : label,
@@ -42978,279 +42864,18 @@ function WebSkillMessageParts() {
42978
42864
  });
42979
42865
  }
42980
42866
 
42981
- //#endregion
42982
- //#region src/react/OpenUiInteraction.tsx
42983
- const inputClass = "w-full rounded-lg border border-border bg-surface px-3 py-2 text-sm text-ink transition-colors placeholder:text-muted hover:border-ring";
42984
- /**
42985
- * openui-lang 组件词汇的 ui-kit 视觉实现(与 @webskill/ui toOpenUiLang 的约定一致:
42986
- * Form/Text/TextField/NumberField/BooleanField/SelectField/SubmitButton/CancelButton)。
42987
- * 视觉对齐 native InteractionCard 的表单样式。
42988
- */
42989
- function buildOpenUiLibrary(openui, z, options = {}) {
42990
- const { defineComponent, createLibrary, useStateField, useTriggerAction } = openui;
42991
- const requiredMark = (required) => required ? /* @__PURE__ */ jsx("span", {
42992
- className: "text-danger",
42993
- children: " *"
42994
- }) : null;
42995
- const TextField = defineComponent({
42996
- name: "TextField",
42997
- description: "text input",
42998
- props: z.object({
42999
- name: z.string(),
43000
- label: z.string().optional(),
43001
- required: z.boolean().optional(),
43002
- defaultValue: z.string().nullable().optional()
43003
- }),
43004
- component: function TextFieldRenderer({ props }) {
43005
- const field = useStateField(props.name, props.defaultValue ?? "");
43006
- return /* @__PURE__ */ jsxs("label", {
43007
- className: "flex flex-col gap-1 text-sm text-ink",
43008
- children: [/* @__PURE__ */ jsxs("span", { children: [props.label ?? props.name, requiredMark(props.required)] }), /* @__PURE__ */ jsx("input", {
43009
- className: inputClass,
43010
- value: String(field.value ?? ""),
43011
- onChange: (e) => field.setValue(e.target.value)
43012
- })]
43013
- });
43014
- }
43015
- });
43016
- const NumberField = defineComponent({
43017
- name: "NumberField",
43018
- description: "number input",
43019
- props: z.object({
43020
- name: z.string(),
43021
- label: z.string().optional(),
43022
- required: z.boolean().optional()
43023
- }),
43024
- component: function NumberFieldRenderer({ props }) {
43025
- const field = useStateField(props.name, null);
43026
- return /* @__PURE__ */ jsxs("label", {
43027
- className: "flex flex-col gap-1 text-sm text-ink",
43028
- children: [/* @__PURE__ */ jsxs("span", { children: [props.label ?? props.name, requiredMark(props.required)] }), /* @__PURE__ */ jsx("input", {
43029
- type: "number",
43030
- className: inputClass,
43031
- value: field.value === void 0 || field.value === null ? "" : String(field.value),
43032
- onChange: (e) => field.setValue(e.target.value === "" ? void 0 : Number(e.target.value))
43033
- })]
43034
- });
43035
- }
43036
- });
43037
- const BooleanField = defineComponent({
43038
- name: "BooleanField",
43039
- description: "checkbox",
43040
- props: z.object({
43041
- name: z.string(),
43042
- label: z.string().optional(),
43043
- defaultValue: z.boolean().optional()
43044
- }),
43045
- component: function BooleanFieldRenderer({ props }) {
43046
- const field = useStateField(props.name, props.defaultValue ?? false);
43047
- return /* @__PURE__ */ jsxs("label", {
43048
- className: "flex items-center gap-2 text-sm text-ink",
43049
- children: [/* @__PURE__ */ jsx("input", {
43050
- type: "checkbox",
43051
- className: "size-4 accent-primary",
43052
- checked: field.value === true,
43053
- onChange: (e) => field.setValue(e.target.checked)
43054
- }), /* @__PURE__ */ jsx("span", { children: props.label ?? props.name })]
43055
- });
43056
- }
43057
- });
43058
- const SelectField = defineComponent({
43059
- name: "SelectField",
43060
- description: "select input",
43061
- props: z.object({
43062
- name: z.string(),
43063
- label: z.string().optional(),
43064
- options: z.array(z.object({
43065
- label: z.string(),
43066
- value: z.unknown()
43067
- }))
43068
- }),
43069
- component: function SelectFieldRenderer({ props }) {
43070
- const field = useStateField(props.name, props.options[0]?.value ?? "");
43071
- return /* @__PURE__ */ jsxs("label", {
43072
- className: "flex flex-col gap-1 text-sm text-ink",
43073
- children: [/* @__PURE__ */ jsx("span", { children: props.label ?? props.name }), /* @__PURE__ */ jsx("select", {
43074
- className: inputClass,
43075
- value: JSON.stringify(field.value ?? ""),
43076
- onChange: (e) => field.setValue(JSON.parse(e.target.value)),
43077
- children: props.options.map((option, i) => /* @__PURE__ */ jsx("option", {
43078
- value: JSON.stringify(option.value),
43079
- children: option.label
43080
- }, i))
43081
- })]
43082
- });
43083
- }
43084
- });
43085
- const SubmitButton = defineComponent({
43086
- name: "SubmitButton",
43087
- description: "submit button",
43088
- props: z.object({
43089
- label: z.string(),
43090
- actionType: z.string(),
43091
- requestId: z.string()
43092
- }),
43093
- component: function SubmitButtonRenderer({ props }) {
43094
- const trigger = useTriggerAction();
43095
- return /* @__PURE__ */ jsx(Button, {
43096
- onClick: () => void trigger(props.label, void 0, {
43097
- type: props.actionType,
43098
- params: { id: props.requestId }
43099
- }),
43100
- children: props.label
43101
- });
43102
- }
43103
- });
43104
- const CancelButton = defineComponent({
43105
- name: "CancelButton",
43106
- description: "cancel button",
43107
- props: z.object({
43108
- label: z.string(),
43109
- actionType: z.string(),
43110
- requestId: z.string()
43111
- }),
43112
- component: function CancelButtonRenderer({ props }) {
43113
- const trigger = useTriggerAction();
43114
- return /* @__PURE__ */ jsx(Button, {
43115
- variant: "secondary",
43116
- onClick: () => void trigger(props.label, void 0, {
43117
- type: props.actionType,
43118
- params: { id: props.requestId }
43119
- }),
43120
- children: props.label
43121
- });
43122
- }
43123
- });
43124
- const Text = defineComponent({
43125
- name: "Text",
43126
- description: "plain display text",
43127
- props: z.object({ content: z.string() }),
43128
- component: function TextRenderer({ props }) {
43129
- return /* @__PURE__ */ jsx("p", {
43130
- className: "text-sm break-words text-muted",
43131
- children: props.content
43132
- });
43133
- }
43134
- });
43135
- const components = [
43136
- defineComponent({
43137
- name: "Form",
43138
- description: "form container",
43139
- props: z.object({
43140
- title: z.string().nullable().optional(),
43141
- children: z.array(z.any()).optional()
43142
- }),
43143
- component: function FormRenderer({ props, renderNode }) {
43144
- return /* @__PURE__ */ jsxs("form", {
43145
- className: "flex flex-col gap-3",
43146
- onSubmit: (e) => {
43147
- e.preventDefault();
43148
- },
43149
- children: [props.title ? /* @__PURE__ */ jsx("h3", {
43150
- className: "font-display text-sm font-semibold text-ink",
43151
- children: props.title
43152
- }) : null, (props.children ?? []).map((child, i) => /* @__PURE__ */ jsx("div", { children: renderNode(child) }, i))]
43153
- });
43154
- }
43155
- }),
43156
- Text,
43157
- TextField,
43158
- NumberField,
43159
- BooleanField,
43160
- SelectField,
43161
- SubmitButton,
43162
- CancelButton
43163
- ];
43164
- if (options.onSurfaceAction) {
43165
- const WebSkillSurfaceHost = defineComponent({
43166
- name: "WebSkillSurfaceHost",
43167
- description: "controlled WebSkill structured UI surface",
43168
- props: z.object({ descriptor: z.any() }),
43169
- component: function WebSkillSurfaceHostRenderer({ props }) {
43170
- if (props.descriptor?.type !== "webskill-surface") return null;
43171
- return /* @__PURE__ */ jsx("div", {
43172
- "data-webskill-provenance": props.descriptor.provenance,
43173
- children: /* @__PURE__ */ jsx(UiSurfaceSnapshotList, {
43174
- snapshots: [props.descriptor.snapshot],
43175
- ...options.registry ? { registry: options.registry } : {},
43176
- onAction: options.onSurfaceAction,
43177
- ...options.drafts ? { drafts: options.drafts } : {},
43178
- ...options.onSurfaceDraftChange ? { onDraftChange: options.onSurfaceDraftChange } : {}
43179
- })
43180
- });
43181
- }
43182
- });
43183
- components.push(WebSkillSurfaceHost);
43184
- }
43185
- return createLibrary({
43186
- components,
43187
- root: options.root ?? "Form"
43188
- });
43189
- }
43190
- /**
43191
- * openui 档交互视图:订阅 OpenUiChannel(core 产出 openui-lang 文本),动态加载
43192
- * optional peer @openuidev/react-lang 的 Renderer 渲染;动作事件回传 channel.handleAction。
43193
- * 模块加载失败 → channel.fail(桥粘性降级 native,InteractionCard 接管)。
43194
- */
43195
- function OpenUiInteraction({ channel }) {
43196
- const session = useSyncExternalStore(channel.subscribe, () => channel.current);
43197
- const [ready, setReady] = useState();
43198
- useEffect(() => {
43199
- channel.attach();
43200
- return () => channel.detach();
43201
- }, [channel]);
43202
- useEffect(() => {
43203
- let cancelled = false;
43204
- (async () => {
43205
- try {
43206
- const { openui, z } = await loadOpenUiPeers();
43207
- if (!cancelled) setReady({
43208
- Renderer: openui.Renderer,
43209
- library: buildOpenUiLibrary(openui, z)
43210
- });
43211
- } catch (e) {
43212
- if (!cancelled) channel.fail(messageOf(e));
43213
- }
43214
- })();
43215
- return () => {
43216
- cancelled = true;
43217
- };
43218
- }, [channel]);
43219
- if (!session || !ready) return null;
43220
- const { Renderer, library } = ready;
43221
- return /* @__PURE__ */ jsx("div", {
43222
- "data-testid": "openui-interaction",
43223
- className: "rounded-card border border-border bg-surface px-4 py-4 shadow-card",
43224
- children: /* @__PURE__ */ jsx(Renderer, {
43225
- response: session.lang,
43226
- library,
43227
- onAction: (action) => channel.handleAction(action)
43228
- })
43229
- });
43230
- }
43231
-
43232
42867
  //#endregion
43233
42868
  //#region src/react/OpenUiSurfaceHost.tsx
43234
- /** Renders persisted UiSurface snapshots through the OpenUI extension without a live bridge. @experimental */
43235
- function OpenUiSurfaceSnapshotHost({ snapshots, registry, onAction, drafts, onDraftChange }) {
43236
- const [ready, setReady] = useState();
42869
+ /** Renders persisted UI spec snapshots through the OpenUI extension without a live bridge. @experimental */
42870
+ function OpenUiSurfaceSnapshotHost({ snapshots, onAction }) {
42871
+ const [ready, setReady] = useState(false);
43237
42872
  const [fallbackReason, setFallbackReason] = useState();
43238
- const emitAction = useEffectEvent((event) => onAction?.(event));
43239
42873
  useEffect(() => {
43240
42874
  let cancelled = false;
43241
42875
  (async () => {
43242
42876
  try {
43243
- const { openui, z } = await loadOpenUiPeers();
43244
- if (!cancelled) setReady({
43245
- Renderer: openui.Renderer,
43246
- library: buildOpenUiLibrary(openui, z, {
43247
- root: "WebSkillSurfaceHost",
43248
- ...registry ? { registry } : {},
43249
- onSurfaceAction: emitAction,
43250
- ...drafts ? { drafts } : {},
43251
- ...onDraftChange ? { onSurfaceDraftChange: onDraftChange } : {}
43252
- })
43253
- });
42877
+ await loadOpenUiPeers();
42878
+ if (!cancelled) setReady(true);
43254
42879
  } catch (error) {
43255
42880
  const reason = error?.code === "UI_UNAVAILABLE" ? "openui-peer-missing" : "openui-load-failed";
43256
42881
  if (reason !== "openui-peer-missing") console.warn("[webskill] OpenUI renderer unavailable, falling back to native", { error });
@@ -43260,63 +42885,40 @@ function OpenUiSurfaceSnapshotHost({ snapshots, registry, onAction, drafts, onDr
43260
42885
  return () => {
43261
42886
  cancelled = true;
43262
42887
  };
43263
- }, [registry]);
42888
+ }, []);
43264
42889
  if (snapshots.length === 0) return null;
43265
- const specs = snapshots.filter((snapshot) => isUiSpecSurface(snapshot.surface));
43266
- const legacy = snapshots.filter((snapshot) => !isUiSpecSurface(snapshot.surface));
43267
- const specNodes = specs.map((snapshot) => {
43268
- const surface = snapshot.surface;
43269
- return /* @__PURE__ */ jsx(OpenUiSpecSurface, { spec: surface.props.spec }, surface.id);
43270
- });
43271
- if (!ready) return /* @__PURE__ */ jsxs("div", {
42890
+ return /* @__PURE__ */ jsx("div", {
43272
42891
  "data-testid": "openui-surface-host",
43273
- "data-renderer": "native-fallback",
42892
+ "data-renderer": ready ? "openui" : "native-fallback",
43274
42893
  ...fallbackReason ? { "data-fallback-reason": fallbackReason } : {},
43275
- children: [specNodes, legacy.length > 0 ? /* @__PURE__ */ jsx(UiSurfaceSnapshotList, {
43276
- snapshots: legacy,
43277
- ...registry ? { registry } : {},
43278
- ...onAction ? { onAction: emitAction } : {},
43279
- ...drafts ? { drafts } : {},
43280
- ...onDraftChange ? { onDraftChange } : {}
43281
- }) : null]
43282
- });
43283
- const { Renderer, library } = ready;
43284
- return /* @__PURE__ */ jsxs("div", {
43285
- "data-testid": "openui-surface-host",
43286
- "data-renderer": "openui",
43287
- children: [specNodes, legacy.map((snapshot) => /* @__PURE__ */ jsx(Renderer, {
43288
- response: toOpenUiSurfaceLang(snapshot),
43289
- library
43290
- }, snapshot.surface.id))]
42894
+ children: snapshots.map((snapshot) => /* @__PURE__ */ jsx(OpenUiSpecSurface, {
42895
+ spec: snapshot.node,
42896
+ surfaceId: snapshot.id,
42897
+ actions: snapshot.actions ?? [],
42898
+ ...onAction ? { onAction } : {}
42899
+ }, snapshot.id))
43291
42900
  });
43292
42901
  }
43293
- /** Renders serializable UiSurface descriptors through an OpenUI library extension. @experimental */
43294
- function OpenUiSurfaceHost({ bridge, runId, registry }) {
42902
+ /** Renders WebSkill UI spec snapshots through an OpenUI library extension. @experimental */
42903
+ function OpenUiSurfaceHost({ bridge, runId }) {
43295
42904
  const snapshots = useSyncExternalStore(bridge.subscribe, () => bridge.surfaceSnapshots);
43296
42905
  const visibleSnapshots = runId === void 0 ? snapshots : snapshots.filter((snapshot) => snapshot.runId === runId);
43297
42906
  const handleAction = (event) => {
43298
- const action = fromOpenUiSurfaceAction({
43299
- type: OPENUI_SURFACE_ACTION,
43300
- params: event
43301
- });
43302
- if (!action?.runId || !action.nonce) return;
42907
+ const snapshot = visibleSnapshots.find((candidate) => candidate.id === event.surfaceId);
42908
+ const capability = snapshot?.actions?.find((candidate) => candidate.id === event.actionId);
42909
+ if (!snapshot?.runId || !capability?.nonce) return;
43303
42910
  bridge.resolveSurfaceAction({
43304
- runId: action.runId,
43305
- surfaceId: action.surfaceId,
43306
- actionId: action.actionId,
43307
- intent: action.intent,
43308
- nonce: action.nonce,
43309
- ...action.value ? { value: action.value } : {},
43310
- ...action.cancelled ? { cancelled: true } : {}
42911
+ runId: snapshot.runId,
42912
+ surfaceId: event.surfaceId,
42913
+ actionId: event.actionId,
42914
+ intent: event.intent,
42915
+ nonce: capability.nonce,
42916
+ ...event.value ? { value: event.value } : {}
43311
42917
  });
43312
42918
  };
43313
- const drafts = runId ? bridge.surfaceDrafts(runId) : {};
43314
42919
  return /* @__PURE__ */ jsx(OpenUiSurfaceSnapshotHost, {
43315
42920
  snapshots: visibleSnapshots,
43316
- ...registry ? { registry } : {},
43317
- onAction: handleAction,
43318
- drafts,
43319
- onDraftChange: (event) => bridge.setSurfaceDraft(event.runId, event.surfaceId, event.value)
42921
+ onAction: handleAction
43320
42922
  });
43321
42923
  }
43322
42924
 
@@ -53394,6 +52996,7 @@ function Block({ block, runId, onDownload }) {
53394
52996
  /**
53395
52997
  * 结果块列表(AnimatePresence 逐块入场):markdown / json / table / chart / image / file。
53396
52998
  * 历史消息(ChatMessage.blocks)与当前 run(ResultBlocksPro)共用的渲染形态。
52999
+ * @stable
53397
53000
  */
53398
53001
  function ResultBlockList({ blocks, runId, onDownload }) {
53399
53002
  return /* @__PURE__ */ jsx(AnimatePresence, {
@@ -53415,6 +53018,7 @@ function ResultBlockList({ blocks, runId, onDownload }) {
53415
53018
  /**
53416
53019
  * run 完成结果块渐进挂载(AnimatePresence 逐块入场):
53417
53020
  * markdown / json / table / chart / image / file + artifact 下载卡。
53021
+ * @stable
53418
53022
  */
53419
53023
  function ResultBlocksPro({ bridge, activeRunId, onDownload }) {
53420
53024
  const t = useT();
@@ -53457,7 +53061,7 @@ function ResultBlocksPro({ bridge, activeRunId, onDownload }) {
53457
53061
 
53458
53062
  //#endregion
53459
53063
  //#region src/react/SkillBadges.tsx
53460
- /** 消息底部展示该 run 激活的技能名徽章(无技能不渲染) */
53064
+ /** 消息底部展示该 run 激活的技能名徽章(无技能不渲染) @stable */
53461
53065
  function SkillBadges({ skills }) {
53462
53066
  const t = useT();
53463
53067
  if (skills.length === 0) return null;
@@ -53483,56 +53087,42 @@ function SkillBadges({ skills }) {
53483
53087
 
53484
53088
  //#endregion
53485
53089
  //#region src/react/VercelSurfaceHost.tsx
53486
- /** Renders persisted Vercel-compatible data parts without subscribing to a live bridge. @experimental */
53487
- function VercelSurfaceSnapshotHost({ snapshots, registry, onAction, drafts, onDraftChange }) {
53488
- const dataParts = snapshots.map((snapshot) => toVercelSurfaceDataPart(snapshot));
53489
- if (dataParts.length === 0) return null;
53490
- const specs = dataParts.filter((part) => isUiSpecSurface(part.data.snapshot.surface));
53491
- const legacy = dataParts.filter((part) => !isUiSpecSurface(part.data.snapshot.surface));
53492
- return /* @__PURE__ */ jsxs("div", {
53090
+ /** Renders persisted UI spec snapshots through the json-render registry without a live bridge. @experimental */
53091
+ function VercelSurfaceSnapshotHost({ snapshots, onAction }) {
53092
+ if (snapshots.length === 0) return null;
53093
+ return /* @__PURE__ */ jsx("div", {
53493
53094
  "data-testid": "vercel-surface-snapshot-host",
53494
- "data-surface-parts": dataParts.length,
53495
- children: [specs.map((part) => {
53496
- const surface = part.data.snapshot.surface;
53497
- return /* @__PURE__ */ jsx(JsonRenderSpecSurface, { spec: surface.props.spec }, surface.id);
53498
- }), legacy.length > 0 ? /* @__PURE__ */ jsx(UiSurfaceSnapshotList, {
53499
- snapshots: legacy.map((part) => part.data.snapshot),
53500
- ...registry ? { registry } : {},
53501
- ...onAction ? { onAction } : {},
53502
- ...drafts ? { drafts } : {},
53503
- ...onDraftChange ? { onDraftChange } : {}
53504
- }) : null]
53095
+ "data-surface-parts": snapshots.length,
53096
+ children: snapshots.map((snapshot) => /* @__PURE__ */ jsx(JsonRenderSpecSurface, {
53097
+ spec: snapshot.node,
53098
+ surfaceId: snapshot.id,
53099
+ actions: snapshot.actions ?? [],
53100
+ ...onAction ? { onAction } : {}
53101
+ }, snapshot.id))
53505
53102
  });
53506
53103
  }
53507
- /** Consumes Vercel-compatible surface data parts with a controlled React surface renderer. @experimental */
53508
- function VercelSurfaceHost({ bridge, runId, registry }) {
53104
+ /** Consumes WebSkill UI spec snapshots with a json-render surface renderer. @experimental */
53105
+ function VercelSurfaceHost({ bridge, runId }) {
53509
53106
  const visibleSnapshots = useSyncExternalStore(bridge.subscribe, () => bridge.surfaceSnapshots).filter((snapshot) => runId === void 0 || snapshot.runId === runId);
53107
+ if (visibleSnapshots.length === 0) return null;
53510
53108
  const handleAction = (event) => {
53511
- const action = fromVercelSurfaceAction({
53512
- type: VERCEL_SURFACE_ACTION_DATA_PART_TYPE,
53513
- data: event
53514
- });
53515
- if (!action?.runId || !action.nonce) return;
53109
+ const snapshot = visibleSnapshots.find((candidate) => candidate.id === event.surfaceId);
53110
+ const capability = snapshot?.actions?.find((candidate) => candidate.id === event.actionId);
53111
+ if (!snapshot?.runId || !capability?.nonce) return;
53516
53112
  bridge.resolveSurfaceAction({
53517
- runId: action.runId,
53518
- surfaceId: action.surfaceId,
53519
- actionId: action.actionId,
53520
- intent: action.intent,
53521
- nonce: action.nonce,
53522
- ...action.value ? { value: action.value } : {},
53523
- ...action.cancelled ? { cancelled: true } : {}
53113
+ runId: snapshot.runId,
53114
+ surfaceId: event.surfaceId,
53115
+ actionId: event.actionId,
53116
+ intent: event.intent,
53117
+ nonce: capability.nonce,
53118
+ ...event.value ? { value: event.value } : {}
53524
53119
  });
53525
53120
  };
53526
- if (visibleSnapshots.length === 0) return null;
53527
- const drafts = runId ? bridge.surfaceDrafts(runId) : {};
53528
53121
  return /* @__PURE__ */ jsx("div", {
53529
53122
  "data-testid": "vercel-surface-host",
53530
53123
  children: /* @__PURE__ */ jsx(VercelSurfaceSnapshotHost, {
53531
53124
  snapshots: visibleSnapshots,
53532
- ...registry ? { registry } : {},
53533
- onAction: handleAction,
53534
- drafts,
53535
- onDraftChange: (event) => bridge.setSurfaceDraft(event.runId, event.surfaceId, event.value)
53125
+ onAction: handleAction
53536
53126
  })
53537
53127
  });
53538
53128
  }
@@ -53544,23 +53134,30 @@ function HistoricalSurfaces({ snapshots, renderer, registry }) {
53544
53134
  snapshots,
53545
53135
  ...registry ? { registry } : {}
53546
53136
  });
53547
- if (renderer === "openui") return /* @__PURE__ */ jsx(OpenUiSurfaceSnapshotHost, {
53548
- snapshots,
53549
- ...registry ? { registry } : {}
53550
- });
53551
- if (renderer === "vercel") return /* @__PURE__ */ jsx(VercelSurfaceSnapshotHost, {
53552
- snapshots,
53553
- ...registry ? { registry } : {}
53554
- });
53137
+ if (renderer === "openui") return /* @__PURE__ */ jsx(OpenUiSurfaceSnapshotHost, { snapshots });
53138
+ if (renderer === "vercel") return /* @__PURE__ */ jsx(VercelSurfaceSnapshotHost, { snapshots });
53555
53139
  return /* @__PURE__ */ jsx(UiSurfaceSnapshotList, {
53556
53140
  snapshots,
53557
53141
  ...registry ? { registry } : {}
53558
53142
  });
53559
53143
  }
53144
+ /**
53145
+ * 旧版本会话里的 surface 条目是六类 `{ surface: { kind } }`,没有节点树,任何渲染器都吃不下。
53146
+ * 判定只看渲染入口是否成立,不做深校验:深校验属于产出侧,历史消息只决定「渲染还是占位」。
53147
+ */
53148
+ function isRenderableSpec(snapshot) {
53149
+ if (typeof snapshot !== "object" || snapshot === null) return false;
53150
+ const node = snapshot.node;
53151
+ if (typeof node !== "object" || node === null) return false;
53152
+ return typeof node.component === "string";
53153
+ }
53560
53154
  /** WebSkill domain content rendered beneath a Base message without choosing its chat layout. */
53561
53155
  function WebSkillMessageExtensions({ message, onDownload, surfaceRegistry, renderer }) {
53156
+ const t = useT();
53562
53157
  if (message.role === "user") return null;
53563
53158
  const blocks = message.blocks?.filter((block) => block.type !== "markdown" || block.text.trim() !== message.text.trim());
53159
+ const surfaces = message.surfaces ?? [];
53160
+ const renderable = surfaces.filter(isRenderableSpec);
53564
53161
  return /* @__PURE__ */ jsxs("div", {
53565
53162
  className: "min-w-0 w-full",
53566
53163
  children: [
@@ -53569,11 +53166,16 @@ function WebSkillMessageExtensions({ message, onDownload, surfaceRegistry, rende
53569
53166
  runId: message.runId ?? "",
53570
53167
  ...onDownload ? { onDownload } : {}
53571
53168
  }) : null,
53572
- message.surfaces && message.surfaces.length > 0 ? /* @__PURE__ */ jsx(HistoricalSurfaces, {
53573
- snapshots: message.surfaces,
53169
+ renderable.length > 0 ? /* @__PURE__ */ jsx(HistoricalSurfaces, {
53170
+ snapshots: renderable,
53574
53171
  ...renderer ? { renderer } : {},
53575
53172
  ...surfaceRegistry ? { registry: surfaceRegistry } : {}
53576
53173
  }) : null,
53174
+ renderable.length < surfaces.length ? /* @__PURE__ */ jsx("p", {
53175
+ "data-testid": "legacy-surface-placeholder",
53176
+ className: "my-2 rounded-lg border border-border bg-canvas px-3 py-2 text-xs text-muted",
53177
+ children: t("surface.legacy.placeholder")
53178
+ }) : null,
53577
53179
  /* @__PURE__ */ jsx(SkillBadges, { skills: message.activeSkillNames ?? [] })
53578
53180
  ]
53579
53181
  });
@@ -53790,23 +53392,35 @@ const start = (runId, at) => ({
53790
53392
  text: "",
53791
53393
  chunks: 0
53792
53394
  });
53793
- function appendPhase(live, phase, at, data) {
53794
- const display = DISPLAY_PHASE[phase];
53395
+ function appendPhase(live, event) {
53396
+ const display = DISPLAY_PHASE[event.phase];
53795
53397
  const last = live.phases.at(-1);
53796
53398
  if (last?.phase === display) return live;
53797
53399
  const closed = last ? [...live.phases.slice(0, -1), {
53798
53400
  ...last,
53799
- endedAt: at
53401
+ endedAt: event.at
53800
53402
  }] : [];
53403
+ const note = phaseNote(event);
53801
53404
  return {
53802
53405
  ...live,
53803
53406
  phases: [...closed, {
53804
53407
  phase: display,
53805
- at,
53806
- ...data ? { data } : {}
53408
+ at: event.at,
53409
+ ...note ? { note } : {}
53807
53410
  }]
53808
53411
  };
53809
53412
  }
53413
+ /** 相位摘要:唯一读 `data` 的地方,此处事件还带着 `phase` 判别,下游不必再猜键名 */
53414
+ function phaseNote(event) {
53415
+ switch (event.phase) {
53416
+ case "route": return event.data.strategy;
53417
+ case "activate": return event.data.skillName;
53418
+ case "interact": return event.data.kind === "interaction" ? event.data.interactionType : event.data.actionId;
53419
+ case "complete":
53420
+ case "fail": return event.data.reason;
53421
+ default: return;
53422
+ }
53423
+ }
53810
53424
  /**
53811
53425
  * ChatEvent → 进行中 run 的 part 累积器。返回 undefined 表示当前没有进行中的 run。
53812
53426
  * 只处理属于当前 runId 的事件,跨 run 的迟到事件被忽略。
@@ -53820,7 +53434,7 @@ function reduceLiveRun(live, event, at) {
53820
53434
  }
53821
53435
  if (!live || !("runId" in event) || event.runId !== live.runId) return live;
53822
53436
  switch (event.type) {
53823
- case "lifecycle": return appendPhase(live, event.phase, event.at, event.data);
53437
+ case "lifecycle": return appendPhase(live, event);
53824
53438
  case "skill-activated": return {
53825
53439
  ...live,
53826
53440
  skills: event.skills
@@ -53859,7 +53473,7 @@ function reduceLiveRun(live, event, at) {
53859
53473
 
53860
53474
  //#endregion
53861
53475
  //#region src/react/ErrorCard.tsx
53862
- /** 结构化错误卡:错误码徽章 + 描述 + 建议(engine error 事件 / 失败 run) */
53476
+ /** 结构化错误卡:错误码徽章 + 描述 + 建议(engine error 事件 / 失败 run) @stable */
53863
53477
  function ErrorCard({ code, message, onDismiss }) {
53864
53478
  const t = useT();
53865
53479
  return /* @__PURE__ */ jsx("div", {
@@ -53913,9 +53527,42 @@ function ErrorCard({ code, message, onDismiss }) {
53913
53527
  });
53914
53528
  }
53915
53529
 
53530
+ //#endregion
53531
+ //#region src/react/interactionLabels.ts
53532
+ /**
53533
+ * 交互卡的界面文案:生成器(`@webskill/ui`)与语言无关,本地化由持有字典的宿主注入。
53534
+ * 四档共用本函数,切换渲染档不会让同一个请求出现两套文案。
53535
+ */
53536
+ function interactionLabels(request, t) {
53537
+ return {
53538
+ title: request.type === "form" && request.title ? request.title : t(`interaction.${request.type}.title`),
53539
+ submitLabel: t(request.type === "authorize" ? "interaction.allow" : request.type === "confirm" ? "interaction.confirm" : "interaction.submit"),
53540
+ cancelLabel: t(request.type === "authorize" ? "interaction.deny" : "interaction.cancel")
53541
+ };
53542
+ }
53543
+
53916
53544
  //#endregion
53917
53545
  //#region src/react/InteractionCard.tsx
53918
- /** 订阅 bridge.pending 渲染五类交互卡(ask/confirm/form/select/authorize,native) */
53546
+ /** 交互表单的两个动作:与 surface 侧共用 catalog 的 submit / cancel 语义 */
53547
+ const INTERACTION_ACTIONS$1 = [{
53548
+ id: "submit",
53549
+ intent: "submit"
53550
+ }, {
53551
+ id: "cancel",
53552
+ intent: "cancel"
53553
+ }];
53554
+ const kindIcons = {
53555
+ ask: MessageCircleQuestionMark,
53556
+ confirm: CircleQuestionMark,
53557
+ form: ClipboardList,
53558
+ select: ListChecks,
53559
+ authorize: ShieldAlert
53560
+ };
53561
+ /**
53562
+ * 订阅 bridge.pending 渲染五类交互卡(native 档;其它档降级后也由它接管)。
53563
+ * 表单本体走 `NativeSpecSurface`——与 native 档 surface 侧同一个渲染入口。
53564
+ * @stable
53565
+ */
53919
53566
  function InteractionCard({ bridge }) {
53920
53567
  const pending = useSyncExternalStore(bridge.subscribe, () => bridge.pending);
53921
53568
  if (!pending) return null;
@@ -53924,102 +53571,25 @@ function InteractionCard({ bridge }) {
53924
53571
  bridge
53925
53572
  }, pending.id);
53926
53573
  }
53927
- /** 单个表单控件(ask/form 用;data-webskill-control 契约与 collectValues 对齐) */
53928
- function Field({ control, invalid }) {
53929
- const t = useT();
53930
- const id = `webskill-field-${control.name}`;
53931
- const label = /* @__PURE__ */ jsxs(Fragment$1, { children: [control.label, control.required ? /* @__PURE__ */ jsx("span", {
53932
- className: "text-danger",
53933
- children: " *"
53934
- }) : null] });
53935
- let element;
53936
- switch (control.control) {
53937
- case "boolean":
53938
- element = /* @__PURE__ */ jsx(Checkbox, {
53939
- id,
53940
- "data-webskill-control": control.name,
53941
- defaultChecked: control.defaultValue === true ? true : void 0,
53942
- invalid
53943
- });
53944
- break;
53945
- case "select":
53946
- element = /* @__PURE__ */ jsx("select", {
53947
- id,
53948
- "data-webskill-control": control.name,
53949
- "aria-invalid": invalid || void 0,
53950
- className: "h-9 w-full rounded-md border border-input bg-surface px-3 text-sm text-ink shadow-xs outline-none transition-colors focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/20",
53951
- ...control.defaultValue !== void 0 ? { defaultValue: JSON.stringify(control.defaultValue) } : {},
53952
- children: (control.options ?? []).map((option, i) => /* @__PURE__ */ jsx("option", {
53953
- value: JSON.stringify(option.value),
53954
- children: option.label
53955
- }, i))
53956
- });
53957
- break;
53958
- case "textarea":
53959
- element = /* @__PURE__ */ jsx(Textarea, {
53960
- id,
53961
- "data-webskill-control": control.name,
53962
- invalid,
53963
- rows: 3,
53964
- defaultValue: control.defaultValue !== void 0 ? String(control.defaultValue) : ""
53965
- });
53966
- break;
53967
- default: element = /* @__PURE__ */ jsx(Input, {
53968
- type: control.control === "number" ? "number" : "text",
53969
- id,
53970
- "data-webskill-control": control.name,
53971
- invalid,
53972
- defaultValue: control.defaultValue !== void 0 ? String(control.defaultValue) : ""
53973
- });
53974
- }
53975
- return /* @__PURE__ */ jsx(FormField, {
53976
- label,
53977
- htmlFor: id,
53978
- ...control.description ? { description: control.description } : {},
53979
- ...invalid ? { error: t("interaction.required") } : {},
53980
- children: element
53981
- });
53982
- }
53983
- const kindIcons = {
53984
- ask: MessageCircleQuestionMark,
53985
- confirm: CircleQuestionMark,
53986
- form: ClipboardList,
53987
- select: ListChecks,
53988
- authorize: ShieldAlert
53989
- };
53990
53574
  function ActiveInteractionCard({ request, bridge }) {
53991
53575
  const t = useT();
53992
- const model = interactionToFormModel(request);
53993
- const formRef = useRef(null);
53994
- const [invalid, setInvalid] = useState([]);
53995
- const resolve = (value) => bridge.resolve({
53996
- id: request.id,
53997
- value
53998
- });
53999
- const cancel = () => bridge.resolve({
54000
- id: request.id,
54001
- cancelled: true
54002
- });
54003
- const submitForm = () => {
54004
- if (!formRef.current) return;
54005
- const { values, missingRequired } = collectValues(model.controls, formRef.current);
54006
- if (missingRequired.length > 0) {
54007
- setInvalid(missingRequired);
53576
+ const spec = interactionToUiSpec(request, interactionLabels(request, t));
53577
+ const isAuthorize = request.type === "authorize";
53578
+ const Icon = kindIcons[request.type];
53579
+ const handleAction = (event) => {
53580
+ if (event.intent !== "submit") {
53581
+ bridge.resolve({
53582
+ id: request.id,
53583
+ cancelled: true
53584
+ });
54008
53585
  return;
54009
53586
  }
54010
- resolve(shapeInteractionValue(model, values));
54011
- };
54012
- const isAuthorize = model.kind === "authorize";
54013
- const Icon = kindIcons[model.kind];
54014
- const title = resolveTitle(model, t);
54015
- const body = renderBody(model, request, {
54016
- t,
54017
- formRef,
54018
- invalid,
54019
- submitForm,
54020
- resolve,
54021
- cancel
54022
- });
53587
+ const value = shapeInteractionValue(interactionToFormModel(request), event.value ?? {});
53588
+ bridge.resolve({
53589
+ id: request.id,
53590
+ value
53591
+ });
53592
+ };
54023
53593
  return /* @__PURE__ */ jsxs(motion.div, {
54024
53594
  ...fadeInUp,
54025
53595
  className: `rounded-card border shadow-card ${isAuthorize ? "border-warning/50 bg-warning-soft" : "border-border bg-surface"}`,
@@ -54031,132 +53601,51 @@ function ActiveInteractionCard({ request, bridge }) {
54031
53601
  className: "size-4",
54032
53602
  "aria-hidden": true
54033
53603
  })
54034
- }), /* @__PURE__ */ jsxs("div", {
54035
- className: "min-w-0 flex-1",
54036
- children: [/* @__PURE__ */ jsx("h3", {
54037
- className: "font-display text-sm font-semibold text-ink",
54038
- children: title
54039
- }), model.message ? /* @__PURE__ */ jsx("p", {
54040
- className: "mt-0.5 text-sm break-words text-muted",
54041
- children: model.message
54042
- }) : null]
54043
- })]
53604
+ }), request.type === "authorize" ? /* @__PURE__ */ jsxs("div", {
53605
+ className: "flex min-w-0 flex-1 flex-col gap-2",
53606
+ children: [
53607
+ /* @__PURE__ */ jsxs("div", {
53608
+ className: "flex items-center gap-2",
53609
+ children: [/* @__PURE__ */ jsx("span", {
53610
+ className: "text-xs font-medium text-muted",
53611
+ children: t("interaction.authorize.capability")
53612
+ }), /* @__PURE__ */ jsx(Badge, {
53613
+ tone: "warning",
53614
+ children: request.capability
53615
+ })]
53616
+ }),
53617
+ /* @__PURE__ */ jsx("p", {
53618
+ className: "text-xs text-muted",
53619
+ children: t("interaction.authorize.description")
53620
+ }),
53621
+ request.details !== void 0 ? /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
53622
+ className: "mb-1 text-xs font-medium text-muted",
53623
+ children: t("interaction.authorize.details")
53624
+ }), /* @__PURE__ */ jsx("pre", {
53625
+ className: "max-h-40 overflow-auto rounded-lg border border-border bg-canvas p-3 font-mono text-xs text-ink",
53626
+ children: JSON.stringify(request.details, null, 2)
53627
+ })] }) : null
53628
+ ]
53629
+ }) : null]
54044
53630
  }), /* @__PURE__ */ jsx("div", {
54045
53631
  className: "px-4 py-4",
54046
- children: body
54047
- })]
54048
- });
54049
- }
54050
- function resolveTitle(model, t) {
54051
- if (model.title) return model.title;
54052
- switch (model.kind) {
54053
- case "ask": return t("interaction.ask.title");
54054
- case "confirm": return t("interaction.confirm.title");
54055
- case "select": return t("interaction.select.title");
54056
- case "authorize": return t("interaction.authorize.title");
54057
- default: return t("interaction.form.title");
54058
- }
54059
- }
54060
- function renderBody(model, request, deps) {
54061
- const { t, formRef, invalid, submitForm, resolve, cancel } = deps;
54062
- if (model.kind === "authorize") {
54063
- const capability = request.type === "authorize" ? request.capability : void 0;
54064
- const details = request.type === "authorize" ? request.details : void 0;
54065
- return /* @__PURE__ */ jsxs("div", {
54066
- className: "flex flex-col gap-3",
54067
- children: [
54068
- capability ? /* @__PURE__ */ jsxs("div", {
54069
- className: "flex items-center gap-2",
54070
- children: [/* @__PURE__ */ jsx("span", {
54071
- className: "text-xs font-medium text-muted",
54072
- children: t("interaction.authorize.capability")
54073
- }), /* @__PURE__ */ jsx(Badge, {
54074
- tone: "warning",
54075
- children: capability
54076
- })]
54077
- }) : null,
54078
- /* @__PURE__ */ jsx("p", {
54079
- className: "text-xs text-muted",
54080
- children: t("interaction.authorize.description")
54081
- }),
54082
- details !== void 0 ? /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
54083
- className: "mb-1 text-xs font-medium text-muted",
54084
- children: t("interaction.authorize.details")
54085
- }), /* @__PURE__ */ jsx("pre", {
54086
- className: "max-h-40 overflow-auto rounded-lg border border-border bg-canvas p-3 font-mono text-xs text-ink",
54087
- children: JSON.stringify(details, null, 2)
54088
- })] }) : null,
54089
- /* @__PURE__ */ jsxs("div", {
54090
- className: "flex items-center gap-2",
54091
- children: [/* @__PURE__ */ jsx(Button, {
54092
- onClick: () => resolve(shapeInteractionValue(model, {})),
54093
- children: t("interaction.allow")
54094
- }), /* @__PURE__ */ jsx(Button, {
54095
- variant: "danger",
54096
- onClick: cancel,
54097
- children: t("interaction.deny")
54098
- })]
54099
- })
54100
- ]
54101
- });
54102
- }
54103
- if (model.kind === "confirm") return /* @__PURE__ */ jsxs("div", {
54104
- className: "flex items-center gap-2",
54105
- children: [/* @__PURE__ */ jsx(Button, {
54106
- onClick: () => resolve(shapeInteractionValue(model, { confirmed: true })),
54107
- children: t("interaction.confirm")
54108
- }), /* @__PURE__ */ jsx(Button, {
54109
- variant: "secondary",
54110
- onClick: cancel,
54111
- children: t("interaction.cancel")
54112
- })]
54113
- });
54114
- if (model.kind === "select") return /* @__PURE__ */ jsxs("div", {
54115
- className: "flex flex-col gap-3",
54116
- children: [/* @__PURE__ */ jsx("ul", {
54117
- className: "flex flex-col gap-1.5",
54118
- children: (model.controls[0]?.options ?? []).map((option, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
54119
- type: "button",
54120
- onClick: () => resolve(shapeInteractionValue(model, { selected: option.value })),
54121
- className: "w-full cursor-pointer rounded-lg border border-border bg-surface px-3.5 py-2.5 text-left text-sm text-ink transition-colors hover:border-ring hover:bg-subtle",
54122
- children: option.label
54123
- }) }, i))
54124
- }), /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, {
54125
- variant: "secondary",
54126
- onClick: cancel,
54127
- children: t("interaction.cancel")
54128
- }) })]
54129
- });
54130
- return /* @__PURE__ */ jsxs("form", {
54131
- ref: formRef,
54132
- noValidate: true,
54133
- className: "flex flex-col gap-3",
54134
- onSubmit: (event) => {
54135
- event.preventDefault();
54136
- submitForm();
54137
- },
54138
- children: [model.controls.map((control) => /* @__PURE__ */ jsx(Field, {
54139
- control,
54140
- invalid: invalid.includes(control.name)
54141
- }, control.name)), /* @__PURE__ */ jsxs("div", {
54142
- className: "flex items-center gap-2",
54143
- children: [/* @__PURE__ */ jsx(Button, {
54144
- type: "submit",
54145
- children: t("interaction.submit")
54146
- }), /* @__PURE__ */ jsx(Button, {
54147
- variant: "secondary",
54148
- onClick: cancel,
54149
- children: t("interaction.cancel")
54150
- })]
53632
+ children: /* @__PURE__ */ jsx(NativeSpecSurface, {
53633
+ surfaceId: request.id,
53634
+ spec,
53635
+ actions: INTERACTION_ACTIONS$1,
53636
+ onAction: handleAction
53637
+ })
54151
53638
  })]
54152
53639
  });
54153
53640
  }
54154
53641
 
54155
53642
  //#endregion
54156
53643
  //#region src/react/InterruptedBanner.tsx
53644
+ const resumable = (list) => list.filter((entry) => !isUnsupportedRunSnapshot(entry));
54157
53645
  /**
54158
53646
  * 未完成对话提示条:挂载/会话切换时检查 interrupted 快照,非空则顶部 banner
54159
53647
  * + Resume(engine.resume 后等待中的表单重新进入 bridge.pending)。
53648
+ * @stable
54160
53649
  */
54161
53650
  function InterruptedBanner({ engine, sessionId }) {
54162
53651
  const t = useT();
@@ -54164,7 +53653,7 @@ function InterruptedBanner({ engine, sessionId }) {
54164
53653
  useEffect(() => {
54165
53654
  let cancelled = false;
54166
53655
  engine.listInterrupted().then((list) => {
54167
- if (!cancelled) setInterrupted(list);
53656
+ if (!cancelled) setInterrupted(resumable(list));
54168
53657
  }).catch(() => {});
54169
53658
  return () => {
54170
53659
  cancelled = true;
@@ -54174,7 +53663,7 @@ function InterruptedBanner({ engine, sessionId }) {
54174
53663
  if (!current) return null;
54175
53664
  const resume = () => {
54176
53665
  engine.resume(current.runId).then(async () => {
54177
- setInterrupted(await engine.listInterrupted());
53666
+ setInterrupted(resumable(await engine.listInterrupted()));
54178
53667
  });
54179
53668
  };
54180
53669
  return /* @__PURE__ */ jsxs("div", {
@@ -54208,6 +53697,68 @@ function InterruptedBanner({ engine, sessionId }) {
54208
53697
  });
54209
53698
  }
54210
53699
 
53700
+ //#endregion
53701
+ //#region src/react/SpecInteraction.tsx
53702
+ /** 交互表单的两个动作:与 surface 侧共用 catalog 的 submit / cancel 语义 */
53703
+ const INTERACTION_ACTIONS = [{
53704
+ id: "submit",
53705
+ intent: "submit"
53706
+ }, {
53707
+ id: "cancel",
53708
+ intent: "cancel"
53709
+ }];
53710
+ /** 各档的 spec 渲染入口——交互(路径 A)与 surface(路径 B)在同一档下命中同一个组件 */
53711
+ const SURFACES = {
53712
+ a2ui: A2uiSpecSurface,
53713
+ openui: OpenUiSpecSurface,
53714
+ vercel: JsonRenderSpecSurface
53715
+ };
53716
+ /** optional peer 探测:缺包时通知通道,桥据此粘性降级 native(不悬挂请求、不阻断 run) */
53717
+ const PROBES = {
53718
+ a2ui: probeA2uiAvailability,
53719
+ openui: probeOpenUiAvailability,
53720
+ vercel: probeJsonRenderAvailability
53721
+ };
53722
+ const MISSING_PEER = {
53723
+ a2ui: "@a2ui/lit and @a2ui/web_core are not installed in this host",
53724
+ openui: "@openuidev/react-lang is not installed in this host",
53725
+ vercel: "@json-render/core and @json-render/react are not installed in this host"
53726
+ };
53727
+ /**
53728
+ * 非 native 三档的交互视图(路径 A):订阅 SpecInteractionChannel(core 产出 catalog
53729
+ * 节点树),交给本档 surface 侧同一个渲染入口渲染;提交/取消经 handleAction 回传。
53730
+ * 未挂载时桥直接降级 native(不悬挂请求)。
53731
+ * @experimental
53732
+ */
53733
+ function SpecInteraction({ channel, renderer }) {
53734
+ const t = useT();
53735
+ const session = useSyncExternalStore(channel.subscribe, () => channel.current);
53736
+ useEffect(() => {
53737
+ channel.labelsFor = (request) => interactionLabels(request, t);
53738
+ }, [channel, t]);
53739
+ useEffect(() => {
53740
+ channel.attach();
53741
+ return () => channel.detach();
53742
+ }, [channel]);
53743
+ useEffect(() => {
53744
+ let cancelled = false;
53745
+ PROBES[renderer]().then((available) => {
53746
+ if (!cancelled && !available) channel.fail(MISSING_PEER[renderer]);
53747
+ });
53748
+ return () => {
53749
+ cancelled = true;
53750
+ };
53751
+ }, [channel, renderer]);
53752
+ if (!session) return null;
53753
+ const Surface = SURFACES[renderer];
53754
+ return /* @__PURE__ */ jsx(Surface, {
53755
+ surfaceId: session.request.id,
53756
+ spec: session.spec,
53757
+ actions: INTERACTION_ACTIONS,
53758
+ onAction: (event) => channel.handleAction(event)
53759
+ });
53760
+ }
53761
+
54211
53762
  //#endregion
54212
53763
  //#region src/react/SettingsDrawer.tsx
54213
53764
  const PROVIDERS = [
@@ -54231,7 +53782,7 @@ function createProbeClient(provider, form) {
54231
53782
  model: form.model
54232
53783
  });
54233
53784
  }
54234
- /** 设置抽屉:LLM 配置(三协议供应商 / 能力探测 / Demo model 标识 / 流式与 temperature)+ 外观(主题/语言) */
53785
+ /** 设置抽屉:LLM 配置(三协议供应商 / 能力探测 / Demo model 标识 / 流式与 temperature)+ 外观(主题/语言) @stable */
54235
53786
  function SettingsDrawer({ open, llmConfig, runtimeConfig, theme, locale, renderer, onAppearanceChange, onSaved, onClose }) {
54236
53787
  const t = useT();
54237
53788
  const [provider, setProvider] = useState("openai-compatible");
@@ -54601,53 +54152,6 @@ function useChatLayout(layout = "auto") {
54601
54152
  };
54602
54153
  }
54603
54154
 
54604
- //#endregion
54605
- //#region src/react/VercelPayloadPreview.tsx
54606
- /**
54607
- * vercel 档(payload 预览):不渲染表单,展示 InteractionRequest 经 toVercelToolInvocation
54608
- * 转换后的 Vercel AI SDK 数据契约 JSON 卡。仅提供 Cancel 结束交互(非完整运行时)。
54609
- */
54610
- function VercelPayloadPreview({ bridge }) {
54611
- const t = useT();
54612
- const pending = useSyncExternalStore(bridge.subscribe, () => bridge.pending);
54613
- if (!pending) return null;
54614
- const payload = toVercelToolInvocation(pending);
54615
- return /* @__PURE__ */ jsxs("div", {
54616
- "data-testid": "vercel-payload-preview",
54617
- className: "rounded-card border border-border bg-surface shadow-card",
54618
- children: [/* @__PURE__ */ jsxs("div", {
54619
- className: "flex items-center gap-2 px-4 pt-4",
54620
- children: [/* @__PURE__ */ jsx("h3", {
54621
- className: "font-display text-sm font-semibold text-ink",
54622
- children: t("vercel.preview.title")
54623
- }), /* @__PURE__ */ jsx(Badge, {
54624
- tone: "neutral",
54625
- children: t("vercel.preview.badge")
54626
- })]
54627
- }), /* @__PURE__ */ jsxs("div", {
54628
- className: "flex flex-col gap-3 px-4 py-4",
54629
- children: [
54630
- /* @__PURE__ */ jsx("p", {
54631
- className: "text-xs text-muted",
54632
- children: t("vercel.preview.description")
54633
- }),
54634
- /* @__PURE__ */ jsx("pre", {
54635
- className: "max-h-64 overflow-auto rounded-lg border border-border bg-canvas p-3 font-mono text-xs text-ink",
54636
- children: JSON.stringify(payload, null, 2)
54637
- }),
54638
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, {
54639
- variant: "secondary",
54640
- onClick: () => bridge.resolve({
54641
- id: pending.id,
54642
- cancelled: true
54643
- }),
54644
- children: t("interaction.cancel")
54645
- }) })
54646
- ]
54647
- })]
54648
- });
54649
- }
54650
-
54651
54155
  //#endregion
54652
54156
  //#region src/react/Chatbot.tsx
54653
54157
  const toErrorMessage = (e) => e instanceof Error ? e.message : String(e);
@@ -54670,14 +54174,17 @@ async function downloadArtifactFile(storage, chatRoot, file) {
54670
54174
  /**
54671
54175
  * ChatEngine owns message/session/runtime state while assistant-ui Base owns the
54672
54176
  * presentation shell and accessible thread primitives.
54177
+ * @stable
54673
54178
  */
54674
- function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, renderer: rendererProp, surfaceRegistry, layout = "auto", onAppearanceChange }) {
54179
+ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, renderer: rendererProp, surfaceRegistry, layout = "auto", onAppearanceChange, onEngineReady }) {
54675
54180
  const engine = useMemo(() => new ChatEngine(adapter, {
54676
54181
  ...config?.chatRoot ? { chatRoot: config.chatRoot } : {},
54677
54182
  ...config?.llm ? { llm: config.llm } : {},
54678
54183
  ...config?.loopConfig ? { loopConfig: config.loopConfig } : {},
54679
54184
  ...config?.runtimeConfig ? { runtimeConfig: config.runtimeConfig } : {},
54680
54185
  ...config?.generativeUi ? { generativeUi: true } : {},
54186
+ ...config?.hooks ? { hooks: config.hooks } : {},
54187
+ ...config?.governance ? { governance: config.governance } : {},
54681
54188
  ...rendererProp ? { renderer: rendererProp } : {}
54682
54189
  }), [
54683
54190
  adapter,
@@ -54686,8 +54193,13 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54686
54193
  config?.loopConfig,
54687
54194
  config?.runtimeConfig,
54688
54195
  config?.generativeUi,
54196
+ config?.hooks,
54197
+ config?.governance,
54689
54198
  rendererProp
54690
54199
  ]);
54200
+ useEffect(() => {
54201
+ onEngineReady?.(engine);
54202
+ }, [engine, onEngineReady]);
54691
54203
  const [theme, setTheme] = useState(themeProp ?? "light");
54692
54204
  const [locale, setLocale] = useState(localeProp ?? "en");
54693
54205
  const [renderer, setRenderer] = useState(rendererProp ?? "native");
@@ -54707,6 +54219,11 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54707
54219
  const [sessions, setSessions] = useState([]);
54708
54220
  /** 首次 listSessions 未完成(threads 客户端的 isLoading) */
54709
54221
  const [sessionsLoading, setSessionsLoading] = useState(true);
54222
+ /** 分页游标:非空即「还有更早的一页」。页大小归 SessionStore,这里不覆写 limit */
54223
+ const [sessionsCursor, setSessionsCursor] = useState();
54224
+ const [messagesCursor, setMessagesCursor] = useState();
54225
+ const [loadingEarlierSessions, setLoadingEarlierSessions] = useState(false);
54226
+ const [loadingEarlierMessages, setLoadingEarlierMessages] = useState(false);
54710
54227
  const [currentSessionId, setCurrentSessionId] = useState();
54711
54228
  const [sending, setSending] = useState(false);
54712
54229
  /** 当前活跃 runId(run-started 捕获;Stop 按钮 engine.cancel 用) */
@@ -54716,14 +54233,15 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54716
54233
  const [settingsOpen, setSettingsOpen] = useState(false);
54717
54234
  /** 当前进行中 run 的 part 累积器(流式正文 / 工具 / 生命周期步进的唯一来源) */
54718
54235
  const [live, setLive] = useState();
54719
- /** a2ui 档交互容器显隐(interaction-requested/resolved 事件驱动) */
54720
- const [a2uiActive, setA2uiActive] = useState(false);
54721
54236
  const [interactionPending, setInteractionPending] = useState(false);
54722
54237
  /** pending 交互归属的会话(跨会话查看时隐藏交互卡,防串台) */
54723
54238
  const [interactionSessionId, setInteractionSessionId] = useState();
54724
54239
  /** currentSessionId 的 ref 镜像(事件订阅闭包 [engine] 内读取最新值) */
54725
54240
  const sessionRef = useRef(currentSessionId);
54726
54241
  sessionRef.current = currentSessionId;
54242
+ /** sessions 的 ref 镜像(handleSend 判定「这次是否会生成标题」,不想为此进依赖表) */
54243
+ const sessionsRef = useRef(sessions);
54244
+ sessionsRef.current = sessions;
54727
54245
  const { containerRef, resolved: resolvedLayout } = useChatLayout(layout);
54728
54246
  /** 附件按钮只在存储确实可写时出现(R11:不渲染点了就报错的按钮) */
54729
54247
  const [attachmentsReady, setAttachmentsReady] = useState(false);
@@ -54742,30 +54260,26 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54742
54260
  cancelled = true;
54743
54261
  };
54744
54262
  }, [adapter, engine]);
54745
- /** a2ui 交互容器 ref:挂载即注入引擎(卸载传 null),引擎懒建 LitRendererBridge 渲染其中;
54746
- 同时为容器配置 @a2ui/markdown-it(optional peer,缺失时保持纯文本降级) */
54747
- const interactionMountRef = useCallback((el) => {
54748
- engine.setInteractionMount(el);
54749
- if (el) configureA2uiMarkdown(el).then((configured) => {
54750
- if (!configured) console.warn("A2UI markdown renderer is not configured: install @a2ui/markdown-it to render markdown in A2UI interactions");
54751
- });
54752
- }, [engine]);
54753
54263
  const refreshSessions = useCallback(async () => {
54754
- setSessions(await engine.listSessions());
54264
+ const page = await engine.listSessions();
54265
+ setSessions(page.items);
54266
+ setSessionsCursor(page.nextCursor);
54755
54267
  }, [engine]);
54756
54268
  useEffect(() => {
54757
54269
  let cancelled = false;
54758
54270
  (async () => {
54759
- const list = await engine.listSessions();
54271
+ const page = await engine.listSessions();
54760
54272
  if (cancelled) return;
54761
- setSessions(list);
54273
+ setSessions(page.items);
54274
+ setSessionsCursor(page.nextCursor);
54762
54275
  setSessionsLoading(false);
54763
- const latest = list[list.length - 1];
54276
+ const latest = page.items[page.items.length - 1];
54764
54277
  if (!latest) return;
54765
54278
  const history = await engine.selectSession(latest.id);
54766
54279
  if (cancelled) return;
54767
54280
  setCurrentSessionId(latest.id);
54768
- setMessages(history);
54281
+ setMessages(history.items);
54282
+ setMessagesCursor(history.nextCursor);
54769
54283
  })().catch((e) => {
54770
54284
  if (!cancelled) {
54771
54285
  setSessionsLoading(false);
@@ -54788,12 +54302,10 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54788
54302
  setMessages((prev) => prev.some((message) => message.id === event.message.id) ? prev : [...prev, event.message]);
54789
54303
  break;
54790
54304
  case "interaction-requested":
54791
- setA2uiActive(true);
54792
54305
  setInteractionPending(true);
54793
54306
  setInteractionSessionId(sessionRef.current);
54794
54307
  break;
54795
54308
  case "interaction-resolved":
54796
- setA2uiActive(false);
54797
54309
  setInteractionPending(false);
54798
54310
  setInteractionSessionId(void 0);
54799
54311
  break;
@@ -54818,12 +54330,16 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54818
54330
  }), [engine]);
54819
54331
  const handleSend = useCallback((text, attachments = []) => {
54820
54332
  (async () => {
54821
- if (!currentSessionId) {
54333
+ let sessionId = currentSessionId;
54334
+ if (!sessionId) {
54822
54335
  const meta = await engine.createSession();
54336
+ sessionId = meta.id;
54823
54337
  setCurrentSessionId(meta.id);
54824
54338
  await refreshSessions();
54825
54339
  }
54340
+ const needsTitle = sessionsRef.current.find((session) => session.id === sessionId)?.title === void 0;
54826
54341
  await engine.send(text, attachments);
54342
+ if (needsTitle) await refreshSessions();
54827
54343
  })().catch((e) => setError({ message: toErrorMessage(e) }));
54828
54344
  }, [
54829
54345
  engine,
@@ -54845,14 +54361,41 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54845
54361
  const handleSelect = useCallback((id) => {
54846
54362
  engine.selectSession(id).then((history) => {
54847
54363
  setCurrentSessionId(id);
54848
- setMessages(history);
54364
+ setMessages(history.items);
54365
+ setMessagesCursor(history.nextCursor);
54849
54366
  setDrawerOpen(false);
54850
54367
  }).catch((e) => setError({ message: toErrorMessage(e) }));
54851
54368
  }, [engine]);
54369
+ /** 向历史方向再取一页:页内升序,所以是**前插**而不是追加 */
54370
+ const handleLoadEarlierMessages = useCallback(() => {
54371
+ if (!messagesCursor || loadingEarlierMessages) return;
54372
+ setLoadingEarlierMessages(true);
54373
+ engine.loadMoreMessages(messagesCursor).then((page) => {
54374
+ setMessages((prev) => [...page.items, ...prev]);
54375
+ setMessagesCursor(page.nextCursor);
54376
+ }).catch((e) => setError({ message: toErrorMessage(e) })).finally(() => setLoadingEarlierMessages(false));
54377
+ }, [
54378
+ engine,
54379
+ messagesCursor,
54380
+ loadingEarlierMessages
54381
+ ]);
54382
+ const handleLoadEarlierSessions = useCallback(() => {
54383
+ if (!sessionsCursor || loadingEarlierSessions) return;
54384
+ setLoadingEarlierSessions(true);
54385
+ engine.listSessions({ cursor: sessionsCursor }).then((page) => {
54386
+ setSessions((prev) => [...page.items, ...prev]);
54387
+ setSessionsCursor(page.nextCursor);
54388
+ }).catch((e) => setError({ message: toErrorMessage(e) })).finally(() => setLoadingEarlierSessions(false));
54389
+ }, [
54390
+ engine,
54391
+ sessionsCursor,
54392
+ loadingEarlierSessions
54393
+ ]);
54852
54394
  const handleCreate = useCallback(() => {
54853
54395
  engine.createSession().then(async (meta) => {
54854
54396
  setCurrentSessionId(meta.id);
54855
54397
  setMessages([]);
54398
+ setMessagesCursor(void 0);
54856
54399
  await refreshSessions();
54857
54400
  }).catch((e) => setError({ message: toErrorMessage(e) }));
54858
54401
  }, [engine, refreshSessions]);
@@ -54917,7 +54460,12 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54917
54460
  "data-layout": resolvedLayout,
54918
54461
  className: `webskill-aui-shell flex h-full min-h-0 flex-row font-sans text-ink ${theme === "dark" ? "dark" : ""}`,
54919
54462
  children: [
54920
- /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(AssistantUiSessionList, { className: "hidden lg:flex" }), /* @__PURE__ */ jsx(Sheet, {
54463
+ /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(AssistantUiSessionList, {
54464
+ className: "hidden lg:flex",
54465
+ hasEarlier: sessionsCursor !== void 0,
54466
+ loadingEarlier: loadingEarlierSessions,
54467
+ onLoadEarlier: handleLoadEarlierSessions
54468
+ }), /* @__PURE__ */ jsx(Sheet, {
54921
54469
  open: drawerOpen,
54922
54470
  onOpenChange: setDrawerOpen,
54923
54471
  children: /* @__PURE__ */ jsx(SheetContent, {
@@ -54926,7 +54474,10 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54926
54474
  className: "p-0 lg:hidden",
54927
54475
  children: /* @__PURE__ */ jsx(AssistantUiSessionList, {
54928
54476
  className: "h-full w-full border-r-0",
54929
- onNavigate: () => setDrawerOpen(false)
54477
+ onNavigate: () => setDrawerOpen(false),
54478
+ hasEarlier: sessionsCursor !== void 0,
54479
+ loadingEarlier: loadingEarlierSessions,
54480
+ onLoadEarlier: handleLoadEarlierSessions
54930
54481
  })
54931
54482
  })
54932
54483
  })] }),
@@ -54959,6 +54510,10 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54959
54510
  }) : null,
54960
54511
  /* @__PURE__ */ jsx(AssistantUiMessageList, {
54961
54512
  messages,
54513
+ ...messagesCursor !== void 0 ? { earlier: {
54514
+ loading: loadingEarlierMessages,
54515
+ onLoad: handleLoadEarlierMessages
54516
+ } } : {},
54962
54517
  renderMessage: (message) => /* @__PURE__ */ jsx(AssistantUiMessage, {
54963
54518
  message,
54964
54519
  onRetry: handleRetry,
@@ -54971,18 +54526,14 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54971
54526
  }),
54972
54527
  (() => {
54973
54528
  const interactionVisible = interactionSessionId === void 0 || interactionSessionId === currentSessionId;
54974
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
54975
- renderer === "a2ui" ? /* @__PURE__ */ jsx("div", {
54976
- ref: interactionMountRef,
54977
- "data-testid": "a2ui-interaction-mount",
54978
- className: interactionVisible && a2uiActive ? void 0 : "hidden"
54979
- }) : null,
54980
- renderer === "openui" ? /* @__PURE__ */ jsx("div", {
54981
- className: interactionVisible ? void 0 : "hidden",
54982
- children: /* @__PURE__ */ jsx(OpenUiInteraction, { channel: engine.openUiChannel })
54983
- }) : null,
54984
- interactionVisible ? renderer === "vercel" ? /* @__PURE__ */ jsx(VercelPayloadPreview, { bridge: engine.bridge }) : /* @__PURE__ */ jsx(InteractionCard, { bridge: engine.bridge }) : null
54985
- ] });
54529
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [renderer !== "native" ? /* @__PURE__ */ jsx("div", {
54530
+ "data-testid": "spec-interaction-slot",
54531
+ className: interactionVisible ? void 0 : "hidden",
54532
+ children: /* @__PURE__ */ jsx(SpecInteraction, {
54533
+ channel: engine.interactionChannel,
54534
+ renderer
54535
+ })
54536
+ }) : null, interactionVisible ? /* @__PURE__ */ jsx(InteractionCard, { bridge: engine.bridge }) : null] });
54986
54537
  })(),
54987
54538
  /* @__PURE__ */ jsx(ResultBlocksPro, {
54988
54539
  bridge: engine.bridge,
@@ -54996,13 +54547,11 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
54996
54547
  }) : null,
54997
54548
  renderer === "vercel" && currentRunId ? /* @__PURE__ */ jsx(VercelSurfaceHost, {
54998
54549
  bridge: engine.bridge,
54999
- runId: currentRunId,
55000
- ...surfaceRegistry ? { registry: surfaceRegistry } : {}
54550
+ runId: currentRunId
55001
54551
  }) : null,
55002
54552
  renderer === "openui" && currentRunId ? /* @__PURE__ */ jsx(OpenUiSurfaceHost, {
55003
54553
  bridge: engine.bridge,
55004
- runId: currentRunId,
55005
- ...surfaceRegistry ? { registry: surfaceRegistry } : {}
54554
+ runId: currentRunId
55006
54555
  }) : null,
55007
54556
  renderer === "a2ui" && currentRunId ? /* @__PURE__ */ jsx(A2uiSurfaceHost, {
55008
54557
  bridge: engine.bridge,
@@ -55044,4 +54593,52 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
55044
54593
  }
55045
54594
 
55046
54595
  //#endregion
55047
- export { A2uiSurfaceHost, A2uiSurfaceSnapshotHost, ChatEngine, Chatbot, CompositeUiBridge, ErrorCard, InteractionCard, InterruptedBanner, OpenUiChannel, OpenUiInteraction, OpenUiSurfaceHost, OpenUiSurfaceSnapshotHost, ResultBlockList, ResultBlocksPro, SettingsDrawer, SkillBadges, VercelPayloadPreview, VercelSurfaceHost, VercelSurfaceSnapshotHost, chatbotDictionary, configureA2uiMarkdown, probeA2uiAvailability, probeOpenUiAvailability, useT };
54596
+ //#region src/react/VercelPayloadPreview.tsx
54597
+ /**
54598
+ * vercel 档(payload 预览):不渲染表单,展示 InteractionRequest 经 toVercelToolInvocation
54599
+ * 转换后的 Vercel AI SDK 数据契约 JSON 卡。仅提供 Cancel 结束交互(非完整运行时)。
54600
+ * @experimental
54601
+ */
54602
+ function VercelPayloadPreview({ bridge }) {
54603
+ const t = useT();
54604
+ const pending = useSyncExternalStore(bridge.subscribe, () => bridge.pending);
54605
+ if (!pending) return null;
54606
+ const payload = toVercelToolInvocation(pending);
54607
+ return /* @__PURE__ */ jsxs("div", {
54608
+ "data-testid": "vercel-payload-preview",
54609
+ className: "rounded-card border border-border bg-surface shadow-card",
54610
+ children: [/* @__PURE__ */ jsxs("div", {
54611
+ className: "flex items-center gap-2 px-4 pt-4",
54612
+ children: [/* @__PURE__ */ jsx("h3", {
54613
+ className: "font-display text-sm font-semibold text-ink",
54614
+ children: t("vercel.preview.title")
54615
+ }), /* @__PURE__ */ jsx(Badge, {
54616
+ tone: "neutral",
54617
+ children: t("vercel.preview.badge")
54618
+ })]
54619
+ }), /* @__PURE__ */ jsxs("div", {
54620
+ className: "flex flex-col gap-3 px-4 py-4",
54621
+ children: [
54622
+ /* @__PURE__ */ jsx("p", {
54623
+ className: "text-xs text-muted",
54624
+ children: t("vercel.preview.description")
54625
+ }),
54626
+ /* @__PURE__ */ jsx("pre", {
54627
+ className: "max-h-64 overflow-auto rounded-lg border border-border bg-canvas p-3 font-mono text-xs text-ink",
54628
+ children: JSON.stringify(payload, null, 2)
54629
+ }),
54630
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, {
54631
+ variant: "secondary",
54632
+ onClick: () => bridge.resolve({
54633
+ id: pending.id,
54634
+ cancelled: true
54635
+ }),
54636
+ children: t("interaction.cancel")
54637
+ }) })
54638
+ ]
54639
+ })]
54640
+ });
54641
+ }
54642
+
54643
+ //#endregion
54644
+ export { A2uiSurfaceHost, A2uiSurfaceSnapshotHost, ChatEngine, Chatbot, CompositeUiBridge, DEFAULT_RENDERER_CAPABILITIES, ErrorCard, InteractionCard, InterruptedBanner, OpenUiSurfaceHost, OpenUiSurfaceSnapshotHost, ResultBlockList, ResultBlocksPro, SettingsDrawer, SkillBadges, SpecInteraction, VercelPayloadPreview, VercelSurfaceHost, VercelSurfaceSnapshotHost, chatbotDictionary, configureA2uiMarkdown, probeA2uiAvailability, probeOpenUiAvailability, useT };