@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.js
CHANGED
|
@@ -177,21 +177,21 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
177
177
|
});
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
|
-
const
|
|
181
|
-
if (typeof
|
|
182
|
-
const target = resolveRef(root,
|
|
180
|
+
const s2 = schema;
|
|
181
|
+
if (typeof s2.$ref === "string") {
|
|
182
|
+
const target = resolveRef(root, s2.$ref);
|
|
183
183
|
if (target === void 0) {
|
|
184
184
|
issues.push({
|
|
185
185
|
path,
|
|
186
|
-
message: `references unknown schema ${
|
|
186
|
+
message: `references unknown schema ${s2.$ref}`
|
|
187
187
|
});
|
|
188
188
|
return;
|
|
189
189
|
}
|
|
190
190
|
check(target, value, path, root, issues, depth + 1);
|
|
191
191
|
}
|
|
192
|
-
if (
|
|
193
|
-
const types = Array.isArray(
|
|
194
|
-
|
|
192
|
+
if (s2.type !== void 0) {
|
|
193
|
+
const types = Array.isArray(s2.type) ? s2.type : [
|
|
194
|
+
s2.type
|
|
195
195
|
];
|
|
196
196
|
if (!types.some((type) => matchesType(type, value))) {
|
|
197
197
|
issues.push({
|
|
@@ -201,76 +201,76 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
201
201
|
return;
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
|
-
if (Array.isArray(
|
|
204
|
+
if (Array.isArray(s2.enum) && !s2.enum.some((option) => deepEqual(option, value))) {
|
|
205
205
|
issues.push({
|
|
206
206
|
path,
|
|
207
|
-
message: `must be one of ${
|
|
207
|
+
message: `must be one of ${s2.enum.map((option) => JSON.stringify(option)).join(", ")}`
|
|
208
208
|
});
|
|
209
209
|
}
|
|
210
|
-
if ("const" in
|
|
210
|
+
if ("const" in s2 && !deepEqual(s2.const, value)) {
|
|
211
211
|
issues.push({
|
|
212
212
|
path,
|
|
213
|
-
message: `must be ${JSON.stringify(
|
|
213
|
+
message: `must be ${JSON.stringify(s2.const)}`
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
216
|
if (typeof value === "string") {
|
|
217
|
-
if (typeof
|
|
217
|
+
if (typeof s2.minLength === "number" && value.length < s2.minLength) {
|
|
218
218
|
issues.push({
|
|
219
219
|
path,
|
|
220
|
-
message: `must be at least ${
|
|
220
|
+
message: `must be at least ${s2.minLength} characters`
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
|
-
if (typeof
|
|
223
|
+
if (typeof s2.maxLength === "number" && value.length > s2.maxLength) {
|
|
224
224
|
issues.push({
|
|
225
225
|
path,
|
|
226
|
-
message: `must be at most ${
|
|
226
|
+
message: `must be at most ${s2.maxLength} characters`
|
|
227
227
|
});
|
|
228
228
|
}
|
|
229
|
-
if (typeof
|
|
229
|
+
if (typeof s2.pattern === "string") {
|
|
230
230
|
let pattern;
|
|
231
231
|
try {
|
|
232
|
-
pattern = new RegExp(
|
|
232
|
+
pattern = new RegExp(s2.pattern, "u");
|
|
233
233
|
} catch {
|
|
234
234
|
pattern = void 0;
|
|
235
235
|
}
|
|
236
236
|
if (pattern !== void 0 && !pattern.test(value)) {
|
|
237
237
|
issues.push({
|
|
238
238
|
path,
|
|
239
|
-
message: `must match ${
|
|
239
|
+
message: `must match ${s2.pattern}`
|
|
240
240
|
});
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
if (typeof value === "number") {
|
|
245
|
-
if (typeof
|
|
245
|
+
if (typeof s2.minimum === "number" && value < s2.minimum) {
|
|
246
246
|
issues.push({
|
|
247
247
|
path,
|
|
248
|
-
message: `must be >= ${
|
|
248
|
+
message: `must be >= ${s2.minimum}`
|
|
249
249
|
});
|
|
250
250
|
}
|
|
251
|
-
if (typeof
|
|
251
|
+
if (typeof s2.maximum === "number" && value > s2.maximum) {
|
|
252
252
|
issues.push({
|
|
253
253
|
path,
|
|
254
|
-
message: `must be <= ${
|
|
254
|
+
message: `must be <= ${s2.maximum}`
|
|
255
255
|
});
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
if (Array.isArray(value)) {
|
|
259
|
-
if (typeof
|
|
259
|
+
if (typeof s2.minItems === "number" && value.length < s2.minItems) {
|
|
260
260
|
issues.push({
|
|
261
261
|
path,
|
|
262
|
-
message: `must have at least ${
|
|
262
|
+
message: `must have at least ${s2.minItems} items`
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
|
-
if (typeof
|
|
265
|
+
if (typeof s2.maxItems === "number" && value.length > s2.maxItems) {
|
|
266
266
|
issues.push({
|
|
267
267
|
path,
|
|
268
|
-
message: `must have at most ${
|
|
268
|
+
message: `must have at most ${s2.maxItems} items`
|
|
269
269
|
});
|
|
270
270
|
}
|
|
271
|
-
if (
|
|
271
|
+
if (s2.items !== void 0 && !Array.isArray(s2.items)) {
|
|
272
272
|
value.forEach((item, index) => {
|
|
273
|
-
check(
|
|
273
|
+
check(s2.items, item, [
|
|
274
274
|
...path,
|
|
275
275
|
index
|
|
276
276
|
], root, issues, depth + 1);
|
|
@@ -278,11 +278,11 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
278
278
|
}
|
|
279
279
|
}
|
|
280
280
|
if (matchesType("object", value)) {
|
|
281
|
-
const
|
|
282
|
-
const properties = typeof
|
|
283
|
-
if (Array.isArray(
|
|
284
|
-
for (const key of
|
|
285
|
-
if (
|
|
281
|
+
const record2 = value;
|
|
282
|
+
const properties = typeof s2.properties === "object" && s2.properties !== null ? s2.properties : {};
|
|
283
|
+
if (Array.isArray(s2.required)) {
|
|
284
|
+
for (const key of s2.required) {
|
|
285
|
+
if (record2[key] === void 0) {
|
|
286
286
|
issues.push({
|
|
287
287
|
path: [
|
|
288
288
|
...path,
|
|
@@ -293,7 +293,7 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
}
|
|
296
|
-
for (const [key, entry] of Object.entries(
|
|
296
|
+
for (const [key, entry] of Object.entries(record2)) {
|
|
297
297
|
if (key in properties) {
|
|
298
298
|
if (entry !== void 0) {
|
|
299
299
|
check(properties[key], entry, [
|
|
@@ -301,7 +301,7 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
301
301
|
key
|
|
302
302
|
], root, issues, depth + 1);
|
|
303
303
|
}
|
|
304
|
-
} else if (
|
|
304
|
+
} else if (s2.additionalProperties === false) {
|
|
305
305
|
issues.push({
|
|
306
306
|
path: [
|
|
307
307
|
...path,
|
|
@@ -309,34 +309,34 @@ function check(schema, value, path, root, issues, depth) {
|
|
|
309
309
|
],
|
|
310
310
|
message: "is not a known property"
|
|
311
311
|
});
|
|
312
|
-
} else if (typeof
|
|
313
|
-
check(
|
|
312
|
+
} else if (typeof s2.additionalProperties === "object" && s2.additionalProperties !== null) {
|
|
313
|
+
check(s2.additionalProperties, entry, [
|
|
314
314
|
...path,
|
|
315
315
|
key
|
|
316
316
|
], root, issues, depth + 1);
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
|
-
if (Array.isArray(
|
|
321
|
-
for (const sub of
|
|
320
|
+
if (Array.isArray(s2.allOf)) {
|
|
321
|
+
for (const sub of s2.allOf) check(sub, value, path, root, issues, depth + 1);
|
|
322
322
|
}
|
|
323
|
-
if (Array.isArray(
|
|
324
|
-
const options = Array.isArray(
|
|
323
|
+
if (Array.isArray(s2.anyOf) || Array.isArray(s2.oneOf)) {
|
|
324
|
+
const options = Array.isArray(s2.anyOf) ? s2.anyOf : s2.oneOf;
|
|
325
325
|
const passing = options.filter((sub) => {
|
|
326
326
|
const nested = [];
|
|
327
327
|
check(sub, value, path, root, nested, depth + 1);
|
|
328
328
|
return nested.length === 0;
|
|
329
329
|
}).length;
|
|
330
|
-
if (Array.isArray(
|
|
330
|
+
if (Array.isArray(s2.anyOf) ? passing === 0 : passing !== 1) {
|
|
331
331
|
issues.push({
|
|
332
332
|
path,
|
|
333
|
-
message: Array.isArray(
|
|
333
|
+
message: Array.isArray(s2.anyOf) ? "does not match any allowed shape" : "must match exactly one allowed shape"
|
|
334
334
|
});
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
|
-
if (
|
|
337
|
+
if (s2.not !== void 0) {
|
|
338
338
|
const nested = [];
|
|
339
|
-
check(
|
|
339
|
+
check(s2.not, value, path, root, nested, depth + 1);
|
|
340
340
|
if (nested.length === 0) {
|
|
341
341
|
issues.push({
|
|
342
342
|
path,
|
|
@@ -353,6 +353,8 @@ function defineComponent(definition) {
|
|
|
353
353
|
if (!COMPONENT_NAME.test(definition.name)) {
|
|
354
354
|
throw new Error(`genui: component name "${definition.name}" must be letters and digits, starting with a letter (e.g. DataTable)`);
|
|
355
355
|
}
|
|
356
|
+
if (definition.version !== void 0 && (!Number.isSafeInteger(definition.version) || definition.version <= 0)) throw new RangeError("genui: component version must be a positive safe integer");
|
|
357
|
+
if (definition.fallbackText !== void 0 && typeof definition.fallbackText !== "function") throw new TypeError("genui: fallbackText must be a function");
|
|
356
358
|
return definition;
|
|
357
359
|
}
|
|
358
360
|
__name(defineComponent, "defineComponent");
|
|
@@ -391,7 +393,7 @@ function buildCatalog(byName, validator) {
|
|
|
391
393
|
]
|
|
392
394
|
};
|
|
393
395
|
}
|
|
394
|
-
const result = await validateProps(definition.props, props, validator);
|
|
396
|
+
const result = await validateProps(definition.outputProps ?? definition.props, props, validator);
|
|
395
397
|
return result;
|
|
396
398
|
},
|
|
397
399
|
validateSync(component, props) {
|
|
@@ -407,11 +409,11 @@ function buildCatalog(byName, validator) {
|
|
|
407
409
|
]
|
|
408
410
|
};
|
|
409
411
|
}
|
|
410
|
-
return validatePropsSync(definition.props, props, validator);
|
|
412
|
+
return validatePropsSync(definition.outputProps ?? definition.props, props, validator);
|
|
411
413
|
},
|
|
412
414
|
jsonSchemaFor(component) {
|
|
413
415
|
const definition = byName.get(component);
|
|
414
|
-
return definition === void 0 ? void 0 : toJsonSchema(definition.props);
|
|
416
|
+
return definition === void 0 ? void 0 : toJsonSchema(definition.outputProps ?? definition.props);
|
|
415
417
|
},
|
|
416
418
|
extend(more) {
|
|
417
419
|
const next = new Map(byName);
|
|
@@ -435,7 +437,7 @@ __name(toolNameFor, "toolNameFor");
|
|
|
435
437
|
|
|
436
438
|
// src/genui/tree.ts
|
|
437
439
|
var GENUI_TREE_COMPONENT = "genui:tree";
|
|
438
|
-
async function validateTree(catalog, tree, limits = {}) {
|
|
440
|
+
async function validateTree(catalog, tree, limits = {}, phase = "output") {
|
|
439
441
|
const maxDepth = limits.maxDepth ?? 12;
|
|
440
442
|
const maxNodes = limits.maxNodes ?? 200;
|
|
441
443
|
const issues = [];
|
|
@@ -487,7 +489,7 @@ async function validateTree(catalog, tree, limits = {}) {
|
|
|
487
489
|
});
|
|
488
490
|
return void 0;
|
|
489
491
|
}
|
|
490
|
-
const validated = await catalog.validate(element.type, element.props ?? {});
|
|
492
|
+
const validated = phase === "input" ? await validateProps(definition.props, element.props ?? {}, catalog.validator) : await catalog.validate(element.type, element.props ?? {});
|
|
491
493
|
let props = {};
|
|
492
494
|
if (!validated.ok) {
|
|
493
495
|
for (const issue of validated.issues) {
|
|
@@ -661,7 +663,8 @@ function componentToText(catalog, component, props) {
|
|
|
661
663
|
const fallback = catalog.get(component)?.fallbackText;
|
|
662
664
|
if (fallback !== void 0) {
|
|
663
665
|
try {
|
|
664
|
-
|
|
666
|
+
const text = fallback(props);
|
|
667
|
+
if (typeof text === "string" && text.trim().length > 0) return text;
|
|
665
668
|
} catch {
|
|
666
669
|
}
|
|
667
670
|
}
|
|
@@ -675,7 +678,8 @@ function treeToText(catalog, root) {
|
|
|
675
678
|
const definition = catalog.get(node.type);
|
|
676
679
|
if (definition?.fallbackText !== void 0) {
|
|
677
680
|
try {
|
|
678
|
-
|
|
681
|
+
const text = definition.fallbackText(node.props);
|
|
682
|
+
out.push(typeof text === "string" && text.trim().length > 0 ? text : jsonBlock(node.props));
|
|
679
683
|
} catch {
|
|
680
684
|
out.push(jsonBlock(node.props));
|
|
681
685
|
}
|
|
@@ -692,7 +696,7 @@ function jsonBlock(props) {
|
|
|
692
696
|
const title = typeof props.title === "string" && props.title.length > 0 ? `*${props.title}*
|
|
693
697
|
` : "";
|
|
694
698
|
return `${title}\`\`\`
|
|
695
|
-
${JSON.stringify(props, null, 2)
|
|
699
|
+
${JSON.stringify(props, null, 2)}
|
|
696
700
|
\`\`\``;
|
|
697
701
|
}
|
|
698
702
|
__name(jsonBlock, "jsonBlock");
|
|
@@ -707,7 +711,7 @@ function catalogToModelText(catalog, options = {}) {
|
|
|
707
711
|
lines.push("Components you can show (one tool each):");
|
|
708
712
|
}
|
|
709
713
|
for (const component of catalog.modelComponents()) {
|
|
710
|
-
const schema =
|
|
714
|
+
const schema = toJsonSchema(component.props);
|
|
711
715
|
const head = mode === "per-component" ? `- ${component.name} (tool \`${toolNameFor(component.name, options.namePrefix)}\`)` : `- ${component.name}`;
|
|
712
716
|
lines.push(`${head}: ${component.description}`);
|
|
713
717
|
if (schema !== void 0) {
|
|
@@ -722,38 +726,38 @@ function catalogToModelText(catalog, options = {}) {
|
|
|
722
726
|
__name(catalogToModelText, "catalogToModelText");
|
|
723
727
|
function summarizeSchema(schema, root, depth) {
|
|
724
728
|
if (typeof schema !== "object" || schema === null) return "unknown";
|
|
725
|
-
const
|
|
729
|
+
const s2 = schema;
|
|
726
730
|
if (depth > 5) return "\u2026";
|
|
727
|
-
if (typeof
|
|
728
|
-
return
|
|
731
|
+
if (typeof s2.$ref === "string") {
|
|
732
|
+
return s2.$ref === "#" ? "Self" : s2.$ref.split("/").pop() ?? "unknown";
|
|
729
733
|
}
|
|
730
|
-
if (Array.isArray(
|
|
731
|
-
return
|
|
734
|
+
if (Array.isArray(s2.enum)) {
|
|
735
|
+
return s2.enum.map((option) => JSON.stringify(option)).join(" | ");
|
|
732
736
|
}
|
|
733
|
-
if ("const" in
|
|
734
|
-
const variants =
|
|
737
|
+
if ("const" in s2) return JSON.stringify(s2.const);
|
|
738
|
+
const variants = s2.anyOf ?? s2.oneOf;
|
|
735
739
|
if (Array.isArray(variants)) {
|
|
736
740
|
return variants.map((variant) => summarizeSchema(variant, root, depth + 1)).join(" | ");
|
|
737
741
|
}
|
|
738
|
-
const types = Array.isArray(
|
|
739
|
-
|
|
742
|
+
const types = Array.isArray(s2.type) ? s2.type : s2.type !== void 0 ? [
|
|
743
|
+
s2.type
|
|
740
744
|
] : [];
|
|
741
745
|
if (types.length > 1) {
|
|
742
746
|
return types.map((type2) => summarizeSchema({
|
|
743
|
-
...
|
|
747
|
+
...s2,
|
|
744
748
|
type: type2
|
|
745
749
|
}, root, depth + 1)).join(" | ");
|
|
746
750
|
}
|
|
747
751
|
const type = types[0];
|
|
748
752
|
if (type === "array") {
|
|
749
|
-
const item =
|
|
753
|
+
const item = s2.items === void 0 ? "unknown" : summarizeSchema(s2.items, root, depth + 1);
|
|
750
754
|
return /[|\s]/.test(item) && !item.startsWith("{") ? `(${item})[]` : `${item}[]`;
|
|
751
755
|
}
|
|
752
|
-
if (type === "object" || type === void 0 &&
|
|
753
|
-
const properties =
|
|
756
|
+
if (type === "object" || type === void 0 && s2.properties !== void 0) {
|
|
757
|
+
const properties = s2.properties ?? {};
|
|
754
758
|
const keys = Object.keys(properties);
|
|
755
759
|
if (keys.length === 0) return "object";
|
|
756
|
-
const required = new Set(Array.isArray(
|
|
760
|
+
const required = new Set(Array.isArray(s2.required) ? s2.required : []);
|
|
757
761
|
const fields = keys.map((key) => {
|
|
758
762
|
const field = properties[key];
|
|
759
763
|
const note = typeof field?.description === "string" && depth === 0 ? ` /* ${field.description} */` : "";
|
|
@@ -783,6 +787,81 @@ function getPath(source, path) {
|
|
|
783
787
|
}
|
|
784
788
|
__name(getPath, "getPath");
|
|
785
789
|
|
|
790
|
+
// src/genui/capabilities.ts
|
|
791
|
+
function validateUiCapabilities(value) {
|
|
792
|
+
if (!record(value) || Object.keys(value).some((key) => key !== "components") || !Array.isArray(value.components)) throw new TypeError("Invalid UI capabilities");
|
|
793
|
+
const seen = /* @__PURE__ */ new Set();
|
|
794
|
+
const components = value.components.map((component) => {
|
|
795
|
+
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");
|
|
796
|
+
seen.add(component.name);
|
|
797
|
+
return {
|
|
798
|
+
name: component.name,
|
|
799
|
+
version: Number(component.version)
|
|
800
|
+
};
|
|
801
|
+
});
|
|
802
|
+
return {
|
|
803
|
+
components
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
__name(validateUiCapabilities, "validateUiCapabilities");
|
|
807
|
+
function record(value) {
|
|
808
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
809
|
+
}
|
|
810
|
+
__name(record, "record");
|
|
811
|
+
function negotiateCatalog(catalog, capabilities) {
|
|
812
|
+
if (capabilities === void 0) return catalog;
|
|
813
|
+
const supported = validateUiCapabilities(capabilities).components;
|
|
814
|
+
return defineCatalog(catalog.components.filter((component) => supported.some((entry) => entry.name === component.name && entry.version === (component.version ?? 1))), {
|
|
815
|
+
jsonSchemaValidator: catalog.validator
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
__name(negotiateCatalog, "negotiateCatalog");
|
|
819
|
+
async function prepareUiEmission(catalog, capabilities, component, props, version) {
|
|
820
|
+
const drawable = negotiateCatalog(catalog, capabilities);
|
|
821
|
+
if (component === GENUI_TREE_COMPONENT) {
|
|
822
|
+
if (version !== void 0 && version !== 1) throw new Error("Invalid UI tree version");
|
|
823
|
+
const validated2 = await validateTree(catalog, props.root);
|
|
824
|
+
if (!validated2.ok) throw new Error(`Invalid UI tree: ${formatIssues(validated2.issues)}`);
|
|
825
|
+
const supported = /* @__PURE__ */ __name((node) => drawable.has(node.type) && (node.children ?? []).every(supported), "supported");
|
|
826
|
+
const versions = /* @__PURE__ */ new Map();
|
|
827
|
+
const collectVersions = /* @__PURE__ */ __name((node) => {
|
|
828
|
+
versions.set(node.type, catalog.get(node.type)?.version ?? 1);
|
|
829
|
+
for (const child of node.children ?? []) collectVersions(child);
|
|
830
|
+
}, "collectVersions");
|
|
831
|
+
collectVersions(validated2.value);
|
|
832
|
+
return supported(validated2.value) ? {
|
|
833
|
+
kind: "ui",
|
|
834
|
+
component,
|
|
835
|
+
props: {
|
|
836
|
+
root: validated2.value
|
|
837
|
+
},
|
|
838
|
+
version: 1,
|
|
839
|
+
fallbackText: treeToText(catalog, validated2.value),
|
|
840
|
+
componentVersions: Object.fromEntries(versions)
|
|
841
|
+
} : {
|
|
842
|
+
kind: "text",
|
|
843
|
+
text: treeToText(catalog, validated2.value)
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
const definition = catalog.get(component);
|
|
847
|
+
if (definition === void 0) throw new Error(`Unknown UI component "${component}"`);
|
|
848
|
+
const currentVersion = definition.version ?? 1;
|
|
849
|
+
if (version !== void 0 && version !== currentVersion) throw new Error(`Invalid UI component version for "${component}"`);
|
|
850
|
+
const validated = await catalog.validate(component, props);
|
|
851
|
+
if (!validated.ok) throw new Error(`Invalid UI props: ${formatIssues(validated.issues)}`);
|
|
852
|
+
return drawable.has(component) ? {
|
|
853
|
+
kind: "ui",
|
|
854
|
+
component,
|
|
855
|
+
props: validated.value,
|
|
856
|
+
version: currentVersion,
|
|
857
|
+
fallbackText: componentToText(catalog, component, validated.value)
|
|
858
|
+
} : {
|
|
859
|
+
kind: "text",
|
|
860
|
+
text: componentToText(catalog, component, validated.value)
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
__name(prepareUiEmission, "prepareUiEmission");
|
|
864
|
+
|
|
786
865
|
// src/genui/tools.ts
|
|
787
866
|
var GENUI_SHOW_TOOL = "ui__show";
|
|
788
867
|
function genuiTools(catalog, options = {}) {
|
|
@@ -846,30 +925,29 @@ function componentTool(catalog, component, options) {
|
|
|
846
925
|
if (definition === void 0) {
|
|
847
926
|
throw new Error(`component "${component.name}" is not available here`);
|
|
848
927
|
}
|
|
849
|
-
const validated = await validateProps(definition.props, input, resolved.validator);
|
|
928
|
+
const validated = await validateProps(dynamic ? definition.props : definition.outputProps ?? definition.props, input, resolved.validator);
|
|
850
929
|
if (!validated.ok) {
|
|
851
930
|
throw new Error(`invalid ${component.name} props: ${formatIssues(validated.issues)}`);
|
|
852
931
|
}
|
|
853
932
|
return push(ctx, component.name, validated.value, definition.version);
|
|
854
933
|
}
|
|
855
934
|
};
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
if (definition === void 0) {
|
|
861
|
-
return {
|
|
862
|
-
description: `Not available in this conversation \u2014 do not call this tool. (${component.name})`
|
|
863
|
-
};
|
|
864
|
-
}
|
|
935
|
+
handler.describe = async (scope) => {
|
|
936
|
+
const resolved = negotiateCatalog(await catalogFor(catalog, options, scopeOf(scope)), scope.uiCapabilities);
|
|
937
|
+
const definition = modelComponent(resolved, component.name);
|
|
938
|
+
if (definition === void 0) {
|
|
865
939
|
return {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
type: "object"
|
|
869
|
-
})
|
|
940
|
+
available: false,
|
|
941
|
+
description: `Not available in this conversation \u2014 do not call this tool. (${component.name})`
|
|
870
942
|
};
|
|
943
|
+
}
|
|
944
|
+
return {
|
|
945
|
+
description: describeFor(definition),
|
|
946
|
+
inputSchema: permissiveSchema(toJsonSchema(definition.props) ?? {
|
|
947
|
+
type: "object"
|
|
948
|
+
})
|
|
871
949
|
};
|
|
872
|
-
}
|
|
950
|
+
};
|
|
873
951
|
return {
|
|
874
952
|
spec: {
|
|
875
953
|
name: toolNameFor(component.name, options.namePrefix),
|
|
@@ -903,7 +981,7 @@ function treeTool(catalog, options) {
|
|
|
903
981
|
const handler = {
|
|
904
982
|
async execute(input, ctx) {
|
|
905
983
|
const resolved = await catalogFor(catalog, options, scopeOf(ctx));
|
|
906
|
-
const result = await validateTree(resolved, input, options.treeLimits);
|
|
984
|
+
const result = await validateTree(resolved, input, options.treeLimits, dynamic ? "input" : "output");
|
|
907
985
|
if (!result.ok) {
|
|
908
986
|
throw new Error(`invalid UI tree: ${formatIssues(result.issues)}`);
|
|
909
987
|
}
|
|
@@ -913,22 +991,21 @@ function treeTool(catalog, options) {
|
|
|
913
991
|
});
|
|
914
992
|
}
|
|
915
993
|
};
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
};
|
|
994
|
+
handler.describe = async (scope) => {
|
|
995
|
+
const resolved = negotiateCatalog(await catalogFor(catalog, options, scopeOf(scope)), scope.uiCapabilities);
|
|
996
|
+
return {
|
|
997
|
+
available: resolved.modelComponents().length > 0,
|
|
998
|
+
description: describeFor(resolved),
|
|
999
|
+
inputSchema: permissiveSchema(treeJsonSchema(resolved))
|
|
923
1000
|
};
|
|
924
|
-
}
|
|
1001
|
+
};
|
|
925
1002
|
return {
|
|
926
1003
|
spec: {
|
|
927
1004
|
name,
|
|
928
1005
|
kind: "read",
|
|
929
1006
|
description: describeFor(catalog),
|
|
930
1007
|
inputSchema: dynamic ? permissiveSchema(treeJsonSchema(catalog)) : asyncJsonStandardSchema(treeJsonSchema(catalog), async (value) => {
|
|
931
|
-
const result = await validateTree(catalog, value, options.treeLimits);
|
|
1008
|
+
const result = await validateTree(catalog, value, options.treeLimits, "input");
|
|
932
1009
|
return result.ok ? {
|
|
933
1010
|
value: result.value
|
|
934
1011
|
} : {
|
|
@@ -963,7 +1040,7 @@ function showToolJsonSchema(catalog) {
|
|
|
963
1040
|
};
|
|
964
1041
|
}
|
|
965
1042
|
__name(showToolJsonSchema, "showToolJsonSchema");
|
|
966
|
-
async function validateShow(catalog, input) {
|
|
1043
|
+
async function validateShow(catalog, input, phase = "input") {
|
|
967
1044
|
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
968
1045
|
return {
|
|
969
1046
|
ok: false,
|
|
@@ -1004,7 +1081,7 @@ async function validateShow(catalog, input) {
|
|
|
1004
1081
|
]
|
|
1005
1082
|
};
|
|
1006
1083
|
}
|
|
1007
|
-
const validated = await validateProps(definition.props, props ?? {}, catalog.validator);
|
|
1084
|
+
const validated = await validateProps(phase === "input" ? definition.props : definition.outputProps ?? definition.props, props ?? {}, catalog.validator);
|
|
1008
1085
|
if (!validated.ok) {
|
|
1009
1086
|
return {
|
|
1010
1087
|
ok: false,
|
|
@@ -1044,22 +1121,21 @@ function showTool(catalog, options) {
|
|
|
1044
1121
|
const handler = {
|
|
1045
1122
|
async execute(input, ctx) {
|
|
1046
1123
|
const resolved = await catalogFor(catalog, options, scopeOf(ctx));
|
|
1047
|
-
const result = await validateShow(resolved, input);
|
|
1124
|
+
const result = await validateShow(resolved, input, dynamic ? "input" : "output");
|
|
1048
1125
|
if (!result.ok) {
|
|
1049
1126
|
throw new Error(`invalid ${name} call: ${formatIssues(result.issues)}`);
|
|
1050
1127
|
}
|
|
1051
1128
|
return push(ctx, result.definition.name, result.props, result.definition.version);
|
|
1052
1129
|
}
|
|
1053
1130
|
};
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
};
|
|
1131
|
+
handler.describe = async (scope) => {
|
|
1132
|
+
const resolved = negotiateCatalog(await catalogFor(catalog, options, scopeOf(scope)), scope.uiCapabilities);
|
|
1133
|
+
return {
|
|
1134
|
+
available: resolved.modelComponents().length > 0,
|
|
1135
|
+
description: describeFor(resolved),
|
|
1136
|
+
inputSchema: permissiveSchema(showToolJsonSchema(resolved))
|
|
1061
1137
|
};
|
|
1062
|
-
}
|
|
1138
|
+
};
|
|
1063
1139
|
return {
|
|
1064
1140
|
spec: {
|
|
1065
1141
|
name,
|
|
@@ -1144,6 +1220,586 @@ function asyncJsonStandardSchema(schema, validate) {
|
|
|
1144
1220
|
};
|
|
1145
1221
|
}
|
|
1146
1222
|
__name(asyncJsonStandardSchema, "asyncJsonStandardSchema");
|
|
1223
|
+
|
|
1224
|
+
// src/genui/builtins.ts
|
|
1225
|
+
var str = /* @__PURE__ */ __name((description, extra = {}) => ({
|
|
1226
|
+
type: "string",
|
|
1227
|
+
...description !== void 0 ? {
|
|
1228
|
+
description
|
|
1229
|
+
} : {},
|
|
1230
|
+
...extra
|
|
1231
|
+
}), "str");
|
|
1232
|
+
var obj = /* @__PURE__ */ __name((properties, required = []) => ({
|
|
1233
|
+
type: "object",
|
|
1234
|
+
properties,
|
|
1235
|
+
required,
|
|
1236
|
+
additionalProperties: false
|
|
1237
|
+
}), "obj");
|
|
1238
|
+
var arr = /* @__PURE__ */ __name((items, extra = {}) => ({
|
|
1239
|
+
type: "array",
|
|
1240
|
+
items,
|
|
1241
|
+
...extra
|
|
1242
|
+
}), "arr");
|
|
1243
|
+
var cell = {
|
|
1244
|
+
type: [
|
|
1245
|
+
"string",
|
|
1246
|
+
"number",
|
|
1247
|
+
"boolean",
|
|
1248
|
+
"null"
|
|
1249
|
+
]
|
|
1250
|
+
};
|
|
1251
|
+
var row = {
|
|
1252
|
+
type: "object",
|
|
1253
|
+
additionalProperties: cell
|
|
1254
|
+
};
|
|
1255
|
+
var s = /* @__PURE__ */ __name((value) => value === null || value === void 0 ? "" : String(value), "s");
|
|
1256
|
+
var heading = /* @__PURE__ */ __name((props) => props.title ? `*${s(props.title)}*
|
|
1257
|
+
` : "", "heading");
|
|
1258
|
+
function textTable(columns, rows, max = 15) {
|
|
1259
|
+
const shown = rows.slice(0, max);
|
|
1260
|
+
const widths = columns.map((column) => Math.min(28, Math.max(column.label.length, ...shown.map((r) => s(r[column.key]).length))));
|
|
1261
|
+
const format = /* @__PURE__ */ __name((values) => values.map((value, index) => value.slice(0, widths[index]).padEnd(widths[index] ?? 0)).join(" "), "format");
|
|
1262
|
+
const lines = [
|
|
1263
|
+
format(columns.map((column) => column.label)),
|
|
1264
|
+
widths.map((width) => "-".repeat(width)).join(" "),
|
|
1265
|
+
...shown.map((r) => format(columns.map((column) => s(r[column.key]))))
|
|
1266
|
+
];
|
|
1267
|
+
if (rows.length > max) lines.push(`\u2026 ${rows.length - max} more rows`);
|
|
1268
|
+
return `\`\`\`
|
|
1269
|
+
${lines.join("\n")}
|
|
1270
|
+
\`\`\``;
|
|
1271
|
+
}
|
|
1272
|
+
__name(textTable, "textTable");
|
|
1273
|
+
function lineDiff(before, after) {
|
|
1274
|
+
const a = before.split("\n");
|
|
1275
|
+
const b = after.split("\n");
|
|
1276
|
+
if (a.length * b.length > 25e4) {
|
|
1277
|
+
return [
|
|
1278
|
+
...a.map((text) => ({
|
|
1279
|
+
op: "del",
|
|
1280
|
+
text
|
|
1281
|
+
})),
|
|
1282
|
+
...b.map((text) => ({
|
|
1283
|
+
op: "add",
|
|
1284
|
+
text
|
|
1285
|
+
}))
|
|
1286
|
+
];
|
|
1287
|
+
}
|
|
1288
|
+
const dp = Array.from({
|
|
1289
|
+
length: a.length + 1
|
|
1290
|
+
}, () => new Array(b.length + 1).fill(0));
|
|
1291
|
+
const at = /* @__PURE__ */ __name((i2, j2) => dp[i2]?.[j2] ?? 0, "at");
|
|
1292
|
+
for (let i2 = a.length - 1; i2 >= 0; i2--) {
|
|
1293
|
+
for (let j2 = b.length - 1; j2 >= 0; j2--) {
|
|
1294
|
+
dp[i2][j2] = a[i2] === b[j2] ? at(i2 + 1, j2 + 1) + 1 : Math.max(at(i2 + 1, j2), at(i2, j2 + 1));
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
const out = [];
|
|
1298
|
+
let i = 0;
|
|
1299
|
+
let j = 0;
|
|
1300
|
+
while (i < a.length && j < b.length) {
|
|
1301
|
+
if (a[i] === b[j]) {
|
|
1302
|
+
out.push({
|
|
1303
|
+
op: "same",
|
|
1304
|
+
text: a[i]
|
|
1305
|
+
});
|
|
1306
|
+
i++;
|
|
1307
|
+
j++;
|
|
1308
|
+
} else if (at(i + 1, j) >= at(i, j + 1)) {
|
|
1309
|
+
out.push({
|
|
1310
|
+
op: "del",
|
|
1311
|
+
text: a[i++]
|
|
1312
|
+
});
|
|
1313
|
+
} else {
|
|
1314
|
+
out.push({
|
|
1315
|
+
op: "add",
|
|
1316
|
+
text: b[j++]
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
while (i < a.length) out.push({
|
|
1321
|
+
op: "del",
|
|
1322
|
+
text: a[i++]
|
|
1323
|
+
});
|
|
1324
|
+
while (j < b.length) out.push({
|
|
1325
|
+
op: "add",
|
|
1326
|
+
text: b[j++]
|
|
1327
|
+
});
|
|
1328
|
+
return out;
|
|
1329
|
+
}
|
|
1330
|
+
__name(lineDiff, "lineDiff");
|
|
1331
|
+
function bar(value, max, width = 20) {
|
|
1332
|
+
const n = max > 0 ? Math.round(Math.abs(value) / max * width) : 0;
|
|
1333
|
+
return "\u2588".repeat(n) || "\u258F";
|
|
1334
|
+
}
|
|
1335
|
+
__name(bar, "bar");
|
|
1336
|
+
var DataTable = defineComponent({
|
|
1337
|
+
name: "DataTable",
|
|
1338
|
+
title: "Data table",
|
|
1339
|
+
description: "Tabular data (records with the same fields) as a sortable table. Prefer it over markdown tables for more than 3 rows.",
|
|
1340
|
+
props: obj({
|
|
1341
|
+
title: str("Short caption"),
|
|
1342
|
+
columns: arr(obj({
|
|
1343
|
+
key: str("Field name in each row"),
|
|
1344
|
+
label: str("Column header"),
|
|
1345
|
+
align: str(void 0, {
|
|
1346
|
+
enum: [
|
|
1347
|
+
"left",
|
|
1348
|
+
"right",
|
|
1349
|
+
"center"
|
|
1350
|
+
]
|
|
1351
|
+
}),
|
|
1352
|
+
format: str("How to format values", {
|
|
1353
|
+
enum: [
|
|
1354
|
+
"text",
|
|
1355
|
+
"number",
|
|
1356
|
+
"currency",
|
|
1357
|
+
"percent",
|
|
1358
|
+
"date",
|
|
1359
|
+
"link"
|
|
1360
|
+
]
|
|
1361
|
+
})
|
|
1362
|
+
}, [
|
|
1363
|
+
"key",
|
|
1364
|
+
"label"
|
|
1365
|
+
]), {
|
|
1366
|
+
minItems: 1,
|
|
1367
|
+
maxItems: 12
|
|
1368
|
+
}),
|
|
1369
|
+
rows: arr(row, {
|
|
1370
|
+
maxItems: 500
|
|
1371
|
+
})
|
|
1372
|
+
}, [
|
|
1373
|
+
"columns",
|
|
1374
|
+
"rows"
|
|
1375
|
+
]),
|
|
1376
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${textTable(props.columns ?? [], props.rows ?? [])}`, "fallbackText")
|
|
1377
|
+
});
|
|
1378
|
+
var Chart = defineComponent({
|
|
1379
|
+
name: "Chart",
|
|
1380
|
+
title: "Chart",
|
|
1381
|
+
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.",
|
|
1382
|
+
props: obj({
|
|
1383
|
+
type: str("Chart type", {
|
|
1384
|
+
enum: [
|
|
1385
|
+
"bar",
|
|
1386
|
+
"line"
|
|
1387
|
+
]
|
|
1388
|
+
}),
|
|
1389
|
+
title: str(),
|
|
1390
|
+
xKey: str("Field of each point used for the x axis"),
|
|
1391
|
+
series: arr(obj({
|
|
1392
|
+
key: str("Numeric field"),
|
|
1393
|
+
label: str()
|
|
1394
|
+
}, [
|
|
1395
|
+
"key"
|
|
1396
|
+
]), {
|
|
1397
|
+
minItems: 1,
|
|
1398
|
+
maxItems: 6
|
|
1399
|
+
}),
|
|
1400
|
+
data: arr(row, {
|
|
1401
|
+
minItems: 1,
|
|
1402
|
+
maxItems: 200
|
|
1403
|
+
}),
|
|
1404
|
+
unit: str("Unit shown after values, e.g. `KB` or `%`")
|
|
1405
|
+
}, [
|
|
1406
|
+
"type",
|
|
1407
|
+
"xKey",
|
|
1408
|
+
"series",
|
|
1409
|
+
"data"
|
|
1410
|
+
]),
|
|
1411
|
+
fallbackText: /* @__PURE__ */ __name((props) => {
|
|
1412
|
+
const series = props.series ?? [];
|
|
1413
|
+
const data = props.data ?? [];
|
|
1414
|
+
const first = series[0]?.key ?? "";
|
|
1415
|
+
const max = Math.max(0, ...data.map((point) => Math.abs(Number(point[first]) || 0)));
|
|
1416
|
+
const unit = props.unit ? ` ${s(props.unit)}` : "";
|
|
1417
|
+
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}`);
|
|
1418
|
+
return `${heading(props)}\`\`\`
|
|
1419
|
+
${lines.join("\n")}
|
|
1420
|
+
\`\`\``;
|
|
1421
|
+
}, "fallbackText")
|
|
1422
|
+
});
|
|
1423
|
+
var KpiCards = defineComponent({
|
|
1424
|
+
name: "KpiCards",
|
|
1425
|
+
title: "KPI cards",
|
|
1426
|
+
description: "A few key numbers (metrics, totals, counts) as cards.",
|
|
1427
|
+
props: obj({
|
|
1428
|
+
title: str(),
|
|
1429
|
+
items: arr(obj({
|
|
1430
|
+
label: str(),
|
|
1431
|
+
value: {
|
|
1432
|
+
type: [
|
|
1433
|
+
"string",
|
|
1434
|
+
"number"
|
|
1435
|
+
]
|
|
1436
|
+
},
|
|
1437
|
+
delta: str("Change, e.g. `+12%`"),
|
|
1438
|
+
trend: str(void 0, {
|
|
1439
|
+
enum: [
|
|
1440
|
+
"up",
|
|
1441
|
+
"down",
|
|
1442
|
+
"flat"
|
|
1443
|
+
]
|
|
1444
|
+
}),
|
|
1445
|
+
hint: str()
|
|
1446
|
+
}, [
|
|
1447
|
+
"label",
|
|
1448
|
+
"value"
|
|
1449
|
+
]), {
|
|
1450
|
+
minItems: 1,
|
|
1451
|
+
maxItems: 8
|
|
1452
|
+
})
|
|
1453
|
+
}, [
|
|
1454
|
+
"items"
|
|
1455
|
+
]),
|
|
1456
|
+
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")
|
|
1457
|
+
});
|
|
1458
|
+
var SourceCards = defineComponent({
|
|
1459
|
+
name: "SourceCards",
|
|
1460
|
+
title: "Sources",
|
|
1461
|
+
description: "The documents, pages or links an answer is based on, as cards.",
|
|
1462
|
+
props: obj({
|
|
1463
|
+
title: str(),
|
|
1464
|
+
items: arr(obj({
|
|
1465
|
+
title: str(),
|
|
1466
|
+
url: str(),
|
|
1467
|
+
snippet: str(),
|
|
1468
|
+
source: str("e.g. Wiki, GitHub")
|
|
1469
|
+
}, [
|
|
1470
|
+
"title"
|
|
1471
|
+
]), {
|
|
1472
|
+
minItems: 1,
|
|
1473
|
+
maxItems: 12
|
|
1474
|
+
})
|
|
1475
|
+
}, [
|
|
1476
|
+
"items"
|
|
1477
|
+
]),
|
|
1478
|
+
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")
|
|
1479
|
+
});
|
|
1480
|
+
var Checklist = defineComponent({
|
|
1481
|
+
name: "Checklist",
|
|
1482
|
+
title: "Checklist",
|
|
1483
|
+
description: "Steps or a to-do list with done/not-done state.",
|
|
1484
|
+
props: obj({
|
|
1485
|
+
title: str(),
|
|
1486
|
+
items: arr(obj({
|
|
1487
|
+
label: str(),
|
|
1488
|
+
done: {
|
|
1489
|
+
type: "boolean"
|
|
1490
|
+
},
|
|
1491
|
+
note: str()
|
|
1492
|
+
}, [
|
|
1493
|
+
"label"
|
|
1494
|
+
]), {
|
|
1495
|
+
minItems: 1,
|
|
1496
|
+
maxItems: 50
|
|
1497
|
+
})
|
|
1498
|
+
}, [
|
|
1499
|
+
"items"
|
|
1500
|
+
]),
|
|
1501
|
+
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")
|
|
1502
|
+
});
|
|
1503
|
+
var Timeline = defineComponent({
|
|
1504
|
+
name: "Timeline",
|
|
1505
|
+
title: "Timeline",
|
|
1506
|
+
description: "Events in chronological order (the history of a project, an incident, a deal).",
|
|
1507
|
+
props: obj({
|
|
1508
|
+
title: str(),
|
|
1509
|
+
events: arr(obj({
|
|
1510
|
+
date: str(),
|
|
1511
|
+
title: str(),
|
|
1512
|
+
description: str()
|
|
1513
|
+
}, [
|
|
1514
|
+
"title"
|
|
1515
|
+
]), {
|
|
1516
|
+
minItems: 1,
|
|
1517
|
+
maxItems: 50
|
|
1518
|
+
})
|
|
1519
|
+
}, [
|
|
1520
|
+
"events"
|
|
1521
|
+
]),
|
|
1522
|
+
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")
|
|
1523
|
+
});
|
|
1524
|
+
var CodeBlock = defineComponent({
|
|
1525
|
+
name: "CodeBlock",
|
|
1526
|
+
title: "Code",
|
|
1527
|
+
description: "A code snippet or file excerpt with syntax highlighting.",
|
|
1528
|
+
props: obj({
|
|
1529
|
+
title: str(),
|
|
1530
|
+
language: str(),
|
|
1531
|
+
code: str()
|
|
1532
|
+
}, [
|
|
1533
|
+
"code"
|
|
1534
|
+
]),
|
|
1535
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}\`\`\`
|
|
1536
|
+
${s(props.code)}
|
|
1537
|
+
\`\`\``, "fallbackText")
|
|
1538
|
+
});
|
|
1539
|
+
var Diff = defineComponent({
|
|
1540
|
+
name: "Diff",
|
|
1541
|
+
title: "Diff",
|
|
1542
|
+
description: "A before/after change to a text or code file, as a line diff.",
|
|
1543
|
+
props: obj({
|
|
1544
|
+
title: str(),
|
|
1545
|
+
language: str(),
|
|
1546
|
+
before: str(),
|
|
1547
|
+
after: str()
|
|
1548
|
+
}, [
|
|
1549
|
+
"before",
|
|
1550
|
+
"after"
|
|
1551
|
+
]),
|
|
1552
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}\`\`\`
|
|
1553
|
+
${lineDiff(s(props.before), s(props.after)).map((line) => `${line.op === "add" ? "+" : line.op === "del" ? "-" : " "} ${line.text}`).join("\n")}
|
|
1554
|
+
\`\`\``, "fallbackText")
|
|
1555
|
+
});
|
|
1556
|
+
var Callout = defineComponent({
|
|
1557
|
+
name: "Callout",
|
|
1558
|
+
title: "Callout",
|
|
1559
|
+
description: "A short note, warning or success message, emphasized.",
|
|
1560
|
+
props: obj({
|
|
1561
|
+
tone: str(void 0, {
|
|
1562
|
+
enum: [
|
|
1563
|
+
"info",
|
|
1564
|
+
"success",
|
|
1565
|
+
"warning",
|
|
1566
|
+
"danger"
|
|
1567
|
+
]
|
|
1568
|
+
}),
|
|
1569
|
+
title: str(),
|
|
1570
|
+
text: str()
|
|
1571
|
+
}, [
|
|
1572
|
+
"text"
|
|
1573
|
+
]),
|
|
1574
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${props.tone === "warning" || props.tone === "danger" ? ":warning: " : ":information_source: "}${heading(props)}${s(props.text)}`, "fallbackText")
|
|
1575
|
+
});
|
|
1576
|
+
var Stack = defineComponent({
|
|
1577
|
+
name: "Stack",
|
|
1578
|
+
title: "Stack",
|
|
1579
|
+
description: "Lays its children out vertically (or horizontally with direction=row).",
|
|
1580
|
+
props: obj({
|
|
1581
|
+
direction: str(void 0, {
|
|
1582
|
+
enum: [
|
|
1583
|
+
"column",
|
|
1584
|
+
"row"
|
|
1585
|
+
]
|
|
1586
|
+
}),
|
|
1587
|
+
gap: {
|
|
1588
|
+
type: "number"
|
|
1589
|
+
}
|
|
1590
|
+
}),
|
|
1591
|
+
children: true,
|
|
1592
|
+
fallbackText: /* @__PURE__ */ __name(() => "", "fallbackText")
|
|
1593
|
+
});
|
|
1594
|
+
var Card = defineComponent({
|
|
1595
|
+
name: "Card",
|
|
1596
|
+
title: "Card",
|
|
1597
|
+
description: "A box with an optional title around its children.",
|
|
1598
|
+
props: obj({
|
|
1599
|
+
title: str(),
|
|
1600
|
+
subtitle: str()
|
|
1601
|
+
}),
|
|
1602
|
+
children: true,
|
|
1603
|
+
fallbackText: /* @__PURE__ */ __name((props) => props.title ? `*${s(props.title)}*${props.subtitle ? ` \u2014 ${s(props.subtitle)}` : ""}` : "", "fallbackText")
|
|
1604
|
+
});
|
|
1605
|
+
var Heading = defineComponent({
|
|
1606
|
+
name: "Heading",
|
|
1607
|
+
title: "Heading",
|
|
1608
|
+
description: "A heading.",
|
|
1609
|
+
props: obj({
|
|
1610
|
+
text: str()
|
|
1611
|
+
}, [
|
|
1612
|
+
"text"
|
|
1613
|
+
]),
|
|
1614
|
+
fallbackText: /* @__PURE__ */ __name((props) => `*${s(props.text)}*`, "fallbackText")
|
|
1615
|
+
});
|
|
1616
|
+
var Text = defineComponent({
|
|
1617
|
+
name: "Text",
|
|
1618
|
+
title: "Text",
|
|
1619
|
+
description: "A paragraph of plain text (no markdown).",
|
|
1620
|
+
props: obj({
|
|
1621
|
+
text: str(),
|
|
1622
|
+
muted: {
|
|
1623
|
+
type: "boolean"
|
|
1624
|
+
}
|
|
1625
|
+
}, [
|
|
1626
|
+
"text"
|
|
1627
|
+
]),
|
|
1628
|
+
fallbackText: /* @__PURE__ */ __name((props) => s(props.text), "fallbackText")
|
|
1629
|
+
});
|
|
1630
|
+
var Badge = defineComponent({
|
|
1631
|
+
name: "Badge",
|
|
1632
|
+
title: "Badge",
|
|
1633
|
+
description: "A small label.",
|
|
1634
|
+
props: obj({
|
|
1635
|
+
text: str(),
|
|
1636
|
+
tone: str(void 0, {
|
|
1637
|
+
enum: [
|
|
1638
|
+
"neutral",
|
|
1639
|
+
"brand",
|
|
1640
|
+
"success",
|
|
1641
|
+
"warning",
|
|
1642
|
+
"danger"
|
|
1643
|
+
]
|
|
1644
|
+
})
|
|
1645
|
+
}, [
|
|
1646
|
+
"text"
|
|
1647
|
+
]),
|
|
1648
|
+
fallbackText: /* @__PURE__ */ __name((props) => `[${s(props.text)}]`, "fallbackText")
|
|
1649
|
+
});
|
|
1650
|
+
var Link = defineComponent({
|
|
1651
|
+
name: "Link",
|
|
1652
|
+
title: "Link",
|
|
1653
|
+
description: "A link to an http(s) URL.",
|
|
1654
|
+
props: obj({
|
|
1655
|
+
text: str(),
|
|
1656
|
+
url: str(void 0, {
|
|
1657
|
+
pattern: "^https?://"
|
|
1658
|
+
})
|
|
1659
|
+
}, [
|
|
1660
|
+
"text",
|
|
1661
|
+
"url"
|
|
1662
|
+
]),
|
|
1663
|
+
fallbackText: /* @__PURE__ */ __name((props) => `<${s(props.url)}|${s(props.text || props.url)}>`, "fallbackText")
|
|
1664
|
+
});
|
|
1665
|
+
var Image = defineComponent({
|
|
1666
|
+
name: "Image",
|
|
1667
|
+
title: "Image",
|
|
1668
|
+
description: "An image from an https URL.",
|
|
1669
|
+
props: obj({
|
|
1670
|
+
url: str(void 0, {
|
|
1671
|
+
pattern: "^https://"
|
|
1672
|
+
}),
|
|
1673
|
+
alt: str()
|
|
1674
|
+
}, [
|
|
1675
|
+
"url"
|
|
1676
|
+
]),
|
|
1677
|
+
fallbackText: /* @__PURE__ */ __name((props) => s(props.url), "fallbackText")
|
|
1678
|
+
});
|
|
1679
|
+
|
|
1680
|
+
// src/genui/registry.ts
|
|
1681
|
+
function snapshotComponentPresentation(value) {
|
|
1682
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1683
|
+
const check2 = /* @__PURE__ */ __name((entry) => {
|
|
1684
|
+
if (entry === null || typeof entry === "string" || typeof entry === "boolean") return;
|
|
1685
|
+
if (typeof entry === "number" && Number.isFinite(entry)) return;
|
|
1686
|
+
if (typeof entry !== "object" || entry === null) throw new TypeError("genui: presentation must contain only JSON values");
|
|
1687
|
+
if (seen.has(entry)) throw new TypeError("genui: presentation must contain acyclic JSON values");
|
|
1688
|
+
if (!Array.isArray(entry) && Object.getPrototypeOf(entry) !== Object.prototype && Object.getPrototypeOf(entry) !== null) throw new TypeError("genui: presentation must contain plain JSON objects");
|
|
1689
|
+
seen.add(entry);
|
|
1690
|
+
for (const item of Object.values(entry)) check2(item);
|
|
1691
|
+
seen.delete(entry);
|
|
1692
|
+
}, "check");
|
|
1693
|
+
check2(value);
|
|
1694
|
+
return JSON.parse(JSON.stringify(value));
|
|
1695
|
+
}
|
|
1696
|
+
__name(snapshotComponentPresentation, "snapshotComponentPresentation");
|
|
1697
|
+
function createComponent(definition, options = {}) {
|
|
1698
|
+
defineComponent(definition);
|
|
1699
|
+
const catalog = defineCatalog([
|
|
1700
|
+
definition
|
|
1701
|
+
], options);
|
|
1702
|
+
const factory = /* @__PURE__ */ __name(async (props) => {
|
|
1703
|
+
const result = await validateProps(definition.props, props, catalog.validator);
|
|
1704
|
+
if (!result.ok) throw new Error(`genui: invalid ${definition.name} props: ${formatIssues(result.issues)}`);
|
|
1705
|
+
const normalized = snapshotComponentPresentation(result.value);
|
|
1706
|
+
if (typeof normalized !== "object" || normalized === null || Array.isArray(normalized)) throw new TypeError("genui: component props must be a JSON object");
|
|
1707
|
+
const portable = await catalog.validate(definition.name, normalized);
|
|
1708
|
+
if (!portable.ok || canonicalJson(snapshotComponentPresentation(portable.value)) !== canonicalJson(normalized)) {
|
|
1709
|
+
throw new Error(`genui: ${definition.name} requires outputProps accepting stable normalized JSON props`);
|
|
1710
|
+
}
|
|
1711
|
+
return {
|
|
1712
|
+
component: definition.name,
|
|
1713
|
+
props: normalized,
|
|
1714
|
+
version: definition.version ?? 1,
|
|
1715
|
+
fallbackText: componentToText(catalog, definition.name, normalized)
|
|
1716
|
+
};
|
|
1717
|
+
}, "factory");
|
|
1718
|
+
return Object.assign(factory, {
|
|
1719
|
+
definition
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
__name(createComponent, "createComponent");
|
|
1723
|
+
function createComponentRegistry(options = {}) {
|
|
1724
|
+
let catalog = defineCatalog([], options);
|
|
1725
|
+
const channels = /* @__PURE__ */ new Map();
|
|
1726
|
+
const registry = {
|
|
1727
|
+
get catalog() {
|
|
1728
|
+
return catalog;
|
|
1729
|
+
},
|
|
1730
|
+
get manifest() {
|
|
1731
|
+
return catalog.components.map((definition) => {
|
|
1732
|
+
const props = catalog.jsonSchemaFor(definition.name);
|
|
1733
|
+
return {
|
|
1734
|
+
name: definition.name,
|
|
1735
|
+
title: definition.title,
|
|
1736
|
+
description: definition.description,
|
|
1737
|
+
version: definition.version ?? 1,
|
|
1738
|
+
...props === void 0 ? {} : {
|
|
1739
|
+
props: snapshotComponentPresentation(props)
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1742
|
+
});
|
|
1743
|
+
},
|
|
1744
|
+
register(definition, renderers) {
|
|
1745
|
+
if (catalog.has(definition.name)) throw new Error(`genui: component "${definition.name}" is already registered`);
|
|
1746
|
+
catalog = catalog.extend([
|
|
1747
|
+
definition
|
|
1748
|
+
]);
|
|
1749
|
+
channels.set(definition.name, {
|
|
1750
|
+
...renderers
|
|
1751
|
+
});
|
|
1752
|
+
return this;
|
|
1753
|
+
},
|
|
1754
|
+
async prepare(presentation) {
|
|
1755
|
+
const definition = catalog.get(presentation.component);
|
|
1756
|
+
if (definition === void 0) throw new Error(`genui: unknown component "${presentation.component}"`);
|
|
1757
|
+
if (presentation.version !== (definition.version ?? 1)) throw new Error(`genui: component "${presentation.component}" version mismatch`);
|
|
1758
|
+
const validated = await catalog.validate(presentation.component, presentation.props);
|
|
1759
|
+
if (!validated.ok) throw new Error(`genui: invalid ${presentation.component} props: ${formatIssues(validated.issues)}`);
|
|
1760
|
+
const props = snapshotComponentPresentation(validated.value);
|
|
1761
|
+
if (typeof props !== "object" || props === null || Array.isArray(props)) throw new TypeError("genui: component props must be a JSON object");
|
|
1762
|
+
return {
|
|
1763
|
+
component: definition.name,
|
|
1764
|
+
props,
|
|
1765
|
+
version: definition.version ?? 1,
|
|
1766
|
+
fallbackText: componentToText(catalog, definition.name, props)
|
|
1767
|
+
};
|
|
1768
|
+
},
|
|
1769
|
+
async render(presentation, channel, context) {
|
|
1770
|
+
const prepared = await this.prepare(presentation);
|
|
1771
|
+
const mapping = channels.get(prepared.component);
|
|
1772
|
+
const renderer = mapping === void 0 ? void 0 : Object.hasOwn(mapping, channel) ? mapping[channel] : Object.hasOwn(mapping, "text") ? mapping.text : void 0;
|
|
1773
|
+
return renderer === void 0 ? prepared.fallbackText : renderer(prepared.props, context);
|
|
1774
|
+
}
|
|
1775
|
+
};
|
|
1776
|
+
return registry;
|
|
1777
|
+
}
|
|
1778
|
+
__name(createComponentRegistry, "createComponentRegistry");
|
|
1779
|
+
var table = createComponent(DataTable);
|
|
1780
|
+
var chart = createComponent(Chart);
|
|
1781
|
+
function validatePresentationBatch(presentations) {
|
|
1782
|
+
const batch = Array.isArray(presentations) ? presentations : [
|
|
1783
|
+
presentations
|
|
1784
|
+
];
|
|
1785
|
+
return batch.map((item) => {
|
|
1786
|
+
const presentation = snapshotComponentPresentation(item);
|
|
1787
|
+
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)) {
|
|
1788
|
+
throw new TypeError("genui: invalid component presentation");
|
|
1789
|
+
}
|
|
1790
|
+
return presentation;
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
__name(validatePresentationBatch, "validatePresentationBatch");
|
|
1794
|
+
function canonicalJson(value) {
|
|
1795
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
1796
|
+
if (typeof value === "object" && value !== null) {
|
|
1797
|
+
const record2 = value;
|
|
1798
|
+
return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record2[key])}`).join(",")}}`;
|
|
1799
|
+
}
|
|
1800
|
+
return JSON.stringify(value);
|
|
1801
|
+
}
|
|
1802
|
+
__name(canonicalJson, "canonicalJson");
|
|
1147
1803
|
export {
|
|
1148
1804
|
COMPONENT_NAME,
|
|
1149
1805
|
GENUI_SHOW_TOOL,
|
|
@@ -1151,7 +1807,10 @@ export {
|
|
|
1151
1807
|
ajvValidator,
|
|
1152
1808
|
builtinJsonSchemaValidator,
|
|
1153
1809
|
catalogToModelText,
|
|
1810
|
+
chart,
|
|
1154
1811
|
componentToText,
|
|
1812
|
+
createComponent,
|
|
1813
|
+
createComponentRegistry,
|
|
1155
1814
|
defineCatalog,
|
|
1156
1815
|
defineComponent,
|
|
1157
1816
|
fillTemplate,
|
|
@@ -1160,16 +1819,22 @@ export {
|
|
|
1160
1819
|
getPath,
|
|
1161
1820
|
isStandardSchema,
|
|
1162
1821
|
jsonStandardSchema,
|
|
1822
|
+
negotiateCatalog,
|
|
1823
|
+
prepareUiEmission,
|
|
1163
1824
|
showToolJsonSchema,
|
|
1825
|
+
snapshotComponentPresentation,
|
|
1164
1826
|
summarizeSchema,
|
|
1827
|
+
table,
|
|
1165
1828
|
toJsonSchema,
|
|
1166
1829
|
toSnakeCase,
|
|
1167
1830
|
toolNameFor,
|
|
1168
1831
|
treeJsonSchema,
|
|
1169
1832
|
treeToFlatSpec,
|
|
1170
1833
|
treeToText,
|
|
1834
|
+
validatePresentationBatch,
|
|
1171
1835
|
validateProps,
|
|
1172
1836
|
validatePropsSync,
|
|
1173
|
-
validateTree
|
|
1837
|
+
validateTree,
|
|
1838
|
+
validateUiCapabilities
|
|
1174
1839
|
};
|
|
1175
1840
|
//# sourceMappingURL=index.js.map
|