@dudousxd/nestjs-agent-core 0.25.0 → 0.27.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.
@@ -0,0 +1,1225 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/genui/index.ts
22
+ var genui_exports = {};
23
+ __export(genui_exports, {
24
+ COMPONENT_NAME: () => COMPONENT_NAME,
25
+ GENUI_SHOW_TOOL: () => GENUI_SHOW_TOOL,
26
+ GENUI_TREE_COMPONENT: () => GENUI_TREE_COMPONENT,
27
+ ajvValidator: () => ajvValidator,
28
+ builtinJsonSchemaValidator: () => builtinJsonSchemaValidator,
29
+ catalogToModelText: () => catalogToModelText,
30
+ componentToText: () => componentToText,
31
+ defineCatalog: () => defineCatalog,
32
+ defineComponent: () => defineComponent,
33
+ fillTemplate: () => fillTemplate,
34
+ formatIssues: () => formatIssues,
35
+ genuiTools: () => genuiTools,
36
+ getPath: () => getPath,
37
+ isStandardSchema: () => isStandardSchema,
38
+ jsonStandardSchema: () => jsonStandardSchema,
39
+ showToolJsonSchema: () => showToolJsonSchema,
40
+ summarizeSchema: () => summarizeSchema,
41
+ toJsonSchema: () => toJsonSchema,
42
+ toSnakeCase: () => toSnakeCase,
43
+ toolNameFor: () => toolNameFor,
44
+ treeJsonSchema: () => treeJsonSchema,
45
+ treeToFlatSpec: () => treeToFlatSpec,
46
+ treeToText: () => treeToText,
47
+ validateProps: () => validateProps,
48
+ validatePropsSync: () => validatePropsSync,
49
+ validateTree: () => validateTree
50
+ });
51
+ module.exports = __toCommonJS(genui_exports);
52
+
53
+ // src/genui/schema.ts
54
+ function isStandardSchema(schema) {
55
+ return typeof schema === "object" && schema !== null && "~standard" in schema && typeof schema["~standard"]?.validate === "function";
56
+ }
57
+ __name(isStandardSchema, "isStandardSchema");
58
+ function toJsonSchema(schema) {
59
+ if (!isStandardSchema(schema)) {
60
+ return schema;
61
+ }
62
+ const standard = schema["~standard"];
63
+ const converter = standard.jsonSchema;
64
+ if (converter === void 0 || typeof converter.input !== "function") {
65
+ return void 0;
66
+ }
67
+ try {
68
+ return converter.input({
69
+ target: "draft-07"
70
+ });
71
+ } catch {
72
+ return void 0;
73
+ }
74
+ }
75
+ __name(toJsonSchema, "toJsonSchema");
76
+ async function validateProps(schema, value, validator) {
77
+ if (isStandardSchema(schema)) {
78
+ const result = await schema["~standard"].validate(value);
79
+ if (result.issues !== void 0) {
80
+ return {
81
+ ok: false,
82
+ issues: toGenuiIssues(result.issues)
83
+ };
84
+ }
85
+ return {
86
+ ok: true,
87
+ value: result.value
88
+ };
89
+ }
90
+ const issues = validator.validate(schema, value);
91
+ return issues.length > 0 ? {
92
+ ok: false,
93
+ issues
94
+ } : {
95
+ ok: true,
96
+ value
97
+ };
98
+ }
99
+ __name(validateProps, "validateProps");
100
+ function validatePropsSync(schema, value, validator) {
101
+ if (!isStandardSchema(schema)) {
102
+ const issues = validator.validate(schema, value);
103
+ return issues.length > 0 ? {
104
+ ok: false,
105
+ issues
106
+ } : {
107
+ ok: true,
108
+ value
109
+ };
110
+ }
111
+ const result = schema["~standard"].validate(value);
112
+ if (result instanceof Promise) {
113
+ result.catch(() => void 0);
114
+ return void 0;
115
+ }
116
+ return result.issues !== void 0 ? {
117
+ ok: false,
118
+ issues: toGenuiIssues(result.issues)
119
+ } : {
120
+ ok: true,
121
+ value: result.value
122
+ };
123
+ }
124
+ __name(validatePropsSync, "validatePropsSync");
125
+ function toGenuiIssues(issues) {
126
+ return issues.map((issue) => ({
127
+ path: (issue.path ?? []).map((segment) => typeof segment === "object" && segment !== null && "key" in segment ? segment.key : segment),
128
+ message: issue.message
129
+ }));
130
+ }
131
+ __name(toGenuiIssues, "toGenuiIssues");
132
+ function formatIssues(issues) {
133
+ return issues.map((issue) => `${issue.path.length > 0 ? formatPath(issue.path) : "(root)"}: ${issue.message}`).join("; ");
134
+ }
135
+ __name(formatIssues, "formatIssues");
136
+ function formatPath(path) {
137
+ return path.map((segment, index) => typeof segment === "number" ? `[${segment}]` : index === 0 ? segment : `.${segment}`).join("");
138
+ }
139
+ __name(formatPath, "formatPath");
140
+ function ajvValidator(ajv) {
141
+ const compiled = /* @__PURE__ */ new WeakMap();
142
+ return {
143
+ validate(schema, value) {
144
+ let fn = compiled.get(schema);
145
+ if (fn === void 0) {
146
+ fn = ajv.compile(schema);
147
+ compiled.set(schema, fn);
148
+ }
149
+ if (fn(value) === true) {
150
+ return [];
151
+ }
152
+ return (fn.errors ?? []).map((error) => ({
153
+ path: (error.instancePath ?? "").split("/").filter((segment) => segment.length > 0).map((segment) => {
154
+ const decoded = segment.replace(/~1/g, "/").replace(/~0/g, "~");
155
+ return /^\d+$/.test(decoded) ? Number(decoded) : decoded;
156
+ }),
157
+ message: error.message ?? "is invalid"
158
+ }));
159
+ }
160
+ };
161
+ }
162
+ __name(ajvValidator, "ajvValidator");
163
+ var builtinJsonSchemaValidator = {
164
+ validate(schema, value) {
165
+ const issues = [];
166
+ check(schema, value, [], schema, issues, 0);
167
+ return issues;
168
+ }
169
+ };
170
+ var MAX_DEPTH = 64;
171
+ function typeOf(value) {
172
+ if (value === null) return "null";
173
+ if (Array.isArray(value)) return "array";
174
+ return typeof value;
175
+ }
176
+ __name(typeOf, "typeOf");
177
+ function matchesType(type, value) {
178
+ switch (type) {
179
+ case "integer":
180
+ return typeof value === "number" && Number.isInteger(value);
181
+ case "number":
182
+ return typeof value === "number" && Number.isFinite(value);
183
+ case "object":
184
+ return typeof value === "object" && value !== null && !Array.isArray(value);
185
+ default:
186
+ return typeOf(value) === type;
187
+ }
188
+ }
189
+ __name(matchesType, "matchesType");
190
+ function resolveRef(root, ref) {
191
+ if (ref === "#") return root;
192
+ if (!ref.startsWith("#/")) return void 0;
193
+ let current = root;
194
+ for (const raw of ref.slice(2).split("/")) {
195
+ const key = raw.replace(/~1/g, "/").replace(/~0/g, "~");
196
+ if (typeof current !== "object" || current === null) return void 0;
197
+ current = current[key];
198
+ }
199
+ return typeof current === "object" && current !== null ? current : void 0;
200
+ }
201
+ __name(resolveRef, "resolveRef");
202
+ function deepEqual(a, b) {
203
+ if (a === b) return true;
204
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
205
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
206
+ const keysA = Object.keys(a);
207
+ const keysB = Object.keys(b);
208
+ if (keysA.length !== keysB.length) return false;
209
+ return keysA.every((key) => deepEqual(a[key], b[key]));
210
+ }
211
+ __name(deepEqual, "deepEqual");
212
+ function check(schema, value, path, root, issues, depth) {
213
+ if (schema === true || schema === void 0) return;
214
+ if (schema === false) {
215
+ issues.push({
216
+ path,
217
+ message: "is not allowed"
218
+ });
219
+ return;
220
+ }
221
+ if (typeof schema !== "object" || schema === null) return;
222
+ if (depth > MAX_DEPTH) {
223
+ issues.push({
224
+ path,
225
+ message: "is nested too deeply"
226
+ });
227
+ return;
228
+ }
229
+ const s = schema;
230
+ if (typeof s.$ref === "string") {
231
+ const target = resolveRef(root, s.$ref);
232
+ if (target === void 0) {
233
+ issues.push({
234
+ path,
235
+ message: `references unknown schema ${s.$ref}`
236
+ });
237
+ return;
238
+ }
239
+ check(target, value, path, root, issues, depth + 1);
240
+ }
241
+ if (s.type !== void 0) {
242
+ const types = Array.isArray(s.type) ? s.type : [
243
+ s.type
244
+ ];
245
+ if (!types.some((type) => matchesType(type, value))) {
246
+ issues.push({
247
+ path,
248
+ message: `must be ${types.join(" or ")}`
249
+ });
250
+ return;
251
+ }
252
+ }
253
+ if (Array.isArray(s.enum) && !s.enum.some((option) => deepEqual(option, value))) {
254
+ issues.push({
255
+ path,
256
+ message: `must be one of ${s.enum.map((option) => JSON.stringify(option)).join(", ")}`
257
+ });
258
+ }
259
+ if ("const" in s && !deepEqual(s.const, value)) {
260
+ issues.push({
261
+ path,
262
+ message: `must be ${JSON.stringify(s.const)}`
263
+ });
264
+ }
265
+ if (typeof value === "string") {
266
+ if (typeof s.minLength === "number" && value.length < s.minLength) {
267
+ issues.push({
268
+ path,
269
+ message: `must be at least ${s.minLength} characters`
270
+ });
271
+ }
272
+ if (typeof s.maxLength === "number" && value.length > s.maxLength) {
273
+ issues.push({
274
+ path,
275
+ message: `must be at most ${s.maxLength} characters`
276
+ });
277
+ }
278
+ if (typeof s.pattern === "string") {
279
+ let pattern;
280
+ try {
281
+ pattern = new RegExp(s.pattern, "u");
282
+ } catch {
283
+ pattern = void 0;
284
+ }
285
+ if (pattern !== void 0 && !pattern.test(value)) {
286
+ issues.push({
287
+ path,
288
+ message: `must match ${s.pattern}`
289
+ });
290
+ }
291
+ }
292
+ }
293
+ if (typeof value === "number") {
294
+ if (typeof s.minimum === "number" && value < s.minimum) {
295
+ issues.push({
296
+ path,
297
+ message: `must be >= ${s.minimum}`
298
+ });
299
+ }
300
+ if (typeof s.maximum === "number" && value > s.maximum) {
301
+ issues.push({
302
+ path,
303
+ message: `must be <= ${s.maximum}`
304
+ });
305
+ }
306
+ }
307
+ if (Array.isArray(value)) {
308
+ if (typeof s.minItems === "number" && value.length < s.minItems) {
309
+ issues.push({
310
+ path,
311
+ message: `must have at least ${s.minItems} items`
312
+ });
313
+ }
314
+ if (typeof s.maxItems === "number" && value.length > s.maxItems) {
315
+ issues.push({
316
+ path,
317
+ message: `must have at most ${s.maxItems} items`
318
+ });
319
+ }
320
+ if (s.items !== void 0 && !Array.isArray(s.items)) {
321
+ value.forEach((item, index) => {
322
+ check(s.items, item, [
323
+ ...path,
324
+ index
325
+ ], root, issues, depth + 1);
326
+ });
327
+ }
328
+ }
329
+ if (matchesType("object", value)) {
330
+ const record = value;
331
+ const properties = typeof s.properties === "object" && s.properties !== null ? s.properties : {};
332
+ if (Array.isArray(s.required)) {
333
+ for (const key of s.required) {
334
+ if (record[key] === void 0) {
335
+ issues.push({
336
+ path: [
337
+ ...path,
338
+ key
339
+ ],
340
+ message: "is required"
341
+ });
342
+ }
343
+ }
344
+ }
345
+ for (const [key, entry] of Object.entries(record)) {
346
+ if (key in properties) {
347
+ if (entry !== void 0) {
348
+ check(properties[key], entry, [
349
+ ...path,
350
+ key
351
+ ], root, issues, depth + 1);
352
+ }
353
+ } else if (s.additionalProperties === false) {
354
+ issues.push({
355
+ path: [
356
+ ...path,
357
+ key
358
+ ],
359
+ message: "is not a known property"
360
+ });
361
+ } else if (typeof s.additionalProperties === "object" && s.additionalProperties !== null) {
362
+ check(s.additionalProperties, entry, [
363
+ ...path,
364
+ key
365
+ ], root, issues, depth + 1);
366
+ }
367
+ }
368
+ }
369
+ if (Array.isArray(s.allOf)) {
370
+ for (const sub of s.allOf) check(sub, value, path, root, issues, depth + 1);
371
+ }
372
+ if (Array.isArray(s.anyOf) || Array.isArray(s.oneOf)) {
373
+ const options = Array.isArray(s.anyOf) ? s.anyOf : s.oneOf;
374
+ const passing = options.filter((sub) => {
375
+ const nested = [];
376
+ check(sub, value, path, root, nested, depth + 1);
377
+ return nested.length === 0;
378
+ }).length;
379
+ if (Array.isArray(s.anyOf) ? passing === 0 : passing !== 1) {
380
+ issues.push({
381
+ path,
382
+ message: Array.isArray(s.anyOf) ? "does not match any allowed shape" : "must match exactly one allowed shape"
383
+ });
384
+ }
385
+ }
386
+ if (s.not !== void 0) {
387
+ const nested = [];
388
+ check(s.not, value, path, root, nested, depth + 1);
389
+ if (nested.length === 0) {
390
+ issues.push({
391
+ path,
392
+ message: "matches a shape that is not allowed"
393
+ });
394
+ }
395
+ }
396
+ }
397
+ __name(check, "check");
398
+
399
+ // src/genui/catalog.ts
400
+ var COMPONENT_NAME = /^[A-Za-z][A-Za-z0-9]{0,63}$/;
401
+ function defineComponent(definition) {
402
+ if (!COMPONENT_NAME.test(definition.name)) {
403
+ throw new Error(`genui: component name "${definition.name}" must be letters and digits, starting with a letter (e.g. DataTable)`);
404
+ }
405
+ return definition;
406
+ }
407
+ __name(defineComponent, "defineComponent");
408
+ function defineCatalog(components, options = {}) {
409
+ const byName = /* @__PURE__ */ new Map();
410
+ for (const component of components) {
411
+ defineComponent(component);
412
+ if (byName.has(component.name)) {
413
+ throw new Error(`genui: component "${component.name}" is defined twice in one catalog`);
414
+ }
415
+ byName.set(component.name, component);
416
+ }
417
+ return buildCatalog(byName, options.jsonSchemaValidator ?? builtinJsonSchemaValidator);
418
+ }
419
+ __name(defineCatalog, "defineCatalog");
420
+ function buildCatalog(byName, validator) {
421
+ const list = Object.freeze([
422
+ ...byName.values()
423
+ ]);
424
+ return {
425
+ components: list,
426
+ validator,
427
+ get: /* @__PURE__ */ __name((name) => byName.get(name), "get"),
428
+ has: /* @__PURE__ */ __name((name) => byName.has(name), "has"),
429
+ modelComponents: /* @__PURE__ */ __name(() => list.filter((component) => component.internal !== true), "modelComponents"),
430
+ async validate(component, props) {
431
+ const definition = byName.get(component);
432
+ if (definition === void 0) {
433
+ return {
434
+ ok: false,
435
+ issues: [
436
+ {
437
+ path: [],
438
+ message: `unknown component "${component}"`
439
+ }
440
+ ]
441
+ };
442
+ }
443
+ const result = await validateProps(definition.props, props, validator);
444
+ return result;
445
+ },
446
+ validateSync(component, props) {
447
+ const definition = byName.get(component);
448
+ if (definition === void 0) {
449
+ return {
450
+ ok: false,
451
+ issues: [
452
+ {
453
+ path: [],
454
+ message: `unknown component "${component}"`
455
+ }
456
+ ]
457
+ };
458
+ }
459
+ return validatePropsSync(definition.props, props, validator);
460
+ },
461
+ jsonSchemaFor(component) {
462
+ const definition = byName.get(component);
463
+ return definition === void 0 ? void 0 : toJsonSchema(definition.props);
464
+ },
465
+ extend(more) {
466
+ const next = new Map(byName);
467
+ for (const component of more) {
468
+ defineComponent(component);
469
+ next.set(component.name, component);
470
+ }
471
+ return buildCatalog(next, validator);
472
+ }
473
+ };
474
+ }
475
+ __name(buildCatalog, "buildCatalog");
476
+ function toSnakeCase(name) {
477
+ return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toLowerCase();
478
+ }
479
+ __name(toSnakeCase, "toSnakeCase");
480
+ function toolNameFor(component, prefix = "ui__show_") {
481
+ return `${prefix}${toSnakeCase(component)}`;
482
+ }
483
+ __name(toolNameFor, "toolNameFor");
484
+
485
+ // src/genui/tree.ts
486
+ var GENUI_TREE_COMPONENT = "genui:tree";
487
+ async function validateTree(catalog, tree, limits = {}) {
488
+ const maxDepth = limits.maxDepth ?? 12;
489
+ const maxNodes = limits.maxNodes ?? 200;
490
+ const issues = [];
491
+ let nodes = 0;
492
+ const visit = /* @__PURE__ */ __name(async (node, path, depth) => {
493
+ nodes += 1;
494
+ if (nodes > maxNodes) {
495
+ if (nodes === maxNodes + 1) {
496
+ issues.push({
497
+ path,
498
+ message: `the tree has more than ${maxNodes} elements`
499
+ });
500
+ }
501
+ return void 0;
502
+ }
503
+ if (depth > maxDepth) {
504
+ issues.push({
505
+ path,
506
+ message: `the tree is nested deeper than ${maxDepth} levels`
507
+ });
508
+ return void 0;
509
+ }
510
+ if (typeof node !== "object" || node === null || Array.isArray(node)) {
511
+ issues.push({
512
+ path,
513
+ message: "must be an element object { type, props, children? }"
514
+ });
515
+ return void 0;
516
+ }
517
+ const element = node;
518
+ if (typeof element.type !== "string") {
519
+ issues.push({
520
+ path: [
521
+ ...path,
522
+ "type"
523
+ ],
524
+ message: "must be a component name"
525
+ });
526
+ return void 0;
527
+ }
528
+ const definition = catalog.get(element.type);
529
+ if (definition === void 0 || definition.internal === true) {
530
+ issues.push({
531
+ path: [
532
+ ...path,
533
+ "type"
534
+ ],
535
+ message: `unknown component "${element.type}" (allowed: ${catalog.modelComponents().map((component) => component.name).join(", ")})`
536
+ });
537
+ return void 0;
538
+ }
539
+ const validated = await catalog.validate(element.type, element.props ?? {});
540
+ let props = {};
541
+ if (!validated.ok) {
542
+ for (const issue of validated.issues) {
543
+ issues.push({
544
+ path: [
545
+ ...path,
546
+ "props",
547
+ ...issue.path
548
+ ],
549
+ message: issue.message
550
+ });
551
+ }
552
+ } else {
553
+ props = validated.value;
554
+ }
555
+ const rawChildren = parseChildrenIfStringified(element.children);
556
+ if (rawChildren === void 0 || rawChildren === null) {
557
+ return {
558
+ type: element.type,
559
+ props
560
+ };
561
+ }
562
+ if (!Array.isArray(rawChildren)) {
563
+ issues.push({
564
+ path: [
565
+ ...path,
566
+ "children"
567
+ ],
568
+ message: "must be an array of elements (a literal array, not a string)"
569
+ });
570
+ return void 0;
571
+ }
572
+ if (rawChildren.length > 0 && definition.children !== true) {
573
+ issues.push({
574
+ path: [
575
+ ...path,
576
+ "children"
577
+ ],
578
+ message: `${element.type} does not take children`
579
+ });
580
+ return void 0;
581
+ }
582
+ const children = [];
583
+ for (const [index, child] of rawChildren.entries()) {
584
+ const next = await visit(child, [
585
+ ...path,
586
+ "children",
587
+ index
588
+ ], depth + 1);
589
+ if (next !== void 0) {
590
+ children.push(next);
591
+ }
592
+ }
593
+ return children.length > 0 ? {
594
+ type: element.type,
595
+ props,
596
+ children
597
+ } : {
598
+ type: element.type,
599
+ props
600
+ };
601
+ }, "visit");
602
+ const root = await visit(tree, [], 1);
603
+ return issues.length > 0 || root === void 0 ? {
604
+ ok: false,
605
+ issues: issues.length > 0 ? issues : [
606
+ {
607
+ path: [],
608
+ message: "is invalid"
609
+ }
610
+ ]
611
+ } : {
612
+ ok: true,
613
+ value: root
614
+ };
615
+ }
616
+ __name(validateTree, "validateTree");
617
+ function treeJsonSchema(catalog) {
618
+ return {
619
+ type: "object",
620
+ properties: {
621
+ type: {
622
+ type: "string",
623
+ enum: catalog.modelComponents().map((component) => component.name),
624
+ description: "Component name from the catalog"
625
+ },
626
+ props: {
627
+ type: "object",
628
+ description: "The component's props, as the catalog describes them"
629
+ },
630
+ children: {
631
+ type: "array",
632
+ items: {
633
+ $ref: "#"
634
+ },
635
+ description: "Nested elements, only for components that take children. A literal JSON array, never a JSON-stringified one."
636
+ }
637
+ },
638
+ required: [
639
+ "type",
640
+ "props"
641
+ ]
642
+ };
643
+ }
644
+ __name(treeJsonSchema, "treeJsonSchema");
645
+ function treeToFlatSpec(root) {
646
+ const elements = {};
647
+ let next = 0;
648
+ const visit = /* @__PURE__ */ __name((node) => {
649
+ const id = `el-${next++}`;
650
+ const entry = {
651
+ type: node.type,
652
+ props: node.props,
653
+ children: []
654
+ };
655
+ elements[id] = entry;
656
+ for (const child of node.children ?? []) {
657
+ entry.children.push(visit(child));
658
+ }
659
+ return id;
660
+ }, "visit");
661
+ return {
662
+ root: visit(root),
663
+ elements
664
+ };
665
+ }
666
+ __name(treeToFlatSpec, "treeToFlatSpec");
667
+ function parseChildrenIfStringified(value) {
668
+ if (typeof value !== "string") return value;
669
+ const trimmed = value.trim();
670
+ if (!trimmed.startsWith("[")) return value;
671
+ return leadingJsonArray(trimmed) ?? value;
672
+ }
673
+ __name(parseChildrenIfStringified, "parseChildrenIfStringified");
674
+ function leadingJsonArray(text) {
675
+ let depth = 0;
676
+ let inString = false;
677
+ let escaped = false;
678
+ for (let index = 0; index < text.length; index += 1) {
679
+ const char = text[index];
680
+ if (inString) {
681
+ if (escaped) escaped = false;
682
+ else if (char === "\\") escaped = true;
683
+ else if (char === '"') inString = false;
684
+ continue;
685
+ }
686
+ if (char === '"') inString = true;
687
+ else if (char === "[" || char === "{") depth += 1;
688
+ else if (char === "]" || char === "}") {
689
+ depth -= 1;
690
+ if (depth === 0) {
691
+ try {
692
+ const parsed = JSON.parse(text.slice(0, index + 1));
693
+ return Array.isArray(parsed) ? parsed : void 0;
694
+ } catch {
695
+ return void 0;
696
+ }
697
+ }
698
+ }
699
+ }
700
+ return void 0;
701
+ }
702
+ __name(leadingJsonArray, "leadingJsonArray");
703
+
704
+ // src/genui/text.ts
705
+ function componentToText(catalog, component, props) {
706
+ if (component === GENUI_TREE_COMPONENT) {
707
+ const root = props.root;
708
+ return root === void 0 ? "" : treeToText(catalog, root);
709
+ }
710
+ const fallback = catalog.get(component)?.fallbackText;
711
+ if (fallback !== void 0) {
712
+ try {
713
+ return fallback(props);
714
+ } catch {
715
+ }
716
+ }
717
+ return jsonBlock(props);
718
+ }
719
+ __name(componentToText, "componentToText");
720
+ function treeToText(catalog, root) {
721
+ const out = [];
722
+ const visit = /* @__PURE__ */ __name((node, depth) => {
723
+ if (depth > 32) return;
724
+ const definition = catalog.get(node.type);
725
+ if (definition?.fallbackText !== void 0) {
726
+ try {
727
+ out.push(definition.fallbackText(node.props));
728
+ } catch {
729
+ out.push(jsonBlock(node.props));
730
+ }
731
+ } else if (definition?.children !== true) {
732
+ out.push(jsonBlock(node.props));
733
+ }
734
+ for (const child of node.children ?? []) visit(child, depth + 1);
735
+ }, "visit");
736
+ visit(root, 0);
737
+ return out.filter((line) => line.trim().length > 0).join("\n");
738
+ }
739
+ __name(treeToText, "treeToText");
740
+ function jsonBlock(props) {
741
+ const title = typeof props.title === "string" && props.title.length > 0 ? `*${props.title}*
742
+ ` : "";
743
+ return `${title}\`\`\`
744
+ ${JSON.stringify(props, null, 2).slice(0, 2500)}
745
+ \`\`\``;
746
+ }
747
+ __name(jsonBlock, "jsonBlock");
748
+ function catalogToModelText(catalog, options = {}) {
749
+ const mode = options.mode ?? "tree";
750
+ const lines = [];
751
+ if (mode === "tree") {
752
+ lines.push('Compose the UI as ONE tree of elements: { "type": <component>, "props": { \u2026 }, "children"?: [ \u2026 ] }.', 'Only components marked "takes children" accept children; `children` is a literal JSON array, never a string.', "Components:");
753
+ } else if (mode === "show") {
754
+ lines.push('Pass { "component": <name>, "props": { \u2026 } } with one of these components:');
755
+ } else {
756
+ lines.push("Components you can show (one tool each):");
757
+ }
758
+ for (const component of catalog.modelComponents()) {
759
+ const schema = catalog.jsonSchemaFor(component.name);
760
+ const head = mode === "per-component" ? `- ${component.name} (tool \`${toolNameFor(component.name, options.namePrefix)}\`)` : `- ${component.name}`;
761
+ lines.push(`${head}: ${component.description}`);
762
+ if (schema !== void 0) {
763
+ lines.push(` props: ${summarizeSchema(schema, schema, 0)}`);
764
+ }
765
+ if (mode === "tree" && component.children === true) {
766
+ lines.push(" takes children");
767
+ }
768
+ }
769
+ return lines.join("\n");
770
+ }
771
+ __name(catalogToModelText, "catalogToModelText");
772
+ function summarizeSchema(schema, root, depth) {
773
+ if (typeof schema !== "object" || schema === null) return "unknown";
774
+ const s = schema;
775
+ if (depth > 5) return "\u2026";
776
+ if (typeof s.$ref === "string") {
777
+ return s.$ref === "#" ? "Self" : s.$ref.split("/").pop() ?? "unknown";
778
+ }
779
+ if (Array.isArray(s.enum)) {
780
+ return s.enum.map((option) => JSON.stringify(option)).join(" | ");
781
+ }
782
+ if ("const" in s) return JSON.stringify(s.const);
783
+ const variants = s.anyOf ?? s.oneOf;
784
+ if (Array.isArray(variants)) {
785
+ return variants.map((variant) => summarizeSchema(variant, root, depth + 1)).join(" | ");
786
+ }
787
+ const types = Array.isArray(s.type) ? s.type : s.type !== void 0 ? [
788
+ s.type
789
+ ] : [];
790
+ if (types.length > 1) {
791
+ return types.map((type2) => summarizeSchema({
792
+ ...s,
793
+ type: type2
794
+ }, root, depth + 1)).join(" | ");
795
+ }
796
+ const type = types[0];
797
+ if (type === "array") {
798
+ const item = s.items === void 0 ? "unknown" : summarizeSchema(s.items, root, depth + 1);
799
+ return /[|\s]/.test(item) && !item.startsWith("{") ? `(${item})[]` : `${item}[]`;
800
+ }
801
+ if (type === "object" || type === void 0 && s.properties !== void 0) {
802
+ const properties = s.properties ?? {};
803
+ const keys = Object.keys(properties);
804
+ if (keys.length === 0) return "object";
805
+ const required = new Set(Array.isArray(s.required) ? s.required : []);
806
+ const fields = keys.map((key) => {
807
+ const field = properties[key];
808
+ const note = typeof field?.description === "string" && depth === 0 ? ` /* ${field.description} */` : "";
809
+ return `${key}${required.has(key) ? "" : "?"}: ${summarizeSchema(field, root, depth + 1)}${note}`;
810
+ });
811
+ return `{ ${fields.join(", ")} }`;
812
+ }
813
+ if (type === "integer") return "number";
814
+ return type ?? "unknown";
815
+ }
816
+ __name(summarizeSchema, "summarizeSchema");
817
+ function fillTemplate(template, props) {
818
+ return template.replace(/\{\{\s*([\w.[\]]+)\s*\}\}/g, (_match, path) => {
819
+ const value = getPath(props, path);
820
+ if (value === null || value === void 0) return "";
821
+ return typeof value === "object" ? JSON.stringify(value) : String(value);
822
+ });
823
+ }
824
+ __name(fillTemplate, "fillTemplate");
825
+ function getPath(source, path) {
826
+ let current = source;
827
+ for (const part of path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean)) {
828
+ if (current === null || current === void 0) return void 0;
829
+ current = current[part];
830
+ }
831
+ return current;
832
+ }
833
+ __name(getPath, "getPath");
834
+
835
+ // src/genui/tools.ts
836
+ var GENUI_SHOW_TOOL = "ui__show";
837
+ function genuiTools(catalog, options = {}) {
838
+ const tools = options.mode === "tree" ? [
839
+ treeTool(catalog, options)
840
+ ] : catalog.modelComponents().map((component) => componentTool(catalog, component, options));
841
+ if (options.showTool !== void 0 && options.showTool !== false) {
842
+ tools.push(showTool(catalog, options));
843
+ }
844
+ return tools;
845
+ }
846
+ __name(genuiTools, "genuiTools");
847
+ function scopeOf(input) {
848
+ return {
849
+ actor: input.actor,
850
+ ...input.threadId !== void 0 ? {
851
+ threadId: input.threadId
852
+ } : {},
853
+ ...input.actor.tenantRef !== void 0 ? {
854
+ tenant: input.actor.tenantRef
855
+ } : {},
856
+ ...input.agentName !== void 0 ? {
857
+ agentName: input.agentName
858
+ } : {}
859
+ };
860
+ }
861
+ __name(scopeOf, "scopeOf");
862
+ function catalogFor(catalog, options, scope) {
863
+ return options.resolveCatalog === void 0 ? catalog : options.resolveCatalog(scope);
864
+ }
865
+ __name(catalogFor, "catalogFor");
866
+ function common(options) {
867
+ return {
868
+ ...options.roles !== void 0 ? {
869
+ roles: options.roles
870
+ } : {},
871
+ ...options.terminal === true ? {
872
+ terminal: true
873
+ } : {}
874
+ };
875
+ }
876
+ __name(common, "common");
877
+ function componentTool(catalog, component, options) {
878
+ const presentation = options.presentation?.(component.name) ?? {
879
+ label: component.title,
880
+ running: `Showing ${lowerFirst(component.title)}`,
881
+ done: `Showed ${lowerFirst(component.title)}`,
882
+ result: {
883
+ kind: "elsewhere"
884
+ }
885
+ };
886
+ const describeFor = /* @__PURE__ */ __name((definition) => `Show the user a ${definition.title} (${definition.name}). ${definition.description}`, "describeFor");
887
+ const dynamic = options.resolveCatalog !== void 0;
888
+ const inputSchema = dynamic ? permissiveSchema(toJsonSchema(component.props) ?? {
889
+ type: "object"
890
+ }) : isStandardSchema(component.props) ? component.props : jsonStandardSchema(component.props, (value) => catalog.validator.validate(component.props, value));
891
+ const handler = {
892
+ async execute(input, ctx) {
893
+ const resolved = await catalogFor(catalog, options, scopeOf(ctx));
894
+ const definition = modelComponent(resolved, component.name);
895
+ if (definition === void 0) {
896
+ throw new Error(`component "${component.name}" is not available here`);
897
+ }
898
+ const validated = await validateProps(definition.props, input, resolved.validator);
899
+ if (!validated.ok) {
900
+ throw new Error(`invalid ${component.name} props: ${formatIssues(validated.issues)}`);
901
+ }
902
+ return push(ctx, component.name, validated.value, definition.version);
903
+ }
904
+ };
905
+ if (dynamic) {
906
+ handler.describe = async (scope) => {
907
+ const resolved = await catalogFor(catalog, options, scopeOf(scope));
908
+ const definition = modelComponent(resolved, component.name);
909
+ if (definition === void 0) {
910
+ return {
911
+ description: `Not available in this conversation \u2014 do not call this tool. (${component.name})`
912
+ };
913
+ }
914
+ return {
915
+ description: describeFor(definition),
916
+ inputSchema: permissiveSchema(toJsonSchema(definition.props) ?? {
917
+ type: "object"
918
+ })
919
+ };
920
+ };
921
+ }
922
+ return {
923
+ spec: {
924
+ name: toolNameFor(component.name, options.namePrefix),
925
+ kind: "read",
926
+ description: describeFor(component),
927
+ inputSchema,
928
+ presentation,
929
+ ...common(options)
930
+ },
931
+ handler
932
+ };
933
+ }
934
+ __name(componentTool, "componentTool");
935
+ function treeTool(catalog, options) {
936
+ const name = options.treeToolName ?? "ui__render";
937
+ const presentation = options.presentation?.(name) ?? {
938
+ label: "Answer",
939
+ running: "Laying out the answer",
940
+ done: "Laid out the answer",
941
+ result: {
942
+ kind: "elsewhere"
943
+ }
944
+ };
945
+ const describeFor = /* @__PURE__ */ __name((resolved) => [
946
+ options.treeInstructions ?? "Render a rich UI to present the answer to the user.",
947
+ catalogToModelText(resolved, {
948
+ mode: "tree"
949
+ })
950
+ ].join("\n"), "describeFor");
951
+ const dynamic = options.resolveCatalog !== void 0;
952
+ const handler = {
953
+ async execute(input, ctx) {
954
+ const resolved = await catalogFor(catalog, options, scopeOf(ctx));
955
+ const result = await validateTree(resolved, input, options.treeLimits);
956
+ if (!result.ok) {
957
+ throw new Error(`invalid UI tree: ${formatIssues(result.issues)}`);
958
+ }
959
+ const root = result.value;
960
+ return push(ctx, GENUI_TREE_COMPONENT, {
961
+ root
962
+ });
963
+ }
964
+ };
965
+ if (dynamic) {
966
+ handler.describe = async (scope) => {
967
+ const resolved = await catalogFor(catalog, options, scopeOf(scope));
968
+ return {
969
+ description: describeFor(resolved),
970
+ inputSchema: permissiveSchema(treeJsonSchema(resolved))
971
+ };
972
+ };
973
+ }
974
+ return {
975
+ spec: {
976
+ name,
977
+ kind: "read",
978
+ description: describeFor(catalog),
979
+ inputSchema: dynamic ? permissiveSchema(treeJsonSchema(catalog)) : asyncJsonStandardSchema(treeJsonSchema(catalog), async (value) => {
980
+ const result = await validateTree(catalog, value, options.treeLimits);
981
+ return result.ok ? {
982
+ value: result.value
983
+ } : {
984
+ issues: result.issues
985
+ };
986
+ }),
987
+ presentation,
988
+ ...common(options)
989
+ },
990
+ handler
991
+ };
992
+ }
993
+ __name(treeTool, "treeTool");
994
+ function showToolJsonSchema(catalog) {
995
+ return {
996
+ type: "object",
997
+ properties: {
998
+ component: {
999
+ type: "string",
1000
+ enum: catalog.modelComponents().map((component) => component.name),
1001
+ description: "Component name from the catalog"
1002
+ },
1003
+ props: {
1004
+ type: "object",
1005
+ description: "The component's props, as the catalog describes them"
1006
+ }
1007
+ },
1008
+ required: [
1009
+ "component",
1010
+ "props"
1011
+ ]
1012
+ };
1013
+ }
1014
+ __name(showToolJsonSchema, "showToolJsonSchema");
1015
+ async function validateShow(catalog, input) {
1016
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
1017
+ return {
1018
+ ok: false,
1019
+ issues: [
1020
+ {
1021
+ path: [],
1022
+ message: "must be { component, props }"
1023
+ }
1024
+ ]
1025
+ };
1026
+ }
1027
+ const { component, props } = input;
1028
+ if (typeof component !== "string") {
1029
+ return {
1030
+ ok: false,
1031
+ issues: [
1032
+ {
1033
+ path: [
1034
+ "component"
1035
+ ],
1036
+ message: "must be a component name"
1037
+ }
1038
+ ]
1039
+ };
1040
+ }
1041
+ const definition = modelComponent(catalog, component);
1042
+ if (definition === void 0) {
1043
+ const allowed = catalog.modelComponents().map((each) => each.name).join(", ");
1044
+ return {
1045
+ ok: false,
1046
+ issues: [
1047
+ {
1048
+ path: [
1049
+ "component"
1050
+ ],
1051
+ message: `unknown component "${component}" (allowed: ${allowed})`
1052
+ }
1053
+ ]
1054
+ };
1055
+ }
1056
+ const validated = await validateProps(definition.props, props ?? {}, catalog.validator);
1057
+ if (!validated.ok) {
1058
+ return {
1059
+ ok: false,
1060
+ issues: validated.issues.map((issue) => ({
1061
+ ...issue,
1062
+ path: [
1063
+ "props",
1064
+ ...issue.path
1065
+ ]
1066
+ }))
1067
+ };
1068
+ }
1069
+ return {
1070
+ ok: true,
1071
+ definition,
1072
+ props: validated.value
1073
+ };
1074
+ }
1075
+ __name(validateShow, "validateShow");
1076
+ function showTool(catalog, options) {
1077
+ const name = typeof options.showTool === "string" ? options.showTool : GENUI_SHOW_TOOL;
1078
+ const presentation = options.presentation?.(name) ?? {
1079
+ label: "Show",
1080
+ running: "Preparing a view",
1081
+ done: "Showed a view",
1082
+ result: {
1083
+ kind: "elsewhere"
1084
+ }
1085
+ };
1086
+ const describeFor = /* @__PURE__ */ __name((resolved) => [
1087
+ options.showInstructions ?? "Show the user one component from the catalog.",
1088
+ catalogToModelText(resolved, {
1089
+ mode: "show"
1090
+ })
1091
+ ].join("\n"), "describeFor");
1092
+ const dynamic = options.resolveCatalog !== void 0;
1093
+ const handler = {
1094
+ async execute(input, ctx) {
1095
+ const resolved = await catalogFor(catalog, options, scopeOf(ctx));
1096
+ const result = await validateShow(resolved, input);
1097
+ if (!result.ok) {
1098
+ throw new Error(`invalid ${name} call: ${formatIssues(result.issues)}`);
1099
+ }
1100
+ return push(ctx, result.definition.name, result.props, result.definition.version);
1101
+ }
1102
+ };
1103
+ if (dynamic) {
1104
+ handler.describe = async (scope) => {
1105
+ const resolved = await catalogFor(catalog, options, scopeOf(scope));
1106
+ return {
1107
+ description: describeFor(resolved),
1108
+ inputSchema: permissiveSchema(showToolJsonSchema(resolved))
1109
+ };
1110
+ };
1111
+ }
1112
+ return {
1113
+ spec: {
1114
+ name,
1115
+ kind: "read",
1116
+ description: describeFor(catalog),
1117
+ inputSchema: dynamic ? permissiveSchema(showToolJsonSchema(catalog)) : asyncJsonStandardSchema(showToolJsonSchema(catalog), async (value) => {
1118
+ const result = await validateShow(catalog, value);
1119
+ return result.ok ? {
1120
+ value: {
1121
+ component: result.definition.name,
1122
+ props: result.props
1123
+ }
1124
+ } : {
1125
+ issues: result.issues
1126
+ };
1127
+ }),
1128
+ presentation,
1129
+ ...common(options)
1130
+ },
1131
+ handler
1132
+ };
1133
+ }
1134
+ __name(showTool, "showTool");
1135
+ function modelComponent(catalog, name) {
1136
+ const definition = catalog.get(name);
1137
+ return definition === void 0 || definition.internal === true ? void 0 : definition;
1138
+ }
1139
+ __name(modelComponent, "modelComponent");
1140
+ async function push(ctx, component, props, version) {
1141
+ const { id } = await ctx.emitUi(component, props, version !== void 0 ? {
1142
+ version
1143
+ } : {});
1144
+ return {
1145
+ shown: component,
1146
+ id
1147
+ };
1148
+ }
1149
+ __name(push, "push");
1150
+ function lowerFirst(text) {
1151
+ return text.length > 0 ? `${text[0]?.toLowerCase()}${text.slice(1)}` : text;
1152
+ }
1153
+ __name(lowerFirst, "lowerFirst");
1154
+ function jsonStandardSchema(schema, validate) {
1155
+ return asyncJsonStandardSchema(schema, (value) => {
1156
+ const issues = validate(value);
1157
+ return issues.length > 0 ? {
1158
+ issues
1159
+ } : {
1160
+ value
1161
+ };
1162
+ });
1163
+ }
1164
+ __name(jsonStandardSchema, "jsonStandardSchema");
1165
+ function permissiveSchema(schema) {
1166
+ return asyncJsonStandardSchema(schema, (value) => ({
1167
+ value
1168
+ }));
1169
+ }
1170
+ __name(permissiveSchema, "permissiveSchema");
1171
+ function asyncJsonStandardSchema(schema, validate) {
1172
+ const toResult = /* @__PURE__ */ __name((outcome) => outcome.issues !== void 0 ? {
1173
+ issues: outcome.issues.map((issue) => ({
1174
+ message: issue.message,
1175
+ path: issue.path
1176
+ }))
1177
+ } : {
1178
+ value: outcome.value
1179
+ }, "toResult");
1180
+ return {
1181
+ "~standard": {
1182
+ version: 1,
1183
+ vendor: "nestjs-agent-genui",
1184
+ validate(value) {
1185
+ const outcome = validate(value);
1186
+ return outcome instanceof Promise ? outcome.then(toResult) : toResult(outcome);
1187
+ },
1188
+ jsonSchema: {
1189
+ input: /* @__PURE__ */ __name(() => schema, "input"),
1190
+ output: /* @__PURE__ */ __name(() => schema, "output")
1191
+ }
1192
+ }
1193
+ };
1194
+ }
1195
+ __name(asyncJsonStandardSchema, "asyncJsonStandardSchema");
1196
+ // Annotate the CommonJS export names for ESM import in node:
1197
+ 0 && (module.exports = {
1198
+ COMPONENT_NAME,
1199
+ GENUI_SHOW_TOOL,
1200
+ GENUI_TREE_COMPONENT,
1201
+ ajvValidator,
1202
+ builtinJsonSchemaValidator,
1203
+ catalogToModelText,
1204
+ componentToText,
1205
+ defineCatalog,
1206
+ defineComponent,
1207
+ fillTemplate,
1208
+ formatIssues,
1209
+ genuiTools,
1210
+ getPath,
1211
+ isStandardSchema,
1212
+ jsonStandardSchema,
1213
+ showToolJsonSchema,
1214
+ summarizeSchema,
1215
+ toJsonSchema,
1216
+ toSnakeCase,
1217
+ toolNameFor,
1218
+ treeJsonSchema,
1219
+ treeToFlatSpec,
1220
+ treeToText,
1221
+ validateProps,
1222
+ validatePropsSync,
1223
+ validateTree
1224
+ });
1225
+ //# sourceMappingURL=index.cjs.map