@dudousxd/nestjs-agent-core 0.39.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/ag-ui/index.cjs +123 -9
- package/dist/ag-ui/index.cjs.map +1 -1
- package/dist/ag-ui/index.d.cts +19 -3
- package/dist/ag-ui/index.d.ts +19 -3
- package/dist/ag-ui/index.js +122 -9
- package/dist/ag-ui/index.js.map +1 -1
- package/dist/{catalog-CrzetM3_.d.cts → catalog-BKS3Yxo6.d.cts} +2 -0
- package/dist/{catalog-CrzetM3_.d.ts → catalog-BKS3Yxo6.d.ts} +2 -0
- package/dist/genui/builtins.cjs +2 -0
- package/dist/genui/builtins.cjs.map +1 -1
- package/dist/genui/builtins.d.cts +1 -1
- package/dist/genui/builtins.d.ts +1 -1
- package/dist/genui/builtins.js +2 -0
- package/dist/genui/builtins.js.map +1 -1
- package/dist/genui/index.cjs +780 -106
- package/dist/genui/index.cjs.map +1 -1
- package/dist/genui/index.d.cts +5 -5
- package/dist/genui/index.d.ts +5 -5
- package/dist/genui/index.js +770 -105
- package/dist/genui/index.js.map +1 -1
- package/dist/guardrails/index.cjs +3 -1
- package/dist/guardrails/index.cjs.map +1 -1
- package/dist/guardrails/index.d.cts +5 -4
- package/dist/guardrails/index.d.ts +5 -4
- package/dist/guardrails/index.js +3 -1
- package/dist/guardrails/index.js.map +1 -1
- package/dist/index.cjs +3324 -380
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +388 -96
- package/dist/index.d.ts +388 -96
- package/dist/index.js +3279 -377
- package/dist/index.js.map +1 -1
- package/dist/{processors-6p9nrqEi.d.cts → processors-BXM-MNga.d.cts} +1 -1
- package/dist/{processors-Bp5XmF6V.d.ts → processors-ByDr5POu.d.ts} +1 -1
- package/dist/{stream-events-CbVEowYb.d.cts → stream-events-BGKLD6RX.d.ts} +664 -86
- package/dist/{stream-events-CbVEowYb.d.ts → stream-events-CF-6-Y6L.d.cts} +664 -86
- package/package.json +1 -1
- package/dist/tool-DZYLEKnl.d.cts +0 -121
- package/dist/tool-_iq4xRyk.d.ts +0 -121
package/dist/genui/index.cjs
CHANGED
|
@@ -27,7 +27,10 @@ __export(genui_exports, {
|
|
|
27
27
|
ajvValidator: () => ajvValidator,
|
|
28
28
|
builtinJsonSchemaValidator: () => builtinJsonSchemaValidator,
|
|
29
29
|
catalogToModelText: () => catalogToModelText,
|
|
30
|
+
chart: () => chart,
|
|
30
31
|
componentToText: () => componentToText,
|
|
32
|
+
createComponent: () => createComponent,
|
|
33
|
+
createComponentRegistry: () => createComponentRegistry,
|
|
31
34
|
defineCatalog: () => defineCatalog,
|
|
32
35
|
defineComponent: () => defineComponent,
|
|
33
36
|
fillTemplate: () => fillTemplate,
|
|
@@ -36,17 +39,23 @@ __export(genui_exports, {
|
|
|
36
39
|
getPath: () => getPath,
|
|
37
40
|
isStandardSchema: () => isStandardSchema,
|
|
38
41
|
jsonStandardSchema: () => jsonStandardSchema,
|
|
42
|
+
negotiateCatalog: () => negotiateCatalog,
|
|
43
|
+
prepareUiEmission: () => prepareUiEmission,
|
|
39
44
|
showToolJsonSchema: () => showToolJsonSchema,
|
|
45
|
+
snapshotComponentPresentation: () => snapshotComponentPresentation,
|
|
40
46
|
summarizeSchema: () => summarizeSchema,
|
|
47
|
+
table: () => table,
|
|
41
48
|
toJsonSchema: () => toJsonSchema,
|
|
42
49
|
toSnakeCase: () => toSnakeCase,
|
|
43
50
|
toolNameFor: () => toolNameFor,
|
|
44
51
|
treeJsonSchema: () => treeJsonSchema,
|
|
45
52
|
treeToFlatSpec: () => treeToFlatSpec,
|
|
46
53
|
treeToText: () => treeToText,
|
|
54
|
+
validatePresentationBatch: () => validatePresentationBatch,
|
|
47
55
|
validateProps: () => validateProps,
|
|
48
56
|
validatePropsSync: () => validatePropsSync,
|
|
49
|
-
validateTree: () => validateTree
|
|
57
|
+
validateTree: () => validateTree,
|
|
58
|
+
validateUiCapabilities: () => validateUiCapabilities
|
|
50
59
|
});
|
|
51
60
|
module.exports = __toCommonJS(genui_exports);
|
|
52
61
|
|
|
@@ -226,21 +235,21 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
226
235
|
});
|
|
227
236
|
return;
|
|
228
237
|
}
|
|
229
|
-
const
|
|
230
|
-
if (typeof
|
|
231
|
-
const target = resolveRef(root,
|
|
238
|
+
const s2 = schema;
|
|
239
|
+
if (typeof s2.$ref === "string") {
|
|
240
|
+
const target = resolveRef(root, s2.$ref);
|
|
232
241
|
if (target === void 0) {
|
|
233
242
|
issues.push({
|
|
234
243
|
path,
|
|
235
|
-
message: `references unknown schema ${
|
|
244
|
+
message: `references unknown schema ${s2.$ref}`
|
|
236
245
|
});
|
|
237
246
|
return;
|
|
238
247
|
}
|
|
239
248
|
check(target, value, path, root, issues, depth + 1);
|
|
240
249
|
}
|
|
241
|
-
if (
|
|
242
|
-
const types = Array.isArray(
|
|
243
|
-
|
|
250
|
+
if (s2.type !== void 0) {
|
|
251
|
+
const types = Array.isArray(s2.type) ? s2.type : [
|
|
252
|
+
s2.type
|
|
244
253
|
];
|
|
245
254
|
if (!types.some((type) => matchesType(type, value))) {
|
|
246
255
|
issues.push({
|
|
@@ -250,76 +259,76 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
250
259
|
return;
|
|
251
260
|
}
|
|
252
261
|
}
|
|
253
|
-
if (Array.isArray(
|
|
262
|
+
if (Array.isArray(s2.enum) && !s2.enum.some((option) => deepEqual(option, value))) {
|
|
254
263
|
issues.push({
|
|
255
264
|
path,
|
|
256
|
-
message: `must be one of ${
|
|
265
|
+
message: `must be one of ${s2.enum.map((option) => JSON.stringify(option)).join(", ")}`
|
|
257
266
|
});
|
|
258
267
|
}
|
|
259
|
-
if ("const" in
|
|
268
|
+
if ("const" in s2 && !deepEqual(s2.const, value)) {
|
|
260
269
|
issues.push({
|
|
261
270
|
path,
|
|
262
|
-
message: `must be ${JSON.stringify(
|
|
271
|
+
message: `must be ${JSON.stringify(s2.const)}`
|
|
263
272
|
});
|
|
264
273
|
}
|
|
265
274
|
if (typeof value === "string") {
|
|
266
|
-
if (typeof
|
|
275
|
+
if (typeof s2.minLength === "number" && value.length < s2.minLength) {
|
|
267
276
|
issues.push({
|
|
268
277
|
path,
|
|
269
|
-
message: `must be at least ${
|
|
278
|
+
message: `must be at least ${s2.minLength} characters`
|
|
270
279
|
});
|
|
271
280
|
}
|
|
272
|
-
if (typeof
|
|
281
|
+
if (typeof s2.maxLength === "number" && value.length > s2.maxLength) {
|
|
273
282
|
issues.push({
|
|
274
283
|
path,
|
|
275
|
-
message: `must be at most ${
|
|
284
|
+
message: `must be at most ${s2.maxLength} characters`
|
|
276
285
|
});
|
|
277
286
|
}
|
|
278
|
-
if (typeof
|
|
287
|
+
if (typeof s2.pattern === "string") {
|
|
279
288
|
let pattern;
|
|
280
289
|
try {
|
|
281
|
-
pattern = new RegExp(
|
|
290
|
+
pattern = new RegExp(s2.pattern, "u");
|
|
282
291
|
} catch {
|
|
283
292
|
pattern = void 0;
|
|
284
293
|
}
|
|
285
294
|
if (pattern !== void 0 && !pattern.test(value)) {
|
|
286
295
|
issues.push({
|
|
287
296
|
path,
|
|
288
|
-
message: `must match ${
|
|
297
|
+
message: `must match ${s2.pattern}`
|
|
289
298
|
});
|
|
290
299
|
}
|
|
291
300
|
}
|
|
292
301
|
}
|
|
293
302
|
if (typeof value === "number") {
|
|
294
|
-
if (typeof
|
|
303
|
+
if (typeof s2.minimum === "number" && value < s2.minimum) {
|
|
295
304
|
issues.push({
|
|
296
305
|
path,
|
|
297
|
-
message: `must be >= ${
|
|
306
|
+
message: `must be >= ${s2.minimum}`
|
|
298
307
|
});
|
|
299
308
|
}
|
|
300
|
-
if (typeof
|
|
309
|
+
if (typeof s2.maximum === "number" && value > s2.maximum) {
|
|
301
310
|
issues.push({
|
|
302
311
|
path,
|
|
303
|
-
message: `must be <= ${
|
|
312
|
+
message: `must be <= ${s2.maximum}`
|
|
304
313
|
});
|
|
305
314
|
}
|
|
306
315
|
}
|
|
307
316
|
if (Array.isArray(value)) {
|
|
308
|
-
if (typeof
|
|
317
|
+
if (typeof s2.minItems === "number" && value.length < s2.minItems) {
|
|
309
318
|
issues.push({
|
|
310
319
|
path,
|
|
311
|
-
message: `must have at least ${
|
|
320
|
+
message: `must have at least ${s2.minItems} items`
|
|
312
321
|
});
|
|
313
322
|
}
|
|
314
|
-
if (typeof
|
|
323
|
+
if (typeof s2.maxItems === "number" && value.length > s2.maxItems) {
|
|
315
324
|
issues.push({
|
|
316
325
|
path,
|
|
317
|
-
message: `must have at most ${
|
|
326
|
+
message: `must have at most ${s2.maxItems} items`
|
|
318
327
|
});
|
|
319
328
|
}
|
|
320
|
-
if (
|
|
329
|
+
if (s2.items !== void 0 && !Array.isArray(s2.items)) {
|
|
321
330
|
value.forEach((item, index) => {
|
|
322
|
-
check(
|
|
331
|
+
check(s2.items, item, [
|
|
323
332
|
...path,
|
|
324
333
|
index
|
|
325
334
|
], root, issues, depth + 1);
|
|
@@ -327,11 +336,11 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
327
336
|
}
|
|
328
337
|
}
|
|
329
338
|
if (matchesType("object", value)) {
|
|
330
|
-
const
|
|
331
|
-
const properties = typeof
|
|
332
|
-
if (Array.isArray(
|
|
333
|
-
for (const key of
|
|
334
|
-
if (
|
|
339
|
+
const record2 = value;
|
|
340
|
+
const properties = typeof s2.properties === "object" && s2.properties !== null ? s2.properties : {};
|
|
341
|
+
if (Array.isArray(s2.required)) {
|
|
342
|
+
for (const key of s2.required) {
|
|
343
|
+
if (record2[key] === void 0) {
|
|
335
344
|
issues.push({
|
|
336
345
|
path: [
|
|
337
346
|
...path,
|
|
@@ -342,7 +351,7 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
342
351
|
}
|
|
343
352
|
}
|
|
344
353
|
}
|
|
345
|
-
for (const [key, entry] of Object.entries(
|
|
354
|
+
for (const [key, entry] of Object.entries(record2)) {
|
|
346
355
|
if (key in properties) {
|
|
347
356
|
if (entry !== void 0) {
|
|
348
357
|
check(properties[key], entry, [
|
|
@@ -350,7 +359,7 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
350
359
|
key
|
|
351
360
|
], root, issues, depth + 1);
|
|
352
361
|
}
|
|
353
|
-
} else if (
|
|
362
|
+
} else if (s2.additionalProperties === false) {
|
|
354
363
|
issues.push({
|
|
355
364
|
path: [
|
|
356
365
|
...path,
|
|
@@ -358,34 +367,34 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
358
367
|
],
|
|
359
368
|
message: "is not a known property"
|
|
360
369
|
});
|
|
361
|
-
} else if (typeof
|
|
362
|
-
check(
|
|
370
|
+
} else if (typeof s2.additionalProperties === "object" && s2.additionalProperties !== null) {
|
|
371
|
+
check(s2.additionalProperties, entry, [
|
|
363
372
|
...path,
|
|
364
373
|
key
|
|
365
374
|
], root, issues, depth + 1);
|
|
366
375
|
}
|
|
367
376
|
}
|
|
368
377
|
}
|
|
369
|
-
if (Array.isArray(
|
|
370
|
-
for (const sub of
|
|
378
|
+
if (Array.isArray(s2.allOf)) {
|
|
379
|
+
for (const sub of s2.allOf) check(sub, value, path, root, issues, depth + 1);
|
|
371
380
|
}
|
|
372
|
-
if (Array.isArray(
|
|
373
|
-
const options = Array.isArray(
|
|
381
|
+
if (Array.isArray(s2.anyOf) || Array.isArray(s2.oneOf)) {
|
|
382
|
+
const options = Array.isArray(s2.anyOf) ? s2.anyOf : s2.oneOf;
|
|
374
383
|
const passing = options.filter((sub) => {
|
|
375
384
|
const nested = [];
|
|
376
385
|
check(sub, value, path, root, nested, depth + 1);
|
|
377
386
|
return nested.length === 0;
|
|
378
387
|
}).length;
|
|
379
|
-
if (Array.isArray(
|
|
388
|
+
if (Array.isArray(s2.anyOf) ? passing === 0 : passing !== 1) {
|
|
380
389
|
issues.push({
|
|
381
390
|
path,
|
|
382
|
-
message: Array.isArray(
|
|
391
|
+
message: Array.isArray(s2.anyOf) ? "does not match any allowed shape" : "must match exactly one allowed shape"
|
|
383
392
|
});
|
|
384
393
|
}
|
|
385
394
|
}
|
|
386
|
-
if (
|
|
395
|
+
if (s2.not !== void 0) {
|
|
387
396
|
const nested = [];
|
|
388
|
-
check(
|
|
397
|
+
check(s2.not, value, path, root, nested, depth + 1);
|
|
389
398
|
if (nested.length === 0) {
|
|
390
399
|
issues.push({
|
|
391
400
|
path,
|
|
@@ -402,6 +411,8 @@ function defineComponent(definition) {
|
|
|
402
411
|
if (!COMPONENT_NAME.test(definition.name)) {
|
|
403
412
|
throw new Error(`genui: component name "${definition.name}" must be letters and digits, starting with a letter (e.g. DataTable)`);
|
|
404
413
|
}
|
|
414
|
+
if (definition.version !== void 0 && (!Number.isSafeInteger(definition.version) || definition.version <= 0)) throw new RangeError("genui: component version must be a positive safe integer");
|
|
415
|
+
if (definition.fallbackText !== void 0 && typeof definition.fallbackText !== "function") throw new TypeError("genui: fallbackText must be a function");
|
|
405
416
|
return definition;
|
|
406
417
|
}
|
|
407
418
|
__name(defineComponent, "defineComponent");
|
|
@@ -440,7 +451,7 @@ function buildCatalog(byName, validator) {
|
|
|
440
451
|
]
|
|
441
452
|
};
|
|
442
453
|
}
|
|
443
|
-
const result = await validateProps(definition.props, props, validator);
|
|
454
|
+
const result = await validateProps(definition.outputProps ?? definition.props, props, validator);
|
|
444
455
|
return result;
|
|
445
456
|
},
|
|
446
457
|
validateSync(component, props) {
|
|
@@ -456,11 +467,11 @@ function buildCatalog(byName, validator) {
|
|
|
456
467
|
]
|
|
457
468
|
};
|
|
458
469
|
}
|
|
459
|
-
return validatePropsSync(definition.props, props, validator);
|
|
470
|
+
return validatePropsSync(definition.outputProps ?? definition.props, props, validator);
|
|
460
471
|
},
|
|
461
472
|
jsonSchemaFor(component) {
|
|
462
473
|
const definition = byName.get(component);
|
|
463
|
-
return definition === void 0 ? void 0 : toJsonSchema(definition.props);
|
|
474
|
+
return definition === void 0 ? void 0 : toJsonSchema(definition.outputProps ?? definition.props);
|
|
464
475
|
},
|
|
465
476
|
extend(more) {
|
|
466
477
|
const next = new Map(byName);
|
|
@@ -484,7 +495,7 @@ __name(toolNameFor, "toolNameFor");
|
|
|
484
495
|
|
|
485
496
|
// src/genui/tree.ts
|
|
486
497
|
var GENUI_TREE_COMPONENT = "genui:tree";
|
|
487
|
-
async function validateTree(catalog, tree, limits = {}) {
|
|
498
|
+
async function validateTree(catalog, tree, limits = {}, phase = "output") {
|
|
488
499
|
const maxDepth = limits.maxDepth ?? 12;
|
|
489
500
|
const maxNodes = limits.maxNodes ?? 200;
|
|
490
501
|
const issues = [];
|
|
@@ -536,7 +547,7 @@ async function validateTree(catalog, tree, limits = {}) {
|
|
|
536
547
|
});
|
|
537
548
|
return void 0;
|
|
538
549
|
}
|
|
539
|
-
const validated = await catalog.validate(element.type, element.props ?? {});
|
|
550
|
+
const validated = phase === "input" ? await validateProps(definition.props, element.props ?? {}, catalog.validator) : await catalog.validate(element.type, element.props ?? {});
|
|
540
551
|
let props = {};
|
|
541
552
|
if (!validated.ok) {
|
|
542
553
|
for (const issue of validated.issues) {
|
|
@@ -710,7 +721,8 @@ function componentToText(catalog, component, props) {
|
|
|
710
721
|
const fallback = catalog.get(component)?.fallbackText;
|
|
711
722
|
if (fallback !== void 0) {
|
|
712
723
|
try {
|
|
713
|
-
|
|
724
|
+
const text = fallback(props);
|
|
725
|
+
if (typeof text === "string" && text.trim().length > 0) return text;
|
|
714
726
|
} catch {
|
|
715
727
|
}
|
|
716
728
|
}
|
|
@@ -724,7 +736,8 @@ function treeToText(catalog, root) {
|
|
|
724
736
|
const definition = catalog.get(node.type);
|
|
725
737
|
if (definition?.fallbackText !== void 0) {
|
|
726
738
|
try {
|
|
727
|
-
|
|
739
|
+
const text = definition.fallbackText(node.props);
|
|
740
|
+
out.push(typeof text === "string" && text.trim().length > 0 ? text : jsonBlock(node.props));
|
|
728
741
|
} catch {
|
|
729
742
|
out.push(jsonBlock(node.props));
|
|
730
743
|
}
|
|
@@ -741,7 +754,7 @@ function jsonBlock(props) {
|
|
|
741
754
|
const title = typeof props.title === "string" && props.title.length > 0 ? `*${props.title}*
|
|
742
755
|
` : "";
|
|
743
756
|
return `${title}\`\`\`
|
|
744
|
-
${JSON.stringify(props, null, 2)
|
|
757
|
+
${JSON.stringify(props, null, 2)}
|
|
745
758
|
\`\`\``;
|
|
746
759
|
}
|
|
747
760
|
__name(jsonBlock, "jsonBlock");
|
|
@@ -756,7 +769,7 @@ function catalogToModelText(catalog, options = {}) {
|
|
|
756
769
|
lines.push("Components you can show (one tool each):");
|
|
757
770
|
}
|
|
758
771
|
for (const component of catalog.modelComponents()) {
|
|
759
|
-
const schema =
|
|
772
|
+
const schema = toJsonSchema(component.props);
|
|
760
773
|
const head = mode === "per-component" ? `- ${component.name} (tool \`${toolNameFor(component.name, options.namePrefix)}\`)` : `- ${component.name}`;
|
|
761
774
|
lines.push(`${head}: ${component.description}`);
|
|
762
775
|
if (schema !== void 0) {
|
|
@@ -771,38 +784,38 @@ function catalogToModelText(catalog, options = {}) {
|
|
|
771
784
|
__name(catalogToModelText, "catalogToModelText");
|
|
772
785
|
function summarizeSchema(schema, root, depth) {
|
|
773
786
|
if (typeof schema !== "object" || schema === null) return "unknown";
|
|
774
|
-
const
|
|
787
|
+
const s2 = schema;
|
|
775
788
|
if (depth > 5) return "\u2026";
|
|
776
|
-
if (typeof
|
|
777
|
-
return
|
|
789
|
+
if (typeof s2.$ref === "string") {
|
|
790
|
+
return s2.$ref === "#" ? "Self" : s2.$ref.split("/").pop() ?? "unknown";
|
|
778
791
|
}
|
|
779
|
-
if (Array.isArray(
|
|
780
|
-
return
|
|
792
|
+
if (Array.isArray(s2.enum)) {
|
|
793
|
+
return s2.enum.map((option) => JSON.stringify(option)).join(" | ");
|
|
781
794
|
}
|
|
782
|
-
if ("const" in
|
|
783
|
-
const variants =
|
|
795
|
+
if ("const" in s2) return JSON.stringify(s2.const);
|
|
796
|
+
const variants = s2.anyOf ?? s2.oneOf;
|
|
784
797
|
if (Array.isArray(variants)) {
|
|
785
798
|
return variants.map((variant) => summarizeSchema(variant, root, depth + 1)).join(" | ");
|
|
786
799
|
}
|
|
787
|
-
const types = Array.isArray(
|
|
788
|
-
|
|
800
|
+
const types = Array.isArray(s2.type) ? s2.type : s2.type !== void 0 ? [
|
|
801
|
+
s2.type
|
|
789
802
|
] : [];
|
|
790
803
|
if (types.length > 1) {
|
|
791
804
|
return types.map((type2) => summarizeSchema({
|
|
792
|
-
...
|
|
805
|
+
...s2,
|
|
793
806
|
type: type2
|
|
794
807
|
}, root, depth + 1)).join(" | ");
|
|
795
808
|
}
|
|
796
809
|
const type = types[0];
|
|
797
810
|
if (type === "array") {
|
|
798
|
-
const item =
|
|
811
|
+
const item = s2.items === void 0 ? "unknown" : summarizeSchema(s2.items, root, depth + 1);
|
|
799
812
|
return /[|\s]/.test(item) && !item.startsWith("{") ? `(${item})[]` : `${item}[]`;
|
|
800
813
|
}
|
|
801
|
-
if (type === "object" || type === void 0 &&
|
|
802
|
-
const properties =
|
|
814
|
+
if (type === "object" || type === void 0 && s2.properties !== void 0) {
|
|
815
|
+
const properties = s2.properties ?? {};
|
|
803
816
|
const keys = Object.keys(properties);
|
|
804
817
|
if (keys.length === 0) return "object";
|
|
805
|
-
const required = new Set(Array.isArray(
|
|
818
|
+
const required = new Set(Array.isArray(s2.required) ? s2.required : []);
|
|
806
819
|
const fields = keys.map((key) => {
|
|
807
820
|
const field = properties[key];
|
|
808
821
|
const note = typeof field?.description === "string" && depth === 0 ? ` /* ${field.description} */` : "";
|
|
@@ -832,6 +845,81 @@ function getPath(source, path) {
|
|
|
832
845
|
}
|
|
833
846
|
__name(getPath, "getPath");
|
|
834
847
|
|
|
848
|
+
// src/genui/capabilities.ts
|
|
849
|
+
function validateUiCapabilities(value) {
|
|
850
|
+
if (!record(value) || Object.keys(value).some((key) => key !== "components") || !Array.isArray(value.components)) throw new TypeError("Invalid UI capabilities");
|
|
851
|
+
const seen = /* @__PURE__ */ new Set();
|
|
852
|
+
const components = value.components.map((component) => {
|
|
853
|
+
if (!record(component) || Object.keys(component).some((key) => key !== "name" && key !== "version") || typeof component.name !== "string" || !COMPONENT_NAME.test(component.name) || !Number.isSafeInteger(component.version) || Number(component.version) <= 0 || seen.has(component.name)) throw new TypeError("Invalid UI component capability");
|
|
854
|
+
seen.add(component.name);
|
|
855
|
+
return {
|
|
856
|
+
name: component.name,
|
|
857
|
+
version: Number(component.version)
|
|
858
|
+
};
|
|
859
|
+
});
|
|
860
|
+
return {
|
|
861
|
+
components
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
__name(validateUiCapabilities, "validateUiCapabilities");
|
|
865
|
+
function record(value) {
|
|
866
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
867
|
+
}
|
|
868
|
+
__name(record, "record");
|
|
869
|
+
function negotiateCatalog(catalog, capabilities) {
|
|
870
|
+
if (capabilities === void 0) return catalog;
|
|
871
|
+
const supported = validateUiCapabilities(capabilities).components;
|
|
872
|
+
return defineCatalog(catalog.components.filter((component) => supported.some((entry) => entry.name === component.name && entry.version === (component.version ?? 1))), {
|
|
873
|
+
jsonSchemaValidator: catalog.validator
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
__name(negotiateCatalog, "negotiateCatalog");
|
|
877
|
+
async function prepareUiEmission(catalog, capabilities, component, props, version) {
|
|
878
|
+
const drawable = negotiateCatalog(catalog, capabilities);
|
|
879
|
+
if (component === GENUI_TREE_COMPONENT) {
|
|
880
|
+
if (version !== void 0 && version !== 1) throw new Error("Invalid UI tree version");
|
|
881
|
+
const validated2 = await validateTree(catalog, props.root);
|
|
882
|
+
if (!validated2.ok) throw new Error(`Invalid UI tree: ${formatIssues(validated2.issues)}`);
|
|
883
|
+
const supported = /* @__PURE__ */ __name((node) => drawable.has(node.type) && (node.children ?? []).every(supported), "supported");
|
|
884
|
+
const versions = /* @__PURE__ */ new Map();
|
|
885
|
+
const collectVersions = /* @__PURE__ */ __name((node) => {
|
|
886
|
+
versions.set(node.type, catalog.get(node.type)?.version ?? 1);
|
|
887
|
+
for (const child of node.children ?? []) collectVersions(child);
|
|
888
|
+
}, "collectVersions");
|
|
889
|
+
collectVersions(validated2.value);
|
|
890
|
+
return supported(validated2.value) ? {
|
|
891
|
+
kind: "ui",
|
|
892
|
+
component,
|
|
893
|
+
props: {
|
|
894
|
+
root: validated2.value
|
|
895
|
+
},
|
|
896
|
+
version: 1,
|
|
897
|
+
fallbackText: treeToText(catalog, validated2.value),
|
|
898
|
+
componentVersions: Object.fromEntries(versions)
|
|
899
|
+
} : {
|
|
900
|
+
kind: "text",
|
|
901
|
+
text: treeToText(catalog, validated2.value)
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
const definition = catalog.get(component);
|
|
905
|
+
if (definition === void 0) throw new Error(`Unknown UI component "${component}"`);
|
|
906
|
+
const currentVersion = definition.version ?? 1;
|
|
907
|
+
if (version !== void 0 && version !== currentVersion) throw new Error(`Invalid UI component version for "${component}"`);
|
|
908
|
+
const validated = await catalog.validate(component, props);
|
|
909
|
+
if (!validated.ok) throw new Error(`Invalid UI props: ${formatIssues(validated.issues)}`);
|
|
910
|
+
return drawable.has(component) ? {
|
|
911
|
+
kind: "ui",
|
|
912
|
+
component,
|
|
913
|
+
props: validated.value,
|
|
914
|
+
version: currentVersion,
|
|
915
|
+
fallbackText: componentToText(catalog, component, validated.value)
|
|
916
|
+
} : {
|
|
917
|
+
kind: "text",
|
|
918
|
+
text: componentToText(catalog, component, validated.value)
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
__name(prepareUiEmission, "prepareUiEmission");
|
|
922
|
+
|
|
835
923
|
// src/genui/tools.ts
|
|
836
924
|
var GENUI_SHOW_TOOL = "ui__show";
|
|
837
925
|
function genuiTools(catalog, options = {}) {
|
|
@@ -895,30 +983,29 @@ function componentTool(catalog, component, options) {
|
|
|
895
983
|
if (definition === void 0) {
|
|
896
984
|
throw new Error(`component "${component.name}" is not available here`);
|
|
897
985
|
}
|
|
898
|
-
const validated = await validateProps(definition.props, input, resolved.validator);
|
|
986
|
+
const validated = await validateProps(dynamic ? definition.props : definition.outputProps ?? definition.props, input, resolved.validator);
|
|
899
987
|
if (!validated.ok) {
|
|
900
988
|
throw new Error(`invalid ${component.name} props: ${formatIssues(validated.issues)}`);
|
|
901
989
|
}
|
|
902
990
|
return push(ctx, component.name, validated.value, definition.version);
|
|
903
991
|
}
|
|
904
992
|
};
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
if (definition === void 0) {
|
|
910
|
-
return {
|
|
911
|
-
description: `Not available in this conversation \u2014 do not call this tool. (${component.name})`
|
|
912
|
-
};
|
|
913
|
-
}
|
|
993
|
+
handler.describe = async (scope) => {
|
|
994
|
+
const resolved = negotiateCatalog(await catalogFor(catalog, options, scopeOf(scope)), scope.uiCapabilities);
|
|
995
|
+
const definition = modelComponent(resolved, component.name);
|
|
996
|
+
if (definition === void 0) {
|
|
914
997
|
return {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
type: "object"
|
|
918
|
-
})
|
|
998
|
+
available: false,
|
|
999
|
+
description: `Not available in this conversation \u2014 do not call this tool. (${component.name})`
|
|
919
1000
|
};
|
|
1001
|
+
}
|
|
1002
|
+
return {
|
|
1003
|
+
description: describeFor(definition),
|
|
1004
|
+
inputSchema: permissiveSchema(toJsonSchema(definition.props) ?? {
|
|
1005
|
+
type: "object"
|
|
1006
|
+
})
|
|
920
1007
|
};
|
|
921
|
-
}
|
|
1008
|
+
};
|
|
922
1009
|
return {
|
|
923
1010
|
spec: {
|
|
924
1011
|
name: toolNameFor(component.name, options.namePrefix),
|
|
@@ -952,7 +1039,7 @@ function treeTool(catalog, options) {
|
|
|
952
1039
|
const handler = {
|
|
953
1040
|
async execute(input, ctx) {
|
|
954
1041
|
const resolved = await catalogFor(catalog, options, scopeOf(ctx));
|
|
955
|
-
const result = await validateTree(resolved, input, options.treeLimits);
|
|
1042
|
+
const result = await validateTree(resolved, input, options.treeLimits, dynamic ? "input" : "output");
|
|
956
1043
|
if (!result.ok) {
|
|
957
1044
|
throw new Error(`invalid UI tree: ${formatIssues(result.issues)}`);
|
|
958
1045
|
}
|
|
@@ -962,22 +1049,21 @@ function treeTool(catalog, options) {
|
|
|
962
1049
|
});
|
|
963
1050
|
}
|
|
964
1051
|
};
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
};
|
|
1052
|
+
handler.describe = async (scope) => {
|
|
1053
|
+
const resolved = negotiateCatalog(await catalogFor(catalog, options, scopeOf(scope)), scope.uiCapabilities);
|
|
1054
|
+
return {
|
|
1055
|
+
available: resolved.modelComponents().length > 0,
|
|
1056
|
+
description: describeFor(resolved),
|
|
1057
|
+
inputSchema: permissiveSchema(treeJsonSchema(resolved))
|
|
972
1058
|
};
|
|
973
|
-
}
|
|
1059
|
+
};
|
|
974
1060
|
return {
|
|
975
1061
|
spec: {
|
|
976
1062
|
name,
|
|
977
1063
|
kind: "read",
|
|
978
1064
|
description: describeFor(catalog),
|
|
979
1065
|
inputSchema: dynamic ? permissiveSchema(treeJsonSchema(catalog)) : asyncJsonStandardSchema(treeJsonSchema(catalog), async (value) => {
|
|
980
|
-
const result = await validateTree(catalog, value, options.treeLimits);
|
|
1066
|
+
const result = await validateTree(catalog, value, options.treeLimits, "input");
|
|
981
1067
|
return result.ok ? {
|
|
982
1068
|
value: result.value
|
|
983
1069
|
} : {
|
|
@@ -1012,7 +1098,7 @@ function showToolJsonSchema(catalog) {
|
|
|
1012
1098
|
};
|
|
1013
1099
|
}
|
|
1014
1100
|
__name(showToolJsonSchema, "showToolJsonSchema");
|
|
1015
|
-
async function validateShow(catalog, input) {
|
|
1101
|
+
async function validateShow(catalog, input, phase = "input") {
|
|
1016
1102
|
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
1017
1103
|
return {
|
|
1018
1104
|
ok: false,
|
|
@@ -1053,7 +1139,7 @@ async function validateShow(catalog, input) {
|
|
|
1053
1139
|
]
|
|
1054
1140
|
};
|
|
1055
1141
|
}
|
|
1056
|
-
const validated = await validateProps(definition.props, props ?? {}, catalog.validator);
|
|
1142
|
+
const validated = await validateProps(phase === "input" ? definition.props : definition.outputProps ?? definition.props, props ?? {}, catalog.validator);
|
|
1057
1143
|
if (!validated.ok) {
|
|
1058
1144
|
return {
|
|
1059
1145
|
ok: false,
|
|
@@ -1093,22 +1179,21 @@ function showTool(catalog, options) {
|
|
|
1093
1179
|
const handler = {
|
|
1094
1180
|
async execute(input, ctx) {
|
|
1095
1181
|
const resolved = await catalogFor(catalog, options, scopeOf(ctx));
|
|
1096
|
-
const result = await validateShow(resolved, input);
|
|
1182
|
+
const result = await validateShow(resolved, input, dynamic ? "input" : "output");
|
|
1097
1183
|
if (!result.ok) {
|
|
1098
1184
|
throw new Error(`invalid ${name} call: ${formatIssues(result.issues)}`);
|
|
1099
1185
|
}
|
|
1100
1186
|
return push(ctx, result.definition.name, result.props, result.definition.version);
|
|
1101
1187
|
}
|
|
1102
1188
|
};
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
};
|
|
1189
|
+
handler.describe = async (scope) => {
|
|
1190
|
+
const resolved = negotiateCatalog(await catalogFor(catalog, options, scopeOf(scope)), scope.uiCapabilities);
|
|
1191
|
+
return {
|
|
1192
|
+
available: resolved.modelComponents().length > 0,
|
|
1193
|
+
description: describeFor(resolved),
|
|
1194
|
+
inputSchema: permissiveSchema(showToolJsonSchema(resolved))
|
|
1110
1195
|
};
|
|
1111
|
-
}
|
|
1196
|
+
};
|
|
1112
1197
|
return {
|
|
1113
1198
|
spec: {
|
|
1114
1199
|
name,
|
|
@@ -1193,6 +1278,586 @@ function asyncJsonStandardSchema(schema, validate) {
|
|
|
1193
1278
|
};
|
|
1194
1279
|
}
|
|
1195
1280
|
__name(asyncJsonStandardSchema, "asyncJsonStandardSchema");
|
|
1281
|
+
|
|
1282
|
+
// src/genui/builtins.ts
|
|
1283
|
+
var str = /* @__PURE__ */ __name((description, extra = {}) => ({
|
|
1284
|
+
type: "string",
|
|
1285
|
+
...description !== void 0 ? {
|
|
1286
|
+
description
|
|
1287
|
+
} : {},
|
|
1288
|
+
...extra
|
|
1289
|
+
}), "str");
|
|
1290
|
+
var obj = /* @__PURE__ */ __name((properties, required = []) => ({
|
|
1291
|
+
type: "object",
|
|
1292
|
+
properties,
|
|
1293
|
+
required,
|
|
1294
|
+
additionalProperties: false
|
|
1295
|
+
}), "obj");
|
|
1296
|
+
var arr = /* @__PURE__ */ __name((items, extra = {}) => ({
|
|
1297
|
+
type: "array",
|
|
1298
|
+
items,
|
|
1299
|
+
...extra
|
|
1300
|
+
}), "arr");
|
|
1301
|
+
var cell = {
|
|
1302
|
+
type: [
|
|
1303
|
+
"string",
|
|
1304
|
+
"number",
|
|
1305
|
+
"boolean",
|
|
1306
|
+
"null"
|
|
1307
|
+
]
|
|
1308
|
+
};
|
|
1309
|
+
var row = {
|
|
1310
|
+
type: "object",
|
|
1311
|
+
additionalProperties: cell
|
|
1312
|
+
};
|
|
1313
|
+
var s = /* @__PURE__ */ __name((value) => value === null || value === void 0 ? "" : String(value), "s");
|
|
1314
|
+
var heading = /* @__PURE__ */ __name((props) => props.title ? `*${s(props.title)}*
|
|
1315
|
+
` : "", "heading");
|
|
1316
|
+
function textTable(columns, rows, max = 15) {
|
|
1317
|
+
const shown = rows.slice(0, max);
|
|
1318
|
+
const widths = columns.map((column) => Math.min(28, Math.max(column.label.length, ...shown.map((r) => s(r[column.key]).length))));
|
|
1319
|
+
const format = /* @__PURE__ */ __name((values) => values.map((value, index) => value.slice(0, widths[index]).padEnd(widths[index] ?? 0)).join(" "), "format");
|
|
1320
|
+
const lines = [
|
|
1321
|
+
format(columns.map((column) => column.label)),
|
|
1322
|
+
widths.map((width) => "-".repeat(width)).join(" "),
|
|
1323
|
+
...shown.map((r) => format(columns.map((column) => s(r[column.key]))))
|
|
1324
|
+
];
|
|
1325
|
+
if (rows.length > max) lines.push(`\u2026 ${rows.length - max} more rows`);
|
|
1326
|
+
return `\`\`\`
|
|
1327
|
+
${lines.join("\n")}
|
|
1328
|
+
\`\`\``;
|
|
1329
|
+
}
|
|
1330
|
+
__name(textTable, "textTable");
|
|
1331
|
+
function lineDiff(before, after) {
|
|
1332
|
+
const a = before.split("\n");
|
|
1333
|
+
const b = after.split("\n");
|
|
1334
|
+
if (a.length * b.length > 25e4) {
|
|
1335
|
+
return [
|
|
1336
|
+
...a.map((text) => ({
|
|
1337
|
+
op: "del",
|
|
1338
|
+
text
|
|
1339
|
+
})),
|
|
1340
|
+
...b.map((text) => ({
|
|
1341
|
+
op: "add",
|
|
1342
|
+
text
|
|
1343
|
+
}))
|
|
1344
|
+
];
|
|
1345
|
+
}
|
|
1346
|
+
const dp = Array.from({
|
|
1347
|
+
length: a.length + 1
|
|
1348
|
+
}, () => new Array(b.length + 1).fill(0));
|
|
1349
|
+
const at = /* @__PURE__ */ __name((i2, j2) => dp[i2]?.[j2] ?? 0, "at");
|
|
1350
|
+
for (let i2 = a.length - 1; i2 >= 0; i2--) {
|
|
1351
|
+
for (let j2 = b.length - 1; j2 >= 0; j2--) {
|
|
1352
|
+
dp[i2][j2] = a[i2] === b[j2] ? at(i2 + 1, j2 + 1) + 1 : Math.max(at(i2 + 1, j2), at(i2, j2 + 1));
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
const out = [];
|
|
1356
|
+
let i = 0;
|
|
1357
|
+
let j = 0;
|
|
1358
|
+
while (i < a.length && j < b.length) {
|
|
1359
|
+
if (a[i] === b[j]) {
|
|
1360
|
+
out.push({
|
|
1361
|
+
op: "same",
|
|
1362
|
+
text: a[i]
|
|
1363
|
+
});
|
|
1364
|
+
i++;
|
|
1365
|
+
j++;
|
|
1366
|
+
} else if (at(i + 1, j) >= at(i, j + 1)) {
|
|
1367
|
+
out.push({
|
|
1368
|
+
op: "del",
|
|
1369
|
+
text: a[i++]
|
|
1370
|
+
});
|
|
1371
|
+
} else {
|
|
1372
|
+
out.push({
|
|
1373
|
+
op: "add",
|
|
1374
|
+
text: b[j++]
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
while (i < a.length) out.push({
|
|
1379
|
+
op: "del",
|
|
1380
|
+
text: a[i++]
|
|
1381
|
+
});
|
|
1382
|
+
while (j < b.length) out.push({
|
|
1383
|
+
op: "add",
|
|
1384
|
+
text: b[j++]
|
|
1385
|
+
});
|
|
1386
|
+
return out;
|
|
1387
|
+
}
|
|
1388
|
+
__name(lineDiff, "lineDiff");
|
|
1389
|
+
function bar(value, max, width = 20) {
|
|
1390
|
+
const n = max > 0 ? Math.round(Math.abs(value) / max * width) : 0;
|
|
1391
|
+
return "\u2588".repeat(n) || "\u258F";
|
|
1392
|
+
}
|
|
1393
|
+
__name(bar, "bar");
|
|
1394
|
+
var DataTable = defineComponent({
|
|
1395
|
+
name: "DataTable",
|
|
1396
|
+
title: "Data table",
|
|
1397
|
+
description: "Tabular data (records with the same fields) as a sortable table. Prefer it over markdown tables for more than 3 rows.",
|
|
1398
|
+
props: obj({
|
|
1399
|
+
title: str("Short caption"),
|
|
1400
|
+
columns: arr(obj({
|
|
1401
|
+
key: str("Field name in each row"),
|
|
1402
|
+
label: str("Column header"),
|
|
1403
|
+
align: str(void 0, {
|
|
1404
|
+
enum: [
|
|
1405
|
+
"left",
|
|
1406
|
+
"right",
|
|
1407
|
+
"center"
|
|
1408
|
+
]
|
|
1409
|
+
}),
|
|
1410
|
+
format: str("How to format values", {
|
|
1411
|
+
enum: [
|
|
1412
|
+
"text",
|
|
1413
|
+
"number",
|
|
1414
|
+
"currency",
|
|
1415
|
+
"percent",
|
|
1416
|
+
"date",
|
|
1417
|
+
"link"
|
|
1418
|
+
]
|
|
1419
|
+
})
|
|
1420
|
+
}, [
|
|
1421
|
+
"key",
|
|
1422
|
+
"label"
|
|
1423
|
+
]), {
|
|
1424
|
+
minItems: 1,
|
|
1425
|
+
maxItems: 12
|
|
1426
|
+
}),
|
|
1427
|
+
rows: arr(row, {
|
|
1428
|
+
maxItems: 500
|
|
1429
|
+
})
|
|
1430
|
+
}, [
|
|
1431
|
+
"columns",
|
|
1432
|
+
"rows"
|
|
1433
|
+
]),
|
|
1434
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${textTable(props.columns ?? [], props.rows ?? [])}`, "fallbackText")
|
|
1435
|
+
});
|
|
1436
|
+
var Chart = defineComponent({
|
|
1437
|
+
name: "Chart",
|
|
1438
|
+
title: "Chart",
|
|
1439
|
+
description: "`bar` to compare categories, `line` for a trend over time. `data` is a list of points; `xKey` names the category/time field and each series names a numeric field.",
|
|
1440
|
+
props: obj({
|
|
1441
|
+
type: str("Chart type", {
|
|
1442
|
+
enum: [
|
|
1443
|
+
"bar",
|
|
1444
|
+
"line"
|
|
1445
|
+
]
|
|
1446
|
+
}),
|
|
1447
|
+
title: str(),
|
|
1448
|
+
xKey: str("Field of each point used for the x axis"),
|
|
1449
|
+
series: arr(obj({
|
|
1450
|
+
key: str("Numeric field"),
|
|
1451
|
+
label: str()
|
|
1452
|
+
}, [
|
|
1453
|
+
"key"
|
|
1454
|
+
]), {
|
|
1455
|
+
minItems: 1,
|
|
1456
|
+
maxItems: 6
|
|
1457
|
+
}),
|
|
1458
|
+
data: arr(row, {
|
|
1459
|
+
minItems: 1,
|
|
1460
|
+
maxItems: 200
|
|
1461
|
+
}),
|
|
1462
|
+
unit: str("Unit shown after values, e.g. `KB` or `%`")
|
|
1463
|
+
}, [
|
|
1464
|
+
"type",
|
|
1465
|
+
"xKey",
|
|
1466
|
+
"series",
|
|
1467
|
+
"data"
|
|
1468
|
+
]),
|
|
1469
|
+
fallbackText: /* @__PURE__ */ __name((props) => {
|
|
1470
|
+
const series = props.series ?? [];
|
|
1471
|
+
const data = props.data ?? [];
|
|
1472
|
+
const first = series[0]?.key ?? "";
|
|
1473
|
+
const max = Math.max(0, ...data.map((point) => Math.abs(Number(point[first]) || 0)));
|
|
1474
|
+
const unit = props.unit ? ` ${s(props.unit)}` : "";
|
|
1475
|
+
const lines = data.slice(0, 20).map((point) => `${s(point[props.xKey]).slice(0, 18).padEnd(18)} ${bar(Number(point[first]) || 0, max)} ${s(point[first])}${unit}`);
|
|
1476
|
+
return `${heading(props)}\`\`\`
|
|
1477
|
+
${lines.join("\n")}
|
|
1478
|
+
\`\`\``;
|
|
1479
|
+
}, "fallbackText")
|
|
1480
|
+
});
|
|
1481
|
+
var KpiCards = defineComponent({
|
|
1482
|
+
name: "KpiCards",
|
|
1483
|
+
title: "KPI cards",
|
|
1484
|
+
description: "A few key numbers (metrics, totals, counts) as cards.",
|
|
1485
|
+
props: obj({
|
|
1486
|
+
title: str(),
|
|
1487
|
+
items: arr(obj({
|
|
1488
|
+
label: str(),
|
|
1489
|
+
value: {
|
|
1490
|
+
type: [
|
|
1491
|
+
"string",
|
|
1492
|
+
"number"
|
|
1493
|
+
]
|
|
1494
|
+
},
|
|
1495
|
+
delta: str("Change, e.g. `+12%`"),
|
|
1496
|
+
trend: str(void 0, {
|
|
1497
|
+
enum: [
|
|
1498
|
+
"up",
|
|
1499
|
+
"down",
|
|
1500
|
+
"flat"
|
|
1501
|
+
]
|
|
1502
|
+
}),
|
|
1503
|
+
hint: str()
|
|
1504
|
+
}, [
|
|
1505
|
+
"label",
|
|
1506
|
+
"value"
|
|
1507
|
+
]), {
|
|
1508
|
+
minItems: 1,
|
|
1509
|
+
maxItems: 8
|
|
1510
|
+
})
|
|
1511
|
+
}, [
|
|
1512
|
+
"items"
|
|
1513
|
+
]),
|
|
1514
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${(props.items ?? []).map((item) => `\u2022 *${s(item.label)}:* ${s(item.value)}${item.delta ? ` (${s(item.delta)})` : ""}`).join("\n")}`, "fallbackText")
|
|
1515
|
+
});
|
|
1516
|
+
var SourceCards = defineComponent({
|
|
1517
|
+
name: "SourceCards",
|
|
1518
|
+
title: "Sources",
|
|
1519
|
+
description: "The documents, pages or links an answer is based on, as cards.",
|
|
1520
|
+
props: obj({
|
|
1521
|
+
title: str(),
|
|
1522
|
+
items: arr(obj({
|
|
1523
|
+
title: str(),
|
|
1524
|
+
url: str(),
|
|
1525
|
+
snippet: str(),
|
|
1526
|
+
source: str("e.g. Wiki, GitHub")
|
|
1527
|
+
}, [
|
|
1528
|
+
"title"
|
|
1529
|
+
]), {
|
|
1530
|
+
minItems: 1,
|
|
1531
|
+
maxItems: 12
|
|
1532
|
+
})
|
|
1533
|
+
}, [
|
|
1534
|
+
"items"
|
|
1535
|
+
]),
|
|
1536
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${(props.items ?? []).map((item) => `\u2022 ${item.url ? `<${s(item.url)}|${s(item.title)}>` : s(item.title)}${item.source ? ` \u2014 ${s(item.source)}` : ""}`).join("\n")}`, "fallbackText")
|
|
1537
|
+
});
|
|
1538
|
+
var Checklist = defineComponent({
|
|
1539
|
+
name: "Checklist",
|
|
1540
|
+
title: "Checklist",
|
|
1541
|
+
description: "Steps or a to-do list with done/not-done state.",
|
|
1542
|
+
props: obj({
|
|
1543
|
+
title: str(),
|
|
1544
|
+
items: arr(obj({
|
|
1545
|
+
label: str(),
|
|
1546
|
+
done: {
|
|
1547
|
+
type: "boolean"
|
|
1548
|
+
},
|
|
1549
|
+
note: str()
|
|
1550
|
+
}, [
|
|
1551
|
+
"label"
|
|
1552
|
+
]), {
|
|
1553
|
+
minItems: 1,
|
|
1554
|
+
maxItems: 50
|
|
1555
|
+
})
|
|
1556
|
+
}, [
|
|
1557
|
+
"items"
|
|
1558
|
+
]),
|
|
1559
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${(props.items ?? []).map((item) => `${item.done ? "\u2611" : "\u2610"} ${s(item.label)}${item.note ? ` \u2014 _${s(item.note)}_` : ""}`).join("\n")}`, "fallbackText")
|
|
1560
|
+
});
|
|
1561
|
+
var Timeline = defineComponent({
|
|
1562
|
+
name: "Timeline",
|
|
1563
|
+
title: "Timeline",
|
|
1564
|
+
description: "Events in chronological order (the history of a project, an incident, a deal).",
|
|
1565
|
+
props: obj({
|
|
1566
|
+
title: str(),
|
|
1567
|
+
events: arr(obj({
|
|
1568
|
+
date: str(),
|
|
1569
|
+
title: str(),
|
|
1570
|
+
description: str()
|
|
1571
|
+
}, [
|
|
1572
|
+
"title"
|
|
1573
|
+
]), {
|
|
1574
|
+
minItems: 1,
|
|
1575
|
+
maxItems: 50
|
|
1576
|
+
})
|
|
1577
|
+
}, [
|
|
1578
|
+
"events"
|
|
1579
|
+
]),
|
|
1580
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${(props.events ?? []).map((event) => `\u2022 ${event.date ? `*${s(event.date)}* ` : ""}${s(event.title)}${event.description ? ` \u2014 ${s(event.description)}` : ""}`).join("\n")}`, "fallbackText")
|
|
1581
|
+
});
|
|
1582
|
+
var CodeBlock = defineComponent({
|
|
1583
|
+
name: "CodeBlock",
|
|
1584
|
+
title: "Code",
|
|
1585
|
+
description: "A code snippet or file excerpt with syntax highlighting.",
|
|
1586
|
+
props: obj({
|
|
1587
|
+
title: str(),
|
|
1588
|
+
language: str(),
|
|
1589
|
+
code: str()
|
|
1590
|
+
}, [
|
|
1591
|
+
"code"
|
|
1592
|
+
]),
|
|
1593
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}\`\`\`
|
|
1594
|
+
${s(props.code)}
|
|
1595
|
+
\`\`\``, "fallbackText")
|
|
1596
|
+
});
|
|
1597
|
+
var Diff = defineComponent({
|
|
1598
|
+
name: "Diff",
|
|
1599
|
+
title: "Diff",
|
|
1600
|
+
description: "A before/after change to a text or code file, as a line diff.",
|
|
1601
|
+
props: obj({
|
|
1602
|
+
title: str(),
|
|
1603
|
+
language: str(),
|
|
1604
|
+
before: str(),
|
|
1605
|
+
after: str()
|
|
1606
|
+
}, [
|
|
1607
|
+
"before",
|
|
1608
|
+
"after"
|
|
1609
|
+
]),
|
|
1610
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}\`\`\`
|
|
1611
|
+
${lineDiff(s(props.before), s(props.after)).map((line) => `${line.op === "add" ? "+" : line.op === "del" ? "-" : " "} ${line.text}`).join("\n")}
|
|
1612
|
+
\`\`\``, "fallbackText")
|
|
1613
|
+
});
|
|
1614
|
+
var Callout = defineComponent({
|
|
1615
|
+
name: "Callout",
|
|
1616
|
+
title: "Callout",
|
|
1617
|
+
description: "A short note, warning or success message, emphasized.",
|
|
1618
|
+
props: obj({
|
|
1619
|
+
tone: str(void 0, {
|
|
1620
|
+
enum: [
|
|
1621
|
+
"info",
|
|
1622
|
+
"success",
|
|
1623
|
+
"warning",
|
|
1624
|
+
"danger"
|
|
1625
|
+
]
|
|
1626
|
+
}),
|
|
1627
|
+
title: str(),
|
|
1628
|
+
text: str()
|
|
1629
|
+
}, [
|
|
1630
|
+
"text"
|
|
1631
|
+
]),
|
|
1632
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${props.tone === "warning" || props.tone === "danger" ? ":warning: " : ":information_source: "}${heading(props)}${s(props.text)}`, "fallbackText")
|
|
1633
|
+
});
|
|
1634
|
+
var Stack = defineComponent({
|
|
1635
|
+
name: "Stack",
|
|
1636
|
+
title: "Stack",
|
|
1637
|
+
description: "Lays its children out vertically (or horizontally with direction=row).",
|
|
1638
|
+
props: obj({
|
|
1639
|
+
direction: str(void 0, {
|
|
1640
|
+
enum: [
|
|
1641
|
+
"column",
|
|
1642
|
+
"row"
|
|
1643
|
+
]
|
|
1644
|
+
}),
|
|
1645
|
+
gap: {
|
|
1646
|
+
type: "number"
|
|
1647
|
+
}
|
|
1648
|
+
}),
|
|
1649
|
+
children: true,
|
|
1650
|
+
fallbackText: /* @__PURE__ */ __name(() => "", "fallbackText")
|
|
1651
|
+
});
|
|
1652
|
+
var Card = defineComponent({
|
|
1653
|
+
name: "Card",
|
|
1654
|
+
title: "Card",
|
|
1655
|
+
description: "A box with an optional title around its children.",
|
|
1656
|
+
props: obj({
|
|
1657
|
+
title: str(),
|
|
1658
|
+
subtitle: str()
|
|
1659
|
+
}),
|
|
1660
|
+
children: true,
|
|
1661
|
+
fallbackText: /* @__PURE__ */ __name((props) => props.title ? `*${s(props.title)}*${props.subtitle ? ` \u2014 ${s(props.subtitle)}` : ""}` : "", "fallbackText")
|
|
1662
|
+
});
|
|
1663
|
+
var Heading = defineComponent({
|
|
1664
|
+
name: "Heading",
|
|
1665
|
+
title: "Heading",
|
|
1666
|
+
description: "A heading.",
|
|
1667
|
+
props: obj({
|
|
1668
|
+
text: str()
|
|
1669
|
+
}, [
|
|
1670
|
+
"text"
|
|
1671
|
+
]),
|
|
1672
|
+
fallbackText: /* @__PURE__ */ __name((props) => `*${s(props.text)}*`, "fallbackText")
|
|
1673
|
+
});
|
|
1674
|
+
var Text = defineComponent({
|
|
1675
|
+
name: "Text",
|
|
1676
|
+
title: "Text",
|
|
1677
|
+
description: "A paragraph of plain text (no markdown).",
|
|
1678
|
+
props: obj({
|
|
1679
|
+
text: str(),
|
|
1680
|
+
muted: {
|
|
1681
|
+
type: "boolean"
|
|
1682
|
+
}
|
|
1683
|
+
}, [
|
|
1684
|
+
"text"
|
|
1685
|
+
]),
|
|
1686
|
+
fallbackText: /* @__PURE__ */ __name((props) => s(props.text), "fallbackText")
|
|
1687
|
+
});
|
|
1688
|
+
var Badge = defineComponent({
|
|
1689
|
+
name: "Badge",
|
|
1690
|
+
title: "Badge",
|
|
1691
|
+
description: "A small label.",
|
|
1692
|
+
props: obj({
|
|
1693
|
+
text: str(),
|
|
1694
|
+
tone: str(void 0, {
|
|
1695
|
+
enum: [
|
|
1696
|
+
"neutral",
|
|
1697
|
+
"brand",
|
|
1698
|
+
"success",
|
|
1699
|
+
"warning",
|
|
1700
|
+
"danger"
|
|
1701
|
+
]
|
|
1702
|
+
})
|
|
1703
|
+
}, [
|
|
1704
|
+
"text"
|
|
1705
|
+
]),
|
|
1706
|
+
fallbackText: /* @__PURE__ */ __name((props) => `[${s(props.text)}]`, "fallbackText")
|
|
1707
|
+
});
|
|
1708
|
+
var Link = defineComponent({
|
|
1709
|
+
name: "Link",
|
|
1710
|
+
title: "Link",
|
|
1711
|
+
description: "A link to an http(s) URL.",
|
|
1712
|
+
props: obj({
|
|
1713
|
+
text: str(),
|
|
1714
|
+
url: str(void 0, {
|
|
1715
|
+
pattern: "^https?://"
|
|
1716
|
+
})
|
|
1717
|
+
}, [
|
|
1718
|
+
"text",
|
|
1719
|
+
"url"
|
|
1720
|
+
]),
|
|
1721
|
+
fallbackText: /* @__PURE__ */ __name((props) => `<${s(props.url)}|${s(props.text || props.url)}>`, "fallbackText")
|
|
1722
|
+
});
|
|
1723
|
+
var Image = defineComponent({
|
|
1724
|
+
name: "Image",
|
|
1725
|
+
title: "Image",
|
|
1726
|
+
description: "An image from an https URL.",
|
|
1727
|
+
props: obj({
|
|
1728
|
+
url: str(void 0, {
|
|
1729
|
+
pattern: "^https://"
|
|
1730
|
+
}),
|
|
1731
|
+
alt: str()
|
|
1732
|
+
}, [
|
|
1733
|
+
"url"
|
|
1734
|
+
]),
|
|
1735
|
+
fallbackText: /* @__PURE__ */ __name((props) => s(props.url), "fallbackText")
|
|
1736
|
+
});
|
|
1737
|
+
|
|
1738
|
+
// src/genui/registry.ts
|
|
1739
|
+
function snapshotComponentPresentation(value) {
|
|
1740
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1741
|
+
const check2 = /* @__PURE__ */ __name((entry) => {
|
|
1742
|
+
if (entry === null || typeof entry === "string" || typeof entry === "boolean") return;
|
|
1743
|
+
if (typeof entry === "number" && Number.isFinite(entry)) return;
|
|
1744
|
+
if (typeof entry !== "object" || entry === null) throw new TypeError("genui: presentation must contain only JSON values");
|
|
1745
|
+
if (seen.has(entry)) throw new TypeError("genui: presentation must contain acyclic JSON values");
|
|
1746
|
+
if (!Array.isArray(entry) && Object.getPrototypeOf(entry) !== Object.prototype && Object.getPrototypeOf(entry) !== null) throw new TypeError("genui: presentation must contain plain JSON objects");
|
|
1747
|
+
seen.add(entry);
|
|
1748
|
+
for (const item of Object.values(entry)) check2(item);
|
|
1749
|
+
seen.delete(entry);
|
|
1750
|
+
}, "check");
|
|
1751
|
+
check2(value);
|
|
1752
|
+
return JSON.parse(JSON.stringify(value));
|
|
1753
|
+
}
|
|
1754
|
+
__name(snapshotComponentPresentation, "snapshotComponentPresentation");
|
|
1755
|
+
function createComponent(definition, options = {}) {
|
|
1756
|
+
defineComponent(definition);
|
|
1757
|
+
const catalog = defineCatalog([
|
|
1758
|
+
definition
|
|
1759
|
+
], options);
|
|
1760
|
+
const factory = /* @__PURE__ */ __name(async (props) => {
|
|
1761
|
+
const result = await validateProps(definition.props, props, catalog.validator);
|
|
1762
|
+
if (!result.ok) throw new Error(`genui: invalid ${definition.name} props: ${formatIssues(result.issues)}`);
|
|
1763
|
+
const normalized = snapshotComponentPresentation(result.value);
|
|
1764
|
+
if (typeof normalized !== "object" || normalized === null || Array.isArray(normalized)) throw new TypeError("genui: component props must be a JSON object");
|
|
1765
|
+
const portable = await catalog.validate(definition.name, normalized);
|
|
1766
|
+
if (!portable.ok || canonicalJson(snapshotComponentPresentation(portable.value)) !== canonicalJson(normalized)) {
|
|
1767
|
+
throw new Error(`genui: ${definition.name} requires outputProps accepting stable normalized JSON props`);
|
|
1768
|
+
}
|
|
1769
|
+
return {
|
|
1770
|
+
component: definition.name,
|
|
1771
|
+
props: normalized,
|
|
1772
|
+
version: definition.version ?? 1,
|
|
1773
|
+
fallbackText: componentToText(catalog, definition.name, normalized)
|
|
1774
|
+
};
|
|
1775
|
+
}, "factory");
|
|
1776
|
+
return Object.assign(factory, {
|
|
1777
|
+
definition
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
__name(createComponent, "createComponent");
|
|
1781
|
+
function createComponentRegistry(options = {}) {
|
|
1782
|
+
let catalog = defineCatalog([], options);
|
|
1783
|
+
const channels = /* @__PURE__ */ new Map();
|
|
1784
|
+
const registry = {
|
|
1785
|
+
get catalog() {
|
|
1786
|
+
return catalog;
|
|
1787
|
+
},
|
|
1788
|
+
get manifest() {
|
|
1789
|
+
return catalog.components.map((definition) => {
|
|
1790
|
+
const props = catalog.jsonSchemaFor(definition.name);
|
|
1791
|
+
return {
|
|
1792
|
+
name: definition.name,
|
|
1793
|
+
title: definition.title,
|
|
1794
|
+
description: definition.description,
|
|
1795
|
+
version: definition.version ?? 1,
|
|
1796
|
+
...props === void 0 ? {} : {
|
|
1797
|
+
props: snapshotComponentPresentation(props)
|
|
1798
|
+
}
|
|
1799
|
+
};
|
|
1800
|
+
});
|
|
1801
|
+
},
|
|
1802
|
+
register(definition, renderers) {
|
|
1803
|
+
if (catalog.has(definition.name)) throw new Error(`genui: component "${definition.name}" is already registered`);
|
|
1804
|
+
catalog = catalog.extend([
|
|
1805
|
+
definition
|
|
1806
|
+
]);
|
|
1807
|
+
channels.set(definition.name, {
|
|
1808
|
+
...renderers
|
|
1809
|
+
});
|
|
1810
|
+
return this;
|
|
1811
|
+
},
|
|
1812
|
+
async prepare(presentation) {
|
|
1813
|
+
const definition = catalog.get(presentation.component);
|
|
1814
|
+
if (definition === void 0) throw new Error(`genui: unknown component "${presentation.component}"`);
|
|
1815
|
+
if (presentation.version !== (definition.version ?? 1)) throw new Error(`genui: component "${presentation.component}" version mismatch`);
|
|
1816
|
+
const validated = await catalog.validate(presentation.component, presentation.props);
|
|
1817
|
+
if (!validated.ok) throw new Error(`genui: invalid ${presentation.component} props: ${formatIssues(validated.issues)}`);
|
|
1818
|
+
const props = snapshotComponentPresentation(validated.value);
|
|
1819
|
+
if (typeof props !== "object" || props === null || Array.isArray(props)) throw new TypeError("genui: component props must be a JSON object");
|
|
1820
|
+
return {
|
|
1821
|
+
component: definition.name,
|
|
1822
|
+
props,
|
|
1823
|
+
version: definition.version ?? 1,
|
|
1824
|
+
fallbackText: componentToText(catalog, definition.name, props)
|
|
1825
|
+
};
|
|
1826
|
+
},
|
|
1827
|
+
async render(presentation, channel, context) {
|
|
1828
|
+
const prepared = await this.prepare(presentation);
|
|
1829
|
+
const mapping = channels.get(prepared.component);
|
|
1830
|
+
const renderer = mapping === void 0 ? void 0 : Object.hasOwn(mapping, channel) ? mapping[channel] : Object.hasOwn(mapping, "text") ? mapping.text : void 0;
|
|
1831
|
+
return renderer === void 0 ? prepared.fallbackText : renderer(prepared.props, context);
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
return registry;
|
|
1835
|
+
}
|
|
1836
|
+
__name(createComponentRegistry, "createComponentRegistry");
|
|
1837
|
+
var table = createComponent(DataTable);
|
|
1838
|
+
var chart = createComponent(Chart);
|
|
1839
|
+
function validatePresentationBatch(presentations) {
|
|
1840
|
+
const batch = Array.isArray(presentations) ? presentations : [
|
|
1841
|
+
presentations
|
|
1842
|
+
];
|
|
1843
|
+
return batch.map((item) => {
|
|
1844
|
+
const presentation = snapshotComponentPresentation(item);
|
|
1845
|
+
if (typeof presentation !== "object" || presentation === null || typeof presentation.component !== "string" || !/^[A-Za-z][A-Za-z0-9]{0,63}$/.test(presentation.component) || !Number.isSafeInteger(presentation.version) || presentation.version <= 0 || typeof presentation.fallbackText !== "string" || typeof presentation.props !== "object" || presentation.props === null || Array.isArray(presentation.props)) {
|
|
1846
|
+
throw new TypeError("genui: invalid component presentation");
|
|
1847
|
+
}
|
|
1848
|
+
return presentation;
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
__name(validatePresentationBatch, "validatePresentationBatch");
|
|
1852
|
+
function canonicalJson(value) {
|
|
1853
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
1854
|
+
if (typeof value === "object" && value !== null) {
|
|
1855
|
+
const record2 = value;
|
|
1856
|
+
return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record2[key])}`).join(",")}}`;
|
|
1857
|
+
}
|
|
1858
|
+
return JSON.stringify(value);
|
|
1859
|
+
}
|
|
1860
|
+
__name(canonicalJson, "canonicalJson");
|
|
1196
1861
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1197
1862
|
0 && (module.exports = {
|
|
1198
1863
|
COMPONENT_NAME,
|
|
@@ -1201,7 +1866,10 @@ __name(asyncJsonStandardSchema, "asyncJsonStandardSchema");
|
|
|
1201
1866
|
ajvValidator,
|
|
1202
1867
|
builtinJsonSchemaValidator,
|
|
1203
1868
|
catalogToModelText,
|
|
1869
|
+
chart,
|
|
1204
1870
|
componentToText,
|
|
1871
|
+
createComponent,
|
|
1872
|
+
createComponentRegistry,
|
|
1205
1873
|
defineCatalog,
|
|
1206
1874
|
defineComponent,
|
|
1207
1875
|
fillTemplate,
|
|
@@ -1210,16 +1878,22 @@ __name(asyncJsonStandardSchema, "asyncJsonStandardSchema");
|
|
|
1210
1878
|
getPath,
|
|
1211
1879
|
isStandardSchema,
|
|
1212
1880
|
jsonStandardSchema,
|
|
1881
|
+
negotiateCatalog,
|
|
1882
|
+
prepareUiEmission,
|
|
1213
1883
|
showToolJsonSchema,
|
|
1884
|
+
snapshotComponentPresentation,
|
|
1214
1885
|
summarizeSchema,
|
|
1886
|
+
table,
|
|
1215
1887
|
toJsonSchema,
|
|
1216
1888
|
toSnakeCase,
|
|
1217
1889
|
toolNameFor,
|
|
1218
1890
|
treeJsonSchema,
|
|
1219
1891
|
treeToFlatSpec,
|
|
1220
1892
|
treeToText,
|
|
1893
|
+
validatePresentationBatch,
|
|
1221
1894
|
validateProps,
|
|
1222
1895
|
validatePropsSync,
|
|
1223
|
-
validateTree
|
|
1896
|
+
validateTree,
|
|
1897
|
+
validateUiCapabilities
|
|
1224
1898
|
});
|
|
1225
1899
|
//# sourceMappingURL=index.cjs.map
|