@runtypelabs/persona 4.7.0 → 4.9.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 (185) hide show
  1. package/README.md +1 -0
  2. package/dist/animations/glyph-cycle.cjs +2 -2
  3. package/dist/animations/glyph-cycle.d.cts +1 -1
  4. package/dist/animations/glyph-cycle.d.ts +1 -1
  5. package/dist/animations/glyph-cycle.js +2 -2
  6. package/dist/animations/{types-CSmiKRVa.d.cts → types-4ROVJ1gA.d.cts} +85 -3
  7. package/dist/animations/{types-CSmiKRVa.d.ts → types-4ROVJ1gA.d.ts} +85 -3
  8. package/dist/animations/wipe.cjs +2 -2
  9. package/dist/animations/wipe.d.cts +1 -1
  10. package/dist/animations/wipe.d.ts +1 -1
  11. package/dist/chunk-5EIIHQLQ.js +1 -0
  12. package/dist/chunk-IO5VVUKP.js +3 -0
  13. package/dist/chunk-IPVK3KOM.js +1 -0
  14. package/dist/chunk-UPO4GUFC.js +1 -0
  15. package/dist/codegen.cjs +13 -13
  16. package/dist/codegen.js +14 -14
  17. package/dist/context-mentions-7S5KVUTG.js +169 -0
  18. package/dist/context-mentions-inline-TTCN7ZM2.js +4 -0
  19. package/dist/context-mentions-inline.cjs +4 -0
  20. package/dist/context-mentions-inline.d.cts +203 -0
  21. package/dist/context-mentions-inline.d.ts +203 -0
  22. package/dist/context-mentions-inline.js +4 -0
  23. package/dist/context-mentions.cjs +295 -0
  24. package/dist/context-mentions.d.cts +7025 -0
  25. package/dist/context-mentions.d.ts +7025 -0
  26. package/dist/context-mentions.js +295 -0
  27. package/dist/index.cjs +99 -68
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +1507 -182
  30. package/dist/index.d.ts +1507 -182
  31. package/dist/index.global.js +88 -56
  32. package/dist/index.global.js.map +1 -1
  33. package/dist/index.js +99 -68
  34. package/dist/index.js.map +1 -1
  35. package/dist/install.global.js +1 -1
  36. package/dist/install.global.js.map +1 -1
  37. package/dist/launcher.global.js +3 -2
  38. package/dist/launcher.global.js.map +1 -1
  39. package/dist/markdown-parsers.js +24 -24
  40. package/dist/plugin-kit.cjs +1 -1
  41. package/dist/plugin-kit.d.cts +17 -0
  42. package/dist/plugin-kit.d.ts +17 -0
  43. package/dist/plugin-kit.js +1 -1
  44. package/dist/runtype-tts-entry-UJAEF7NZ.js +1 -0
  45. package/dist/runtype-tts.js +1 -1
  46. package/dist/session-reconnect-JKIJBHS5.js +1 -0
  47. package/dist/smart-dom-reader.cjs +18 -17
  48. package/dist/smart-dom-reader.d.cts +1260 -16
  49. package/dist/smart-dom-reader.d.ts +1260 -16
  50. package/dist/smart-dom-reader.js +18 -17
  51. package/dist/testing.cjs +3 -3
  52. package/dist/testing.js +3 -3
  53. package/dist/theme-editor-preview.cjs +260 -58
  54. package/dist/theme-editor-preview.d.cts +1234 -15
  55. package/dist/theme-editor-preview.d.ts +1234 -15
  56. package/dist/theme-editor-preview.js +87 -58
  57. package/dist/theme-editor.cjs +10 -10
  58. package/dist/theme-editor.d.cts +1226 -15
  59. package/dist/theme-editor.d.ts +1226 -15
  60. package/dist/theme-editor.js +10 -10
  61. package/dist/theme-reference.cjs +1 -1
  62. package/dist/theme-reference.d.cts +76 -0
  63. package/dist/theme-reference.d.ts +76 -0
  64. package/dist/theme-reference.js +1 -1
  65. package/dist/voice-worklet-player.cjs +2 -2
  66. package/dist/voice-worklet-player.js +2 -2
  67. package/dist/webmcp-polyfill.js +2 -2
  68. package/dist/widget.css +1 -1
  69. package/package.json +16 -5
  70. package/src/artifacts-session.test.ts +178 -0
  71. package/src/client.test.ts +255 -1
  72. package/src/client.ts +157 -60
  73. package/src/components/artifact-card.test.ts +333 -0
  74. package/src/components/artifact-card.ts +75 -28
  75. package/src/components/artifact-inline.test.ts +1328 -0
  76. package/src/components/artifact-inline.ts +920 -0
  77. package/src/components/artifact-pane.test.ts +1042 -0
  78. package/src/components/artifact-pane.ts +440 -131
  79. package/src/components/artifact-preview.test.ts +1155 -0
  80. package/src/components/artifact-preview.ts +994 -0
  81. package/src/components/composer-parts.ts +3 -12
  82. package/src/components/context-mention-button.test.ts +70 -0
  83. package/src/components/context-mention-button.ts +82 -0
  84. package/src/components/context-mention-chip.ts +134 -0
  85. package/src/components/context-mention-menu.test.ts +508 -0
  86. package/src/components/context-mention-menu.ts +0 -0
  87. package/src/components/message-bubble.test.ts +175 -0
  88. package/src/components/message-bubble.ts +177 -19
  89. package/src/components/panel.ts +7 -10
  90. package/src/components/pill-composer-builder.test.ts +6 -2
  91. package/src/components/pill-composer-builder.ts +6 -6
  92. package/src/components/reasoning-bubble.ts +1 -13
  93. package/src/components/registry.ts +38 -3
  94. package/src/components/tool-bubble.ts +1 -13
  95. package/src/context-mentions-bundle.test.ts +163 -0
  96. package/src/context-mentions-entry.ts +185 -0
  97. package/src/context-mentions-inline-entry.test.ts +136 -0
  98. package/src/context-mentions-inline-entry.ts +226 -0
  99. package/src/context-mentions-inline-loader.test.ts +30 -0
  100. package/src/context-mentions-inline-loader.ts +36 -0
  101. package/src/context-mentions-inline.ts +15 -0
  102. package/src/context-mentions-loader.ts +32 -0
  103. package/src/context-mentions.ts +16 -0
  104. package/src/defaults.ts +1 -0
  105. package/src/generated/runtype-openapi-contract.ts +55 -3
  106. package/src/index-core.ts +46 -1
  107. package/src/index-global.ts +51 -0
  108. package/src/index.ts +8 -0
  109. package/src/markdown-parsers-loader.test.ts +158 -0
  110. package/src/markdown-parsers-loader.ts +83 -27
  111. package/src/plugin-kit.test.ts +40 -0
  112. package/src/plugin-kit.ts +39 -5
  113. package/src/runtime/host-layout.test.ts +163 -0
  114. package/src/runtime/host-layout.ts +110 -7
  115. package/src/runtime/init.ts +18 -61
  116. package/src/session.mentions.test.ts +175 -0
  117. package/src/session.test.ts +52 -4
  118. package/src/session.ts +197 -27
  119. package/src/smart-dom-reader.test.ts +129 -2
  120. package/src/smart-dom-reader.ts +127 -1
  121. package/src/styles/context-mention-menu-css.ts +176 -0
  122. package/src/styles/widget.css +1002 -152
  123. package/src/theme-editor/preview.ts +2 -0
  124. package/src/theme-editor/sections.test.ts +26 -1
  125. package/src/theme-editor/sections.ts +13 -5
  126. package/src/theme-reference.ts +2 -2
  127. package/src/tool-call-display-defaults.test.ts +1 -0
  128. package/src/types/theme.ts +79 -0
  129. package/src/types.ts +1041 -17
  130. package/src/ui.artifact-pane-gating.test.ts +636 -0
  131. package/src/ui.component-directive.test.ts +104 -0
  132. package/src/ui.composer-bar.test.ts +60 -2
  133. package/src/ui.detached-panel.test.ts +1049 -0
  134. package/src/ui.mention-submit.test.ts +235 -0
  135. package/src/ui.tool-display.test.ts +51 -0
  136. package/src/ui.ts +998 -159
  137. package/src/utils/artifact-custom-actions.ts +128 -0
  138. package/src/utils/artifact-display.test.ts +42 -0
  139. package/src/utils/artifact-display.ts +84 -0
  140. package/src/utils/artifact-file.test.ts +116 -0
  141. package/src/utils/artifact-file.ts +117 -0
  142. package/src/utils/artifact-gate.test.ts +112 -5
  143. package/src/utils/artifact-gate.ts +39 -14
  144. package/src/utils/artifact-loading-status.ts +55 -0
  145. package/src/utils/artifact-status-label.ts +190 -0
  146. package/src/utils/buttons.ts +7 -1
  147. package/src/utils/chunk-loader.test.ts +97 -0
  148. package/src/utils/chunk-loader.ts +88 -0
  149. package/src/utils/code-highlight.test.ts +186 -0
  150. package/src/utils/code-highlight.ts +400 -0
  151. package/src/utils/composer-contenteditable.test.ts +507 -0
  152. package/src/utils/composer-contenteditable.ts +626 -0
  153. package/src/utils/composer-document.test.ts +280 -0
  154. package/src/utils/composer-document.ts +293 -0
  155. package/src/utils/composer-history.test.ts +35 -7
  156. package/src/utils/composer-history.ts +30 -20
  157. package/src/utils/composer-input.ts +159 -0
  158. package/src/utils/context-mention-controller.test.ts +1215 -0
  159. package/src/utils/context-mention-controller.ts +1186 -0
  160. package/src/utils/context-mention-manager.test.ts +422 -0
  161. package/src/utils/context-mention-manager.ts +410 -0
  162. package/src/utils/context-mention-orchestrator.test.ts +538 -0
  163. package/src/utils/context-mention-orchestrator.ts +348 -0
  164. package/src/utils/icons.ts +2 -0
  165. package/src/utils/live-region.test.ts +108 -0
  166. package/src/utils/live-region.ts +94 -0
  167. package/src/utils/mention-channels.ts +63 -0
  168. package/src/utils/mention-llm-format.test.ts +91 -0
  169. package/src/utils/mention-llm-format.ts +79 -0
  170. package/src/utils/mention-matcher.test.ts +86 -0
  171. package/src/utils/mention-matcher.ts +221 -0
  172. package/src/utils/mention-token.ts +72 -0
  173. package/src/utils/mention-trigger.test.ts +155 -0
  174. package/src/utils/mention-trigger.ts +156 -0
  175. package/src/utils/roving-tablist.test.ts +152 -0
  176. package/src/utils/roving-tablist.ts +111 -0
  177. package/src/utils/spinner.ts +45 -0
  178. package/src/utils/theme.test.ts +76 -4
  179. package/src/utils/theme.ts +7 -0
  180. package/src/utils/tokens.ts +118 -11
  181. package/src/utils/tool-loading-animation.test.ts +32 -0
  182. package/src/utils/tool-loading-animation.ts +24 -0
  183. package/dist/chunk-DFBSCFYN.js +0 -1
  184. package/dist/runtype-tts-entry-HFUV2UF7.js +0 -1
  185. package/dist/session-reconnect-U77QFUR7.js +0 -1
