@runtypelabs/persona 4.13.0 → 4.15.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 (106) hide show
  1. package/README.md +4 -4
  2. package/dist/animations/glyph-cycle.d.cts +1 -1
  3. package/dist/animations/glyph-cycle.d.ts +1 -1
  4. package/dist/animations/{types-DveIaNx6.d.cts → types-BpWGm7_6.d.cts} +17 -0
  5. package/dist/animations/{types-DveIaNx6.d.ts → types-BpWGm7_6.d.ts} +17 -0
  6. package/dist/animations/wipe.d.cts +1 -1
  7. package/dist/animations/wipe.d.ts +1 -1
  8. package/dist/chunk-QJ4LV2KW.js +1 -0
  9. package/dist/codegen.cjs +12 -11
  10. package/dist/codegen.js +14 -13
  11. package/dist/{context-mentions-ONG7A7M6.js → context-mentions-BTSTIBFC.js} +1 -1
  12. package/dist/context-mentions.cjs +11 -8
  13. package/dist/context-mentions.d.cts +339 -22
  14. package/dist/context-mentions.d.ts +339 -22
  15. package/dist/context-mentions.js +11 -8
  16. package/dist/index.cjs +68 -67
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +483 -48
  19. package/dist/index.d.ts +483 -48
  20. package/dist/index.global.js +61 -58
  21. package/dist/index.global.js.map +1 -1
  22. package/dist/index.js +70 -69
  23. package/dist/index.js.map +1 -1
  24. package/dist/launcher.global.js +5 -2
  25. package/dist/launcher.global.js.map +1 -1
  26. package/dist/smart-dom-reader.d.cts +339 -22
  27. package/dist/smart-dom-reader.d.ts +339 -22
  28. package/dist/theme-editor-preview.cjs +67 -67
  29. package/dist/theme-editor-preview.d.cts +355 -23
  30. package/dist/theme-editor-preview.d.ts +355 -23
  31. package/dist/theme-editor-preview.js +75 -75
  32. package/dist/theme-editor.cjs +10 -10
  33. package/dist/theme-editor.d.cts +376 -24
  34. package/dist/theme-editor.d.ts +376 -24
  35. package/dist/theme-editor.js +10 -10
  36. package/dist/theme-reference.cjs +1 -1
  37. package/dist/theme-reference.d.cts +38 -0
  38. package/dist/theme-reference.d.ts +38 -0
  39. package/dist/theme-reference.js +1 -1
  40. package/dist/widget.css +1 -1
  41. package/package.json +1 -1
  42. package/src/artifacts-session.test.ts +106 -0
  43. package/src/ask-user-question-tool.ts +10 -7
  44. package/src/client.test.ts +2 -2
  45. package/src/client.ts +4 -1
  46. package/src/components/artifact-card.ts +13 -2
  47. package/src/components/artifact-inline.ts +11 -2
  48. package/src/components/artifact-preview.ts +1 -1
  49. package/src/components/composer-builder.test.ts +2 -0
  50. package/src/components/composer-builder.ts +1 -1
  51. package/src/components/composer-parts.test.ts +105 -4
  52. package/src/components/composer-parts.ts +54 -16
  53. package/src/components/message-bubble.test.ts +7 -1
  54. package/src/components/message-bubble.ts +11 -8
  55. package/src/components/messages.ts +5 -2
  56. package/src/components/panel.ts +31 -5
  57. package/src/components/pill-composer-builder.test.ts +18 -0
  58. package/src/components/suggestions.test.ts +233 -0
  59. package/src/components/suggestions.ts +463 -81
  60. package/src/components/widget-view.ts +4 -0
  61. package/src/defaults.ts +5 -3
  62. package/src/generated/runtype-openapi-contract.ts +17 -0
  63. package/src/index-core.ts +52 -2
  64. package/src/launcher-global.ts +1 -1
  65. package/src/plugins/types.ts +71 -3
  66. package/src/presets.ts +3 -3
  67. package/src/session.ts +55 -12
  68. package/src/styles/widget-styles.test.ts +162 -0
  69. package/src/styles/widget.css +440 -1
  70. package/src/suggest-replies-tool.test.ts +233 -2
  71. package/src/suggest-replies-tool.ts +115 -39
  72. package/src/theme-editor/index.ts +5 -0
  73. package/src/theme-editor/presets.test.ts +43 -0
  74. package/src/theme-editor/presets.ts +101 -87
  75. package/src/theme-editor/preview-utils.test.ts +34 -0
  76. package/src/theme-editor/preview-utils.ts +77 -2
  77. package/src/theme-editor/sections.test.ts +72 -7
  78. package/src/theme-editor/sections.ts +113 -13
  79. package/src/theme-editor/state-preferences.test.ts +15 -0
  80. package/src/theme-editor/state.ts +46 -0
  81. package/src/theme-editor/types.ts +15 -1
  82. package/src/theme-editor/webmcp/tools.test.ts +13 -0
  83. package/src/theme-editor/webmcp/tools.ts +5 -0
  84. package/src/theme-reference.ts +9 -2
  85. package/src/types/theme.ts +32 -0
  86. package/src/types.ts +291 -25
  87. package/src/ui.artifact-pane-gating.test.ts +5 -5
  88. package/src/ui.config-preferences.test.ts +166 -0
  89. package/src/ui.detached-panel.test.ts +1 -1
  90. package/src/ui.suggest-replies.test.ts +1066 -1
  91. package/src/ui.ts +311 -45
  92. package/src/ui.typing-indicator.test.ts +135 -0
  93. package/src/utils/artifact-display.test.ts +180 -16
  94. package/src/utils/artifact-display.ts +155 -14
  95. package/src/utils/artifact-file.test.ts +1 -1
  96. package/src/utils/code-generators.test.ts +40 -0
  97. package/src/utils/code-generators.ts +22 -0
  98. package/src/utils/config-merge.test.ts +84 -0
  99. package/src/utils/config-merge.ts +6 -1
  100. package/src/utils/feature-preferences.test.ts +326 -0
  101. package/src/utils/feature-preferences.ts +498 -0
  102. package/src/utils/icons.test.ts +26 -0
  103. package/src/utils/icons.ts +8 -0
  104. package/src/utils/theme.test.ts +171 -0
  105. package/src/utils/tokens.ts +71 -7
  106. package/dist/chunk-MMUPR2JW.js +0 -1
