@runtypelabs/persona 4.7.0 → 4.8.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.
Files changed (117) hide show
  1. package/dist/animations/glyph-cycle.cjs +2 -2
  2. package/dist/animations/glyph-cycle.d.cts +1 -1
  3. package/dist/animations/glyph-cycle.d.ts +1 -1
  4. package/dist/animations/glyph-cycle.js +2 -2
  5. package/dist/animations/{types-CSmiKRVa.d.cts → types-BsZtXPKK.d.cts} +43 -3
  6. package/dist/animations/{types-CSmiKRVa.d.ts → types-BsZtXPKK.d.ts} +43 -3
  7. package/dist/animations/wipe.cjs +2 -2
  8. package/dist/animations/wipe.d.cts +1 -1
  9. package/dist/animations/wipe.d.ts +1 -1
  10. package/dist/chunk-5EIIHQLQ.js +1 -0
  11. package/dist/codegen.cjs +12 -12
  12. package/dist/codegen.js +14 -14
  13. package/dist/index.cjs +91 -68
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +877 -172
  16. package/dist/index.d.ts +877 -172
  17. package/dist/index.global.js +81 -57
  18. package/dist/index.global.js.map +1 -1
  19. package/dist/index.js +91 -68
  20. package/dist/index.js.map +1 -1
  21. package/dist/install.global.js +1 -1
  22. package/dist/install.global.js.map +1 -1
  23. package/dist/launcher.global.js +3 -2
  24. package/dist/launcher.global.js.map +1 -1
  25. package/dist/markdown-parsers.js +24 -24
  26. package/dist/plugin-kit.cjs +1 -1
  27. package/dist/plugin-kit.js +1 -1
  28. package/dist/runtype-tts-entry-UJAEF7NZ.js +1 -0
  29. package/dist/runtype-tts.js +1 -1
  30. package/dist/session-reconnect-JKIJBHS5.js +1 -0
  31. package/dist/smart-dom-reader.cjs +17 -17
  32. package/dist/smart-dom-reader.d.cts +753 -15
  33. package/dist/smart-dom-reader.d.ts +753 -15
  34. package/dist/smart-dom-reader.js +17 -17
  35. package/dist/testing.cjs +3 -3
  36. package/dist/testing.js +3 -3
  37. package/dist/theme-editor-preview.cjs +81 -58
  38. package/dist/theme-editor-preview.d.cts +761 -15
  39. package/dist/theme-editor-preview.d.ts +761 -15
  40. package/dist/theme-editor-preview.js +81 -58
  41. package/dist/theme-editor.cjs +6 -6
  42. package/dist/theme-editor.d.cts +753 -15
  43. package/dist/theme-editor.d.ts +753 -15
  44. package/dist/theme-editor.js +10 -10
  45. package/dist/theme-reference.cjs +1 -1
  46. package/dist/theme-reference.d.cts +74 -0
  47. package/dist/theme-reference.d.ts +74 -0
  48. package/dist/theme-reference.js +1 -1
  49. package/dist/voice-worklet-player.cjs +2 -2
  50. package/dist/voice-worklet-player.js +2 -2
  51. package/dist/webmcp-polyfill.js +2 -2
  52. package/dist/widget.css +1 -1
  53. package/package.json +2 -3
  54. package/src/artifacts-session.test.ts +178 -0
  55. package/src/client.test.ts +186 -1
  56. package/src/client.ts +92 -9
  57. package/src/components/artifact-card.test.ts +333 -0
  58. package/src/components/artifact-card.ts +75 -28
  59. package/src/components/artifact-inline.test.ts +1328 -0
  60. package/src/components/artifact-inline.ts +920 -0
  61. package/src/components/artifact-pane.test.ts +1042 -0
  62. package/src/components/artifact-pane.ts +440 -131
  63. package/src/components/artifact-preview.test.ts +1155 -0
  64. package/src/components/artifact-preview.ts +994 -0
  65. package/src/components/pill-composer-builder.test.ts +6 -2
  66. package/src/components/pill-composer-builder.ts +6 -6
  67. package/src/components/reasoning-bubble.ts +1 -13
  68. package/src/components/registry.ts +38 -3
  69. package/src/components/tool-bubble.ts +1 -13
  70. package/src/defaults.ts +1 -0
  71. package/src/generated/runtype-openapi-contract.ts +55 -3
  72. package/src/index-core.ts +20 -1
  73. package/src/index.ts +8 -0
  74. package/src/markdown-parsers-loader.test.ts +158 -0
  75. package/src/markdown-parsers-loader.ts +74 -9
  76. package/src/runtime/host-layout.test.ts +163 -0
  77. package/src/runtime/host-layout.ts +110 -7
  78. package/src/runtime/init.ts +18 -61
  79. package/src/session.ts +76 -22
  80. package/src/styles/widget.css +773 -26
  81. package/src/theme-editor/preview.ts +2 -0
  82. package/src/theme-editor/sections.test.ts +26 -1
  83. package/src/theme-editor/sections.ts +10 -2
  84. package/src/theme-reference.ts +2 -2
  85. package/src/tool-call-display-defaults.test.ts +1 -0
  86. package/src/types/theme.ts +77 -0
  87. package/src/types.ts +516 -17
  88. package/src/ui.artifact-pane-gating.test.ts +636 -0
  89. package/src/ui.component-directive.test.ts +104 -0
  90. package/src/ui.composer-bar.test.ts +60 -2
  91. package/src/ui.detached-panel.test.ts +1049 -0
  92. package/src/ui.tool-display.test.ts +51 -0
  93. package/src/ui.ts +698 -109
  94. package/src/utils/artifact-custom-actions.ts +128 -0
  95. package/src/utils/artifact-display.test.ts +42 -0
  96. package/src/utils/artifact-display.ts +84 -0
  97. package/src/utils/artifact-file.test.ts +116 -0
  98. package/src/utils/artifact-file.ts +117 -0
  99. package/src/utils/artifact-gate.test.ts +112 -5
  100. package/src/utils/artifact-gate.ts +39 -14
  101. package/src/utils/artifact-loading-status.ts +55 -0
  102. package/src/utils/artifact-status-label.ts +190 -0
  103. package/src/utils/buttons.ts +7 -1
  104. package/src/utils/code-highlight.test.ts +186 -0
  105. package/src/utils/code-highlight.ts +400 -0
  106. package/src/utils/icons.ts +2 -0
  107. package/src/utils/roving-tablist.test.ts +152 -0
  108. package/src/utils/roving-tablist.ts +111 -0
  109. package/src/utils/spinner.ts +45 -0
  110. package/src/utils/theme.test.ts +48 -0
  111. package/src/utils/theme.ts +7 -0
  112. package/src/utils/tokens.ts +91 -0
  113. package/src/utils/tool-loading-animation.test.ts +32 -0
  114. package/src/utils/tool-loading-animation.ts +24 -0
  115. package/dist/chunk-DFBSCFYN.js +0 -1
  116. package/dist/runtype-tts-entry-HFUV2UF7.js +0 -1
  117. package/dist/session-reconnect-U77QFUR7.js +0 -1
@@ -1,3 +1,5 @@
1
+ import { IconNode } from 'lucide';
2
+
1
3
  /**
2
4
  * Plugin interface for customizing widget components
3
5
  */
