@runtypelabs/persona 4.21.0 → 4.22.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/{approval-ui-RNNBR5R3.js → approval-ui-K7R5Q5OC.js} +1 -1
- package/dist/approval-ui.cjs +2 -2
- package/dist/approval-ui.d.cts +73 -2
- package/dist/approval-ui.d.ts +73 -2
- package/dist/approval-ui.js +2 -2
- package/dist/artifacts-ui-F4N6VMKF.js +7 -0
- package/dist/artifacts-ui.cjs +1 -1
- package/dist/artifacts-ui.d.cts +73 -2
- package/dist/artifacts-ui.d.ts +73 -2
- package/dist/artifacts-ui.js +1 -1
- package/dist/chunk-NQLDCJAP.js +4 -0
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/context-mentions.d.cts +73 -2
- package/dist/context-mentions.d.ts +73 -2
- package/dist/event-stream-view-FKWDY3UB.js +1 -0
- package/dist/event-stream-view.cjs +1 -1
- package/dist/event-stream-view.d.cts +73 -2
- package/dist/event-stream-view.d.ts +73 -2
- package/dist/event-stream-view.js +1 -1
- package/dist/forms-ui.d.cts +73 -2
- package/dist/forms-ui.d.ts +73 -2
- package/dist/index.cjs +66 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +136 -5
- package/dist/index.d.ts +136 -5
- package/dist/index.global.js +50 -50
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +67 -67
- package/dist/index.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 +73 -2
- package/dist/session-reconnect.d.ts +73 -2
- package/dist/smart-dom-reader.d.cts +73 -2
- package/dist/smart-dom-reader.d.ts +73 -2
- package/dist/theme-editor-preview.cjs +65 -65
- package/dist/theme-editor-preview.d.cts +73 -2
- package/dist/theme-editor-preview.d.ts +73 -2
- package/dist/theme-editor-preview.js +49 -49
- package/dist/theme-editor.cjs +4 -4
- package/dist/theme-editor.d.cts +73 -2
- package/dist/theme-editor.d.ts +73 -2
- package/dist/theme-editor.js +2 -2
- package/dist/theme-reference.cjs +1 -1
- package/dist/theme-reference.d.cts +65 -1
- package/dist/theme-reference.d.ts +65 -1
- package/dist/theme-reference.js +1 -1
- package/dist/webmcp-polyfill.js +1 -4
- package/dist/webmcp-runtime-JI7T4QYF.js +6 -0
- package/dist/webmcp-runtime.cjs +2 -2
- package/dist/webmcp-runtime.d.cts +34 -2
- package/dist/webmcp-runtime.d.ts +34 -2
- package/dist/webmcp-runtime.js +2 -2
- package/package.json +2 -2
- package/src/client-visitor-history.test.ts +131 -0
- package/src/components/artifact-preview.ts +5 -0
- package/src/components/event-stream-badge-theming.test.ts +159 -0
- package/src/components/event-stream-view.ts +50 -20
- package/src/generated/runtype-openapi-contract.ts +8 -0
- package/src/index-core.ts +2 -0
- package/src/runtime/init.registry.test.ts +56 -0
- package/src/runtime/init.ts +17 -0
- package/src/types/theme.ts +41 -1
- package/src/types.ts +38 -1
- package/src/ui.reasoning-display.test.ts +136 -2
- package/src/ui.ts +69 -21
- package/src/utils/__snapshots__/tokens-parity.test.ts.snap +1740 -0
- package/src/utils/formatting.ts +22 -0
- package/src/utils/theme.ts +16 -0
- package/src/utils/tokens.ts +59 -0
- package/src/webmcp-bridge.test.ts +132 -23
- package/src/webmcp-bridge.ts +26 -2
- package/src/webmcp-runtime-entry.ts +71 -11
- package/dist/artifacts-ui-J6AKUGTS.js +0 -7
- package/dist/chunk-HBE7LFNT.js +0 -4
- package/dist/event-stream-view-73NWKWVQ.js +0 -1
- package/dist/webmcp-runtime-P3CHZRHF.js +0 -6
package/src/utils/formatting.ts
CHANGED
|
@@ -52,6 +52,28 @@ export const describeReasonStatus = (reasoning: AgentWidgetReasoning) => {
|
|
|
52
52
|
return "";
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
/** Defaults for `features.reasoningDisplay.shortThinkThreshold`. */
|
|
56
|
+
export const DEFAULT_SHORT_THINK_DURATION_MS = 15_000;
|
|
57
|
+
export const DEFAULT_SHORT_THINK_CHARS = 1_200;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A completed reasoning trace is short when its duration is under the
|
|
61
|
+
* threshold, or (with no reported duration) its streamed text is under the
|
|
62
|
+
* character threshold. Duration is preferred when available.
|
|
63
|
+
*/
|
|
64
|
+
export const isShortReasoning = (
|
|
65
|
+
reasoning: AgentWidgetReasoning,
|
|
66
|
+
threshold?: { durationMs?: number; chars?: number }
|
|
67
|
+
): boolean => {
|
|
68
|
+
const durationThreshold = threshold?.durationMs ?? DEFAULT_SHORT_THINK_DURATION_MS;
|
|
69
|
+
const charsThreshold = threshold?.chars ?? DEFAULT_SHORT_THINK_CHARS;
|
|
70
|
+
if (typeof reasoning.durationMs === "number") {
|
|
71
|
+
return reasoning.durationMs < durationThreshold;
|
|
72
|
+
}
|
|
73
|
+
const chars = (reasoning.chunks ?? []).join("").length;
|
|
74
|
+
return chars < charsThreshold;
|
|
75
|
+
};
|
|
76
|
+
|
|
55
77
|
export const formatToolDuration = (tool: AgentWidgetToolCall) => {
|
|
56
78
|
const durationMs =
|
|
57
79
|
typeof tool.duration === "number"
|
package/src/utils/theme.ts
CHANGED
|
@@ -128,6 +128,22 @@ const DARK_COMPONENTS: DeepPartial<PersonaTheme> = {
|
|
|
128
128
|
foreground: 'palette.colors.primary.300',
|
|
129
129
|
},
|
|
130
130
|
},
|
|
131
|
+
// Event-stream badge chips flip to a 900-tone fill with a 300-tone text
|
|
132
|
+
// (primary is the inverted dark ramp, so 800/200 lands the same way).
|
|
133
|
+
// The light defaults are 100-tone fills that read as glowing swatches on
|
|
134
|
+
// a dark panel; every pair here keeps >=4.5:1 text contrast (locked by
|
|
135
|
+
// event-stream-badge-theming.test.ts).
|
|
136
|
+
eventStream: {
|
|
137
|
+
badge: {
|
|
138
|
+
flow: { background: 'palette.colors.success.900', foreground: 'palette.colors.success.300' },
|
|
139
|
+
step: { background: 'palette.colors.primary.800', foreground: 'palette.colors.primary.200' },
|
|
140
|
+
reasoning: { background: 'palette.colors.warning.900', foreground: 'palette.colors.warning.300' },
|
|
141
|
+
tool: { background: 'palette.colors.purple.900', foreground: 'palette.colors.purple.300' },
|
|
142
|
+
agent: { background: 'palette.colors.teal.900', foreground: 'palette.colors.teal.300' },
|
|
143
|
+
error: { background: 'palette.colors.error.900', foreground: 'palette.colors.error.300' },
|
|
144
|
+
default: { background: 'palette.colors.gray.800', foreground: 'palette.colors.gray.300' },
|
|
145
|
+
},
|
|
146
|
+
},
|
|
131
147
|
history: {
|
|
132
148
|
// error-400: the light-surface error-600 red lands ~3:1 on dark
|
|
133
149
|
// surfaces, under the 4.5:1 AA floor for the 14px destructive labels.
|
package/src/utils/tokens.ts
CHANGED
|
@@ -128,6 +128,32 @@ export const DEFAULT_PALETTE = {
|
|
|
128
128
|
900: '#1e3a8a',
|
|
129
129
|
950: '#172554',
|
|
130
130
|
},
|
|
131
|
+
purple: {
|
|
132
|
+
50: '#faf5ff',
|
|
133
|
+
100: '#f3e8ff',
|
|
134
|
+
200: '#e9d5ff',
|
|
135
|
+
300: '#d8b4fe',
|
|
136
|
+
400: '#c084fc',
|
|
137
|
+
500: '#a855f7',
|
|
138
|
+
600: '#9333ea',
|
|
139
|
+
700: '#7e22ce',
|
|
140
|
+
800: '#6b21a8',
|
|
141
|
+
900: '#581c87',
|
|
142
|
+
950: '#3b0764',
|
|
143
|
+
},
|
|
144
|
+
teal: {
|
|
145
|
+
50: '#f0fdfa',
|
|
146
|
+
100: '#ccfbf1',
|
|
147
|
+
200: '#99f6e4',
|
|
148
|
+
300: '#5eead4',
|
|
149
|
+
400: '#2dd4bf',
|
|
150
|
+
500: '#14b8a6',
|
|
151
|
+
600: '#0d9488',
|
|
152
|
+
700: '#0f766e',
|
|
153
|
+
800: '#115e59',
|
|
154
|
+
900: '#134e4a',
|
|
155
|
+
950: '#042f2e',
|
|
156
|
+
},
|
|
131
157
|
},
|
|
132
158
|
spacing,
|
|
133
159
|
typography: {
|
|
@@ -472,6 +498,20 @@ export const DEFAULT_COMPONENTS: ComponentTokens = {
|
|
|
472
498
|
border: 'palette.colors.gray.200',
|
|
473
499
|
},
|
|
474
500
|
},
|
|
501
|
+
// Event-stream badge chips: 100-tone fill / dark text per family. tool/agent
|
|
502
|
+
// keep their pre-token literals (#6b21a8 / #115e59), which sit at the 800
|
|
503
|
+
// step of the canonical purple/teal ramps.
|
|
504
|
+
eventStream: {
|
|
505
|
+
badge: {
|
|
506
|
+
flow: { background: 'palette.colors.success.100', foreground: 'palette.colors.success.700' },
|
|
507
|
+
step: { background: 'palette.colors.primary.100', foreground: 'palette.colors.primary.700' },
|
|
508
|
+
reasoning: { background: 'palette.colors.warning.100', foreground: 'palette.colors.warning.700' },
|
|
509
|
+
tool: { background: 'palette.colors.purple.100', foreground: 'palette.colors.purple.800' },
|
|
510
|
+
agent: { background: 'palette.colors.teal.100', foreground: 'palette.colors.teal.800' },
|
|
511
|
+
error: { background: 'palette.colors.error.100', foreground: 'palette.colors.error.700' },
|
|
512
|
+
default: { background: 'palette.colors.gray.100', foreground: 'palette.colors.gray.600' },
|
|
513
|
+
},
|
|
514
|
+
},
|
|
475
515
|
scrollToBottom: {
|
|
476
516
|
background: 'components.button.primary.background',
|
|
477
517
|
foreground: 'components.button.primary.foreground',
|
|
@@ -1085,6 +1125,25 @@ export function themeToCssVariables(theme: PersonaTheme): Record<string, string>
|
|
|
1085
1125
|
['scroll-to-bottom-gap', 'components-scrollToBottom-gap', '=0.5rem'],
|
|
1086
1126
|
['scroll-to-bottom-font-size', 'components-scrollToBottom-fontSize', 'palette-typography-fontSize-sm', '=0.875rem'],
|
|
1087
1127
|
['scroll-to-bottom-icon-size', 'components-scrollToBottom-iconSize', '=14px'],
|
|
1128
|
+
// Event-stream badge chips. Materialized in every theme (light defaults in
|
|
1129
|
+
// DEFAULT_COMPONENTS, dark pairs in the built-in dark layer), so the
|
|
1130
|
+
// chip's inline var() refs always resolve inside a themed root and
|
|
1131
|
+
// re-resolve on scheme toggles; the literal terminals only cover unthemed
|
|
1132
|
+
// direct mounts.
|
|
1133
|
+
['event-badge-flow-bg', 'components-eventStream-badge-flow-background', '=#dcfce7'],
|
|
1134
|
+
['event-badge-flow-fg', 'components-eventStream-badge-flow-foreground', '=#15803d'],
|
|
1135
|
+
['event-badge-step-bg', 'components-eventStream-badge-step-background', '=#f5f5f5'],
|
|
1136
|
+
['event-badge-step-fg', 'components-eventStream-badge-step-foreground', '=#0a0a0a'],
|
|
1137
|
+
['event-badge-reasoning-bg', 'components-eventStream-badge-reasoning-background', '=#fef9c3'],
|
|
1138
|
+
['event-badge-reasoning-fg', 'components-eventStream-badge-reasoning-foreground', '=#a16207'],
|
|
1139
|
+
['event-badge-tool-bg', 'components-eventStream-badge-tool-background', '=#f3e8ff'],
|
|
1140
|
+
['event-badge-tool-fg', 'components-eventStream-badge-tool-foreground', '=#6b21a8'],
|
|
1141
|
+
['event-badge-agent-bg', 'components-eventStream-badge-agent-background', '=#ccfbf1'],
|
|
1142
|
+
['event-badge-agent-fg', 'components-eventStream-badge-agent-foreground', '=#115e59'],
|
|
1143
|
+
['event-badge-error-bg', 'components-eventStream-badge-error-background', '=#fee2e2'],
|
|
1144
|
+
['event-badge-error-fg', 'components-eventStream-badge-error-foreground', '=#b91c1c'],
|
|
1145
|
+
['event-badge-default-bg', 'components-eventStream-badge-default-background', '=#f3f4f6'],
|
|
1146
|
+
['event-badge-default-fg', 'components-eventStream-badge-default-foreground', '=#4b5563'],
|
|
1088
1147
|
['tool-bubble-shadow', 'components-toolBubble-shadow', '=0 5px 15px rgba(15, 23, 42, 0.08)'],
|
|
1089
1148
|
['reasoning-bubble-shadow', 'components-reasoningBubble-shadow', '=0 5px 15px rgba(15, 23, 42, 0.08)'],
|
|
1090
1149
|
['composer-shadow', 'components-composer-shadow', '=none'],
|
|
@@ -11,7 +11,8 @@ import type {
|
|
|
11
11
|
// calls `initializeWebMCPPolyfill()` (idempotent install of document.modelContext).
|
|
12
12
|
// We stub the install as a no-op and provide `document.modelContext` ourselves,
|
|
13
13
|
// modeling the strict producer-preview surface the bridge consumes:
|
|
14
|
-
// - getTools(): async; inputSchema
|
|
14
|
+
// - getTools(): async; inputSchema in either generation (see
|
|
15
|
+
// `registry.schemaShape`); annotations only when the tool declared them
|
|
15
16
|
// - executeTool(info, argsJson, { signal }): async; validates+runs execute(),
|
|
16
17
|
// returns JSON.stringify(rawResult) or null; honors the abort signal.
|
|
17
18
|
// ---------------------------------------------------------------------------
|
|
@@ -45,21 +46,46 @@ type MockTool = {
|
|
|
45
46
|
description?: string;
|
|
46
47
|
inputSchema?: object;
|
|
47
48
|
title?: string;
|
|
49
|
+
annotations?: Record<string, unknown>;
|
|
48
50
|
execute: (args: Record<string, unknown>, client: MockClient) => unknown;
|
|
49
51
|
};
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Which generation of the WebMCP `inputSchema` contract the fake emits.
|
|
55
|
+
*
|
|
56
|
+
* `"object"` is what `@mcp-b/webmcp-polyfill` v5 and Chrome 154+ return after
|
|
57
|
+
* `webmcp#241`; `"string"` is the serialized form Chrome 149-153 and 154's
|
|
58
|
+
* same-document tools still emit. Both are live in the field, so the snapshot
|
|
59
|
+
* tests run against both -- pinning this fake to one generation is exactly how
|
|
60
|
+
* the v5 bump landed green while every real dispatch 400'd.
|
|
61
|
+
*/
|
|
62
|
+
type SchemaShape = "object" | "string";
|
|
63
|
+
|
|
64
|
+
const registry: { tools: MockTool[]; schemaShape: SchemaShape } = {
|
|
65
|
+
tools: [],
|
|
66
|
+
schemaShape: "object",
|
|
67
|
+
};
|
|
52
68
|
|
|
53
69
|
/** A fake `document.modelContext` exposing the strict consumer surface. */
|
|
54
70
|
const makeModelContext = () => ({
|
|
55
71
|
async getTools() {
|
|
56
|
-
// Mirrors the real polyfill's
|
|
57
|
-
//
|
|
72
|
+
// Mirrors the real polyfill's getTools(): `title` is always present, ""
|
|
73
|
+
// when the tool didn't declare one; annotations are absent. v5 OMITS
|
|
74
|
+
// `inputSchema` for a tool that registered none, where v4 always emitted a
|
|
75
|
+
// `{"type":"object"}` string.
|
|
58
76
|
return registry.tools.map((t) => ({
|
|
59
77
|
name: t.name,
|
|
60
78
|
description: t.description ?? `mock ${t.name}`,
|
|
61
|
-
|
|
79
|
+
...(t.inputSchema === undefined
|
|
80
|
+
? {}
|
|
81
|
+
: {
|
|
82
|
+
inputSchema:
|
|
83
|
+
registry.schemaShape === "object"
|
|
84
|
+
? t.inputSchema
|
|
85
|
+
: JSON.stringify(t.inputSchema),
|
|
86
|
+
}),
|
|
62
87
|
title: t.title ?? "",
|
|
88
|
+
...(t.annotations === undefined ? {} : { annotations: t.annotations }),
|
|
63
89
|
}));
|
|
64
90
|
},
|
|
65
91
|
async executeTool(
|
|
@@ -110,6 +136,7 @@ beforeEach(() => {
|
|
|
110
136
|
vi.clearAllMocks();
|
|
111
137
|
polyfillMock.initThrows = false;
|
|
112
138
|
registry.tools = [];
|
|
139
|
+
registry.schemaShape = "object";
|
|
113
140
|
// location is read by snapshotForDispatch; document.modelContext is the
|
|
114
141
|
// consumer surface. Both are absent in the Node test environment.
|
|
115
142
|
vi.stubGlobal("location", { origin: "https://example.test" });
|
|
@@ -166,29 +193,111 @@ describe("WebMcpBridge.snapshotForDispatch", () => {
|
|
|
166
193
|
expect(bridge.isOperational()).toBe(false);
|
|
167
194
|
});
|
|
168
195
|
|
|
169
|
-
|
|
196
|
+
// Both `inputSchema` generations must produce the same wire tool: the object
|
|
197
|
+
// form (webmcp#241 / polyfill v5 / Chrome 154+) and the serialized string
|
|
198
|
+
// Chrome 149-153 still emits.
|
|
199
|
+
it.each(["object", "string"] as const)(
|
|
200
|
+
"ships only the JSON-serializable surface (name, description, schema, origin) [%s inputSchema]",
|
|
201
|
+
async (schemaShape) => {
|
|
202
|
+
registry.schemaShape = schemaShape;
|
|
203
|
+
registry.tools = [
|
|
204
|
+
fakeTool({
|
|
205
|
+
name: "search",
|
|
206
|
+
description: "search the shop",
|
|
207
|
+
inputSchema: { type: "object", properties: { q: { type: "string" } } },
|
|
208
|
+
}),
|
|
209
|
+
];
|
|
210
|
+
const bridge = new WebMcpBridge({ enabled: true });
|
|
211
|
+
const snap = await bridge.snapshotForDispatch();
|
|
212
|
+
expect(snap).toHaveLength(1);
|
|
213
|
+
const tool = snap[0]!;
|
|
214
|
+
expect(tool.name).toBe("search");
|
|
215
|
+
expect(tool.description).toBe("search the shop");
|
|
216
|
+
expect(tool.parametersSchema).toEqual({
|
|
217
|
+
type: "object",
|
|
218
|
+
properties: { q: { type: "string" } },
|
|
219
|
+
});
|
|
220
|
+
expect(tool.origin).toBe("webmcp");
|
|
221
|
+
expect(tool.pageOrigin).toBe("https://example.test");
|
|
222
|
+
expect((tool as unknown as { execute?: unknown }).execute).toBeUndefined();
|
|
223
|
+
// Now that the registry was read, the bridge reports operational.
|
|
224
|
+
expect(bridge.isOperational()).toBe(true);
|
|
225
|
+
},
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
// `parametersSchema` is required by the server's InlineClientToolSchema, and
|
|
229
|
+
// one entry missing it fails the whole DispatchRequestSchema union: a tool
|
|
230
|
+
// with no usable schema must degrade to "takes no arguments", never to an
|
|
231
|
+
// omitted key that 400s the turn.
|
|
232
|
+
it("always sends a parametersSchema, even when the tool declared none", async () => {
|
|
233
|
+
registry.tools = [fakeTool({ name: "ping" })];
|
|
234
|
+
const snap = await new WebMcpBridge({ enabled: true }).snapshotForDispatch();
|
|
235
|
+
expect(snap[0]!.parametersSchema).toEqual({ type: "object", properties: {} });
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("forwards annotations and hoists untrustedContentHint to the top level", async () => {
|
|
170
239
|
registry.tools = [
|
|
171
240
|
fakeTool({
|
|
172
|
-
name: "
|
|
173
|
-
|
|
174
|
-
inputSchema: { type: "object", properties: { q: { type: "string" } } },
|
|
241
|
+
name: "get_reviews",
|
|
242
|
+
annotations: { readOnlyHint: true, untrustedContentHint: true },
|
|
175
243
|
}),
|
|
176
244
|
];
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
expect(tool.name).toBe("search");
|
|
182
|
-
expect(tool.description).toBe("search the shop");
|
|
183
|
-
expect(tool.parametersSchema).toEqual({
|
|
184
|
-
type: "object",
|
|
185
|
-
properties: { q: { type: "string" } },
|
|
245
|
+
const snap = await new WebMcpBridge({ enabled: true }).snapshotForDispatch();
|
|
246
|
+
expect(snap[0]!.annotations).toEqual({
|
|
247
|
+
readOnlyHint: true,
|
|
248
|
+
untrustedContentHint: true,
|
|
186
249
|
});
|
|
187
|
-
|
|
188
|
-
expect(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
250
|
+
// The server acts on the top-level field, not the nested metadata copy.
|
|
251
|
+
expect(snap[0]!.untrustedContentHint).toBe(true);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("omits annotations and the top-level hint when the tool declared none", async () => {
|
|
255
|
+
registry.tools = [fakeTool({ name: "search" })];
|
|
256
|
+
const snap = await new WebMcpBridge({ enabled: true }).snapshotForDispatch();
|
|
257
|
+
expect(snap[0]!).not.toHaveProperty("annotations");
|
|
258
|
+
expect(snap[0]!).not.toHaveProperty("untrustedContentHint");
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("does not hoist untrustedContentHint: false, and drops unknown annotation keys", async () => {
|
|
262
|
+
registry.tools = [
|
|
263
|
+
fakeTool({
|
|
264
|
+
name: "add_to_cart",
|
|
265
|
+
annotations: {
|
|
266
|
+
readOnlyHint: false,
|
|
267
|
+
untrustedContentHint: false,
|
|
268
|
+
destructiveHint: true, // MCP-only today; not in the WebMCP dict
|
|
269
|
+
evil: () => "not JSON",
|
|
270
|
+
},
|
|
271
|
+
}),
|
|
272
|
+
];
|
|
273
|
+
const snap = await new WebMcpBridge({ enabled: true }).snapshotForDispatch();
|
|
274
|
+
expect(snap[0]!.annotations).toEqual({
|
|
275
|
+
readOnlyHint: false,
|
|
276
|
+
untrustedContentHint: false,
|
|
277
|
+
});
|
|
278
|
+
expect(snap[0]!).not.toHaveProperty("untrustedContentHint");
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it.each([
|
|
282
|
+
["unparseable string", "{not json"],
|
|
283
|
+
["non-object JSON string", '"just a string"'],
|
|
284
|
+
["JSON array string", "[1,2,3]"],
|
|
285
|
+
["array object", [1, 2, 3]],
|
|
286
|
+
["null", null],
|
|
287
|
+
])("falls back to an empty schema for %s", async (_label, inputSchema) => {
|
|
288
|
+
registry.tools = [fakeTool({ name: "odd" })];
|
|
289
|
+
// Bypass the fake's shape switch: these are malformed values a page or a
|
|
290
|
+
// future runtime could hand us, not either sanctioned generation.
|
|
291
|
+
vi.stubGlobal("document", {
|
|
292
|
+
modelContext: {
|
|
293
|
+
...makeModelContext(),
|
|
294
|
+
async getTools() {
|
|
295
|
+
return [{ name: "odd", description: "odd", inputSchema, title: "" }];
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
const snap = await new WebMcpBridge({ enabled: true }).snapshotForDispatch();
|
|
300
|
+
expect(snap[0]!.parametersSchema).toEqual({ type: "object", properties: {} });
|
|
192
301
|
});
|
|
193
302
|
|
|
194
303
|
it("applies client-side allowlist glob (`search_*`)", async () => {
|
package/src/webmcp-bridge.ts
CHANGED
|
@@ -49,8 +49,22 @@ export const WEBMCP_TOOL_PREFIX = "webmcp:";
|
|
|
49
49
|
export interface ModelContextToolInfo {
|
|
50
50
|
name: string;
|
|
51
51
|
description: string;
|
|
52
|
-
/**
|
|
53
|
-
|
|
52
|
+
/**
|
|
53
|
+
* JSON Schema for the tool's input, in EITHER generation of the WebMCP
|
|
54
|
+
* contract. Never read it raw: `normalizeInputSchema` in
|
|
55
|
+
* `webmcp-runtime-entry.ts` collapses both shapes to the object the wire
|
|
56
|
+
* needs.
|
|
57
|
+
*
|
|
58
|
+
* `webmcp#241` changed this from a JSON-encoded string to a JSON Schema
|
|
59
|
+
* object. `@mcp-b/webmcp-polyfill` made the switch in v5, and Chrome ships it
|
|
60
|
+
* from 154.0.8013 (cross-document tools first) -- but Chrome 149-153, most of
|
|
61
|
+
* the Origin Trial population, and 154's same-document tools still emit the
|
|
62
|
+
* string. Both are live in the field, so we accept both.
|
|
63
|
+
*
|
|
64
|
+
* Absent when the tool registered no schema: v5 omits the member, where v4
|
|
65
|
+
* always emitted a `{"type":"object"}` string.
|
|
66
|
+
*/
|
|
67
|
+
inputSchema?: object | string;
|
|
54
68
|
/**
|
|
55
69
|
* Display title declared on the tool (`ToolDescriptor.title` in the WebMCP
|
|
56
70
|
* spec). The polyfill returns `""` when the tool didn't declare one. Note:
|
|
@@ -59,6 +73,16 @@ export interface ModelContextToolInfo {
|
|
|
59
73
|
* channel available to us.
|
|
60
74
|
*/
|
|
61
75
|
title?: string;
|
|
76
|
+
/**
|
|
77
|
+
* WebMCP `Tool.annotations`. Returned by `getTools()` since
|
|
78
|
+
* `@mcp-b/webmcp-polyfill` v5 (and by Chrome's native implementation);
|
|
79
|
+
* absent on v4 and whenever the tool declared none -- the spec omits the
|
|
80
|
+
* member rather than emitting an empty object.
|
|
81
|
+
*/
|
|
82
|
+
annotations?: {
|
|
83
|
+
readOnlyHint?: boolean;
|
|
84
|
+
untrustedContentHint?: boolean;
|
|
85
|
+
};
|
|
62
86
|
}
|
|
63
87
|
|
|
64
88
|
export interface ModelContextCoreLike {
|
|
@@ -131,14 +131,21 @@ export class WebMcpBridge {
|
|
|
131
131
|
return infos
|
|
132
132
|
.filter((info) => this.passesClientAllowlist(info.name))
|
|
133
133
|
.map<ClientToolDefinition>((info) => {
|
|
134
|
+
const annotations = pickAnnotations(info.annotations);
|
|
134
135
|
const def: ClientToolDefinition = {
|
|
135
136
|
name: info.name,
|
|
136
137
|
description: info.description,
|
|
138
|
+
parametersSchema: normalizeInputSchema(info.inputSchema),
|
|
137
139
|
origin: "webmcp",
|
|
138
140
|
...(pageOrigin ? { pageOrigin } : {}),
|
|
141
|
+
...(annotations ? { annotations } : {}),
|
|
142
|
+
// Hoisted because the server acts on the TOP-LEVEL field
|
|
143
|
+
// (`InlineClientToolSchema.untrustedContentHint` gates output
|
|
144
|
+
// spotlighting); the nested `annotations` object is metadata only.
|
|
145
|
+
...(annotations?.untrustedContentHint === true
|
|
146
|
+
? { untrustedContentHint: true }
|
|
147
|
+
: {}),
|
|
139
148
|
};
|
|
140
|
-
const schema = parseSchema(info.inputSchema);
|
|
141
|
-
if (schema) def.parametersSchema = schema;
|
|
142
149
|
return def;
|
|
143
150
|
});
|
|
144
151
|
}
|
|
@@ -404,19 +411,72 @@ const matchesGlob = (name: string, pattern: string): boolean => {
|
|
|
404
411
|
};
|
|
405
412
|
|
|
406
413
|
/**
|
|
407
|
-
*
|
|
408
|
-
* `parametersSchema`. Returns `undefined` for a missing or unparseable schema
|
|
409
|
-
* (the server can still accept a tool with no declared parameters).
|
|
414
|
+
* A tool that declared no usable schema. Sent rather than omitted: see below.
|
|
410
415
|
*/
|
|
411
|
-
const
|
|
412
|
-
|
|
416
|
+
const EMPTY_INPUT_SCHEMA = { type: "object", properties: {} } as const;
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* `getTools()`'s `inputSchema`, in either generation, as the JSON Schema object
|
|
420
|
+
* `dispatch.clientTools[].parametersSchema` carries.
|
|
421
|
+
*
|
|
422
|
+
* TWO shapes are live in the field. `webmcp#241` replaced the serialized JSON
|
|
423
|
+
* string with a JSON Schema object; `@mcp-b/webmcp-polyfill` adopted that in v5
|
|
424
|
+
* and Chrome ships it from 154.0.8013 (cross-document tools first), while
|
|
425
|
+
* Chrome 149-153 -- most of the Origin Trial population -- and 154's
|
|
426
|
+
* same-document tools still emit the string. So: branch on `typeof`, and guard
|
|
427
|
+
* the parse of the string arm. Assuming one shape is a silent failure here and
|
|
428
|
+
* a loud one at dispatch, which is how the object generation shipped past us
|
|
429
|
+
* (`JSON.parse(object)` throws, every schema was dropped, every turn 400'd).
|
|
430
|
+
*
|
|
431
|
+
* ALWAYS returns an object. `parametersSchema` is required by the server's
|
|
432
|
+
* `InlineClientToolSchema`, and one entry missing it fails the whole top-level
|
|
433
|
+
* `DispatchRequestSchema` union -- 400-ing the entire turn rather than dropping
|
|
434
|
+
* the one tool, with an `INVALID_UNION` at path `""` that names nothing. A tool
|
|
435
|
+
* with no schema, or an unparseable one, degrades to "takes no arguments"
|
|
436
|
+
* instead of taking the conversation down with it.
|
|
437
|
+
*/
|
|
438
|
+
/**
|
|
439
|
+
* Copy the WebMCP annotation hints onto the wire, dropping anything else.
|
|
440
|
+
*
|
|
441
|
+
* `getTools()` returns `annotations` since `@mcp-b/webmcp-polyfill` v5 (absent
|
|
442
|
+
* on v4 and when the tool declared none). Only the spec's two boolean hints are
|
|
443
|
+
* forwarded -- annotations are page-authored, so an explicit copy keeps
|
|
444
|
+
* functions/junk off the dispatch payload. Returns `undefined` when nothing
|
|
445
|
+
* usable remains so the member is omitted, matching the spec's own
|
|
446
|
+
* omit-when-empty behavior.
|
|
447
|
+
*/
|
|
448
|
+
const pickAnnotations = (
|
|
449
|
+
raw: ModelContextToolInfo["annotations"],
|
|
450
|
+
): ClientToolDefinition["annotations"] | undefined => {
|
|
451
|
+
if (!raw || typeof raw !== "object") return undefined;
|
|
452
|
+
const picked = {
|
|
453
|
+
...(typeof raw.readOnlyHint === "boolean"
|
|
454
|
+
? { readOnlyHint: raw.readOnlyHint }
|
|
455
|
+
: {}),
|
|
456
|
+
...(typeof raw.untrustedContentHint === "boolean"
|
|
457
|
+
? { untrustedContentHint: raw.untrustedContentHint }
|
|
458
|
+
: {}),
|
|
459
|
+
};
|
|
460
|
+
return Object.keys(picked).length > 0 ? picked : undefined;
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const normalizeInputSchema = (raw: object | string | undefined): object => {
|
|
464
|
+
if (raw === undefined || raw === "") return { ...EMPTY_INPUT_SCHEMA };
|
|
465
|
+
|
|
466
|
+
// Object generation (webmcp#241): pass through as-is. Arrays are `typeof
|
|
467
|
+
// "object"` but are not JSON Schema objects, so they fall through.
|
|
468
|
+
if (typeof raw === "object") {
|
|
469
|
+
return raw !== null && !Array.isArray(raw) ? raw : { ...EMPTY_INPUT_SCHEMA };
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// String generation: guarded parse.
|
|
413
473
|
try {
|
|
414
|
-
const parsed = JSON.parse(raw);
|
|
415
|
-
return parsed !== null && typeof parsed === "object"
|
|
474
|
+
const parsed: unknown = JSON.parse(raw);
|
|
475
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)
|
|
416
476
|
? (parsed as object)
|
|
417
|
-
:
|
|
477
|
+
: { ...EMPTY_INPUT_SCHEMA };
|
|
418
478
|
} catch {
|
|
419
|
-
return
|
|
479
|
+
return { ...EMPTY_INPUT_SCHEMA };
|
|
420
480
|
}
|
|
421
481
|
};
|
|
422
482
|
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import{c as Qe,d as et,e as tt,f as nt,g as ot,h as rt,i as st,q as V,r as ge,s as Te,t as lt,v as ct,w as dt}from"./chunk-NIKYKSNZ.js";import{a as ye}from"./chunk-7NQ4ZTHF.js";import{a as m,b as at,d as it}from"./chunk-76IELU7F.js";function oe(e){let t=String(e).split(/[\\/]/);return t[t.length-1]??""}function ft(e){let t=oe(e),n=t.lastIndexOf(".");return n<=0?"":t.slice(n+1).toLowerCase()}function ke(e){if(typeof e!="string")return"";let t=e.indexOf(`
|
|
2
|
-
`);if(t===-1||!e.slice(0,t).startsWith("```"))return e;let r=e.slice(t+1),o=r.lastIndexOf(`
|
|
3
|
-
`);return(o===-1?r:r.slice(0,o)).split("`\u200B``").join("```")}function fe(e){let t=ft(e.path);if(t)return t==="html"||t==="htm"?"html":t==="svg"?"svg":t==="md"||t==="mdx"?"markdown":"other";let n=(e.mimeType||"").toLowerCase();return n.includes("html")?"html":n.includes("svg")?"svg":n.includes("markdown")?"markdown":"other"}function ce(e){switch(fe(e)){case"html":return"HTML";case"svg":return"SVG";case"markdown":return"Markdown";default:{let t=ft(e.path);return t?t.toUpperCase():"File"}}}function Se(e){let t=e.markdown??"";return e.file?{filename:oe(e.file.path)||"artifact",mime:e.file.mimeType||"application/octet-stream",content:ke(t)}:{filename:`${e.title||"artifact"}.md`,mime:"text/markdown",content:t}}function Ee(e){let t=new Blob([e.content],{type:e.mime}),n=URL.createObjectURL(t),r=document.createElement("a");r.href=n,r.download=e.filename,r.click(),URL.revokeObjectURL(n)}var Pe="persona-artifact-custom-action-btn";function be(e,t){let n=t?.documentChrome??!1,r;if(typeof e.icon=="function"){if(e.showLabel){let o="persona-label-btn persona-label-btn--sm "+Pe+(n?" persona-artifact-doc-copy-btn":"");r=m("button",o)}else{let o="persona-icon-btn "+Pe+(n?" persona-artifact-doc-icon-btn":"");r=m("button",o)}r.type="button",r.setAttribute("aria-label",e.label),r.title=e.label;try{let o=e.icon();o&&r.appendChild(o)}catch{}if(e.showLabel){let o=m("span");o.textContent=e.label,r.appendChild(o)}}else e.showLabel||!e.icon?r=ge({icon:e.icon,label:e.label,className:Pe+(n?" persona-artifact-doc-copy-btn":"")}):r=V({icon:e.icon,label:e.label,className:Pe+(n?" persona-artifact-doc-icon-btn":"")});return t?.onClick&&r.addEventListener("click",t.onClick),r}function ve(e){if(!e)return null;let t={artifactId:e.id,title:e.title??"",artifactType:e.artifactType};return e.artifactType==="markdown"?(t.markdown=e.markdown??"",e.file&&(t.file=e.file)):t.jsonPayload=JSON.stringify({component:e.component,props:e.props},null,2),t}var Ne="http://www.w3.org/2000/svg";function pt(e){let t=document.createElementNS(Ne,"svg");t.setAttribute("class",it("persona-spinner",e)),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("aria-hidden","true"),t.setAttribute("focusable","false");let n=document.createElementNS(Ne,"circle");n.setAttribute("class","persona-spinner-track"),n.setAttribute("cx","12"),n.setAttribute("cy","12"),n.setAttribute("r","9");let r=document.createElementNS(Ne,"circle");return r.setAttribute("class","persona-spinner-arc"),r.setAttribute("cx","12"),r.setAttribute("cy","12"),r.setAttribute("r","9"),t.appendChild(n),t.appendChild(r),t}function ut(e,t,n){let r=n?.loadingAnimation??"shimmer",o=n?.loadingAnimationDuration??2e3;if(r==="none"){e.textContent=t;return}if(r==="pulse"){e.setAttribute("data-preserve-animation","true"),e.classList.add("persona-tool-loading-pulse"),e.style.setProperty("--persona-tool-anim-duration",`${o}ms`),e.textContent=t;return}e.setAttribute("data-preserve-animation","true"),e.classList.add(`persona-tool-loading-${r}`),e.style.setProperty("--persona-tool-anim-duration",`${o}ms`),r==="shimmer-color"&&(n?.loadingAnimationColor&&e.style.setProperty("--persona-tool-anim-color",n.loadingAnimationColor),n?.loadingAnimationSecondaryColor&&e.style.setProperty("--persona-tool-anim-secondary-color",n.loadingAnimationSecondaryColor)),ct(e,t,0)}var Ve="persona-artifact-status-label",mt="persona-artifact-status-detail",yt="data-artifact-status-label",ze=new Map,gt=()=>typeof performance<"u"&&typeof performance.now=="function"?performance.now():Date.now();function he(e){e&&ze.delete(e)}function Ot(e){let t=e.artifactType==="markdown"?e.file:void 0;return t?ce(t):e.artifactType==="component"?"Component":"Document"}function we(e,t,n){let r=Ot(e),o=`Generating ${r.toLowerCase()}...`,s=t?.statusLabel;if(typeof s=="string")return{label:s};if(typeof s!="function")return{label:o};let i=e.id,l=ze.get(i);e.status!=="complete"&&l===void 0&&(l=gt(),ze.set(i,l));let A=l===void 0?0:Math.max(0,gt()-l),h=e.artifactType==="component",f=!h&&typeof e.markdown=="string"?e.markdown:"",p=h?0:f.length,u=h||f===""?0:f.split(`
|
|
4
|
-
`).length,c=e.artifactType==="markdown"?e.file:void 0,y={artifactId:i,artifactType:e.artifactType,title:e.title,typeLabel:r,file:c,chars:p,lines:u,elapsedMs:A,content:()=>h?"":f,surface:n};try{let g=s(y);return typeof g=="string"?{label:g}:g&&typeof g=="object"&&typeof g.label=="string"?{label:g.label,detail:typeof g.detail=="string"?g.detail:void 0}:{label:o}}catch{return{label:o}}}function Ft(e){e.className=Ve,e.removeAttribute("data-preserve-animation"),e.style.removeProperty("--persona-tool-anim-duration"),e.style.removeProperty("--persona-tool-anim-color"),e.style.removeProperty("--persona-tool-anim-secondary-color"),e.replaceChildren()}function pe(e,t,n){let r=e.querySelector(`:scope > .${Ve}`);r||(r=m("span",Ve),e.appendChild(r)),r.getAttribute(yt)!==t.label&&(Ft(r),ut(r,t.label,n),r.setAttribute(yt,t.label));let o=e.querySelector(`:scope > .${mt}`),s=t.detail;s?(o||(o=m("span",mt),e.appendChild(o)),o.textContent!==s&&(o.textContent=s)):o&&o.remove()}var _t={keyword:"persona-code-token-keyword",string:"persona-code-token-string",comment:"persona-code-token-comment",number:"persona-code-token-number",tag:"persona-code-token-tag",attr:"persona-code-token-attr",property:"persona-code-token-property"},Dt=15e4,Me={html:"html",htm:"html",xhtml:"html",xml:"html",svg:"html",css:"css",js:"js",jsx:"js",mjs:"js",cjs:"js",ts:"js",tsx:"js",mts:"js",cts:"js",javascript:"js",typescript:"js",ecmascript:"js",json:"json",jsonc:"json",json5:"json"};function jt(e,t){let n=(e||"").trim().toLowerCase();if(n&&Me[n])return Me[n];if(t){let r=t.lastIndexOf(".");if(r>=0){let o=t.slice(r+1).toLowerCase();if(Me[o])return Me[o]}}return null}function Re(e,t){let n=[],r=0,o=0,s=i=>{i>o&&n.push({type:"plain",value:e.slice(o,i)})};for(;r<e.length;){let i=!1;for(let l of t){l.re.lastIndex=r;let A=l.re.exec(e);if(A&&A.index===r&&A[0].length>0){s(r);let h=l.map?l.map(A[0]):l.type;n.push({type:h,value:A[0]}),r+=A[0].length,o=r,i=!0;break}}i||(r+=1)}return s(e.length),n}var Nt=new Set(["abstract","any","as","async","await","boolean","break","case","catch","class","const","continue","debugger","declare","default","delete","do","else","enum","export","extends","false","finally","for","from","function","get","if","implements","import","in","instanceof","interface","keyof","let","namespace","never","new","null","number","object","of","private","protected","public","readonly","return","satisfies","set","static","string","super","switch","symbol","this","throw","true","try","type","typeof","undefined","unknown","var","void","while","yield"]),Vt=[{type:"comment",re:/\/\/[^\n]*/y},{type:"comment",re:/\/\*[\s\S]*?\*\//y},{type:"string",re:/`(?:\\[\s\S]|[^\\`])*`/y},{type:"string",re:/"(?:\\.|[^"\\\n])*"/y},{type:"string",re:/'(?:\\.|[^'\\\n])*'/y},{type:"number",re:/0[xX][0-9a-fA-F]+|(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/y},{type:"plain",re:/[A-Za-z_$][\w$]*/y,map:e=>Nt.has(e)?"keyword":"plain"}];function bt(e){return Re(e,Vt)}var zt=[{type:"string",re:/"(?:\\.|[^"\\])*"/y},{type:"number",re:/-?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/y},{type:"plain",re:/[A-Za-z_]\w*/y,map:e=>e==="true"||e==="false"||e==="null"?"keyword":"plain"}];function Wt(e){let t=Re(e,zt);for(let n=0;n<t.length;n+=1){if(t[n].type!=="string")continue;let r=n+1;for(;r<t.length&&t[r].value.trim()==="";)r+=1;let o=t[r];o&&o.value.replace(/^\s*/,"").startsWith(":")&&(t[n].type="property")}return t}var Ut=[{type:"comment",re:/\/\*[\s\S]*?\*\//y},{type:"string",re:/"(?:\\.|[^"\\\n])*"/y},{type:"string",re:/'(?:\\.|[^'\\\n])*'/y},{type:"keyword",re:/@[A-Za-z-]+/y},{type:"number",re:/#[0-9a-fA-F]{3,8}\b/y},{type:"number",re:/-?(?:\d+\.?\d*|\.\d+)(?:[a-z%]+)?/y},{type:"plain",re:/[A-Za-z_-][\w-]*/y}];function ht(e){let t=Re(e,Ut),n="";for(let r=0;r<t.length;r+=1){let o=t[r];if(o.type==="plain"&&/^[A-Za-z_-][\w-]*$/.test(o.value)){let i=r+1;for(;i<t.length&&t[i].value.trim()==="";)i+=1;let l=t[i];l&&l.value.replace(/^\s*/,"").startsWith(":")&&(n===""||n==="{"||n==="}"||n===";"||n===",")&&(o.type="property")}let s=o.value.replace(/\s+$/,"");s&&(n=s[s.length-1])}return t}var $t=[{type:"tag",re:/<\/?\s*[A-Za-z][\w:-]*/y},{type:"string",re:/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/y},{type:"attr",re:/[A-Za-z_:@][\w:.-]*(?=\s*=)/y},{type:"attr",re:/[A-Za-z_:@][\w:.-]*/y},{type:"tag",re:/\/?>/y}];function qt(e){let t=[],n=(s,i)=>{i&&t.push({type:s,value:i})},r=e.length,o=0;for(;o<r;){if(e.startsWith("<!--",o)){let i=e.indexOf("-->",o+4),l=i===-1?r:i+3;n("comment",e.slice(o,l)),o=l;continue}if(e[o]==="<"&&e[o+1]==="!"){let i=e.indexOf(">",o),l=i===-1?r:i+1;n("tag",e.slice(o,l)),o=l;continue}if(e[o]==="<"&&/[A-Za-z/]/.test(e[o+1]||"")){let i=e.indexOf(">",o),l=i===-1?r:i+1,A=e.slice(o,l);for(let f of Re(A,$t))t.push(f);o=l;let h=/^<\s*(script|style)\b/i.exec(A);if(h&&!/\/>\s*$/.test(A)){let f=h[1].toLowerCase(),u=new RegExp("</\\s*"+f+"\\s*>","i").exec(e.slice(o)),c=u?o+u.index:r,y=e.slice(o,c),g=f==="script"?bt(y):ht(y);for(let S of g)t.push(S);o=c}continue}let s=e.indexOf("<",o);if(s===o)n("plain",e[o]),o+=1;else{let i=s===-1?r:s;n("plain",e.slice(o,i)),o=i}}return t}function Gt(e,t){switch(t){case"html":return qt(e);case"css":return ht(e);case"js":return bt(e);case"json":return Wt(e)}}function Kt(e){let t=at(),n=m("span","persona-code-line"),r=(o,s)=>{if(!s)return;let i=_t[o];if(i){let l=m("span",i);l.textContent=s,n.appendChild(l)}else n.appendChild(document.createTextNode(s))};for(let o of e){let s=o.value.split(`
|
|
5
|
-
`);for(let i=0;i<s.length;i+=1)i>0&&(t.appendChild(n),t.appendChild(document.createTextNode(`
|
|
6
|
-
`)),n=m("span","persona-code-line")),r(o.type,s[i])}return n.childNodes.length>0?t.appendChild(n):t.lastChild||t.appendChild(n),t}function wt(e,t,n){let r=e.length<=Dt?jt(t,n):null,o=r?Gt(e,r):[{type:"plain",value:e}];return Kt(o)}var At=null,vt=e=>{At=e.componentRegistry},Ct=()=>At;function He(e){if(!e)return"";if(e.artifactType==="markdown"){let t=e.markdown??"";return e.file?ke(t):t}return JSON.stringify({component:e.component,props:e.props},null,2)}var We=!1;function Zt(e){return"persona-artifact-vt-"+((e||"artifact").replace(/[^A-Za-z0-9_-]/g,"-").replace(/^-+/,"")||"artifact")}function xt(e,t,n,r){let o=typeof document<"u"?document.startViewTransition:void 0,s=!1;try{s=typeof window<"u"&&typeof window.matchMedia=="function"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}catch{s=!1}if(t!=="auto"||!e||typeof o!="function"||We||s){r();return}We=!0;let i=Zt(n);e.style.setProperty("view-transition-name",i);let l=()=>{We=!1,e.style.removeProperty("view-transition-name")};try{o.call(document,()=>{r()}).finished.then(l,l)}catch{l(),r()}}var Jt="persona-font-mono persona-text-xs persona-whitespace-pre-wrap persona-break-words persona-text-persona-primary",Xt="persona-text-sm persona-leading-relaxed persona-markdown-bubble";function Yt(e){let t=m("div","persona-rounded-lg persona-border persona-border-persona-border persona-p-3 persona-text-persona-primary"),n=m("div","persona-font-semibold persona-text-sm persona-mb-2");n.textContent=e.component?`Component: ${e.component}`:"Component";let r=m("pre","persona-font-mono persona-text-xs persona-whitespace-pre-wrap persona-overflow-x-auto");return r.textContent=JSON.stringify(e.props??{},null,2),t.appendChild(n),t.appendChild(r),t}function Qt(e){if(e===!1)return{enabled:!1,delayMs:0,minVisibleMs:0,timeoutMs:0,injectReadySignal:!1,label:"Starting preview...",labelDelayMs:2e3};let t=e&&typeof e=="object"?e:void 0;return{enabled:!0,delayMs:t?.delayMs??200,minVisibleMs:t?.minVisibleMs??300,timeoutMs:t?.timeoutMs??8e3,injectReadySignal:t?.injectReadySignal!==!1,label:t?.label===!1?!1:t?.label??"Starting preview...",labelDelayMs:t?.labelDelayMs??2e3,renderIndicator:t?.renderIndicator}}var en=220;function tn(){try{if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint32Array(2);return crypto.getRandomValues(e),e[0].toString(36)+e[1].toString(36)}}catch{}return Math.random().toString(36).slice(2)+Math.random().toString(36).slice(2)}function nn(e){return`
|
|
7
|
-
<script>(function(){var d=false;var t=`+JSON.stringify(e)+";function r(){if(d)return;d=true;try{parent.postMessage({persona:'artifact-preview-ready',token:t},'*');}catch(e){}}function s(){if(typeof requestAnimationFrame==='function'){requestAnimationFrame(function(){requestAnimationFrame(r);});}setTimeout(r,150);}if(document.readyState==='complete'){s();}else{window.addEventListener('load',s);}})();</script>"}function on(e,t,n){let r=m("div","persona-artifact-frame-loading");if(n.renderIndicator)try{let i=n.renderIndicator({artifactId:e,config:t});if(i)return r.appendChild(i),{el:r,revealLabel:()=>{}}}catch{}let o=m("div","persona-artifact-frame-loading-indicator");o.appendChild(pt());let s=null;return n.label!==!1&&(s=m("div","persona-artifact-frame-loading-text"),s.textContent=n.label,o.appendChild(s)),r.appendChild(o),{el:r,revealLabel:()=>{s&&s.classList.add("persona-artifact-frame-loading-text--visible")}}}function rn(e,t,n,r,o,s){let i=null,l=0,A=!1,h=new Set,f=()=>{h.forEach(x=>clearTimeout(x)),h.clear()},p=(x,P)=>{let $=setTimeout(()=>{h.delete($),x()},P);h.add($)},u=()=>{i&&i.parentElement&&i.remove(),i=null},c=()=>{if(i||A)return;let x=on(o,s,r);i=x.el,e.appendChild(i),l=Date.now(),r.label!==!1&&p(x.revealLabel,r.labelDelayMs)},y=()=>{i&&(i.classList.add("persona-artifact-frame-loading--out"),p(u,en))},g=()=>{n!==null?typeof window<"u"&&window.removeEventListener("message",I):t.removeEventListener("load",L)},S=()=>{if(A||(A=!0,g(),f(),!i))return;let x=Math.max(0,r.minVisibleMs-(Date.now()-l));x>0?p(y,x):y()};function I(x){if(n===null)return;let P=x.data;!P||P.persona!=="artifact-preview-ready"||P.token!==n||x.source===t.contentWindow&&S()}function L(){let x=P=>{typeof requestAnimationFrame=="function"?requestAnimationFrame(()=>P()):setTimeout(P,0)};x(()=>x(()=>S()))}return p(c,r.delayMs),p(S,r.timeoutMs),n!==null?typeof window<"u"&&window.addEventListener("message",I):t.addEventListener("load",L),()=>{A=!0,f(),g(),u()}}function Ie(e,t){let{config:n}=t,r=t.registry??Ct()??dt,o=t.bodyLayout,s=n.markdown?nt(n.markdown):null,i=rt(n.sanitize),l=e,A=!1,h=d=>{let M=tt()!==null;s&&!M&&!A&&(A=!0,Qe(()=>Z(l)));let O=s?s(d):ot(d);return s&&M&&i?i(O):O},f=m("div","persona-artifact-preview-body"),p=null,u=null,c=null,y=()=>{c&&(c(),c=null),p=null,u=null},g=null,S=null,I=null,L=!1,x=()=>{g=null,S=null,I=null,L=!1},P=null,$=null,J=()=>{P=null,$=null},re=40,Y=0,ie=d=>typeof requestAnimationFrame=="function"?requestAnimationFrame(()=>d()):setTimeout(d,0),_=d=>d.scrollHeight-d.clientHeight-d.scrollTop<=re,K=d=>{if(!o)return;let M=d.scrollHeight-d.clientHeight>1,O=d.scrollHeight-d.clientHeight-d.scrollTop;d.classList.toggle("persona-artifact-fade-top",o.fadeTop&&M&&d.scrollTop>1),d.classList.toggle("persona-artifact-fade-bottom",o.fadeBottom&&M&&O>1)},D=d=>{Y||(Y=ie(()=>{Y=0,d.scrollTop=d.scrollHeight,K(d)}))},z=(d,M,O,b)=>{let T=!!o,F=O.id+"|"+(T?"w":"p");if(!g||I!==F||g.parentElement!==f){y(),J(),f.replaceChildren();let w=m("pre",Jt+" persona-code-pre"),H=m("code","persona-code");if(w.appendChild(H),T){let j=m("div","persona-artifact-source-window");if(j.appendChild(w),f.appendChild(j),!(o?.overflow==="clip")&&typeof j.addEventListener=="function"){let X=()=>j.scrollHeight-j.clientHeight>1;j.addEventListener("scroll",()=>{_(j)&&(L=!1),K(j)},{passive:!0}),j.addEventListener("wheel",ee=>{X()&&ee.deltaY<0&&(L=!0)},{passive:!0}),j.addEventListener("touchmove",()=>{X()&&(L=!0)},{passive:!0})}g=j}else f.appendChild(w),g=w;S=H,I=F}let k=T?g:null;k&&(k.classList.toggle("persona-artifact-source-window--fixed",b),k.classList.toggle("persona-artifact-source-window--clip",b&&o?.overflow==="clip"));let R=k?_(k):!0;if(S.replaceChildren(wt(d,M?.language,M?.path)),k){let w=O.status!=="complete";b&&w&&o?.followOutput&&!L&&R?D(k):w||(L=!1),K(k)}},W=d=>{y(),x(),J(),f.replaceChildren();let M=m("div",Xt);M.innerHTML=h(d),f.appendChild(M)},Q=d=>{let M=d.id,O=n.features?.artifacts,b=we(d,O,"status-body");if(P&&$===M&&P.parentElement===f){let k=P.querySelector(".persona-artifact-status-view-text");k&&pe(k,b,O);return}y(),x(),f.replaceChildren();let T=m("div","persona-artifact-status-view"),F=m("div","persona-artifact-status-view-text");pe(F,b,O),T.appendChild(F),f.appendChild(T),P=T,$=M},Z=d=>{l=d;let M=t.resolveViewMode?.(d)??o?.viewMode??"rendered",O=d.artifactType==="markdown"?d.file:void 0,b=d.status!=="complete";b||he(d.id);let T=b?o?.streamingHeight:o?.completeHeight,F=!!o&&typeof T=="number";if(o?.streamingView==="status"&&b){Q(d);return}if(O){let R=ke(d.markdown??""),w=fe(O),H=n.features?.artifacts?.filePreview?.enabled!==!1;if(!b&&M==="rendered"&&H&&(w==="html"||w==="svg")){let ue=d.id+"\0"+R;if(p&&u===ue&&p.parentElement===f)return;x(),J(),y(),f.replaceChildren();let X=n.features?.artifacts?.filePreview,ee=X?.iframeSandbox??"allow-scripts";!X?.dangerouslyAllowSameOrigin&&ee.includes("allow-same-origin")&&(console.warn("[AgentWidget] Stripped allow-same-origin from filePreview.iframeSandbox: it lets artifact content run with the page origin. Set filePreview.dangerouslyAllowSameOrigin to keep it."),ee=ee.split(/\s+/).filter(B=>B&&B!=="allow-same-origin").join(" "));let me=Qt(X?.loading),U=m("div","persona-artifact-frame"),te=m("iframe","persona-artifact-iframe");te.setAttribute("sandbox",ee),te.setAttribute("data-artifact-id",d.id);let Ae=null;me.enabled&&me.injectReadySignal?(Ae=tn(),te.srcdoc=R+nn(Ae)):te.srcdoc=R,U.appendChild(te),f.appendChild(U),me.enabled&&(c=rn(U,te,Ae,me,d.id,n)),p=U,u=ue;return}if(y(),!b&&w==="markdown"&&M==="rendered"){W(R);return}z(R,{language:O.language,path:O.path},d,F);return}if(d.artifactType==="markdown"){if(M==="source"){y(),z(d.markdown??"",void 0,d,F);return}W(d.markdown??"");return}y(),x(),J(),f.replaceChildren();let k=d.component?r.get(d.component):void 0;if(k){let w={message:{id:d.id,role:"assistant",content:"",createdAt:new Date().toISOString()},config:n,updateProps:()=>{}};try{let H=k(d.props??{},w);if(H){f.appendChild(H);return}}catch{}}f.appendChild(Yt(d))};return Z(e),{el:f,update(d){Z(d)},destroy(){y()}}}import{Check as an,ChevronDown as sn,Maximize as ln,Minimize as cn}from"lucide";function Lt(e,t){let n=t.orientation??"horizontal",r=n==="vertical"?"ArrowUp":"ArrowLeft",o=n==="vertical"?"ArrowDown":"ArrowRight";e.setAttribute("role","tablist");let s=[],i=!1,l=p=>{typeof p.scrollIntoView=="function"&&p.scrollIntoView({block:"nearest",inline:"nearest"})},A=p=>{let u=p;return s.findIndex(c=>c===u||c.contains(u))},h=p=>{let u=A(p.target);if(u<0)return;let c=u;if(p.key===o)c=Math.min(u+1,s.length-1);else if(p.key===r)c=Math.max(u-1,0);else if(p.key==="Home")c=0;else if(p.key==="End")c=s.length-1;else return;p.preventDefault(),c!==u&&t.onSelect(c)},f=p=>{let u=A(p.target);u>=0&&l(s[u])};return e.addEventListener("keydown",h),e.addEventListener("focusin",f),{beforeRender(){i=typeof document<"u"&&e.contains(document.activeElement)},render(p,u){if(s=p,p.forEach((c,y)=>{c.setAttribute("role","tab");let g=y===u;c.setAttribute("aria-selected",g?"true":"false"),c.tabIndex=g||u<0&&y===0?0:-1}),i){let c=(u>=0?p[u]:void 0)??p[0];c&&typeof c.focus=="function"&&(l(c),c.focus())}},destroy(){e.removeEventListener("keydown",h),e.removeEventListener("focusin",f)}}}function Tt(e,t){let n=e.features?.artifacts?.layout,o=(n?.toolbarPreset??"default")==="document",s=n?.toolbarTitle??"Artifacts",i=n?.closeButtonLabel??"Close",l=n?.panePadding?.trim(),A=n?.tabFadeSize?.trim(),h=a=>({start:a===!1?!1:typeof a=="object"&&a?a.start!==!1:!0,end:a===!1?!1:typeof a=="object"&&a?a.end!==!1:!0}),{start:f,end:p}=h(n?.tabFade),u=typeof document<"u"?m("div","persona-artifact-backdrop persona-fixed persona-inset-0 persona-z-[55] persona-bg-black/30 persona-hidden md:persona-hidden"):null,c=()=>{u?.classList.add("persona-hidden"),y.classList.remove("persona-artifact-drawer-open"),K?.closeMenu()};u&&u.addEventListener("click",()=>{c(),t.onDismiss?.()});let y=m("aside","persona-artifact-pane persona-flex persona-flex-col persona-min-h-0 persona-min-w-0 persona-bg-persona-surface persona-text-persona-primary persona-border-l persona-border-persona-border");y.setAttribute("data-persona-theme-zone","artifact-pane"),o&&y.classList.add("persona-artifact-pane-document");let g=m("div","persona-artifact-toolbar persona-flex persona-items-center persona-justify-between persona-gap-2 persona-px-2 persona-py-2 persona-border-b persona-border-persona-border persona-shrink-0");g.setAttribute("data-persona-theme-zone","artifact-toolbar"),o&&g.classList.add("persona-artifact-toolbar-document");let S=m("span","persona-text-xs persona-font-medium persona-truncate");S.textContent=s;let I=V({icon:"x",label:i});I.addEventListener("click",()=>{c(),t.onDismiss?.()});let L="rendered",x=Te({items:[{id:"rendered",icon:"eye",label:"Rendered view",className:o?"persona-artifact-doc-icon-btn persona-artifact-view-btn":void 0},{id:"source",icon:"code-xml",label:"Source",className:o?"persona-artifact-doc-icon-btn persona-artifact-code-btn":void 0}],selectedId:"rendered",className:"persona-artifact-toggle-group persona-shrink-0",onSelect:a=>{L=a==="source"?"source":"rendered",Le()}}),P=m("div","persona-flex persona-items-center persona-gap-1 persona-shrink-0"),$=n?.documentToolbarShowCopyLabel===!0,J=n?.documentToolbarShowCopyChevron===!0,re=n?.documentToolbarCopyMenuItems,Y=!!(J&&re&&re.length>0),ie=null,_,K=null;if(o&&($||J)&&!Y){if(_=$?ge({icon:"copy",label:"Copy",iconSize:14,className:"persona-artifact-doc-copy-btn"}):V({icon:"copy",label:"Copy",className:"persona-artifact-doc-copy-btn"}),J){let a=ye(sn,14,"currentColor",2);a&&_.appendChild(a)}}else o&&Y?(K=lt({label:"Copy",icon:"copy",iconSize:14,iconOnly:!$,primaryClassName:"persona-artifact-doc-copy-btn",chevronLabel:"More copy options",chevronClassName:"persona-artifact-doc-copy-menu-chevron persona-artifact-doc-icon-btn",menuItems:(re??[]).map(a=>({id:a.id,label:a.label})),position:"bottom-right",portal:()=>y.closest("[data-persona-root]")??document.body,onSelect:a=>{k(a)}}),ie=K.element,_=K.primaryButton):o?_=V({icon:"copy",label:"Copy",className:"persona-artifact-doc-icon-btn"}):(_=V({icon:"copy",label:"Copy"}),n?.showCopyButton!==!0&&_.classList.add("persona-hidden"));let D=o?V({icon:"refresh-cw",label:"Refresh",className:"persona-artifact-doc-icon-btn"}):V({icon:"refresh-cw",label:"Refresh"});n?.onDocumentToolbarRefresh||D.classList.add("persona-hidden");let z=o?V({icon:"x",label:i,className:"persona-artifact-doc-icon-btn"}):V({icon:"x",label:i}),W=V({icon:"maximize",label:"Expand artifacts panel",className:"persona-artifact-expand-btn"+(o?" persona-artifact-doc-icon-btn":""),onClick:()=>t.onToggleExpand?.()});n?.showExpandToggle!==!0&&W.classList.add("persona-hidden");let Q=m("div","persona-flex persona-items-center persona-gap-1 persona-shrink-0 persona-artifact-toolbar-custom-actions"),Z=e.features?.artifacts?.toolbarActions??[],d=()=>{let a=B.find(ae=>ae.id===q)??B[B.length-1],C=a?.id??null,v=a?.artifactType==="markdown"?a.markdown??"":"",E=a?JSON.stringify({component:a.component,props:a.props},null,2):"",{filename:N,mime:G,content:se}=Se({title:a?.title,markdown:a?.markdown??"",file:a?.file});return{markdown:v,jsonPayload:E,id:C,file:a?.file,suggestedFilename:N,mime:G,content:se}},M=()=>{let{suggestedFilename:a,mime:C,content:v}=d();v&&Ee({filename:a,mime:C,content:v})},O=a=>{let{id:C,...v}=d();return{actionId:a,artifactId:C,...v}},b=async()=>{let a=B.find(C=>C.id===q)??B[B.length-1];try{return await navigator.clipboard.writeText(He(a)),!0}catch{return!1}},T=null,F=()=>{T?.();let a=_.querySelector("svg"),C=Number(a?.getAttribute("width"))||16,v=ye(an,C,"currentColor",2);if(!a||!v)return;a.replaceWith(v);let E=_.querySelector("span");E&&(E.textContent="Copied");let N=setTimeout(()=>T?.(),2e3);T=()=>{clearTimeout(N),v.replaceWith(a),E&&(E.textContent="Copy"),T=null}};_.addEventListener("click",async()=>{let a=n?.onDocumentToolbarCopyMenuSelect;if(a&&Y){try{if(await a(O("primary"))===!1){await b()&&F();return}F()}catch{}return}await b()&&F()});async function k(a){let C=n?.onDocumentToolbarCopyMenuSelect;try{if(C&&await C(O(a))!==!1)return;if(a==="download"){M();return}let{markdown:v,jsonPayload:E}=d();a==="markdown"||a==="md"?await navigator.clipboard.writeText(v):a==="json"||a==="source"?await navigator.clipboard.writeText(E):await navigator.clipboard.writeText(v||E),F()}catch{}}D.addEventListener("click",async()=>{try{await n?.onDocumentToolbarRefresh?.()}catch{}Le()}),z.addEventListener("click",()=>{c(),t.onDismiss?.()});let R=m("span","persona-min-w-0 persona-flex-1 persona-text-xs persona-font-medium persona-text-persona-primary persona-truncate persona-text-center md:persona-text-left");if(o)g.replaceChildren(),ie?P.append(ie,D,z):P.append(_,D,z),P.insertBefore(Q,z),P.insertBefore(W,z),g.append(x.element,R,P);else{let a=m("div","persona-flex persona-items-center persona-gap-1 persona-shrink-0");a.append(_,Q,W,I),g.appendChild(S),g.appendChild(a)}l&&(g.style.paddingLeft=l,g.style.paddingRight=l);let w=m("div","persona-artifact-list persona-shrink-0 persona-flex persona-gap-1 persona-overflow-x-auto persona-p-2 persona-border-b persona-border-persona-border");A&&w.style.setProperty("--persona-artifact-tab-fade-size",A);let H=e.features?.artifacts?.renderTabBar,j=m("div","persona-artifact-tab-custom persona-shrink-0 persona-border-b persona-border-persona-border persona-hidden"),ue=Lt(w,{onSelect:a=>t.onSelect(B[a].id)}),X=a=>{let C=a.scrollWidth-a.clientWidth,v=C>1,E=Math.abs(a.scrollLeft);a.classList.toggle("persona-artifact-tab-fade-start",f&&v&&E>1),a.classList.toggle("persona-artifact-tab-fade-end",p&&v&&E<C-1)},ee=0,me=()=>{if(ee)return;let a=()=>{ee=0,X(w)};ee=typeof requestAnimationFrame=="function"?requestAnimationFrame(a):setTimeout(a,0)};w.addEventListener("scroll",()=>me(),{passive:!0}),typeof ResizeObserver<"u"&&new ResizeObserver(()=>X(w)).observe(w);let U=m("div","persona-artifact-content persona-flex-1 persona-min-h-0 persona-overflow-y-auto persona-p-3"),te=()=>{U.scrollLeft=0},Ae=()=>{typeof requestAnimationFrame=="function"?requestAnimationFrame(te):setTimeout(te,0)};if(l){for(let a of[w,j])a.style.paddingLeft=l,a.style.paddingRight=l;U.style.padding=l}y.appendChild(g),y.appendChild(w),y.appendChild(j),y.appendChild(U);let B=[],q=null,Oe=!1,Ue=!1,Fe=!0,_e=!1,$e=null,De="",ne=null,xe=!1,Bt=a=>a.artifactType==="markdown"&&!!a.file||o?L:"rendered",qe=a=>{o||(a&&!xe?(g.insertBefore(x.element,S),xe=!0):!a&&xe&&(x.element.remove(),xe=!1))},Ge=()=>q&&B.find(a=>a.id===q)||B[B.length-1],Ke=()=>{let a=ve(Ge());if(!a){Q.replaceChildren();return}let C=Z.filter(v=>v.visible===void 0||v.visible(a)).map(v=>be(v,{documentChrome:o,onClick:()=>{let E=ve(Ge());if(E)try{Promise.resolve(v.onClick(E)).catch(()=>{})}catch{}}}));Q.replaceChildren(...C)},Le=()=>{Ke();let a=o&&B.length<=1,C=!!H;if(w.classList.toggle("persona-hidden",a||C),j.classList.toggle("persona-hidden",a||!C),C&&H){let N=B.map(G=>G.id).join("|")+" "+(q??"");if(N!==De){De=N;let G=H({records:B,selectedId:q,onSelect:t.onSelect});j.firstElementChild!==G&&j.replaceChildren(G)}}else{ue.beforeRender(),w.replaceChildren();let N=[],G=-1;for(let[se,ae]of B.entries()){let le=m("button","persona-artifact-tab persona-shrink-0 persona-rounded-lg persona-px-2 persona-py-1 persona-text-xs persona-border persona-border-transparent persona-text-persona-primary");le.type="button";let je=ae.artifactType==="markdown"?ae.file:void 0,Xe=je?oe(je.path):ae.title||ae.id.slice(0,8),Ye=je?.path||ae.title||Xe;le.textContent=Xe,le.title=Ye,le.setAttribute("aria-label",Ye),ae.id===q&&(le.classList.add("persona-bg-persona-container","persona-border-persona-border"),G=se),le.addEventListener("click",()=>t.onSelect(ae.id)),w.appendChild(le),N.push(le)}if(ue.render(N,G),G>=0&&q!==$e){$e=q;let se=N[G];typeof se.scrollIntoView=="function"&&se.scrollIntoView({block:"nearest",inline:"nearest"})}X(w)}let v=q&&B.find(N=>N.id===q)||B[B.length-1];if(!v){U.replaceChildren(),ne?.destroy(),ne=null,qe(!1);return}let E=v.artifactType==="markdown"?v.file:void 0;if(qe(!!E&&fe(E)!=="other"),o){let N=E?ce(E):v.artifactType==="markdown"?"MD":v.component??"Component",G=(v.title||"Document").trim(),se=E?oe(E.path):G.replace(/\s*·\s*MD\s*$/i,"").trim()||"Document";R.textContent=`${se} \xB7 ${N}`}else S.textContent=E?oe(E.path):s;ne?(ne.el.parentElement!==U&&U.replaceChildren(ne.el),ne.update(v)):(ne=Ie(v,{config:e,resolveViewMode:Bt}),U.replaceChildren(ne.el)),U.classList.toggle("persona-artifact-content-flush",!!U.querySelector(".persona-code-pre"))},Ze=()=>{let a=B.length>0;if(y.classList.toggle("persona-hidden",!a),u){let E=((typeof y.closest=="function"?y.closest("[data-persona-root]"):null)?.classList.contains("persona-artifact-narrow-host")??!1)||typeof window<"u"&&window.matchMedia("(max-width: 640px)").matches;a&&E&&Oe?(u.classList.remove("persona-hidden"),y.classList.add("persona-artifact-drawer-open")):(u.classList.add("persona-hidden"),y.classList.remove("persona-artifact-drawer-open"))}},Je=()=>{_e=!1,Le(),Ze()};return{element:y,backdrop:u,update(a){let C=a.selectedId??a.artifacts[a.artifacts.length-1]?.id??null,v=C!==q;B=a.artifacts,q=C,B.length>0&&(Oe=!0),_e=!0,Fe&&Je(),v&&te()},setMobileOpen(a){Oe=a,!a&&u?(u.classList.add("persona-hidden"),y.classList.remove("persona-artifact-drawer-open")):Ze()},setExpanded(a){a!==Ue&&(Ue=a,Ae());let C=ye(a?cn:ln,16,"currentColor",2);C&&W.replaceChildren(C);let v=a?"Collapse artifacts panel":"Expand artifacts panel";W.setAttribute("aria-label",v),W.title=v},setExpandToggleVisible(a){W.classList.toggle("persona-hidden",!a)},setCopyButtonVisible(a){o||_.classList.toggle("persona-hidden",!a)},setRefreshButtonVisible(a){D.classList.toggle("persona-hidden",!a)},setCustomActions(a){Z=a,Ke()},setTabFade(a){let C=h(a);C.start===f&&C.end===p||(f=C.start,p=C.end,X(w))},setRenderTabBar(a){a!==H&&(H=a,De="",Le())},setVisible(a){a!==Fe&&(Fe=a,a&&_e&&Je())},destroy(){ne?.destroy(),ne=null}}}import{FileText as dn}from"lucide";function kt(e,t){let n=e.file&&typeof e.file=="object"&&!Array.isArray(e.file)?e.file:void 0,r=typeof e.title=="string"&&e.title?e.title:"Untitled artifact",o=n?oe(n.path):r,s=typeof e.artifactId=="string"?e.artifactId:"",i=e.status==="streaming"?"streaming":"complete",l=typeof e.artifactType=="string"?e.artifactType:"markdown",A=e.presentation&&typeof e.presentation=="object"&&!Array.isArray(e.presentation)?e.presentation:void 0,h=n?ce(n):l==="component"?"Component":"Document",f=document.createElement("div");f.className="persona-artifact-card persona-flex persona-w-full persona-max-w-full persona-items-center persona-gap-3 persona-px-4 persona-py-3",f.tabIndex=0,f.setAttribute("role","button"),f.setAttribute("aria-label",`Open ${o} in artifact panel`),s&&f.setAttribute("data-open-artifact",s);let p=document.createElement("div");p.className="persona-flex persona-h-10 persona-w-10 persona-flex-shrink-0 persona-items-center persona-justify-center persona-rounded-lg",p.style.border="1px solid var(--persona-border, #e5e7eb)",p.style.color="var(--persona-muted, #9ca3af)",p.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/><polyline points="14 2 14 8 20 8"/></svg>';let u=document.createElement("div");u.className="persona-min-w-0 persona-flex-1 persona-flex persona-flex-col persona-gap-0.5";let c=document.createElement("div");c.className="persona-truncate persona-text-sm persona-font-medium",c.style.color="var(--persona-text, #1f2937)",c.textContent=o;let y=document.createElement("div");if(y.className="persona-text-xs persona-flex persona-items-center persona-gap-1.5",y.style.color="var(--persona-muted, #9ca3af)",i==="streaming"){let g=t?.config?.features?.artifacts,S={id:s,artifactType:l==="component"?"component":"markdown",title:r,status:"streaming",...typeof e.markdown=="string"?{markdown:e.markdown}:{},...n?{file:n}:{},...A?{presentation:A}:{}},I=we(S,g,"card");pe(y,I,g)}else s&&he(s),y.textContent=h;if(u.append(c,y),f.append(p,u),i==="complete"){let g=t?.config?.features?.artifacts?.cardActions;if(g&&g.length>0){let I={artifactId:s||null,title:o,artifactType:l,markdown:typeof e.markdown=="string"?e.markdown:void 0,file:n};for(let L of g)try{if(L.visible===void 0||L.visible(I)){let x=be(L);x.setAttribute("data-artifact-custom-action",L.id),x.className=`${x.className} persona-flex-shrink-0`,f.append(x)}}catch{}}let S=ge({label:"Download",className:"persona-flex-shrink-0"});S.title=`Download ${o}`,S.setAttribute("data-download-artifact",s),f.append(S)}return f}var Be=(e,t)=>{let n=t?.config?.features?.artifacts?.renderCard;if(n){let r=typeof e.title=="string"&&e.title?e.title:"Untitled artifact",o=typeof e.artifactId=="string"?e.artifactId:"",s=e.status==="streaming"?"streaming":"complete",i=typeof e.artifactType=="string"?e.artifactType:"markdown",l=n({artifact:{artifactId:o,title:r,artifactType:i,status:s},config:t.config,defaultRenderer:()=>kt(e,t)});if(l)return l}return kt(e,t)};var de=new WeakMap;function Rt(e,t,n){if(t.length===0)return;let r=new Map(t.map(o=>[o.id,o]));e.querySelectorAll("[data-artifact-inline]").forEach(o=>{let s=de.get(o);if(!s)return;let i=r.get(o.getAttribute("data-artifact-inline")??"");i&&s(i,n)})}function Ht(e){return de.has(e)}function fn(e){let t=typeof e.artifactId=="string"?e.artifactId:"",n=typeof e.title=="string"&&e.title?e.title:void 0,r=e.status==="streaming"?"streaming":"complete",o=e.presentation&&typeof e.presentation=="object"&&!Array.isArray(e.presentation)?e.presentation:void 0;if(e.artifactType==="component"){let i=e.componentProps,l=i&&typeof i=="object"&&!Array.isArray(i)?i:{};return{id:t,artifactType:"component",title:n,status:r,component:typeof e.component=="string"?e.component:"",props:l,...o?{presentation:o}:{}}}let s=e.file&&typeof e.file=="object"&&!Array.isArray(e.file)?e.file:void 0;return{id:t,artifactType:"markdown",title:n,status:r,markdown:typeof e.markdown=="string"?e.markdown:"",...s?{file:s}:{},...o?{presentation:o}:{}}}function St(e){let t=e.artifactType==="markdown"?e.file:void 0,n=t?oe(t.path):e.title&&e.title.trim()?e.title:"Untitled artifact",r=t?ce(t):e.artifactType==="component"?"Component":"Document";return{title:n,typeLabel:r}}function pn(e){let t={artifactId:e.id,title:e.title??"",status:e.status,artifactType:e.artifactType};return e.artifactType==="markdown"&&(typeof e.markdown=="string"&&(t.markdown=e.markdown),e.file&&(t.file=e.file)),t}var Et=180,un=240,mn=.8,yn=300,gn=500,bn="cubic-bezier(0.2, 0, 0, 1)",Pt=240,hn=.35;function wn(e,t,n){let{swap:r,onSettled:o}=n,s=!1;try{s=typeof window<"u"&&typeof window.matchMedia=="function"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}catch{s=!1}if(!t||!e.isConnected||s||typeof e.animate!="function"){r(),o();return}e.style.height=`${t}px`,e.style.overflow="hidden";let i=[];for(let l of Array.from(e.children))l instanceof HTMLElement&&i.push(l.animate([{opacity:1},{opacity:0}],{duration:Et,easing:"ease-out",fill:"forwards"}));window.setTimeout(()=>{for(let I of i)I.cancel();r();let l=()=>{e.style.removeProperty("height"),e.style.removeProperty("overflow")};if(!e.isConnected){l(),o();return}e.style.height="auto";let A=e.getBoundingClientRect().height;if(e.style.height=`${t}px`,!A||Math.abs(A-t)<1){l(),o();return}let h=Math.abs(t-A),f=Math.round(Math.min(gn,Math.max(yn,un+h*mn))),p=Math.round(f*hn),u=e.firstElementChild instanceof HTMLElement?e.firstElementChild:null,c=u?u.animate([{opacity:0},{opacity:1}],{duration:Pt,delay:p,easing:"ease-out",fill:"backwards"}):null,y=e.animate([{height:`${t}px`},{height:`${A}px`}],{duration:f,easing:bn});e.style.height=`${A}px`;let g=!1,S=()=>{g||(g=!0,l(),o())};Promise.allSettled([y.finished,c?.finished].filter(Boolean)).then(S),window.setTimeout(S,Math.max(f,p+Pt)+120)},Et)}function An(e){let t=e?.inlineChrome;if(t===!1)return{chromeEnabled:!1,showCopy:!1,showExpand:!1,showViewToggle:!1};let n=typeof t=="object"?t:void 0;return{chromeEnabled:!0,showCopy:n?.showCopy!==!1,showExpand:n?.showExpand!==!1,showViewToggle:n?.showViewToggle!==!1}}var Ce="--persona-artifact-inline-body-height";function vn(e){let t=e?.inlineBody,n=t?.streamingView==="status"?"status":"source",r=t?.viewMode==="source"?"source":"rendered",o=320,s=320,i=t?.height;typeof i=="number"||i==="auto"?(o=i,s=i):i&&typeof i=="object"&&(o=i.streaming??320,s=i.complete??320);let l=t?.overflow==="clip"?"clip":"scroll",A=l==="clip"?!1:t?.followOutput!==!1,h,f,p=t?.fadeMask;p===!0?(h=!0,f=!0):p===!1?(h=!1,f=!1):p&&typeof p=="object"?(h=p.top===!0,f=p.bottom===!0):l==="clip"?(h=!1,f=!0):(h=!0,f=!0);let u=t?.transition==="none"?"none":"auto",c=t?.completeDisplay==="card"?"card":"inline";return{streamingView:n,viewMode:r,streamingHeight:o,completeHeight:s,followOutput:A,overflow:l,fadeTop:h,fadeBottom:f,transition:u,completeDisplay:c}}function Mt(e,t){let n=fn(e),r=t.config?.features?.artifacts,{chromeEnabled:o,showCopy:s,showExpand:i,showViewToggle:l}=An(r),A=r?.inlineActions??[],h=vn(r),f=h.completeDisplay==="card",p=null,u=n,c=m("div","persona-artifact-inline persona-w-full persona-max-w-full");c.setAttribute("data-persona-theme-zone","artifact-inline"),n.id&&c.setAttribute("data-artifact-inline",n.id);let y=b=>Be(pn(b),t),g=null,S=b=>{g?.destroy(),g=null,c.classList.add("persona-artifact-inline--card"),c.style.removeProperty(Ce),c.replaceChildren(y(b)),de.set(c,T=>{c.replaceChildren(y(T))})};if(f&&n.status==="complete")return S(n),c;let I=Ie(n,{config:t.config,bodyLayout:h,resolveViewMode:()=>p??h.viewMode});g=I;let L=m("div","persona-artifact-inline-body");L.appendChild(I.el);let x=b=>{let T=b.status!=="complete",F=T?h.streamingHeight:h.completeHeight,k=typeof F=="number";k?c.style.setProperty(Ce,`${F}px`):c.style.removeProperty(Ce);let R=!!I.el.querySelector(".persona-code-pre"),w=!!I.el.querySelector("iframe, .persona-artifact-source-window--fixed, .persona-artifact-status-view");L.classList.toggle("persona-artifact-content-flush",R),L.classList.toggle("persona-artifact-inline-body--sized",k&&w),L.classList.toggle("persona-artifact-inline-body--cap",!T&&!w&&typeof h.completeHeight=="number")},P=n.status,$=(b,T)=>{P!=="complete"&&b.status==="complete"?(typeof h.completeHeight=="number"?c.style.setProperty(Ce,`${h.completeHeight}px`):c.style.removeProperty(Ce),xt(L,T?.suppressTransition?"none":h.transition,b.id,()=>{I.update(b),x(b)})):I.update(b),x(b),P=b.status};x(n);let J=h.overflow==="clip"&&i&&!!n.id;if(J&&(L.setAttribute("data-expand-artifact-inline",n.id),L.setAttribute("role","button"),L.setAttribute("tabindex","0"),L.classList.add("persona-cursor-pointer"),L.setAttribute("aria-label",`Open ${St(n).title} in panel`)),!o)return c.appendChild(L),de.set(c,$),c;let re=m("div","persona-artifact-inline-chrome");re.setAttribute("data-persona-theme-zone","artifact-inline-chrome");let Y=m("div","persona-artifact-inline-chrome-lead"),ie=m("span","persona-flex persona-items-center persona-flex-shrink-0"),_=ye(dn,16,"currentColor",2);_&&ie.appendChild(_);let K=m("span","persona-artifact-inline-title persona-truncate persona-min-w-0"),D=m("span","persona-artifact-inline-type");Y.append(ie,K,D);let z=m("div","persona-artifact-inline-chrome-actions"),W=m("span","persona-flex persona-items-center persona-gap-1"),Q=()=>p??h.viewMode,Z=l?Te({items:[{id:"rendered",icon:"eye",label:"Rendered view",className:"persona-artifact-doc-icon-btn persona-artifact-view-btn"},{id:"source",icon:"code-xml",label:"Source",className:"persona-artifact-doc-icon-btn persona-artifact-code-btn"}],selectedId:Q(),className:"persona-artifact-toggle-group persona-flex-shrink-0",onSelect:b=>{let T=b==="source"?"source":"rendered";T!==Q()&&(p=T,I.update(u),x(u))}}):null,d=s?V({icon:"copy",label:"Copy",className:"persona-artifact-doc-icon-btn persona-flex-shrink-0"}):null;d&&n.id&&d.setAttribute("data-copy-artifact",n.id);let M=i?V({icon:"maximize",label:"Open in panel",className:"persona-artifact-doc-icon-btn persona-flex-shrink-0"}):null;M&&n.id&&M.setAttribute("data-expand-artifact-inline",n.id),z.appendChild(W),Z&&z.appendChild(Z.element),d&&z.appendChild(d),M&&z.appendChild(M),re.append(Y,z),c.append(re,L);let O=b=>{let{title:T,typeLabel:F}=St(b);K.textContent=T,K.title=T,J&&L.setAttribute("aria-label",`Open ${T} in panel`);let k=b.status!=="complete";if(k){D.classList.contains("persona-artifact-inline-status")||(D.className="persona-artifact-inline-status",D.removeAttribute("data-preserve-animation"),D.replaceChildren());let R=we(b,r,"inline-chrome");pe(D,R,r)}else he(b.id),D.className="persona-artifact-inline-type",D.removeAttribute("data-preserve-animation"),D.replaceChildren(),D.textContent=F;if(d&&d.classList.toggle("persona-hidden",k),Z){let R=b.artifactType==="markdown"?b.file:void 0,w=!1;if(!k&&R&&h.viewMode!=="source"){let H=fe(R);H==="markdown"?w=!0:(H==="html"||H==="svg")&&(w=r?.filePreview?.enabled!==!1)}Z.element.classList.toggle("persona-hidden",!w),Z.setSelected(Q())}if(W.replaceChildren(),!k&&A.length>0){let R=ve(b);if(R)for(let w of A)try{if(w.visible===void 0||w.visible(R)){let H=be(w,{documentChrome:!0});H.setAttribute("data-artifact-custom-action",w.id),H.classList.add("persona-flex-shrink-0"),W.appendChild(H)}}catch{}}};return O(n),de.set(c,(b,T)=>{if(f&&P!=="complete"&&b.status==="complete"){let F=c.isConnected?c.getBoundingClientRect().height:0;P="complete";let k=b,R=!1,w=H=>{k=H,R=!0};de.set(c,w),wn(c,F,{swap:()=>{S(k),R=!1,de.set(c,w)},onSettled:()=>{R?S(k):de.set(c,H=>{c.replaceChildren(y(H))})}});return}(b.status!=="complete"||b.id!==u.id)&&(p=null),u=b,$(b,T),O(b)}),c}var It=(e,t)=>{let n=t?.config?.features?.artifacts?.renderInline;if(n){let r=typeof e.title=="string"&&e.title?e.title:"Untitled artifact",o=typeof e.artifactId=="string"?e.artifactId:"",s=e.status==="streaming"?"streaming":"complete",i=typeof e.artifactType=="string"?e.artifactType:"markdown",l=n({artifact:{artifactId:o,title:r,artifactType:i,status:s},config:t.config,defaultRenderer:()=>Mt(e,t)});if(l)return l}return Mt(e,t)};export{Be as PersonaArtifactCard,It as PersonaArtifactInline,et as __provideMarkdownParsers,st as __setIconsExtraLoader,He as artifactCopyText,Tt as createArtifactPane,Se as downloadInfoFor,Ht as hasLiveInlineArtifactBlock,vt as initArtifactsUi,Ee as triggerArtifactDownload,Rt as updateInlineArtifactBlocks};
|
package/dist/chunk-HBE7LFNT.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
var c="webmcp:",g=new Map,A=t=>{g.clear();for(let r of t){let e=r.title?.trim();e&&g.set(r.name,e)}},w=t=>g.get(h(t)),u=null;function R(t){if(t.length===0)return"0:empty";let r=t.map(e=>[e.name,e.description??"",e.parametersSchema?JSON.stringify(e.parametersSchema):"",e.origin??"",e.annotations?JSON.stringify(e.annotations):""].join("")).sort();return`${t.length}:${m(r.join(""))}`}function p(t,r){let e=3735928559^r,n=1103547991^r;for(let o=0;o<t.length;o++){let s=t.charCodeAt(o);e=Math.imul(e^s,2654435761),n=Math.imul(n^s,1597334677)}return e=Math.imul(e^e>>>16,2246822507),e^=Math.imul(n^n>>>13,3266489909),n=Math.imul(n^n>>>16,2246822507),n^=Math.imul(e^e>>>13,3266489909),4294967296*(2097151&n)+(e>>>0)}function m(t){let r=p(t,0).toString(36),e=p(t,2654435761).toString(36);return`${r}.${e}`}var h=t=>t.startsWith(c)?t.slice(c.length):t,D=t=>t.startsWith(c),E=()=>u?u():import("@mcp-b/webmcp-polyfill");import{parse as T,STR as y,OBJ as M}from"partial-json";var d=t=>t.replace(/\\n/g,`
|
|
2
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\"),_=t=>{if(t===null)return"null";if(t===void 0)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return String(t);try{return JSON.stringify(t,null,2)}catch{return String(t)}},W=t=>{let r=t.completedAt??Date.now(),e=t.startedAt??r,o=(t.durationMs!==void 0?t.durationMs:Math.max(0,r-e))/1e3;return o<.1?"Thought for <0.1 seconds":`Thought for ${o>=10?Math.round(o).toString():o.toFixed(1).replace(/\.0$/,"")} seconds`},F=t=>t.status==="complete"?W(t):t.status==="pending"?"Waiting":"",P=t=>{let e=(typeof t.duration=="number"?t.duration:typeof t.durationMs=="number"?t.durationMs:Math.max(0,(t.completedAt??Date.now())-(t.startedAt??t.completedAt??Date.now())))/1e3;return e<.1?"Used tool for <0.1 seconds":`Used tool for ${e>=10?Math.round(e).toString():e.toFixed(1).replace(/\.0$/,"")} seconds`};var C=t=>t.status==="complete"?P(t):"Using tool...",x=t=>{let r=t/1e3;return r<.1?"<0.1s":r>=10?`${Math.round(r)}s`:`${r.toFixed(1).replace(/\.0$/,"")}s`},S=t=>{let r=typeof t.duration=="number"?t.duration:typeof t.durationMs=="number"?t.durationMs:Math.max(0,(t.completedAt??Date.now())-(t.startedAt??t.completedAt??Date.now()));return x(r)},$=t=>{let r=t.durationMs!==void 0?t.durationMs:Math.max(0,(t.completedAt??Date.now())-(t.startedAt??t.completedAt??Date.now()));return x(r)},I=(t,r,e)=>{if(!r)return e;let n=t.name?.trim()||"tool",o=S(t);return r.replace(/\{toolName\}/g,n).replace(/\{duration\}/g,o)},N=(t,r)=>{let e=t.replace(/\{toolName\}/g,r),n=[],o=/\*\*(.+?)\*\*|\*(.+?)\*|~(.+?)~/g,s=0,i;for(;(i=o.exec(e))!==null;)i.index>s&&l(n,e.slice(s,i.index),[]),i[1]!==void 0?l(n,i[1],["bold"]):i[2]!==void 0?l(n,i[2],["italic"]):i[3]!==void 0&&l(n,i[3],["dim"]),s=i.index+i[0].length;return s<e.length&&l(n,e.slice(s),[]),n},l=(t,r,e)=>{let n=r.split("{duration}");for(let o=0;o<n.length;o++)n[o]&&t.push({text:n[o],styles:e}),o<n.length-1&&t.push({text:"{duration}",styles:e,isDuration:!0})},b=()=>{let t=null,r=0,e=n=>{let o=/"text"\s*:\s*"((?:[^"\\]|\\.|")*?)"/,s=n.match(o);if(s&&s[1])try{return s[1].replace(/\\n/g,`
|
|
3
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}catch{return s[1]}let i=/"text"\s*:\s*"((?:[^"\\]|\\.)*)/,a=n.match(i);if(a&&a[1])try{return a[1].replace(/\\n/g,`
|
|
4
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}catch{return a[1]}return null};return{getExtractedText:()=>t,processChunk:async n=>{if(n.length<=r)return t!==null?{text:t,raw:n}:null;let o=n.trim();if(!o.startsWith("{")&&!o.startsWith("["))return null;let s=e(n);return s!==null&&(t=s),r=n.length,t!==null?{text:t,raw:n}:null},close:async()=>{}}},L=t=>{try{let r=JSON.parse(t);if(r&&typeof r=="object"&&typeof r.text=="string")return r.text}catch{return null}return null},O=()=>{let t={processChunk:r=>null,getExtractedText:()=>null};return t.__isPlainTextParser=!0,t},j=()=>{let t=b();return{processChunk:async r=>{let e=r.trim();return!e.startsWith("{")&&!e.startsWith("[")?null:t.processChunk(r)},getExtractedText:t.getExtractedText.bind(t),close:t.close?.bind(t)}},U=()=>{let t=null,r=0;return{getExtractedText:()=>t,processChunk:e=>{let n=e.trim();if(!n.startsWith("{")&&!n.startsWith("["))return null;if(e.length<=r)return t!==null||t===""?{text:t||"",raw:e}:null;try{let o=T(e,y|M);o&&typeof o=="object"&&(o.component&&typeof o.component=="string"?t=typeof o.text=="string"?d(o.text):"":o.type==="init"&&o.form?t="":typeof o.text=="string"&&(t=d(o.text)))}catch{}return r=e.length,t!==null?{text:t,raw:e}:null},close:()=>{}}};var B=()=>{let t=null;return{processChunk:r=>{if(!r.trim().startsWith("<"))return null;let n=r.match(/<text[^>]*>([\s\S]*?)<\/text>/);return n&&n[1]?(t=n[1],{text:t,raw:r}):null},getExtractedText:()=>t}};export{c as a,A as b,w as c,R as d,D as e,E as f,_ as g,F as h,C as i,x as j,S as k,$ as l,I as m,N as n,L as o,O as p,j as q,U as r,B as s};
|