@runtypelabs/persona 4.32.0 → 4.32.2
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/activity-ui.cjs +1 -1
- package/dist/activity-ui.js +1 -1
- package/dist/{chunk-BrptyKSq.js → chunk-B3l7TOOv.js} +1 -1
- package/dist/{chunk-CkE90FtA.js → chunk-B4ecQzeK.js} +1 -1
- package/dist/{chunk-CzZBmTLd.js → chunk-B9Zu-wrk.js} +1 -1
- package/dist/chunk-BNE40cEG.js +1 -0
- package/dist/{chunk-BWCo3rCm.js → chunk-B_H0l3u2.js} +1 -1
- package/dist/{chunk-MdlQetfC.js → chunk-BbXc58OA.js} +1 -1
- package/dist/{chunk-DE0cSmku.js → chunk-BpjtKnGI.js} +1 -1
- package/dist/{chunk-CHAwCqpk.js → chunk-CdpVP6LZ.js} +1 -1
- package/dist/{chunk-FEzOcZof.js → chunk-CjkechxR.js} +1 -1
- package/dist/{chunk-DZg9bFK6.js → chunk-D0tcIZJM.js} +1 -1
- package/dist/{chunk-Cb7qy0c7.js → chunk-DNdeIFJ6.js} +1 -1
- package/dist/{chunk-VaT6xry9.js → chunk-DTGvDx8o.js} +1 -1
- package/dist/{chunk-ezlpsYGk.js → chunk-DVZ8ri1z.js} +1 -1
- package/dist/{chunk-DhedQnek.js → chunk-DgZZqy14.js} +1 -1
- package/dist/{chunk-C2IbR39s.js → chunk-UWMfWW2a.js} +1 -1
- package/dist/client-dispatch.js +1 -1
- package/dist/client-history.js +1 -1
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.global.js +1 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +4 -4
- 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/theme-editor-preview.cjs +4 -4
- package/dist/theme-editor-preview.js +4 -4
- package/dist/theme-editor.cjs +1 -1
- package/dist/theme-editor.js +1 -1
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.js +1 -1
- package/dist/voice-runtime.cjs +1 -1
- package/dist/voice-runtime.js +1 -1
- package/dist/widget.css +1 -1
- package/package.json +1 -1
- package/src/index-global.ts +2 -1
- package/src/install.test.ts +6 -5
- package/src/install.ts +2 -2
- package/src/launcher-global.ts +2 -1
- package/src/session.test.ts +41 -0
- package/src/session.ts +14 -7
- package/src/styles/widget.css +12 -0
- package/src/utils/brand.test.ts +50 -0
- package/src/utils/brand.ts +6 -2
- package/src/utils/cdn-release.test.ts +20 -0
- package/src/utils/cdn-release.ts +14 -0
- package/src/utils/tokens.ts +2 -1
- package/src/utils/tool-activity-summary.test.ts +8 -0
- package/src/utils/tool-activity-summary.ts +2 -1
- package/dist/chunk-DDAwu89-.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runtypelabs/persona",
|
|
3
|
-
"version": "4.32.
|
|
3
|
+
"version": "4.32.2",
|
|
4
4
|
"description": "Themeable, pluggable streaming agent widget for websites, in plain JS with support for voice input and reasoning / tool output.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
package/src/index-global.ts
CHANGED
|
@@ -37,12 +37,13 @@ export type { StreamAnimationPlugin, StreamAnimationContext } from "./types";
|
|
|
37
37
|
// ---------------------------------------------------------------------------
|
|
38
38
|
|
|
39
39
|
import { setWebMcpPolyfillLoader } from "./webmcp-bridge";
|
|
40
|
+
import { pinCdnRelease } from "./utils/cdn-release";
|
|
40
41
|
|
|
41
42
|
// Capture at module-evaluation time: `document.currentScript` is null once
|
|
42
43
|
// execution leaves the script's initial synchronous run.
|
|
43
44
|
const widgetScriptSrc: string | null =
|
|
44
45
|
typeof document !== "undefined"
|
|
45
|
-
? ((document.currentScript as HTMLScriptElement | null)?.src ?? null
|
|
46
|
+
? pinCdnRelease((document.currentScript as HTMLScriptElement | null)?.src ?? "") || null
|
|
46
47
|
: null;
|
|
47
48
|
|
|
48
49
|
/**
|
package/src/install.test.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// `vi.runAllTimersAsync()` to drive it forward deterministically.
|
|
11
11
|
|
|
12
12
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
13
|
+
import { version } from "../package.json";
|
|
13
14
|
|
|
14
15
|
const PERSONA_EVENTS = [
|
|
15
16
|
"persona:script-load",
|
|
@@ -464,11 +465,11 @@ describe("install.ts: CDN base derivation", () => {
|
|
|
464
465
|
return { cssHref: css?.href ?? null, scripts };
|
|
465
466
|
}
|
|
466
467
|
|
|
467
|
-
it("
|
|
468
|
+
it("pins first-party latest installer assets to the embedded release", async () => {
|
|
468
469
|
setCurrentScript("https://cdn.runtype.com/persona/latest/install.global.js");
|
|
469
470
|
const { cssHref, scripts } = await installedUrls({});
|
|
470
|
-
expect(cssHref).toBe(
|
|
471
|
-
expect(scripts).toContain(
|
|
471
|
+
expect(cssHref).toBe(`https://cdn.runtype.com/persona/${version}/widget.css`);
|
|
472
|
+
expect(scripts).toContain(`https://cdn.runtype.com/persona/${version}/launcher.global.js`);
|
|
472
473
|
});
|
|
473
474
|
|
|
474
475
|
it("keeps npm-CDN siblings on the installer's own pinned range (no @latest skew)", async () => {
|
|
@@ -478,13 +479,13 @@ describe("install.ts: CDN base derivation", () => {
|
|
|
478
479
|
expect(scripts).toContain("https://cdn.jsdelivr.net/npm/@runtypelabs/persona@4/dist/launcher.global.js");
|
|
479
480
|
});
|
|
480
481
|
|
|
481
|
-
it("the full bundle
|
|
482
|
+
it("pins the full bundle on the eager first-party latest path", async () => {
|
|
482
483
|
setCurrentScript("https://cdn.runtype.com/persona/latest/install.global.js");
|
|
483
484
|
markCssLoaded();
|
|
484
485
|
await install({ config: { apiUrl: "/api", launcher: { enabled: false } } });
|
|
485
486
|
await flush();
|
|
486
487
|
const scripts = Array.from(document.head.querySelectorAll("script")).map((s) => s.src);
|
|
487
|
-
expect(scripts).toContain(
|
|
488
|
+
expect(scripts).toContain(`https://cdn.runtype.com/persona/${version}/index.global.js`);
|
|
488
489
|
});
|
|
489
490
|
|
|
490
491
|
it("falls back to jsDelivr@latest when currentScript is unavailable", async () => {
|
package/src/install.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* if configuration is provided via window.siteAgentConfig
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import { pinCdnRelease } from "./utils/cdn-release";
|
|
8
8
|
|
|
9
9
|
import type { BrandConfig } from "./types/theme";
|
|
10
10
|
import { delayInstallLoading } from "./utils/install-loading";
|
|
@@ -201,7 +201,7 @@ declare global {
|
|
|
201
201
|
const getInstallerBase = (): string | null => {
|
|
202
202
|
if (!installerSrc) return null;
|
|
203
203
|
try {
|
|
204
|
-
const url = new URL(installerSrc, document.baseURI);
|
|
204
|
+
const url = new URL(pinCdnRelease(installerSrc), document.baseURI);
|
|
205
205
|
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
206
206
|
return url.origin + url.pathname.slice(0, url.pathname.lastIndexOf("/"));
|
|
207
207
|
} catch {
|
package/src/launcher-global.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { createLauncherSurface } from "./components/launcher";
|
|
|
24
24
|
import { applyLauncherThemeVariables } from "./utils/theme";
|
|
25
25
|
import { DEFAULT_LAUNCHER_CONFIG, DEFAULT_LAUNCHER_V5 } from "./defaults";
|
|
26
26
|
import { setIconsExtraLoader } from "./icons-extra-loader";
|
|
27
|
+
import { pinCdnRelease } from "./utils/cdn-release";
|
|
27
28
|
import type { AgentWidgetConfig } from "./types";
|
|
28
29
|
|
|
29
30
|
// ---------------------------------------------------------------------------
|
|
@@ -33,7 +34,7 @@ import type { AgentWidgetConfig } from "./types";
|
|
|
33
34
|
// ---------------------------------------------------------------------------
|
|
34
35
|
const launcherScriptSrc: string | null =
|
|
35
36
|
typeof document !== "undefined"
|
|
36
|
-
? ((document.currentScript as HTMLScriptElement | null)?.src ?? null
|
|
37
|
+
? pinCdnRelease((document.currentScript as HTMLScriptElement | null)?.src ?? "") || null
|
|
37
38
|
: null;
|
|
38
39
|
|
|
39
40
|
setIconsExtraLoader(() => {
|
package/src/session.test.ts
CHANGED
|
@@ -1070,6 +1070,47 @@ describe('AgentWidgetSession - dispatch error fallback', () => {
|
|
|
1070
1070
|
expect(session.getStatus()).toBe('idle');
|
|
1071
1071
|
});
|
|
1072
1072
|
|
|
1073
|
+
it('does not blame the backend for an internal stream TypeError after a successful response', async () => {
|
|
1074
|
+
const response = new Response('data: {}\n\n', { headers: { 'Content-Type': 'text/event-stream' } });
|
|
1075
|
+
const fault = new TypeError('t.streamGeneration is not a function');
|
|
1076
|
+
vi.spyOn(response.body!, 'getReader').mockImplementation(() => { throw fault; });
|
|
1077
|
+
global.fetch = vi.fn().mockResolvedValue(response);
|
|
1078
|
+
const errors: Error[] = [];
|
|
1079
|
+
const session = new AgentWidgetSession({ apiUrl: 'http://example.invalid/chat' }, {
|
|
1080
|
+
onMessagesChanged: () => {}, onStatusChanged: () => {}, onStreamingChanged: () => {},
|
|
1081
|
+
onError: error => errors.push(error),
|
|
1082
|
+
});
|
|
1083
|
+
await session.sendMessage('Hello');
|
|
1084
|
+
const content = lastAssistantMessage(session)?.content;
|
|
1085
|
+
expect(content).toContain('the chat encountered an unexpected error');
|
|
1086
|
+
expect(content).toContain('t.streamGeneration is not a function');
|
|
1087
|
+
expect(content).not.toContain('backend');
|
|
1088
|
+
expect(content).not.toContain("couldn't reach");
|
|
1089
|
+
expect(errors).toContain(fault);
|
|
1090
|
+
expect(session.isStreaming()).toBe(false);
|
|
1091
|
+
});
|
|
1092
|
+
|
|
1093
|
+
it.each(['Failed to fetch', 'Load failed', 'NetworkError when attempting to fetch resource.', 'fetch failed'])(
|
|
1094
|
+
'recognizes the browser fetch TypeError: %s', async (message) => {
|
|
1095
|
+
failFetchWith(new TypeError(message));
|
|
1096
|
+
const session = new AgentWidgetSession({ apiUrl: 'http://example.invalid/chat' }, {
|
|
1097
|
+
onMessagesChanged: () => {}, onStatusChanged: () => {}, onStreamingChanged: () => {},
|
|
1098
|
+
});
|
|
1099
|
+
await session.sendMessage('Hello');
|
|
1100
|
+
expect(lastAssistantMessage(session)?.content).toContain("I couldn't reach the assistant");
|
|
1101
|
+
},
|
|
1102
|
+
);
|
|
1103
|
+
|
|
1104
|
+
it('describes a server rejection without claiming the server was unreachable', async () => {
|
|
1105
|
+
global.fetch = vi.fn().mockResolvedValue(new Response('unavailable', { status: 503 }));
|
|
1106
|
+
const session = new AgentWidgetSession({ apiUrl: 'http://example.invalid/chat' }, {
|
|
1107
|
+
onMessagesChanged: () => {}, onStatusChanged: () => {}, onStreamingChanged: () => {},
|
|
1108
|
+
});
|
|
1109
|
+
await session.sendMessage('Hello');
|
|
1110
|
+
expect(lastAssistantMessage(session)?.content).toContain("chat service couldn't complete the request");
|
|
1111
|
+
expect(lastAssistantMessage(session)?.content).toContain('_Details: Chat backend request failed: 503_');
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1073
1114
|
it('uses a static errorMessage override verbatim', async () => {
|
|
1074
1115
|
failFetchWith(new Error('boom'));
|
|
1075
1116
|
const session = new AgentWidgetSession(
|
package/src/session.ts
CHANGED
|
@@ -265,10 +265,9 @@ export class SessionHistoryError extends Error {
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
/**
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
* underlying reason to help with debugging.
|
|
268
|
+
* Dispatch can fail in transport, stream parsing, lazy modules or application
|
|
269
|
+
* callbacks. Only recognized fetch failures should suggest connectivity;
|
|
270
|
+
* unknown/internal failures must not send users to debug a healthy backend.
|
|
272
271
|
*
|
|
273
272
|
* Callers can override the copy via `config.errorMessage` (a static string or
|
|
274
273
|
* a function of the error). An override that returns an empty string yields ""
|
|
@@ -283,9 +282,17 @@ function buildDispatchErrorContent(
|
|
|
283
282
|
if (typeof override === "string") return override;
|
|
284
283
|
if (typeof override === "function") return override(err);
|
|
285
284
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
285
|
+
// Fetch rejects with TypeError too, so the error class cannot distinguish
|
|
286
|
+
// an offline browser from an internal fault such as a missing function.
|
|
287
|
+
const detail = err.message.trim();
|
|
288
|
+
const networkFailure = /^(Failed to fetch|fetch failed|Load failed|NetworkError when attempting to fetch resource\.?)$/i.test(detail);
|
|
289
|
+
const backendFailure = /^(Chat backend|Agent execution) request failed: \d{3}\b/.test(detail);
|
|
290
|
+
const base = networkFailure
|
|
291
|
+
? "Sorry: I couldn't reach the assistant. Please check your connection and try again."
|
|
292
|
+
: backendFailure
|
|
293
|
+
? "Sorry: the chat service couldn't complete the request. Please try again."
|
|
294
|
+
: "Sorry: the chat encountered an unexpected error. Please reload the page and try again.";
|
|
295
|
+
return detail ? `${base}\n\n_Details: ${detail}_` : base;
|
|
289
296
|
}
|
|
290
297
|
|
|
291
298
|
/**
|
package/src/styles/widget.css
CHANGED
|
@@ -6993,6 +6993,18 @@
|
|
|
6993
6993
|
.persona-turn-activity-body .persona-tool-bubble.persona-activity-row {
|
|
6994
6994
|
--persona-activity-height: var(--persona-components-toolBubble-rowHeight, var(--persona-components-activity-rowHeight, 28px));
|
|
6995
6995
|
}
|
|
6996
|
+
[data-persona-defaults="v5"] [data-persona-tool-group-stack] .persona-tool-bubble.persona-activity-row {
|
|
6997
|
+
--persona-activity-height: var(--persona-components-toolBubble-rowHeight, var(--persona-components-activity-rowHeight, 24px));
|
|
6998
|
+
}
|
|
6999
|
+
[data-persona-defaults="v5"] [data-persona-tool-group-stack] .persona-activity-header:not(.persona-theme-padding) {
|
|
7000
|
+
padding-block: 2px;
|
|
7001
|
+
line-height: max(18px, calc(var(--persona-activity-label-size) * 1.35));
|
|
7002
|
+
}
|
|
7003
|
+
@media (any-pointer: coarse) {
|
|
7004
|
+
[data-persona-defaults="v5"] [data-persona-tool-group-stack] .persona-tool-bubble.persona-activity-row {
|
|
7005
|
+
--persona-activity-height: var(--persona-components-toolBubble-rowHeight, var(--persona-components-activity-rowHeight, 44px));
|
|
7006
|
+
}
|
|
7007
|
+
}
|
|
6996
7008
|
.persona-turn-activity-body .persona-reasoning-bubble.persona-activity-row {
|
|
6997
7009
|
--persona-activity-height: var(--persona-components-reasoningBubble-rowHeight, var(--persona-components-activity-rowHeight, 28px));
|
|
6998
7010
|
}
|
package/src/utils/brand.test.ts
CHANGED
|
@@ -73,6 +73,56 @@ describe('brand derivation', () => {
|
|
|
73
73
|
expect(theme.components?.panel?.modes?.floating?.border).toContain('var(--persona-border)');
|
|
74
74
|
expect(theme.components?.panel?.shadow).toBe(theme.palette?.shadows?.xl);
|
|
75
75
|
});
|
|
76
|
+
describe.each(['light', 'dark'] as const)('%s message presentation', (colorScheme) => {
|
|
77
|
+
const elevations = [
|
|
78
|
+
['flat', 'none'],
|
|
79
|
+
['subtle', '0 2px 8px rgba(0, 0, 0, 0.08)'],
|
|
80
|
+
['raised', '0 12px 32px rgba(0, 0, 0, 0.18)'],
|
|
81
|
+
] as const;
|
|
82
|
+
it.each(elevations)('keeps V5 prose plain with %s elevation at every density', (elevation, shadow) => {
|
|
83
|
+
for (const density of ['compact', 'comfortable', 'spacious'] as const) {
|
|
84
|
+
const config = { colorScheme, future: { v5Defaults: true }, brand: { elevation, density } };
|
|
85
|
+
const vars = getCssVariables(getActiveTheme(config));
|
|
86
|
+
expect(vars['--persona-message-assistant-shadow']).toBe('none');
|
|
87
|
+
expect(vars['--persona-message-assistant-border']).toBe('transparent');
|
|
88
|
+
expect(vars['--persona-message-assistant-padding']).toBe('0px');
|
|
89
|
+
// These existing surfaces still follow elevation; this is not a global
|
|
90
|
+
// rule that every default of `none` must opt out of brand styling.
|
|
91
|
+
expect(vars['--persona-message-user-shadow']).toBe(shadow);
|
|
92
|
+
expect(getActiveTheme(config).components.introCard?.shadow).toBe(shadow);
|
|
93
|
+
const v4 = getCssVariables(getActiveTheme({ ...config, future: { v5Defaults: false } }));
|
|
94
|
+
expect(v4['--persona-message-assistant-shadow']).toBe(shadow);
|
|
95
|
+
expect(v4['--persona-message-assistant-border']).not.toBe('transparent');
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
it.each(elevations)('lets custom padded bubbles follow %s elevation', (elevation, shadow) => {
|
|
99
|
+
for (const [density, padding] of [['compact', '8px'], ['comfortable', '12px'], ['spacious', '16px']] as const) {
|
|
100
|
+
const theme = { components: { message: { assistant: {
|
|
101
|
+
background: 'semantic.colors.container', padding, borderRadius: '12px',
|
|
102
|
+
border: 'semantic.colors.border', borderWidth: '1px', shadow: 'palette.shadows.sm',
|
|
103
|
+
} } } };
|
|
104
|
+
// Shared overrides and dark-only overrides both remain authoritative.
|
|
105
|
+
for (const overrides of colorScheme === 'dark' ? [{ theme }, { darkTheme: theme }] : [{ theme }]) {
|
|
106
|
+
const vars = getCssVariables(getActiveTheme({
|
|
107
|
+
colorScheme, future: { v5Defaults: true }, brand: { elevation, density }, ...overrides,
|
|
108
|
+
}));
|
|
109
|
+
expect(vars['--persona-message-assistant-shadow']).toBe(shadow);
|
|
110
|
+
expect(vars['--persona-message-assistant-padding']).toBe(padding);
|
|
111
|
+
expect(vars['--persona-message-assistant-border']).not.toBe('transparent');
|
|
112
|
+
expect(vars['--persona-message-assistant-border-width']).toBe('1px');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
it('preserves explicit assistant shadows and borders over brand elevation', () => {
|
|
117
|
+
const vars = getCssVariables(getActiveTheme({
|
|
118
|
+
colorScheme, future: { v5Defaults: true }, brand: { elevation: 'raised' },
|
|
119
|
+
theme: { components: { message: { assistant: { shadow: '0 1px 2px red', border: '#123456' } } } },
|
|
120
|
+
...(colorScheme === 'dark' ? { darkTheme: { components: { message: { assistant: { shadow: 'none', border: '#abcdef' } } } } } : {}),
|
|
121
|
+
}));
|
|
122
|
+
expect(vars['--persona-message-assistant-shadow']).toBe(colorScheme === 'dark' ? 'none' : '0 1px 2px red');
|
|
123
|
+
expect(vars['--persona-message-assistant-border']).toBe(colorScheme === 'dark' ? '#abcdef' : '#123456');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
76
126
|
it.each([false, true])('keeps neutral-derived surfaces and elevation coherent (%s)', (v5Defaults) => {
|
|
77
127
|
const theme = getActiveTheme({ future: { v5Defaults }, brand: { neutral: '#161b22', radius: 'none', elevation: 'flat' } });
|
|
78
128
|
const vars = getCssVariables(theme);
|
package/src/utils/brand.ts
CHANGED
|
@@ -111,8 +111,12 @@ export const deriveBrandTheme = (brand?: BrandConfig, scheme: 'light' | 'dark' =
|
|
|
111
111
|
const shadow = flat ? 'none' : brand.elevation === 'subtle' ? '0 2px 8px rgba(0, 0, 0, 0.08)' : '0 12px 32px rgba(0, 0, 0, 0.18)';
|
|
112
112
|
const border = flat ? '1px solid var(--persona-border)' : '1px solid color-mix(in srgb, var(--persona-border) 65%, transparent)';
|
|
113
113
|
theme.palette = { ...theme.palette, shadows: { sm: shadow, md: shadow, lg: shadow, xl: shadow, '2xl': shadow } };
|
|
114
|
-
const shadows = (node: Record<string, unknown
|
|
114
|
+
const shadows = (node: Record<string, unknown>, path = ''): Record<string, unknown> => {
|
|
115
115
|
const overlay: Record<string, unknown> = {};
|
|
116
|
+
// V5 assistant defaults are unpadded prose, not a surface to elevate.
|
|
117
|
+
// Explicit theme tokens still win; custom bubbles can opt into the brand
|
|
118
|
+
// shadow scale with `palette.shadows.sm` alongside their padding/background.
|
|
119
|
+
if (v5Defaults && path === 'message.assistant') return overlay;
|
|
116
120
|
for (const [key, value] of Object.entries(node)) {
|
|
117
121
|
if (key.toLowerCase().endsWith('shadow')) {
|
|
118
122
|
overlay[key] = shadow;
|
|
@@ -120,7 +124,7 @@ export const deriveBrandTheme = (brand?: BrandConfig, scheme: 'light' | 'dark' =
|
|
|
120
124
|
if (borderKey in node) overlay[borderKey] = typeof node[borderKey] === 'string' && (node[borderKey] as string).includes('solid') ? border : flat ? 'semantic.colors.border' : 'color-mix(in srgb, var(--persona-border) 65%, transparent)';
|
|
121
125
|
}
|
|
122
126
|
else if (value && typeof value === 'object') {
|
|
123
|
-
const child = shadows(value as Record<string, unknown
|
|
127
|
+
const child = shadows(value as Record<string, unknown>, path ? `${path}.${key}` : key);
|
|
124
128
|
if (Object.keys(child).length) overlay[key] = child;
|
|
125
129
|
}
|
|
126
130
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { version } from "../../package.json";
|
|
3
|
+
import { pinCdnRelease } from "./cdn-release";
|
|
4
|
+
|
|
5
|
+
describe("pinCdnRelease", () => {
|
|
6
|
+
it.each(["install", "index", "launcher"])("pins the %s entry's dependencies to its embedded release", (entry) => {
|
|
7
|
+
expect(pinCdnRelease(`https://cdn.runtype.com/persona/latest/${entry}.global.js?embed=1`))
|
|
8
|
+
.toBe(`https://cdn.runtype.com/persona/${version}/${entry}.global.js?embed=1`);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it.each([
|
|
12
|
+
"https://cdn.runtype.com/persona/4.0.0/index.global.js",
|
|
13
|
+
"https://cdn.example.com/persona/latest/index.global.js",
|
|
14
|
+
"https://cdn.jsdelivr.net/npm/@runtypelabs/persona@4/dist/index.global.js",
|
|
15
|
+
"https://cdn.runtype.com/other/latest/index.global.js",
|
|
16
|
+
"",
|
|
17
|
+
])("preserves explicit versions and other hosting layouts: %s", (src) => {
|
|
18
|
+
expect(pinCdnRelease(src)).toBe(src);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { version } from "../../package.json";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A cached /latest/ entry must keep using its own release, even after another
|
|
5
|
+
* release replaces latest. Only rewrite our published CDN layout; custom hosts
|
|
6
|
+
* and explicitly versioned URLs retain their existing sibling resolution.
|
|
7
|
+
* The bundler embeds this package version in each script-tag entry.
|
|
8
|
+
*/
|
|
9
|
+
export function pinCdnRelease(src: string): string {
|
|
10
|
+
return src.replace(
|
|
11
|
+
/^https:\/\/cdn\.runtype\.com\/persona\/latest\//,
|
|
12
|
+
`https://cdn.runtype.com/persona/${version}/`,
|
|
13
|
+
);
|
|
14
|
+
}
|
package/src/utils/tokens.ts
CHANGED
|
@@ -603,7 +603,8 @@ export const DEFAULT_COMPONENTS_V5: ComponentTokens = {
|
|
|
603
603
|
},
|
|
604
604
|
launcher: CIRCLE_LAUNCHER_TOKENS,
|
|
605
605
|
activity: {
|
|
606
|
-
|
|
606
|
+
// CSS owns contextual parent, nested, and coarse-pointer row heights.
|
|
607
|
+
labelSize: "13px", iconSize: "16px", indent: "0px",
|
|
607
608
|
transcriptGap: "0px", responseGap: "12px",
|
|
608
609
|
groupIndent: "16px", groupGap: "2px", groupPadding: "2px 0",
|
|
609
610
|
bodyPadding: "4px 0", bodyFontWeight: "400", sectionGap: "8px", bodySurface: "transparent",
|
|
@@ -6,6 +6,7 @@ const tool = (name: string, extra: Partial<AgentWidgetToolCall> = {}): AgentWidg
|
|
|
6
6
|
|
|
7
7
|
describe("semantic tool activity", () => {
|
|
8
8
|
it.each([
|
|
9
|
+
["search_docs", "Searched docs"], ["read_file", "Read a file"],
|
|
9
10
|
["web_search", "Searched the web"], ["web_search_preview", "Searched the web"], ["WebSearch", "Searched the web"],
|
|
10
11
|
["web_fetch", "Read a web page"], ["WebFetch", "Read a web page"],
|
|
11
12
|
["file_search", "Searched files"], ["search_files", "Searched files"], ["Glob", "Searched files"],
|
|
@@ -22,6 +23,12 @@ describe("semantic tool activity", () => {
|
|
|
22
23
|
["sql_db_query", "Queried the database"], ["search_gmail", "Searched email"],
|
|
23
24
|
])("maps exact alias %s", (name, label) => expect(toolActivityLabel(tool(name))).toBe(label));
|
|
24
25
|
|
|
26
|
+
it("summarizes documentation searches and file reads without a custom hook", () => {
|
|
27
|
+
expect(summarizeToolActivity([tool("search_docs"), tool("read_file")])).toBe("Searched docs, read files");
|
|
28
|
+
expect(summarizeToolActivity([tool("search_docs", { status: "running" }), tool("read_file", { status: "pending" })])).toBe("Searching docs, reading files");
|
|
29
|
+
expect(toolActivityLabel(tool("read_file", { status: "running" }))).toBe("Reading a file");
|
|
30
|
+
});
|
|
31
|
+
|
|
25
32
|
it.each(["search_events", "search_nodes", "read_graph", "open_nodes", "read", "search", "git_commit", "my_web_search", "web_search_custom"])("keeps ambiguous %s generic", name => {
|
|
26
33
|
expect(toolActivityLabel(tool(name))).toMatch(/^Used /);
|
|
27
34
|
});
|
|
@@ -127,6 +134,7 @@ describe("semantic tool activity", () => {
|
|
|
127
134
|
});
|
|
128
135
|
|
|
129
136
|
it.each([
|
|
137
|
+
["search_docs", "search"], ["read_file", "file-text"],
|
|
130
138
|
["web_search", "globe"], ["Read", "file-text"], ["edit_file", "pencil"], ["Bash", "terminal"],
|
|
131
139
|
["sql_db_query", "database"], ["search_events", "wrench"], ["my_web_search", "wrench"],
|
|
132
140
|
])("maps the completed icon for %s without guessing", (name, icon) => expect(toolActivityIcon(tool(name))).toBe(icon));
|
|
@@ -3,10 +3,11 @@ import type { AgentWidgetConfig, AgentWidgetToolCall } from "../types";
|
|
|
3
3
|
// Exact documented names only. Ambiguous names such as search_events or
|
|
4
4
|
// search_nodes need provider metadata, which tool messages do not carry.
|
|
5
5
|
const categories = [
|
|
6
|
+
["search_docs", "Searching docs", "Searched docs", "search"],
|
|
6
7
|
["web_search|web_search_preview|WebSearch", "Searching the web", "Searched the web", "globe"],
|
|
7
8
|
["web_fetch|WebFetch", "Reading web pages", "Read web pages", "globe", "single"],
|
|
8
9
|
["file_search|search_files|Glob", "Searching files", "Searched files", "search"],
|
|
9
|
-
["read_text_file|read_multiple_files|Read", "Reading files", "Read files", "file-text", "single"],
|
|
10
|
+
["read_file|read_text_file|read_multiple_files|Read", "Reading files", "Read files", "file-text", "single"],
|
|
10
11
|
["write_file|edit_file|apply_patch|Write|Edit|NotebookEdit", "Editing files", "Edited files", "pencil", "single"],
|
|
11
12
|
["list_directory|list_directory_with_sizes|directory_tree", "Browsing files", "Browsed files", "folder"],
|
|
12
13
|
["Grep", "Searching code", "Searched code", "search"],
|
package/dist/chunk-DDAwu89-.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e=`4.32.0`;export{e as t};
|