@@ -1,3 +1,5 @@
1
+ import { IconNode } from 'lucide';
2
+
1
3
  /**
2
4
  * VENDORED type declarations: @mcp-b/smart-dom-reader v2.3.1 (MIT).
3
5
  * Copied verbatim from upstream dist/index.d.mts (only the trailing sourceMappingURL
@@ -690,6 +692,8 @@ interface ComponentTokenSet {
690
692
  margin?: TokenReference<'spacing'>;
691
693
  shadow?: TokenReference<'shadow'>;
692
694
  opacity?: number;
695
+ /** Hover background — used by transparent variants like `button.ghost`. */
696
+ hoverBackground?: TokenReference<'color'>;
693
697
  }
694
698
  interface ButtonTokens extends ComponentTokenSet {
695
699
  primary: ComponentTokenSet;
@@ -714,6 +718,10 @@ interface PanelTokens extends ComponentTokenSet {
714
718
  maxWidth: string;
715
719
  height: string;
716
720
  maxHeight: string;
721
+ /** Gap between the detached panel and its region edges. Only used when detached. */
722
+ inset?: string;
723
+ /** Background of the region revealed behind a detached panel. */
724
+ canvasBackground?: string;
717
725
  }
718
726
  interface HeaderTokens extends ComponentTokenSet {
719
727
  background: TokenReference<'color'>;
@@ -878,6 +886,14 @@ interface ArtifactToolbarTokens {
878
886
  iconBorder?: string;
879
887
  toggleGroupGap?: string;
880
888
  toggleBorderRadius?: string;
889
+ /** Inner padding of the segmented view/source toggle pill. */
890
+ toggleGroupPadding?: string;
891
+ /** Border of the segmented view/source toggle pill (e.g., `none`). */
892
+ toggleGroupBorder?: string;
893
+ /** Corner radius of the segmented view/source toggle pill. */
894
+ toggleGroupBorderRadius?: string;
895
+ /** Background of the segmented view/source toggle pill. */
896
+ toggleGroupBackground?: string;
881
897
  copyBackground?: string;
882
898
  copyBorder?: string;
883
899
  copyColor?: string;
@@ -909,6 +925,16 @@ interface ArtifactTabTokens {
909
925
  /** Tab list container padding (CSS shorthand). */
910
926
  listPadding?: string;
911
927
  }
928
+ /** Artifact reference card (chat thread) chrome. */
929
+ interface ArtifactCardTokens {
930
+ background?: string;
931
+ /** Full border shorthand (e.g. `1px solid #e5e7eb`). */
932
+ border?: string;
933
+ borderRadius?: string;
934
+ hoverBackground?: string;
935
+ /** Border color on hover. */
936
+ hoverBorderColor?: string;
937
+ }
912
938
  /** Artifact pane chrome. */
913
939
  interface ArtifactPaneTokens {
914
940
  /**
@@ -919,6 +945,54 @@ interface ArtifactPaneTokens {
919
945
  background?: string;
920
946
  toolbarBackground?: string;
921
947
  }
948
+ /** Inline artifact block chrome (`display: "inline"` file preview). */
949
+ interface ArtifactInlineTokens {
950
+ /** Background of the inline preview frame. */
951
+ background?: string;
952
+ /** Full border shorthand for the frame (e.g. `1px solid #e5e7eb`). */
953
+ border?: string;
954
+ /** Border radius of the inline preview frame. */
955
+ borderRadius?: string;
956
+ /** Background of the title/toolbar chrome bar. */
957
+ chromeBackground?: string;
958
+ /** Bottom border of the title bar. */
959
+ chromeBorder?: string;
960
+ /** Title text color in the chrome bar (artifact basename). */
961
+ titleColor?: string;
962
+ /** Muted text color for the type label / streaming status. */
963
+ mutedColor?: string;
964
+ /** Preview iframe height inside the inline body. */
965
+ frameHeight?: string;
966
+ }
967
+ /**
968
+ * Syntax-highlighted artifact source view (pane + inline), rendered by
969
+ * `utils/code-highlight.ts`. One Light defaults ship in `widget.css`, with a
970
+ * One Dark override keyed off the widget's resolved color scheme (the
971
+ * `data-persona-color-scheme` root attribute, not the OS preference); set any
972
+ * of these to retheme the tokenizer palette and the line-number gutter.
973
+ */
974
+ interface CodeTokens {
975
+ /** Keywords, booleans, null (e.g. `const`, `true`). */
976
+ keywordColor?: string;
977
+ /** String and template literals; HTML attribute values. */
978
+ stringColor?: string;
979
+ /** Line and block comments. */
980
+ commentColor?: string;
981
+ /** Numeric literals; CSS hex colors / units. */
982
+ numberColor?: string;
983
+ /** HTML tag brackets + names; doctype. */
984
+ tagColor?: string;
985
+ /** HTML attribute names. */
986
+ attrColor?: string;
987
+ /** CSS property names; JSON object keys. */
988
+ propertyColor?: string;
989
+ /** Line-number gutter digits. */
990
+ lineNumberColor?: string;
991
+ /** Right border of the line-number gutter. */
992
+ gutterBorderColor?: string;
993
+ /** Background of the source-view code sheet (defaults to One Light/Dark editor background). */
994
+ background?: string;
995
+ }
922
996
  /** Icon button chrome (used by createIconButton). */
923
997
  interface IconButtonTokens {
924
998
  background?: string;
@@ -988,9 +1062,13 @@ interface ComponentTokens {
988
1062
  toolbar?: ArtifactToolbarTokens;
989
1063
  tab?: ArtifactTabTokens;
990
1064
  pane?: ArtifactPaneTokens;
1065
+ card?: ArtifactCardTokens;
1066
+ inline?: ArtifactInlineTokens;
991
1067
  };
992
1068
  /** Collapsible widget chrome (tool/reasoning/approval bubbles). */
993
1069
  collapsibleWidget?: CollapsibleWidgetTokens;
1070
+ /** Syntax-highlighted artifact source view (tokenizer palette + gutter). */
1071
+ code?: CodeTokens;
994
1072
  }
995
1073
  interface PaletteExtras {
996
1074
  transitions?: Record<string, string>;
@@ -1033,6 +1111,7 @@ type RuntypeExecutionStreamEvent = ({
1033
1111
  totalSteps?: number;
1034
1112
  type: "execution_start";
1035
1113
  }) | ({
1114
+ claudeManagedAgentId?: string;
1036
1115
  completedAt?: string;
1037
1116
  durationMs?: number;
1038
1117
  executionId: string;
@@ -1077,6 +1156,15 @@ type RuntypeExecutionStreamEvent = ({
1077
1156
  completedAt?: string;
1078
1157
  content?: string;
1079
1158
  cost?: number;
1159
+ estimatedContextBreakdown?: {
1160
+ categories: Record<string, {
1161
+ chars: number;
1162
+ estimatedTokens: number;
1163
+ }>;
1164
+ contextWindowSize?: number;
1165
+ estimatedTotalTokens: number;
1166
+ estimatedUtilizationPercent?: number;
1167
+ };
1080
1168
  executionId: string;
1081
1169
  fallback?: {
1082
1170
  attempts: Array<{
@@ -1114,6 +1202,7 @@ type RuntypeExecutionStreamEvent = ({
1114
1202
  type: "step_start";
1115
1203
  } | ({
1116
1204
  completedAt?: string;
1205
+ cost?: number;
1117
1206
  durationMs?: number;
1118
1207
  error?: string;
1119
1208
  executionId: string;
@@ -1219,6 +1308,11 @@ type RuntypeExecutionStreamEvent = ({
1219
1308
  artifactType: "markdown" | "component";
1220
1309
  component?: string;
1221
1310
  executionId?: string;
1311
+ file?: {
1312
+ language?: string;
1313
+ mimeType: string;
1314
+ path: string;
1315
+ };
1222
1316
  id: string;
1223
1317
  seq?: number;
1224
1318
  title?: string;
@@ -1327,6 +1421,14 @@ type RuntypeExecutionStreamEvent = ({
1327
1421
  awaitReason?: string;
1328
1422
  awaitedAt?: string;
1329
1423
  crawlId?: string;
1424
+ elicitation?: {
1425
+ message: string;
1426
+ mode: "form" | "url";
1427
+ pauseCount?: number;
1428
+ requestedSchema?: Record<string, unknown>;
1429
+ serverName?: string;
1430
+ url?: string;
1431
+ };
1330
1432
  executionId: string;
1331
1433
  origin?: "webmcp" | "sdk";
1332
1434
  pageOrigin?: string;
@@ -1426,6 +1528,14 @@ type RuntypeFlowSSEEvent = {
1426
1528
  awaitReason?: string;
1427
1529
  awaitedAt: string;
1428
1530
  crawlId?: string;
1531
+ elicitation?: {
1532
+ message: string;
1533
+ mode: "form" | "url";
1534
+ pauseCount?: number;
1535
+ requestedSchema?: Record<string, unknown>;
1536
+ serverName?: string;
1537
+ url?: string;
1538
+ };
1429
1539
  executionId?: string;
1430
1540
  flowId: string;
1431
1541
  origin?: "webmcp" | "sdk";
@@ -1476,7 +1586,7 @@ type RuntypeFlowSSEEvent = {
1476
1586
  completedAt?: string;
1477
1587
  duration?: number;
1478
1588
  durationMs?: number;
1479
- error?: string;
1589
+ error?: string | null;
1480
1590
  executionId?: string;
1481
1591
  executionTime?: number;
1482
1592
  id?: string;
@@ -1520,13 +1630,21 @@ type RuntypeFlowSSEEvent = {
1520
1630
  totalSteps: number;
1521
1631
  type: "step_skip";
1522
1632
  when: string;
1523
- } | {
1633
+ } | ({
1634
+ elicitation?: {
1635
+ message: string;
1636
+ mode: "form" | "url";
1637
+ pauseCount?: number;
1638
+ requestedSchema?: Record<string, unknown>;
1639
+ serverName?: string;
1640
+ url?: string;
1641
+ };
1524
1642
  executionId?: string;
1525
1643
  reason?: string;
1526
1644
  seq?: number;
1527
1645
  type: "step_await";
1528
1646
  [key: string]: unknown;
1529
- } | ({
1647
+ }) | ({
1530
1648
  agentContext?: {
1531
1649
  executionId: string;
1532
1650
  iteration: number;
@@ -1691,6 +1809,149 @@ type TargetResolver = (id: string) => {
1691
1809
  payload: Record<string, unknown>;
1692
1810
  };
1693
1811
 
1812
+ /**
1813
+ * Curated registry of lucide icons available to `renderLucideIcon`.
1814
+ *
1815
+ * The widget used to do `import * as icons from "lucide"` and look up
1816
+ * icons dynamically by string. That defeated tree-shaking, so the IIFE
1817
+ * (CDN/script-tag) bundle shipped all 1640 lucide icons (~400KB of icon
1818
+ * data) regardless of which we actually used. This explicit registry
1819
+ * lets the bundler drop any icon not listed here.
1820
+ *
1821
+ * Trade-off: `renderLucideIcon(name)` is now a *closed set*. Names not
1822
+ * in this map return `null` and log a warning, exactly as a typo did
1823
+ * before. The registry is intentionally generous (~110 icons) so that
1824
+ * custom `ComponentRenderer` authors rarely hit a missing-icon dead end.
1825
+ *
1826
+ * To add icons: add a named import above and a row in `LUCIDE_ICONS`,
1827
+ * keyed by the lucide kebab-case name (matches their filename and
1828
+ * https://lucide.dev/icons).
1829
+ *
1830
+ * See `packages/widget/docs/icon-registry-shortlist.md` for the full
1831
+ * curation rationale and which icons were considered but excluded.
1832
+ */
1833
+ declare const LUCIDE_ICONS: {
1834
+ readonly activity: IconNode;
1835
+ readonly "arrow-down": IconNode;
1836
+ readonly "arrow-up": IconNode;
1837
+ readonly "arrow-up-right": IconNode;
1838
+ readonly bot: IconNode;
1839
+ readonly "chevron-down": IconNode;
1840
+ readonly "chevron-up": IconNode;
1841
+ readonly "chevron-right": IconNode;
1842
+ readonly "chevron-left": IconNode;
1843
+ readonly check: IconNode;
1844
+ readonly clipboard: IconNode;
1845
+ readonly "clipboard-copy": IconNode;
1846
+ readonly "code-xml": IconNode;
1847
+ readonly copy: IconNode;
1848
+ readonly file: IconNode;
1849
+ readonly "file-code": IconNode;
1850
+ readonly "file-spreadsheet": IconNode;
1851
+ readonly "file-text": IconNode;
1852
+ readonly "image-plus": IconNode;
1853
+ readonly loader: IconNode;
1854
+ readonly "loader-circle": IconNode;
1855
+ readonly mic: IconNode;
1856
+ readonly paperclip: IconNode;
1857
+ readonly "refresh-cw": IconNode;
1858
+ readonly search: IconNode;
1859
+ readonly send: IconNode;
1860
+ readonly "shield-alert": IconNode;
1861
+ readonly "shield-check": IconNode;
1862
+ readonly "shield-x": IconNode;
1863
+ readonly square: IconNode;
1864
+ readonly "thumbs-down": IconNode;
1865
+ readonly "thumbs-up": IconNode;
1866
+ readonly upload: IconNode;
1867
+ readonly "volume-2": IconNode;
1868
+ readonly x: IconNode;
1869
+ readonly user: IconNode;
1870
+ readonly mail: IconNode;
1871
+ readonly phone: IconNode;
1872
+ readonly calendar: IconNode;
1873
+ readonly clock: IconNode;
1874
+ readonly building: IconNode;
1875
+ readonly "map-pin": IconNode;
1876
+ readonly lock: IconNode;
1877
+ readonly key: IconNode;
1878
+ readonly "credit-card": IconNode;
1879
+ readonly "at-sign": IconNode;
1880
+ readonly hash: IconNode;
1881
+ readonly globe: IconNode;
1882
+ readonly link: IconNode;
1883
+ readonly "circle-check": IconNode;
1884
+ readonly "circle-x": IconNode;
1885
+ readonly "triangle-alert": IconNode;
1886
+ readonly info: IconNode;
1887
+ readonly ban: IconNode;
1888
+ readonly shield: IconNode;
1889
+ readonly "arrow-left": IconNode;
1890
+ readonly "arrow-right": IconNode;
1891
+ readonly "external-link": IconNode;
1892
+ readonly ellipsis: IconNode;
1893
+ readonly "ellipsis-vertical": IconNode;
1894
+ readonly menu: IconNode;
1895
+ readonly house: IconNode;
1896
+ readonly plus: IconNode;
1897
+ readonly minus: IconNode;
1898
+ readonly pencil: IconNode;
1899
+ readonly trash: IconNode;
1900
+ readonly "trash-2": IconNode;
1901
+ readonly save: IconNode;
1902
+ readonly download: IconNode;
1903
+ readonly share: IconNode;
1904
+ readonly funnel: IconNode;
1905
+ readonly settings: IconNode;
1906
+ readonly "rotate-cw": IconNode;
1907
+ readonly maximize: IconNode;
1908
+ readonly minimize: IconNode;
1909
+ readonly "shopping-cart": IconNode;
1910
+ readonly "shopping-bag": IconNode;
1911
+ readonly package: IconNode;
1912
+ readonly truck: IconNode;
1913
+ readonly tag: IconNode;
1914
+ readonly gift: IconNode;
1915
+ readonly receipt: IconNode;
1916
+ readonly wallet: IconNode;
1917
+ readonly store: IconNode;
1918
+ readonly "dollar-sign": IconNode;
1919
+ readonly percent: IconNode;
1920
+ readonly play: IconNode;
1921
+ readonly pause: IconNode;
1922
+ readonly "volume-x": IconNode;
1923
+ readonly camera: IconNode;
1924
+ readonly image: IconNode;
1925
+ readonly film: IconNode;
1926
+ readonly headphones: IconNode;
1927
+ readonly "message-circle": IconNode;
1928
+ readonly "message-square": IconNode;
1929
+ readonly bell: IconNode;
1930
+ readonly heart: IconNode;
1931
+ readonly star: IconNode;
1932
+ readonly eye: IconNode;
1933
+ readonly "eye-off": IconNode;
1934
+ readonly bookmark: IconNode;
1935
+ readonly "calendar-days": IconNode;
1936
+ readonly history: IconNode;
1937
+ readonly timer: IconNode;
1938
+ readonly folder: IconNode;
1939
+ readonly "folder-open": IconNode;
1940
+ readonly files: IconNode;
1941
+ readonly sparkles: IconNode;
1942
+ readonly zap: IconNode;
1943
+ readonly sun: IconNode;
1944
+ readonly moon: IconNode;
1945
+ readonly flag: IconNode;
1946
+ readonly monitor: IconNode;
1947
+ readonly smartphone: IconNode;
1948
+ };
1949
+ /**
1950
+ * Names of lucide icons that ship with the widget. Names not in this
1951
+ * union return `null` from `renderLucideIcon` (with a console warning).
1952
+ */
1953
+ type IconName = keyof typeof LUCIDE_ICONS;
1954
+
1694
1955
  /**
1695
1956
  * Text content part for multi-modal messages
1696
1957
  */
@@ -1749,6 +2010,446 @@ type AgentWidgetContextProviderContext = {
1749
2010
  config: AgentWidgetConfig;
1750
2011
  };
1751
2012
  type AgentWidgetContextProvider = (context: AgentWidgetContextProviderContext) => Record<string, unknown> | void | Promise<Record<string, unknown> | void>;
2013
+ /** A single selectable item in the mention menu (host-provided). */
2014
+ type AgentWidgetContextMentionItem = {
2015
+ /** Stable key within its source. */
2016
+ id: string;
2017
+ /** Shown in the menu and on the chip (e.g. "App.tsx"). */
2018
+ label: string;
2019
+ /** Subtitle line in the menu. */
2020
+ description?: string;
2021
+ /** Lucide icon name. */
2022
+ iconName?: string;
2023
+ /**
2024
+ * Accent color for this item's inline token (`display: "inline"`), any CSS
2025
+ * color. Sets `--persona-mention-token-accent` on the token, tinting its pill
2026
+ * background + icon/label — the per-item/per-type color knob (Slack/Linear
2027
+ * style). Prefer setting the same color across a source's items for a "color
2028
+ * per type" look, or theme by `[data-mention-source]` in CSS instead. Ignored
2029
+ * in chip mode.
2030
+ */
2031
+ color?: string;
2032
+ /** Group header override; defaults to the source's `label`. */
2033
+ group?: string;
2034
+ /** Optional recency/popularity hint the default matcher boosts on. */
2035
+ recencyScore?: number;
2036
+ /**
2037
+ * SKILLS / SLASH-COMMANDS. When set, this item is a COMMAND (a verb) rather
2038
+ * than a context mention (a noun), so selecting it dispatches a behavior
2039
+ * instead of adding a context chip. Absent for ordinary mentions.
2040
+ *
2041
+ * - `"prompt"`: a prompt macro. `resolve()` returns `insertText` (or
2042
+ * `llmAppend`) which is written into the composer (see `insertMode`);
2043
+ * `submitOnSelect` optionally sends it immediately. No chip.
2044
+ * - `"action"`: a client action. `action()` runs in the browser; no resolve,
2045
+ * no chip, no message sent (e.g. `/clear`, `/theme dark`).
2046
+ * - `"server"`: a server-invoked skill. Routed like a `resolveOn:"submit"`
2047
+ * mention whose `resolve().context` reaches the backend via request
2048
+ * `context.mentions.<sourceId>.<itemId>` (a flow/agent reads it).
2049
+ */
2050
+ command?: "prompt" | "action" | "server";
2051
+ /**
2052
+ * `command:"action"` handler. Receives the parsed `args` (text after the
2053
+ * command name), plus a small `composer` capability + `config`/`messages`.
2054
+ * Short-circuits the mention flow (no chip, no send). Ignored otherwise.
2055
+ */
2056
+ action?: (ctx: AgentWidgetContextMentionCommandContext) => void | Promise<void>;
2057
+ /**
2058
+ * `command:"prompt"` insertion mode. `"replace"` (default) swaps the whole
2059
+ * composer value for the resolved text; `"insert-at-caret"` replaces only the
2060
+ * `/token` span, keeping surrounding prose. Ignored otherwise.
2061
+ */
2062
+ insertMode?: "replace" | "insert-at-caret";
2063
+ /**
2064
+ * When true, a `command:"prompt"` submits the composer immediately after
2065
+ * inserting its text (a one-shot macro). Ignored for other kinds.
2066
+ */
2067
+ submitOnSelect?: boolean;
2068
+ /**
2069
+ * COMMANDS only. Ghost hint for a free-text argument (e.g. "order id" →
2070
+ * `/lookup ‹order id›` in the menu). Its presence switches the command to
2071
+ * INLINE COMPLETION (Slack-style): selecting it fills `/name ` into the
2072
+ * composer for inline arg entry instead of dispatching on select, and the
2073
+ * command is executed at SUBMIT with the typed args. `command:"server"` items
2074
+ * always use inline completion (their chip had no way to add an argument);
2075
+ * for `"prompt"`/`"action"` items this is opt-in. Ignored for non-commands.
2076
+ */
2077
+ commandArgsPlaceholder?: string;
2078
+ };
2079
+ /**
2080
+ * Capability object handed to a `command:"action"` handler. The widget exposes
2081
+ * only composer-local operations; broader actions (clear the transcript, change
2082
+ * theme) are wired by the host via closures over its own controller.
2083
+ */
2084
+ type AgentWidgetContextMentionComposerCapability = {
2085
+ /** Current composer text. */
2086
+ getValue: () => string;
2087
+ /** Replace composer text (fires `input`, moves caret to end, refocuses). */
2088
+ setValue: (value: string) => void;
2089
+ /** Submit the composer (same path as pressing send). */
2090
+ submit: () => void;
2091
+ };
2092
+ /** Context passed to a `command:"action"` handler. */
2093
+ type AgentWidgetContextMentionCommandContext = {
2094
+ /** Text typed after the command name (e.g. `staging` for `/deploy staging`). */
2095
+ args: string;
2096
+ config: AgentWidgetConfig;
2097
+ messages: AgentWidgetMessage[];
2098
+ composer: AgentWidgetContextMentionComposerCapability;
2099
+ };
2100
+ /** Reference stored on a sent message for transcript fidelity + chip rendering. */
2101
+ type AgentWidgetContextMentionRef = {
2102
+ sourceId: string;
2103
+ itemId: string;
2104
+ label: string;
2105
+ iconName?: string;
2106
+ /** Accent color for the inline token (see `AgentWidgetContextMentionItem.color`). */
2107
+ color?: string;
2108
+ };
2109
+ /**
2110
+ * One ordered segment of a sent message's prose, for inline mention rendering
2111
+ * (`contextMentions.display: "inline"`). Text runs and atomic mention tokens
2112
+ * interleave in document order so the sent bubble re-renders `@tokens` in place
2113
+ * and composer history can round-trip them. Display/transcript concern only —
2114
+ * the model still sees resolved bodies via `llmContent`/`contentParts`.
2115
+ */
2116
+ type AgentWidgetContentSegment = {
2117
+ kind: "text";
2118
+ text: string;
2119
+ } | {
2120
+ kind: "mention";
2121
+ ref: AgentWidgetContextMentionRef;
2122
+ };
2123
+ /**
2124
+ * The payload a source returns from `resolve()` for one selected item.
2125
+ * Lead with `llmAppend` — it is the only channel guaranteed to reach the model
2126
+ * with no backend changes.
2127
+ */
2128
+ type AgentWidgetContextMentionPayload = {
2129
+ /**
2130
+ * PRIMARY, model-visible channel. Appended to this user message's LLM content
2131
+ * so the model actually sees the context with no backend changes.
2132
+ */
2133
+ llmAppend?: string;
2134
+ /**
2135
+ * `command:"prompt"` macros only. Text written into the COMPOSER on select
2136
+ * (see `AgentWidgetContextMentionItem.insertMode`) — distinct from the hidden
2137
+ * `llmAppend` context channel. Falls back to `llmAppend` when omitted.
2138
+ */
2139
+ insertText?: string;
2140
+ /** Extra content parts (e.g. file text / image) via the multi-modal path. */
2141
+ contentParts?: ContentPart[];
2142
+ /**
2143
+ * OPT-IN structured channel. Merged into request `context` under
2144
+ * `mentions.<sourceId>.<itemId>` for flows/agents that read it. NOTE: ambient
2145
+ * `context` is NOT guaranteed to reach the model — use `llmAppend` if you need
2146
+ * the model to see it.
2147
+ */
2148
+ context?: Record<string, unknown>;
2149
+ };
2150
+ /**
2151
+ * One resolved mention, handed to `contextMentions.llmFormat` to build the
2152
+ * model-visible block. `text` is the source's `llmAppend`; `ref`/`item` carry
2153
+ * the selection identity/metadata for a custom formatter (e.g. a source-specific
2154
+ * wrapper or a path from `item`).
2155
+ */
2156
+ type AgentWidgetMentionLlmEntry = {
2157
+ /** The mention's display label (from `ref.label`). */
2158
+ label: string;
2159
+ /** The resolved model-visible body (the source's `llmAppend`). */
2160
+ text: string;
2161
+ ref: AgentWidgetContextMentionRef;
2162
+ item: AgentWidgetContextMentionItem;
2163
+ };
2164
+ type AgentWidgetContextMentionSearchContext = {
2165
+ messages: AgentWidgetMessage[];
2166
+ config: AgentWidgetConfig;
2167
+ /** Aborts when the next keystroke supersedes this in-flight search. */
2168
+ signal: AbortSignal;
2169
+ };
2170
+ type AgentWidgetContextMentionResolveContext = AgentWidgetContextMentionSearchContext & {
2171
+ /** Plain-text composer value at resolve time. */
2172
+ composerText: string;
2173
+ /**
2174
+ * For `command` items: the text typed after the command name (e.g.
2175
+ * `"123"` for `/lookup 123`). Empty string for ordinary mentions.
2176
+ */
2177
+ args: string;
2178
+ };
2179
+ type AgentWidgetContextMentionSource = {
2180
+ id: string;
2181
+ /** Group header shown in the menu. */
2182
+ label: string;
2183
+ /**
2184
+ * Filter items for the current `@query` (empty query → recent/popular).
2185
+ * Implement server-side search for large/remote sets, or return all items and
2186
+ * let the widget rank them with `defaultMentionFilter`
2187
+ * (see `createStaticMentionSource` for the common case).
2188
+ */
2189
+ search: (query: string, ctx: AgentWidgetContextMentionSearchContext) => AgentWidgetContextMentionItem[] | Promise<AgentWidgetContextMentionItem[]>;
2190
+ /**
2191
+ * Fetch the payload for dispatch. Called once when the user SELECTS the item
2192
+ * (eagerly, cached on the chip, abortable on removal) unless `resolveOn` is
2193
+ * `"submit"`. A throw/abort drops the mention via `onMentionResolveError`.
2194
+ */
2195
+ resolve: (item: AgentWidgetContextMentionItem, ctx: AgentWidgetContextMentionResolveContext) => AgentWidgetContextMentionPayload | Promise<AgentWidgetContextMentionPayload>;
2196
+ /**
2197
+ * When to call `resolve()`:
2198
+ * - `"select"` (default): eager on pick; parallelizes the fetch with the user
2199
+ * finishing their sentence so submit stays instant.
2200
+ * - `"submit"`: defer to send time, for time-sensitive sources (e.g. current
2201
+ * page state that may change between select and send).
2202
+ * @default "select"
2203
+ */
2204
+ resolveOn?: "select" | "submit";
2205
+ /**
2206
+ * COMMAND sources only. Resolve a `/name` (the first token of a command line)
2207
+ * to its menu item, for submit-time inline-command dispatch and the menu's
2208
+ * "typing args now" suppression. `createSlashCommandsSource` sets this; plain
2209
+ * `@`-mention sources leave it undefined.
2210
+ */
2211
+ matchCommand?: (name: string) => AgentWidgetContextMentionItem | undefined;
2212
+ };
2213
+ /** Context passed to the optional `renderMentionMenu` override. */
2214
+ type AgentWidgetContextMentionMenuRenderContext = {
2215
+ /** Current trigger query ("" when freshly opened). */
2216
+ query: string;
2217
+ /** Grouped, ranked, capped results ready to paint. */
2218
+ groups: {
2219
+ source: AgentWidgetContextMentionSource;
2220
+ items: AgentWidgetContextMentionItem[];
2221
+ }[];
2222
+ /** Per-source async state for loading/empty/error rendering, keyed by source id. */
2223
+ status: Record<string, "loading" | "ready" | "empty" | "error">;
2224
+ /** Index into the flat keyboard-traversal order. */
2225
+ activeIndex: number;
2226
+ /** Commit a selection (strips `@query`, adds chip, resolves on select). */
2227
+ select: (item: AgentWidgetContextMentionItem) => void;
2228
+ /** Close the menu, keeping a literal `@`. */
2229
+ close: () => void;
2230
+ };
2231
+ /** Context passed to the optional `renderMentionItem` per-row override. */
2232
+ type AgentWidgetContextMentionItemRenderContext = {
2233
+ /** The item to render. */
2234
+ item: AgentWidgetContextMentionItem;
2235
+ /** The source this item came from (its group). */
2236
+ source: AgentWidgetContextMentionSource;
2237
+ /** Current trigger query, for highlighting matches. */
2238
+ query: string;
2239
+ /** True when this row is the keyboard-highlighted one at render time. */
2240
+ active: boolean;
2241
+ /** Position in the flat keyboard-traversal order. */
2242
+ index: number;
2243
+ };
2244
+ /** Context passed to the optional `renderMentionChip` override. */
2245
+ type AgentWidgetContextMentionChipRenderContext = {
2246
+ ref: AgentWidgetContextMentionRef;
2247
+ /** Resolve-on-select lifecycle for spinner→ready→error UI. */
2248
+ status: "resolving" | "ready" | "error";
2249
+ /**
2250
+ * The resolved payload, once available (select-resolved sources only). Use it
2251
+ * to preview already-fetched content on hover. Undefined while `status` is
2252
+ * `"resolving"`, on `"error"`, and for `resolveOn:"submit"` sources (which
2253
+ * resolve at send time, not while the chip sits in the composer — for those,
2254
+ * `ref.itemId` carries the source key you can re-read on demand, e.g. a CSS
2255
+ * selector for the smart-dom source).
2256
+ */
2257
+ payload?: AgentWidgetContextMentionPayload;
2258
+ /** Remove the chip; aborts any in-flight resolve. */
2259
+ remove: () => void;
2260
+ };
2261
+ /**
2262
+ * Where a trigger char is allowed to open the menu:
2263
+ * - `"anywhere"` (default): after any whitespace or start (the `@` rule).
2264
+ * - `"line-start"`: only when the char before the trigger is a newline or the
2265
+ * start of input — the natural rule for `/` slash-commands.
2266
+ * - `"input-start"`: only at index 0 of the composer.
2267
+ */
2268
+ type AgentWidgetMentionTriggerPosition = "anywhere" | "line-start" | "input-start";
2269
+ /**
2270
+ * A SECOND (or Nth) trigger channel sharing the same menu engine — e.g. `/` for
2271
+ * slash-commands alongside `@` for context. The legacy `trigger`/`sources`
2272
+ * fields form the implicit first channel; `triggers[]` adds more. At any caret
2273
+ * at most one channel is active, so all channels drive one menu/controller.
2274
+ */
2275
+ type AgentWidgetMentionTriggerChannel = {
2276
+ /** Trigger character (e.g. "/"). */
2277
+ trigger: string;
2278
+ /** Sources for this channel (searched only when this trigger is active). */
2279
+ sources: AgentWidgetContextMentionSource[];
2280
+ /** Where the trigger may open. @default "anywhere" */
2281
+ triggerPosition?: AgentWidgetMentionTriggerPosition;
2282
+ /**
2283
+ * Let the query span spaces so a command can take ARGS (`/deploy staging`).
2284
+ * A newline still ends it. Pair with `triggerPosition: "line-start"` for
2285
+ * slash-commands. @default false
2286
+ */
2287
+ allowSpaces?: boolean;
2288
+ /** Show a composer affordance button for this channel. @default false */
2289
+ showButton?: boolean;
2290
+ /** Icon for this channel's affordance button. */
2291
+ buttonIconName?: string;
2292
+ /** Tooltip / aria-label for this channel's affordance button. */
2293
+ buttonTooltipText?: string;
2294
+ /** Placeholder for this channel's picker search field. */
2295
+ searchPlaceholder?: string;
2296
+ };
2297
+ type AgentWidgetContextMentionConfig = {
2298
+ /** @default false */
2299
+ enabled?: boolean;
2300
+ /**
2301
+ * Show the visible composer affordance button (the discoverable entry point).
2302
+ * Strongly recommended; the bare `@` trigger alone is hard to discover for
2303
+ * non-technical users. @default true
2304
+ */
2305
+ showButton?: boolean;
2306
+ /**
2307
+ * Icon for the affordance button (any registered Lucide name). Defaults to a
2308
+ * "+" signifier — the consumer-recognized "add context" affordance — rather
2309
+ * than an "@" glyph, which reads as power-user. Use `"at-sign"` on a
2310
+ * developer/power-user surface. @default "plus"
2311
+ */
2312
+ buttonIconName?: string;
2313
+ /** Tooltip / aria-label for the affordance button. @default "Add context" */
2314
+ buttonTooltipText?: string;
2315
+ /**
2316
+ * Placeholder for the picker's search field, shown when the menu is opened
2317
+ * from the affordance button (a Cursor/Copilot-style picker that inserts no
2318
+ * trigger character). The typed-trigger path keeps its query in the textarea
2319
+ * and never shows this field. @default "Search context…"
2320
+ */
2321
+ searchPlaceholder?: string;
2322
+ /** Trigger character. @default "@" */
2323
+ trigger?: string;
2324
+ /**
2325
+ * Where the primary `trigger` may open the menu. @default "anywhere"
2326
+ */
2327
+ triggerPosition?: AgentWidgetMentionTriggerPosition;
2328
+ /**
2329
+ * ADDITIONAL trigger channels sharing this engine — e.g. a `/` slash-command
2330
+ * channel next to `@` context. Each channel has its own trigger char,
2331
+ * sources, and position rule. See `AgentWidgetMentionTriggerChannel`.
2332
+ */
2333
+ triggers?: AgentWidgetMentionTriggerChannel[];
2334
+ /** Max mentions per message. @default 8 */
2335
+ maxMentions?: number;
2336
+ /** Max items shown per source group before "keep typing to narrow". @default 6 */
2337
+ maxItemsPerGroup?: number;
2338
+ /**
2339
+ * Debounce for ASYNC source search only (ms). Synchronous sources and the
2340
+ * menu's first paint are never debounced. @default 150
2341
+ */
2342
+ searchDebounceMs?: number;
2343
+ /** Registered mention sources (search + resolve). */
2344
+ sources: AgentWidgetContextMentionSource[];
2345
+ /** Chip icon fallback when a source/item omits one. @default "at-sign" */
2346
+ chipIconName?: string;
2347
+ /**
2348
+ * How each resolved mention's `llmAppend` text is wrapped into a delimited
2349
+ * block before it is prepended to the model-visible message content. Blocks
2350
+ * are joined with a blank line and the typed prose follows last.
2351
+ *
2352
+ * - `"fenced"` (default): a fenced code block with the label in the info
2353
+ * string, e.g. selecting `App.tsx` emits:
2354
+ * ```text
2355
+ * ```App.tsx
2356
+ * <file body>
2357
+ * ```
2358
+ * ```
2359
+ * The fence auto-escalates (four+ backticks) when the body itself contains a
2360
+ * fence, so a body can never terminate its own wrapper.
2361
+ * - `"document"`: Anthropic's long-context document shape, e.g.:
2362
+ * ```text
2363
+ * <document index="1">
2364
+ * <source>App.tsx</source>
2365
+ * <document_content>
2366
+ * <file body>
2367
+ * </document_content>
2368
+ * </document>
2369
+ * ```
2370
+ * Prefer this for prose/document-shaped sources per Anthropic's long-context
2371
+ * guidance (indexed `<document>` blocks improve grounding and citation). A
2372
+ * body containing the literal `</document_content>` closing tag falls back to
2373
+ * the fenced block for that entry to avoid a broken XML boundary.
2374
+ * - function form: fully owns the block for one mention — its return string is
2375
+ * used verbatim (no extra wrapping), joined with the other blocks. `index` is
2376
+ * the 0-based position among the message's mention blocks.
2377
+ *
2378
+ * @default "fenced"
2379
+ */
2380
+ llmFormat?: "fenced" | "document" | ((entry: AgentWidgetMentionLlmEntry, index: number) => string);
2381
+ /**
2382
+ * How `@` selections appear in the composer and sent user bubble.
2383
+ *
2384
+ * - `"chip"` (default): strip `@query` on select; show a compact pill in the
2385
+ * composer context row; `content` is prose-only.
2386
+ * - `"inline"`: insert an atomic styled token in the sentence (Slack/Linear/
2387
+ * Cursor style), backed by a contenteditable composer. Slash-command channels
2388
+ * (`triggers[]` with `/`) stay inline-text regardless — they already use the
2389
+ * `/name args` model, not chips. `renderMentionChip` is ignored for `@`
2390
+ * mentions in this mode.
2391
+ *
2392
+ * The resolved-context channel (`llmContent`/`contentParts`) is unchanged
2393
+ * across both modes — inline tokens are a display concern.
2394
+ *
2395
+ * @default "chip"
2396
+ */
2397
+ display?: "chip" | "inline";
2398
+ /**
2399
+ * Fired when a pick is rejected: it duplicates an existing chip in chip display
2400
+ * (`"duplicate"` — inline display allows the same item as multiple tokens, so it
2401
+ * never rejects for this reason), hits `maxMentions` (`"limit"`), or (inline
2402
+ * display) the composer text changed between parse and commit so the token could
2403
+ * not be inserted (`"stale"`).
2404
+ */
2405
+ onMentionRejected?: (item: AgentWidgetContextMentionItem, reason: "duplicate" | "limit" | "stale") => void;
2406
+ /**
2407
+ * A `resolve()` that throws/aborts: the mention is dropped and the message
2408
+ * still sends. Surface a non-blocking notice here if desired.
2409
+ */
2410
+ onMentionResolveError?: (item: AgentWidgetContextMentionItem, error: unknown) => void;
2411
+ /**
2412
+ * MID-LEVEL render override for the autocomplete menu. The widget still owns
2413
+ * trigger detection, search, debounce/abort, keyboard nav, and positioning;
2414
+ * you only supply the menu markup and drive selection through `ctx`. Omit to
2415
+ * use the built-in grouped menu. @default built-in
2416
+ */
2417
+ renderMentionMenu?: (ctx: AgentWidgetContextMentionMenuRenderContext) => HTMLElement;
2418
+ /**
2419
+ * NARROW render override for a single result row's INNER content, keeping the
2420
+ * built-in menu chrome (group headers, loading/empty/error, keyboard nav, the
2421
+ * "keep typing" hint). The widget keeps the `role="option"` wrapper and its
2422
+ * click/hover wiring; you return only the row's contents. For full menu
2423
+ * control use `renderMentionMenu` instead. Highlight is CSS-driven via the
2424
+ * wrapper's `[data-active]` attribute, so this is called once per render, not
2425
+ * on every arrow key. Ignored when `renderMentionMenu` is set. @default built-in
2426
+ */
2427
+ renderMentionItem?: (ctx: AgentWidgetContextMentionItemRenderContext) => HTMLElement;
2428
+ /**
2429
+ * MID-LEVEL render override for a single context chip. Return your own pill
2430
+ * (must include an accessible remove control wired to `ctx.remove`); reflect
2431
+ * `ctx.status` for resolve-on-select. Omit to use the built-in compact pill.
2432
+ * @default built-in
2433
+ */
2434
+ renderMentionChip?: (ctx: AgentWidgetContextMentionChipRenderContext) => HTMLElement;
2435
+ /**
2436
+ * INLINE display only (`display: "inline"`). Render override for a single inline
2437
+ * mention TOKEN — the atomic styled node that sits in the sentence, in both the
2438
+ * contenteditable composer and the read-only sent bubble. Return your own
2439
+ * element (e.g. a fully custom colored pill); the composer marks it
2440
+ * `contenteditable="false"` and stamps `data-mention-id` so it stays atomic.
2441
+ * Omit to use the built-in pill (icon + `@label`, tinted by
2442
+ * `--persona-mention-token-accent` / `ref.color`, themeable per source via the
2443
+ * `[data-mention-source]` attribute). Ignored in chip mode.
2444
+ * @default built-in
2445
+ */
2446
+ renderMentionToken?: (ctx: AgentWidgetContextMentionTokenRenderContext) => HTMLElement;
2447
+ };
2448
+ /** Render context for `renderMentionToken`. `readonly` is true in the sent bubble. */
2449
+ type AgentWidgetContextMentionTokenRenderContext = {
2450
+ ref: AgentWidgetContextMentionRef;
2451
+ readonly: boolean;
2452
+ };
1752
2453
  type AgentWidgetRequestPayloadMessage = {
1753
2454
  role: AgentWidgetMessageRole;
1754
2455
  content: MessageContent;
@@ -2211,7 +2912,13 @@ type AgentWidgetMessageActionsConfig = {
2211
2912
  * new artifact content arrives or the host calls `showArtifacts()` on the widget handle.
2212
2913
  */
2213
2914
  type AgentWidgetArtifactsLayoutConfig = {
2214
- /** Flex gap between chat column and artifact pane. @default 0.5rem */
2915
+ /**
2916
+ * Flex gap between chat column and artifact pane.
2917
+ * @default 0 (welded); detached uses the panel inset
2918
+ * @remarks In welded appearances (`panel` / `seamless`) a nonzero gap opens a
2919
+ * visible seam in the single card. It is honored geometrically (resize clamps
2920
+ * and the seam handle account for it) but is usually undesired.
2921
+ */
2215
2922
  splitGap?: string;
2216
2923
  /** Artifact column width in split mode. @default 40% */
2217
2924
  paneWidth?: string;
@@ -2242,16 +2949,39 @@ type AgentWidgetArtifactsLayoutConfig = {
2242
2949
  /** Optional max artifact width cap while resizing (`px` only). Layout still bounds by chat min width. */
2243
2950
  resizableMaxWidth?: string;
2244
2951
  /**
2245
- * Visual treatment for the artifact column in split mode.
2246
- * - `'panel'`: bordered sidebar with left border, gap, and shadow (default).
2247
- * - `'seamless'`: flush with chat: no border or shadow, container background, zero gap.
2952
+ * Visual treatment for the artifact column in a desktop split.
2953
+ * - `'panel'`: one welded card (border + radius wrap chat + pane) with a hairline
2954
+ * divider on the pane's chat-facing edge, zero gap (default).
2955
+ * - `'seamless'`: the same welded card with no internal divider or chrome, zero gap.
2956
+ * - `'detached'`: two separate elevated cards: gap from `--persona-panel-inset`,
2957
+ * all-side border and radius on each, and canvas background behind the split.
2958
+ * In an inline embed this also insets the split from the container edges on all
2959
+ * sides (the page canvas shows through), so the all-side margin no longer requires
2960
+ * `launcher.detachedPanel`.
2961
+ *
2962
+ * Default is `'panel'` unless `launcher.detachedPanel` is true, in which case an unset
2963
+ * `paneAppearance` resolves to `'detached'`. An explicit value always wins.
2248
2964
  * @default 'panel'
2249
2965
  */
2250
- paneAppearance?: "panel" | "seamless";
2966
+ paneAppearance?: "panel" | "seamless" | "detached";
2251
2967
  /** Border radius on the artifact pane (CSS length). Works with any `paneAppearance`. */
2252
2968
  paneBorderRadius?: string;
2253
2969
  /** CSS `box-shadow` on the artifact pane. Set `"none"` to suppress the default shadow. */
2254
2970
  paneShadow?: string;
2971
+ /**
2972
+ * CSS `box-shadow` for the chat column card in a detached split. Defaults to the same
2973
+ * elevation as the artifact pane; set to `"none"` to keep the chat flat while the pane stays raised.
2974
+ */
2975
+ chatShadow?: string;
2976
+ /**
2977
+ * Chat column surface in a detached split. `"card"` (default) renders the chat as an inset card
2978
+ * matching the artifact pane; `"flush"` renders the chat flush with the container (no border, radius,
2979
+ * or shadow) and insets only the artifact pane, so the chat is flat background and the pane floats.
2980
+ * Only affects an inline-embedded detached split (the container-filling case); in floating, docked,
2981
+ * or sidebar modes it falls back to the card look.
2982
+ * @default 'card'
2983
+ */
2984
+ chatSurface?: "card" | "flush";
2255
2985
  /**
2256
2986
  * Full `border` shorthand for the artifact `<aside>` (all sides). Overrides default pane borders.
2257
2987
  * Example: `"1px solid #cccccc"`.
@@ -2263,14 +2993,12 @@ type AgentWidgetArtifactsLayoutConfig = {
2263
2993
  */
2264
2994
  paneBorderLeft?: string;
2265
2995
  /**
2266
- * Desktop split only (not narrow-host drawer / not ≤640px): square the **main chat card’s**
2267
- * top-right and bottom-right radii, and round the **artifact pane’s** top-right and bottom-right
2268
- * to match `persona-rounded-2xl` (`--persona-radius-lg`) so the two columns read as one shell.
2996
+ * @deprecated No-op. Panel and seamless splits now weld into one card by default.
2269
2997
  */
2270
2998
  unifiedSplitChrome?: boolean;
2271
2999
  /**
2272
- * When `unifiedSplitChrome` is true, outer-right corner radius on the artifact column (CSS length).
2273
- * @default matches theme large radius (`--persona-radius-lg`)
3000
+ * Desktop welded split only: override the artifact pane's outer-right corner radius (CSS length).
3001
+ * @default matches the panel radius (`--persona-panel-radius`)
2274
3002
  */
2275
3003
  unifiedSplitOuterRadius?: string;
2276
3004
  /**
@@ -2290,6 +3018,10 @@ type AgentWidgetArtifactsLayoutConfig = {
2290
3018
  * @default 'default'
2291
3019
  */
2292
3020
  toolbarPreset?: "default" | "document";
3021
+ /** Visible title in the artifact toolbar. @default "Artifacts" */
3022
+ toolbarTitle?: string;
3023
+ /** Label for the artifact dismiss control. @default "Close" */
3024
+ closeButtonLabel?: string;
2293
3025
  /**
2294
3026
  * When `toolbarPreset` is `document`, show a visible "Copy" label next to the copy icon.
2295
3027
  */
@@ -2304,6 +3036,17 @@ type AgentWidgetArtifactsLayoutConfig = {
2304
3036
  documentToolbarToggleActiveBackground?: string;
2305
3037
  /** Active view/source toggle border color. Sets `--persona-artifact-doc-toggle-active-border`. */
2306
3038
  documentToolbarToggleActiveBorderColor?: string;
3039
+ /** 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. */
3040
+ showExpandToggle?: boolean;
3041
+ /** Show the copy control in the `default` toolbar preset (the `document` preset always shows it). Default: false. */
3042
+ showCopyButton?: boolean;
3043
+ /** Edge fade on the scrollable tab strip. true = both ends (dynamic). @default true */
3044
+ tabFade?: boolean | {
3045
+ start?: boolean;
3046
+ end?: boolean;
3047
+ };
3048
+ /** Tab fade width (CSS length). @default 24px */
3049
+ tabFadeSize?: string;
2307
3050
  /**
2308
3051
  * Invoked when the document toolbar Refresh control is used (before the pane re-renders).
2309
3052
  * Use to replay `connectStream`, refetch, etc.
@@ -2327,20 +3070,349 @@ type AgentWidgetArtifactsLayoutConfig = {
2327
3070
  jsonPayload: string;
2328
3071
  }) => void | Promise<void>;
2329
3072
  };
3073
+ type PersonaArtifactDisplayMode = "card" | "panel" | "inline";
3074
+ /** 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. */
3075
+ type PersonaArtifactActionContext = {
3076
+ artifactId: string | null;
3077
+ title: string;
3078
+ artifactType: string;
3079
+ markdown?: string;
3080
+ file?: PersonaArtifactFileMeta;
3081
+ /** Component artifacts: pretty-printed { component, props } JSON. */
3082
+ jsonPayload?: string;
3083
+ };
3084
+ /**
3085
+ * Context passed to a `features.artifacts.statusLabel` function on every
3086
+ * artifact streaming update, once per visible surface. Treat it as read-only:
3087
+ * the function should be pure and fast (it runs per streaming delta, per
3088
+ * surface).
3089
+ */
3090
+ type PersonaArtifactStatusLabelContext = {
3091
+ artifactId: string;
3092
+ artifactType: "markdown" | "component";
3093
+ title?: string;
3094
+ /** The default subject, e.g. "document", "component", or a file type label like "HTML file". */
3095
+ typeLabel: string;
3096
+ file?: PersonaArtifactFileMeta;
3097
+ /** Accumulated streamed content length so far (0 for component artifacts). */
3098
+ chars: number;
3099
+ /** Accumulated line count so far (0 for component artifacts). */
3100
+ lines: number;
3101
+ /** Milliseconds since this artifact's first streaming update was seen. */
3102
+ elapsedMs: number;
3103
+ /** Lazy accessor for the accumulated markdown source (empty string for component artifacts). Call only if needed; parsing cost is opt-in. */
3104
+ content: () => string;
3105
+ /** Which surface is asking, so hosts can shorten for cramped spots. */
3106
+ surface: "card" | "inline-chrome" | "status-body";
3107
+ };
3108
+ /** A custom action button rendered in an artifact toolbar/card slot. */
3109
+ type PersonaArtifactCustomAction = {
3110
+ /** Stable id, used for DOM wiring and keyed re-renders. */
3111
+ id: string;
3112
+ /** Accessible label; also the visible text when showLabel is true. */
3113
+ label: string;
3114
+ /** 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. */
3115
+ icon?: IconName | (() => HTMLElement | SVGElement);
3116
+ /** Render icon + text instead of icon-only. Default: false. */
3117
+ showLabel?: boolean;
3118
+ /** Per-artifact gate, evaluated on each render. Omitted = always visible. */
3119
+ visible?: (ctx: PersonaArtifactActionContext) => boolean;
3120
+ /** May be async; rejections are swallowed like built-in action errors. */
3121
+ onClick: (ctx: PersonaArtifactActionContext) => void | Promise<void>;
3122
+ };
2330
3123
  type AgentWidgetArtifactsFeature = {
2331
3124
  /** When true, Persona shows the artifact pane and handles artifact_* SSE events */
2332
3125
  enabled?: boolean;
2333
3126
  /** If set, artifact events for other types are ignored */
2334
3127
  allowedTypes?: PersonaArtifactKind[];
3128
+ /**
3129
+ * Where artifact bodies render. A single mode applies to all artifacts;
3130
+ * the object form sets a default plus per-type overrides.
3131
+ * Defaults to "panel" (current behavior).
3132
+ */
3133
+ display?: PersonaArtifactDisplayMode | {
3134
+ default?: PersonaArtifactDisplayMode;
3135
+ byType?: Partial<Record<PersonaArtifactKind, PersonaArtifactDisplayMode>>;
3136
+ };
2335
3137
  /** Split / drawer dimensions and launcher widen behavior */
2336
3138
  layout?: AgentWidgetArtifactsLayoutConfig;
2337
3139
  /**
2338
- * Called when an artifact card action is triggered (open, download).
2339
- * Return `true` to prevent the default behavior.
3140
+ * Controls inline preview of previewable file artifacts (HTML/SVG written by
3141
+ * a Claude Managed agent). When a markdown artifact carries `file` metadata,
3142
+ * the pane can render an isolated `<iframe srcdoc>` sandbox instead of a code
3143
+ * block.
3144
+ */
3145
+ filePreview?: {
3146
+ /** Enable rendered preview for html/svg files. Defaults to enabled. Set false to force source view. */
3147
+ enabled?: boolean;
3148
+ /**
3149
+ * `sandbox` attribute for the preview iframe. Defaults to `"allow-scripts"`.
3150
+ * `allow-same-origin` is stripped (with a console warning) unless
3151
+ * `dangerouslyAllowSameOrigin` is set: the opaque origin is what isolates
3152
+ * the preview from the host page. Embedder-trusted config.
3153
+ */
3154
+ iframeSandbox?: string;
3155
+ /**
3156
+ * Allows `allow-same-origin` to pass through `iframeSandbox`. Off by
3157
+ * default because it lets agent-written file content run with the host
3158
+ * page's origin (DOM, storage, credentialed requests). Only set this when
3159
+ * every previewed file source is fully trusted.
3160
+ */
3161
+ dangerouslyAllowSameOrigin?: boolean;
3162
+ /**
3163
+ * Loading treatment for the preview iframe. Default on.
3164
+ *
3165
+ * A sandboxed `iframe srcdoc` (opaque origin, `allow-scripts` only) paints
3166
+ * blank until its content renders — seconds for artifacts that pull CDN
3167
+ * scripts (React/Babel). The default shows a themed "Loading preview…"
3168
+ * overlay over the iframe, dismissed the instant the content signals it has
3169
+ * painted (an injected `postMessage` reporter) or a hard timeout elapses.
3170
+ *
3171
+ * `false` disables the overlay and the injected ready signal entirely (the
3172
+ * srcdoc becomes the raw file source, the prior behavior). An object tunes
3173
+ * the timing; omitted / `true` uses all defaults.
3174
+ */
3175
+ loading?: boolean | {
3176
+ /** Show the overlay only if the preview is not ready after this many ms. Default 200. */
3177
+ delayMs?: number;
3178
+ /** Once shown, keep the overlay visible at least this long (anti-flicker). Default 300. */
3179
+ minVisibleMs?: number;
3180
+ /** Give up waiting and reveal the iframe regardless after this many ms. Default 8000. */
3181
+ timeoutMs?: number;
3182
+ /**
3183
+ * Append the `postMessage` ready reporter to the srcdoc so the overlay
3184
+ * dismisses on first paint rather than the iframe `load` event (which
3185
+ * fires before post-DOMContentLoaded rendering like Babel compilation).
3186
+ * Default true. When false, the overlay dismisses on `load` + a double
3187
+ * `requestAnimationFrame`, or the timeout.
3188
+ */
3189
+ injectReadySignal?: boolean;
3190
+ /**
3191
+ * Escalation text shown beside the spinner after `labelDelayMs`.
3192
+ * Default `"Starting preview..."`. `false` renders an icon-only
3193
+ * indicator forever (no text ever). A short work-naming label is
3194
+ * added only after a delay by design — icon-first, with text reserved
3195
+ * for genuinely slow loads (per Geist/Sandpack guidance; HIG warns
3196
+ * against the vague word "loading").
3197
+ */
3198
+ label?: string | false;
3199
+ /**
3200
+ * Delay before the escalation label fades in, measured from when the
3201
+ * overlay actually becomes visible (i.e. after `delayMs`), not from
3202
+ * iframe creation. Default 2000.
3203
+ */
3204
+ labelDelayMs?: number;
3205
+ /**
3206
+ * Full replacement for the default indicator (spinner + escalation
3207
+ * label). Called once when the overlay is built; return any element
3208
+ * (a brand mark, skeleton, custom animation) to own the indicator
3209
+ * content entirely (the escalation-label logic is then skipped), or
3210
+ * return `null` to fall back to the default. A thrown error also falls
3211
+ * back. Mirrors `renderInline` / `renderCard`'s null-falls-back
3212
+ * contract. The overlay backdrop, timing, and dismissal stay
3213
+ * widget-owned either way.
3214
+ */
3215
+ renderIndicator?: (ctx: {
3216
+ artifactId: string;
3217
+ config: AgentWidgetConfig;
3218
+ }) => HTMLElement | null;
3219
+ };
3220
+ };
3221
+ /**
3222
+ * Custom action buttons for the artifact pane toolbar, rendered between the
3223
+ * refresh and expand/close controls in both toolbar presets. Re-read on live
3224
+ * config updates.
3225
+ */
3226
+ toolbarActions?: PersonaArtifactCustomAction[];
3227
+ /**
3228
+ * Custom action buttons for the artifact reference card, rendered before the
3229
+ * Download button on complete artifacts. Clicks are delegated, so they
3230
+ * survive re-renders and page refresh.
3231
+ */
3232
+ cardActions?: PersonaArtifactCustomAction[];
3233
+ /**
3234
+ * File chrome (title bar + toolbar) around inline preview blocks
3235
+ * (`display: "inline"`). Default when undefined: chrome on, with the built-in
3236
+ * Copy and Expand controls. Pass `false` to render the bare preview body
3237
+ * (frame → padded body, no chrome bar), or an object to toggle the built-in
3238
+ * controls individually.
3239
+ *
3240
+ * Note: default-on chrome adds a title bar and buttons to every existing
3241
+ * inline host on upgrade; set `inlineChrome: false` to opt out.
3242
+ */
3243
+ inlineChrome?: boolean | {
3244
+ /** Show the built-in Copy button (complete artifacts only). Default true. */
3245
+ showCopy?: boolean;
3246
+ /** Show the built-in Expand button (opens the pane for this artifact). Default true. */
3247
+ showExpand?: boolean;
3248
+ /**
3249
+ * Show the built-in rendered/source view toggle (complete artifacts
3250
+ * only). Default true. The toggle is availability-gated: it appears only
3251
+ * for file-backed markdown artifacts that have a rendered alternative to
3252
+ * their source (previewable HTML/SVG, or markdown-kind files), and never
3253
+ * when `inlineBody.viewMode: "source"` forces a source-only body. Plain
3254
+ * markdown and component artifacts don't get it (the pane toggle covers
3255
+ * those).
3256
+ */
3257
+ showViewToggle?: boolean;
3258
+ };
3259
+ /**
3260
+ * Custom action buttons for the inline chrome toolbar, rendered before the
3261
+ * built-in Copy/Expand controls on complete artifacts. Same shape as
3262
+ * `cardActions`; each action's `visible` gate is respected and clicks are
3263
+ * delegated, so they survive re-renders and page refresh.
3264
+ */
3265
+ inlineActions?: PersonaArtifactCustomAction[];
3266
+ /**
3267
+ * Replace the artifact tab strip entirely (Seam A). Return an element mounted in
3268
+ * place of the built-in `.persona-artifact-list`; the pane still owns the toolbar,
3269
+ * preview body, iframe reuse, and lazy-render gate. Re-invoked when the records or
3270
+ * selection change. Custom bars own their own accessibility; use `createRovingTablist`
3271
+ * to keep keyboard/tablist behavior. When set, the built-in strip (scroll, fade,
3272
+ * tablist) is not rendered.
3273
+ *
3274
+ * Return either a fresh element per call, or the SAME element updated in place.
3275
+ * Returning a stable element preserves internal state across selection changes:
3276
+ * the pane skips remounting an unchanged node, so a roving tablist keeps keyboard
3277
+ * focus on the selected tab (a fresh element per call drops focus and breaks
3278
+ * Arrow-key nav). See the reference bars in `apps/web/src/artifact-demo.ts`.
3279
+ */
3280
+ renderTabBar?: (ctx: {
3281
+ records: PersonaArtifactRecord[];
3282
+ selectedId: string | null;
3283
+ onSelect: (id: string) => void;
3284
+ }) => HTMLElement;
3285
+ /**
3286
+ * Body layout for inline artifact blocks (`display: "inline"`). Controls how
3287
+ * the block reserves height and behaves while a file/document artifact
3288
+ * streams, so the streaming source no longer grows an unbounded `<pre>` and
3289
+ * then snaps to the completed preview. Affects only the inline block; the
3290
+ * artifact pane is unchanged.
3291
+ *
3292
+ * Defaults (a behavior change from prior versions, which grew with content
3293
+ * during streaming): a fixed 320px streaming source window with tail-follow,
3294
+ * a top edge fade, and an animated streaming→complete swap. Pass
3295
+ * `height: "auto"` to restore the old grow-with-content streaming behavior.
3296
+ */
3297
+ inlineBody?: {
3298
+ /** What the body shows while streaming. Default `"source"`. */
3299
+ streamingView?: "source" | "status";
3300
+ /**
3301
+ * How the completed body renders. `"rendered"` (default) keeps the current
3302
+ * behavior: file previews in a sandboxed iframe, markdown through the
3303
+ * markdown pipeline. `"source"` always shows the raw syntax-highlighted
3304
+ * source instead — for hosts where the artifact is input to the host system
3305
+ * (a code editor, a query runner) rather than something to preview. Unlike
3306
+ * `filePreview.enabled: false`, this also covers markdown-kind files and
3307
+ * plain markdown artifacts. Component artifacts always render through the
3308
+ * registry.
3309
+ */
3310
+ viewMode?: "rendered" | "source";
3311
+ /**
3312
+ * Body height per state. A number reserves that many px for the whole body
3313
+ * region (border-box, padding included) with internal scroll — the
3314
+ * zero-layout-shift path; `"auto"` means content-sized. A
3315
+ * scalar applies to both the streaming and complete states; the object form
3316
+ * sets them independently. Default `320` for both states.
3317
+ *
3318
+ * Note: with `"auto"` on the complete state, non-iframe bodies (rendered
3319
+ * markdown, source view, component) are content-sized, but a file-preview
3320
+ * iframe cannot be content-sized without postMessage plumbing, so it falls
3321
+ * back to the CSS-var default (`--persona-artifact-inline-frame-height`,
3322
+ * 320px).
3323
+ *
3324
+ * Numeric heights are applied via the CSS var
3325
+ * `--persona-artifact-inline-body-height` on the block root. The older
3326
+ * `--persona-artifact-inline-frame-height` var still overrides the iframe
3327
+ * height when this one is unset, so themes pinned to it keep working.
3328
+ */
3329
+ height?: number | "auto" | {
3330
+ streaming?: number | "auto";
3331
+ complete?: number | "auto";
3332
+ };
3333
+ /**
3334
+ * Tail-follow the newest streamed lines in a fixed-height source window: if
3335
+ * the viewport is already at the bottom, keep it pinned as content arrives;
3336
+ * if the reader scrolled up, don't fight them. Only meaningful for a numeric
3337
+ * streaming height. Default `true`.
3338
+ *
3339
+ * Precedence: ignored when `overflow: "clip"` (a clipped window shows the
3340
+ * top of the document and never scrolls, so there is no tail to follow).
3341
+ */
3342
+ followOutput?: boolean;
3343
+ /**
3344
+ * How a fixed-height source window handles content taller than the window.
3345
+ *
3346
+ * - `"scroll"` (default) — the current behavior: an internally scrollable
3347
+ * window that tail-follows the newest streamed lines (see `followOutput`),
3348
+ * so the reader sees the growing tail of the document.
3349
+ * - `"clip"` — a fixed-height window that shows the TOP of the document,
3350
+ * `overflow: hidden` with no internal scroll and no tail-follow
3351
+ * (`followOutput` is ignored in this mode). When content overflows the
3352
+ * window a bottom edge fade signals there is more below (the top is always
3353
+ * visible, so a top fade never applies); an explicit `fadeMask` still wins
3354
+ * over this clip-mode default. When the inline chrome's Expand control is
3355
+ * enabled the whole body doubles as an expand hitbox (click / Enter / Space
3356
+ * opens the artifact in the pane), matching the industry inline-card
3357
+ * pattern; otherwise the clip is purely visual.
3358
+ *
3359
+ * Only meaningful for a numeric streaming/complete height. Default
3360
+ * `"scroll"`.
3361
+ */
3362
+ overflow?: "scroll" | "clip";
3363
+ /**
3364
+ * Edge fade masks on the fixed-height streaming window (a top fade signals
3365
+ * clipped content above, a bottom fade signals clipped content below). Each
3366
+ * fade renders only when content is actually clipped on that edge, so with
3367
+ * tail-follow pinned at the bottom the bottom fade stays inert until the
3368
+ * reader scrolls up mid-stream. `true` = `{ top: true, bottom: true }`,
3369
+ * `false` = none. Default `{ top: true, bottom: true }`.
3370
+ */
3371
+ fadeMask?: boolean | {
3372
+ top?: boolean;
3373
+ bottom?: boolean;
3374
+ };
3375
+ /**
3376
+ * Animate the streaming→complete body swap. `"auto"` uses the View
3377
+ * Transitions API when supported and `prefers-reduced-motion` is off;
3378
+ * `"none"` swaps instantly. Default `"auto"`.
3379
+ */
3380
+ transition?: "auto" | "none";
3381
+ /**
3382
+ * What the block becomes once the artifact completes.
3383
+ *
3384
+ * - `"inline"` (default) — the streamed body stays inline forever, as
3385
+ * configured by the other `inlineBody` options.
3386
+ * - `"card"` — the block streams inline as configured, then collapses to the
3387
+ * compact artifact reference card once the artifact completes (the Copilot
3388
+ * "chiclet" / Claude side-panel handoff pattern), keeping the thread
3389
+ * scannable. The collapse plays as a short CSS height transition (skipped
3390
+ * under `prefers-reduced-motion`); it does not use the View Transitions
3391
+ * API, so `transition` does not affect it. After the collapse the card's
3392
+ * normal actions apply (click opens the artifact pane). `viewMode`, the
3393
+ * inline rendered/source view toggle, `inlineActions`, and inline copy are
3394
+ * streaming-phase-only in this mode and inert once the block is a card
3395
+ * (there is nothing to toggle or copy on a collapsed card). Blocks that are
3396
+ * already complete when they first render (page-refresh hydration) render
3397
+ * the card directly, with no flash of the inline body and no animation.
3398
+ *
3399
+ * Default `"inline"`.
3400
+ */
3401
+ completeDisplay?: "inline" | "card";
3402
+ };
3403
+ /**
3404
+ * Called when an artifact action is triggered (open, download, expand).
3405
+ * Return `true` to intercept: the widget then does not change state.
3406
+ * For `expand`, `expanded` is the state the toggle is about to enter and
3407
+ * `artifactId` is the currently selected artifact (or `null` when none).
2340
3408
  */
2341
3409
  onArtifactAction?: (action: {
2342
3410
  type: 'open' | 'download';
2343
3411
  artifactId: string;
3412
+ } | {
3413
+ type: 'expand';
3414
+ artifactId: string | null;
3415
+ expanded: boolean;
2344
3416
  }) => boolean | void;
2345
3417
  /**
2346
3418
  * Custom renderer for artifact reference cards shown in the message thread.
@@ -2356,6 +3428,72 @@ type AgentWidgetArtifactsFeature = {
2356
3428
  config: AgentWidgetConfig;
2357
3429
  defaultRenderer: () => HTMLElement;
2358
3430
  }) => HTMLElement | null;
3431
+ /**
3432
+ * Custom renderer for inline artifact blocks (display: "inline"), mirroring
3433
+ * `renderCard`. Return an element to replace the default inline preview,
3434
+ * or null to use the default.
3435
+ */
3436
+ renderInline?: (context: {
3437
+ artifact: {
3438
+ artifactId: string;
3439
+ title: string;
3440
+ artifactType: string;
3441
+ status: string;
3442
+ };
3443
+ config: AgentWidgetConfig;
3444
+ defaultRenderer: () => HTMLElement;
3445
+ }) => HTMLElement | null;
3446
+ /**
3447
+ * Text shown while an artifact streams, in place of the default
3448
+ * `Generating <type>...` status. Applies to every streaming surface: the
3449
+ * reference card status line, the inline chrome meta label, and the inline
3450
+ * streaming status body (`inlineBody.streamingView: "status"`).
3451
+ *
3452
+ * - A plain string replaces the default label everywhere (localization or
3453
+ * brand voice).
3454
+ * - A function is called on every artifact update for each visible surface;
3455
+ * it must be pure and fast. Returning a string sets the animated label
3456
+ * only. Returning `{ label, detail }` splits the status into an animated
3457
+ * label (re-applied only when its text changes, so the loading animation
3458
+ * stays stable) and a plain un-animated detail span that may update freely
3459
+ * per delta (live counters).
3460
+ *
3461
+ * Default when unset: the current behavior, `Generating <type>...` with no
3462
+ * detail. If the function throws, the default label is used for that update
3463
+ * (a bad host callback must never break rendering). There is deliberately no
3464
+ * percent progress: streams do not announce total length, so counts and
3465
+ * elapsed time are the only truthful signals.
3466
+ */
3467
+ statusLabel?: string | ((ctx: PersonaArtifactStatusLabelContext) => string | {
3468
+ label: string;
3469
+ detail?: string;
3470
+ });
3471
+ /**
3472
+ * Animation applied to the artifact card's "Generating …" status text while
3473
+ * the artifact streams. Character-by-character modes (`shimmer`,
3474
+ * `shimmer-color`, `rainbow`) wrap each character in a span with a staggered
3475
+ * `animation-delay`; `pulse` fades the whole status text; `none` disables the
3476
+ * animation. Honors `prefers-reduced-motion`.
3477
+ * @default "shimmer"
3478
+ */
3479
+ loadingAnimation?: AgentWidgetToolCallLoadingAnimation;
3480
+ /**
3481
+ * Duration of one full animation cycle in milliseconds.
3482
+ * Applies to pulse, shimmer, shimmer-color, and rainbow modes.
3483
+ * @default 2000
3484
+ */
3485
+ loadingAnimationDuration?: number;
3486
+ /**
3487
+ * Primary color for shimmer-color animation mode.
3488
+ * Defaults to the current text color.
3489
+ */
3490
+ loadingAnimationColor?: string;
3491
+ /**
3492
+ * Secondary/end color for shimmer-color animation mode.
3493
+ * Creates a gradient sweep between `loadingAnimationColor` and this color.
3494
+ * @default "#3b82f6"
3495
+ */
3496
+ loadingAnimationSecondaryColor?: string;
2359
3497
  };
2360
3498
  /**
2361
3499
  * How the transcript scrolls while an assistant response streams in.
@@ -2483,6 +3621,13 @@ type AgentWidgetToolCallDisplayFeature = {
2483
3621
  * @default false
2484
3622
  */
2485
3623
  grouped?: boolean;
3624
+ /**
3625
+ * Controls how a grouped tool sequence is rendered.
3626
+ * - `"stack"`: show the group summary and each child tool row.
3627
+ * - `"summary"`: show one consolidated summary row only.
3628
+ * @default "stack"
3629
+ */
3630
+ groupedMode?: "stack" | "summary";
2486
3631
  /**
2487
3632
  * When false, tool call bubbles show only the collapsed summary with no
2488
3633
  * expand/collapse toggle. Users see tool awareness without full details.
@@ -3172,6 +4317,24 @@ type AgentWidgetLauncherConfig = {
3172
4317
  * @default false
3173
4318
  */
3174
4319
  sidebarMode?: boolean;
4320
+ /**
4321
+ * When true, the widget panel renders as a detached card inset within its region,
4322
+ * with rounded corners on all sides and elevation (shadow plus hairline border),
4323
+ * instead of sitting flush against the region edges.
4324
+ *
4325
+ * The gap around the card is themed via `theme.components.panel.inset`. The
4326
+ * background revealed behind it is themed via `theme.components.panel.canvasBackground`
4327
+ * in docked and inline embed modes. In sidebar mode the gap stays click-through, so the
4328
+ * host page shows through it the same way it does in floating mode, and canvasBackground
4329
+ * is a no-op there.
4330
+ *
4331
+ * Applies to sidebar, docked, and inline embed modes. Ignored in mobile fullscreen,
4332
+ * where chrome is already suppressed. Floating mode is unchanged, since it already
4333
+ * renders as a detached card.
4334
+ *
4335
+ * @default false
4336
+ */
4337
+ detachedPanel?: boolean;
3175
4338
  /**
3176
4339
  * Width of the sidebar panel when sidebarMode is true.
3177
4340
  * @default "420px"
@@ -5206,6 +6369,18 @@ type AgentWidgetConfig = {
5206
6369
  }) => string;
5207
6370
  plugins?: AgentWidgetPlugin[];
5208
6371
  contextProviders?: AgentWidgetContextProvider[];
6372
+ /**
6373
+ * Context mentions: let users explicitly pull external context into a turn by
6374
+ * typing `@` or clicking a visible composer button, both opening one shared
6375
+ * searchable menu of host-provided sources. Selecting a mention adds a
6376
+ * removable pill chip; resolved content reaches the model via `llmAppend`
6377
+ * (default) or the opt-in structured `context` channel.
6378
+ *
6379
+ * Disabled by default. When enabled, the mention runtime is lazy-loaded from a
6380
+ * sibling chunk on first use, so sites that leave it off pay no bundle cost.
6381
+ * See `docs/context-mentions-plan.md`.
6382
+ */
6383
+ contextMentions?: AgentWidgetContextMentionConfig;
5209
6384
  requestMiddleware?: AgentWidgetRequestMiddleware;
5210
6385
  actionParsers?: AgentWidgetActionParser[];
5211
6386
  actionHandlers?: AgentWidgetActionHandler[];
@@ -5748,6 +6923,25 @@ type AgentWidgetMessage = {
5748
6923
  * The `content` field contains the text-only representation for display.
5749
6924
  */
5750
6925
  contentParts?: ContentPart[];
6926
+ /**
6927
+ * Context mentions attached to this (user) message, for transcript fidelity +
6928
+ * chip rendering in the sent bubble. Refs only — the resolved payloads are
6929
+ * merged into `llmContent`/`contentParts` (model-visible) at send time.
6930
+ */
6931
+ contextMentions?: AgentWidgetContextMentionRef[];
6932
+ /**
6933
+ * Ordered prose + mention blocks for inline-mode rendering and composer history
6934
+ * recall (`contextMentions.display: "inline"`). Present only on inline-mode user
6935
+ * messages; when omitted the sent bubble falls back to the chip row derived from
6936
+ * `contextMentions`. Display/transcript concern only — not the model channel.
6937
+ */
6938
+ contentSegments?: AgentWidgetContentSegment[];
6939
+ /**
6940
+ * Resolved opt-in structured mention context for this (user) message, merged
6941
+ * into the request `context` under `mentions.<sourceId>.<itemId>` by the
6942
+ * client. Internal: set at send time from each source's `resolve().context`.
6943
+ */
6944
+ mentionContext?: Record<string, unknown>;
5751
6945
  streaming?: boolean;
5752
6946
  variant?: AgentWidgetMessageVariant;
5753
6947
  sequence?: number;
@@ -5818,6 +7012,21 @@ type AgentWidgetMessage = {
5818
7012
  */
5819
7013
  stopReason?: StopReasonKind;
5820
7014
  };
7015
+ /**
7016
+ * Optional file metadata attached to a markdown artifact that represents a
7017
+ * concrete file written by a Claude Managed agent (e.g. `/mnt/session/outputs/cat.html`).
7018
+ * Additive: the artifact content stays a fenced code block on the wire for
7019
+ * backward compatibility; new widgets use this to recover the raw source and
7020
+ * offer a preview. Mirrors the `file` field on the core `artifact_start` event.
7021
+ */
7022
+ type PersonaArtifactFileMeta = {
7023
+ /** Full path of the written file (also used as the artifact title). */
7024
+ path: string;
7025
+ /** MIME type of the file (used for download and preview decisions). */
7026
+ mimeType: string;
7027
+ /** Fence language the content was encoded with (html/xml/md/text). */
7028
+ language?: string;
7029
+ };
5821
7030
  type PersonaArtifactRecord = {
5822
7031
  id: string;
5823
7032
  artifactType: PersonaArtifactKind;
@@ -5826,6 +7035,8 @@ type PersonaArtifactRecord = {
5826
7035
  markdown?: string;
5827
7036
  component?: string;
5828
7037
  props?: Record<string, unknown>;
7038
+ /** Present when this markdown artifact is a previewable file (see PersonaArtifactFileMeta). */
7039
+ file?: PersonaArtifactFileMeta;
5829
7040
  };
5830
7041
 
5831
7042
  /**
@@ -5910,5 +7121,38 @@ interface SmartDomReaderProviderOptions extends SmartDomContextOptions {
5910
7121
  * `payload.context` on every agent request.
5911
7122
  */
5912
7123
  declare function createSmartDomReaderContextProvider(opts?: SmartDomReaderProviderOptions): AgentWidgetContextProvider;
7124
+ /** Options for {@link createSmartDomMentionSource}. */
7125
+ interface SmartDomMentionSourceOptions extends SmartDomContextOptions {
7126
+ /** Source id. Default: "page". */
7127
+ id?: string;
7128
+ /** Group header shown in the menu. Default: "Page". */
7129
+ label?: string;
7130
+ /**
7131
+ * Reshape each surfaced element into a mention item. Receives the raw
7132
+ * {@link EnrichedPageElement} and the default-mapped item, so you can tweak
7133
+ * one field (`{ ...defaultItem, iconName: "star" }`) or build from scratch.
7134
+ * The returned item's `id` MUST stay a selector `resolve()` can read at submit
7135
+ * (default: `el.selector`) unless you also override resolution. @default built-in mapping
7136
+ */
7137
+ mapItem?: (el: EnrichedPageElement, defaultItem: AgentWidgetContextMentionItem) => AgentWidgetContextMentionItem;
7138
+ }
7139
+ /**
7140
+ * First-class **supported** mention source backed by smart-dom-reader: surfaces
7141
+ * visible page elements (Shadow-DOM-piercing) as mentionable items, resolving a
7142
+ * fresh snapshot of the chosen element's text at SUBMIT (`resolveOn: "submit"`),
7143
+ * since the page is time-sensitive. The element list is snapshotted when the
7144
+ * menu opens (empty query) and filtered client-side with `defaultMentionFilter`
7145
+ * as the user types.
7146
+ *
7147
+ * @example
7148
+ * ```ts
7149
+ * import { createSmartDomMentionSource } from "@runtypelabs/persona/smart-dom-reader";
7150
+ *
7151
+ * initAgentWidget({
7152
+ * contextMentions: { enabled: true, sources: [createSmartDomMentionSource()] },
7153
+ * });
7154
+ * ```
7155
+ */
7156
+ declare function createSmartDomMentionSource(opts?: SmartDomMentionSourceOptions): AgentWidgetContextMentionSource;
5913
7157
 
5914
- export { type SmartDomAdapterOptions, type SmartDomContextOptions, type SmartDomReaderProviderOptions, collectSmartDomContext, createSmartDomReaderContextProvider, smartDomResultToEnriched };
7158
+ export { type EnrichedPageElement, type SmartDomAdapterOptions, type SmartDomContextOptions, type SmartDomMentionSourceOptions, type SmartDomReaderProviderOptions, collectSmartDomContext, createSmartDomMentionSource, createSmartDomReaderContextProvider, smartDomResultToEnriched };