@@ -445,6 +447,10 @@ interface PanelTokens extends ComponentTokenSet {
445
447
  maxWidth: string;
446
448
  height: string;
447
449
  maxHeight: string;
450
+ /** Gap between the detached panel and its region edges. Only used when detached. */
451
+ inset?: string;
452
+ /** Background of the region revealed behind a detached panel. */
453
+ canvasBackground?: string;
448
454
  }
449
455
  interface HeaderTokens extends ComponentTokenSet {
450
456
  background: TokenReference<'color'>;
@@ -609,6 +615,14 @@ interface ArtifactToolbarTokens {
609
615
  iconBorder?: string;
610
616
  toggleGroupGap?: string;
611
617
  toggleBorderRadius?: string;
618
+ /** Inner padding of the segmented view/source toggle pill. */
619
+ toggleGroupPadding?: string;
620
+ /** Border of the segmented view/source toggle pill (e.g., `none`). */
621
+ toggleGroupBorder?: string;
622
+ /** Corner radius of the segmented view/source toggle pill. */
623
+ toggleGroupBorderRadius?: string;
624
+ /** Background of the segmented view/source toggle pill. */
625
+ toggleGroupBackground?: string;
612
626
  copyBackground?: string;
613
627
  copyBorder?: string;
614
628
  copyColor?: string;
@@ -640,6 +654,16 @@ interface ArtifactTabTokens {
640
654
  /** Tab list container padding (CSS shorthand). */
641
655
  listPadding?: string;
642
656
  }
657
+ /** Artifact reference card (chat thread) chrome. */
658
+ interface ArtifactCardTokens {
659
+ background?: string;
660
+ /** Full border shorthand (e.g. `1px solid #e5e7eb`). */
661
+ border?: string;
662
+ borderRadius?: string;
663
+ hoverBackground?: string;
664
+ /** Border color on hover. */
665
+ hoverBorderColor?: string;
666
+ }
643
667
  /** Artifact pane chrome. */
644
668
  interface ArtifactPaneTokens {
645
669
  /**
@@ -650,6 +674,54 @@ interface ArtifactPaneTokens {
650
674
  background?: string;
651
675
  toolbarBackground?: string;
652
676
  }
677
+ /** Inline artifact block chrome (`display: "inline"` file preview). */
678
+ interface ArtifactInlineTokens {
679
+ /** Background of the inline preview frame. */
680
+ background?: string;
681
+ /** Full border shorthand for the frame (e.g. `1px solid #e5e7eb`). */
682
+ border?: string;
683
+ /** Border radius of the inline preview frame. */
684
+ borderRadius?: string;
685
+ /** Background of the title/toolbar chrome bar. */
686
+ chromeBackground?: string;
687
+ /** Bottom border of the title bar. */
688
+ chromeBorder?: string;
689
+ /** Title text color in the chrome bar (artifact basename). */
690
+ titleColor?: string;
691
+ /** Muted text color for the type label / streaming status. */
692
+ mutedColor?: string;
693
+ /** Preview iframe height inside the inline body. */
694
+ frameHeight?: string;
695
+ }
696
+ /**
697
+ * Syntax-highlighted artifact source view (pane + inline), rendered by
698
+ * `utils/code-highlight.ts`. One Light defaults ship in `widget.css`, with a
699
+ * One Dark override keyed off the widget's resolved color scheme (the
700
+ * `data-persona-color-scheme` root attribute, not the OS preference); set any
701
+ * of these to retheme the tokenizer palette and the line-number gutter.
702
+ */
703
+ interface CodeTokens {
704
+ /** Keywords, booleans, null (e.g. `const`, `true`). */
705
+ keywordColor?: string;
706
+ /** String and template literals; HTML attribute values. */
707
+ stringColor?: string;
708
+ /** Line and block comments. */
709
+ commentColor?: string;
710
+ /** Numeric literals; CSS hex colors / units. */
711
+ numberColor?: string;
712
+ /** HTML tag brackets + names; doctype. */
713
+ tagColor?: string;
714
+ /** HTML attribute names. */
715
+ attrColor?: string;
716
+ /** CSS property names; JSON object keys. */
717
+ propertyColor?: string;
718
+ /** Line-number gutter digits. */
719
+ lineNumberColor?: string;
720
+ /** Right border of the line-number gutter. */
721
+ gutterBorderColor?: string;
722
+ /** Background of the source-view code sheet (defaults to One Light/Dark editor background). */
723
+ background?: string;
724
+ }
653
725
  /** Icon button chrome (used by createIconButton). */
654
726
  interface IconButtonTokens {
655
727
  background?: string;
@@ -719,9 +791,13 @@ interface ComponentTokens {
719
791
  toolbar?: ArtifactToolbarTokens;
720
792
  tab?: ArtifactTabTokens;
721
793
  pane?: ArtifactPaneTokens;
794
+ card?: ArtifactCardTokens;
795
+ inline?: ArtifactInlineTokens;
722
796
  };
723
797
  /** Collapsible widget chrome (tool/reasoning/approval bubbles). */
724
798
  collapsibleWidget?: CollapsibleWidgetTokens;
799
+ /** Syntax-highlighted artifact source view (tokenizer palette + gutter). */
800
+ code?: CodeTokens;
725
801
  }
726
802
  interface PaletteExtras {
727
803
  transitions?: Record<string, string>;
@@ -764,6 +840,7 @@ type RuntypeExecutionStreamEvent = ({
764
840
  totalSteps?: number;
765
841
  type: "execution_start";
766
842
  }) | ({
843
+ claudeManagedAgentId?: string;
767
844
  completedAt?: string;
768
845
  durationMs?: number;
769
846
  executionId: string;
@@ -808,6 +885,15 @@ type RuntypeExecutionStreamEvent = ({
808
885
  completedAt?: string;
809
886
  content?: string;
810
887
  cost?: number;
888
+ estimatedContextBreakdown?: {
889
+ categories: Record<string, {
890
+ chars: number;
891
+ estimatedTokens: number;
892
+ }>;
893
+ contextWindowSize?: number;
894
+ estimatedTotalTokens: number;
895
+ estimatedUtilizationPercent?: number;
896
+ };
811
897
  executionId: string;
812
898
  fallback?: {
813
899
  attempts: Array<{
@@ -845,6 +931,7 @@ type RuntypeExecutionStreamEvent = ({
845
931
  type: "step_start";
846
932
  } | ({
847
933
  completedAt?: string;
934
+ cost?: number;
848
935
  durationMs?: number;
849
936
  error?: string;
850
937
  executionId: string;
@@ -950,6 +1037,11 @@ type RuntypeExecutionStreamEvent = ({
950
1037
  artifactType: "markdown" | "component";
951
1038
  component?: string;
952
1039
  executionId?: string;
1040
+ file?: {
1041
+ language?: string;
1042
+ mimeType: string;
1043
+ path: string;
1044
+ };
953
1045
  id: string;
954
1046
  seq?: number;
955
1047
  title?: string;
@@ -1058,6 +1150,14 @@ type RuntypeExecutionStreamEvent = ({
1058
1150
  awaitReason?: string;
1059
1151
  awaitedAt?: string;
1060
1152
  crawlId?: string;
1153
+ elicitation?: {
1154
+ message: string;
1155
+ mode: "form" | "url";
1156
+ pauseCount?: number;
1157
+ requestedSchema?: Record<string, unknown>;
1158
+ serverName?: string;
1159
+ url?: string;
1160
+ };
1061
1161
  executionId: string;
1062
1162
  origin?: "webmcp" | "sdk";
1063
1163
  pageOrigin?: string;
@@ -1157,6 +1257,14 @@ type RuntypeFlowSSEEvent = {
1157
1257
  awaitReason?: string;
1158
1258
  awaitedAt: string;
1159
1259
  crawlId?: string;
1260
+ elicitation?: {
1261
+ message: string;
1262
+ mode: "form" | "url";
1263
+ pauseCount?: number;
1264
+ requestedSchema?: Record<string, unknown>;
1265
+ serverName?: string;
1266
+ url?: string;
1267
+ };
1160
1268
  executionId?: string;
1161
1269
  flowId: string;
1162
1270
  origin?: "webmcp" | "sdk";
@@ -1207,7 +1315,7 @@ type RuntypeFlowSSEEvent = {
1207
1315
  completedAt?: string;
1208
1316
  duration?: number;
1209
1317
  durationMs?: number;
1210
- error?: string;
1318
+ error?: string | null;
1211
1319
  executionId?: string;
1212
1320
  executionTime?: number;
1213
1321
  id?: string;
@@ -1251,13 +1359,21 @@ type RuntypeFlowSSEEvent = {
1251
1359
  totalSteps: number;
1252
1360
  type: "step_skip";
1253
1361
  when: string;
1254
- } | {
1362
+ } | ({
1363
+ elicitation?: {
1364
+ message: string;
1365
+ mode: "form" | "url";
1366
+ pauseCount?: number;
1367
+ requestedSchema?: Record<string, unknown>;
1368
+ serverName?: string;
1369
+ url?: string;
1370
+ };
1255
1371
  executionId?: string;
1256
1372
  reason?: string;
1257
1373
  seq?: number;
1258
1374
  type: "step_await";
1259
1375
  [key: string]: unknown;
1260
- } | ({
1376
+ }) | ({
1261
1377
  agentContext?: {
1262
1378
  executionId: string;
1263
1379
  iteration: number;
@@ -1422,6 +1538,149 @@ type TargetResolver = (id: string) => {
1422
1538
  payload: Record<string, unknown>;
1423
1539
  };
1424
1540
 
1541
+ /**
1542
+ * Curated registry of lucide icons available to `renderLucideIcon`.
1543
+ *
1544
+ * The widget used to do `import * as icons from "lucide"` and look up
1545
+ * icons dynamically by string. That defeated tree-shaking, so the IIFE
1546
+ * (CDN/script-tag) bundle shipped all 1640 lucide icons (~400KB of icon
1547
+ * data) regardless of which we actually used. This explicit registry
1548
+ * lets the bundler drop any icon not listed here.
1549
+ *
1550
+ * Trade-off: `renderLucideIcon(name)` is now a *closed set*. Names not
1551
+ * in this map return `null` and log a warning, exactly as a typo did
1552
+ * before. The registry is intentionally generous (~110 icons) so that
1553
+ * custom `ComponentRenderer` authors rarely hit a missing-icon dead end.
1554
+ *
1555
+ * To add icons: add a named import above and a row in `LUCIDE_ICONS`,
1556
+ * keyed by the lucide kebab-case name (matches their filename and
1557
+ * https://lucide.dev/icons).
1558
+ *
1559
+ * See `packages/widget/docs/icon-registry-shortlist.md` for the full
1560
+ * curation rationale and which icons were considered but excluded.
1561
+ */
1562
+ declare const LUCIDE_ICONS: {
1563
+ readonly activity: IconNode;
1564
+ readonly "arrow-down": IconNode;
1565
+ readonly "arrow-up": IconNode;
1566
+ readonly "arrow-up-right": IconNode;
1567
+ readonly bot: IconNode;
1568
+ readonly "chevron-down": IconNode;
1569
+ readonly "chevron-up": IconNode;
1570
+ readonly "chevron-right": IconNode;
1571
+ readonly "chevron-left": IconNode;
1572
+ readonly check: IconNode;
1573
+ readonly clipboard: IconNode;
1574
+ readonly "clipboard-copy": IconNode;
1575
+ readonly "code-xml": IconNode;
1576
+ readonly copy: IconNode;
1577
+ readonly file: IconNode;
1578
+ readonly "file-code": IconNode;
1579
+ readonly "file-spreadsheet": IconNode;
1580
+ readonly "file-text": IconNode;
1581
+ readonly "image-plus": IconNode;
1582
+ readonly loader: IconNode;
1583
+ readonly "loader-circle": IconNode;
1584
+ readonly mic: IconNode;
1585
+ readonly paperclip: IconNode;
1586
+ readonly "refresh-cw": IconNode;
1587
+ readonly search: IconNode;
1588
+ readonly send: IconNode;
1589
+ readonly "shield-alert": IconNode;
1590
+ readonly "shield-check": IconNode;
1591
+ readonly "shield-x": IconNode;
1592
+ readonly square: IconNode;
1593
+ readonly "thumbs-down": IconNode;
1594
+ readonly "thumbs-up": IconNode;
1595
+ readonly upload: IconNode;
1596
+ readonly "volume-2": IconNode;
1597
+ readonly x: IconNode;
1598
+ readonly user: IconNode;
1599
+ readonly mail: IconNode;
1600
+ readonly phone: IconNode;
1601
+ readonly calendar: IconNode;
1602
+ readonly clock: IconNode;
1603
+ readonly building: IconNode;
1604
+ readonly "map-pin": IconNode;
1605
+ readonly lock: IconNode;
1606
+ readonly key: IconNode;
1607
+ readonly "credit-card": IconNode;
1608
+ readonly "at-sign": IconNode;
1609
+ readonly hash: IconNode;
1610
+ readonly globe: IconNode;
1611
+ readonly link: IconNode;
1612
+ readonly "circle-check": IconNode;
1613
+ readonly "circle-x": IconNode;
1614
+ readonly "triangle-alert": IconNode;
1615
+ readonly info: IconNode;
1616
+ readonly ban: IconNode;
1617
+ readonly shield: IconNode;
1618
+ readonly "arrow-left": IconNode;
1619
+ readonly "arrow-right": IconNode;
1620
+ readonly "external-link": IconNode;
1621
+ readonly ellipsis: IconNode;
1622
+ readonly "ellipsis-vertical": IconNode;
1623
+ readonly menu: IconNode;
1624
+ readonly house: IconNode;
1625
+ readonly plus: IconNode;
1626
+ readonly minus: IconNode;
1627
+ readonly pencil: IconNode;
1628
+ readonly trash: IconNode;
1629
+ readonly "trash-2": IconNode;
1630
+ readonly save: IconNode;
1631
+ readonly download: IconNode;
1632
+ readonly share: IconNode;
1633
+ readonly funnel: IconNode;
1634
+ readonly settings: IconNode;
1635
+ readonly "rotate-cw": IconNode;
1636
+ readonly maximize: IconNode;
1637
+ readonly minimize: IconNode;
1638
+ readonly "shopping-cart": IconNode;
1639
+ readonly "shopping-bag": IconNode;
1640
+ readonly package: IconNode;
1641
+ readonly truck: IconNode;
1642
+ readonly tag: IconNode;
1643
+ readonly gift: IconNode;
1644
+ readonly receipt: IconNode;
1645
+ readonly wallet: IconNode;
1646
+ readonly store: IconNode;
1647
+ readonly "dollar-sign": IconNode;
1648
+ readonly percent: IconNode;
1649
+ readonly play: IconNode;
1650
+ readonly pause: IconNode;
1651
+ readonly "volume-x": IconNode;
1652
+ readonly camera: IconNode;
1653
+ readonly image: IconNode;
1654
+ readonly film: IconNode;
1655
+ readonly headphones: IconNode;
1656
+ readonly "message-circle": IconNode;
1657
+ readonly "message-square": IconNode;
1658
+ readonly bell: IconNode;
1659
+ readonly heart: IconNode;
1660
+ readonly star: IconNode;
1661
+ readonly eye: IconNode;
1662
+ readonly "eye-off": IconNode;
1663
+ readonly bookmark: IconNode;
1664
+ readonly "calendar-days": IconNode;
1665
+ readonly history: IconNode;
1666
+ readonly timer: IconNode;
1667
+ readonly folder: IconNode;
1668
+ readonly "folder-open": IconNode;
1669
+ readonly files: IconNode;
1670
+ readonly sparkles: IconNode;
1671
+ readonly zap: IconNode;
1672
+ readonly sun: IconNode;
1673
+ readonly moon: IconNode;
1674
+ readonly flag: IconNode;
1675
+ readonly monitor: IconNode;
1676
+ readonly smartphone: IconNode;
1677
+ };
1678
+ /**
1679
+ * Names of lucide icons that ship with the widget. Names not in this
1680
+ * union return `null` from `renderLucideIcon` (with a console warning).
1681
+ */
1682
+ type IconName = keyof typeof LUCIDE_ICONS;
1683
+
1425
1684
  /**
1426
1685
  * Text content part for multi-modal messages
1427
1686
  */
@@ -2032,7 +2291,13 @@ type AgentWidgetControllerEventMap = {
2032
2291
  * new artifact content arrives or the host calls `showArtifacts()` on the widget handle.
2033
2292
  */
2034
2293
  type AgentWidgetArtifactsLayoutConfig = {
2035
- /** Flex gap between chat column and artifact pane. @default 0.5rem */
2294
+ /**
2295
+ * Flex gap between chat column and artifact pane.
2296
+ * @default 0 (welded); detached uses the panel inset
2297
+ * @remarks In welded appearances (`panel` / `seamless`) a nonzero gap opens a
2298
+ * visible seam in the single card. It is honored geometrically (resize clamps
2299
+ * and the seam handle account for it) but is usually undesired.
2300
+ */
2036
2301
  splitGap?: string;
2037
2302
  /** Artifact column width in split mode. @default 40% */
2038
2303
  paneWidth?: string;
@@ -2063,16 +2328,39 @@ type AgentWidgetArtifactsLayoutConfig = {
2063
2328
  /** Optional max artifact width cap while resizing (`px` only). Layout still bounds by chat min width. */
2064
2329
  resizableMaxWidth?: string;
2065
2330
  /**
2066
- * Visual treatment for the artifact column in split mode.
2067
- * - `'panel'`: bordered sidebar with left border, gap, and shadow (default).
2068
- * - `'seamless'`: flush with chat: no border or shadow, container background, zero gap.
2331
+ * Visual treatment for the artifact column in a desktop split.
2332
+ * - `'panel'`: one welded card (border + radius wrap chat + pane) with a hairline
2333
+ * divider on the pane's chat-facing edge, zero gap (default).
2334
+ * - `'seamless'`: the same welded card with no internal divider or chrome, zero gap.
2335
+ * - `'detached'`: two separate elevated cards: gap from `--persona-panel-inset`,
2336
+ * all-side border and radius on each, and canvas background behind the split.
2337
+ * In an inline embed this also insets the split from the container edges on all
2338
+ * sides (the page canvas shows through), so the all-side margin no longer requires
2339
+ * `launcher.detachedPanel`.
2340
+ *
2341
+ * Default is `'panel'` unless `launcher.detachedPanel` is true, in which case an unset
2342
+ * `paneAppearance` resolves to `'detached'`. An explicit value always wins.
2069
2343
  * @default 'panel'
2070
2344
  */
2071
- paneAppearance?: "panel" | "seamless";
2345
+ paneAppearance?: "panel" | "seamless" | "detached";
2072
2346
  /** Border radius on the artifact pane (CSS length). Works with any `paneAppearance`. */
2073
2347
  paneBorderRadius?: string;
2074
2348
  /** CSS `box-shadow` on the artifact pane. Set `"none"` to suppress the default shadow. */
2075
2349
  paneShadow?: string;
2350
+ /**
2351
+ * CSS `box-shadow` for the chat column card in a detached split. Defaults to the same
2352
+ * elevation as the artifact pane; set to `"none"` to keep the chat flat while the pane stays raised.
2353
+ */
2354
+ chatShadow?: string;
2355
+ /**
2356
+ * Chat column surface in a detached split. `"card"` (default) renders the chat as an inset card
2357
+ * matching the artifact pane; `"flush"` renders the chat flush with the container (no border, radius,
2358
+ * or shadow) and insets only the artifact pane, so the chat is flat background and the pane floats.
2359
+ * Only affects an inline-embedded detached split (the container-filling case); in floating, docked,
2360
+ * or sidebar modes it falls back to the card look.
2361
+ * @default 'card'
2362
+ */
2363
+ chatSurface?: "card" | "flush";
2076
2364
  /**
2077
2365
  * Full `border` shorthand for the artifact `<aside>` (all sides). Overrides default pane borders.
2078
2366
  * Example: `"1px solid #cccccc"`.
@@ -2084,14 +2372,12 @@ type AgentWidgetArtifactsLayoutConfig = {
2084
2372
  */
2085
2373
  paneBorderLeft?: string;
2086
2374
  /**
2087
- * Desktop split only (not narrow-host drawer / not ≤640px): square the **main chat card’s**
2088
- * top-right and bottom-right radii, and round the **artifact pane’s** top-right and bottom-right
2089
- * to match `persona-rounded-2xl` (`--persona-radius-lg`) so the two columns read as one shell.
2375
+ * @deprecated No-op. Panel and seamless splits now weld into one card by default.
2090
2376
  */
2091
2377
  unifiedSplitChrome?: boolean;
2092
2378
  /**
2093
- * When `unifiedSplitChrome` is true, outer-right corner radius on the artifact column (CSS length).
2094
- * @default matches theme large radius (`--persona-radius-lg`)
2379
+ * Desktop welded split only: override the artifact pane's outer-right corner radius (CSS length).
2380
+ * @default matches the panel radius (`--persona-panel-radius`)
2095
2381
  */
2096
2382
  unifiedSplitOuterRadius?: string;
2097
2383
  /**
@@ -2111,6 +2397,10 @@ type AgentWidgetArtifactsLayoutConfig = {
2111
2397
  * @default 'default'
2112
2398
  */
2113
2399
  toolbarPreset?: "default" | "document";
2400
+ /** Visible title in the artifact toolbar. @default "Artifacts" */
2401
+ toolbarTitle?: string;
2402
+ /** Label for the artifact dismiss control. @default "Close" */
2403
+ closeButtonLabel?: string;
2114
2404
  /**
2115
2405
  * When `toolbarPreset` is `document`, show a visible "Copy" label next to the copy icon.
2116
2406
  */
@@ -2125,6 +2415,17 @@ type AgentWidgetArtifactsLayoutConfig = {
2125
2415
  documentToolbarToggleActiveBackground?: string;
2126
2416
  /** Active view/source toggle border color. Sets `--persona-artifact-doc-toggle-active-border`. */
2127
2417
  documentToolbarToggleActiveBorderColor?: string;
2418
+ /** Show an expand/collapse toggle in the artifact toolbar (both presets). Expanded fills the widget with the pane and hides the chat column. Default: false. */
2419
+ showExpandToggle?: boolean;
2420
+ /** Show the copy control in the `default` toolbar preset (the `document` preset always shows it). Default: false. */
2421
+ showCopyButton?: boolean;
2422
+ /** Edge fade on the scrollable tab strip. true = both ends (dynamic). @default true */
2423
+ tabFade?: boolean | {
2424
+ start?: boolean;
2425
+ end?: boolean;
2426
+ };
2427
+ /** Tab fade width (CSS length). @default 24px */
2428
+ tabFadeSize?: string;
2128
2429
  /**
2129
2430
  * Invoked when the document toolbar Refresh control is used (before the pane re-renders).
2130
2431
  * Use to replay `connectStream`, refetch, etc.
@@ -2148,20 +2449,349 @@ type AgentWidgetArtifactsLayoutConfig = {
2148
2449
  jsonPayload: string;
2149
2450
  }) => void | Promise<void>;
2150
2451
  };
2452
+ type PersonaArtifactDisplayMode = "card" | "panel" | "inline";
2453
+ /** Context handed to custom artifact actions. Content fields are best-effort: resolved from live session state or, after a refresh, from the persisted reference-card payload. */
2454
+ type PersonaArtifactActionContext = {
2455
+ artifactId: string | null;
2456
+ title: string;
2457
+ artifactType: string;
2458
+ markdown?: string;
2459
+ file?: PersonaArtifactFileMeta;
2460
+ /** Component artifacts: pretty-printed { component, props } JSON. */
2461
+ jsonPayload?: string;
2462
+ };
2463
+ /**
2464
+ * Context passed to a `features.artifacts.statusLabel` function on every
2465
+ * artifact streaming update, once per visible surface. Treat it as read-only:
2466
+ * the function should be pure and fast (it runs per streaming delta, per
2467
+ * surface).
2468
+ */
2469
+ type PersonaArtifactStatusLabelContext = {
2470
+ artifactId: string;
2471
+ artifactType: "markdown" | "component";
2472
+ title?: string;
2473
+ /** The default subject, e.g. "document", "component", or a file type label like "HTML file". */
2474
+ typeLabel: string;
2475
+ file?: PersonaArtifactFileMeta;
2476
+ /** Accumulated streamed content length so far (0 for component artifacts). */
2477
+ chars: number;
2478
+ /** Accumulated line count so far (0 for component artifacts). */
2479
+ lines: number;
2480
+ /** Milliseconds since this artifact's first streaming update was seen. */
2481
+ elapsedMs: number;
2482
+ /** Lazy accessor for the accumulated markdown source (empty string for component artifacts). Call only if needed; parsing cost is opt-in. */
2483
+ content: () => string;
2484
+ /** Which surface is asking, so hosts can shorten for cramped spots. */
2485
+ surface: "card" | "inline-chrome" | "status-body";
2486
+ };
2487
+ /** A custom action button rendered in an artifact toolbar/card slot. */
2488
+ type PersonaArtifactCustomAction = {
2489
+ /** Stable id, used for DOM wiring and keyed re-renders. */
2490
+ id: string;
2491
+ /** Accessible label; also the visible text when showLabel is true. */
2492
+ label: string;
2493
+ /** Registry icon name, or a factory returning your own element (e.g. a brand SVG). The factory result is author-owned code, not sanitized wire data. */
2494
+ icon?: IconName | (() => HTMLElement | SVGElement);
2495
+ /** Render icon + text instead of icon-only. Default: false. */
2496
+ showLabel?: boolean;
2497
+ /** Per-artifact gate, evaluated on each render. Omitted = always visible. */
2498
+ visible?: (ctx: PersonaArtifactActionContext) => boolean;
2499
+ /** May be async; rejections are swallowed like built-in action errors. */
2500
+ onClick: (ctx: PersonaArtifactActionContext) => void | Promise<void>;
2501
+ };
2151
2502
  type AgentWidgetArtifactsFeature = {
2152
2503
  /** When true, Persona shows the artifact pane and handles artifact_* SSE events */
2153
2504
  enabled?: boolean;
2154
2505
  /** If set, artifact events for other types are ignored */
2155
2506
  allowedTypes?: PersonaArtifactKind[];
2507
+ /**
2508
+ * Where artifact bodies render. A single mode applies to all artifacts;
2509
+ * the object form sets a default plus per-type overrides.
2510
+ * Defaults to "panel" (current behavior).
2511
+ */
2512
+ display?: PersonaArtifactDisplayMode | {
2513
+ default?: PersonaArtifactDisplayMode;
2514
+ byType?: Partial<Record<PersonaArtifactKind, PersonaArtifactDisplayMode>>;
2515
+ };
2156
2516
  /** Split / drawer dimensions and launcher widen behavior */
2157
2517
  layout?: AgentWidgetArtifactsLayoutConfig;
2158
2518
  /**
2159
- * Called when an artifact card action is triggered (open, download).
2160
- * Return `true` to prevent the default behavior.
2519
+ * Controls inline preview of previewable file artifacts (HTML/SVG written by
2520
+ * a Claude Managed agent). When a markdown artifact carries `file` metadata,
2521
+ * the pane can render an isolated `<iframe srcdoc>` sandbox instead of a code
2522
+ * block.
2523
+ */
2524
+ filePreview?: {
2525
+ /** Enable rendered preview for html/svg files. Defaults to enabled. Set false to force source view. */
2526
+ enabled?: boolean;
2527
+ /**
2528
+ * `sandbox` attribute for the preview iframe. Defaults to `"allow-scripts"`.
2529
+ * `allow-same-origin` is stripped (with a console warning) unless
2530
+ * `dangerouslyAllowSameOrigin` is set: the opaque origin is what isolates
2531
+ * the preview from the host page. Embedder-trusted config.
2532
+ */
2533
+ iframeSandbox?: string;
2534
+ /**
2535
+ * Allows `allow-same-origin` to pass through `iframeSandbox`. Off by
2536
+ * default because it lets agent-written file content run with the host
2537
+ * page's origin (DOM, storage, credentialed requests). Only set this when
2538
+ * every previewed file source is fully trusted.
2539
+ */
2540
+ dangerouslyAllowSameOrigin?: boolean;
2541
+ /**
2542
+ * Loading treatment for the preview iframe. Default on.
2543
+ *
2544
+ * A sandboxed `iframe srcdoc` (opaque origin, `allow-scripts` only) paints
2545
+ * blank until its content renders — seconds for artifacts that pull CDN
2546
+ * scripts (React/Babel). The default shows a themed "Loading preview…"
2547
+ * overlay over the iframe, dismissed the instant the content signals it has
2548
+ * painted (an injected `postMessage` reporter) or a hard timeout elapses.
2549
+ *
2550
+ * `false` disables the overlay and the injected ready signal entirely (the
2551
+ * srcdoc becomes the raw file source, the prior behavior). An object tunes
2552
+ * the timing; omitted / `true` uses all defaults.
2553
+ */
2554
+ loading?: boolean | {
2555
+ /** Show the overlay only if the preview is not ready after this many ms. Default 200. */
2556
+ delayMs?: number;
2557
+ /** Once shown, keep the overlay visible at least this long (anti-flicker). Default 300. */
2558
+ minVisibleMs?: number;
2559
+ /** Give up waiting and reveal the iframe regardless after this many ms. Default 8000. */
2560
+ timeoutMs?: number;
2561
+ /**
2562
+ * Append the `postMessage` ready reporter to the srcdoc so the overlay
2563
+ * dismisses on first paint rather than the iframe `load` event (which
2564
+ * fires before post-DOMContentLoaded rendering like Babel compilation).
2565
+ * Default true. When false, the overlay dismisses on `load` + a double
2566
+ * `requestAnimationFrame`, or the timeout.
2567
+ */
2568
+ injectReadySignal?: boolean;
2569
+ /**
2570
+ * Escalation text shown beside the spinner after `labelDelayMs`.
2571
+ * Default `"Starting preview..."`. `false` renders an icon-only
2572
+ * indicator forever (no text ever). A short work-naming label is
2573
+ * added only after a delay by design — icon-first, with text reserved
2574
+ * for genuinely slow loads (per Geist/Sandpack guidance; HIG warns
2575
+ * against the vague word "loading").
2576
+ */
2577
+ label?: string | false;
2578
+ /**
2579
+ * Delay before the escalation label fades in, measured from when the
2580
+ * overlay actually becomes visible (i.e. after `delayMs`), not from
2581
+ * iframe creation. Default 2000.
2582
+ */
2583
+ labelDelayMs?: number;
2584
+ /**
2585
+ * Full replacement for the default indicator (spinner + escalation
2586
+ * label). Called once when the overlay is built; return any element
2587
+ * (a brand mark, skeleton, custom animation) to own the indicator
2588
+ * content entirely (the escalation-label logic is then skipped), or
2589
+ * return `null` to fall back to the default. A thrown error also falls
2590
+ * back. Mirrors `renderInline` / `renderCard`'s null-falls-back
2591
+ * contract. The overlay backdrop, timing, and dismissal stay
2592
+ * widget-owned either way.
2593
+ */
2594
+ renderIndicator?: (ctx: {
2595
+ artifactId: string;
2596
+ config: AgentWidgetConfig;
2597
+ }) => HTMLElement | null;
2598
+ };
2599
+ };
2600
+ /**
2601
+ * Custom action buttons for the artifact pane toolbar, rendered between the
2602
+ * refresh and expand/close controls in both toolbar presets. Re-read on live
2603
+ * config updates.
2604
+ */
2605
+ toolbarActions?: PersonaArtifactCustomAction[];
2606
+ /**
2607
+ * Custom action buttons for the artifact reference card, rendered before the
2608
+ * Download button on complete artifacts. Clicks are delegated, so they
2609
+ * survive re-renders and page refresh.
2610
+ */
2611
+ cardActions?: PersonaArtifactCustomAction[];
2612
+ /**
2613
+ * File chrome (title bar + toolbar) around inline preview blocks
2614
+ * (`display: "inline"`). Default when undefined: chrome on, with the built-in
2615
+ * Copy and Expand controls. Pass `false` to render the bare preview body
2616
+ * (frame → padded body, no chrome bar), or an object to toggle the built-in
2617
+ * controls individually.
2618
+ *
2619
+ * Note: default-on chrome adds a title bar and buttons to every existing
2620
+ * inline host on upgrade; set `inlineChrome: false` to opt out.
2621
+ */
2622
+ inlineChrome?: boolean | {
2623
+ /** Show the built-in Copy button (complete artifacts only). Default true. */
2624
+ showCopy?: boolean;
2625
+ /** Show the built-in Expand button (opens the pane for this artifact). Default true. */
2626
+ showExpand?: boolean;
2627
+ /**
2628
+ * Show the built-in rendered/source view toggle (complete artifacts
2629
+ * only). Default true. The toggle is availability-gated: it appears only
2630
+ * for file-backed markdown artifacts that have a rendered alternative to
2631
+ * their source (previewable HTML/SVG, or markdown-kind files), and never
2632
+ * when `inlineBody.viewMode: "source"` forces a source-only body. Plain
2633
+ * markdown and component artifacts don't get it (the pane toggle covers
2634
+ * those).
2635
+ */
2636
+ showViewToggle?: boolean;
2637
+ };
2638
+ /**
2639
+ * Custom action buttons for the inline chrome toolbar, rendered before the
2640
+ * built-in Copy/Expand controls on complete artifacts. Same shape as
2641
+ * `cardActions`; each action's `visible` gate is respected and clicks are
2642
+ * delegated, so they survive re-renders and page refresh.
2643
+ */
2644
+ inlineActions?: PersonaArtifactCustomAction[];
2645
+ /**
2646
+ * Replace the artifact tab strip entirely (Seam A). Return an element mounted in
2647
+ * place of the built-in `.persona-artifact-list`; the pane still owns the toolbar,
2648
+ * preview body, iframe reuse, and lazy-render gate. Re-invoked when the records or
2649
+ * selection change. Custom bars own their own accessibility; use `createRovingTablist`
2650
+ * to keep keyboard/tablist behavior. When set, the built-in strip (scroll, fade,
2651
+ * tablist) is not rendered.
2652
+ *
2653
+ * Return either a fresh element per call, or the SAME element updated in place.
2654
+ * Returning a stable element preserves internal state across selection changes:
2655
+ * the pane skips remounting an unchanged node, so a roving tablist keeps keyboard
2656
+ * focus on the selected tab (a fresh element per call drops focus and breaks
2657
+ * Arrow-key nav). See the reference bars in `apps/web/src/artifact-demo.ts`.
2658
+ */
2659
+ renderTabBar?: (ctx: {
2660
+ records: PersonaArtifactRecord[];
2661
+ selectedId: string | null;
2662
+ onSelect: (id: string) => void;
2663
+ }) => HTMLElement;
2664
+ /**
2665
+ * Body layout for inline artifact blocks (`display: "inline"`). Controls how
2666
+ * the block reserves height and behaves while a file/document artifact
2667
+ * streams, so the streaming source no longer grows an unbounded `<pre>` and
2668
+ * then snaps to the completed preview. Affects only the inline block; the
2669
+ * artifact pane is unchanged.
2670
+ *
2671
+ * Defaults (a behavior change from prior versions, which grew with content
2672
+ * during streaming): a fixed 320px streaming source window with tail-follow,
2673
+ * a top edge fade, and an animated streaming→complete swap. Pass
2674
+ * `height: "auto"` to restore the old grow-with-content streaming behavior.
2675
+ */
2676
+ inlineBody?: {
2677
+ /** What the body shows while streaming. Default `"source"`. */
2678
+ streamingView?: "source" | "status";
2679
+ /**
2680
+ * How the completed body renders. `"rendered"` (default) keeps the current
2681
+ * behavior: file previews in a sandboxed iframe, markdown through the
2682
+ * markdown pipeline. `"source"` always shows the raw syntax-highlighted
2683
+ * source instead — for hosts where the artifact is input to the host system
2684
+ * (a code editor, a query runner) rather than something to preview. Unlike
2685
+ * `filePreview.enabled: false`, this also covers markdown-kind files and
2686
+ * plain markdown artifacts. Component artifacts always render through the
2687
+ * registry.
2688
+ */
2689
+ viewMode?: "rendered" | "source";
2690
+ /**
2691
+ * Body height per state. A number reserves that many px for the whole body
2692
+ * region (border-box, padding included) with internal scroll — the
2693
+ * zero-layout-shift path; `"auto"` means content-sized. A
2694
+ * scalar applies to both the streaming and complete states; the object form
2695
+ * sets them independently. Default `320` for both states.
2696
+ *
2697
+ * Note: with `"auto"` on the complete state, non-iframe bodies (rendered
2698
+ * markdown, source view, component) are content-sized, but a file-preview
2699
+ * iframe cannot be content-sized without postMessage plumbing, so it falls
2700
+ * back to the CSS-var default (`--persona-artifact-inline-frame-height`,
2701
+ * 320px).
2702
+ *
2703
+ * Numeric heights are applied via the CSS var
2704
+ * `--persona-artifact-inline-body-height` on the block root. The older
2705
+ * `--persona-artifact-inline-frame-height` var still overrides the iframe
2706
+ * height when this one is unset, so themes pinned to it keep working.
2707
+ */
2708
+ height?: number | "auto" | {
2709
+ streaming?: number | "auto";
2710
+ complete?: number | "auto";
2711
+ };
2712
+ /**
2713
+ * Tail-follow the newest streamed lines in a fixed-height source window: if
2714
+ * the viewport is already at the bottom, keep it pinned as content arrives;
2715
+ * if the reader scrolled up, don't fight them. Only meaningful for a numeric
2716
+ * streaming height. Default `true`.
2717
+ *
2718
+ * Precedence: ignored when `overflow: "clip"` (a clipped window shows the
2719
+ * top of the document and never scrolls, so there is no tail to follow).
2720
+ */
2721
+ followOutput?: boolean;
2722
+ /**
2723
+ * How a fixed-height source window handles content taller than the window.
2724
+ *
2725
+ * - `"scroll"` (default) — the current behavior: an internally scrollable
2726
+ * window that tail-follows the newest streamed lines (see `followOutput`),
2727
+ * so the reader sees the growing tail of the document.
2728
+ * - `"clip"` — a fixed-height window that shows the TOP of the document,
2729
+ * `overflow: hidden` with no internal scroll and no tail-follow
2730
+ * (`followOutput` is ignored in this mode). When content overflows the
2731
+ * window a bottom edge fade signals there is more below (the top is always
2732
+ * visible, so a top fade never applies); an explicit `fadeMask` still wins
2733
+ * over this clip-mode default. When the inline chrome's Expand control is
2734
+ * enabled the whole body doubles as an expand hitbox (click / Enter / Space
2735
+ * opens the artifact in the pane), matching the industry inline-card
2736
+ * pattern; otherwise the clip is purely visual.
2737
+ *
2738
+ * Only meaningful for a numeric streaming/complete height. Default
2739
+ * `"scroll"`.
2740
+ */
2741
+ overflow?: "scroll" | "clip";
2742
+ /**
2743
+ * Edge fade masks on the fixed-height streaming window (a top fade signals
2744
+ * clipped content above, a bottom fade signals clipped content below). Each
2745
+ * fade renders only when content is actually clipped on that edge, so with
2746
+ * tail-follow pinned at the bottom the bottom fade stays inert until the
2747
+ * reader scrolls up mid-stream. `true` = `{ top: true, bottom: true }`,
2748
+ * `false` = none. Default `{ top: true, bottom: true }`.
2749
+ */
2750
+ fadeMask?: boolean | {
2751
+ top?: boolean;
2752
+ bottom?: boolean;
2753
+ };
2754
+ /**
2755
+ * Animate the streaming→complete body swap. `"auto"` uses the View
2756
+ * Transitions API when supported and `prefers-reduced-motion` is off;
2757
+ * `"none"` swaps instantly. Default `"auto"`.
2758
+ */
2759
+ transition?: "auto" | "none";
2760
+ /**
2761
+ * What the block becomes once the artifact completes.
2762
+ *
2763
+ * - `"inline"` (default) — the streamed body stays inline forever, as
2764
+ * configured by the other `inlineBody` options.
2765
+ * - `"card"` — the block streams inline as configured, then collapses to the
2766
+ * compact artifact reference card once the artifact completes (the Copilot
2767
+ * "chiclet" / Claude side-panel handoff pattern), keeping the thread
2768
+ * scannable. The collapse plays as a short CSS height transition (skipped
2769
+ * under `prefers-reduced-motion`); it does not use the View Transitions
2770
+ * API, so `transition` does not affect it. After the collapse the card's
2771
+ * normal actions apply (click opens the artifact pane). `viewMode`, the
2772
+ * inline rendered/source view toggle, `inlineActions`, and inline copy are
2773
+ * streaming-phase-only in this mode and inert once the block is a card
2774
+ * (there is nothing to toggle or copy on a collapsed card). Blocks that are
2775
+ * already complete when they first render (page-refresh hydration) render
2776
+ * the card directly, with no flash of the inline body and no animation.
2777
+ *
2778
+ * Default `"inline"`.
2779
+ */
2780
+ completeDisplay?: "inline" | "card";
2781
+ };
2782
+ /**
2783
+ * Called when an artifact action is triggered (open, download, expand).
2784
+ * Return `true` to intercept: the widget then does not change state.
2785
+ * For `expand`, `expanded` is the state the toggle is about to enter and
2786
+ * `artifactId` is the currently selected artifact (or `null` when none).
2161
2787
  */
2162
2788
  onArtifactAction?: (action: {
2163
2789
  type: 'open' | 'download';
2164
2790
  artifactId: string;
2791
+ } | {
2792
+ type: 'expand';
2793
+ artifactId: string | null;
2794
+ expanded: boolean;
2165
2795
  }) => boolean | void;
2166
2796
  /**
2167
2797
  * Custom renderer for artifact reference cards shown in the message thread.
@@ -2177,6 +2807,72 @@ type AgentWidgetArtifactsFeature = {
2177
2807
  config: AgentWidgetConfig;
2178
2808
  defaultRenderer: () => HTMLElement;
2179
2809
  }) => HTMLElement | null;
2810
+ /**
2811
+ * Custom renderer for inline artifact blocks (display: "inline"), mirroring
2812
+ * `renderCard`. Return an element to replace the default inline preview,
2813
+ * or null to use the default.
2814
+ */
2815
+ renderInline?: (context: {
2816
+ artifact: {
2817
+ artifactId: string;
2818
+ title: string;
2819
+ artifactType: string;
2820
+ status: string;
2821
+ };
2822
+ config: AgentWidgetConfig;
2823
+ defaultRenderer: () => HTMLElement;
2824
+ }) => HTMLElement | null;
2825
+ /**
2826
+ * Text shown while an artifact streams, in place of the default
2827
+ * `Generating <type>...` status. Applies to every streaming surface: the
2828
+ * reference card status line, the inline chrome meta label, and the inline
2829
+ * streaming status body (`inlineBody.streamingView: "status"`).
2830
+ *
2831
+ * - A plain string replaces the default label everywhere (localization or
2832
+ * brand voice).
2833
+ * - A function is called on every artifact update for each visible surface;
2834
+ * it must be pure and fast. Returning a string sets the animated label
2835
+ * only. Returning `{ label, detail }` splits the status into an animated
2836
+ * label (re-applied only when its text changes, so the loading animation
2837
+ * stays stable) and a plain un-animated detail span that may update freely
2838
+ * per delta (live counters).
2839
+ *
2840
+ * Default when unset: the current behavior, `Generating <type>...` with no
2841
+ * detail. If the function throws, the default label is used for that update
2842
+ * (a bad host callback must never break rendering). There is deliberately no
2843
+ * percent progress: streams do not announce total length, so counts and
2844
+ * elapsed time are the only truthful signals.
2845
+ */
2846
+ statusLabel?: string | ((ctx: PersonaArtifactStatusLabelContext) => string | {
2847
+ label: string;
2848
+ detail?: string;
2849
+ });
2850
+ /**
2851
+ * Animation applied to the artifact card's "Generating …" status text while
2852
+ * the artifact streams. Character-by-character modes (`shimmer`,
2853
+ * `shimmer-color`, `rainbow`) wrap each character in a span with a staggered
2854
+ * `animation-delay`; `pulse` fades the whole status text; `none` disables the
2855
+ * animation. Honors `prefers-reduced-motion`.
2856
+ * @default "shimmer"
2857
+ */
2858
+ loadingAnimation?: AgentWidgetToolCallLoadingAnimation;
2859
+ /**
2860
+ * Duration of one full animation cycle in milliseconds.
2861
+ * Applies to pulse, shimmer, shimmer-color, and rainbow modes.
2862
+ * @default 2000
2863
+ */
2864
+ loadingAnimationDuration?: number;
2865
+ /**
2866
+ * Primary color for shimmer-color animation mode.
2867
+ * Defaults to the current text color.
2868
+ */
2869
+ loadingAnimationColor?: string;
2870
+ /**
2871
+ * Secondary/end color for shimmer-color animation mode.
2872
+ * Creates a gradient sweep between `loadingAnimationColor` and this color.
2873
+ * @default "#3b82f6"
2874
+ */
2875
+ loadingAnimationSecondaryColor?: string;
2180
2876
  };
2181
2877
  /**
2182
2878
  * How the transcript scrolls while an assistant response streams in.
@@ -2304,6 +3000,13 @@ type AgentWidgetToolCallDisplayFeature = {
2304
3000
  * @default false
2305
3001
  */
2306
3002
  grouped?: boolean;
3003
+ /**
3004
+ * Controls how a grouped tool sequence is rendered.
3005
+ * - `"stack"`: show the group summary and each child tool row.
3006
+ * - `"summary"`: show one consolidated summary row only.
3007
+ * @default "stack"
3008
+ */
3009
+ groupedMode?: "stack" | "summary";
2307
3010
  /**
2308
3011
  * When false, tool call bubbles show only the collapsed summary with no
2309
3012
  * expand/collapse toggle. Users see tool awareness without full details.
@@ -2993,6 +3696,24 @@ type AgentWidgetLauncherConfig = {
2993
3696
  * @default false
2994
3697
  */
2995
3698
  sidebarMode?: boolean;
3699
+ /**
3700
+ * When true, the widget panel renders as a detached card inset within its region,
3701
+ * with rounded corners on all sides and elevation (shadow plus hairline border),
3702
+ * instead of sitting flush against the region edges.
3703
+ *
3704
+ * The gap around the card is themed via `theme.components.panel.inset`. The
3705
+ * background revealed behind it is themed via `theme.components.panel.canvasBackground`
3706
+ * in docked and inline embed modes. In sidebar mode the gap stays click-through, so the
3707
+ * host page shows through it the same way it does in floating mode, and canvasBackground
3708
+ * is a no-op there.
3709
+ *
3710
+ * Applies to sidebar, docked, and inline embed modes. Ignored in mobile fullscreen,
3711
+ * where chrome is already suppressed. Floating mode is unchanged, since it already
3712
+ * renders as a detached card.
3713
+ *
3714
+ * @default false
3715
+ */
3716
+ detachedPanel?: boolean;
2996
3717
  /**
2997
3718
  * Width of the sidebar panel when sidebarMode is true.
2998
3719
  * @default "420px"
@@ -5798,6 +6519,21 @@ type InjectComponentDirectiveOptions = {
5798
6519
  */
5799
6520
  sequence?: number;
5800
6521
  };
6522
+ /**
6523
+ * Optional file metadata attached to a markdown artifact that represents a
6524
+ * concrete file written by a Claude Managed agent (e.g. `/mnt/session/outputs/cat.html`).
6525
+ * Additive: the artifact content stays a fenced code block on the wire for
6526
+ * backward compatibility; new widgets use this to recover the raw source and
6527
+ * offer a preview. Mirrors the `file` field on the core `artifact_start` event.
6528
+ */
6529
+ type PersonaArtifactFileMeta = {
6530
+ /** Full path of the written file (also used as the artifact title). */
6531
+ path: string;
6532
+ /** MIME type of the file (used for download and preview decisions). */
6533
+ mimeType: string;
6534
+ /** Fence language the content was encoded with (html/xml/md/text). */
6535
+ language?: string;
6536
+ };
5801
6537
  type PersonaArtifactRecord = {
5802
6538
  id: string;
5803
6539
  artifactType: PersonaArtifactKind;
@@ -5806,6 +6542,8 @@ type PersonaArtifactRecord = {
5806
6542
  markdown?: string;
5807
6543
  component?: string;
5808
6544
  props?: Record<string, unknown>;
6545
+ /** Present when this markdown artifact is a previewable file (see PersonaArtifactFileMeta). */
6546
+ file?: PersonaArtifactFileMeta;
5809
6547
  };
5810
6548
  /** Programmatic artifact upsert (controller / window API) */
5811
6549
  type PersonaArtifactManualUpsert = {
@@ -5813,12 +6551,18 @@ type PersonaArtifactManualUpsert = {
5813
6551
  artifactType: "markdown";
5814
6552
  title?: string;
5815
6553
  content: string;
6554
+ /** Optional file metadata for previewable file artifacts. */
6555
+ file?: PersonaArtifactFileMeta;
6556
+ /** Set false to update the registry/pane without a transcript block (pre-4.x behavior). */
6557
+ transcript?: boolean;
5816
6558
  } | {
5817
6559
  id?: string;
5818
6560
  artifactType: "component";
5819
6561
  title?: string;
5820
6562
  component: string;
5821
6563
  props?: Record<string, unknown>;
6564
+ /** Set false to update the registry/pane without a transcript block (pre-4.x behavior). */
6565
+ transcript?: boolean;
5822
6566
  };
5823
6567
  type AgentWidgetEvent = {
5824
6568
  type: "message";
@@ -5853,6 +6597,8 @@ type AgentWidgetEvent = {
5853
6597
  artifactType: PersonaArtifactKind;
5854
6598
  title?: string;
5855
6599
  component?: string;
6600
+ /** Present when this markdown artifact is a previewable file. */
6601
+ file?: PersonaArtifactFileMeta;
5856
6602
  } | {
5857
6603
  type: "artifact_delta";
5858
6604
  id: string;