@ai-matrx/content-ir 0.8.0 → 0.10.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +24 -5
  3. package/dist/convert.cjs +1680 -0
  4. package/dist/convert.cjs.map +1 -0
  5. package/dist/convert.d.cts +230 -0
  6. package/dist/convert.d.ts +230 -0
  7. package/dist/convert.js +1666 -0
  8. package/dist/convert.js.map +1 -0
  9. package/dist/core.cjs +2493 -0
  10. package/dist/core.cjs.map +1 -0
  11. package/dist/core.d.cts +370 -0
  12. package/dist/core.d.ts +370 -0
  13. package/dist/core.js +2452 -0
  14. package/dist/core.js.map +1 -0
  15. package/dist/index.cjs +11 -1
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +9 -2030
  18. package/dist/index.d.ts +9 -2030
  19. package/dist/index.js +11 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/ir-tree-DbLVxbf1.d.cts +441 -0
  22. package/dist/ir-tree-Dsc_66ek.d.ts +441 -0
  23. package/dist/ir-types-95bA2cXH.d.cts +119 -0
  24. package/dist/ir-types-95bA2cXH.d.ts +119 -0
  25. package/dist/kind-schema.types-CwncWj9U.d.cts +139 -0
  26. package/dist/kind-schema.types-CwncWj9U.d.ts +139 -0
  27. package/dist/registry.cjs +468 -0
  28. package/dist/registry.cjs.map +1 -0
  29. package/dist/registry.d.cts +357 -0
  30. package/dist/registry.d.ts +357 -0
  31. package/dist/registry.js +456 -0
  32. package/dist/registry.js.map +1 -0
  33. package/dist/session.cjs +2052 -0
  34. package/dist/session.cjs.map +1 -0
  35. package/dist/session.d.cts +75 -0
  36. package/dist/session.d.ts +75 -0
  37. package/dist/session.js +2047 -0
  38. package/dist/session.js.map +1 -0
  39. package/dist/wire.cjs +310 -0
  40. package/dist/wire.cjs.map +1 -0
  41. package/dist/wire.d.cts +326 -0
  42. package/dist/wire.d.ts +326 -0
  43. package/dist/wire.js +291 -0
  44. package/dist/wire.js.map +1 -0
  45. package/package.json +73 -1
