@runtypelabs/persona 4.23.1 → 4.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animations/glyph-cycle.d.cts +1 -1
- package/dist/animations/glyph-cycle.d.ts +1 -1
- package/dist/animations/{types-9Vxm-PPz.d.cts → types-Db61aI9J.d.cts} +25 -2
- package/dist/animations/{types-9Vxm-PPz.d.ts → types-Db61aI9J.d.ts} +25 -2
- package/dist/animations/wipe.d.cts +1 -1
- package/dist/animations/wipe.d.ts +1 -1
- package/dist/animations-extra.d.cts +25 -2
- package/dist/animations-extra.d.ts +25 -2
- package/dist/approval-ui-3NMYNXBD.js +1 -0
- package/dist/approval-ui.cjs +2 -2
- package/dist/approval-ui.d.cts +261 -40
- package/dist/approval-ui.d.ts +261 -40
- package/dist/approval-ui.js +2 -2
- package/dist/{artifacts-ui-F4N6VMKF.js → artifacts-ui-IGB5YKLO.js} +4 -4
- package/dist/artifacts-ui.d.cts +256 -28
- package/dist/artifacts-ui.d.ts +256 -28
- package/dist/{chunk-NIKYKSNZ.js → chunk-7CO4T5KB.js} +1 -1
- package/dist/codegen.cjs +11 -11
- package/dist/codegen.js +13 -13
- package/dist/context-mentions.d.cts +256 -28
- package/dist/context-mentions.d.ts +256 -28
- package/dist/event-stream-view.d.cts +256 -28
- package/dist/event-stream-view.d.ts +256 -28
- package/dist/forms-ui.d.cts +291 -30
- package/dist/forms-ui.d.ts +291 -30
- package/dist/history-view.d.cts +25 -2
- package/dist/history-view.d.ts +25 -2
- package/dist/index.cjs +70 -69
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +337 -51
- package/dist/index.d.ts +337 -51
- package/dist/index.global.js +57 -54
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +70 -69
- package/dist/index.js.map +1 -1
- package/dist/install.global.js +1 -1
- package/dist/install.global.js.map +1 -1
- package/dist/launcher.global.js +2 -2
- package/dist/launcher.global.js.map +1 -1
- package/dist/session-reconnect.d.cts +256 -28
- package/dist/session-reconnect.d.ts +256 -28
- package/dist/smart-dom-reader.d.cts +256 -28
- package/dist/smart-dom-reader.d.ts +256 -28
- package/dist/theme-editor-preview.cjs +74 -73
- package/dist/theme-editor-preview.d.cts +263 -28
- package/dist/theme-editor-preview.d.ts +263 -28
- package/dist/theme-editor-preview.js +51 -50
- package/dist/theme-editor.cjs +10 -10
- package/dist/theme-editor.d.cts +276 -30
- package/dist/theme-editor.d.ts +276 -30
- package/dist/theme-editor.js +10 -10
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +1522 -11
- package/dist/theme-reference.d.ts +1522 -11
- package/dist/theme-reference.js +1 -1
- package/dist/widget.css +1 -1
- package/package.json +3 -2
- package/src/__fixtures__/defaults-parity.v4.json +776 -0
- package/src/approval-ui-entry.ts +0 -1
- package/src/approval-ui-loader.ts +5 -4
- package/src/approval-ui.ts +0 -1
- package/src/client-identity-proof.test.ts +193 -0
- package/src/client-session-warm.test.ts +216 -0
- package/src/client-visitor-history.test.ts +6 -0
- package/src/client.tool-pair-replay.test.ts +325 -0
- package/src/client.ts +154 -61
- package/src/codegen.test.ts +24 -0
- package/src/components/activity-row.test.ts +100 -0
- package/src/components/activity-row.ts +136 -0
- package/src/components/approval-actions.test.ts +8 -5
- package/src/components/approval-actions.ts +19 -6
- package/src/components/approval-bubble.test.ts +56 -9
- package/src/components/approval-bubble.ts +36 -41
- package/src/components/composer-builder.ts +5 -2
- package/src/components/composer-parts.ts +10 -2
- package/src/components/header-builder.test.ts +32 -0
- package/src/components/header-builder.ts +7 -4
- package/src/components/header-layouts.test.ts +12 -0
- package/src/components/header-layouts.ts +3 -2
- package/src/components/launcher.ts +11 -2
- package/src/components/message-bubble.test.ts +22 -0
- package/src/components/message-bubble.ts +7 -3
- package/src/components/panel.test.ts +52 -1
- package/src/components/panel.ts +47 -8
- package/src/components/pill-composer-builder.test.ts +2 -0
- package/src/components/pill-composer-builder.ts +0 -1
- package/src/components/reasoning-bubble.ts +29 -17
- package/src/components/suggestions.test.ts +1 -0
- package/src/components/suggestions.ts +0 -16
- package/src/components/tool-bubble.ts +131 -114
- package/src/components/tool-details.test.ts +87 -0
- package/src/components/tool-details.ts +102 -0
- package/src/components/welcome.test.ts +8 -0
- package/src/components/welcome.ts +4 -2
- package/src/defaults-parity.test.ts +158 -0
- package/src/defaults.test.ts +69 -0
- package/src/defaults.ts +128 -49
- package/src/generated/runtype-openapi-contract.ts +28 -13
- package/src/index-core.ts +2 -0
- package/src/install.test.ts +24 -0
- package/src/install.ts +3 -1
- package/src/launcher-global.ts +2 -1
- package/src/launcher-variants.test.ts +52 -0
- package/src/runtime/init-update-reset.test.ts +21 -0
- package/src/session.ts +61 -9
- package/src/styles/widget-styles.test.ts +19 -0
- package/src/styles/widget.css +295 -23
- package/src/theme-editor/index.ts +2 -0
- package/src/theme-editor/preview-utils.test.ts +8 -0
- package/src/theme-editor/preview-utils.ts +7 -3
- package/src/theme-editor/sections.test.ts +31 -0
- package/src/theme-editor/sections.ts +55 -1
- package/src/theme-editor/state-preferences.test.ts +49 -0
- package/src/theme-editor/state.ts +73 -15
- package/src/theme-reference.test.ts +20 -0
- package/src/theme-reference.ts +11 -5
- package/src/tool-call-display-defaults.test.ts +33 -1
- package/src/types/theme.ts +80 -3
- package/src/types.ts +179 -23
- package/src/ui.activity-row.test.ts +91 -0
- package/src/ui.approval-plugin.test.ts +63 -0
- package/src/ui.composer-compact.test.ts +24 -2
- package/src/ui.composer-placement.test.ts +23 -0
- package/src/ui.detached-panel.test.ts +33 -6
- package/src/ui.docked.test.ts +19 -0
- package/src/ui.header-update-stability.test.ts +25 -0
- package/src/ui.identity-proof.test.ts +58 -0
- package/src/ui.launcher-teaser.test.ts +25 -0
- package/src/ui.message-width.test.ts +17 -2
- package/src/ui.reasoning-display.test.ts +92 -0
- package/src/ui.rebuild-composer.test.ts +20 -3
- package/src/ui.scroll.test.ts +32 -0
- package/src/ui.session-init.test.ts +312 -0
- package/src/ui.status-indicator.test.ts +82 -0
- package/src/ui.suggest-replies.test.ts +11 -0
- package/src/ui.ts +363 -74
- package/src/ui.v5-defaults.test.ts +144 -0
- package/src/ui.welcome.test.ts +92 -3
- package/src/utils/__snapshots__/tokens-parity.test.ts.snap +811 -140
- package/src/utils/code-generators.ts +14 -0
- package/src/utils/composer-compact.test.ts +0 -2
- package/src/utils/composer-compact.ts +2 -4
- package/src/utils/composer-placement.ts +2 -3
- package/src/utils/config-merge.test.ts +81 -5
- package/src/utils/config-merge.ts +13 -3
- package/src/utils/defaults-provenance.ts +67 -0
- package/src/utils/dock.ts +7 -1
- package/src/utils/launcher-variant.ts +16 -0
- package/src/utils/panel-config.ts +97 -0
- package/src/utils/status-indicator.ts +39 -0
- package/src/utils/theme.test.ts +182 -0
- package/src/utils/theme.ts +131 -18
- package/src/utils/tokens.test.ts +122 -1
- package/src/utils/tokens.ts +177 -17
- package/src/utils/tool-pair-replay.ts +100 -0
- package/src/welcome.test.ts +23 -0
- package/src/welcome.ts +16 -9
- package/dist/approval-ui-K7R5Q5OC.js +0 -1
|
@@ -78,6 +78,7 @@ export type RuntypeExecutionStreamEvent = ({
|
|
|
78
78
|
turnIndex?: number;
|
|
79
79
|
type: "turn_start";
|
|
80
80
|
}) | ({
|
|
81
|
+
attributes?: Record<string, string | number | boolean>;
|
|
81
82
|
completedAt?: string;
|
|
82
83
|
content?: string;
|
|
83
84
|
cost?: number;
|
|
@@ -136,7 +137,8 @@ export type RuntypeExecutionStreamEvent = ({
|
|
|
136
137
|
};
|
|
137
138
|
turnId?: string;
|
|
138
139
|
type: "model_call_start";
|
|
139
|
-
} | {
|
|
140
|
+
} | ({
|
|
141
|
+
attributes?: Record<string, string | number | boolean>;
|
|
140
142
|
completedAt?: string;
|
|
141
143
|
cost?: number;
|
|
142
144
|
durationMs?: number;
|
|
@@ -160,10 +162,11 @@ export type RuntypeExecutionStreamEvent = ({
|
|
|
160
162
|
cacheWrite?: number;
|
|
161
163
|
input: number;
|
|
162
164
|
output: number;
|
|
165
|
+
reasoning?: number;
|
|
163
166
|
};
|
|
164
167
|
turnId?: string;
|
|
165
168
|
type: "model_call_complete";
|
|
166
|
-
} | {
|
|
169
|
+
}) | {
|
|
167
170
|
executionId: string;
|
|
168
171
|
id: string;
|
|
169
172
|
index?: number;
|
|
@@ -558,38 +561,50 @@ export type RuntypeStopReasonKind = NonNullable<
|
|
|
558
561
|
RuntypeTurnCompleteEvent["stopReason"] | RuntypeStepCompleteEvent["stopReason"]
|
|
559
562
|
>;
|
|
560
563
|
|
|
561
|
-
export type RuntypeClientInitRequest = {
|
|
564
|
+
export type RuntypeClientInitRequest = ({
|
|
562
565
|
durableRecovery?: boolean;
|
|
563
566
|
flowId?: string;
|
|
564
|
-
identityProof?: string
|
|
567
|
+
identityProof?: string | {
|
|
568
|
+
provider: string;
|
|
569
|
+
token: string;
|
|
570
|
+
};
|
|
565
571
|
token: string;
|
|
566
572
|
visitorHistory?: boolean;
|
|
567
573
|
visitorToken?: string;
|
|
568
|
-
} | {
|
|
574
|
+
}) | ({
|
|
569
575
|
durableRecovery?: boolean;
|
|
570
576
|
flowId?: string;
|
|
571
|
-
identityProof?: string
|
|
577
|
+
identityProof?: string | {
|
|
578
|
+
provider: string;
|
|
579
|
+
token: string;
|
|
580
|
+
};
|
|
572
581
|
sessionId: string;
|
|
573
582
|
token: string;
|
|
574
583
|
visitorHistory?: boolean;
|
|
575
584
|
visitorToken?: string;
|
|
576
|
-
} | {
|
|
585
|
+
}) | ({
|
|
577
586
|
conversationId: string;
|
|
578
587
|
durableRecovery?: boolean;
|
|
579
588
|
flowId?: string;
|
|
580
|
-
identityProof?: string
|
|
589
|
+
identityProof?: string | {
|
|
590
|
+
provider: string;
|
|
591
|
+
token: string;
|
|
592
|
+
};
|
|
581
593
|
token: string;
|
|
582
594
|
visitorHistory?: boolean;
|
|
583
595
|
visitorToken: string;
|
|
584
|
-
} | {
|
|
596
|
+
}) | ({
|
|
585
597
|
conversationId: string;
|
|
586
598
|
durableRecovery?: boolean;
|
|
587
599
|
flowId?: string;
|
|
588
|
-
identityProof: string
|
|
600
|
+
identityProof: string | {
|
|
601
|
+
provider: string;
|
|
602
|
+
token: string;
|
|
603
|
+
};
|
|
589
604
|
token: string;
|
|
590
605
|
visitorHistory?: boolean;
|
|
591
606
|
visitorToken?: string;
|
|
592
|
-
};
|
|
607
|
+
});
|
|
593
608
|
|
|
594
609
|
export type RuntypeClientInitResponse = {
|
|
595
610
|
app?: {
|
|
@@ -604,7 +619,7 @@ export type RuntypeClientInitResponse = {
|
|
|
604
619
|
conversationRevision: string;
|
|
605
620
|
durableRecovery?: {
|
|
606
621
|
enabled: boolean;
|
|
607
|
-
|
|
622
|
+
steer?: boolean;
|
|
608
623
|
};
|
|
609
624
|
expiresAt: string;
|
|
610
625
|
flow?: {
|
|
@@ -666,7 +681,7 @@ export type RuntypeClientChatRequest = {
|
|
|
666
681
|
}>;
|
|
667
682
|
metadata?: Record<string, unknown>;
|
|
668
683
|
sessionId: string;
|
|
669
|
-
submitMode?: "normal" | "interrupt" | "
|
|
684
|
+
submitMode?: "normal" | "interrupt" | "steer";
|
|
670
685
|
turnId?: string;
|
|
671
686
|
};
|
|
672
687
|
|
package/src/index-core.ts
CHANGED
package/src/install.test.ts
CHANGED
|
@@ -226,6 +226,30 @@ describe("install.ts: deferred launcher path", () => {
|
|
|
226
226
|
|
|
227
227
|
expect(initAgentWidget).toHaveBeenCalledTimes(1);
|
|
228
228
|
});
|
|
229
|
+
|
|
230
|
+
it.each([false, true])("passes future.v5Defaults=%s through the deferred launcher handoff", async (v5Defaults) => {
|
|
231
|
+
markCssLoaded();
|
|
232
|
+
provideFullBundle();
|
|
233
|
+
provideLauncherBundle();
|
|
234
|
+
|
|
235
|
+
const variant = v5Defaults ? "pill" : "circle";
|
|
236
|
+
await install({
|
|
237
|
+
config: { apiUrl: "/api", launcher: { variant } },
|
|
238
|
+
future: { v5Defaults },
|
|
239
|
+
});
|
|
240
|
+
await flush();
|
|
241
|
+
|
|
242
|
+
expect(launcherMount).toHaveBeenCalledWith(expect.objectContaining({
|
|
243
|
+
config: expect.objectContaining({ future: { v5Defaults }, launcher: expect.objectContaining({ variant }) }),
|
|
244
|
+
}));
|
|
245
|
+
|
|
246
|
+
capturedOnOpen!();
|
|
247
|
+
await flush();
|
|
248
|
+
|
|
249
|
+
expect(initAgentWidget).toHaveBeenCalledWith(expect.objectContaining({
|
|
250
|
+
config: expect.objectContaining({ future: { v5Defaults }, launcher: expect.objectContaining({ variant }) }),
|
|
251
|
+
}));
|
|
252
|
+
});
|
|
229
253
|
});
|
|
230
254
|
|
|
231
255
|
describe("install.ts: eager path", () => {
|
package/src/install.ts
CHANGED
|
@@ -19,6 +19,8 @@ interface SiteAgentInstallConfig {
|
|
|
19
19
|
jsUrl?: string;
|
|
20
20
|
target?: string | HTMLElement;
|
|
21
21
|
config?: any;
|
|
22
|
+
/** Opt in to the staged v5 defaults when using top-level installer options. */
|
|
23
|
+
future?: { v5Defaults?: boolean };
|
|
22
24
|
autoInit?: boolean;
|
|
23
25
|
// Client token mode options (can also be set via data attributes)
|
|
24
26
|
clientToken?: string;
|
|
@@ -447,6 +449,7 @@ declare global {
|
|
|
447
449
|
if (config.clientToken && !widgetConfig.clientToken) widgetConfig.clientToken = config.clientToken;
|
|
448
450
|
if (config.flowId && !widgetConfig.flowId) widgetConfig.flowId = config.flowId;
|
|
449
451
|
if (config.agentId && !widgetConfig.agentId) widgetConfig.agentId = config.agentId;
|
|
452
|
+
if (config.future && !widgetConfig.future) widgetConfig.future = config.future;
|
|
450
453
|
|
|
451
454
|
const hasApiConfig = !!(widgetConfig.apiUrl || widgetConfig.clientToken);
|
|
452
455
|
return { target, widgetConfig, hasApiConfig };
|
|
@@ -631,4 +634,3 @@ declare global {
|
|
|
631
634
|
// This prevents Next.js/Nuxt/etc. from removing dynamically added CSS
|
|
632
635
|
waitForHydration(install);
|
|
633
636
|
})();
|
|
634
|
-
|
package/src/launcher-global.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { createLauncherSurface } from "./components/launcher";
|
|
24
24
|
import { applyThemeVariables } from "./utils/theme";
|
|
25
|
-
import { DEFAULT_LAUNCHER_CONFIG } from "./defaults";
|
|
25
|
+
import { DEFAULT_LAUNCHER_CONFIG, DEFAULT_LAUNCHER_V5 } from "./defaults";
|
|
26
26
|
import { setIconsExtraLoader } from "./icons-extra-loader";
|
|
27
27
|
import type { AgentWidgetConfig } from "./types";
|
|
28
28
|
|
|
@@ -94,6 +94,7 @@ const mergeCriticalLauncherConfig = (
|
|
|
94
94
|
...config,
|
|
95
95
|
launcher: {
|
|
96
96
|
...DEFAULT_LAUNCHER_CONFIG,
|
|
97
|
+
...(config?.future?.v5Defaults === true ? DEFAULT_LAUNCHER_V5 : {}),
|
|
97
98
|
...config?.launcher,
|
|
98
99
|
dock: {
|
|
99
100
|
...DEFAULT_LAUNCHER_CONFIG.dock,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { createAgentExperience } from "./ui";
|
|
4
|
+
import { mount as mountCritical } from "./launcher-global";
|
|
5
|
+
import { getActiveTheme, themeToCssVariables } from "./utils/theme";
|
|
6
|
+
import type { AgentWidgetConfig } from "./types";
|
|
7
|
+
|
|
8
|
+
afterEach(() => { document.body.replaceChildren(); vi.restoreAllMocks(); });
|
|
9
|
+
|
|
10
|
+
describe.each([false, true])("launcher variants (v5=%s)", (v5Defaults) => {
|
|
11
|
+
it.each([undefined, "pill", "circle"] as const)("matches deferred and full rendering for %s", (variant) => {
|
|
12
|
+
window.scrollTo = vi.fn();
|
|
13
|
+
const config: AgentWidgetConfig = {
|
|
14
|
+
apiUrl: "/dispatch", persistState: false, future: { v5Defaults },
|
|
15
|
+
launcher: { ...(variant ? { variant } : {}), title: "Open support", teaser: { text: "Need help?" } },
|
|
16
|
+
};
|
|
17
|
+
const host = document.body.appendChild(document.createElement("div"));
|
|
18
|
+
const target = document.body.appendChild(document.createElement("div"));
|
|
19
|
+
const full = createAgentExperience(host, config);
|
|
20
|
+
const critical = mountCritical({ target, config, onOpen: vi.fn() });
|
|
21
|
+
const button = host.querySelector<HTMLButtonElement>(".persona-launcher-surface > button")!;
|
|
22
|
+
try {
|
|
23
|
+
const circle = variant ? variant === "circle" : v5Defaults;
|
|
24
|
+
expect(button.dataset.personaLauncherVariant).toBe(circle ? "circle" : undefined);
|
|
25
|
+
expect(button.innerHTML).toBe(critical.element.innerHTML);
|
|
26
|
+
expect(button.getAttribute("style")).toBe(critical.element.getAttribute("style"));
|
|
27
|
+
expect(host.style.getPropertyValue("--persona-launcher-bg"))
|
|
28
|
+
.toBe(critical.root.style.getPropertyValue("--persona-launcher-bg"));
|
|
29
|
+
if (circle) expect(button.getAttribute("aria-label")).toBe("Open support");
|
|
30
|
+
full.update({ launcher: { variant: circle ? "pill" : "circle" } });
|
|
31
|
+
critical.update({ ...config, launcher: { ...config.launcher, variant: circle ? "pill" : "circle" } });
|
|
32
|
+
expect(button.dataset.personaLauncherVariant).toBe(circle ? undefined : "circle");
|
|
33
|
+
expect(button.innerHTML).toBe(critical.element.innerHTML);
|
|
34
|
+
} finally { full.destroy(); critical.destroy(); }
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it.each(["light", "dark"] as const)("resolves circle geometry and explicit tokens in %s", colorScheme => {
|
|
38
|
+
const config: AgentWidgetConfig = { future: { v5Defaults }, colorScheme, launcher: { variant: "circle" } };
|
|
39
|
+
const css = themeToCssVariables(getActiveTheme(config));
|
|
40
|
+
expect(css["--persona-components-launcher-size"]).toBe("48px");
|
|
41
|
+
expect(css["--persona-components-launcher-offset"]).toBe("20px");
|
|
42
|
+
expect(css["--persona-launcher-shadow"]).toBe("0 8px 24px rgba(0,0,0,.16)");
|
|
43
|
+
expect(css["--persona-launcher-bg"]).not.toBe(css["--persona-launcher-fg"]);
|
|
44
|
+
const custom = themeToCssVariables(getActiveTheme({ ...config, theme: { components: { launcher: {
|
|
45
|
+
size: "56px", iconSize: "20px", offset: "32px", background: "#123456", foreground: "#ffffff", shadow: "none",
|
|
46
|
+
} } } }));
|
|
47
|
+
expect(custom["--persona-components-launcher-size"]).toBe("56px");
|
|
48
|
+
expect(custom["--persona-components-launcher-offset"]).toBe("32px");
|
|
49
|
+
expect(custom["--persona-launcher-bg"]).toBe("#123456");
|
|
50
|
+
expect(custom["--persona-launcher-shadow"]).toBe("none");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -78,4 +78,25 @@ describe("handle.update explicit-undefined reset reaches the controller", () =>
|
|
|
78
78
|
|
|
79
79
|
handle.destroy();
|
|
80
80
|
});
|
|
81
|
+
|
|
82
|
+
it("updates the root defaults-version attribute", () => {
|
|
83
|
+
window.scrollTo = vi.fn();
|
|
84
|
+
document.body.innerHTML = `<div id="target"></div>`;
|
|
85
|
+
|
|
86
|
+
const handle = initAgentWidget({
|
|
87
|
+
target: "#target",
|
|
88
|
+
config: {
|
|
89
|
+
apiUrl: "https://api.example.com/chat",
|
|
90
|
+
launcher: { enabled: false },
|
|
91
|
+
future: { v5Defaults: false },
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
const root = () => document.querySelector<HTMLElement>("[data-persona-root]")!;
|
|
95
|
+
|
|
96
|
+
expect(root().getAttribute("data-persona-defaults")).toBe("v4");
|
|
97
|
+
handle.update({ future: { v5Defaults: true } });
|
|
98
|
+
expect(root().getAttribute("data-persona-defaults")).toBe("v5");
|
|
99
|
+
|
|
100
|
+
handle.destroy();
|
|
101
|
+
});
|
|
81
102
|
});
|
package/src/session.ts
CHANGED
|
@@ -144,6 +144,7 @@ const CONNECTION_CONFIG_KEYS = [
|
|
|
144
144
|
"getStoredSessionId",
|
|
145
145
|
"setStoredSessionId",
|
|
146
146
|
"getIdentityProof",
|
|
147
|
+
"identityProvider",
|
|
147
148
|
"getStoredConversationId",
|
|
148
149
|
"setStoredConversationId",
|
|
149
150
|
"clearStoredConversationId",
|
|
@@ -1033,12 +1034,29 @@ export class AgentWidgetSession {
|
|
|
1033
1034
|
}
|
|
1034
1035
|
}
|
|
1035
1036
|
|
|
1037
|
+
/**
|
|
1038
|
+
* Early, fire-and-forget client-token init (`sessionInit` trigger or
|
|
1039
|
+
* `controller.initSession()`). Failures stay silent here: no `onError`, no
|
|
1040
|
+
* UI. The send re-runs `initSession()` and reports them as it always has.
|
|
1041
|
+
*/
|
|
1042
|
+
public warmClientSession(): void {
|
|
1043
|
+
// The visitor may send before this resolves; the server welcome still
|
|
1044
|
+
// belongs ahead of that first turn when the transcript started empty.
|
|
1045
|
+
const pristine = !this.messages.length;
|
|
1046
|
+
void this.client.warmSession().then((session) => {
|
|
1047
|
+
// A start-new or credential re-init may have replaced it meanwhile.
|
|
1048
|
+
if (session && this.client.getClientSession() === session) {
|
|
1049
|
+
this.setClientSession(session, pristine);
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1036
1054
|
/**
|
|
1037
1055
|
* Set the client session after initialization
|
|
1038
1056
|
*/
|
|
1039
|
-
public setClientSession(session: ClientSession): void {
|
|
1057
|
+
public setClientSession(session: ClientSession, pristine?: boolean): void {
|
|
1040
1058
|
this.clientSession = session;
|
|
1041
|
-
this.injectWelcomeMessage(session);
|
|
1059
|
+
this.injectWelcomeMessage(session, pristine);
|
|
1042
1060
|
}
|
|
1043
1061
|
|
|
1044
1062
|
/**
|
|
@@ -1046,15 +1064,20 @@ export class AgentWidgetSession {
|
|
|
1046
1064
|
* reopening a stored conversation is not a new thread, and the hydrated
|
|
1047
1065
|
* transcript would otherwise race a welcome bubble.
|
|
1048
1066
|
*/
|
|
1049
|
-
private injectWelcomeMessage(
|
|
1067
|
+
private injectWelcomeMessage(
|
|
1068
|
+
session: ClientSession,
|
|
1069
|
+
pristine = !this.messages.length
|
|
1070
|
+
): void {
|
|
1050
1071
|
if (this.suppressWelcomeInjection) return;
|
|
1051
|
-
if (!session.config.welcomeMessage ||
|
|
1072
|
+
if (!session.config.welcomeMessage || !pristine) return;
|
|
1073
|
+
// A late welcome (the first send raced the init) sorts ahead of that turn.
|
|
1074
|
+
const first = this.messages[0];
|
|
1052
1075
|
const welcomeMessage: AgentWidgetMessage = {
|
|
1053
1076
|
id: `welcome-${Date.now()}`,
|
|
1054
1077
|
role: "assistant",
|
|
1055
1078
|
content: session.config.welcomeMessage,
|
|
1056
|
-
createdAt: new Date().toISOString(),
|
|
1057
|
-
sequence: this.nextSequence()
|
|
1079
|
+
createdAt: first?.createdAt ?? new Date().toISOString(),
|
|
1080
|
+
sequence: first ? (first.sequence ?? 0) - 1 : this.nextSequence()
|
|
1058
1081
|
};
|
|
1059
1082
|
this.appendMessage(welcomeMessage);
|
|
1060
1083
|
}
|
|
@@ -3816,16 +3839,34 @@ export class AgentWidgetSession {
|
|
|
3816
3839
|
// re-emits don't re-execute the page tool, then complete each bubble.
|
|
3817
3840
|
// Do this only after /resume HTTP success; if /resume fails, the server
|
|
3818
3841
|
// may still be paused and the retry path must not show a final result.
|
|
3842
|
+
const batch = ready[0]!.dedupeKey;
|
|
3819
3843
|
for (const r of ready) {
|
|
3820
3844
|
this.webMcpResolvedKeys.add(r.dedupeKey);
|
|
3845
|
+
const toolName = r.toolMessage.toolCall?.name;
|
|
3846
|
+
const toolCallId = r.toolMessage.agentMetadata?.webMcpToolCallId;
|
|
3821
3847
|
this.markWebMcpToolComplete(
|
|
3822
3848
|
r.toolMessage,
|
|
3823
3849
|
r.output,
|
|
3824
3850
|
r.startedAt,
|
|
3825
3851
|
r.completedAt,
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3852
|
+
{
|
|
3853
|
+
...(toolName === SUGGEST_REPLIES_TOOL_NAME
|
|
3854
|
+
? { suggestRepliesResolved: true }
|
|
3855
|
+
: {}),
|
|
3856
|
+
// Only a provider call id can be replayed: a legacy name-keyed
|
|
3857
|
+
// resume has nothing the model's transcript can reference.
|
|
3858
|
+
...(toolName && toolCallId
|
|
3859
|
+
? {
|
|
3860
|
+
clientToolAnswer: {
|
|
3861
|
+
toolCallId,
|
|
3862
|
+
toolName,
|
|
3863
|
+
args: r.toolMessage.toolCall?.args,
|
|
3864
|
+
result: r.output,
|
|
3865
|
+
batch,
|
|
3866
|
+
},
|
|
3867
|
+
}
|
|
3868
|
+
: {}),
|
|
3869
|
+
},
|
|
3829
3870
|
);
|
|
3830
3871
|
}
|
|
3831
3872
|
if (response.body) {
|
|
@@ -4928,6 +4969,17 @@ export class AgentWidgetSession {
|
|
|
4928
4969
|
awaitingLocalTool: false,
|
|
4929
4970
|
};
|
|
4930
4971
|
}
|
|
4972
|
+
// The accepted client-tool answer is what later proxy/agent turns
|
|
4973
|
+
// replay; a post-resume `tool_complete` re-emit carries a fresh
|
|
4974
|
+
// metadata skeleton and must not drop it.
|
|
4975
|
+
const clientToolAnswer = existing.agentMetadata?.clientToolAnswer;
|
|
4976
|
+
if (
|
|
4977
|
+
clientToolAnswer &&
|
|
4978
|
+
merged.agentMetadata &&
|
|
4979
|
+
!merged.agentMetadata.clientToolAnswer
|
|
4980
|
+
) {
|
|
4981
|
+
merged.agentMetadata = { ...merged.agentMetadata, clientToolAnswer };
|
|
4982
|
+
}
|
|
4931
4983
|
// Approval equivalent: `approval_complete` carries only the
|
|
4932
4984
|
// resolution (approvalId, decision, resolvedBy): the runtime does not
|
|
4933
4985
|
// re-send toolName/description/toolType/reason/parameters, so client.ts
|
|
@@ -189,6 +189,25 @@ describe("suggestion interaction styles", () => {
|
|
|
189
189
|
});
|
|
190
190
|
});
|
|
191
191
|
|
|
192
|
+
describe("collapsible widget chrome styles", () => {
|
|
193
|
+
it("uses prefixed aliases while retaining each legacy alias and literal fallback", () => {
|
|
194
|
+
const expectedDeclarations: Array<[string, number]> = [
|
|
195
|
+
["var(--persona-cw-border, var(--cw-border, #e5e7eb))", 2],
|
|
196
|
+
["var(--persona-cw-container, var(--cw-container, #f9fafb))", 1],
|
|
197
|
+
["var(--persona-cw-surface, var(--cw-surface, #ffffff))", 2],
|
|
198
|
+
["var(--persona-cw-border, var(--cw-border, #f1f5f9))", 1],
|
|
199
|
+
["var(--persona-cw-container, var(--cw-container, #f8fafc))", 1],
|
|
200
|
+
["var(--persona-cw-border, var(--cw-border, #d1d5db))", 1],
|
|
201
|
+
["var(--persona-cw-surface, var(--cw-surface, #fff))", 2],
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
for (const [declaration, count] of expectedDeclarations) {
|
|
205
|
+
expect(widgetCss).toContain(declaration);
|
|
206
|
+
expect(widgetCss.split(declaration).length - 1).toBe(count);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
192
211
|
describe("composer spacing styles", () => {
|
|
193
212
|
it("themes the composer form padding and gap with utility-matching fallbacks", () => {
|
|
194
213
|
const selector =
|