@heroui/agent 0.2.0-beta.1
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/CHANGELOG.md +64 -0
- package/LICENSE +21 -0
- package/README.md +205 -0
- package/dist/chart-content-VZ66GD22.js +1391 -0
- package/dist/chunk-3FG5NRTX.js +9 -0
- package/dist/chunk-CU6MPKAJ.js +359 -0
- package/dist/chunk-DW4AQRM5.js +297 -0
- package/dist/chunk-GDDNN2XY.js +954 -0
- package/dist/chunk-RQCTC4JB.js +1084 -0
- package/dist/chunk-TOOT6SZ2.js +74 -0
- package/dist/chunk-VJA52U5P.js +137 -0
- package/dist/component-renderer-IBJDNXSO.js +9780 -0
- package/dist/contracts.d.ts +1293 -0
- package/dist/contracts.js +2325 -0
- package/dist/css/index.css +2 -0
- package/dist/embed-runtime-XOPQY7Z5.js +7254 -0
- package/dist/identity-NYCXY1mT.d.ts +164 -0
- package/dist/index.d.ts +594 -0
- package/dist/index.js +28 -0
- package/dist/interactive-map-surface-67KHT3VB.js +362 -0
- package/dist/next.d.ts +4 -0
- package/dist/next.js +22 -0
- package/dist/server.d.ts +31 -0
- package/dist/server.js +256 -0
- package/package.json +133 -0
|
@@ -0,0 +1,2325 @@
|
|
|
1
|
+
// src/contracts/attachments.ts
|
|
2
|
+
var HEROUI_AGENT_MAX_ATTACHMENTS = 5;
|
|
3
|
+
var HEROUI_AGENT_ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024;
|
|
4
|
+
var HEROUI_AGENT_ATTACHMENT_EXTENSION_BY_CONTENT_TYPE = {
|
|
5
|
+
"application/json": "json",
|
|
6
|
+
"application/pdf": "pdf",
|
|
7
|
+
"image/gif": "gif",
|
|
8
|
+
"image/jpeg": "jpg",
|
|
9
|
+
"image/png": "png",
|
|
10
|
+
"image/webp": "webp",
|
|
11
|
+
"text/csv": "csv",
|
|
12
|
+
"text/markdown": "md",
|
|
13
|
+
"text/plain": "txt",
|
|
14
|
+
"text/tab-separated-values": "tsv"
|
|
15
|
+
};
|
|
16
|
+
var HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES = Object.freeze(
|
|
17
|
+
Object.keys(
|
|
18
|
+
HEROUI_AGENT_ATTACHMENT_EXTENSION_BY_CONTENT_TYPE
|
|
19
|
+
)
|
|
20
|
+
);
|
|
21
|
+
var HEROUI_AGENT_ATTACHMENT_ACCEPT = HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES.join(",");
|
|
22
|
+
var HEROUI_AGENT_ATTACHMENT_CONTENT_TYPE_SET = new Set(
|
|
23
|
+
HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES
|
|
24
|
+
);
|
|
25
|
+
var HEROUI_AGENT_TEXT_ATTACHMENT_CONTENT_TYPES = /* @__PURE__ */ new Set([
|
|
26
|
+
"application/json",
|
|
27
|
+
"text/csv",
|
|
28
|
+
"text/markdown",
|
|
29
|
+
"text/plain",
|
|
30
|
+
"text/tab-separated-values"
|
|
31
|
+
]);
|
|
32
|
+
function isHeroUIAgentAttachmentContentType(value) {
|
|
33
|
+
return HEROUI_AGENT_ATTACHMENT_CONTENT_TYPE_SET.has(value.trim().toLowerCase());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/contracts/appearance.ts
|
|
37
|
+
var HEROUI_AGENT_REMOTE_CONFIG_VERSION = 1;
|
|
38
|
+
var INVALID = Symbol("invalid");
|
|
39
|
+
function isRecord(value) {
|
|
40
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41
|
+
}
|
|
42
|
+
function optionalString(value) {
|
|
43
|
+
if (value === void 0) return void 0;
|
|
44
|
+
return typeof value === "string" ? value : INVALID;
|
|
45
|
+
}
|
|
46
|
+
function optionalBoolean(value) {
|
|
47
|
+
if (value === void 0) return void 0;
|
|
48
|
+
return typeof value === "boolean" ? value : INVALID;
|
|
49
|
+
}
|
|
50
|
+
function optionalNumber(value) {
|
|
51
|
+
if (value === void 0) return void 0;
|
|
52
|
+
return typeof value === "number" && Number.isFinite(value) ? value : INVALID;
|
|
53
|
+
}
|
|
54
|
+
function optionalEnum(allowed) {
|
|
55
|
+
return (value) => {
|
|
56
|
+
if (value === void 0) return void 0;
|
|
57
|
+
return typeof value === "string" && allowed.includes(value) ? value : INVALID;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function optionalThemeColor(value) {
|
|
61
|
+
if (value === void 0) return void 0;
|
|
62
|
+
if (typeof value === "string") return value;
|
|
63
|
+
if (!isRecord(value)) return INVALID;
|
|
64
|
+
const dark = optionalString(value["dark"]);
|
|
65
|
+
const light = optionalString(value["light"]);
|
|
66
|
+
if (dark === INVALID || light === INVALID) return INVALID;
|
|
67
|
+
return { ...dark === void 0 ? {} : { dark }, ...light === void 0 ? {} : { light } };
|
|
68
|
+
}
|
|
69
|
+
function optionalStringRecord(value) {
|
|
70
|
+
if (value === void 0) return void 0;
|
|
71
|
+
if (!isRecord(value)) return INVALID;
|
|
72
|
+
const record = {};
|
|
73
|
+
for (const [key2, entry] of Object.entries(value)) {
|
|
74
|
+
if (typeof entry !== "string") return INVALID;
|
|
75
|
+
record[key2] = entry;
|
|
76
|
+
}
|
|
77
|
+
return record;
|
|
78
|
+
}
|
|
79
|
+
function optionalStringArray(value) {
|
|
80
|
+
if (value === void 0) return void 0;
|
|
81
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) return INVALID;
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
function shape(value, validators2) {
|
|
85
|
+
if (value === void 0) return INVALID;
|
|
86
|
+
if (!isRecord(value)) return INVALID;
|
|
87
|
+
const result = {};
|
|
88
|
+
for (const [key2, validate] of Object.entries(validators2)) {
|
|
89
|
+
const parsed = validate(value[key2]);
|
|
90
|
+
if (parsed === INVALID) return INVALID;
|
|
91
|
+
if (parsed !== void 0) result[key2] = parsed;
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
function group(parsed) {
|
|
96
|
+
return parsed === INVALID ? void 0 : parsed;
|
|
97
|
+
}
|
|
98
|
+
var COLOR_KEYS = [
|
|
99
|
+
"accent",
|
|
100
|
+
"background",
|
|
101
|
+
"foreground",
|
|
102
|
+
"overlay",
|
|
103
|
+
"surface",
|
|
104
|
+
"surfaceSecondary",
|
|
105
|
+
"tooltip"
|
|
106
|
+
];
|
|
107
|
+
function parseAppearance(value) {
|
|
108
|
+
return shape(value, {
|
|
109
|
+
launcher: (launcher) => launcher === void 0 ? void 0 : shape(launcher, {
|
|
110
|
+
background: optionalThemeColor,
|
|
111
|
+
icon: optionalString,
|
|
112
|
+
position: optionalEnum(["bottom-left", "bottom-right"]),
|
|
113
|
+
style: optionalStringRecord
|
|
114
|
+
}),
|
|
115
|
+
panel: (panel) => panel === void 0 ? void 0 : shape(panel, {
|
|
116
|
+
expandable: optionalBoolean,
|
|
117
|
+
expanded: optionalBoolean,
|
|
118
|
+
initialHeight: (entry) => entry === void 0 || typeof entry === "string" ? entry : optionalNumber(entry),
|
|
119
|
+
initialWidth: (entry) => entry === void 0 || typeof entry === "string" ? entry : optionalNumber(entry)
|
|
120
|
+
}),
|
|
121
|
+
theme: (theme) => theme === void 0 ? void 0 : shape(theme, {
|
|
122
|
+
colorScheme: optionalEnum(["dark", "light", "system"]),
|
|
123
|
+
colors: (colors) => colors === void 0 ? void 0 : shape(
|
|
124
|
+
colors,
|
|
125
|
+
Object.fromEntries(COLOR_KEYS.map((key2) => [key2, optionalThemeColor]))
|
|
126
|
+
),
|
|
127
|
+
designTheme: optionalEnum(["base", "brutalism", "glass", "mouve"]),
|
|
128
|
+
radius: optionalEnum(["pill", "round", "sharp", "soft"]),
|
|
129
|
+
typography: (typography) => typography === void 0 ? void 0 : shape(typography, { baseSize: optionalNumber, fontFamily: optionalString })
|
|
130
|
+
}),
|
|
131
|
+
viewMode: optionalEnum(["floating", "sidebar"])
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function parseComposer(value) {
|
|
135
|
+
return shape(value, {
|
|
136
|
+
attachments: (attachments) => {
|
|
137
|
+
if (attachments === void 0 || attachments === false) return attachments;
|
|
138
|
+
if (!Array.isArray(attachments)) return INVALID;
|
|
139
|
+
const types = attachments.filter(
|
|
140
|
+
(entry) => typeof entry === "string" && isHeroUIAgentAttachmentContentType(entry)
|
|
141
|
+
);
|
|
142
|
+
return types.length === attachments.length ? types : INVALID;
|
|
143
|
+
},
|
|
144
|
+
defaultModel: optionalString,
|
|
145
|
+
dictation: optionalBoolean,
|
|
146
|
+
disclaimer: (disclaimer) => disclaimer === false ? false : optionalString(disclaimer),
|
|
147
|
+
modelPicker: optionalBoolean,
|
|
148
|
+
placeholder: optionalString
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function parseMarkdown(value) {
|
|
152
|
+
return shape(value, {
|
|
153
|
+
animated: (animated) => {
|
|
154
|
+
if (animated === void 0 || animated === false) return animated;
|
|
155
|
+
if (!isRecord(animated)) return INVALID;
|
|
156
|
+
const animation = optionalEnum(["blurIn", "fadeIn", "slideUp"])(
|
|
157
|
+
animated["animation"]
|
|
158
|
+
);
|
|
159
|
+
if (animation === INVALID || animation === void 0) return INVALID;
|
|
160
|
+
return { ...animated, animation };
|
|
161
|
+
},
|
|
162
|
+
caret: (caret) => caret === false ? false : optionalEnum(["block", "circle"])(caret)
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function parseResponseActions(value) {
|
|
166
|
+
if (value === void 0 || value === false) return value;
|
|
167
|
+
if (!Array.isArray(value)) return INVALID;
|
|
168
|
+
const allowed = ["copy", "feedback", "retry"];
|
|
169
|
+
const actions = value.filter(
|
|
170
|
+
(entry) => typeof entry === "string" && allowed.includes(entry)
|
|
171
|
+
);
|
|
172
|
+
return actions.length === value.length ? actions : INVALID;
|
|
173
|
+
}
|
|
174
|
+
function parseAgentRemoteConfig(value) {
|
|
175
|
+
if (!isRecord(value)) return null;
|
|
176
|
+
if (value["version"] !== HEROUI_AGENT_REMOTE_CONFIG_VERSION) return null;
|
|
177
|
+
const revision = value["revision"];
|
|
178
|
+
if (typeof revision !== "string" || !revision) return null;
|
|
179
|
+
const appearance = group(parseAppearance(value["appearance"]));
|
|
180
|
+
const capabilities = group(
|
|
181
|
+
shape(value["capabilities"], {
|
|
182
|
+
imageSearch: optionalBoolean,
|
|
183
|
+
webSearch: optionalBoolean
|
|
184
|
+
})
|
|
185
|
+
);
|
|
186
|
+
const composer = group(parseComposer(value["composer"]));
|
|
187
|
+
const markdown = group(parseMarkdown(value["markdown"]));
|
|
188
|
+
const permissions = group(
|
|
189
|
+
shape(value["permissions"], {
|
|
190
|
+
defaultMode: optionalEnum(["ask", "auto", "full"]),
|
|
191
|
+
showPicker: optionalBoolean
|
|
192
|
+
})
|
|
193
|
+
);
|
|
194
|
+
const responseActions = group(parseResponseActions(value["responseActions"]));
|
|
195
|
+
const startScreen = group(
|
|
196
|
+
shape(value["startScreen"], {
|
|
197
|
+
greeting: optionalString,
|
|
198
|
+
promptShortcuts: optionalBoolean,
|
|
199
|
+
prompts: optionalStringArray
|
|
200
|
+
})
|
|
201
|
+
);
|
|
202
|
+
const webfont = group(
|
|
203
|
+
shape(value["webfont"], {
|
|
204
|
+
familyName: (familyName) => typeof familyName === "string" && familyName ? familyName : INVALID,
|
|
205
|
+
fontFaceUrl: optionalString,
|
|
206
|
+
stylesheetUrl: optionalString
|
|
207
|
+
})
|
|
208
|
+
);
|
|
209
|
+
return {
|
|
210
|
+
...appearance ? { appearance } : {},
|
|
211
|
+
...capabilities ? { capabilities } : {},
|
|
212
|
+
...composer ? { composer } : {},
|
|
213
|
+
...markdown ? { markdown } : {},
|
|
214
|
+
...permissions ? { permissions } : {},
|
|
215
|
+
...responseActions === void 0 ? {} : { responseActions },
|
|
216
|
+
...startScreen ? { startScreen } : {},
|
|
217
|
+
...webfont ? { webfont } : {},
|
|
218
|
+
revision,
|
|
219
|
+
version: HEROUI_AGENT_REMOTE_CONFIG_VERSION
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ../agent-ui/src/categories.ts
|
|
224
|
+
var COMPONENT_CATEGORY_BY_KIND = {
|
|
225
|
+
accordion: "display-information",
|
|
226
|
+
"action-group": "actions",
|
|
227
|
+
"area-chart": "data-visualization",
|
|
228
|
+
"bar-chart": "data-visualization",
|
|
229
|
+
callout: "display-information",
|
|
230
|
+
"channel-message": "display-information",
|
|
231
|
+
"code-block": "display-information",
|
|
232
|
+
"comparison-list": "data-visualization",
|
|
233
|
+
"composed-chart": "data-visualization",
|
|
234
|
+
"create-event": "display-information",
|
|
235
|
+
"data-table": "data-visualization",
|
|
236
|
+
diagram: "display-information",
|
|
237
|
+
"donut-chart": "data-visualization",
|
|
238
|
+
"enable-notification": "display-information",
|
|
239
|
+
"event-session": "display-information",
|
|
240
|
+
"flight-tracker": "display-information",
|
|
241
|
+
followup: "actions",
|
|
242
|
+
form: "form-elements",
|
|
243
|
+
heatmap: "data-visualization",
|
|
244
|
+
image: "display-information",
|
|
245
|
+
"kpi-grid": "data-visualization",
|
|
246
|
+
"line-chart": "data-visualization",
|
|
247
|
+
list: "display-information",
|
|
248
|
+
"list-block": "display-information",
|
|
249
|
+
map: "display-information",
|
|
250
|
+
"meter-list": "data-visualization",
|
|
251
|
+
"metric-grid": "data-visualization",
|
|
252
|
+
"pie-chart": "data-visualization",
|
|
253
|
+
"player-card": "display-information",
|
|
254
|
+
playlist: "display-information",
|
|
255
|
+
"product-card": "display-information",
|
|
256
|
+
"product-signals": "data-visualization",
|
|
257
|
+
"purchase-complete": "display-information",
|
|
258
|
+
"purchase-items": "display-information",
|
|
259
|
+
"radar-chart": "data-visualization",
|
|
260
|
+
"radial-chart": "data-visualization",
|
|
261
|
+
"record-card": "display-information",
|
|
262
|
+
"ride-status": "display-information",
|
|
263
|
+
"sankey-chart": "data-visualization",
|
|
264
|
+
"scatter-chart": "data-visualization",
|
|
265
|
+
steps: "display-information",
|
|
266
|
+
"switch-group": "form-elements",
|
|
267
|
+
tabs: "display-information",
|
|
268
|
+
"tag-list": "display-information",
|
|
269
|
+
text: "display-information",
|
|
270
|
+
"toggle-group": "form-elements",
|
|
271
|
+
"view-event": "display-information",
|
|
272
|
+
"weather-current": "display-information",
|
|
273
|
+
"weather-forecast": "display-information"
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// ../agent-ui/src/contracts/components.ts
|
|
277
|
+
import { z } from "zod";
|
|
278
|
+
var agentIconNames = [
|
|
279
|
+
"activity",
|
|
280
|
+
"alert",
|
|
281
|
+
"briefcase",
|
|
282
|
+
"calendar",
|
|
283
|
+
"chart",
|
|
284
|
+
"check",
|
|
285
|
+
"clock",
|
|
286
|
+
"code",
|
|
287
|
+
"credit-card",
|
|
288
|
+
"database",
|
|
289
|
+
"device-desktop",
|
|
290
|
+
"device-mobile",
|
|
291
|
+
"document",
|
|
292
|
+
"dollar",
|
|
293
|
+
"flag",
|
|
294
|
+
"globe",
|
|
295
|
+
"heart",
|
|
296
|
+
"home",
|
|
297
|
+
"info",
|
|
298
|
+
"lightning",
|
|
299
|
+
"location",
|
|
300
|
+
"mail",
|
|
301
|
+
"percent",
|
|
302
|
+
"person",
|
|
303
|
+
"question",
|
|
304
|
+
"receipt",
|
|
305
|
+
"rocket",
|
|
306
|
+
"route",
|
|
307
|
+
"search",
|
|
308
|
+
"shopping-bag",
|
|
309
|
+
"speedometer",
|
|
310
|
+
"star",
|
|
311
|
+
"tag",
|
|
312
|
+
"target",
|
|
313
|
+
"users"
|
|
314
|
+
];
|
|
315
|
+
var weatherConditions = [
|
|
316
|
+
"clear",
|
|
317
|
+
"partly-cloudy",
|
|
318
|
+
"cloudy",
|
|
319
|
+
"fog",
|
|
320
|
+
"drizzle",
|
|
321
|
+
"rain",
|
|
322
|
+
"snow",
|
|
323
|
+
"thunderstorm",
|
|
324
|
+
"windy",
|
|
325
|
+
"unknown"
|
|
326
|
+
];
|
|
327
|
+
var title = z.string().trim().min(1).max(120);
|
|
328
|
+
var shortText = z.string().trim().min(1).max(320);
|
|
329
|
+
var content = z.string().trim().min(1).max(1e4);
|
|
330
|
+
var key = z.string().trim().min(1).max(80);
|
|
331
|
+
var id = z.string().trim().min(1).max(100);
|
|
332
|
+
var date = z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
333
|
+
var time = z.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/);
|
|
334
|
+
var datumValue = z.union([z.string().max(500), z.number(), z.boolean(), z.null()]);
|
|
335
|
+
var datum = z.record(z.string().max(80), datumValue);
|
|
336
|
+
var base = z.object({ description: shortText.optional(), id, title });
|
|
337
|
+
var cardComponentVariantSchema = z.enum(["outline", "plain", "surface", "surface-secondary", "surface-tertiary", "widget"]).describe(
|
|
338
|
+
"Card hierarchy: surface for the primary standalone group; surface-secondary for supporting information; surface-tertiary for one featured or emphasized group; outline for equal peers and comparisons; plain for a structural section already separated by surrounding layout; widget for a compact interactive group with actions or controls."
|
|
339
|
+
);
|
|
340
|
+
var recordCardLayoutSchema = z.enum(["compact", "details", "media"]).describe(
|
|
341
|
+
"Record information layout: details for a full labeled fact set; compact for a brief summary or repeated peer cards; media for an image-led product, place, person, or event and only when an image is available."
|
|
342
|
+
);
|
|
343
|
+
var numberFormatSchema = z.discriminatedUnion("style", [
|
|
344
|
+
z.object({ compact: z.boolean().optional(), style: z.literal("number") }),
|
|
345
|
+
z.object({
|
|
346
|
+
maximumFractionDigits: z.number().int().min(0).max(4).optional(),
|
|
347
|
+
style: z.literal("percent")
|
|
348
|
+
}),
|
|
349
|
+
z.object({
|
|
350
|
+
compact: z.boolean().optional(),
|
|
351
|
+
currency: z.string().regex(/^[A-Z]{3}$/),
|
|
352
|
+
style: z.literal("currency")
|
|
353
|
+
})
|
|
354
|
+
]);
|
|
355
|
+
var chartColorSchema = z.enum([
|
|
356
|
+
"accent",
|
|
357
|
+
"chart-1",
|
|
358
|
+
"chart-2",
|
|
359
|
+
"chart-3",
|
|
360
|
+
"chart-4",
|
|
361
|
+
"chart-5",
|
|
362
|
+
"danger",
|
|
363
|
+
"default",
|
|
364
|
+
"success",
|
|
365
|
+
"warning"
|
|
366
|
+
]);
|
|
367
|
+
var chartColors = z.record(z.string().trim().min(1).max(80), chartColorSchema).refine((colors) => Object.keys(colors).length <= 50, "At most 50 category colors are allowed");
|
|
368
|
+
var series = z.object({
|
|
369
|
+
color: chartColorSchema.optional(),
|
|
370
|
+
dataKey: key,
|
|
371
|
+
format: numberFormatSchema.optional(),
|
|
372
|
+
label: shortText
|
|
373
|
+
});
|
|
374
|
+
var composedSeries = series.extend({
|
|
375
|
+
axis: z.enum(["left", "right"]).optional(),
|
|
376
|
+
stacked: z.boolean().optional(),
|
|
377
|
+
type: z.enum(["area", "bar", "line"])
|
|
378
|
+
});
|
|
379
|
+
var cartesianRange = z.object({
|
|
380
|
+
id,
|
|
381
|
+
label: shortText,
|
|
382
|
+
maxItems: z.number().int().min(1).max(200).optional()
|
|
383
|
+
});
|
|
384
|
+
var cartesian = base.extend({
|
|
385
|
+
data: z.array(datum).min(1).max(200),
|
|
386
|
+
defaultRangeId: id.optional(),
|
|
387
|
+
ranges: z.array(cartesianRange).min(2).max(8).optional(),
|
|
388
|
+
series: z.array(series).min(1).max(5),
|
|
389
|
+
showSummary: z.boolean().optional(),
|
|
390
|
+
xKey: key
|
|
391
|
+
});
|
|
392
|
+
var proportional = base.extend({
|
|
393
|
+
colors: chartColors.optional(),
|
|
394
|
+
data: z.array(datum).min(1).max(50),
|
|
395
|
+
format: numberFormatSchema.optional(),
|
|
396
|
+
labelKey: key,
|
|
397
|
+
valueKey: key
|
|
398
|
+
});
|
|
399
|
+
var scatter = base.extend({
|
|
400
|
+
colors: chartColors.optional(),
|
|
401
|
+
data: z.array(datum).min(1).max(200),
|
|
402
|
+
format: numberFormatSchema.optional(),
|
|
403
|
+
groupKey: key.optional(),
|
|
404
|
+
kind: z.literal("scatter-chart"),
|
|
405
|
+
labelKey: key.optional(),
|
|
406
|
+
sizeKey: key.optional(),
|
|
407
|
+
xKey: key,
|
|
408
|
+
yKey: key
|
|
409
|
+
});
|
|
410
|
+
var heatmap = base.extend({
|
|
411
|
+
color: chartColorSchema.optional(),
|
|
412
|
+
data: z.array(datum).min(1).max(400),
|
|
413
|
+
format: numberFormatSchema.optional(),
|
|
414
|
+
kind: z.literal("heatmap"),
|
|
415
|
+
valueKey: key,
|
|
416
|
+
xKey: key,
|
|
417
|
+
yKey: key
|
|
418
|
+
});
|
|
419
|
+
var option = z.object({ label: shortText, value: key });
|
|
420
|
+
var formDateRange = z.object({ end: date, start: date }).refine((range) => range.start <= range.end, "The start date must not be after the end date");
|
|
421
|
+
var fieldBase = {
|
|
422
|
+
description: shortText.optional(),
|
|
423
|
+
label: shortText,
|
|
424
|
+
name: key,
|
|
425
|
+
required: z.boolean().optional()
|
|
426
|
+
};
|
|
427
|
+
var formField = z.discriminatedUnion("kind", [
|
|
428
|
+
z.object({
|
|
429
|
+
...fieldBase,
|
|
430
|
+
defaultValue: z.string().max(500).optional(),
|
|
431
|
+
inputType: z.enum(["email", "number", "password", "search", "tel", "text", "url"]).optional(),
|
|
432
|
+
kind: z.literal("input"),
|
|
433
|
+
placeholder: z.string().max(160).optional()
|
|
434
|
+
}),
|
|
435
|
+
z.object({
|
|
436
|
+
...fieldBase,
|
|
437
|
+
defaultValue: z.string().max(2e3).optional(),
|
|
438
|
+
kind: z.literal("textarea"),
|
|
439
|
+
placeholder: z.string().max(160).optional(),
|
|
440
|
+
rows: z.number().int().min(2).max(12).optional()
|
|
441
|
+
}),
|
|
442
|
+
z.object({
|
|
443
|
+
...fieldBase,
|
|
444
|
+
defaultValue: key.optional(),
|
|
445
|
+
kind: z.literal("select"),
|
|
446
|
+
options: z.array(option).min(1).max(30),
|
|
447
|
+
placeholder: z.string().max(160).optional()
|
|
448
|
+
}),
|
|
449
|
+
z.object({
|
|
450
|
+
...fieldBase,
|
|
451
|
+
defaultValue: key.optional(),
|
|
452
|
+
kind: z.literal("radio-group"),
|
|
453
|
+
options: z.array(option).min(1).max(12),
|
|
454
|
+
placeholder: z.string().max(160).optional()
|
|
455
|
+
}),
|
|
456
|
+
z.object({
|
|
457
|
+
...fieldBase,
|
|
458
|
+
defaultValue: z.array(key).max(20).optional(),
|
|
459
|
+
kind: z.literal("checkbox-group"),
|
|
460
|
+
options: z.array(option).min(1).max(20)
|
|
461
|
+
}),
|
|
462
|
+
z.object({
|
|
463
|
+
...fieldBase,
|
|
464
|
+
defaultValue: z.array(key).max(50).optional(),
|
|
465
|
+
kind: z.literal("combobox"),
|
|
466
|
+
options: z.array(option.extend({ description: z.string().trim().min(1).max(120).optional() })).min(1).max(200).describe(
|
|
467
|
+
"Prefer this over select once there are more options than someone would scan \u2014 it filters as they type. Values must be unique."
|
|
468
|
+
),
|
|
469
|
+
placeholder: z.string().max(160).optional(),
|
|
470
|
+
selectionMode: z.enum(["multiple", "single"]).optional()
|
|
471
|
+
}).superRefine((field, ctx) => {
|
|
472
|
+
const values = new Set(field.options.map((entry) => entry.value));
|
|
473
|
+
if (values.size !== field.options.length) {
|
|
474
|
+
ctx.addIssue({
|
|
475
|
+
code: "custom",
|
|
476
|
+
message: "Combobox option values must be unique",
|
|
477
|
+
path: ["options"]
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
if ((field.selectionMode ?? "single") === "single" && (field.defaultValue?.length ?? 0) > 1) {
|
|
481
|
+
ctx.addIssue({
|
|
482
|
+
code: "custom",
|
|
483
|
+
message: "A single-selection combobox takes at most one default value",
|
|
484
|
+
path: ["defaultValue"]
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (field.defaultValue?.some((value) => !values.has(value))) {
|
|
488
|
+
ctx.addIssue({
|
|
489
|
+
code: "custom",
|
|
490
|
+
message: "Every combobox default value must be one of the options",
|
|
491
|
+
path: ["defaultValue"]
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}),
|
|
495
|
+
z.object({
|
|
496
|
+
...fieldBase,
|
|
497
|
+
defaultValue: z.number().optional(),
|
|
498
|
+
kind: z.literal("slider"),
|
|
499
|
+
max: z.number(),
|
|
500
|
+
min: z.number(),
|
|
501
|
+
step: z.number().positive().optional()
|
|
502
|
+
}),
|
|
503
|
+
z.object({
|
|
504
|
+
...fieldBase,
|
|
505
|
+
defaultValue: z.number().optional(),
|
|
506
|
+
format: numberFormatSchema.optional(),
|
|
507
|
+
kind: z.literal("number"),
|
|
508
|
+
max: z.number().optional(),
|
|
509
|
+
min: z.number().optional(),
|
|
510
|
+
placeholder: z.string().max(160).optional(),
|
|
511
|
+
step: z.number().positive().optional()
|
|
512
|
+
}),
|
|
513
|
+
z.object({
|
|
514
|
+
...fieldBase,
|
|
515
|
+
defaultValue: z.boolean().optional(),
|
|
516
|
+
kind: z.literal("switch")
|
|
517
|
+
}),
|
|
518
|
+
z.object({
|
|
519
|
+
...fieldBase,
|
|
520
|
+
defaultValue: date.optional(),
|
|
521
|
+
kind: z.literal("date-picker"),
|
|
522
|
+
max: date.optional(),
|
|
523
|
+
min: date.optional()
|
|
524
|
+
}),
|
|
525
|
+
z.object({
|
|
526
|
+
...fieldBase,
|
|
527
|
+
defaultValue: formDateRange.optional(),
|
|
528
|
+
kind: z.literal("date-range-picker"),
|
|
529
|
+
max: date.optional(),
|
|
530
|
+
min: date.optional()
|
|
531
|
+
}),
|
|
532
|
+
z.object({
|
|
533
|
+
...fieldBase,
|
|
534
|
+
defaultValue: time.optional(),
|
|
535
|
+
hourCycle: z.union([z.literal(12), z.literal(24)]).optional(),
|
|
536
|
+
kind: z.literal("time-field"),
|
|
537
|
+
max: time.optional(),
|
|
538
|
+
min: time.optional()
|
|
539
|
+
})
|
|
540
|
+
]);
|
|
541
|
+
var actionVariant = z.enum(["danger", "outline", "primary", "secondary", "tertiary"]);
|
|
542
|
+
var agentIconSchema = z.enum(agentIconNames);
|
|
543
|
+
var actionToolCall = z.object({
|
|
544
|
+
arguments: z.record(z.string().max(80), z.unknown()).refine(
|
|
545
|
+
(value) => JSON.stringify(value).length <= 4096,
|
|
546
|
+
"Tool call arguments must serialize to at most 4KB of JSON"
|
|
547
|
+
),
|
|
548
|
+
name: z.string().regex(/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/)
|
|
549
|
+
});
|
|
550
|
+
var action = z.object({
|
|
551
|
+
id,
|
|
552
|
+
label: shortText,
|
|
553
|
+
prompt: z.string().trim().min(1).max(2e3).optional(),
|
|
554
|
+
toolCall: actionToolCall.optional(),
|
|
555
|
+
variant: actionVariant.optional()
|
|
556
|
+
});
|
|
557
|
+
var mapCoordinate = z.object({
|
|
558
|
+
latitude: z.number().finite().min(-85.051129).max(85.051129),
|
|
559
|
+
longitude: z.number().finite().min(-180).max(180)
|
|
560
|
+
});
|
|
561
|
+
var httpUrl = z.string().trim().min(1).max(2e3).refine(
|
|
562
|
+
(value) => {
|
|
563
|
+
try {
|
|
564
|
+
const url = new URL(value);
|
|
565
|
+
return ["http:", "https:"].includes(url.protocol) && !url.username && !url.password;
|
|
566
|
+
} catch {
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
{ message: "URL must use HTTP or HTTPS and cannot include credentials" }
|
|
571
|
+
);
|
|
572
|
+
var contactUrl = z.string().trim().min(1).max(2e3).refine(
|
|
573
|
+
(value) => {
|
|
574
|
+
try {
|
|
575
|
+
const url = new URL(value);
|
|
576
|
+
return ["http:", "https:", "mailto:", "tel:"].includes(url.protocol) && !url.username && !url.password;
|
|
577
|
+
} catch {
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
},
|
|
581
|
+
{ message: "Link must use HTTP, HTTPS, mailto, or tel and cannot include credentials" }
|
|
582
|
+
);
|
|
583
|
+
var mapActionBase = { id, label: shortText, variant: actionVariant.optional() };
|
|
584
|
+
var telephoneUrl = z.string().trim().min(5).max(2e3).refine(
|
|
585
|
+
(value) => /^tel:\+?[0-9().\-\s]+$/.test(value) && /\d/.test(value.slice(4)),
|
|
586
|
+
"Phone links must use the tel: scheme and contain a phone number"
|
|
587
|
+
);
|
|
588
|
+
var mapLocationAction = z.discriminatedUnion("kind", [
|
|
589
|
+
z.object({ ...mapActionBase, href: telephoneUrl, kind: z.literal("call") }),
|
|
590
|
+
z.object({ ...mapActionBase, href: httpUrl, kind: z.literal("directions") }),
|
|
591
|
+
z.object({ ...mapActionBase, href: contactUrl, kind: z.literal("other") }),
|
|
592
|
+
z.object({ ...mapActionBase, href: httpUrl, kind: z.literal("website") })
|
|
593
|
+
]);
|
|
594
|
+
var mapLocation = mapCoordinate.extend({
|
|
595
|
+
actions: z.array(mapLocationAction).max(4).optional(),
|
|
596
|
+
address: shortText.optional(),
|
|
597
|
+
category: z.string().trim().min(1).max(100).optional(),
|
|
598
|
+
id,
|
|
599
|
+
images: z.array(z.object({ alt: shortText, src: httpUrl })).max(4).optional().describe(
|
|
600
|
+
"Prefer one representative image per location when a trusted tool or web image search returns one. The first image becomes the result-card thumbnail; initials are the fallback."
|
|
601
|
+
),
|
|
602
|
+
notes: z.string().trim().min(1).max(2e3).optional(),
|
|
603
|
+
rating: z.number().finite().min(0).max(5).optional(),
|
|
604
|
+
relevance: z.number().finite().min(0).max(1).optional(),
|
|
605
|
+
reviewCount: z.number().int().nonnegative().max(1e9).optional(),
|
|
606
|
+
title: shortText
|
|
607
|
+
});
|
|
608
|
+
var displayImageSrc = z.string().trim().min(1).max(2e3).refine(
|
|
609
|
+
(value) => {
|
|
610
|
+
if (value.startsWith("/")) return !value.startsWith("//");
|
|
611
|
+
try {
|
|
612
|
+
const url = new URL(value);
|
|
613
|
+
return ["http:", "https:"].includes(url.protocol) && !url.username && !url.password;
|
|
614
|
+
} catch {
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
{ message: "Image sources must be HTTP(S) URLs or root-relative paths" }
|
|
619
|
+
);
|
|
620
|
+
var agentUIImage = z.object({
|
|
621
|
+
alt: shortText,
|
|
622
|
+
src: displayImageSrc.refine(
|
|
623
|
+
(value) => !value.split(/[?#]/, 1)[0]?.toLowerCase().endsWith(".svg"),
|
|
624
|
+
"Response-composition images must be raster images"
|
|
625
|
+
)
|
|
626
|
+
});
|
|
627
|
+
var currency = z.string().regex(/^[A-Z]{3}$/);
|
|
628
|
+
var amount = z.object({
|
|
629
|
+
amount: z.number().finite().nonnegative().max(1e9),
|
|
630
|
+
currency
|
|
631
|
+
});
|
|
632
|
+
var weatherConditionSchema = z.enum(weatherConditions);
|
|
633
|
+
var weatherUnit = z.enum(["celsius", "fahrenheit"]);
|
|
634
|
+
var endpoint = z.object({
|
|
635
|
+
label: shortText,
|
|
636
|
+
status: shortText.optional(),
|
|
637
|
+
time: z.string().trim().min(1).max(80)
|
|
638
|
+
});
|
|
639
|
+
var recordTone = z.enum(["accent", "danger", "default", "muted", "success", "warning"]);
|
|
640
|
+
var productCardItem = z.object({
|
|
641
|
+
actions: z.array(action).max(3).optional(),
|
|
642
|
+
badge: z.object({ label: shortText, tone: recordTone.optional() }).optional(),
|
|
643
|
+
description: shortText.optional(),
|
|
644
|
+
id,
|
|
645
|
+
image: z.object({ alt: shortText, src: displayImageSrc }),
|
|
646
|
+
meta: z.string().trim().min(1).max(160).optional(),
|
|
647
|
+
name: shortText,
|
|
648
|
+
price: z.object({
|
|
649
|
+
amount: z.number().finite().nonnegative().max(1e9),
|
|
650
|
+
currency: currency.optional()
|
|
651
|
+
}),
|
|
652
|
+
rating: z.object({
|
|
653
|
+
count: z.number().int().nonnegative().max(1e9).optional(),
|
|
654
|
+
value: z.number().finite().min(0).max(5)
|
|
655
|
+
}).optional()
|
|
656
|
+
});
|
|
657
|
+
var meterTone = z.enum(["accent", "danger", "default", "success", "warning"]);
|
|
658
|
+
var meterItem = z.object({
|
|
659
|
+
description: shortText.optional(),
|
|
660
|
+
format: numberFormatSchema.optional(),
|
|
661
|
+
id,
|
|
662
|
+
label: shortText,
|
|
663
|
+
max: z.number().optional(),
|
|
664
|
+
min: z.number().optional(),
|
|
665
|
+
tone: meterTone.optional(),
|
|
666
|
+
value: z.number()
|
|
667
|
+
}).superRefine((item, ctx) => {
|
|
668
|
+
const min = item.min ?? 0;
|
|
669
|
+
const max = item.max ?? (item.format?.style === "percent" ? 1 : 100);
|
|
670
|
+
if (max <= min) {
|
|
671
|
+
ctx.addIssue({ code: "custom", message: "Meter max must be greater than min" });
|
|
672
|
+
}
|
|
673
|
+
if (item.value < min || item.value > max) {
|
|
674
|
+
ctx.addIssue({ code: "custom", message: "Meter value must be within its min/max range" });
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
var validators = {
|
|
678
|
+
accordion: base.extend({
|
|
679
|
+
kind: z.literal("accordion"),
|
|
680
|
+
sections: z.array(z.object({ content, defaultOpen: z.boolean().optional(), id, title: shortText })).min(1).max(12)
|
|
681
|
+
}),
|
|
682
|
+
actions: base.extend({
|
|
683
|
+
actions: z.array(action).min(1).max(8),
|
|
684
|
+
kind: z.literal("action-group"),
|
|
685
|
+
orientation: z.enum(["horizontal", "vertical"]).optional()
|
|
686
|
+
}),
|
|
687
|
+
area: cartesian.extend({ kind: z.literal("area-chart"), stacked: z.boolean().optional() }),
|
|
688
|
+
bar: cartesian.extend({
|
|
689
|
+
kind: z.literal("bar-chart"),
|
|
690
|
+
layout: z.enum(["horizontal", "vertical"]).optional(),
|
|
691
|
+
stacked: z.boolean().optional()
|
|
692
|
+
}),
|
|
693
|
+
callout: base.extend({
|
|
694
|
+
content,
|
|
695
|
+
icon: agentIconSchema.optional(),
|
|
696
|
+
kind: z.literal("callout"),
|
|
697
|
+
tone: z.enum(["accent", "danger", "neutral", "success", "warning"]).optional()
|
|
698
|
+
}),
|
|
699
|
+
channelMessage: base.extend({
|
|
700
|
+
attachments: z.array(z.object({ id, image: agentUIImage.optional(), name: shortText })).max(8).optional(),
|
|
701
|
+
author: z.object({ image: agentUIImage.optional(), name: shortText }),
|
|
702
|
+
channel: shortText,
|
|
703
|
+
content,
|
|
704
|
+
kind: z.literal("channel-message"),
|
|
705
|
+
timestamp: z.string().trim().min(1).max(80)
|
|
706
|
+
}),
|
|
707
|
+
code: base.extend({
|
|
708
|
+
code: z.string().min(1).max(2e4),
|
|
709
|
+
kind: z.literal("code-block"),
|
|
710
|
+
language: z.string().trim().max(40).optional()
|
|
711
|
+
}),
|
|
712
|
+
comparison: base.extend({
|
|
713
|
+
items: z.array(
|
|
714
|
+
z.object({
|
|
715
|
+
change: z.number().optional(),
|
|
716
|
+
format: numberFormatSchema.optional(),
|
|
717
|
+
label: shortText,
|
|
718
|
+
note: z.string().trim().max(180).optional(),
|
|
719
|
+
value: z.number()
|
|
720
|
+
})
|
|
721
|
+
).min(1).max(12),
|
|
722
|
+
kind: z.literal("comparison-list")
|
|
723
|
+
}),
|
|
724
|
+
composed: cartesian.extend({
|
|
725
|
+
kind: z.literal("composed-chart"),
|
|
726
|
+
series: z.array(composedSeries).min(2).max(5)
|
|
727
|
+
}),
|
|
728
|
+
createEvent: base.extend({
|
|
729
|
+
actions: z.array(action).max(2).optional(),
|
|
730
|
+
date: z.object({
|
|
731
|
+
day: z.number().int().min(1).max(31),
|
|
732
|
+
weekday: z.string().trim().min(1).max(20)
|
|
733
|
+
}),
|
|
734
|
+
events: z.array(
|
|
735
|
+
z.object({
|
|
736
|
+
id,
|
|
737
|
+
status: z.enum(["existing", "proposed"]).optional(),
|
|
738
|
+
time: z.string().trim().min(1).max(80),
|
|
739
|
+
title: shortText,
|
|
740
|
+
tone: recordTone.optional()
|
|
741
|
+
})
|
|
742
|
+
).min(1).max(12),
|
|
743
|
+
kind: z.literal("create-event")
|
|
744
|
+
}),
|
|
745
|
+
diagram: base.extend({
|
|
746
|
+
chart: z.string().trim().min(1).max(4e3).describe(
|
|
747
|
+
'Mermaid source. Pick the diagram type from the relationship: "flowchart LR" for a process or decision path, "sequenceDiagram" for an exchange between parties over time, "erDiagram" for how records relate, "stateDiagram-v2" for the states something moves between. Example: "flowchart LR\\n A[Order placed] --> B{In stock?}\\n B -- yes --> C[Ship]\\n B -- no --> D[Backorder]". Never include HTML, script tags, or click directives.'
|
|
748
|
+
),
|
|
749
|
+
kind: z.literal("diagram")
|
|
750
|
+
}).superRefine((component, ctx) => {
|
|
751
|
+
const forbidden = /<\s*script|javascript:|^\s*click\s+\S/im;
|
|
752
|
+
if (forbidden.test(component.chart)) {
|
|
753
|
+
ctx.addIssue({
|
|
754
|
+
code: "custom",
|
|
755
|
+
message: "Diagram source cannot contain HTML, script URLs, or click directives",
|
|
756
|
+
path: ["chart"]
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
}),
|
|
760
|
+
donut: proportional.extend({ kind: z.literal("donut-chart") }),
|
|
761
|
+
enableNotification: base.extend({
|
|
762
|
+
actions: z.tuple([action, action]),
|
|
763
|
+
kind: z.literal("enable-notification")
|
|
764
|
+
}),
|
|
765
|
+
eventSession: base.extend({
|
|
766
|
+
action: action.optional(),
|
|
767
|
+
eyebrow: z.string().trim().min(1).max(100).optional(),
|
|
768
|
+
kind: z.literal("event-session"),
|
|
769
|
+
location: shortText,
|
|
770
|
+
speakers: z.array(z.object({ image: agentUIImage.optional(), name: shortText, role: shortText })).max(8),
|
|
771
|
+
time: z.string().trim().min(1).max(80)
|
|
772
|
+
}),
|
|
773
|
+
flightTracker: base.extend({
|
|
774
|
+
airline: z.object({ logo: agentUIImage.optional(), name: shortText }),
|
|
775
|
+
date: z.string().trim().min(1).max(80),
|
|
776
|
+
destination: endpoint,
|
|
777
|
+
flightNumber: z.string().trim().min(1).max(40),
|
|
778
|
+
kind: z.literal("flight-tracker"),
|
|
779
|
+
origin: endpoint,
|
|
780
|
+
progress: z.number().finite().min(0).max(100).optional()
|
|
781
|
+
}),
|
|
782
|
+
followup: base.extend({
|
|
783
|
+
kind: z.literal("followup"),
|
|
784
|
+
prompts: z.array(z.object({ id, label: shortText, prompt: content })).min(1).max(8)
|
|
785
|
+
}),
|
|
786
|
+
form: base.extend({
|
|
787
|
+
actions: z.array(action).min(1).max(4),
|
|
788
|
+
fields: z.array(formField).min(1).max(20),
|
|
789
|
+
kind: z.literal("form")
|
|
790
|
+
}),
|
|
791
|
+
heatmap,
|
|
792
|
+
image: base.extend({
|
|
793
|
+
images: z.array(
|
|
794
|
+
z.object({
|
|
795
|
+
alt: shortText,
|
|
796
|
+
aspectRatio: z.enum(["landscape", "portrait", "square", "wide"]).optional(),
|
|
797
|
+
caption: shortText.optional(),
|
|
798
|
+
src: displayImageSrc
|
|
799
|
+
})
|
|
800
|
+
).min(1).max(6),
|
|
801
|
+
kind: z.literal("image"),
|
|
802
|
+
variant: z.enum(["grid", "horizontal"]).optional().describe("Use horizontal for a swipeable gallery in narrow chat interfaces.")
|
|
803
|
+
}),
|
|
804
|
+
kpiGrid: base.extend({
|
|
805
|
+
kind: z.literal("kpi-grid"),
|
|
806
|
+
metrics: z.array(
|
|
807
|
+
z.object({
|
|
808
|
+
change: z.number().optional(),
|
|
809
|
+
color: chartColorSchema.optional(),
|
|
810
|
+
format: numberFormatSchema.optional(),
|
|
811
|
+
icon: agentIconSchema.optional(),
|
|
812
|
+
label: shortText,
|
|
813
|
+
trend: z.array(z.number().finite()).min(2).max(60).describe(
|
|
814
|
+
"The values behind this KPI, oldest to newest, drawn as a sparkline. The last point should agree with value."
|
|
815
|
+
),
|
|
816
|
+
value: z.number()
|
|
817
|
+
})
|
|
818
|
+
).min(1).max(4)
|
|
819
|
+
}),
|
|
820
|
+
line: cartesian.extend({ kind: z.literal("line-chart") }),
|
|
821
|
+
list: base.extend({
|
|
822
|
+
items: z.array(
|
|
823
|
+
z.object({
|
|
824
|
+
checked: z.boolean().optional(),
|
|
825
|
+
children: z.array(shortText).max(8).optional(),
|
|
826
|
+
id,
|
|
827
|
+
text: shortText
|
|
828
|
+
})
|
|
829
|
+
).min(1).max(30),
|
|
830
|
+
kind: z.literal("list"),
|
|
831
|
+
style: z.enum(["bulleted", "checklist", "numbered"]).optional()
|
|
832
|
+
}),
|
|
833
|
+
listBlock: base.extend({
|
|
834
|
+
items: z.array(
|
|
835
|
+
z.object({
|
|
836
|
+
description: shortText.optional(),
|
|
837
|
+
icon: agentIconSchema.optional(),
|
|
838
|
+
id,
|
|
839
|
+
imageAlt: shortText.optional(),
|
|
840
|
+
imageUrl: displayImageSrc.optional(),
|
|
841
|
+
meta: z.string().trim().max(100).optional(),
|
|
842
|
+
rating: z.number().min(0).max(5).optional(),
|
|
843
|
+
title: shortText
|
|
844
|
+
})
|
|
845
|
+
).min(1).max(20),
|
|
846
|
+
kind: z.literal("list-block")
|
|
847
|
+
}),
|
|
848
|
+
map: base.extend({
|
|
849
|
+
initialLocationId: id.optional(),
|
|
850
|
+
kind: z.literal("map"),
|
|
851
|
+
locations: z.array(mapLocation).min(1).max(12),
|
|
852
|
+
viewport: z.object({ center: mapCoordinate, zoom: z.number().int().min(1).max(18) }).optional()
|
|
853
|
+
}).superRefine((map, ctx) => {
|
|
854
|
+
const locationIds = /* @__PURE__ */ new Set();
|
|
855
|
+
for (const [index, location] of map.locations.entries()) {
|
|
856
|
+
if (locationIds.has(location.id)) {
|
|
857
|
+
ctx.addIssue({
|
|
858
|
+
code: "custom",
|
|
859
|
+
message: `Duplicate map location id "${location.id}"`,
|
|
860
|
+
path: ["locations", index, "id"]
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
locationIds.add(location.id);
|
|
864
|
+
const actionIds = /* @__PURE__ */ new Set();
|
|
865
|
+
for (const [actionIndex, action2] of (location.actions ?? []).entries()) {
|
|
866
|
+
if (actionIds.has(action2.id)) {
|
|
867
|
+
ctx.addIssue({
|
|
868
|
+
code: "custom",
|
|
869
|
+
message: `Duplicate action id "${action2.id}" for map location "${location.id}"`,
|
|
870
|
+
path: ["locations", index, "actions", actionIndex, "id"]
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
actionIds.add(action2.id);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
if (map.initialLocationId && !locationIds.has(map.initialLocationId)) {
|
|
877
|
+
ctx.addIssue({
|
|
878
|
+
code: "custom",
|
|
879
|
+
message: "The initial map location must reference one of the locations",
|
|
880
|
+
path: ["initialLocationId"]
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
}).describe(
|
|
884
|
+
"A ranked, map-synchronized set of places or professionals. Coordinates and listing facts must come from tools or user data; never invent them."
|
|
885
|
+
),
|
|
886
|
+
meterList: base.extend({
|
|
887
|
+
items: z.array(meterItem).min(1).max(8),
|
|
888
|
+
kind: z.literal("meter-list")
|
|
889
|
+
}),
|
|
890
|
+
metricGrid: base.extend({
|
|
891
|
+
kind: z.literal("metric-grid"),
|
|
892
|
+
metrics: z.array(
|
|
893
|
+
z.object({
|
|
894
|
+
change: z.number().optional(),
|
|
895
|
+
format: numberFormatSchema.optional(),
|
|
896
|
+
icon: agentIconSchema.optional(),
|
|
897
|
+
label: shortText,
|
|
898
|
+
value: z.number()
|
|
899
|
+
})
|
|
900
|
+
).min(1).max(4)
|
|
901
|
+
}),
|
|
902
|
+
pie: proportional.extend({ kind: z.literal("pie-chart") }),
|
|
903
|
+
playerCard: base.extend({
|
|
904
|
+
backgroundImage: agentUIImage.optional(),
|
|
905
|
+
jerseyNumber: z.string().trim().min(1).max(20).optional(),
|
|
906
|
+
kind: z.literal("player-card"),
|
|
907
|
+
playerName: shortText,
|
|
908
|
+
stats: z.array(
|
|
909
|
+
z.object({
|
|
910
|
+
label: z.string().trim().min(1).max(40),
|
|
911
|
+
value: z.union([z.string().trim().min(1).max(80), z.number().finite()])
|
|
912
|
+
})
|
|
913
|
+
).min(1).max(8)
|
|
914
|
+
}),
|
|
915
|
+
playlist: base.extend({
|
|
916
|
+
actions: z.array(action).max(2).optional(),
|
|
917
|
+
cover: agentUIImage.optional(),
|
|
918
|
+
kind: z.literal("playlist"),
|
|
919
|
+
tracks: z.array(
|
|
920
|
+
z.object({
|
|
921
|
+
action: action.optional(),
|
|
922
|
+
artist: shortText,
|
|
923
|
+
id,
|
|
924
|
+
image: agentUIImage.optional(),
|
|
925
|
+
title: shortText
|
|
926
|
+
})
|
|
927
|
+
).min(1).max(20)
|
|
928
|
+
}),
|
|
929
|
+
productCard: base.extend({
|
|
930
|
+
actions: z.array(action).max(3).optional(),
|
|
931
|
+
kind: z.literal("product-card"),
|
|
932
|
+
products: z.array(productCardItem).min(1).max(8),
|
|
933
|
+
variant: cardComponentVariantSchema.optional()
|
|
934
|
+
}).superRefine((card, ctx) => {
|
|
935
|
+
const productIds = /* @__PURE__ */ new Set();
|
|
936
|
+
for (const [index, item] of card.products.entries()) {
|
|
937
|
+
if (productIds.has(item.id)) {
|
|
938
|
+
ctx.addIssue({
|
|
939
|
+
code: "custom",
|
|
940
|
+
message: `Duplicate product id "${item.id}"`,
|
|
941
|
+
path: ["products", index, "id"]
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
productIds.add(item.id);
|
|
945
|
+
}
|
|
946
|
+
}).describe(
|
|
947
|
+
"A commerce product presentation: one product renders an image-led spotlight, several render a store-style grid. Product facts (id, name, image, price, rating, availability) must come from tools or user data; never invent them."
|
|
948
|
+
),
|
|
949
|
+
purchaseComplete: base.extend({
|
|
950
|
+
action: action.optional(),
|
|
951
|
+
details: z.array(z.object({ label: shortText, value: shortText })).max(8),
|
|
952
|
+
kind: z.literal("purchase-complete"),
|
|
953
|
+
paid: amount.optional(),
|
|
954
|
+
product: z.object({
|
|
955
|
+
description: shortText.optional(),
|
|
956
|
+
image: agentUIImage.optional(),
|
|
957
|
+
name: shortText
|
|
958
|
+
})
|
|
959
|
+
}),
|
|
960
|
+
purchaseItems: base.extend({
|
|
961
|
+
actions: z.array(action).max(3).optional(),
|
|
962
|
+
currency,
|
|
963
|
+
items: z.array(
|
|
964
|
+
z.object({
|
|
965
|
+
description: shortText.optional(),
|
|
966
|
+
id,
|
|
967
|
+
image: agentUIImage.optional(),
|
|
968
|
+
name: shortText,
|
|
969
|
+
price: z.number().finite().nonnegative().max(1e9).optional(),
|
|
970
|
+
quantity: z.number().int().positive().max(1e4).optional()
|
|
971
|
+
})
|
|
972
|
+
).min(1).max(20),
|
|
973
|
+
kind: z.literal("purchase-items"),
|
|
974
|
+
totals: z.array(
|
|
975
|
+
z.object({
|
|
976
|
+
amount: z.number().finite().nonnegative().max(1e9),
|
|
977
|
+
emphasis: z.boolean().optional(),
|
|
978
|
+
label: shortText
|
|
979
|
+
})
|
|
980
|
+
).min(1).max(8)
|
|
981
|
+
}),
|
|
982
|
+
radar: base.extend({
|
|
983
|
+
angleKey: key,
|
|
984
|
+
data: z.array(datum).min(3).max(50),
|
|
985
|
+
kind: z.literal("radar-chart"),
|
|
986
|
+
series: z.array(series).min(1).max(5)
|
|
987
|
+
}),
|
|
988
|
+
radial: proportional.extend({
|
|
989
|
+
endAngle: z.number().min(-360).max(360).optional(),
|
|
990
|
+
kind: z.literal("radial-chart"),
|
|
991
|
+
maxValue: z.number().positive().optional(),
|
|
992
|
+
startAngle: z.number().min(-360).max(360).optional()
|
|
993
|
+
}),
|
|
994
|
+
recordCard: base.extend({
|
|
995
|
+
actions: z.array(action).max(4).optional(),
|
|
996
|
+
eyebrow: z.string().trim().max(100).optional(),
|
|
997
|
+
fields: z.array(
|
|
998
|
+
z.object({
|
|
999
|
+
icon: agentIconSchema.optional(),
|
|
1000
|
+
label: shortText,
|
|
1001
|
+
tone: recordTone.optional(),
|
|
1002
|
+
value: z.string().trim().min(1).max(500)
|
|
1003
|
+
})
|
|
1004
|
+
).max(12),
|
|
1005
|
+
image: z.object({ alt: shortText, src: displayImageSrc }).optional(),
|
|
1006
|
+
kind: z.literal("record-card"),
|
|
1007
|
+
layout: recordCardLayoutSchema.optional(),
|
|
1008
|
+
status: z.object({
|
|
1009
|
+
label: shortText,
|
|
1010
|
+
tone: recordTone.optional()
|
|
1011
|
+
}).optional(),
|
|
1012
|
+
variant: cardComponentVariantSchema.optional()
|
|
1013
|
+
}).superRefine((card, ctx) => {
|
|
1014
|
+
if (card.layout === "media" && !card.image) {
|
|
1015
|
+
ctx.addIssue({
|
|
1016
|
+
code: "custom",
|
|
1017
|
+
message: "The media record layout requires an image",
|
|
1018
|
+
path: ["image"]
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
if (card.layout === "compact" && card.fields.length > 4) {
|
|
1022
|
+
ctx.addIssue({
|
|
1023
|
+
code: "custom",
|
|
1024
|
+
message: "The compact record layout supports at most four fields",
|
|
1025
|
+
path: ["fields"]
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
}),
|
|
1029
|
+
rideStatus: base.extend({
|
|
1030
|
+
driver: z.object({ image: agentUIImage.optional(), name: shortText }),
|
|
1031
|
+
eta: z.string().trim().min(1).max(80),
|
|
1032
|
+
kind: z.literal("ride-status"),
|
|
1033
|
+
pickup: shortText
|
|
1034
|
+
}),
|
|
1035
|
+
sankey: base.extend({
|
|
1036
|
+
format: numberFormatSchema.optional(),
|
|
1037
|
+
kind: z.literal("sankey-chart"),
|
|
1038
|
+
links: z.array(z.object({ source: id, target: id, value: z.number().positive() })).min(1).max(100),
|
|
1039
|
+
nodes: z.array(z.object({ id, label: shortText })).min(2).max(40)
|
|
1040
|
+
}),
|
|
1041
|
+
scatter,
|
|
1042
|
+
steps: base.extend({
|
|
1043
|
+
kind: z.literal("steps"),
|
|
1044
|
+
steps: z.array(
|
|
1045
|
+
z.object({
|
|
1046
|
+
content: shortText.optional(),
|
|
1047
|
+
icon: agentIconSchema.optional(),
|
|
1048
|
+
id,
|
|
1049
|
+
image: agentUIImage.optional().describe(
|
|
1050
|
+
"A representative raster image for this step. Prefer this over icon for place itineraries when a trusted image URL is available."
|
|
1051
|
+
),
|
|
1052
|
+
meta: z.string().trim().max(100).optional(),
|
|
1053
|
+
progress: z.number().min(0).max(100).optional(),
|
|
1054
|
+
status: z.enum([
|
|
1055
|
+
"blocked",
|
|
1056
|
+
"cancelled",
|
|
1057
|
+
"completed",
|
|
1058
|
+
"failed",
|
|
1059
|
+
"in-progress",
|
|
1060
|
+
"pending",
|
|
1061
|
+
"complete",
|
|
1062
|
+
"current",
|
|
1063
|
+
"upcoming"
|
|
1064
|
+
]).optional(),
|
|
1065
|
+
timestamp: z.string().trim().max(100).optional(),
|
|
1066
|
+
title: shortText
|
|
1067
|
+
})
|
|
1068
|
+
).min(1).max(12),
|
|
1069
|
+
variant: z.enum(["steps", "timeline"]).optional()
|
|
1070
|
+
}),
|
|
1071
|
+
switches: base.extend({
|
|
1072
|
+
items: z.array(
|
|
1073
|
+
z.object({
|
|
1074
|
+
defaultSelected: z.boolean().optional(),
|
|
1075
|
+
description: shortText.optional(),
|
|
1076
|
+
id,
|
|
1077
|
+
label: shortText
|
|
1078
|
+
})
|
|
1079
|
+
).min(1).max(20),
|
|
1080
|
+
kind: z.literal("switch-group")
|
|
1081
|
+
}),
|
|
1082
|
+
table: base.extend({
|
|
1083
|
+
columns: z.array(z.object({ format: numberFormatSchema.optional(), key, label: shortText })).min(1).max(12),
|
|
1084
|
+
filterable: z.boolean().optional(),
|
|
1085
|
+
kind: z.literal("data-table"),
|
|
1086
|
+
rows: z.array(datum).max(200),
|
|
1087
|
+
variant: z.enum(["primary", "secondary"]).optional()
|
|
1088
|
+
}),
|
|
1089
|
+
tabs: base.extend({
|
|
1090
|
+
defaultValue: id.optional(),
|
|
1091
|
+
kind: z.literal("tabs"),
|
|
1092
|
+
tabs: z.array(
|
|
1093
|
+
z.union([
|
|
1094
|
+
z.object({
|
|
1095
|
+
children: z.never().optional(),
|
|
1096
|
+
content,
|
|
1097
|
+
id,
|
|
1098
|
+
label: shortText
|
|
1099
|
+
}),
|
|
1100
|
+
z.object({
|
|
1101
|
+
children: z.array(z.lazy(() => agentUINodeSchema)).min(1).max(12),
|
|
1102
|
+
content: z.never().optional(),
|
|
1103
|
+
id,
|
|
1104
|
+
label: shortText
|
|
1105
|
+
})
|
|
1106
|
+
])
|
|
1107
|
+
).min(1).max(10),
|
|
1108
|
+
variant: z.enum(["primary", "secondary"]).optional()
|
|
1109
|
+
}),
|
|
1110
|
+
tags: base.extend({ kind: z.literal("tag-list"), tags: z.array(shortText).min(1).max(30) }),
|
|
1111
|
+
text: base.extend({
|
|
1112
|
+
content,
|
|
1113
|
+
kind: z.literal("text"),
|
|
1114
|
+
variant: z.enum(["card", "clear"]).optional()
|
|
1115
|
+
}),
|
|
1116
|
+
toggles: base.extend({
|
|
1117
|
+
defaultValue: z.array(id).max(12).optional(),
|
|
1118
|
+
items: z.array(z.object({ id, label: shortText })).min(1).max(12),
|
|
1119
|
+
kind: z.literal("toggle-group"),
|
|
1120
|
+
selectionMode: z.enum(["multiple", "single"]).optional()
|
|
1121
|
+
}),
|
|
1122
|
+
viewEvent: base.extend({
|
|
1123
|
+
date: z.string().trim().min(1).max(80),
|
|
1124
|
+
kind: z.literal("view-event"),
|
|
1125
|
+
time: z.string().trim().min(1).max(80),
|
|
1126
|
+
tone: recordTone.optional()
|
|
1127
|
+
}),
|
|
1128
|
+
weatherCurrent: base.extend({
|
|
1129
|
+
condition: weatherConditionSchema,
|
|
1130
|
+
details: z.array(z.object({ label: shortText, value: shortText })).max(6).optional(),
|
|
1131
|
+
kind: z.literal("weather-current"),
|
|
1132
|
+
location: shortText,
|
|
1133
|
+
temperature: z.number().finite().min(-150).max(150),
|
|
1134
|
+
unit: weatherUnit
|
|
1135
|
+
}),
|
|
1136
|
+
weatherForecast: base.extend({
|
|
1137
|
+
condition: weatherConditionSchema,
|
|
1138
|
+
forecast: z.array(
|
|
1139
|
+
z.object({
|
|
1140
|
+
condition: weatherConditionSchema,
|
|
1141
|
+
label: z.string().trim().min(1).max(40),
|
|
1142
|
+
temperature: z.number().finite().min(-150).max(150)
|
|
1143
|
+
})
|
|
1144
|
+
).min(2).max(10),
|
|
1145
|
+
high: z.number().finite().min(-150).max(150),
|
|
1146
|
+
kind: z.literal("weather-forecast"),
|
|
1147
|
+
location: shortText,
|
|
1148
|
+
low: z.number().finite().min(-150).max(150),
|
|
1149
|
+
unit: weatherUnit
|
|
1150
|
+
})
|
|
1151
|
+
};
|
|
1152
|
+
var metricGridComponentSchema = validators.metricGrid;
|
|
1153
|
+
var kpiGridComponentSchema = validators.kpiGrid;
|
|
1154
|
+
var lineChartComponentSchema = validators.line;
|
|
1155
|
+
var areaChartComponentSchema = validators.area;
|
|
1156
|
+
var barChartComponentSchema = validators.bar;
|
|
1157
|
+
var composedChartComponentSchema = validators.composed;
|
|
1158
|
+
var pieChartComponentSchema = validators.pie;
|
|
1159
|
+
var donutChartComponentSchema = validators.donut;
|
|
1160
|
+
var radarChartComponentSchema = validators.radar;
|
|
1161
|
+
var radialChartComponentSchema = validators.radial;
|
|
1162
|
+
var sankeyChartComponentSchema = validators.sankey;
|
|
1163
|
+
var scatterChartComponentSchema = validators.scatter;
|
|
1164
|
+
var heatmapComponentSchema = validators.heatmap;
|
|
1165
|
+
var dataTableComponentSchema = validators.table;
|
|
1166
|
+
var comparisonListComponentSchema = validators.comparison;
|
|
1167
|
+
var meterListComponentSchema = validators.meterList;
|
|
1168
|
+
var formComponentSchema = validators.form;
|
|
1169
|
+
var textComponentSchema = validators.text;
|
|
1170
|
+
var calloutComponentSchema = validators.callout;
|
|
1171
|
+
var imageComponentSchema = validators.image;
|
|
1172
|
+
var mapComponentSchema = validators.map;
|
|
1173
|
+
var tagListComponentSchema = validators.tags;
|
|
1174
|
+
var listComponentSchema = validators.list;
|
|
1175
|
+
var listBlockComponentSchema = validators.listBlock;
|
|
1176
|
+
var accordionComponentSchema = validators.accordion;
|
|
1177
|
+
var stepsComponentSchema = validators.steps;
|
|
1178
|
+
var codeBlockComponentSchema = validators.code;
|
|
1179
|
+
var diagramComponentSchema = validators.diagram;
|
|
1180
|
+
var tabsComponentSchema = validators.tabs.superRefine(validateTabsComponent);
|
|
1181
|
+
var actionGroupComponentSchema = validators.actions;
|
|
1182
|
+
var followupComponentSchema = validators.followup;
|
|
1183
|
+
var switchGroupComponentSchema = validators.switches;
|
|
1184
|
+
var toggleGroupComponentSchema = validators.toggles;
|
|
1185
|
+
var recordCardComponentSchema = validators.recordCard;
|
|
1186
|
+
var productCardComponentSchema = validators.productCard;
|
|
1187
|
+
var flightTrackerComponentSchema = validators.flightTracker;
|
|
1188
|
+
var createEventComponentSchema = validators.createEvent;
|
|
1189
|
+
var playlistComponentSchema = validators.playlist;
|
|
1190
|
+
var rideStatusComponentSchema = validators.rideStatus;
|
|
1191
|
+
var purchaseItemsComponentSchema = validators.purchaseItems;
|
|
1192
|
+
var channelMessageComponentSchema = validators.channelMessage;
|
|
1193
|
+
var purchaseCompleteComponentSchema = validators.purchaseComplete;
|
|
1194
|
+
var playerCardComponentSchema = validators.playerCard;
|
|
1195
|
+
var viewEventComponentSchema = validators.viewEvent;
|
|
1196
|
+
var eventSessionComponentSchema = validators.eventSession;
|
|
1197
|
+
var enableNotificationComponentSchema = validators.enableNotification;
|
|
1198
|
+
var weatherForecastComponentSchema = validators.weatherForecast;
|
|
1199
|
+
var weatherCurrentComponentSchema = validators.weatherCurrent;
|
|
1200
|
+
var analyticalLeafComponentSchema = z.discriminatedUnion("kind", [
|
|
1201
|
+
validators.metricGrid,
|
|
1202
|
+
validators.kpiGrid,
|
|
1203
|
+
validators.line,
|
|
1204
|
+
validators.area,
|
|
1205
|
+
validators.bar,
|
|
1206
|
+
validators.composed,
|
|
1207
|
+
validators.pie,
|
|
1208
|
+
validators.donut,
|
|
1209
|
+
validators.radar,
|
|
1210
|
+
validators.radial,
|
|
1211
|
+
validators.sankey,
|
|
1212
|
+
validators.scatter,
|
|
1213
|
+
validators.heatmap,
|
|
1214
|
+
validators.table,
|
|
1215
|
+
validators.comparison,
|
|
1216
|
+
validators.meterList
|
|
1217
|
+
]);
|
|
1218
|
+
var productSignalsShape = base.extend({
|
|
1219
|
+
defaultValue: id.optional(),
|
|
1220
|
+
kind: z.literal("product-signals"),
|
|
1221
|
+
tabs: z.array(z.object({ component: analyticalLeafComponentSchema, id, label: shortText })).min(2).max(4)
|
|
1222
|
+
});
|
|
1223
|
+
var productSignalsComponentSchema = productSignalsShape.superRefine((signals, ctx) => {
|
|
1224
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1225
|
+
for (const [index, tab] of signals.tabs.entries()) {
|
|
1226
|
+
if (ids.has(tab.id)) {
|
|
1227
|
+
ctx.addIssue({
|
|
1228
|
+
code: "custom",
|
|
1229
|
+
message: `Duplicate product signal tab id "${tab.id}"`,
|
|
1230
|
+
path: ["tabs", index, "id"]
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
ids.add(tab.id);
|
|
1234
|
+
}
|
|
1235
|
+
if (signals.defaultValue && !ids.has(signals.defaultValue)) {
|
|
1236
|
+
ctx.addIssue({
|
|
1237
|
+
code: "custom",
|
|
1238
|
+
message: "The default product signal must reference one of the tabs",
|
|
1239
|
+
path: ["defaultValue"]
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
});
|
|
1243
|
+
var standardAgentUILeafComponentSchema = z.discriminatedUnion("kind", [
|
|
1244
|
+
validators.metricGrid,
|
|
1245
|
+
validators.kpiGrid,
|
|
1246
|
+
validators.line,
|
|
1247
|
+
validators.area,
|
|
1248
|
+
validators.bar,
|
|
1249
|
+
validators.composed,
|
|
1250
|
+
validators.pie,
|
|
1251
|
+
validators.donut,
|
|
1252
|
+
validators.radar,
|
|
1253
|
+
validators.radial,
|
|
1254
|
+
validators.sankey,
|
|
1255
|
+
validators.scatter,
|
|
1256
|
+
validators.heatmap,
|
|
1257
|
+
validators.table,
|
|
1258
|
+
validators.comparison,
|
|
1259
|
+
validators.meterList,
|
|
1260
|
+
validators.form,
|
|
1261
|
+
validators.text,
|
|
1262
|
+
validators.callout,
|
|
1263
|
+
validators.image,
|
|
1264
|
+
validators.map,
|
|
1265
|
+
validators.tags,
|
|
1266
|
+
validators.list,
|
|
1267
|
+
validators.listBlock,
|
|
1268
|
+
validators.accordion,
|
|
1269
|
+
validators.steps,
|
|
1270
|
+
validators.code,
|
|
1271
|
+
validators.diagram,
|
|
1272
|
+
validators.tabs,
|
|
1273
|
+
validators.actions,
|
|
1274
|
+
validators.followup,
|
|
1275
|
+
validators.switches,
|
|
1276
|
+
validators.toggles,
|
|
1277
|
+
validators.recordCard,
|
|
1278
|
+
validators.productCard,
|
|
1279
|
+
validators.flightTracker,
|
|
1280
|
+
validators.createEvent,
|
|
1281
|
+
validators.playlist,
|
|
1282
|
+
validators.rideStatus,
|
|
1283
|
+
validators.purchaseItems,
|
|
1284
|
+
validators.channelMessage,
|
|
1285
|
+
validators.purchaseComplete,
|
|
1286
|
+
validators.playerCard,
|
|
1287
|
+
validators.viewEvent,
|
|
1288
|
+
validators.eventSession,
|
|
1289
|
+
validators.enableNotification,
|
|
1290
|
+
validators.weatherForecast,
|
|
1291
|
+
validators.weatherCurrent
|
|
1292
|
+
]);
|
|
1293
|
+
function findDuplicateId(items) {
|
|
1294
|
+
if (!items) return void 0;
|
|
1295
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1296
|
+
for (const item of items) {
|
|
1297
|
+
if (ids.has(item.id)) return item.id;
|
|
1298
|
+
ids.add(item.id);
|
|
1299
|
+
}
|
|
1300
|
+
return void 0;
|
|
1301
|
+
}
|
|
1302
|
+
var agentUILeafComponentSchema = z.union([standardAgentUILeafComponentSchema, productSignalsComponentSchema]).superRefine((component, ctx) => {
|
|
1303
|
+
const collections = [];
|
|
1304
|
+
switch (component.kind) {
|
|
1305
|
+
case "channel-message":
|
|
1306
|
+
collections.push({ items: component.attachments, path: "attachments" });
|
|
1307
|
+
break;
|
|
1308
|
+
case "create-event":
|
|
1309
|
+
collections.push({ items: component.events, path: "events" });
|
|
1310
|
+
collections.push({ items: component.actions, path: "actions" });
|
|
1311
|
+
break;
|
|
1312
|
+
case "enable-notification":
|
|
1313
|
+
collections.push({ items: component.actions, path: "actions" });
|
|
1314
|
+
break;
|
|
1315
|
+
case "playlist":
|
|
1316
|
+
collections.push({ items: component.tracks, path: "tracks" });
|
|
1317
|
+
collections.push({ items: component.actions, path: "actions" });
|
|
1318
|
+
break;
|
|
1319
|
+
case "purchase-items":
|
|
1320
|
+
collections.push({ items: component.items, path: "items" });
|
|
1321
|
+
collections.push({ items: component.actions, path: "actions" });
|
|
1322
|
+
break;
|
|
1323
|
+
case "tabs": {
|
|
1324
|
+
validateTabsComponent(component, ctx);
|
|
1325
|
+
break;
|
|
1326
|
+
}
|
|
1327
|
+
default:
|
|
1328
|
+
break;
|
|
1329
|
+
}
|
|
1330
|
+
for (const collection of collections) {
|
|
1331
|
+
const duplicateId = findDuplicateId(collection.items);
|
|
1332
|
+
if (duplicateId) {
|
|
1333
|
+
ctx.addIssue({
|
|
1334
|
+
code: "custom",
|
|
1335
|
+
message: `Duplicate ${collection.path} id "${duplicateId}"`,
|
|
1336
|
+
path: [collection.path]
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1341
|
+
var dashboardShape = base.extend({
|
|
1342
|
+
children: z.array(agentUILeafComponentSchema).min(1).max(4),
|
|
1343
|
+
kind: z.literal("dashboard"),
|
|
1344
|
+
layout: z.enum(["chart-table", "grid", "metrics-chart", "stack"])
|
|
1345
|
+
});
|
|
1346
|
+
var dashboardComponentSchema = dashboardShape;
|
|
1347
|
+
var agentUIComponentSchema = z.union([
|
|
1348
|
+
agentUILeafComponentSchema,
|
|
1349
|
+
dashboardComponentSchema
|
|
1350
|
+
]);
|
|
1351
|
+
var renderComponentInputSchema = z.object({
|
|
1352
|
+
component: agentUIComponentSchema
|
|
1353
|
+
});
|
|
1354
|
+
var COMPOSED_UI_MAX_DEPTH = 6;
|
|
1355
|
+
var COMPOSED_UI_MAX_NODES = 48;
|
|
1356
|
+
var CONTAINER_KINDS = /* @__PURE__ */ new Set([
|
|
1357
|
+
"card",
|
|
1358
|
+
"col",
|
|
1359
|
+
"grid",
|
|
1360
|
+
"item-card",
|
|
1361
|
+
"item-card-group",
|
|
1362
|
+
"row"
|
|
1363
|
+
]);
|
|
1364
|
+
var LAYOUT_LEAF_KINDS = /* @__PURE__ */ new Set(["divider", "spacer"]);
|
|
1365
|
+
var PRIMITIVE_KINDS = /* @__PURE__ */ new Set([
|
|
1366
|
+
"badge",
|
|
1367
|
+
"button",
|
|
1368
|
+
"heading",
|
|
1369
|
+
"icon",
|
|
1370
|
+
"progress",
|
|
1371
|
+
"rating"
|
|
1372
|
+
]);
|
|
1373
|
+
var AGENT_UI_CONTAINER_KINDS = CONTAINER_KINDS;
|
|
1374
|
+
var AGENT_UI_LAYOUT_LEAF_KINDS = LAYOUT_LEAF_KINDS;
|
|
1375
|
+
var AGENT_UI_PRIMITIVE_KINDS = PRIMITIVE_KINDS;
|
|
1376
|
+
function isAgentUIContainerComponent(node) {
|
|
1377
|
+
return CONTAINER_KINDS.has(node.kind);
|
|
1378
|
+
}
|
|
1379
|
+
function getAgentUIContainerChildren(node) {
|
|
1380
|
+
if (node.kind === "item-card") {
|
|
1381
|
+
return [...node.left ?? [], ...node.middle, ...node.right ?? []];
|
|
1382
|
+
}
|
|
1383
|
+
return node.children;
|
|
1384
|
+
}
|
|
1385
|
+
function isAgentUILayoutLeafComponent(node) {
|
|
1386
|
+
return LAYOUT_LEAF_KINDS.has(node.kind);
|
|
1387
|
+
}
|
|
1388
|
+
function isAgentUIPrimitiveComponent(node) {
|
|
1389
|
+
return PRIMITIVE_KINDS.has(node.kind);
|
|
1390
|
+
}
|
|
1391
|
+
var layoutBase = z.object({ id });
|
|
1392
|
+
var layoutGap = z.enum(["lg", "md", "none", "sm"]);
|
|
1393
|
+
var layoutAlign = z.enum(["center", "end", "start", "stretch"]);
|
|
1394
|
+
var layoutJustify = z.enum(["between", "center", "end", "start"]);
|
|
1395
|
+
var nodeChildren = z.array(z.lazy(() => agentUINodeSchema)).min(1).max(COMPOSED_UI_MAX_NODES);
|
|
1396
|
+
var spacerComponentSchema = layoutBase.extend({
|
|
1397
|
+
kind: z.literal("spacer"),
|
|
1398
|
+
size: z.enum(["auto", "lg", "md", "sm"]).optional()
|
|
1399
|
+
});
|
|
1400
|
+
var dividerComponentSchema = layoutBase.extend({
|
|
1401
|
+
kind: z.literal("divider")
|
|
1402
|
+
});
|
|
1403
|
+
var headingComponentSchema = layoutBase.extend({
|
|
1404
|
+
icon: agentIconSchema.optional(),
|
|
1405
|
+
kind: z.literal("heading"),
|
|
1406
|
+
level: z.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)]).optional(),
|
|
1407
|
+
text: shortText
|
|
1408
|
+
});
|
|
1409
|
+
var buttonComponentSchema = layoutBase.extend({
|
|
1410
|
+
icon: agentIconSchema.optional(),
|
|
1411
|
+
kind: z.literal("button"),
|
|
1412
|
+
label: shortText,
|
|
1413
|
+
prompt: z.string().trim().min(1).max(2e3).optional(),
|
|
1414
|
+
toolCall: actionToolCall.optional(),
|
|
1415
|
+
variant: actionVariant.optional()
|
|
1416
|
+
}).refine((button) => Boolean(button.prompt ?? button.toolCall), {
|
|
1417
|
+
message: "Buttons need a prompt or a toolCall to do something when pressed"
|
|
1418
|
+
});
|
|
1419
|
+
var badgeComponentSchema = layoutBase.extend({
|
|
1420
|
+
kind: z.literal("badge"),
|
|
1421
|
+
label: shortText,
|
|
1422
|
+
tone: recordTone.optional(),
|
|
1423
|
+
variant: z.enum(["soft", "solid"]).optional()
|
|
1424
|
+
});
|
|
1425
|
+
var iconComponentSchema = layoutBase.extend({
|
|
1426
|
+
kind: z.literal("icon"),
|
|
1427
|
+
name: agentIconSchema,
|
|
1428
|
+
size: z.enum(["lg", "md", "sm"]).optional(),
|
|
1429
|
+
tone: recordTone.optional()
|
|
1430
|
+
});
|
|
1431
|
+
var ratingComponentSchema = layoutBase.extend({
|
|
1432
|
+
count: z.number().int().nonnegative().max(1e9).optional(),
|
|
1433
|
+
kind: z.literal("rating"),
|
|
1434
|
+
value: z.number().finite().min(0).max(5)
|
|
1435
|
+
});
|
|
1436
|
+
var progressComponentSchema = layoutBase.extend({
|
|
1437
|
+
kind: z.literal("progress"),
|
|
1438
|
+
label: shortText.optional(),
|
|
1439
|
+
value: z.number().finite().min(0).max(100)
|
|
1440
|
+
});
|
|
1441
|
+
var itemCardVariant = z.enum(["default", "outline", "secondary", "tertiary", "transparent"]);
|
|
1442
|
+
var itemCardSlotNode = z.lazy(() => agentUINodeSchema);
|
|
1443
|
+
var itemCardShape = base.extend({
|
|
1444
|
+
action: action.optional().describe(
|
|
1445
|
+
"Makes the whole row pressable. Omit when a slot contains its own button or other interactive control."
|
|
1446
|
+
),
|
|
1447
|
+
isDisabled: z.boolean().optional(),
|
|
1448
|
+
isSelected: z.boolean().optional(),
|
|
1449
|
+
kind: z.literal("item-card"),
|
|
1450
|
+
left: z.array(itemCardSlotNode).min(1).max(4).optional().describe("Leading slot. Prefer one icon node or a compact visual."),
|
|
1451
|
+
middle: z.array(itemCardSlotNode).min(1).max(8).describe(
|
|
1452
|
+
"Primary flexible slot. Prefer a level-4 heading followed by a clear text node for a title and description."
|
|
1453
|
+
),
|
|
1454
|
+
right: z.array(itemCardSlotNode).min(1).max(4).optional().describe("Trailing slot. Prefer a badge, short value, icon, or button."),
|
|
1455
|
+
variant: itemCardVariant.optional()
|
|
1456
|
+
});
|
|
1457
|
+
var INTERACTIVE_ITEM_CARD_DESCENDANT_KINDS = /* @__PURE__ */ new Set([
|
|
1458
|
+
"accordion",
|
|
1459
|
+
"action-group",
|
|
1460
|
+
"button",
|
|
1461
|
+
"followup",
|
|
1462
|
+
"form",
|
|
1463
|
+
"map",
|
|
1464
|
+
"switch-group",
|
|
1465
|
+
"tabs",
|
|
1466
|
+
"toggle-group"
|
|
1467
|
+
]);
|
|
1468
|
+
function containsInteractiveItemCardDescendant(nodes) {
|
|
1469
|
+
for (const node of nodes) {
|
|
1470
|
+
if (INTERACTIVE_ITEM_CARD_DESCENDANT_KINDS.has(node.kind)) return true;
|
|
1471
|
+
if (isAgentUIContainerComponent(node) && containsInteractiveItemCardDescendant(getAgentUIContainerChildren(node))) {
|
|
1472
|
+
return true;
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
return false;
|
|
1476
|
+
}
|
|
1477
|
+
var itemCardComponentSchema = itemCardShape.superRefine(
|
|
1478
|
+
(card, ctx) => {
|
|
1479
|
+
if (card.action && containsInteractiveItemCardDescendant([
|
|
1480
|
+
...card.left ?? [],
|
|
1481
|
+
...card.middle,
|
|
1482
|
+
...card.right ?? []
|
|
1483
|
+
])) {
|
|
1484
|
+
ctx.addIssue({
|
|
1485
|
+
code: "custom",
|
|
1486
|
+
message: "A pressable item-card cannot contain buttons or other interactive descendants. Remove action from the card or move the nested control outside it."
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
);
|
|
1491
|
+
var itemCardGroupShape = base.extend({
|
|
1492
|
+
children: z.array(itemCardComponentSchema).min(1).max(12),
|
|
1493
|
+
columns: z.union([z.literal(2), z.literal(3)]).optional(),
|
|
1494
|
+
kind: z.literal("item-card-group"),
|
|
1495
|
+
layout: z.enum(["grid", "list"]).optional(),
|
|
1496
|
+
showHeader: z.boolean().optional(),
|
|
1497
|
+
variant: itemCardVariant.optional()
|
|
1498
|
+
});
|
|
1499
|
+
var itemCardGroupComponentSchema = itemCardGroupShape.superRefine((group2, ctx) => {
|
|
1500
|
+
if (group2.columns && group2.layout !== "grid") {
|
|
1501
|
+
ctx.addIssue({
|
|
1502
|
+
code: "custom",
|
|
1503
|
+
message: "Item-card group columns only apply when layout is grid.",
|
|
1504
|
+
path: ["columns"]
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
var rowShape = layoutBase.extend({
|
|
1509
|
+
align: layoutAlign.optional(),
|
|
1510
|
+
children: nodeChildren,
|
|
1511
|
+
gap: layoutGap.optional(),
|
|
1512
|
+
justify: layoutJustify.optional(),
|
|
1513
|
+
kind: z.literal("row")
|
|
1514
|
+
});
|
|
1515
|
+
var colShape = layoutBase.extend({
|
|
1516
|
+
align: layoutAlign.optional(),
|
|
1517
|
+
children: nodeChildren,
|
|
1518
|
+
gap: layoutGap.optional(),
|
|
1519
|
+
justify: layoutJustify.optional(),
|
|
1520
|
+
kind: z.literal("col")
|
|
1521
|
+
});
|
|
1522
|
+
var gridShape = layoutBase.extend({
|
|
1523
|
+
children: nodeChildren,
|
|
1524
|
+
columns: z.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)]),
|
|
1525
|
+
gap: layoutGap.optional(),
|
|
1526
|
+
kind: z.literal("grid")
|
|
1527
|
+
});
|
|
1528
|
+
var cardShape = base.extend({
|
|
1529
|
+
children: nodeChildren,
|
|
1530
|
+
kind: z.literal("card"),
|
|
1531
|
+
variant: cardComponentVariantSchema.optional()
|
|
1532
|
+
});
|
|
1533
|
+
var rowComponentSchema = rowShape;
|
|
1534
|
+
var colComponentSchema = colShape;
|
|
1535
|
+
var gridComponentSchema = gridShape;
|
|
1536
|
+
var cardComponentSchema = cardShape;
|
|
1537
|
+
var agentUINodeSchema = z.union([
|
|
1538
|
+
agentUILeafComponentSchema,
|
|
1539
|
+
spacerComponentSchema,
|
|
1540
|
+
dividerComponentSchema,
|
|
1541
|
+
headingComponentSchema,
|
|
1542
|
+
buttonComponentSchema,
|
|
1543
|
+
badgeComponentSchema,
|
|
1544
|
+
iconComponentSchema,
|
|
1545
|
+
ratingComponentSchema,
|
|
1546
|
+
progressComponentSchema,
|
|
1547
|
+
rowComponentSchema,
|
|
1548
|
+
colComponentSchema,
|
|
1549
|
+
gridComponentSchema,
|
|
1550
|
+
cardComponentSchema,
|
|
1551
|
+
itemCardComponentSchema,
|
|
1552
|
+
itemCardGroupComponentSchema
|
|
1553
|
+
]);
|
|
1554
|
+
function validateComposedTree(root, ctx) {
|
|
1555
|
+
validateNodeTree(root, ctx);
|
|
1556
|
+
}
|
|
1557
|
+
function validateTabContentTrees(component, ctx) {
|
|
1558
|
+
const richChildren = component.tabs.flatMap((tab) => tab.children ?? []);
|
|
1559
|
+
if (richChildren.length === 0) return;
|
|
1560
|
+
validateNodeForest(richChildren, ctx, component.id, 2, 1);
|
|
1561
|
+
}
|
|
1562
|
+
function validateTabsComponent(component, ctx) {
|
|
1563
|
+
const tabIds = /* @__PURE__ */ new Set();
|
|
1564
|
+
for (const [index, tab] of component.tabs.entries()) {
|
|
1565
|
+
if (tabIds.has(tab.id)) {
|
|
1566
|
+
ctx.addIssue({
|
|
1567
|
+
code: "custom",
|
|
1568
|
+
message: `Duplicate tab id "${tab.id}"`,
|
|
1569
|
+
path: ["tabs", index, "id"]
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
tabIds.add(tab.id);
|
|
1573
|
+
}
|
|
1574
|
+
if (component.defaultValue && !tabIds.has(component.defaultValue)) {
|
|
1575
|
+
ctx.addIssue({
|
|
1576
|
+
code: "custom",
|
|
1577
|
+
message: "The default tab must reference one of the tabs",
|
|
1578
|
+
path: ["defaultValue"]
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
validateTabContentTrees(component, ctx);
|
|
1582
|
+
}
|
|
1583
|
+
function nestedNodeChildren(node) {
|
|
1584
|
+
if (isAgentUIContainerComponent(node)) return getAgentUIContainerChildren(node);
|
|
1585
|
+
if (node.kind === "tabs") return node.tabs.flatMap((tab) => tab.children ?? []);
|
|
1586
|
+
return [];
|
|
1587
|
+
}
|
|
1588
|
+
function validateNodeForest(roots, ctx, reservedRootId, initialDepth = 1, initialNodeCount = 0) {
|
|
1589
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1590
|
+
let nodeCount = initialNodeCount;
|
|
1591
|
+
let deepest = initialNodeCount > 0 ? initialDepth - 1 : 0;
|
|
1592
|
+
if (reservedRootId) ids.add(reservedRootId);
|
|
1593
|
+
const walk = (node, depth) => {
|
|
1594
|
+
nodeCount += 1;
|
|
1595
|
+
deepest = Math.max(deepest, depth);
|
|
1596
|
+
if (ids.has(node.id)) {
|
|
1597
|
+
ctx.addIssue({
|
|
1598
|
+
code: "custom",
|
|
1599
|
+
message: `Duplicate component id "${node.id}" in the composed UI tree. Every node needs a unique id.`
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
ids.add(node.id);
|
|
1603
|
+
if (depth > COMPOSED_UI_MAX_DEPTH) return;
|
|
1604
|
+
for (const child of nestedNodeChildren(node)) walk(child, depth + 1);
|
|
1605
|
+
};
|
|
1606
|
+
for (const root of roots) walk(root, initialDepth);
|
|
1607
|
+
if (deepest > COMPOSED_UI_MAX_DEPTH) {
|
|
1608
|
+
ctx.addIssue({
|
|
1609
|
+
code: "custom",
|
|
1610
|
+
message: `Composed UI trees can nest at most ${COMPOSED_UI_MAX_DEPTH} levels deep.`
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
if (nodeCount > COMPOSED_UI_MAX_NODES) {
|
|
1614
|
+
ctx.addIssue({
|
|
1615
|
+
code: "custom",
|
|
1616
|
+
message: `Composed UI trees can contain at most ${COMPOSED_UI_MAX_NODES} components.`
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
function validateNodeTree(root, ctx) {
|
|
1621
|
+
validateNodeForest([root], ctx);
|
|
1622
|
+
}
|
|
1623
|
+
var composedUIComponentSchema = z.union([
|
|
1624
|
+
rowComponentSchema,
|
|
1625
|
+
colComponentSchema,
|
|
1626
|
+
gridComponentSchema,
|
|
1627
|
+
cardComponentSchema,
|
|
1628
|
+
itemCardComponentSchema,
|
|
1629
|
+
itemCardGroupComponentSchema
|
|
1630
|
+
]).superRefine(validateComposedTree);
|
|
1631
|
+
var agentUIRenderableSchema = z.union([
|
|
1632
|
+
agentUIComponentSchema,
|
|
1633
|
+
composedUIComponentSchema
|
|
1634
|
+
]);
|
|
1635
|
+
var composeUIInputSchema = z.object({
|
|
1636
|
+
component: composedUIComponentSchema
|
|
1637
|
+
});
|
|
1638
|
+
var opaqueChildren = (max) => z.array(z.unknown()).min(1).max(max).describe("Child nodes. Each is any catalog component; look its kind up separately.");
|
|
1639
|
+
var AGENT_UI_KIND_SCHEMAS = {
|
|
1640
|
+
accordion: accordionComponentSchema,
|
|
1641
|
+
"action-group": actionGroupComponentSchema,
|
|
1642
|
+
"area-chart": areaChartComponentSchema,
|
|
1643
|
+
badge: badgeComponentSchema,
|
|
1644
|
+
"bar-chart": barChartComponentSchema,
|
|
1645
|
+
button: buttonComponentSchema,
|
|
1646
|
+
callout: calloutComponentSchema,
|
|
1647
|
+
card: cardShape.extend({ children: opaqueChildren(COMPOSED_UI_MAX_NODES) }),
|
|
1648
|
+
"channel-message": channelMessageComponentSchema,
|
|
1649
|
+
"code-block": codeBlockComponentSchema,
|
|
1650
|
+
col: colShape.extend({ children: opaqueChildren(COMPOSED_UI_MAX_NODES) }),
|
|
1651
|
+
"comparison-list": comparisonListComponentSchema,
|
|
1652
|
+
"composed-chart": composedChartComponentSchema,
|
|
1653
|
+
"create-event": createEventComponentSchema,
|
|
1654
|
+
dashboard: dashboardShape.extend({ children: opaqueChildren(4) }),
|
|
1655
|
+
"data-table": dataTableComponentSchema,
|
|
1656
|
+
diagram: diagramComponentSchema,
|
|
1657
|
+
divider: dividerComponentSchema,
|
|
1658
|
+
"donut-chart": donutChartComponentSchema,
|
|
1659
|
+
"enable-notification": enableNotificationComponentSchema,
|
|
1660
|
+
"event-session": eventSessionComponentSchema,
|
|
1661
|
+
"flight-tracker": flightTrackerComponentSchema,
|
|
1662
|
+
followup: followupComponentSchema,
|
|
1663
|
+
form: formComponentSchema,
|
|
1664
|
+
grid: gridShape.extend({ children: opaqueChildren(COMPOSED_UI_MAX_NODES) }),
|
|
1665
|
+
heading: headingComponentSchema,
|
|
1666
|
+
heatmap: heatmapComponentSchema,
|
|
1667
|
+
icon: iconComponentSchema,
|
|
1668
|
+
image: imageComponentSchema,
|
|
1669
|
+
"item-card": itemCardShape.extend({
|
|
1670
|
+
left: opaqueChildren(4).optional().describe("Leading slot nodes."),
|
|
1671
|
+
middle: opaqueChildren(8).describe("Primary flexible slot nodes."),
|
|
1672
|
+
right: opaqueChildren(4).optional().describe("Trailing slot nodes.")
|
|
1673
|
+
}),
|
|
1674
|
+
"item-card-group": itemCardGroupShape.extend({
|
|
1675
|
+
children: z.array(z.unknown()).min(1).max(12).describe("One to twelve item-card children. Look up item-card for each child's schema.")
|
|
1676
|
+
}),
|
|
1677
|
+
"kpi-grid": kpiGridComponentSchema,
|
|
1678
|
+
"line-chart": lineChartComponentSchema,
|
|
1679
|
+
list: listComponentSchema,
|
|
1680
|
+
"list-block": listBlockComponentSchema,
|
|
1681
|
+
map: mapComponentSchema,
|
|
1682
|
+
"meter-list": meterListComponentSchema,
|
|
1683
|
+
"metric-grid": metricGridComponentSchema,
|
|
1684
|
+
"pie-chart": pieChartComponentSchema,
|
|
1685
|
+
"player-card": playerCardComponentSchema,
|
|
1686
|
+
playlist: playlistComponentSchema,
|
|
1687
|
+
"product-card": productCardComponentSchema,
|
|
1688
|
+
"product-signals": productSignalsShape.extend({
|
|
1689
|
+
tabs: z.array(
|
|
1690
|
+
z.object({
|
|
1691
|
+
component: z.unknown().describe(
|
|
1692
|
+
"One analytical component: metric-grid, kpi-grid, any chart, data-table, comparison-list, or meter-list. Look its kind up separately."
|
|
1693
|
+
),
|
|
1694
|
+
id,
|
|
1695
|
+
label: shortText
|
|
1696
|
+
})
|
|
1697
|
+
).min(2).max(4)
|
|
1698
|
+
}),
|
|
1699
|
+
progress: progressComponentSchema,
|
|
1700
|
+
"purchase-complete": purchaseCompleteComponentSchema,
|
|
1701
|
+
"purchase-items": purchaseItemsComponentSchema,
|
|
1702
|
+
"radar-chart": radarChartComponentSchema,
|
|
1703
|
+
"radial-chart": radialChartComponentSchema,
|
|
1704
|
+
rating: ratingComponentSchema,
|
|
1705
|
+
"record-card": recordCardComponentSchema,
|
|
1706
|
+
"ride-status": rideStatusComponentSchema,
|
|
1707
|
+
row: rowShape.extend({ children: opaqueChildren(COMPOSED_UI_MAX_NODES) }),
|
|
1708
|
+
"sankey-chart": sankeyChartComponentSchema,
|
|
1709
|
+
"scatter-chart": scatterChartComponentSchema,
|
|
1710
|
+
spacer: spacerComponentSchema,
|
|
1711
|
+
steps: stepsComponentSchema,
|
|
1712
|
+
"switch-group": switchGroupComponentSchema,
|
|
1713
|
+
tabs: base.extend({
|
|
1714
|
+
defaultValue: id.optional(),
|
|
1715
|
+
kind: z.literal("tabs"),
|
|
1716
|
+
tabs: z.array(
|
|
1717
|
+
z.union([
|
|
1718
|
+
z.object({
|
|
1719
|
+
content,
|
|
1720
|
+
id,
|
|
1721
|
+
label: shortText
|
|
1722
|
+
}),
|
|
1723
|
+
z.object({
|
|
1724
|
+
children: opaqueChildren(12).describe(
|
|
1725
|
+
"Rich panel nodes rendered as one vertical stack. Look up every child kind separately."
|
|
1726
|
+
),
|
|
1727
|
+
id,
|
|
1728
|
+
label: shortText
|
|
1729
|
+
})
|
|
1730
|
+
])
|
|
1731
|
+
).min(1).max(10),
|
|
1732
|
+
variant: z.enum(["primary", "secondary"]).optional()
|
|
1733
|
+
}),
|
|
1734
|
+
"tag-list": tagListComponentSchema,
|
|
1735
|
+
text: textComponentSchema,
|
|
1736
|
+
"toggle-group": toggleGroupComponentSchema,
|
|
1737
|
+
"view-event": viewEventComponentSchema,
|
|
1738
|
+
"weather-current": weatherCurrentComponentSchema,
|
|
1739
|
+
"weather-forecast": weatherForecastComponentSchema
|
|
1740
|
+
};
|
|
1741
|
+
|
|
1742
|
+
// ../agent-ui/src/contracts/catalog.ts
|
|
1743
|
+
var SUMMARIES = {
|
|
1744
|
+
accordion: "collapsible sections of longer prose",
|
|
1745
|
+
"action-group": "buttons that send prompts or call client tools",
|
|
1746
|
+
"area-chart": "one continuous time series with a filled trend",
|
|
1747
|
+
badge: "a small toned status label",
|
|
1748
|
+
"bar-chart": "ranked or categorical comparison, horizontal layout for rankings",
|
|
1749
|
+
button: "one action with a prompt or client-tool call",
|
|
1750
|
+
callout: "one short toned notice: info, success, warning, or danger",
|
|
1751
|
+
card: "titled surface grouping related children",
|
|
1752
|
+
"channel-message": "a quoted workspace message with author and attachments",
|
|
1753
|
+
"code-block": "a syntax-highlighted snippet",
|
|
1754
|
+
col: "stacks children vertically",
|
|
1755
|
+
"comparison-list": "labeled values with change deltas, no axes",
|
|
1756
|
+
"composed-chart": "two to five mixed area/bar/line series, optional dual axis",
|
|
1757
|
+
"create-event": "a proposed calendar slot beside surrounding events",
|
|
1758
|
+
dashboard: "up to four analytical children in a fixed layout",
|
|
1759
|
+
"data-table": "exact values in filterable rows and columns",
|
|
1760
|
+
diagram: "a flowchart, sequence, ER, or state diagram from Mermaid source, for processes and relationships prose cannot show",
|
|
1761
|
+
divider: "a rule between sections",
|
|
1762
|
+
"donut-chart": "proportions of a whole with a hollow center",
|
|
1763
|
+
"enable-notification": "a binary notification opt-in with two actions",
|
|
1764
|
+
"event-session": "a conference session with time, location, and speakers",
|
|
1765
|
+
"flight-tracker": "a flight's route, times, and live progress",
|
|
1766
|
+
followup: "suggested next prompts the user can send",
|
|
1767
|
+
form: "input fields with submit actions",
|
|
1768
|
+
grid: "one to four equal columns of peers",
|
|
1769
|
+
heading: "a section title, levels one to four",
|
|
1770
|
+
heatmap: "two-dimensional intensity across x and y",
|
|
1771
|
+
icon: "one semantic glyph from the icon vocabulary",
|
|
1772
|
+
image: "one to six real image URLs with captions in a grid or horizontal chat gallery",
|
|
1773
|
+
"item-card": "one compact three-slot row with composable left, middle, and right content",
|
|
1774
|
+
"item-card-group": "one to twelve related item-card rows in a list or grid",
|
|
1775
|
+
"kpi-grid": "up to four headline KPIs, each with a sparkline of its own history",
|
|
1776
|
+
"line-chart": "two or more overlapping series needing equal weight",
|
|
1777
|
+
list: "bulleted, numbered, or checklist items with optional children",
|
|
1778
|
+
"list-block": "richer rows with title, description, meta, rating, icon, or image",
|
|
1779
|
+
map: "ranked places pinned by exact latitude and longitude",
|
|
1780
|
+
"meter-list": "bounded quantities such as quota, utilization, or budget",
|
|
1781
|
+
"metric-grid": "up to four headline KPIs with no history to plot",
|
|
1782
|
+
"pie-chart": "proportions of a whole",
|
|
1783
|
+
"player-card": "an athlete with jersey, portrait, and stat lines",
|
|
1784
|
+
playlist: "a track collection with cover and per-track actions",
|
|
1785
|
+
"product-card": "purchasable items with image, price, rating, availability",
|
|
1786
|
+
"product-signals": "two to four related analytical views in tabs",
|
|
1787
|
+
progress: "a zero to one hundred percentage bar",
|
|
1788
|
+
"purchase-complete": "confirmation after a successful transaction",
|
|
1789
|
+
"purchase-items": "a cart or order summary with line items and totals",
|
|
1790
|
+
"radar-chart": "multivariate comparison across three or more axes",
|
|
1791
|
+
"radial-chart": "compact circular measure",
|
|
1792
|
+
rating: "a zero to five star score with optional count",
|
|
1793
|
+
"record-card": "one entity's labeled facts, layouts details/compact/media",
|
|
1794
|
+
"ride-status": "pickup ETA and driver for a ride in progress",
|
|
1795
|
+
row: "places complementary children side by side",
|
|
1796
|
+
"sankey-chart": "flow volumes between source and target nodes",
|
|
1797
|
+
"scatter-chart": "correlation between two numeric fields, optional grouping",
|
|
1798
|
+
spacer: "a gap between siblings",
|
|
1799
|
+
steps: "task progress or a chronological timeline, up to twelve entries",
|
|
1800
|
+
"switch-group": "toggleable boolean preferences",
|
|
1801
|
+
tabs: "parallel text or rich multi-component sections behind labeled tabs",
|
|
1802
|
+
"tag-list": "short keyword chips",
|
|
1803
|
+
text: "explanatory markdown prose",
|
|
1804
|
+
"toggle-group": "single or multiple choice from short options",
|
|
1805
|
+
"view-event": "one calendar event's date, time, and tone",
|
|
1806
|
+
"weather-current": "current conditions in one location",
|
|
1807
|
+
"weather-forecast": "multi-day or future conditions with highs and lows"
|
|
1808
|
+
};
|
|
1809
|
+
var GROUP_BY_CATEGORY = {
|
|
1810
|
+
actions: "actions",
|
|
1811
|
+
"data-visualization": "data",
|
|
1812
|
+
"display-information": "display",
|
|
1813
|
+
"form-elements": "forms"
|
|
1814
|
+
};
|
|
1815
|
+
function groupFor(kind) {
|
|
1816
|
+
if (kind === "dashboard" || AGENT_UI_CONTAINER_KINDS.has(kind)) return "containers";
|
|
1817
|
+
if (AGENT_UI_LAYOUT_LEAF_KINDS.has(kind)) return "layout";
|
|
1818
|
+
if (AGENT_UI_PRIMITIVE_KINDS.has(kind)) return "primitives";
|
|
1819
|
+
return GROUP_BY_CATEGORY[COMPONENT_CATEGORY_BY_KIND[kind]] ?? "display";
|
|
1820
|
+
}
|
|
1821
|
+
var AGENT_UI_CATALOG = Object.fromEntries(
|
|
1822
|
+
Object.entries(SUMMARIES).map(([kind, summary]) => [
|
|
1823
|
+
kind,
|
|
1824
|
+
{ group: groupFor(kind), summary }
|
|
1825
|
+
])
|
|
1826
|
+
);
|
|
1827
|
+
var AGENT_UI_KIND_NAMES = Object.keys(
|
|
1828
|
+
SUMMARIES
|
|
1829
|
+
).sort();
|
|
1830
|
+
var GROUP_LABELS = [
|
|
1831
|
+
["containers", "Containers"],
|
|
1832
|
+
["layout", "Layout"],
|
|
1833
|
+
["primitives", "Primitives"],
|
|
1834
|
+
["data", "Data"],
|
|
1835
|
+
["display", "Content"],
|
|
1836
|
+
["actions", "Actions"],
|
|
1837
|
+
["forms", "Forms"]
|
|
1838
|
+
];
|
|
1839
|
+
function renderAgentUICatalogPrompt() {
|
|
1840
|
+
const lines = GROUP_LABELS.map(([group2, label]) => {
|
|
1841
|
+
const entries = AGENT_UI_KIND_NAMES.filter(
|
|
1842
|
+
(kind) => AGENT_UI_CATALOG[kind].group === group2
|
|
1843
|
+
).map((kind) => `${kind} \u2014 ${AGENT_UI_CATALOG[kind].summary}`);
|
|
1844
|
+
return `${label}: ${entries.join("; ")}.`;
|
|
1845
|
+
});
|
|
1846
|
+
return lines.join("\n");
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
// src/contracts/client-tools.ts
|
|
1850
|
+
import { z as z2 } from "zod";
|
|
1851
|
+
var RESERVED_AGENT_TOOL_NAMES = [
|
|
1852
|
+
"composeUI",
|
|
1853
|
+
"executeSandbox",
|
|
1854
|
+
"getComponentSchema",
|
|
1855
|
+
"loadUIRenderers",
|
|
1856
|
+
"renderComponent",
|
|
1857
|
+
"searchKnowledge",
|
|
1858
|
+
"searchWeb"
|
|
1859
|
+
];
|
|
1860
|
+
var RESERVED_AGENT_TOOL_PREFIX = "mcp_";
|
|
1861
|
+
var MAX_CLIENT_TOOLS = 20;
|
|
1862
|
+
var MAX_CLIENT_TOOLS_BYTES = 16 * 1024;
|
|
1863
|
+
var clientToolManifestEntrySchema = z2.object({
|
|
1864
|
+
description: z2.string().trim().min(1).max(1e3),
|
|
1865
|
+
inputSchema: z2.record(z2.string(), z2.unknown()),
|
|
1866
|
+
name: z2.string().regex(/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/).refine(
|
|
1867
|
+
(name) => !RESERVED_AGENT_TOOL_NAMES.includes(name) && !name.toLowerCase().startsWith(RESERVED_AGENT_TOOL_PREFIX),
|
|
1868
|
+
"Client tool name is reserved by the HeroUI Agent runtime"
|
|
1869
|
+
),
|
|
1870
|
+
needsApproval: z2.boolean().optional()
|
|
1871
|
+
});
|
|
1872
|
+
var clientToolsSchema = z2.array(clientToolManifestEntrySchema).max(MAX_CLIENT_TOOLS).superRefine((tools, context) => {
|
|
1873
|
+
const names = /* @__PURE__ */ new Set();
|
|
1874
|
+
for (const entry of tools) {
|
|
1875
|
+
if (names.has(entry.name)) {
|
|
1876
|
+
context.addIssue({ code: "custom", message: `Duplicate client tool name: ${entry.name}` });
|
|
1877
|
+
}
|
|
1878
|
+
names.add(entry.name);
|
|
1879
|
+
}
|
|
1880
|
+
if (new TextEncoder().encode(JSON.stringify(tools)).byteLength > MAX_CLIENT_TOOLS_BYTES) {
|
|
1881
|
+
context.addIssue({ code: "custom", message: "Client tool manifest exceeds 16KB" });
|
|
1882
|
+
}
|
|
1883
|
+
});
|
|
1884
|
+
|
|
1885
|
+
// src/contracts/identity.ts
|
|
1886
|
+
import { z as z4 } from "zod";
|
|
1887
|
+
|
|
1888
|
+
// src/contracts/models.schema.ts
|
|
1889
|
+
import { z as z3 } from "zod";
|
|
1890
|
+
|
|
1891
|
+
// src/contracts/models.ts
|
|
1892
|
+
var AGENT_MODEL_IDS = [
|
|
1893
|
+
"moonshotai/Kimi-K3",
|
|
1894
|
+
"openai/gpt-5.6-luna",
|
|
1895
|
+
"openai/gpt-5.6-terra",
|
|
1896
|
+
"openai/gpt-5.6-sol",
|
|
1897
|
+
"google/gemini-3.6-flash",
|
|
1898
|
+
"anthropic/claude-sonnet-5",
|
|
1899
|
+
"anthropic/claude-opus-4.8"
|
|
1900
|
+
];
|
|
1901
|
+
var LEGACY_AGENT_MODEL_IDS = {
|
|
1902
|
+
"google/gemini-3.5-flash": "google/gemini-3.6-flash"
|
|
1903
|
+
};
|
|
1904
|
+
function resolveAgentModelId(value) {
|
|
1905
|
+
return LEGACY_AGENT_MODEL_IDS[value] ?? value;
|
|
1906
|
+
}
|
|
1907
|
+
var DEFAULT_AGENT_PICKER_MODEL_ID = "openai/gpt-5.6-luna";
|
|
1908
|
+
var AGENT_MODEL_OPTIONS = [
|
|
1909
|
+
{
|
|
1910
|
+
description: "Flagship model for coding, reasoning, and knowledge work",
|
|
1911
|
+
id: "moonshotai/Kimi-K3",
|
|
1912
|
+
label: "Kimi K3",
|
|
1913
|
+
provider: "Moonshot AI",
|
|
1914
|
+
tier: "light"
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
description: "Fast answers and lightweight agent workflows",
|
|
1918
|
+
id: "openai/gpt-5.6-luna",
|
|
1919
|
+
label: "GPT-5.6 Luna",
|
|
1920
|
+
provider: "OpenAI",
|
|
1921
|
+
tier: "light"
|
|
1922
|
+
},
|
|
1923
|
+
{
|
|
1924
|
+
description: "Balanced reasoning for everyday agent tasks",
|
|
1925
|
+
id: "openai/gpt-5.6-terra",
|
|
1926
|
+
label: "GPT-5.6 Terra",
|
|
1927
|
+
provider: "OpenAI",
|
|
1928
|
+
tier: "codegen"
|
|
1929
|
+
},
|
|
1930
|
+
{
|
|
1931
|
+
description: "Deep reasoning for complex, multi-step analysis",
|
|
1932
|
+
id: "openai/gpt-5.6-sol",
|
|
1933
|
+
label: "GPT-5.6 Sol",
|
|
1934
|
+
provider: "OpenAI",
|
|
1935
|
+
tier: "complex"
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
description: "Fast multimodal analysis with a large context window",
|
|
1939
|
+
id: "google/gemini-3.6-flash",
|
|
1940
|
+
label: "Gemini 3.6 Flash",
|
|
1941
|
+
provider: "Google",
|
|
1942
|
+
tier: "light"
|
|
1943
|
+
},
|
|
1944
|
+
{
|
|
1945
|
+
description: "Strong agentic reasoning and polished UI decisions",
|
|
1946
|
+
id: "anthropic/claude-sonnet-5",
|
|
1947
|
+
label: "Claude Sonnet 5",
|
|
1948
|
+
provider: "Anthropic",
|
|
1949
|
+
tier: "codegen"
|
|
1950
|
+
},
|
|
1951
|
+
{
|
|
1952
|
+
description: "Highest-capability Claude for difficult research and analysis",
|
|
1953
|
+
id: "anthropic/claude-opus-4.8",
|
|
1954
|
+
label: "Claude Opus 4.8",
|
|
1955
|
+
provider: "Anthropic",
|
|
1956
|
+
tier: "complex"
|
|
1957
|
+
}
|
|
1958
|
+
];
|
|
1959
|
+
var AGENT_MODEL_ID_SET = new Set(AGENT_MODEL_IDS);
|
|
1960
|
+
function isAgentModelId(value) {
|
|
1961
|
+
return typeof value === "string" && AGENT_MODEL_ID_SET.has(value);
|
|
1962
|
+
}
|
|
1963
|
+
function getAgentModelTier(modelId) {
|
|
1964
|
+
const resolved = modelId ? resolveAgentModelId(modelId) : void 0;
|
|
1965
|
+
return AGENT_MODEL_OPTIONS.find((option2) => option2.id === resolved)?.tier ?? "light";
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
// src/contracts/models.schema.ts
|
|
1969
|
+
var agentModelIdSchema = z3.preprocess(
|
|
1970
|
+
(value) => typeof value === "string" ? resolveAgentModelId(value) : value,
|
|
1971
|
+
z3.enum(AGENT_MODEL_IDS)
|
|
1972
|
+
);
|
|
1973
|
+
|
|
1974
|
+
// src/contracts/version.ts
|
|
1975
|
+
var HEROUI_AGENT_PROTOCOL_VERSION = 5;
|
|
1976
|
+
var HEROUI_AGENT_SDK_VERSION = "0.2.0-beta.1";
|
|
1977
|
+
var HEROUI_AGENT_TASK_ID = "heroui-agents-runtime";
|
|
1978
|
+
var TRUSTED_AGENT_CLIENT_DATA_KEY = "__heroUiAgentApi";
|
|
1979
|
+
|
|
1980
|
+
// src/contracts/identity.ts
|
|
1981
|
+
var agentThemeSchema = z4.enum(["light", "dark", "system"]);
|
|
1982
|
+
var agentSurfaceVariantSchema = z4.enum([
|
|
1983
|
+
"outline",
|
|
1984
|
+
"plain",
|
|
1985
|
+
"surface",
|
|
1986
|
+
"surface-secondary"
|
|
1987
|
+
]);
|
|
1988
|
+
var pageContextSchema = z4.record(z4.string().max(100), z4.unknown());
|
|
1989
|
+
var RESERVED_IDENTITY_IDS = /* @__PURE__ */ new Set([
|
|
1990
|
+
"[object object]",
|
|
1991
|
+
"0",
|
|
1992
|
+
"anonymous",
|
|
1993
|
+
"distinct_id",
|
|
1994
|
+
"distinctid",
|
|
1995
|
+
"email",
|
|
1996
|
+
"false",
|
|
1997
|
+
"guest",
|
|
1998
|
+
"id",
|
|
1999
|
+
"nan",
|
|
2000
|
+
"none",
|
|
2001
|
+
"not_authenticated",
|
|
2002
|
+
"null",
|
|
2003
|
+
"true",
|
|
2004
|
+
"undefined"
|
|
2005
|
+
]);
|
|
2006
|
+
var agentIdentityIdSchema = z4.string().trim().min(1).max(200).refine((value) => !RESERVED_IDENTITY_IDS.has(value.toLowerCase()), {
|
|
2007
|
+
message: "Identity id is reserved"
|
|
2008
|
+
});
|
|
2009
|
+
var agentAuthIdentitySchema = z4.discriminatedUnion("type", [
|
|
2010
|
+
z4.object({
|
|
2011
|
+
id: agentIdentityIdSchema,
|
|
2012
|
+
type: z4.literal("anonymous")
|
|
2013
|
+
}),
|
|
2014
|
+
z4.object({
|
|
2015
|
+
id: agentIdentityIdSchema,
|
|
2016
|
+
type: z4.literal("user")
|
|
2017
|
+
})
|
|
2018
|
+
]);
|
|
2019
|
+
var agentAuthProfileSchema = z4.object({
|
|
2020
|
+
avatarUrl: z4.string().trim().pipe(z4.url()).optional(),
|
|
2021
|
+
email: z4.string().trim().max(320).pipe(z4.email()).optional(),
|
|
2022
|
+
name: z4.string().trim().max(120).optional()
|
|
2023
|
+
});
|
|
2024
|
+
var createAgentAuthTokenRequestSchema = z4.object({
|
|
2025
|
+
/**
|
|
2026
|
+
* Browser-scoped id the SDK passed to the host callback. Sending it together
|
|
2027
|
+
* with an identified `identity` merges that anonymous person's conversations
|
|
2028
|
+
* into the identified user, so history survives login.
|
|
2029
|
+
*/
|
|
2030
|
+
anonymousId: agentIdentityIdSchema.optional(),
|
|
2031
|
+
identity: agentAuthIdentitySchema,
|
|
2032
|
+
profile: agentAuthProfileSchema.optional()
|
|
2033
|
+
});
|
|
2034
|
+
var agentAuthTokenSchema = z4.object({
|
|
2035
|
+
expiresAt: z4.number().int().positive(),
|
|
2036
|
+
token: z4.string().trim().min(1)
|
|
2037
|
+
});
|
|
2038
|
+
var agentTokenClaimsSchema = z4.object({
|
|
2039
|
+
agentId: z4.string().trim().min(1).max(100),
|
|
2040
|
+
apiKeyId: z4.string().trim().min(1).max(100),
|
|
2041
|
+
aud: z4.literal("heroui-agent"),
|
|
2042
|
+
exp: z4.number().int().positive(),
|
|
2043
|
+
iat: z4.number().int().positive(),
|
|
2044
|
+
iss: z4.literal("https://api.heroui.com"),
|
|
2045
|
+
jti: z4.uuid(),
|
|
2046
|
+
protocolVersion: z4.literal(HEROUI_AGENT_PROTOCOL_VERSION),
|
|
2047
|
+
sub: z4.string().trim().min(1).max(200)
|
|
2048
|
+
});
|
|
2049
|
+
var trustedAgentClientDataSchema = z4.object({
|
|
2050
|
+
agentId: z4.string(),
|
|
2051
|
+
billingLicenseId: z4.string().nullable(),
|
|
2052
|
+
billingOwnerUserId: z4.string(),
|
|
2053
|
+
/**
|
|
2054
|
+
* Browser-declared client tools the embed can execute for this turn. The
|
|
2055
|
+
* runtime registers them as model-visible tools without an execute function.
|
|
2056
|
+
*/
|
|
2057
|
+
clientTools: clientToolsSchema.default([]),
|
|
2058
|
+
conversationId: z4.uuid(),
|
|
2059
|
+
/**
|
|
2060
|
+
* Pseudonymous identity used by persisted conversations. This is signed by
|
|
2061
|
+
* the API so the runtime can link telemetry without handling a raw identity.
|
|
2062
|
+
*/
|
|
2063
|
+
endUserKey: z4.string().trim().min(1).max(200).optional(),
|
|
2064
|
+
/**
|
|
2065
|
+
* When web search is enabled, allow image results via `includeImages`.
|
|
2066
|
+
* Defaults to true at the host when omitted; optional here so signed
|
|
2067
|
+
* payloads without the field stay valid and keep image search on.
|
|
2068
|
+
*/
|
|
2069
|
+
imageSearch: z4.boolean().optional(),
|
|
2070
|
+
/**
|
|
2071
|
+
* Optional browser-selected OpenRouter model. The API accepts only the
|
|
2072
|
+
* fixed agent allowlist and signs the value before the runtime sees it.
|
|
2073
|
+
*/
|
|
2074
|
+
modelId: agentModelIdSchema.optional(),
|
|
2075
|
+
pageContext: pageContextSchema.default({}),
|
|
2076
|
+
/**
|
|
2077
|
+
* Set by the API when the session was authorized by a dashboard preview
|
|
2078
|
+
* credential rather than a host API key, so operator traffic can be separated
|
|
2079
|
+
* from real visitors. Optional (not defaulted) to keep older signed payloads
|
|
2080
|
+
* valid.
|
|
2081
|
+
*/
|
|
2082
|
+
preview: z4.boolean().optional(),
|
|
2083
|
+
protocolVersion: z4.literal(HEROUI_AGENT_PROTOCOL_VERSION),
|
|
2084
|
+
requestId: z4.uuid(),
|
|
2085
|
+
sdkVersion: z4.string().trim().min(1).max(80),
|
|
2086
|
+
signedAt: z4.number(),
|
|
2087
|
+
subject: z4.string(),
|
|
2088
|
+
/**
|
|
2089
|
+
* Host-enabled public web search. When true the runtime registers the
|
|
2090
|
+
* `searchWeb` tool (if the search backend is configured) so the agent can
|
|
2091
|
+
* look up public information and images. Optional (not defaulted) so schema
|
|
2092
|
+
* parsing never injects a field into an already-signed payload.
|
|
2093
|
+
*/
|
|
2094
|
+
webSearch: z4.boolean().optional()
|
|
2095
|
+
});
|
|
2096
|
+
var signedTrustedAgentClientDataSchema = trustedAgentClientDataSchema.extend({
|
|
2097
|
+
sig: z4.string().min(1)
|
|
2098
|
+
});
|
|
2099
|
+
var AGENT_CONVERSATION_SOURCE = {
|
|
2100
|
+
embed: "embed",
|
|
2101
|
+
preview: "preview"
|
|
2102
|
+
};
|
|
2103
|
+
var agentProjectConfigSchema = z4.object({
|
|
2104
|
+
agentId: z4.string(),
|
|
2105
|
+
minimumProtocolVersion: z4.literal(HEROUI_AGENT_PROTOCOL_VERSION),
|
|
2106
|
+
name: z4.string().trim().min(1).max(120),
|
|
2107
|
+
protocolVersion: z4.literal(HEROUI_AGENT_PROTOCOL_VERSION),
|
|
2108
|
+
/**
|
|
2109
|
+
* Internal streaming infrastructure endpoint, resolved server-side so
|
|
2110
|
+
* customers never configure it. Optional for compatibility with older API
|
|
2111
|
+
* deployments; the SDK falls back to Trigger.dev's public endpoint.
|
|
2112
|
+
*/
|
|
2113
|
+
realtime: z4.object({ url: z4.url() }).optional(),
|
|
2114
|
+
sdkVersion: z4.string().default(HEROUI_AGENT_SDK_VERSION),
|
|
2115
|
+
suggestedPrompts: z4.array(z4.string().trim().min(1).max(160)).max(5),
|
|
2116
|
+
surfaceVariant: agentSurfaceVariantSchema.default("plain"),
|
|
2117
|
+
theme: agentThemeSchema
|
|
2118
|
+
});
|
|
2119
|
+
|
|
2120
|
+
// src/contracts/messages.ts
|
|
2121
|
+
import { z as z5 } from "zod";
|
|
2122
|
+
var agentSourceBaseSchema = z5.object({
|
|
2123
|
+
excerpt: z5.string().trim().min(1).max(2e3).optional(),
|
|
2124
|
+
locator: z5.string().trim().min(1).max(160).optional(),
|
|
2125
|
+
sourceId: z5.string().trim().min(1).max(120)
|
|
2126
|
+
});
|
|
2127
|
+
var safeSourceUrlSchema = z5.string().trim().max(2048).refine((value) => {
|
|
2128
|
+
try {
|
|
2129
|
+
return ["http:", "https:"].includes(new URL(value).protocol);
|
|
2130
|
+
} catch {
|
|
2131
|
+
return false;
|
|
2132
|
+
}
|
|
2133
|
+
});
|
|
2134
|
+
var agentSourceSchema = z5.union([
|
|
2135
|
+
agentSourceBaseSchema.extend({
|
|
2136
|
+
sourceType: z5.literal("document"),
|
|
2137
|
+
title: z5.string().trim().min(1).max(200)
|
|
2138
|
+
}),
|
|
2139
|
+
agentSourceBaseSchema.extend({
|
|
2140
|
+
sourceType: z5.literal("url").optional(),
|
|
2141
|
+
title: z5.string().trim().min(1).max(200).optional(),
|
|
2142
|
+
url: safeSourceUrlSchema
|
|
2143
|
+
})
|
|
2144
|
+
]);
|
|
2145
|
+
var agentSourcesSchema = z5.object({
|
|
2146
|
+
items: z5.array(agentSourceSchema).min(1).max(16)
|
|
2147
|
+
});
|
|
2148
|
+
|
|
2149
|
+
// src/contracts/trusted.ts
|
|
2150
|
+
function canonicalize(value) {
|
|
2151
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
2152
|
+
if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`;
|
|
2153
|
+
const entries = Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).sort(([a], [b]) => a.localeCompare(b)).map(([key2, entryValue]) => `${JSON.stringify(key2)}:${canonicalize(entryValue)}`);
|
|
2154
|
+
return `{${entries.join(",")}}`;
|
|
2155
|
+
}
|
|
2156
|
+
function timingSafeEqual(a, b) {
|
|
2157
|
+
if (a.length !== b.length) return false;
|
|
2158
|
+
let mismatch = 0;
|
|
2159
|
+
for (let index = 0; index < a.length; index += 1) {
|
|
2160
|
+
mismatch |= a.charCodeAt(index) ^ b.charCodeAt(index);
|
|
2161
|
+
}
|
|
2162
|
+
return mismatch === 0;
|
|
2163
|
+
}
|
|
2164
|
+
async function hmacHex(secret, input) {
|
|
2165
|
+
const key2 = await crypto.subtle.importKey(
|
|
2166
|
+
"raw",
|
|
2167
|
+
new TextEncoder().encode(secret),
|
|
2168
|
+
{ hash: "SHA-256", name: "HMAC" },
|
|
2169
|
+
false,
|
|
2170
|
+
["sign"]
|
|
2171
|
+
);
|
|
2172
|
+
const signature = await crypto.subtle.sign("HMAC", key2, new TextEncoder().encode(input));
|
|
2173
|
+
return Array.from(new Uint8Array(signature), (byte) => byte.toString(16).padStart(2, "0")).join(
|
|
2174
|
+
""
|
|
2175
|
+
);
|
|
2176
|
+
}
|
|
2177
|
+
async function signTrustedAgentClientData(secret, data) {
|
|
2178
|
+
return { ...data, sig: await hmacHex(secret, canonicalize(data)) };
|
|
2179
|
+
}
|
|
2180
|
+
async function verifyTrustedAgentClientData(secret, value) {
|
|
2181
|
+
if (!value || typeof value !== "object") return null;
|
|
2182
|
+
const { sig, ...data } = value;
|
|
2183
|
+
if (typeof sig !== "string" || !sig) return null;
|
|
2184
|
+
const expected = await hmacHex(secret, canonicalize(data));
|
|
2185
|
+
return timingSafeEqual(sig, expected) ? data : null;
|
|
2186
|
+
}
|
|
2187
|
+
export {
|
|
2188
|
+
AGENT_CONVERSATION_SOURCE,
|
|
2189
|
+
AGENT_MODEL_IDS,
|
|
2190
|
+
AGENT_MODEL_OPTIONS,
|
|
2191
|
+
AGENT_UI_CATALOG,
|
|
2192
|
+
AGENT_UI_CONTAINER_KINDS,
|
|
2193
|
+
AGENT_UI_KIND_NAMES,
|
|
2194
|
+
AGENT_UI_KIND_SCHEMAS,
|
|
2195
|
+
AGENT_UI_LAYOUT_LEAF_KINDS,
|
|
2196
|
+
AGENT_UI_PRIMITIVE_KINDS,
|
|
2197
|
+
COMPOSED_UI_MAX_DEPTH,
|
|
2198
|
+
COMPOSED_UI_MAX_NODES,
|
|
2199
|
+
DEFAULT_AGENT_PICKER_MODEL_ID,
|
|
2200
|
+
HEROUI_AGENT_ATTACHMENT_ACCEPT,
|
|
2201
|
+
HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES,
|
|
2202
|
+
HEROUI_AGENT_ATTACHMENT_EXTENSION_BY_CONTENT_TYPE,
|
|
2203
|
+
HEROUI_AGENT_ATTACHMENT_MAX_BYTES,
|
|
2204
|
+
HEROUI_AGENT_MAX_ATTACHMENTS,
|
|
2205
|
+
HEROUI_AGENT_PROTOCOL_VERSION,
|
|
2206
|
+
HEROUI_AGENT_REMOTE_CONFIG_VERSION,
|
|
2207
|
+
HEROUI_AGENT_SDK_VERSION,
|
|
2208
|
+
HEROUI_AGENT_TASK_ID,
|
|
2209
|
+
HEROUI_AGENT_TEXT_ATTACHMENT_CONTENT_TYPES,
|
|
2210
|
+
LEGACY_AGENT_MODEL_IDS,
|
|
2211
|
+
MAX_CLIENT_TOOLS,
|
|
2212
|
+
MAX_CLIENT_TOOLS_BYTES,
|
|
2213
|
+
RESERVED_AGENT_TOOL_NAMES,
|
|
2214
|
+
RESERVED_AGENT_TOOL_PREFIX,
|
|
2215
|
+
TRUSTED_AGENT_CLIENT_DATA_KEY,
|
|
2216
|
+
accordionComponentSchema,
|
|
2217
|
+
actionGroupComponentSchema,
|
|
2218
|
+
agentAuthIdentitySchema,
|
|
2219
|
+
agentAuthProfileSchema,
|
|
2220
|
+
agentAuthTokenSchema,
|
|
2221
|
+
agentIconNames,
|
|
2222
|
+
agentIconSchema,
|
|
2223
|
+
agentIdentityIdSchema,
|
|
2224
|
+
agentModelIdSchema,
|
|
2225
|
+
agentProjectConfigSchema,
|
|
2226
|
+
agentSourceSchema,
|
|
2227
|
+
agentSourcesSchema,
|
|
2228
|
+
agentSurfaceVariantSchema,
|
|
2229
|
+
agentThemeSchema,
|
|
2230
|
+
agentTokenClaimsSchema,
|
|
2231
|
+
agentUIComponentSchema,
|
|
2232
|
+
agentUILeafComponentSchema,
|
|
2233
|
+
agentUINodeSchema,
|
|
2234
|
+
agentUIRenderableSchema,
|
|
2235
|
+
analyticalLeafComponentSchema,
|
|
2236
|
+
areaChartComponentSchema,
|
|
2237
|
+
badgeComponentSchema,
|
|
2238
|
+
barChartComponentSchema,
|
|
2239
|
+
buttonComponentSchema,
|
|
2240
|
+
calloutComponentSchema,
|
|
2241
|
+
cardComponentSchema,
|
|
2242
|
+
cardComponentVariantSchema,
|
|
2243
|
+
channelMessageComponentSchema,
|
|
2244
|
+
chartColorSchema,
|
|
2245
|
+
clientToolManifestEntrySchema,
|
|
2246
|
+
clientToolsSchema,
|
|
2247
|
+
codeBlockComponentSchema,
|
|
2248
|
+
colComponentSchema,
|
|
2249
|
+
comparisonListComponentSchema,
|
|
2250
|
+
composeUIInputSchema,
|
|
2251
|
+
composedChartComponentSchema,
|
|
2252
|
+
composedUIComponentSchema,
|
|
2253
|
+
createAgentAuthTokenRequestSchema,
|
|
2254
|
+
createEventComponentSchema,
|
|
2255
|
+
dashboardComponentSchema,
|
|
2256
|
+
dataTableComponentSchema,
|
|
2257
|
+
diagramComponentSchema,
|
|
2258
|
+
dividerComponentSchema,
|
|
2259
|
+
donutChartComponentSchema,
|
|
2260
|
+
enableNotificationComponentSchema,
|
|
2261
|
+
eventSessionComponentSchema,
|
|
2262
|
+
flightTrackerComponentSchema,
|
|
2263
|
+
followupComponentSchema,
|
|
2264
|
+
formComponentSchema,
|
|
2265
|
+
getAgentModelTier,
|
|
2266
|
+
getAgentUIContainerChildren,
|
|
2267
|
+
gridComponentSchema,
|
|
2268
|
+
headingComponentSchema,
|
|
2269
|
+
heatmapComponentSchema,
|
|
2270
|
+
iconComponentSchema,
|
|
2271
|
+
imageComponentSchema,
|
|
2272
|
+
isAgentModelId,
|
|
2273
|
+
isAgentUIContainerComponent,
|
|
2274
|
+
isAgentUILayoutLeafComponent,
|
|
2275
|
+
isAgentUIPrimitiveComponent,
|
|
2276
|
+
isHeroUIAgentAttachmentContentType,
|
|
2277
|
+
itemCardComponentSchema,
|
|
2278
|
+
itemCardGroupComponentSchema,
|
|
2279
|
+
kpiGridComponentSchema,
|
|
2280
|
+
lineChartComponentSchema,
|
|
2281
|
+
listBlockComponentSchema,
|
|
2282
|
+
listComponentSchema,
|
|
2283
|
+
mapComponentSchema,
|
|
2284
|
+
meterListComponentSchema,
|
|
2285
|
+
metricGridComponentSchema,
|
|
2286
|
+
numberFormatSchema,
|
|
2287
|
+
pageContextSchema,
|
|
2288
|
+
parseAgentRemoteConfig,
|
|
2289
|
+
pieChartComponentSchema,
|
|
2290
|
+
playerCardComponentSchema,
|
|
2291
|
+
playlistComponentSchema,
|
|
2292
|
+
productCardComponentSchema,
|
|
2293
|
+
productSignalsComponentSchema,
|
|
2294
|
+
progressComponentSchema,
|
|
2295
|
+
purchaseCompleteComponentSchema,
|
|
2296
|
+
purchaseItemsComponentSchema,
|
|
2297
|
+
radarChartComponentSchema,
|
|
2298
|
+
radialChartComponentSchema,
|
|
2299
|
+
ratingComponentSchema,
|
|
2300
|
+
recordCardComponentSchema,
|
|
2301
|
+
recordCardLayoutSchema,
|
|
2302
|
+
renderAgentUICatalogPrompt,
|
|
2303
|
+
renderComponentInputSchema,
|
|
2304
|
+
resolveAgentModelId,
|
|
2305
|
+
rideStatusComponentSchema,
|
|
2306
|
+
rowComponentSchema,
|
|
2307
|
+
sankeyChartComponentSchema,
|
|
2308
|
+
scatterChartComponentSchema,
|
|
2309
|
+
signTrustedAgentClientData,
|
|
2310
|
+
signedTrustedAgentClientDataSchema,
|
|
2311
|
+
spacerComponentSchema,
|
|
2312
|
+
stepsComponentSchema,
|
|
2313
|
+
switchGroupComponentSchema,
|
|
2314
|
+
tabsComponentSchema,
|
|
2315
|
+
tagListComponentSchema,
|
|
2316
|
+
textComponentSchema,
|
|
2317
|
+
toggleGroupComponentSchema,
|
|
2318
|
+
trustedAgentClientDataSchema,
|
|
2319
|
+
verifyTrustedAgentClientData,
|
|
2320
|
+
viewEventComponentSchema,
|
|
2321
|
+
weatherConditionSchema,
|
|
2322
|
+
weatherConditions,
|
|
2323
|
+
weatherCurrentComponentSchema,
|
|
2324
|
+
weatherForecastComponentSchema
|
|
2325
|
+
};
|