@@ -0,0 +1,1666 @@
1
+ // core/kind-schema.types.ts
2
+ var KIND_KEY = "__kind";
3
+ function scalarArrayItemType(type) {
4
+ if (type === "number[]") return "number";
5
+ if (type === "boolean[]") return "boolean";
6
+ return "string";
7
+ }
8
+
9
+ // utils/text-case-converter.ts
10
+ var DEFAULT_WORD_REPLACEMENTS = {
11
+ // Acronyms & initialisms
12
+ "api": "API",
13
+ "apis": "APIs",
14
+ "ui": "UI",
15
+ "ux": "UX",
16
+ "id": "ID",
17
+ "ids": "IDs",
18
+ "qr": "QR",
19
+ "ssr": "SSR",
20
+ "csr": "CSR",
21
+ "ssg": "SSG",
22
+ "isr": "ISR",
23
+ "spa": "SPA",
24
+ "pwa": "PWA",
25
+ "sdk": "SDK",
26
+ "sdks": "SDKs",
27
+ "cli": "CLI",
28
+ "tty": "TTY",
29
+ "repl": "REPL",
30
+ "ci": "CI",
31
+ "cd": "CD",
32
+ "cpu": "CPU",
33
+ "cpus": "CPUs",
34
+ "gpu": "GPU",
35
+ "gpus": "GPUs",
36
+ "ram": "RAM",
37
+ "rom": "ROM",
38
+ "ssd": "SSD",
39
+ "ssds": "SSDs",
40
+ "hdd": "HDD",
41
+ "hdds": "HDDs",
42
+ "kpi": "KPI",
43
+ "kpis": "KPIs",
44
+ "sla": "SLA",
45
+ "slas": "SLAs",
46
+ "slo": "SLO",
47
+ "slos": "SLOs",
48
+ "sli": "SLI",
49
+ "slis": "SLIs",
50
+ "dom": "DOM",
51
+ // Web, formats, protocols
52
+ "url": "URL",
53
+ "urls": "URLs",
54
+ "uri": "URI",
55
+ "uris": "URIs",
56
+ "http": "HTTP",
57
+ "https": "HTTPS",
58
+ "html": "HTML",
59
+ "css": "CSS",
60
+ "json": "JSON",
61
+ "yaml": "YAML",
62
+ "yml": "YML",
63
+ "toml": "TOML",
64
+ "csv": "CSV",
65
+ "pdf": "PDF",
66
+ "tsv": "TSV",
67
+ "jpg": "JPG",
68
+ "jpeg": "JPEG",
69
+ "png": "PNG",
70
+ "gif": "GIF",
71
+ "webp": "WebP",
72
+ "heic": "HEIC",
73
+ "heif": "HEIF",
74
+ "bmp": "BMP",
75
+ "tiff": "TIFF",
76
+ "ico": "ICO",
77
+ "xml": "XML",
78
+ "sql": "SQL",
79
+ "db": "DB",
80
+ "dbs": "DBs",
81
+ "nosql": "NoSQL",
82
+ "graphql": "GraphQL",
83
+ "grpc": "gRPC",
84
+ "rest": "REST",
85
+ "restful": "RESTful",
86
+ "websocket": "WebSocket",
87
+ "websockets": "WebSockets",
88
+ "webrtc": "WebRTC",
89
+ // Networking
90
+ "ip": "IP",
91
+ "ipv4": "IPv4",
92
+ "ipv6": "IPv6",
93
+ "dns": "DNS",
94
+ "dhcp": "DHCP",
95
+ "nat": "NAT",
96
+ "tcp": "TCP",
97
+ "udp": "UDP",
98
+ "icmp": "ICMP",
99
+ "ttl": "TTL",
100
+ "lan": "LAN",
101
+ "wan": "WAN",
102
+ "vlan": "VLAN",
103
+ "cdn": "CDN",
104
+ "ftp": "FTP",
105
+ "ssh": "SSH",
106
+ "tls": "TLS",
107
+ "ssl": "SSL",
108
+ // Security & crypto
109
+ "jwt": "JWT",
110
+ "jws": "JWS",
111
+ "jwe": "JWE",
112
+ "hmac": "HMAC",
113
+ "rsa": "RSA",
114
+ "ecdsa": "ECDSA",
115
+ "aes": "AES",
116
+ "pbkdf2": "PBKDF2",
117
+ "argon2": "Argon2",
118
+ "scrypt": "scrypt",
119
+ "totp": "TOTP",
120
+ "hotp": "HOTP",
121
+ "mfa": "MFA",
122
+ "2fa": "2FA",
123
+ "csrf": "CSRF",
124
+ "xss": "XSS",
125
+ "ssrf": "SSRF",
126
+ "rce": "RCE",
127
+ "dos": "DoS",
128
+ "ddos": "DDoS",
129
+ "mitm": "MITM",
130
+ "csp": "CSP",
131
+ "cors": "CORS",
132
+ "pii": "PII",
133
+ "phi": "PHI",
134
+ "gdpr": "GDPR",
135
+ "ccpa": "CCPA",
136
+ "hipaa": "HIPAA",
137
+ "rfc": "RFC",
138
+ // Platforms, langs, tools (single-token)
139
+ "javascript": "JavaScript",
140
+ "typescript": "TypeScript",
141
+ "jsx": "JSX",
142
+ "tsx": "TSX",
143
+ "node": "Node",
144
+ // (used when tokenized alone)
145
+ "deno": "Deno",
146
+ "bun": "Bun",
147
+ "react": "React",
148
+ "nextjs": "Next.js",
149
+ // if your tokenizer drops dots, keep this
150
+ "nodejs": "Node.js",
151
+ "postgresql": "PostgreSQL",
152
+ "postgres": "Postgres",
153
+ "mysql": "MySQL",
154
+ "sqlite": "SQLite",
155
+ "redis": "Redis",
156
+ "supabase": "Supabase",
157
+ "docker": "Docker",
158
+ "kubernetes": "Kubernetes",
159
+ "k8s": "Kubernetes",
160
+ "helm": "Helm",
161
+ "npm": "npm",
162
+ "pnpm": "pnpm",
163
+ "yarn": "Yarn",
164
+ "eslint": "ESLint",
165
+ "prettier": "Prettier",
166
+ "vite": "Vite",
167
+ "webpack": "Webpack",
168
+ "babel": "Babel",
169
+ // OS & vendors
170
+ "macos": "macOS",
171
+ "ios": "iOS",
172
+ "ipados": "iPadOS",
173
+ "watchos": "watchOS",
174
+ "tvos": "tvOS",
175
+ "windows": "Windows",
176
+ "linux": "Linux",
177
+ "ubuntu": "Ubuntu",
178
+ "github": "GitHub",
179
+ "gitlab": "GitLab",
180
+ "bitbucket": "Bitbucket",
181
+ // Data & analytics
182
+ "etl": "ETL",
183
+ "elt": "ELT",
184
+ "olap": "OLAP",
185
+ "oltp": "OLTP",
186
+ "bi": "BI",
187
+ // Time & locales
188
+ "utc": "UTC",
189
+ "gmt": "GMT",
190
+ "pst": "PST",
191
+ "pdt": "PDT",
192
+ "pt": "PT",
193
+ // Common “small words” to keep lowercase (unless first/last word)
194
+ "or": "or",
195
+ "and": "and",
196
+ "the": "the",
197
+ "of": "of",
198
+ "in": "in",
199
+ "to": "to",
200
+ "with": "with",
201
+ "as": "as",
202
+ "by": "by",
203
+ "for": "for",
204
+ "on": "on",
205
+ "at": "at",
206
+ "up": "up",
207
+ "a": "a",
208
+ "an": "an",
209
+ "is": "is",
210
+ "are": "are",
211
+ "was": "was",
212
+ "were": "were",
213
+ "be": "be",
214
+ "but": "but",
215
+ "nor": "nor",
216
+ "so": "so",
217
+ "yet": "yet",
218
+ "per": "per",
219
+ "via": "via",
220
+ // Latin abbreviations (tokenized as words in some pipelines)
221
+ "eg": "e.g.",
222
+ "ie": "i.e.",
223
+ "etc": "etc.",
224
+ "aka": "aka",
225
+ "vs": "vs.",
226
+ "v": "v.",
227
+ // Client abbreviations
228
+ "CIC": "CIC",
229
+ "AGR": "AGR",
230
+ "AGER": "AGER",
231
+ "DD": "DD",
232
+ "TS": "TS",
233
+ "TM": "TM",
234
+ "arman": "Arman"
235
+ };
236
+ var DEFAULT_OPTIONS = {
237
+ textCase: "title",
238
+ wordReplacements: DEFAULT_WORD_REPLACEMENTS,
239
+ trim: true
240
+ };
241
+ function formatText(text, options = {}) {
242
+ const opts = { ...DEFAULT_OPTIONS, ...options };
243
+ if (!text) return "";
244
+ let normalized = text.replace(/_/g, " ").replace(/-/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\s+/g, " ");
245
+ if (opts.trim) {
246
+ normalized = normalized.trim();
247
+ }
248
+ let caseTransformed = normalized;
249
+ switch (opts.textCase) {
250
+ case "title":
251
+ caseTransformed = normalized.replace(
252
+ /\w\S*/g,
253
+ (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
254
+ );
255
+ break;
256
+ case "sentence":
257
+ if (normalized.length > 0) {
258
+ caseTransformed = normalized.charAt(0).toUpperCase() + normalized.slice(1).toLowerCase();
259
+ }
260
+ break;
261
+ case "lower":
262
+ caseTransformed = normalized.toLowerCase();
263
+ break;
264
+ case "upper":
265
+ caseTransformed = normalized.toUpperCase();
266
+ break;
267
+ }
268
+ let result = caseTransformed;
269
+ if (opts.wordReplacements) {
270
+ Object.entries(opts.wordReplacements).forEach(([key, value]) => {
271
+ const regex = new RegExp(`\\b${key}\\b`, "gi");
272
+ result = result.replace(regex, value);
273
+ });
274
+ }
275
+ return result;
276
+ }
277
+
278
+ // core/schema-structure.ts
279
+ function formatBlockLabel(key) {
280
+ return formatText(key, { textCase: "title" });
281
+ }
282
+
283
+ // convert/openai-schema-converter.ts
284
+ function requiredNullableFlags(required, nullable) {
285
+ return {
286
+ ...required ? { required: true } : {},
287
+ ...nullable ? { nullable: true } : {}
288
+ };
289
+ }
290
+ var METADATA_KEYS = /* @__PURE__ */ new Set([
291
+ "description",
292
+ "title",
293
+ "default",
294
+ "examples",
295
+ "format",
296
+ "minimum",
297
+ "maximum",
298
+ "multipleOf",
299
+ "exclusiveMinimum",
300
+ "exclusiveMaximum",
301
+ "minLength",
302
+ "maxLength",
303
+ "minItems",
304
+ "maxItems",
305
+ "pattern",
306
+ "const",
307
+ "$schema",
308
+ "$id",
309
+ "deprecated",
310
+ "readOnly",
311
+ "writeOnly"
312
+ ]);
313
+ function isRecord(value) {
314
+ return typeof value === "object" && value !== null && !Array.isArray(value);
315
+ }
316
+ function deepClone(value) {
317
+ return JSON.parse(JSON.stringify(value));
318
+ }
319
+ function fieldSchemaSummary(field) {
320
+ if (field.type === "enum") {
321
+ return `enum(${field.values.join("|")}${field.open ? "|+any" : ""})${field.required ? "*" : ""}`;
322
+ }
323
+ if (field.type === "array") {
324
+ return `array<${field.itemKinds.join("|")}>${field.required ? "*" : ""}`;
325
+ }
326
+ if (field.type === "inline_object") {
327
+ return `inline{${Object.keys(field.fields).join(",")}}${field.required ? "*" : ""}`;
328
+ }
329
+ if (field.type === "object") {
330
+ return `object:${field.kind}${field.required ? "*" : ""}`;
331
+ }
332
+ if (field.type === "union") {
333
+ const members = [...field.scalars, ...field.kinds ?? []];
334
+ return `union(${members.join("|")})${field.required ? "*" : ""}`;
335
+ }
336
+ if (field.type === "record") {
337
+ return `record(${field.values})${field.required ? "*" : ""}`;
338
+ }
339
+ return `${field.type}${field.required ? "*" : ""}${field.nullable ? "?" : ""}`;
340
+ }
341
+ function resolvePrimaryType(node) {
342
+ const raw = node.type;
343
+ if (typeof raw === "string") {
344
+ const t = raw === "integer" ? "number" : raw;
345
+ return { type: t, nullable: false, members: [t] };
346
+ }
347
+ if (Array.isArray(raw)) {
348
+ const types = raw.filter((t) => typeof t === "string");
349
+ const nullable = types.includes("null");
350
+ const members = [
351
+ ...new Set(
352
+ types.filter((t) => t !== "null").map((t) => t === "integer" ? "number" : t)
353
+ )
354
+ ];
355
+ const primary = members[0] ?? (nullable && types.length === 1 ? "null" : null);
356
+ return { type: primary ?? null, nullable, members };
357
+ }
358
+ if (node.enum) return { type: "string", nullable: false, members: ["string"] };
359
+ if (node.properties)
360
+ return { type: "object", nullable: false, members: ["object"] };
361
+ if (node.items)
362
+ return { type: "array", nullable: false, members: ["array"] };
363
+ return { type: null, nullable: false, members: [] };
364
+ }
365
+ function carriedMetadataKeys(field) {
366
+ if (field === null) return /* @__PURE__ */ new Set();
367
+ const carried = /* @__PURE__ */ new Set(["description", "default"]);
368
+ if (field.type === "number") {
369
+ carried.add("minimum");
370
+ carried.add("maximum");
371
+ carried.add("multipleOf");
372
+ }
373
+ return carried;
374
+ }
375
+ function collectDropped(node, path, carriedField = null) {
376
+ const carried = carriedMetadataKeys(carriedField);
377
+ const dropped = {};
378
+ for (const [key, value] of Object.entries(node)) {
379
+ if (METADATA_KEYS.has(key) && !carried.has(key)) {
380
+ dropped[key] = value;
381
+ }
382
+ }
383
+ if (Object.keys(dropped).length > 0) {
384
+ return [{ path, dropped }];
385
+ }
386
+ return [];
387
+ }
388
+ function attachNodeMetadata(node, field) {
389
+ let out = field;
390
+ if (typeof node.description === "string" && out.description === void 0) {
391
+ out = { ...out, description: node.description };
392
+ }
393
+ if (node.default !== void 0 && out.default === void 0) {
394
+ out = { ...out, default: node.default };
395
+ }
396
+ if (out.type === "number") {
397
+ const bounds = {};
398
+ if (typeof node.minimum === "number" && out.min === void 0) {
399
+ bounds.min = node.minimum;
400
+ }
401
+ if (typeof node.maximum === "number" && out.max === void 0) {
402
+ bounds.max = node.maximum;
403
+ }
404
+ if (typeof node.multipleOf === "number" && out.step === void 0) {
405
+ bounds.step = node.multipleOf;
406
+ }
407
+ if (Object.keys(bounds).length > 0) out = { ...out, ...bounds };
408
+ }
409
+ return out;
410
+ }
411
+ function synthesizeItemKindSlug(schemaName, fieldName) {
412
+ const base = fieldName.endsWith("ies") ? `${fieldName.slice(0, -3)}y` : fieldName.endsWith("s") ? fieldName.slice(0, -1) : fieldName;
413
+ return `${schemaName}_${base}`;
414
+ }
415
+ function makeKindJsonSchemaProperty(kindSlug, strict) {
416
+ const base = {
417
+ type: "string",
418
+ description: "Block discriminator for render pipeline."
419
+ };
420
+ if (strict) {
421
+ return { ...base, const: kindSlug };
422
+ }
423
+ return { ...base, enum: [kindSlug] };
424
+ }
425
+ function injectKindIntoObjectSchema(objectSchema, kindSlug, strict) {
426
+ const clone = deepClone(objectSchema);
427
+ const properties = isRecord(clone.properties) ? { ...clone.properties } : {};
428
+ properties[KIND_KEY] = makeKindJsonSchemaProperty(kindSlug, strict);
429
+ const required = Array.isArray(clone.required) ? clone.required.filter((k) => typeof k === "string") : [];
430
+ const nextRequired = required.includes(KIND_KEY) ? required : [KIND_KEY, ...required];
431
+ return {
432
+ ...clone,
433
+ properties,
434
+ required: nextRequired,
435
+ ...strict ? { additionalProperties: false } : {}
436
+ };
437
+ }
438
+ function injectKindsIntoRootSchema(rootSchema, rootKindSlug, arrayBindings, strict) {
439
+ let updated = injectKindIntoObjectSchema(rootSchema, rootKindSlug, strict);
440
+ if (!isRecord(updated.properties)) {
441
+ return updated;
442
+ }
443
+ const properties = { ...updated.properties };
444
+ for (const binding of arrayBindings) {
445
+ const fieldNode = properties[binding.arrayField];
446
+ if (!isRecord(fieldNode)) continue;
447
+ const items = fieldNode.items;
448
+ const itemNode = Array.isArray(items) ? items[0] : items;
449
+ if (!isRecord(itemNode)) continue;
450
+ const updatedItem = injectKindIntoObjectSchema(
451
+ itemNode,
452
+ binding.itemKindSlug,
453
+ strict
454
+ );
455
+ properties[binding.arrayField] = {
456
+ ...fieldNode,
457
+ items: updatedItem
458
+ };
459
+ }
460
+ return { ...updated, properties };
461
+ }
462
+ function buildAgentSchemaWithRenderBlockSupport(input, rootKindSlug, arrayBindings, strict) {
463
+ if (!isRecord(input)) return null;
464
+ const normalized = normalizeAiSchemaInput(input);
465
+ if (!normalized.rootSchema) return null;
466
+ if (normalized.rootSchema.type !== "object" && !isRecord(normalized.rootSchema.properties)) {
467
+ return deepClone(input);
468
+ }
469
+ const updatedRoot = injectKindsIntoRootSchema(
470
+ normalized.rootSchema,
471
+ rootKindSlug,
472
+ arrayBindings,
473
+ strict
474
+ );
475
+ if (isRecord(input.schema) && typeof input.name === "string") {
476
+ return {
477
+ ...deepClone(input),
478
+ schema: updatedRoot
479
+ };
480
+ }
481
+ if (isRecord(input.json_schema)) {
482
+ const inner = buildAgentSchemaWithRenderBlockSupport(
483
+ input.json_schema,
484
+ rootKindSlug,
485
+ arrayBindings,
486
+ strict
487
+ );
488
+ return inner ? { ...deepClone(input), json_schema: inner } : null;
489
+ }
490
+ if (typeof input.name === "string") {
491
+ return {
492
+ ...deepClone(input),
493
+ schema: updatedRoot
494
+ };
495
+ }
496
+ return updatedRoot;
497
+ }
498
+ function resolveRef(ref, ctx) {
499
+ if (ref === "#" || ref === "#/") {
500
+ return { slug: ctx.schemaName, node: ctx.rootSchema };
501
+ }
502
+ const match = /^#\/(?:\$defs|definitions)\/(.+)$/.exec(ref);
503
+ if (!match) return null;
504
+ const name = decodeURIComponent(
505
+ (match[1] ?? "").replace(/~1/g, "/").replace(/~0/g, "~")
506
+ );
507
+ const node = ctx.defs[name];
508
+ if (!isRecord(node)) return null;
509
+ const declared = isRecord(node.properties) ? readBlockKindFromProperties(node.properties) : null;
510
+ return { slug: declared ?? name, node };
511
+ }
512
+ function refToObjectField(resolved, path, ctx) {
513
+ if (ctx.refsInProgress.has(resolved.slug)) return;
514
+ ctx.refsInProgress.add(resolved.slug);
515
+ try {
516
+ registerDeclaredKindDraft(resolved.slug, resolved.node, path, ctx);
517
+ } finally {
518
+ ctx.refsInProgress.delete(resolved.slug);
519
+ }
520
+ }
521
+ function isAnyValueSchema(node) {
522
+ return node.type === void 0 && node.enum === void 0 && node.const === void 0 && node.properties === void 0 && node.items === void 0 && node.additionalProperties === void 0 && node.anyOf === void 0 && node.oneOf === void 0 && node.allOf === void 0 && node.$ref === void 0;
523
+ }
524
+ function registerDeclaredKindDraft(declaredKind, objectNode, path, ctx) {
525
+ if (ctx.blockSchemas.some((draft) => draft.slug === declaredKind)) return;
526
+ if (!isRecord(objectNode.properties)) return;
527
+ const memberRequired = new Set(
528
+ Array.isArray(objectNode.required) ? objectNode.required.filter((k) => typeof k === "string") : []
529
+ );
530
+ const fields = {};
531
+ for (const [propName, propNode] of Object.entries(objectNode.properties)) {
532
+ if (!isRecord(propNode)) continue;
533
+ if (propName === KIND_KEY) continue;
534
+ fields[propName] = convertFieldOrWiden(
535
+ propName,
536
+ propNode,
537
+ memberRequired.has(propName),
538
+ `${path}.${propName}`,
539
+ ctx
540
+ );
541
+ }
542
+ ctx.blockSchemas.push({
543
+ slug: declaredKind,
544
+ label: formatBlockLabel(declaredKind),
545
+ fields
546
+ });
547
+ }
548
+ function convertFieldOrWiden(fieldName, node, required, path, ctx) {
549
+ const before = ctx.problems.length;
550
+ const converted = convertProperty(fieldName, node, required, path, ctx);
551
+ if (converted) return converted;
552
+ for (let i = before; i < ctx.problems.length; i++) {
553
+ const problem = ctx.problems[i];
554
+ if (problem && problem.severity === "error") problem.severity = "warning";
555
+ }
556
+ ctx.problems.push({
557
+ severity: "warning",
558
+ path,
559
+ message: `Field "${fieldName}" has no exact field type \u2014 carried as any JSON value (json) rather than dropped from the kind.`
560
+ });
561
+ return { ...requiredNullableFlags(required), type: "json" };
562
+ }
563
+ function convertProperty(fieldName, node, required, path, ctx) {
564
+ const core = convertPropertyCore(fieldName, node, required, path, ctx);
565
+ const field = core === null ? null : attachNodeMetadata(node, core);
566
+ ctx.droppedMetadata.push(...collectDropped(node, path, field));
567
+ return field;
568
+ }
569
+ function convertPropertyCore(fieldName, node, required, path, ctx) {
570
+ if (typeof node.$ref === "string") {
571
+ const resolved = resolveRef(node.$ref, ctx);
572
+ if (!resolved) {
573
+ ctx.problems.push({
574
+ severity: "error",
575
+ path,
576
+ message: `Unresolvable $ref ("${node.$ref}") \u2014 only "#", "#/$defs/<name>" and "#/definitions/<name>" are supported.`
577
+ });
578
+ return null;
579
+ }
580
+ refToObjectField(resolved, path, ctx);
581
+ return {
582
+ ...requiredNullableFlags(required),
583
+ type: "object",
584
+ kind: resolved.slug
585
+ };
586
+ }
587
+ if (Array.isArray(node.anyOf) || Array.isArray(node.oneOf)) {
588
+ const variants = node.anyOf ?? node.oneOf;
589
+ const scalarTypes = /* @__PURE__ */ new Set();
590
+ const enumVariantSets = [];
591
+ const memberKinds = [];
592
+ const anonymousObjects = [];
593
+ let sawNull = false;
594
+ let unsupported = false;
595
+ for (const variant of variants) {
596
+ if (!isRecord(variant)) {
597
+ unsupported = true;
598
+ continue;
599
+ }
600
+ if (typeof variant.$ref === "string") {
601
+ const resolvedVariant = resolveRef(variant.$ref, ctx);
602
+ if (!resolvedVariant) {
603
+ ctx.problems.push({
604
+ severity: "error",
605
+ path,
606
+ message: `Unresolvable $ref inside anyOf/oneOf ("${variant.$ref}").`
607
+ });
608
+ unsupported = true;
609
+ continue;
610
+ }
611
+ refToObjectField(resolvedVariant, path, ctx);
612
+ memberKinds.push(resolvedVariant.slug);
613
+ continue;
614
+ }
615
+ const { type: type2, nullable: nullable2 } = resolvePrimaryType(variant);
616
+ if (nullable2) sawNull = true;
617
+ if (type2 === "null") {
618
+ sawNull = true;
619
+ continue;
620
+ }
621
+ if (type2 === "string" && Array.isArray(variant.enum)) {
622
+ enumVariantSets.push(
623
+ variant.enum.filter((v) => typeof v === "string")
624
+ );
625
+ continue;
626
+ }
627
+ if (type2 === "string" || type2 === "number" || type2 === "boolean") {
628
+ scalarTypes.add(type2);
629
+ continue;
630
+ }
631
+ if (type2 === "object" && isRecord(variant.properties)) {
632
+ const declared = readBlockKindFromProperties(variant.properties);
633
+ if (declared) {
634
+ memberKinds.push(declared);
635
+ registerDeclaredKindDraft(declared, variant, `${path}<${declared}>`, ctx);
636
+ } else {
637
+ anonymousObjects.push(variant);
638
+ }
639
+ continue;
640
+ }
641
+ unsupported = true;
642
+ }
643
+ if (unsupported) {
644
+ ctx.problems.push({
645
+ severity: "error",
646
+ path,
647
+ message: "anyOf/oneOf with unsupported variants cannot be converted automatically."
648
+ });
649
+ return null;
650
+ }
651
+ if (enumVariantSets.length > 0 && anonymousObjects.length === 0 && memberKinds.length === 0 && [...scalarTypes].every((s) => s === "string")) {
652
+ const values = [...new Set(enumVariantSets.flat())];
653
+ const open = scalarTypes.has("string");
654
+ return {
655
+ ...requiredNullableFlags(required, sawNull),
656
+ type: "enum",
657
+ values,
658
+ ...open ? { open: true } : {}
659
+ };
660
+ }
661
+ if (enumVariantSets.length > 0) {
662
+ ctx.problems.push({
663
+ severity: "warning",
664
+ path,
665
+ message: "anyOf/oneOf mixes an enum variant with non-string members \u2014 enum widened to string within the union."
666
+ });
667
+ scalarTypes.add("string");
668
+ }
669
+ if (anonymousObjects.length === 1 && scalarTypes.size === 0 && memberKinds.length === 0) {
670
+ const [sole] = anonymousObjects;
671
+ const converted = sole ? convertProperty(fieldName, sole, required, path, ctx) : null;
672
+ if (!converted) return null;
673
+ return sawNull ? { ...converted, nullable: true } : converted;
674
+ }
675
+ if (anonymousObjects.length > 0) {
676
+ ctx.problems.push({
677
+ severity: "error",
678
+ path,
679
+ message: "anyOf/oneOf mixing anonymous objects with other variants cannot be converted \u2014 declare __kind on each object variant."
680
+ });
681
+ return null;
682
+ }
683
+ if (scalarTypes.size === 1 && memberKinds.length === 0) {
684
+ const [scalar] = [...scalarTypes];
685
+ if (scalar) {
686
+ return { ...requiredNullableFlags(required, sawNull), type: scalar };
687
+ }
688
+ }
689
+ if (scalarTypes.size > 0 || memberKinds.length > 0) {
690
+ ctx.problems.push({
691
+ severity: "warning",
692
+ path,
693
+ message: `Converted anyOf/oneOf to union of: ${[
694
+ ...scalarTypes,
695
+ ...memberKinds
696
+ ].join(", ")}.`
697
+ });
698
+ return {
699
+ ...requiredNullableFlags(required, sawNull),
700
+ type: "union",
701
+ scalars: [...scalarTypes],
702
+ ...memberKinds.length > 0 ? { kinds: memberKinds } : {}
703
+ };
704
+ }
705
+ ctx.problems.push({
706
+ severity: "warning",
707
+ path,
708
+ message: "anyOf/oneOf carried only null variants \u2014 widened to json (any value)."
709
+ });
710
+ return { ...requiredNullableFlags(required), type: "json" };
711
+ }
712
+ if (Array.isArray(node.allOf)) {
713
+ ctx.problems.push({
714
+ severity: "warning",
715
+ path,
716
+ message: "allOf merged using first object branch only."
717
+ });
718
+ const objectBranch = node.allOf.find(
719
+ (b) => b.properties
720
+ );
721
+ if (objectBranch) {
722
+ return convertProperty(fieldName, objectBranch, required, path, ctx);
723
+ }
724
+ }
725
+ if (isAnyValueSchema(node)) {
726
+ ctx.problems.push({
727
+ severity: "info",
728
+ path,
729
+ message: `Typeless schema at "${path || "(root)"}" \u2014 any JSON value (json).`
730
+ });
731
+ return { ...requiredNullableFlags(required), type: "json" };
732
+ }
733
+ const { type, nullable, members } = resolvePrimaryType(node);
734
+ if (members.length > 1) {
735
+ const objectish = members.some((m) => m === "object" || m === "array");
736
+ if (objectish) {
737
+ ctx.problems.push({
738
+ severity: "info",
739
+ path,
740
+ message: `Union of [${members.join(", ")}] at "${path || "(root)"}" spans objects/arrays \u2014 carried as any JSON value (json).`
741
+ });
742
+ return { ...requiredNullableFlags(required), type: "json" };
743
+ }
744
+ const scalars = members.filter(
745
+ (m) => m === "string" || m === "number" || m === "boolean"
746
+ );
747
+ if (scalars.length === members.length && scalars.length > 1) {
748
+ return {
749
+ ...requiredNullableFlags(required, nullable),
750
+ type: "union",
751
+ scalars
752
+ };
753
+ }
754
+ ctx.problems.push({
755
+ severity: "warning",
756
+ path,
757
+ message: `Union of [${members.join(", ")}] at "${path || "(root)"}" has no exact field type \u2014 carried as any JSON value (json) rather than narrowed to "${type}".`
758
+ });
759
+ return { ...requiredNullableFlags(required), type: "json" };
760
+ }
761
+ if (type === "string") {
762
+ if (Array.isArray(node.enum)) {
763
+ const values = node.enum.filter(
764
+ (v) => typeof v === "string"
765
+ );
766
+ if (values.length !== node.enum.length) {
767
+ ctx.problems.push({
768
+ severity: "warning",
769
+ path,
770
+ message: "Enum contains non-string values; non-strings dropped."
771
+ });
772
+ }
773
+ return {
774
+ ...requiredNullableFlags(required, nullable),
775
+ type: "enum",
776
+ values
777
+ };
778
+ }
779
+ return {
780
+ ...requiredNullableFlags(required, nullable),
781
+ type: "string"
782
+ };
783
+ }
784
+ if (type === "number") {
785
+ return {
786
+ ...requiredNullableFlags(required, nullable),
787
+ type: "number"
788
+ };
789
+ }
790
+ if (type === "boolean") {
791
+ return {
792
+ ...requiredNullableFlags(required, nullable),
793
+ type: "boolean"
794
+ };
795
+ }
796
+ if (type === "array") {
797
+ const items = node.items;
798
+ if (!items) {
799
+ ctx.problems.push({
800
+ severity: "error",
801
+ path,
802
+ message: "Array field is missing items schema."
803
+ });
804
+ return null;
805
+ }
806
+ const itemNode = Array.isArray(items) ? items[0] : items;
807
+ if (!isRecord(itemNode)) {
808
+ ctx.problems.push({
809
+ severity: "error",
810
+ path,
811
+ message: "Array items schema must be an object."
812
+ });
813
+ return null;
814
+ }
815
+ if (typeof itemNode.$ref === "string") {
816
+ const resolvedItem = resolveRef(itemNode.$ref, ctx);
817
+ if (!resolvedItem) {
818
+ ctx.problems.push({
819
+ severity: "error",
820
+ path: `${path}[]`,
821
+ message: `Unresolvable $ref in array items ("${itemNode.$ref}").`
822
+ });
823
+ return null;
824
+ }
825
+ refToObjectField(resolvedItem, `${path}[]`, ctx);
826
+ ctx.arrayBindings.push({
827
+ arrayField: fieldName,
828
+ itemKindSlug: resolvedItem.slug
829
+ });
830
+ return {
831
+ ...requiredNullableFlags(required, nullable),
832
+ type: "array",
833
+ itemKinds: [resolvedItem.slug]
834
+ };
835
+ }
836
+ if (isAnyValueSchema(itemNode)) {
837
+ return {
838
+ ...requiredNullableFlags(required, nullable),
839
+ type: "json[]"
840
+ };
841
+ }
842
+ const itemVariants = Array.isArray(itemNode.anyOf) ? itemNode.anyOf : Array.isArray(itemNode.oneOf) ? itemNode.oneOf : null;
843
+ if (itemVariants) {
844
+ const itemEnumSets = [];
845
+ let itemPlainString = false;
846
+ let itemsAllString = true;
847
+ for (const variant of itemVariants) {
848
+ if (!isRecord(variant) || resolvePrimaryType(variant).type !== "string") {
849
+ itemsAllString = false;
850
+ break;
851
+ }
852
+ if (Array.isArray(variant.enum)) {
853
+ itemEnumSets.push(
854
+ variant.enum.filter((v) => typeof v === "string")
855
+ );
856
+ } else {
857
+ itemPlainString = true;
858
+ }
859
+ }
860
+ if (itemsAllString && itemEnumSets.length > 0) {
861
+ return {
862
+ ...requiredNullableFlags(required, nullable),
863
+ type: "string[]",
864
+ values: [...new Set(itemEnumSets.flat())],
865
+ ...itemPlainString ? { open: true } : {}
866
+ };
867
+ }
868
+ const itemKinds = [];
869
+ for (const variant of itemVariants) {
870
+ if (isRecord(variant) && typeof variant.$ref === "string") {
871
+ const resolvedVariant = resolveRef(variant.$ref, ctx);
872
+ if (!resolvedVariant) {
873
+ ctx.problems.push({
874
+ severity: "error",
875
+ path: `${path}[]`,
876
+ message: `Unresolvable $ref in array items anyOf ("${variant.$ref}").`
877
+ });
878
+ return null;
879
+ }
880
+ itemKinds.push(resolvedVariant.slug);
881
+ refToObjectField(resolvedVariant, `${path}[]<${resolvedVariant.slug}>`, ctx);
882
+ ctx.arrayBindings.push({
883
+ arrayField: fieldName,
884
+ itemKindSlug: resolvedVariant.slug
885
+ });
886
+ continue;
887
+ }
888
+ if (!isRecord(variant) || !isRecord(variant.properties)) {
889
+ ctx.problems.push({
890
+ severity: "error",
891
+ path: `${path}[]`,
892
+ message: "Array items anyOf/oneOf variants must be inline objects declaring __kind, or $refs to defs."
893
+ });
894
+ return null;
895
+ }
896
+ const declared = readBlockKindFromProperties(variant.properties);
897
+ if (!declared) {
898
+ ctx.problems.push({
899
+ severity: "error",
900
+ path: `${path}[]`,
901
+ message: "Array items anyOf/oneOf variant is missing a __kind const/enum declaration."
902
+ });
903
+ return null;
904
+ }
905
+ itemKinds.push(declared);
906
+ registerDeclaredKindDraft(declared, variant, `${path}[]<${declared}>`, ctx);
907
+ ctx.arrayBindings.push({ arrayField: fieldName, itemKindSlug: declared });
908
+ }
909
+ return {
910
+ ...requiredNullableFlags(required, nullable),
911
+ type: "array",
912
+ itemKinds
913
+ };
914
+ }
915
+ const itemType = resolvePrimaryType(itemNode).type;
916
+ if (itemType === "string") {
917
+ if (Array.isArray(itemNode.enum)) {
918
+ return {
919
+ ...requiredNullableFlags(required, nullable),
920
+ type: "string[]",
921
+ values: itemNode.enum.filter(
922
+ (v) => typeof v === "string"
923
+ )
924
+ };
925
+ }
926
+ return {
927
+ ...requiredNullableFlags(required, nullable),
928
+ type: "string[]"
929
+ };
930
+ }
931
+ if (itemType === "number") {
932
+ return {
933
+ ...requiredNullableFlags(required, nullable),
934
+ type: "number[]"
935
+ };
936
+ }
937
+ if (itemType === "boolean") {
938
+ return {
939
+ ...requiredNullableFlags(required, nullable),
940
+ type: "boolean[]"
941
+ };
942
+ }
943
+ if (itemType === "object" && isRecord(itemNode.properties)) {
944
+ const declaredItemKind = readBlockKindFromProperties(itemNode.properties);
945
+ const itemKindSlug = declaredItemKind ?? synthesizeItemKindSlug(ctx.schemaName, fieldName);
946
+ const itemRequired = new Set(
947
+ Array.isArray(itemNode.required) ? itemNode.required.filter((k) => typeof k === "string") : []
948
+ );
949
+ const itemFields = {};
950
+ for (const [propName, propNode] of Object.entries(itemNode.properties)) {
951
+ if (!isRecord(propNode)) continue;
952
+ if (propName === KIND_KEY) continue;
953
+ itemFields[propName] = convertFieldOrWiden(
954
+ propName,
955
+ propNode,
956
+ itemRequired.has(propName),
957
+ `${path}[].${propName}`,
958
+ ctx
959
+ );
960
+ }
961
+ const alreadyHasBlockKind = propNameIsBlockKind(itemNode.properties) || itemRequired.has(KIND_KEY);
962
+ ctx.arrayBindings.push({
963
+ arrayField: fieldName,
964
+ itemKindSlug
965
+ });
966
+ if (!ctx.blockSchemas.some((draft) => draft.slug === itemKindSlug)) {
967
+ ctx.blockSchemas.push({
968
+ slug: itemKindSlug,
969
+ label: declaredItemKind ? formatBlockLabel(itemKindSlug) : formatBlockLabel(`${ctx.schemaName}_${fieldName}_item`),
970
+ fields: itemFields
971
+ });
972
+ }
973
+ if (!alreadyHasBlockKind) {
974
+ ctx.problems.push({
975
+ severity: "warning",
976
+ path: `${path}[]`,
977
+ message: `Array "${fieldName}" items need __kind:"${itemKindSlug}" at runtime (OPTION 1: server injects, OPTION 2: use agent schema with __kind).`
978
+ });
979
+ }
980
+ return {
981
+ ...requiredNullableFlags(required, nullable),
982
+ type: "array",
983
+ itemKinds: [itemKindSlug]
984
+ };
985
+ }
986
+ ctx.problems.push({
987
+ severity: "error",
988
+ path,
989
+ message: `Unsupported array items type "${itemType ?? "unknown"}".`
990
+ });
991
+ return null;
992
+ }
993
+ if (type === "object") {
994
+ const ap = node.additionalProperties;
995
+ const apIsOpen = ap === true || isRecord(ap) && isAnyValueSchema(ap);
996
+ if (isRecord(node.properties)) {
997
+ const nestedRequired = new Set(
998
+ Array.isArray(node.required) ? node.required.filter((k) => typeof k === "string") : []
999
+ );
1000
+ const nestedFields = {};
1001
+ for (const [propName, propNode] of Object.entries(node.properties)) {
1002
+ if (!isRecord(propNode)) continue;
1003
+ if (propName === KIND_KEY) continue;
1004
+ nestedFields[propName] = convertFieldOrWiden(
1005
+ propName,
1006
+ propNode,
1007
+ nestedRequired.has(propName),
1008
+ `${path}.${propName}`,
1009
+ ctx
1010
+ );
1011
+ }
1012
+ const referencedKind = readBlockKindFromProperties(node.properties);
1013
+ if (referencedKind) {
1014
+ if (!ctx.refsInProgress.has(referencedKind)) {
1015
+ ctx.refsInProgress.add(referencedKind);
1016
+ try {
1017
+ registerDeclaredKindDraft(referencedKind, node, path, ctx);
1018
+ } finally {
1019
+ ctx.refsInProgress.delete(referencedKind);
1020
+ }
1021
+ }
1022
+ return {
1023
+ ...requiredNullableFlags(required, nullable),
1024
+ type: "object",
1025
+ kind: referencedKind
1026
+ };
1027
+ }
1028
+ if (Object.keys(nestedFields).length === 0 && !apIsOpen && isRecord(ap) && KIND_KEY in node.properties) {
1029
+ const apType = resolvePrimaryType(ap).type;
1030
+ return {
1031
+ ...requiredNullableFlags(required, nullable),
1032
+ type: "record",
1033
+ values: apType === "string" || apType === "number" || apType === "boolean" ? apType : "json"
1034
+ };
1035
+ }
1036
+ let open = apIsOpen;
1037
+ if (!apIsOpen && isRecord(ap)) {
1038
+ ctx.problems.push({
1039
+ severity: "warning",
1040
+ path,
1041
+ message: "Typed additionalProperties alongside declared properties is not representable \u2014 treated as an OPEN object (extra values unconstrained)."
1042
+ });
1043
+ open = true;
1044
+ } else if (ap === false) {
1045
+ ctx.droppedMetadata.push({
1046
+ path,
1047
+ dropped: { additionalProperties: false }
1048
+ });
1049
+ }
1050
+ return {
1051
+ ...requiredNullableFlags(required, nullable),
1052
+ type: "inline_object",
1053
+ fields: nestedFields,
1054
+ ...open ? { open: true } : {}
1055
+ };
1056
+ }
1057
+ if (apIsOpen || ap === void 0) {
1058
+ if (ap === void 0) {
1059
+ ctx.problems.push({
1060
+ severity: "info",
1061
+ path,
1062
+ message: `Bare object schema at "${path || "(root)"}" \u2014 record of any JSON values.`
1063
+ });
1064
+ }
1065
+ return {
1066
+ ...requiredNullableFlags(required, nullable),
1067
+ type: "record",
1068
+ values: "json"
1069
+ };
1070
+ }
1071
+ if (isRecord(ap)) {
1072
+ const apType = resolvePrimaryType(ap).type;
1073
+ if (apType === "string" || apType === "number" || apType === "boolean") {
1074
+ return {
1075
+ ...requiredNullableFlags(required, nullable),
1076
+ type: "record",
1077
+ values: apType
1078
+ };
1079
+ }
1080
+ ctx.problems.push({
1081
+ severity: "warning",
1082
+ path,
1083
+ message: `Record value schema at "${path}" is not scalar \u2014 widened to record of any JSON values.`
1084
+ });
1085
+ return {
1086
+ ...requiredNullableFlags(required, nullable),
1087
+ type: "record",
1088
+ values: "json"
1089
+ };
1090
+ }
1091
+ return {
1092
+ ...requiredNullableFlags(required, nullable),
1093
+ type: "inline_object",
1094
+ fields: {}
1095
+ };
1096
+ }
1097
+ ctx.problems.push({
1098
+ severity: "error",
1099
+ path,
1100
+ message: `Unsupported or missing JSON Schema type at "${path}".`
1101
+ });
1102
+ return null;
1103
+ }
1104
+ function propNameIsBlockKind(properties) {
1105
+ return KIND_KEY in properties;
1106
+ }
1107
+ function readBlockKindFromProperties(properties) {
1108
+ const kindProp = properties[KIND_KEY];
1109
+ if (!isRecord(kindProp)) return null;
1110
+ if (typeof kindProp.const === "string") return kindProp.const;
1111
+ if (Array.isArray(kindProp.enum) && typeof kindProp.enum[0] === "string") {
1112
+ return kindProp.enum[0];
1113
+ }
1114
+ return null;
1115
+ }
1116
+ function normalizeAiSchemaInput(input) {
1117
+ const parseErrors = [];
1118
+ if (!isRecord(input)) {
1119
+ return {
1120
+ name: null,
1121
+ strict: null,
1122
+ rootSchema: null,
1123
+ parseErrors: ["Input must be a JSON object."]
1124
+ };
1125
+ }
1126
+ if (isRecord(input.json_schema)) {
1127
+ return normalizeAiSchemaInput(input.json_schema);
1128
+ }
1129
+ if (isRecord(input.schema) && typeof input.name === "string") {
1130
+ return {
1131
+ name: input.name,
1132
+ strict: typeof input.strict === "boolean" ? input.strict : null,
1133
+ rootSchema: input.schema,
1134
+ parseErrors: []
1135
+ };
1136
+ }
1137
+ if (typeof input.type === "string" || Array.isArray(input.type) || input.properties || input.items) {
1138
+ const name = typeof input.name === "string" ? input.name : typeof input.title === "string" ? input.title : null;
1139
+ return {
1140
+ name,
1141
+ strict: typeof input.strict === "boolean" ? input.strict : null,
1142
+ rootSchema: input,
1143
+ parseErrors: []
1144
+ };
1145
+ }
1146
+ parseErrors.push(
1147
+ "Expected OpenAI output_schema shape { name, schema } or a root JSON Schema object."
1148
+ );
1149
+ return { name: null, strict: null, rootSchema: null, parseErrors };
1150
+ }
1151
+ function convertAiSchemaToBlockFields(schemaName, rootSchema, strict) {
1152
+ const rawDefs = isRecord(rootSchema.$defs) ? rootSchema.$defs : isRecord(rootSchema.definitions) ? rootSchema.definitions : {};
1153
+ const defs = {};
1154
+ for (const [name, node] of Object.entries(rawDefs)) {
1155
+ if (isRecord(node)) defs[name] = node;
1156
+ }
1157
+ const ctx = {
1158
+ schemaName,
1159
+ strict,
1160
+ problems: [],
1161
+ droppedMetadata: [],
1162
+ blockSchemas: [],
1163
+ arrayBindings: [],
1164
+ defs,
1165
+ rootSchema,
1166
+ refsInProgress: /* @__PURE__ */ new Set()
1167
+ };
1168
+ ctx.droppedMetadata.push(...collectDropped(rootSchema, ""));
1169
+ const rootAp = rootSchema.additionalProperties;
1170
+ const rootIsOpen = rootAp === true || isRecord(rootAp) && isAnyValueSchema(rootAp);
1171
+ const properties = rootSchema.properties;
1172
+ if (!isRecord(properties) || rootIsOpen) {
1173
+ const rootField = convertProperty("$root", rootSchema, false, "$root", ctx);
1174
+ if (!rootField) {
1175
+ ctx.problems.push({
1176
+ severity: "error",
1177
+ path: "",
1178
+ message: "Root schema could not be converted (see problems above) \u2014 expected an object with properties, a scalar/array/json root, or an open object."
1179
+ });
1180
+ return emptyConversionResult(schemaName, strict, ctx);
1181
+ }
1182
+ ctx.blockSchemas.unshift({
1183
+ slug: schemaName,
1184
+ label: formatBlockLabel(schemaName),
1185
+ fields: {},
1186
+ root: rootField
1187
+ });
1188
+ return {
1189
+ schemaName,
1190
+ strict,
1191
+ blockSchemas: ctx.blockSchemas,
1192
+ problems: ctx.problems,
1193
+ droppedMetadata: ctx.droppedMetadata
1194
+ };
1195
+ }
1196
+ const required = new Set(
1197
+ Array.isArray(rootSchema.required) ? rootSchema.required.filter((k) => typeof k === "string") : []
1198
+ );
1199
+ const convertedFields = {};
1200
+ for (const [fieldName, fieldNode] of Object.entries(properties)) {
1201
+ if (!isRecord(fieldNode)) continue;
1202
+ if (fieldName === KIND_KEY) continue;
1203
+ convertedFields[fieldName] = convertFieldOrWiden(
1204
+ fieldName,
1205
+ fieldNode,
1206
+ required.has(fieldName),
1207
+ fieldName,
1208
+ ctx
1209
+ );
1210
+ }
1211
+ const rootHasKind = propNameIsBlockKind(properties) || required.has(KIND_KEY);
1212
+ if (!rootHasKind) {
1213
+ ctx.problems.push({
1214
+ severity: "warning",
1215
+ path: "",
1216
+ message: `Root object needs __kind:"${schemaName}" at runtime (OPTION 1: server injects, OPTION 2: use agent schema with __kind).`
1217
+ });
1218
+ }
1219
+ const rootDraft = {
1220
+ slug: schemaName,
1221
+ label: formatBlockLabel(schemaName),
1222
+ fields: convertedFields
1223
+ };
1224
+ ctx.blockSchemas.unshift(rootDraft);
1225
+ if (typeof rootSchema.additionalProperties === "boolean") {
1226
+ ctx.droppedMetadata.push({
1227
+ path: "",
1228
+ dropped: { additionalProperties: rootSchema.additionalProperties }
1229
+ });
1230
+ }
1231
+ if (strict) {
1232
+ ctx.droppedMetadata.push({
1233
+ path: "",
1234
+ dropped: { strict }
1235
+ });
1236
+ }
1237
+ return {
1238
+ schemaName,
1239
+ strict,
1240
+ blockSchemas: ctx.blockSchemas,
1241
+ problems: ctx.problems,
1242
+ droppedMetadata: ctx.droppedMetadata
1243
+ };
1244
+ }
1245
+ function emptyConversionResult(schemaName, strict, ctx) {
1246
+ return {
1247
+ schemaName,
1248
+ strict,
1249
+ blockSchemas: ctx.blockSchemas,
1250
+ problems: ctx.problems,
1251
+ droppedMetadata: ctx.droppedMetadata
1252
+ };
1253
+ }
1254
+ function compareFieldSchemas(aiField, blockField, fieldName) {
1255
+ const aiPresent = aiField !== void 0;
1256
+ const blockPresent = blockField !== void 0;
1257
+ const aiSummary = aiField ? fieldSchemaSummary(aiField) : null;
1258
+ const blockSummary = blockField ? fieldSchemaSummary(blockField) : null;
1259
+ if (aiPresent && blockPresent) {
1260
+ if (aiSummary === blockSummary) {
1261
+ return {
1262
+ field: fieldName,
1263
+ aiPresent,
1264
+ blockPresent,
1265
+ aiSummary,
1266
+ blockSummary,
1267
+ status: "match"
1268
+ };
1269
+ }
1270
+ const aiRicher = aiField?.type === "enum" && blockField?.type === "string" || aiField?.type === "inline_object" && blockField?.type !== "inline_object";
1271
+ const blockRicher = blockField?.type === "enum" && aiField?.type === "string" || blockField?.required && !aiField?.required;
1272
+ return {
1273
+ field: fieldName,
1274
+ aiPresent,
1275
+ blockPresent,
1276
+ aiSummary,
1277
+ blockSummary,
1278
+ status: aiRicher ? "ai_richer" : blockRicher ? "block_richer" : "type_mismatch",
1279
+ ...aiSummary !== blockSummary && {
1280
+ detail: `${aiSummary} vs ${blockSummary}`
1281
+ }
1282
+ };
1283
+ }
1284
+ if (aiPresent) {
1285
+ return {
1286
+ field: fieldName,
1287
+ aiPresent,
1288
+ blockPresent,
1289
+ aiSummary,
1290
+ blockSummary,
1291
+ status: "ai_only"
1292
+ };
1293
+ }
1294
+ return {
1295
+ field: fieldName,
1296
+ aiPresent,
1297
+ blockPresent,
1298
+ aiSummary,
1299
+ blockSummary,
1300
+ status: "block_only"
1301
+ };
1302
+ }
1303
+ function compareWithExistingKindSchema(convertedFields, existing) {
1304
+ if (!existing) return [];
1305
+ const allFields = /* @__PURE__ */ new Set([
1306
+ ...Object.keys(convertedFields),
1307
+ ...Object.keys(existing.fields)
1308
+ ]);
1309
+ return [...allFields].sort().map(
1310
+ (field) => compareFieldSchemas(
1311
+ convertedFields[field],
1312
+ existing.fields[field],
1313
+ field
1314
+ )
1315
+ );
1316
+ }
1317
+ function runSchemaConversion(input, existingSchemas) {
1318
+ const normalized = normalizeAiSchemaInput(input);
1319
+ if (!normalized.rootSchema || !normalized.name) {
1320
+ return {
1321
+ schemaName: normalized.name,
1322
+ strict: normalized.strict,
1323
+ blockSchemas: [],
1324
+ agentSchemaWithKinds: null,
1325
+ problems: [],
1326
+ droppedMetadata: [],
1327
+ comparisons: [],
1328
+ parseErrors: normalized.parseErrors.length ? normalized.parseErrors : ["Schema name and root schema are required."]
1329
+ };
1330
+ }
1331
+ const strict = normalized.strict ?? false;
1332
+ const core = convertAiSchemaToBlockFields(
1333
+ normalized.name,
1334
+ normalized.rootSchema,
1335
+ strict
1336
+ );
1337
+ const existing = existingSchemas[normalized.name] ?? null;
1338
+ const rootDraft = core.blockSchemas[0];
1339
+ const comparisons = rootDraft ? compareWithExistingKindSchema(rootDraft.fields, existing) : [];
1340
+ const problems = [...core.problems];
1341
+ if (!existing) {
1342
+ problems.push({
1343
+ severity: "info",
1344
+ path: "",
1345
+ message: `No existing block schema with slug "${normalized.name}".`
1346
+ });
1347
+ }
1348
+ const agentSchemaWithKinds = buildAgentSchemaWithRenderBlockSupport(
1349
+ input,
1350
+ normalized.name,
1351
+ collectArrayBindingsFromDrafts(core.blockSchemas, normalized.name),
1352
+ strict
1353
+ );
1354
+ return {
1355
+ ...core,
1356
+ agentSchemaWithKinds,
1357
+ comparisons,
1358
+ problems,
1359
+ parseErrors: []
1360
+ };
1361
+ }
1362
+ function collectArrayBindingsFromDrafts(drafts, rootSlug) {
1363
+ const root = drafts.find((d) => d.slug === rootSlug);
1364
+ if (!root) return [];
1365
+ const bindings = [];
1366
+ for (const [fieldName, field] of Object.entries(root.fields)) {
1367
+ if (field.type !== "array") continue;
1368
+ for (const itemKind of field.itemKinds) {
1369
+ bindings.push({ arrayField: fieldName, itemKindSlug: itemKind });
1370
+ }
1371
+ }
1372
+ return bindings;
1373
+ }
1374
+ function validateBlockSchemaSavePlan(blockSchemas, existingSlugs, hasConversionErrors) {
1375
+ const errors = [];
1376
+ const normalizedExisting = new Set(
1377
+ existingSlugs.map((s) => s.trim().toLowerCase())
1378
+ );
1379
+ const batchSlugs = /* @__PURE__ */ new Set();
1380
+ const itemKindRefs = [];
1381
+ for (const draft of blockSchemas) {
1382
+ const slug = draft.slug.trim();
1383
+ const normalized = slug.toLowerCase();
1384
+ if (!slug) {
1385
+ errors.push("Every block schema must have a non-empty slug.");
1386
+ continue;
1387
+ }
1388
+ if (batchSlugs.has(normalized)) {
1389
+ errors.push(`Duplicate slug in conversion batch: "${slug}".`);
1390
+ }
1391
+ batchSlugs.add(normalized);
1392
+ }
1393
+ const entries = blockSchemas.map((draft) => {
1394
+ const existsInDb = normalizedExisting.has(draft.slug.trim().toLowerCase());
1395
+ return {
1396
+ draft,
1397
+ existsInDb,
1398
+ willSave: !existsInDb
1399
+ };
1400
+ });
1401
+ for (const draft of blockSchemas) {
1402
+ for (const [fieldName, field] of Object.entries(draft.fields)) {
1403
+ if (field.type !== "array") continue;
1404
+ for (const itemKind of field.itemKinds) {
1405
+ const inBatch = batchSlugs.has(itemKind.trim().toLowerCase());
1406
+ const inDb = normalizedExisting.has(itemKind.trim().toLowerCase());
1407
+ const satisfied = inBatch || inDb;
1408
+ itemKindRefs.push({
1409
+ parentSlug: draft.slug,
1410
+ field: fieldName,
1411
+ itemKind,
1412
+ satisfied,
1413
+ source: inBatch ? "batch" : inDb ? "database" : "missing"
1414
+ });
1415
+ if (!satisfied) {
1416
+ errors.push(
1417
+ `"${draft.slug}".${fieldName} references itemKind "${itemKind}" \u2014 not in this batch and not in DB.`
1418
+ );
1419
+ }
1420
+ }
1421
+ }
1422
+ }
1423
+ const newCount = entries.filter((e) => e.willSave).length;
1424
+ if (newCount === 0 && blockSchemas.length > 0) {
1425
+ errors.push("All block schema slugs already exist in the database.");
1426
+ }
1427
+ if (hasConversionErrors) {
1428
+ errors.push("Resolve conversion errors before saving.");
1429
+ }
1430
+ return {
1431
+ entries,
1432
+ itemKindRefs,
1433
+ newCount,
1434
+ canSave: errors.length === 0 && newCount > 0,
1435
+ errors
1436
+ };
1437
+ }
1438
+ function fieldsToDbPayload(fields) {
1439
+ return JSON.parse(JSON.stringify(fields));
1440
+ }
1441
+ function isDuplicateBlockSlug(slug, entries) {
1442
+ const normalized = slug.trim().toLowerCase();
1443
+ return entries.some((e) => e.slug.trim().toLowerCase() === normalized);
1444
+ }
1445
+
1446
+ // convert/kind-to-json-schema.ts
1447
+ function collectReferencedKinds(fields) {
1448
+ const out = [];
1449
+ const seen = /* @__PURE__ */ new Set();
1450
+ const add = (kind) => {
1451
+ if (!seen.has(kind)) {
1452
+ seen.add(kind);
1453
+ out.push(kind);
1454
+ }
1455
+ };
1456
+ const visit = (field) => {
1457
+ if (field.type === "object") {
1458
+ add(field.kind);
1459
+ } else if (field.type === "array") {
1460
+ field.itemKinds.forEach(add);
1461
+ } else if (field.type === "union") {
1462
+ (field.kinds ?? []).forEach(add);
1463
+ } else if (field.type === "inline_object") {
1464
+ Object.values(field.fields).forEach(visit);
1465
+ }
1466
+ };
1467
+ Object.values(fields).forEach(visit);
1468
+ return out;
1469
+ }
1470
+ function collectSchemaReferencedKinds(schema) {
1471
+ if (!schema.root) return collectReferencedKinds(schema.fields);
1472
+ return collectReferencedKinds({ [ROOT_REF_FIELD]: schema.root });
1473
+ }
1474
+ var ROOT_REF_FIELD = "__root";
1475
+ function kindSchemaToJsonSchema(kind, resolve, options = {}) {
1476
+ const strict = options.strict ?? false;
1477
+ const injectKind = options.injectKind ?? true;
1478
+ const rootSchema = resolve(kind);
1479
+ if (!rootSchema) return null;
1480
+ const visited = /* @__PURE__ */ new Set([kind]);
1481
+ const defsOrder = [];
1482
+ const resolvedDefs = /* @__PURE__ */ new Map();
1483
+ const unresolved = [];
1484
+ const queue = collectSchemaReferencedKinds(rootSchema);
1485
+ while (queue.length > 0) {
1486
+ const next = queue.shift();
1487
+ if (visited.has(next)) continue;
1488
+ visited.add(next);
1489
+ defsOrder.push(next);
1490
+ const schema = resolve(next);
1491
+ if (!schema) {
1492
+ unresolved.push(next);
1493
+ continue;
1494
+ }
1495
+ resolvedDefs.set(next, schema);
1496
+ queue.push(...collectSchemaReferencedKinds(schema));
1497
+ }
1498
+ const refFor = (slug) => slug === kind ? { $ref: "#" } : { $ref: `#/$defs/${slug}` };
1499
+ const withNull = (type, nullable) => nullable ? [type, "null"] : type;
1500
+ function fieldToJsonSchema(field) {
1501
+ const node = fieldToJsonSchemaCore(field);
1502
+ if (field.description !== void 0) node.description = field.description;
1503
+ if (field.default !== void 0) node.default = field.default;
1504
+ return node;
1505
+ }
1506
+ function fieldToJsonSchemaCore(field) {
1507
+ switch (field.type) {
1508
+ case "string":
1509
+ case "boolean":
1510
+ return { type: withNull(field.type, field.nullable) };
1511
+ case "number":
1512
+ return {
1513
+ type: withNull("number", field.nullable),
1514
+ ...!strict && field.min !== void 0 ? { minimum: field.min } : {},
1515
+ ...!strict && field.max !== void 0 ? { maximum: field.max } : {},
1516
+ ...!strict && field.step !== void 0 ? { multipleOf: field.step } : {}
1517
+ };
1518
+ case "json":
1519
+ return {};
1520
+ case "string[]": {
1521
+ const items = field.values === void 0 ? { type: "string" } : field.open ? {
1522
+ anyOf: [
1523
+ { type: "string", enum: [...field.values] },
1524
+ { type: "string" }
1525
+ ]
1526
+ } : { type: "string", enum: [...field.values] };
1527
+ return { type: withNull("array", field.nullable), items };
1528
+ }
1529
+ case "number[]":
1530
+ case "boolean[]":
1531
+ return {
1532
+ type: withNull("array", field.nullable),
1533
+ items: { type: scalarArrayItemType(field.type) }
1534
+ };
1535
+ case "json[]":
1536
+ return {
1537
+ type: withNull("array", field.nullable),
1538
+ items: {}
1539
+ };
1540
+ case "enum": {
1541
+ if (!field.open) {
1542
+ return {
1543
+ type: withNull("string", field.nullable),
1544
+ enum: [...field.values]
1545
+ };
1546
+ }
1547
+ const variants = [
1548
+ { type: "string", enum: [...field.values] },
1549
+ { type: "string" }
1550
+ ];
1551
+ if (field.nullable) variants.push({ type: "null" });
1552
+ return { anyOf: variants };
1553
+ }
1554
+ case "union": {
1555
+ const variants = field.scalars.map((scalar) => ({
1556
+ type: scalar
1557
+ }));
1558
+ for (const memberKind of field.kinds ?? []) {
1559
+ variants.push(refFor(memberKind));
1560
+ }
1561
+ if (field.nullable) variants.push({ type: "null" });
1562
+ return { anyOf: variants };
1563
+ }
1564
+ case "record":
1565
+ return {
1566
+ type: withNull("object", field.nullable),
1567
+ additionalProperties: field.values === "json" ? true : { type: field.values }
1568
+ };
1569
+ case "inline_object": {
1570
+ const properties = {};
1571
+ const required = [];
1572
+ for (const [name, child] of Object.entries(field.fields)) {
1573
+ properties[name] = fieldToJsonSchema(child);
1574
+ if (child.required) required.push(name);
1575
+ }
1576
+ return {
1577
+ type: withNull("object", field.nullable),
1578
+ properties,
1579
+ required,
1580
+ ...field.open ? { additionalProperties: true } : strict ? { additionalProperties: false } : {}
1581
+ };
1582
+ }
1583
+ case "object":
1584
+ return field.nullable ? { anyOf: [refFor(field.kind), { type: "null" }] } : refFor(field.kind);
1585
+ case "array": {
1586
+ const [soleItemKind] = field.itemKinds;
1587
+ const items = field.itemKinds.length === 1 && soleItemKind !== void 0 ? refFor(soleItemKind) : { anyOf: field.itemKinds.map(refFor) };
1588
+ return { type: withNull("array", field.nullable), items };
1589
+ }
1590
+ }
1591
+ }
1592
+ function kindObjectSchema(schema) {
1593
+ if (schema.root) {
1594
+ return fieldToJsonSchema(schema.root);
1595
+ }
1596
+ const properties = {};
1597
+ const required = [];
1598
+ for (const [name, field] of Object.entries(schema.fields)) {
1599
+ properties[name] = fieldToJsonSchema(field);
1600
+ if (field.required) required.push(name);
1601
+ }
1602
+ const node = {
1603
+ type: "object",
1604
+ properties,
1605
+ required,
1606
+ ...strict ? { additionalProperties: false } : {}
1607
+ };
1608
+ return injectKind ? injectKindIntoObjectSchema(node, schema.kind, strict) : node;
1609
+ }
1610
+ function unresolvedStub(slug) {
1611
+ const node = {
1612
+ type: "object",
1613
+ description: `Unresolved kind "${slug}" \u2014 schema not available at export time.`
1614
+ };
1615
+ return injectKind ? injectKindIntoObjectSchema(node, slug, false) : node;
1616
+ }
1617
+ const rootNode = kindObjectSchema(rootSchema);
1618
+ if (defsOrder.length === 0) {
1619
+ return { name: kind, schema: rootNode, strict, unresolved };
1620
+ }
1621
+ const defs = {};
1622
+ for (const slug of defsOrder) {
1623
+ const schema = resolvedDefs.get(slug);
1624
+ defs[slug] = schema ? kindObjectSchema(schema) : unresolvedStub(slug);
1625
+ }
1626
+ return { name: kind, schema: { ...rootNode, $defs: defs }, strict, unresolved };
1627
+ }
1628
+
1629
+ // convert/json-schema-to-kind.ts
1630
+ function kindSchemaFromJsonSchema(kind, jsonSchema) {
1631
+ if (jsonSchema === null || jsonSchema === void 0) {
1632
+ return { schema: null, children: {}, problems: [] };
1633
+ }
1634
+ const normalized = normalizeAiSchemaInput(jsonSchema);
1635
+ const rootSchema = normalized.rootSchema ?? (typeof jsonSchema === "object" && !Array.isArray(jsonSchema) ? jsonSchema : null);
1636
+ if (!rootSchema) {
1637
+ return {
1638
+ schema: null,
1639
+ children: {},
1640
+ problems: [
1641
+ {
1642
+ severity: "error",
1643
+ path: "",
1644
+ message: `Kind "${kind}": emitted_json_schema is not a JSON object.`
1645
+ }
1646
+ ]
1647
+ };
1648
+ }
1649
+ const converted = convertAiSchemaToBlockFields(kind, rootSchema, false);
1650
+ let schema = null;
1651
+ const children = {};
1652
+ for (const draft of converted.blockSchemas) {
1653
+ const asKindSchema = {
1654
+ kind: draft.slug,
1655
+ fields: draft.fields,
1656
+ ...draft.root ? { root: draft.root } : {}
1657
+ };
1658
+ if (draft.slug === kind) schema = asKindSchema;
1659
+ else children[draft.slug] = asKindSchema;
1660
+ }
1661
+ return { schema, children, problems: converted.problems };
1662
+ }
1663
+
1664
+ export { buildAgentSchemaWithRenderBlockSupport, collectReferencedKinds, collectSchemaReferencedKinds, compareWithExistingKindSchema, convertAiSchemaToBlockFields, fieldsToDbPayload, injectKindIntoObjectSchema, isDuplicateBlockSlug, kindSchemaFromJsonSchema, kindSchemaToJsonSchema, normalizeAiSchemaInput, runSchemaConversion, validateBlockSchemaSavePlan };
1665
+ //# sourceMappingURL=convert.js.map
1666
+ //# sourceMappingURL=convert.js.map