@@ -27,7 +27,7 @@ beforeAll(() => {
27
27
  *
28
28
  * The pane's own `update()` unhides its shell whenever records exist, so the
29
29
  * gate in `syncArtifactPane` must re-assert `persona-hidden` for artifacts
30
- * whose resolved mode is "card" or "inline". The original implementation only
30
+ * whose resolved mode is "collapsed" or "inline". The original implementation only
31
31
  * removed the class in the show branch and never re-added it, so inline-mode
32
32
  * artifacts still auto-opened the pane.
33
33
  */
@@ -88,8 +88,8 @@ describe("artifact pane auto-open gating by display mode", () => {
88
88
  controller.destroy();
89
89
  });
90
90
 
91
- it('keeps the pane hidden for "card" mode until an explicit open', () => {
92
- const { mount, controller } = mountWithDisplay("card");
91
+ it('keeps the pane hidden for "collapsed" mode until an explicit open', () => {
92
+ const { mount, controller } = mountWithDisplay("collapsed");
93
93
  upsertSample(controller);
94
94
  expect(paneEl(mount).classList.contains("persona-hidden")).toBe(true);
95
95
 
@@ -109,7 +109,7 @@ describe("artifact pane auto-open gating by display mode", () => {
109
109
  urlWithBlob.createObjectURL = () => "blob:persona-test";
110
110
  urlWithBlob.revokeObjectURL = () => {};
111
111
  try {
112
- const { mount, controller } = mountWithDisplay("card");
112
+ const { mount, controller } = mountWithDisplay("collapsed");
113
113
  upsertSample(controller);
114
114
 
115
115
  // Recreate the reference card the way the default renderer shapes it
@@ -170,7 +170,7 @@ describe("artifact card custom actions (full widget)", () => {
170
170
  artifacts: {
171
171
  enabled: true,
172
172
  allowedTypes: ["markdown", "component"],
173
- display: "card",
173
+ display: "collapsed",
174
174
  cardActions,
175
175
  },
176
176
  },
@@ -0,0 +1,166 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { afterEach, beforeAll, describe, expect, it } from "vitest";
4
+
5
+ import { createAgentExperience } from "./ui";
6
+ import type {
7
+ AgentWidgetArtifactsFeature,
8
+ AgentWidgetConfig,
9
+ WidgetPreferenceSlice,
10
+ } from "./types";
11
+
12
+ beforeAll(() => {
13
+ // jsdom does not implement matchMedia; the pane's layout code touches it.
14
+ if (!window.matchMedia) {
15
+ window.matchMedia = ((query: string) => ({
16
+ matches: false,
17
+ media: query,
18
+ onchange: null,
19
+ addListener: () => {},
20
+ removeListener: () => {},
21
+ addEventListener: () => {},
22
+ removeEventListener: () => {},
23
+ dispatchEvent: () => false,
24
+ })) as unknown as typeof window.matchMedia;
25
+ }
26
+ });
27
+
28
+ /**
29
+ * Config-level `preferences` are per-instance display overrides baked over
30
+ * `features` (utils/feature-preferences.ts `resolveConfigPreferences`). The
31
+ * pane's auto-open state is the observable for the effective display mode:
32
+ * "panel" opens it on upsert, "inline"/"collapsed" keep it hidden.
33
+ *
34
+ * The update() path must re-resolve from the pre-preference base features:
35
+ * changing or clearing preferences may not stack onto previously overlaid
36
+ * values.
37
+ */
38
+ describe("config preferences overrides", () => {
39
+ afterEach(() => {
40
+ document.body.innerHTML = "";
41
+ try {
42
+ window.localStorage.clear();
43
+ } catch {
44
+ /* jsdom edge cases */
45
+ }
46
+ });
47
+
48
+ function mountWith(
49
+ display: AgentWidgetArtifactsFeature["display"],
50
+ preferences?: WidgetPreferenceSlice
51
+ ) {
52
+ const mount = document.createElement("div");
53
+ document.body.appendChild(mount);
54
+ const config: AgentWidgetConfig = {
55
+ apiUrl: "https://api.example.com/chat",
56
+ launcher: { enabled: false },
57
+ features: {
58
+ artifacts: {
59
+ enabled: true,
60
+ allowedTypes: ["markdown", "component"],
61
+ ...(display ? { display } : {}),
62
+ },
63
+ },
64
+ ...(preferences ? { preferences } : {}),
65
+ };
66
+ const controller = createAgentExperience(mount, config);
67
+ return { mount, controller };
68
+ }
69
+
70
+ function paneHidden(mount: HTMLElement): boolean {
71
+ const el = mount.querySelector<HTMLElement>(".persona-artifact-pane");
72
+ expect(el).not.toBeNull();
73
+ return el!.classList.contains("persona-hidden");
74
+ }
75
+
76
+ function upsertSample(
77
+ controller: ReturnType<typeof createAgentExperience>,
78
+ id = "prefs-test"
79
+ ) {
80
+ controller.upsertArtifact({
81
+ id,
82
+ title: "Preferences test",
83
+ artifactType: "markdown",
84
+ content: "# Hello",
85
+ });
86
+ }
87
+
88
+ it("applies initial preferences over base features", () => {
89
+ // Base says panel (auto-open); the instance preference says inline.
90
+ const { mount, controller } = mountWith("panel", {
91
+ artifacts: { display: "inline" },
92
+ });
93
+ upsertSample(controller);
94
+ expect(paneHidden(mount)).toBe(true);
95
+ controller.destroy();
96
+ });
97
+
98
+ it("applies preferences passed through controller.update()", () => {
99
+ const { mount, controller } = mountWith("panel");
100
+ controller.update({ preferences: { artifacts: { display: "collapsed" } } });
101
+ upsertSample(controller);
102
+ expect(paneHidden(mount)).toBe(true);
103
+ controller.destroy();
104
+ });
105
+
106
+ // A "panel" upsert marks the pane user-opened, which is sticky by design,
107
+ // so the remaining tests observe the effective mode through the transcript
108
+ // block type instead: refreshArtifactReferenceBlocks re-materializes blocks
109
+ // on a live display change ("inline" → .persona-artifact-inline preview,
110
+ // otherwise the reference card).
111
+ function inlineBlockCount(mount: HTMLElement): number {
112
+ return mount.querySelectorAll(".persona-artifact-inline").length;
113
+ }
114
+
115
+ it("clearing preferences reverts to the base features", () => {
116
+ const { mount, controller } = mountWith("inline", {
117
+ artifacts: { display: "panel" },
118
+ });
119
+ upsertSample(controller);
120
+ expect(inlineBlockCount(mount)).toBe(0);
121
+
122
+ // Explicit-undefined deletes the key (config-merge reset semantics); the
123
+ // effective mode must fall back to the base "inline", not keep "panel".
124
+ controller.update({ preferences: undefined });
125
+ expect(inlineBlockCount(mount)).toBe(1);
126
+ controller.destroy();
127
+ });
128
+
129
+ it("an update's slice replaces the previous slice; dropped keys revert", () => {
130
+ const { mount, controller } = mountWith("collapsed");
131
+ controller.update({
132
+ preferences: {
133
+ showReasoning: false,
134
+ artifacts: { display: "inline" },
135
+ },
136
+ });
137
+ upsertSample(controller);
138
+ expect(inlineBlockCount(mount)).toBe(1);
139
+
140
+ // The new slice keeps showReasoning but drops the artifacts key. Patch
141
+ // semantics would strand display:"inline"; replace semantics revert the
142
+ // block to the base "collapsed" card.
143
+ controller.update({ preferences: { showReasoning: false } });
144
+ expect(inlineBlockCount(mount)).toBe(0);
145
+ controller.destroy();
146
+ });
147
+
148
+ it("replacing preferences re-resolves from the base, not the prior overlay", () => {
149
+ const { mount, controller } = mountWith(
150
+ { default: "collapsed", byKind: { markdown: "inline" } },
151
+ { artifacts: { display: "panel" } }
152
+ );
153
+ upsertSample(controller);
154
+ expect(inlineBlockCount(mount)).toBe(0);
155
+
156
+ // The object-form preference refines the base, so byKind.markdown →
157
+ // "inline" survives and the block converts to an inline preview. If the
158
+ // prior "panel" string overlay had been folded into the base, byKind
159
+ // would be gone and this would resolve "collapsed" (a card).
160
+ controller.update({
161
+ preferences: { artifacts: { display: { default: "collapsed" } } },
162
+ });
163
+ expect(inlineBlockCount(mount)).toBe(1);
164
+ controller.destroy();
165
+ });
166
+ });
@@ -907,7 +907,7 @@ describe("createAgentExperience welded artifact split chrome", () => {
907
907
 
908
908
  controller.hideArtifacts();
909
909
 
910
- // Byte-identical to pane-closed: container carries the border, panel does not.
910
+ // Same as pane-closed: container carries the border, panel does not.
911
911
  expect(mount.classList.contains("persona-artifact-welded-split")).toBe(false);
912
912
  expect(container?.style.border).toContain("--persona-panel-border");
913
913
  expect(panel?.style.border).toBe("");