tool-schema 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,32 @@ All notable changes to this project are documented here. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
5
5
  to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [0.3.1] - 2026-06-07
10
+
11
+ ### Fixed
12
+
13
+ - Applied strict object handling more consistently for nested schemas when
14
+ targeting providers that require `additionalProperties: false`.
15
+ - Preserved object schema details more reliably across OpenAI, Gemini and AI SDK
16
+ conversions.
17
+
18
+ ### Changed
19
+
20
+ - Expanded README guidance for provider-specific strict schema behavior and
21
+ nested object caveats.
22
+
23
+ ## [0.3.0] - 2026-06-05
24
+
25
+ ### Added
26
+
27
+ - Added Vercel AI SDK adapter helpers: `toAISDKTool(...)` emits AI SDK v5
28
+ `inputSchema` tool definitions, and `fromAISDKTool(...)` converts AI SDK tools
29
+ into provider-specific OpenAI, Anthropic, Gemini or MCP tool shapes.
30
+ - Added legacy AI SDK v4 `parameters` support and a zero-dependency
31
+ `zodToJsonSchema` hook for callers using Zod inputs.
32
+
7
33
  ## [0.2.0] - 2026-06-05
8
34
 
9
35
  ### Added
package/README.md CHANGED
@@ -49,6 +49,33 @@ const { tool } = toTool({ name: 'get_weather', description: 'Get the weather', s
49
49
  // `units` becomes required and nullable, additionalProperties:false is added everywhere.
50
50
  ```
51
51
 
52
+ Before:
53
+
54
+ ```json
55
+ {
56
+ "type": "object",
57
+ "properties": {
58
+ "city": { "type": "string" },
59
+ "units": { "type": "string", "enum": ["c", "f"] }
60
+ },
61
+ "required": ["city"]
62
+ }
63
+ ```
64
+
65
+ After `target: 'openai-strict'`:
66
+
67
+ ```json
68
+ {
69
+ "type": "object",
70
+ "properties": {
71
+ "city": { "type": "string" },
72
+ "units": { "type": ["string", "null"], "enum": ["c", "f", null] }
73
+ },
74
+ "required": ["city", "units"],
75
+ "additionalProperties": false
76
+ }
77
+ ```
78
+
52
79
  The same definition, four providers:
53
80
 
54
81
  ```ts
@@ -115,6 +142,43 @@ const schema = z.toJSONSchema(z.object({ city: z.string(), units: z.enum(['c', '
115
142
  const { tool } = toTool({ name: 'get_weather', schema }, { target: 'openai-strict' });
116
143
  ```
117
144
 
145
+ ## Vercel AI SDK adapter
146
+
147
+ AI SDK v5 tools use `{ description?, inputSchema, strict? }`. Convert a normal
148
+ `tool-schema` definition into that shape, while still applying provider rules:
149
+
150
+ ```ts
151
+ import { toAISDKTool, fromAISDKTool } from 'tool-schema';
152
+
153
+ const { tool: aiSdkTool } = toAISDKTool(
154
+ { name: 'get_weather', description: 'Get weather', schema },
155
+ { target: 'openai-strict' },
156
+ );
157
+ // aiSdkTool -> { description, inputSchema, strict: true }
158
+
159
+ // AI SDK tool names usually live as keys in the `tools` object.
160
+ const { tool: openaiTool } = fromAISDKTool('get_weather', aiSdkTool, { target: 'openai-strict' });
161
+ // openaiTool -> { type: 'function', function: { name, description, parameters, strict: true } }
162
+ ```
163
+
164
+ Use `{ aiSDKParameters: true }` for legacy AI SDK v4 `parameters` instead of
165
+ `inputSchema`. For Zod inputs, keep `tool-schema` zero-dependency by passing a
166
+ converter:
167
+
168
+ ```ts
169
+ import { z } from 'zod';
170
+ import { fromAISDKTool } from 'tool-schema';
171
+
172
+ fromAISDKTool(
173
+ 'get_weather',
174
+ { inputSchema: z.object({ city: z.string() }) },
175
+ {
176
+ target: 'openai-strict',
177
+ zodToJsonSchema: z.toJSONSchema,
178
+ },
179
+ );
180
+ ```
181
+
118
182
  ## Lint without transforming
119
183
 
120
184
  Want to know whether a schema is already valid for a provider, for example in a
@@ -129,6 +193,27 @@ if (!ok) {
129
193
  }
130
194
  ```
131
195
 
196
+ ## API reference
197
+
198
+ | Function | Use it when | Returns |
199
+ | ------------------------------------ | --------------------------------------------------------------------------------- | ----------------------------- |
200
+ | `toToolSchema(schema, options)` | You already build the provider tool envelope and only need compatible parameters. | `{ schema, warnings, lossy }` |
201
+ | `toTool(def, options)` | You want the full provider-shaped tool/function declaration. | `{ tool, warnings, lossy }` |
202
+ | `lintToolSchema(schema, options)` | You want CI/test feedback without using the converted schema. | `{ ok, issues }` |
203
+ | `toAISDKTool(def, options)` | You want a Vercel AI SDK tool with converted `inputSchema`. | `{ tool, warnings, lossy }` |
204
+ | `fromAISDKTool(name, tool, options)` | You want to convert an AI SDK tool into a provider tool. | `{ tool, warnings, lossy }` |
205
+
206
+ Options:
207
+
208
+ | Option | Applies to | Default | Effect |
209
+ | ---------------------- | ------------------------- | ---------- | ------------------------------------------------------------------------------------ |
210
+ | `target` | all functions | `'openai'` | One of `openai`, `openai-strict`, `anthropic`, `gemini`, `gemini-jsonschema`, `mcp`. |
211
+ | `openaiResponses` | `toTool`, `fromAISDKTool` | `false` | Emits the flattened OpenAI Responses API tool shape. |
212
+ | `geminiUppercaseTypes` | `gemini` | `false` | Emits `OBJECT`, `STRING`, etc. for raw REST clients that expect enum type names. |
213
+ | `anthropicStrict` | `toTool`, `fromAISDKTool` | `false` | Adds `strict: true` to Anthropic tool declarations. |
214
+ | `aiSDKParameters` | `toAISDKTool` | `false` | Emits legacy AI SDK v4 `parameters` instead of v5 `inputSchema`. |
215
+ | `zodToJsonSchema` | AI SDK helpers | none | Converts Zod/Standard Schema inputs without adding a runtime dependency. |
216
+
132
217
  ## Targets
133
218
 
134
219
  | Target | Output key | What it does |
@@ -174,6 +259,22 @@ to the node), a stable `code`, and a human readable `message`. Codes include
174
259
  `unsupported-format`, `limit-exceeded` and `invalid-name`. `lossy` is `true`
175
260
  whenever a keyword or constraint had to be dropped.
176
261
 
262
+ ## Caveats
263
+
264
+ `tool-schema` is a compatibility transformer, not a full JSON Schema validator.
265
+ It preserves unknown keywords for permissive targets and only strips or rewrites
266
+ keywords that are known to break a target.
267
+
268
+ Gemini has two useful routes. `target: 'gemini'` emits the narrower `parameters`
269
+ schema: local `$ref` pointers are inlined, recursive refs are replaced with `{}`,
270
+ and unsupported composition keywords are stripped with warnings. Use
271
+ `target: 'gemini-jsonschema'` when your Gemini client accepts
272
+ `parametersJsonSchema` and you want to keep richer JSON Schema.
273
+
274
+ OpenAI strict mode has no optional properties. Optional inputs are converted to
275
+ required nullable fields; if an optional field uses `enum`, `null` is added to
276
+ the enum so the nullable value is actually valid JSON Schema.
277
+
177
278
  ## Why zero dependencies
178
279
 
179
280
  This library is meant to sit deep in agent and tool pipelines. No transitive
@@ -27,11 +27,11 @@ function isObjectSchema(schema) {
27
27
  function makeNullable(schema) {
28
28
  if (typeof schema.type === "string") {
29
29
  if (schema.type === "null") return schema;
30
- return { ...schema, type: [schema.type, "null"] };
30
+ return withNullEnum({ ...schema, type: [schema.type, "null"] });
31
31
  }
32
32
  if (Array.isArray(schema.type)) {
33
- if (schema.type.includes("null")) return schema;
34
- return { ...schema, type: [...schema.type, "null"] };
33
+ if (schema.type.includes("null")) return withNullEnum(schema);
34
+ return withNullEnum({ ...schema, type: [...schema.type, "null"] });
35
35
  }
36
36
  if (Array.isArray(schema.anyOf)) {
37
37
  if (schema.anyOf.some((b) => typesOf(b).includes("null"))) return schema;
@@ -39,16 +39,22 @@ function makeNullable(schema) {
39
39
  }
40
40
  return { anyOf: [schema, { type: "null" }] };
41
41
  }
42
+ function withNullEnum(schema) {
43
+ if (!Array.isArray(schema.enum) || schema.enum.some((value) => value === null)) {
44
+ return schema;
45
+ }
46
+ return { ...schema, enum: [...schema.enum, null] };
47
+ }
42
48
  function dereference(root, warnings) {
43
- const defs = {
44
- ...isPlainObject(root.definitions) ? root.definitions : {},
45
- ...isPlainObject(root.$defs) ? root.$defs : {}
46
- };
47
49
  const resolve = (ref) => {
48
- const m = /^#\/(?:\$defs|definitions)\/(.+)$/.exec(ref);
49
- if (!m) return void 0;
50
- const key = decodeURIComponent(m[1].replace(/~1/g, "/").replace(/~0/g, "~"));
51
- return defs[key];
50
+ if (ref === "#") return root;
51
+ if (!ref.startsWith("#/")) return void 0;
52
+ let current = root;
53
+ for (const segment of ref.slice(2).split("/").map(decodePointerSegment)) {
54
+ if (!isPlainObject(current) && !Array.isArray(current)) return void 0;
55
+ current = current[segment];
56
+ }
57
+ return isPlainObject(current) ? current : void 0;
52
58
  };
53
59
  const walk = (node, path, seen) => {
54
60
  if (!isPlainObject(node)) return node;
@@ -66,44 +72,60 @@ function dereference(root, warnings) {
66
72
  const merged = { ...clone(target), ...rest };
67
73
  return walk(merged, path, /* @__PURE__ */ new Set([...seen, ref]));
68
74
  }
69
- return mapChildren(node, path, (child, childPath) => walk(child, childPath, seen));
75
+ const { $defs: _defs, definitions: _definitions, ...withoutDefinitions } = node;
76
+ void _defs;
77
+ void _definitions;
78
+ return mapChildren(withoutDefinitions, path, (child, childPath) => walk(child, childPath, seen));
70
79
  };
71
80
  const out = walk(clone(root), "#", /* @__PURE__ */ new Set());
72
81
  delete out.$defs;
73
82
  delete out.definitions;
74
83
  return out;
75
84
  }
85
+ function decodePointerSegment(segment) {
86
+ try {
87
+ return decodeURIComponent(segment).replace(/~1/g, "/").replace(/~0/g, "~");
88
+ } catch {
89
+ return segment.replace(/~1/g, "/").replace(/~0/g, "~");
90
+ }
91
+ }
92
+ function encodePointerSegment(segment) {
93
+ return segment.replace(/~/g, "~0").replace(/\//g, "~1");
94
+ }
95
+ function pointerPath(path, ...segments) {
96
+ return `${path}/${segments.map((segment) => encodePointerSegment(String(segment))).join("/")}`;
97
+ }
76
98
  function mapChildren(node, path, fn) {
77
99
  const out = { ...node };
78
100
  if (isPlainObject(out.properties)) {
79
101
  const props = {};
80
102
  for (const [k, v] of Object.entries(out.properties)) {
81
- props[k] = fn(v, `${path}/properties/${k}`);
103
+ props[k] = fn(v, pointerPath(path, "properties", k));
82
104
  }
83
105
  out.properties = props;
84
106
  }
85
107
  if (Array.isArray(out.items)) {
86
- out.items = out.items.map((it, i) => fn(it, `${path}/items/${i}`));
108
+ out.items = out.items.map((it, i) => fn(it, pointerPath(path, "items", i)));
87
109
  } else if (isPlainObject(out.items)) {
88
- out.items = fn(out.items, `${path}/items`);
110
+ out.items = fn(out.items, pointerPath(path, "items"));
89
111
  }
90
112
  if (isPlainObject(out.additionalProperties)) {
91
- out.additionalProperties = fn(out.additionalProperties, `${path}/additionalProperties`);
113
+ out.additionalProperties = fn(out.additionalProperties, pointerPath(path, "additionalProperties"));
92
114
  }
93
115
  for (const key of ["anyOf", "oneOf", "allOf"]) {
94
116
  const arr = out[key];
95
117
  if (Array.isArray(arr)) {
96
- out[key] = arr.map((b, i) => fn(b, `${path}/${key}/${i}`));
118
+ out[key] = arr.map((b, i) => fn(b, pointerPath(path, key, i)));
97
119
  }
98
120
  }
99
- if (isPlainObject(out.not)) out.not = fn(out.not, `${path}/not`);
121
+ if (isPlainObject(out.not)) out.not = fn(out.not, pointerPath(path, "not"));
100
122
  for (const key of ["if", "then", "else"]) {
101
- if (isPlainObject(out[key])) out[key] = fn(out[key], `${path}/${key}`);
123
+ if (isPlainObject(out[key])) out[key] = fn(out[key], pointerPath(path, key));
102
124
  }
103
125
  if (isPlainObject(out.patternProperties)) {
104
126
  const pp = {};
105
127
  for (const [k, v] of Object.entries(out.patternProperties)) {
106
- pp[k] = fn(v, `${path}/patternProperties/${k}`);
128
+ pp[k] = fn(v, pointerPath(path, "patternProperties", k));
107
129
  }
108
130
  out.patternProperties = pp;
109
131
  }
@@ -112,7 +134,7 @@ function mapChildren(node, path, fn) {
112
134
  if (isPlainObject(map)) {
113
135
  const next = {};
114
136
  for (const [k, v] of Object.entries(map)) {
115
- next[k] = fn(v, `${path}/${key}/${k}`);
137
+ next[k] = fn(v, pointerPath(path, key, k));
116
138
  }
117
139
  out[key] = next;
118
140
  }
@@ -198,7 +220,7 @@ function toOpenAIStrict(input) {
198
220
  if (!originalRequired.has(key)) {
199
221
  child = makeNullable(child);
200
222
  warnings.add(
201
- `${path}/properties/${key}`,
223
+ pointerPath(path, "properties", key),
202
224
  "forced-required",
203
225
  `Optional property '${key}' was made required and nullable for OpenAI strict mode.`
204
226
  );
@@ -562,8 +584,10 @@ function validateName(name, target, warnings) {
562
584
  }
563
585
 
564
586
  export {
587
+ isPlainObject,
588
+ clone,
565
589
  toToolSchema,
566
590
  toTool,
567
591
  lintToolSchema
568
592
  };
569
- //# sourceMappingURL=chunk-DJPW46DC.js.map
593
+ //# sourceMappingURL=chunk-5J6BWTJC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/util.ts","../src/targets/openai.ts","../src/targets/anthropic.ts","../src/targets/gemini.ts","../src/targets/mcp.ts","../src/transform.ts"],"sourcesContent":["import type { JSONSchema, Warning, WarningCode } from './types.js';\n\n/** Collects warnings and tracks whether the conversion lost information. */\nexport class Warnings {\n readonly list: Warning[] = [];\n lossy = false;\n\n add(path: string, code: WarningCode, message: string, lossy = true): void {\n this.list.push({ path, code, message });\n if (lossy) this.lossy = true;\n }\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** A deep, structurally faithful clone. Uses the platform `structuredClone`. */\nexport function clone<T>(value: T): T {\n return structuredClone(value);\n}\n\n/** Returns the schema's declared types as an array (empty when untyped). */\nexport function typesOf(schema: JSONSchema): string[] {\n if (typeof schema.type === 'string') return [schema.type];\n if (Array.isArray(schema.type)) return schema.type.filter((t) => typeof t === 'string');\n return [];\n}\n\n/**\n * Heuristic: does this node describe an object? True when `type` is `object`\n * (or a union containing it) or when it is untyped but carries object keywords.\n */\nexport function isObjectSchema(schema: JSONSchema): boolean {\n const types = typesOf(schema);\n if (types.includes('object')) return true;\n if (types.length > 0) return false;\n return isPlainObject(schema.properties) || schema.additionalProperties !== undefined;\n}\n\n/**\n * Makes a schema accept `null`. Adds `null` to a string/array `type`, appends a\n * `{ type: 'null' }` branch to an `anyOf`, otherwise wraps the node in an\n * `anyOf` with a null branch. Used by OpenAI strict mode where every property\n * must be `required`, so optional fields are expressed as nullable instead.\n */\nexport function makeNullable(schema: JSONSchema): JSONSchema {\n if (typeof schema.type === 'string') {\n if (schema.type === 'null') return schema;\n return withNullEnum({ ...schema, type: [schema.type, 'null'] });\n }\n if (Array.isArray(schema.type)) {\n if (schema.type.includes('null')) return withNullEnum(schema);\n return withNullEnum({ ...schema, type: [...schema.type, 'null'] });\n }\n if (Array.isArray(schema.anyOf)) {\n if (schema.anyOf.some((b) => typesOf(b).includes('null'))) return schema;\n return { ...schema, anyOf: [...schema.anyOf, { type: 'null' }] };\n }\n return { anyOf: [schema, { type: 'null' }] };\n}\n\nfunction withNullEnum(schema: JSONSchema): JSONSchema {\n if (!Array.isArray(schema.enum) || schema.enum.some((value) => value === null)) {\n return schema;\n }\n return { ...schema, enum: [...schema.enum, null] };\n}\n\n/**\n * Resolves local `$ref` pointers (`#/$defs/...` or `#/definitions/...`) by\n * inlining them. Non local refs are left untouched. Recursive refs are replaced\n * with an empty schema and reported, since target dialects that need inlining\n * (Gemini route A) cannot express recursion.\n */\nexport function dereference(root: JSONSchema, warnings: Warnings): JSONSchema {\n const resolve = (ref: string): JSONSchema | undefined => {\n if (ref === '#') return root;\n if (!ref.startsWith('#/')) return undefined;\n\n let current: unknown = root;\n for (const segment of ref.slice(2).split('/').map(decodePointerSegment)) {\n if (!isPlainObject(current) && !Array.isArray(current)) return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return isPlainObject(current) ? (current as JSONSchema) : undefined;\n };\n\n const walk = (node: JSONSchema, path: string, seen: Set<string>): JSONSchema => {\n if (!isPlainObject(node)) return node;\n if (typeof node.$ref === 'string') {\n const ref = node.$ref;\n const target = resolve(ref);\n if (!target) return node; // leave external / unknown refs in place\n if (seen.has(ref)) {\n warnings.add(path, 'recursive-ref', `Recursive $ref '${ref}' cannot be inlined; replaced with an open schema.`);\n return {};\n }\n const { $ref: _drop, ...rest } = node;\n void _drop;\n warnings.add(path, 'inlined-ref', `Inlined $ref '${ref}'.`, false);\n const merged = { ...clone(target), ...rest };\n return walk(merged, path, new Set([...seen, ref]));\n }\n const { $defs: _defs, definitions: _definitions, ...withoutDefinitions } = node;\n void _defs;\n void _definitions;\n return mapChildren(withoutDefinitions, path, (child, childPath) => walk(child, childPath, seen));\n };\n\n const out = walk(clone(root), '#', new Set());\n delete out.$defs;\n delete out.definitions;\n return out;\n}\n\nfunction decodePointerSegment(segment: string): string {\n try {\n return decodeURIComponent(segment).replace(/~1/g, '/').replace(/~0/g, '~');\n } catch {\n return segment.replace(/~1/g, '/').replace(/~0/g, '~');\n }\n}\n\nfunction encodePointerSegment(segment: string): string {\n return segment.replace(/~/g, '~0').replace(/\\//g, '~1');\n}\n\nexport function pointerPath(path: string, ...segments: Array<string | number>): string {\n return `${path}/${segments.map((segment) => encodePointerSegment(String(segment))).join('/')}`;\n}\n\n/**\n * Applies `fn` to every direct sub schema of `node`, returning a new node. Walks\n * the standard applicator keywords. Leaf keywords are copied as is.\n */\nexport function mapChildren(\n node: JSONSchema,\n path: string,\n fn: (child: JSONSchema, childPath: string) => JSONSchema,\n): JSONSchema {\n const out: JSONSchema = { ...node };\n\n if (isPlainObject(out.properties)) {\n const props: Record<string, JSONSchema> = {};\n for (const [k, v] of Object.entries(out.properties as Record<string, JSONSchema>)) {\n props[k] = fn(v, pointerPath(path, 'properties', k));\n }\n out.properties = props;\n }\n\n if (Array.isArray(out.items)) {\n out.items = out.items.map((it, i) => fn(it, pointerPath(path, 'items', i)));\n } else if (isPlainObject(out.items)) {\n out.items = fn(out.items as JSONSchema, pointerPath(path, 'items'));\n }\n\n if (isPlainObject(out.additionalProperties)) {\n out.additionalProperties = fn(out.additionalProperties as JSONSchema, pointerPath(path, 'additionalProperties'));\n }\n\n for (const key of ['anyOf', 'oneOf', 'allOf'] as const) {\n const arr = out[key];\n if (Array.isArray(arr)) {\n out[key] = arr.map((b, i) => fn(b, pointerPath(path, key, i)));\n }\n }\n\n if (isPlainObject(out.not)) out.not = fn(out.not as JSONSchema, pointerPath(path, 'not'));\n for (const key of ['if', 'then', 'else'] as const) {\n if (isPlainObject(out[key])) out[key] = fn(out[key] as JSONSchema, pointerPath(path, key));\n }\n\n if (isPlainObject(out.patternProperties)) {\n const pp: Record<string, JSONSchema> = {};\n for (const [k, v] of Object.entries(out.patternProperties as Record<string, JSONSchema>)) {\n pp[k] = fn(v, pointerPath(path, 'patternProperties', k));\n }\n out.patternProperties = pp;\n }\n\n for (const key of ['$defs', 'definitions', 'dependentSchemas'] as const) {\n const map = out[key];\n if (isPlainObject(map)) {\n const next: Record<string, JSONSchema> = {};\n for (const [k, v] of Object.entries(map as Record<string, JSONSchema>)) {\n next[k] = fn(v as JSONSchema, pointerPath(path, key, k));\n }\n out[key] = next;\n }\n }\n\n return out;\n}\n\n/** Ensures the root is an object schema, reporting when it was not. */\nexport function ensureObjectRoot(schema: JSONSchema, warnings: Warnings, target: string): JSONSchema {\n if (isObjectSchema(schema)) {\n if (typesOf(schema).length === 0) return { type: 'object', ...schema };\n return schema;\n }\n warnings.add(\n '#',\n 'root-not-object',\n `${target} requires the root schema to be an object; wrapped the schema under a 'value' property.`,\n );\n return {\n type: 'object',\n properties: { value: schema },\n required: ['value'],\n };\n}\n","import type { JSONSchema, TransformResult } from '../types.js';\nimport {\n Warnings,\n clone,\n isObjectSchema,\n isPlainObject,\n makeNullable,\n mapChildren,\n ensureObjectRoot,\n pointerPath,\n} from '../util.js';\n\n/** Formats OpenAI Structured Outputs accepts. Others are dropped in strict mode. */\nconst FORMAT_WHITELIST = new Set([\n 'date-time',\n 'time',\n 'date',\n 'duration',\n 'email',\n 'hostname',\n 'ipv4',\n 'ipv6',\n 'uuid',\n]);\n\n/** Keywords OpenAI strict mode rejects outright. */\nconst UNSUPPORTED = [\n 'not',\n 'if',\n 'then',\n 'else',\n 'dependentRequired',\n 'dependentSchemas',\n 'patternProperties',\n 'unevaluatedProperties',\n] as const;\n\nconst MAX_PROPERTIES = 5000;\nconst MAX_DEPTH = 10;\nconst MAX_ENUM_VALUES = 1000;\n\n/** OpenAI non strict: tool parameters should be an object, otherwise pass through. */\nexport function toOpenAI(input: JSONSchema): TransformResult {\n const warnings = new Warnings();\n const schema = ensureObjectRoot(clone(input), warnings, 'OpenAI');\n return { schema, warnings: warnings.list, lossy: warnings.lossy };\n}\n\n/**\n * OpenAI Structured Outputs / `strict: true`. Enforces: every object has\n * `additionalProperties: false`; every property is `required` (optional ones\n * become nullable); unsupported keywords are stripped; `allOf` is merged; only\n * whitelisted `format` values survive. `$defs` / `$ref` and `anyOf` are kept.\n */\nexport function toOpenAIStrict(input: JSONSchema): TransformResult {\n const warnings = new Warnings();\n\n const transform = (node: JSONSchema, path: string): JSONSchema => {\n if (!isPlainObject(node)) return node;\n let s: JSONSchema = { ...node };\n\n if (Array.isArray(s.allOf)) {\n s = mergeAllOf(s, path, warnings);\n }\n\n for (const kw of UNSUPPORTED) {\n if (kw in s) {\n delete s[kw];\n warnings.add(path, 'stripped-keyword', `'${kw}' is not supported in OpenAI strict mode; removed.`);\n }\n }\n\n if (typeof s.format === 'string' && !FORMAT_WHITELIST.has(s.format)) {\n warnings.add(\n `${path}/format`,\n 'unsupported-format',\n `format '${s.format}' is not in OpenAI's whitelist; removed.`,\n );\n delete s.format;\n }\n\n // Recurse into all sub schemas first (anyOf branches, items, $defs, ...).\n s = mapChildren(s, path, transform);\n\n if (isObjectSchema(s) && isPlainObject(s.properties)) {\n const props = s.properties as Record<string, JSONSchema>;\n const originalRequired = new Set(Array.isArray(s.required) ? s.required : []);\n const nextProps: Record<string, JSONSchema> = {};\n for (const key of Object.keys(props)) {\n let child = props[key];\n if (!originalRequired.has(key)) {\n child = makeNullable(child);\n warnings.add(\n pointerPath(path, 'properties', key),\n 'forced-required',\n `Optional property '${key}' was made required and nullable for OpenAI strict mode.`,\n );\n }\n nextProps[key] = child;\n }\n s.properties = nextProps;\n s.required = Object.keys(nextProps);\n if (s.additionalProperties !== false) {\n warnings.add(\n path,\n 'forced-additional-properties',\n \"Set 'additionalProperties: false' as required by strict mode.\",\n false,\n );\n }\n s.additionalProperties = false;\n } else if (isObjectSchema(s)) {\n // Object without declared properties: strict mode still forbids extra keys.\n if (s.additionalProperties !== false) {\n warnings.add(\n path,\n 'forced-additional-properties',\n \"Set 'additionalProperties: false' on a property-less object.\",\n false,\n );\n }\n s.additionalProperties = false;\n }\n\n return s;\n };\n\n const schema = ensureObjectRoot(transform(clone(input), '#'), warnings, 'OpenAI strict mode');\n checkLimits(schema, warnings);\n return { schema, warnings: warnings.list, lossy: warnings.lossy };\n}\n\n/** Shallow merges `allOf` object subschemas into the parent, then drops `allOf`. */\nfunction mergeAllOf(node: JSONSchema, path: string, warnings: Warnings): JSONSchema {\n const parts = node.allOf as JSONSchema[];\n const { allOf: _drop, ...base } = node;\n void _drop;\n const merged: JSONSchema = { ...base };\n const props: Record<string, JSONSchema> = isPlainObject(merged.properties)\n ? { ...(merged.properties as Record<string, JSONSchema>) }\n : {};\n const required = new Set<string>(Array.isArray(merged.required) ? merged.required : []);\n\n for (const part of parts) {\n if (!isPlainObject(part)) continue;\n if (isPlainObject(part.properties)) {\n Object.assign(props, part.properties);\n }\n if (Array.isArray(part.required)) {\n for (const r of part.required) required.add(r);\n }\n if (part.type && !merged.type) merged.type = part.type;\n }\n\n if (Object.keys(props).length > 0) merged.properties = props;\n if (required.size > 0) merged.required = [...required];\n if (!merged.type && (merged.properties || isObjectSchema(merged))) merged.type = 'object';\n warnings.add(path, 'merged-allof', \"Merged 'allOf' subschemas into the parent (unsupported in strict mode).\");\n return merged;\n}\n\nfunction checkLimits(schema: JSONSchema, warnings: Warnings): void {\n let propertyCount = 0;\n let maxDepth = 0;\n\n const visit = (node: JSONSchema, depth: number): void => {\n if (!isPlainObject(node)) return;\n maxDepth = Math.max(maxDepth, depth);\n if (isPlainObject(node.properties)) {\n const keys = Object.keys(node.properties as Record<string, JSONSchema>);\n propertyCount += keys.length;\n }\n if (Array.isArray(node.enum) && node.enum.length > MAX_ENUM_VALUES) {\n warnings.add(\n '#',\n 'limit-exceeded',\n `An enum has ${node.enum.length} values; OpenAI allows at most ${MAX_ENUM_VALUES}.`,\n false,\n );\n }\n const children = collectChildren(node);\n for (const c of children) visit(c, depth + 1);\n };\n\n visit(schema, 0);\n if (propertyCount > MAX_PROPERTIES) {\n warnings.add(\n '#',\n 'limit-exceeded',\n `Schema has ${propertyCount} object properties; OpenAI allows at most ${MAX_PROPERTIES}.`,\n false,\n );\n }\n if (maxDepth > MAX_DEPTH) {\n warnings.add(\n '#',\n 'limit-exceeded',\n `Schema nests ${maxDepth} levels deep; OpenAI allows at most ${MAX_DEPTH}.`,\n false,\n );\n }\n}\n\nfunction collectChildren(node: JSONSchema): JSONSchema[] {\n const out: JSONSchema[] = [];\n if (isPlainObject(node.properties)) out.push(...Object.values(node.properties as Record<string, JSONSchema>));\n if (Array.isArray(node.items)) out.push(...node.items);\n else if (isPlainObject(node.items)) out.push(node.items as JSONSchema);\n for (const key of ['anyOf', 'oneOf', 'allOf'] as const) {\n const arr = node[key];\n if (Array.isArray(arr)) out.push(...arr);\n }\n if (isPlainObject(node.$defs)) out.push(...Object.values(node.$defs as Record<string, JSONSchema>));\n return out.filter(isPlainObject) as JSONSchema[];\n}\n","import type { JSONSchema, TransformResult } from '../types.js';\nimport { Warnings, clone, ensureObjectRoot } from '../util.js';\n\n/**\n * Anthropic tool use. The API is permissive: it accepts standard JSON Schema for\n * `input_schema` (anyOf, oneOf, allOf, $ref, format, pattern, ...). The only hard\n * requirement is that the root is an object, so that is all we enforce.\n */\nexport function toAnthropic(input: JSONSchema): TransformResult {\n const warnings = new Warnings();\n const schema = ensureObjectRoot(clone(input), warnings, 'Anthropic');\n return { schema, warnings: warnings.list, lossy: warnings.lossy };\n}\n","import type { JSONSchema, TransformResult } from '../types.js';\nimport { Warnings, clone, dereference, ensureObjectRoot, isPlainObject, mapChildren, typesOf } from '../util.js';\n\n/**\n * Keywords absent from Gemini's `Schema` proto (route A). Sending them either\n * errors or is silently ignored, so they are stripped.\n */\nconst STRIP = [\n '$schema',\n '$id',\n '$anchor',\n '$ref',\n 'oneOf',\n 'allOf',\n 'not',\n 'if',\n 'then',\n 'else',\n 'additionalProperties',\n 'patternProperties',\n 'unevaluatedProperties',\n 'const',\n 'dependentRequired',\n 'dependentSchemas',\n 'multipleOf',\n 'exclusiveMinimum',\n 'exclusiveMaximum',\n 'uniqueItems',\n 'contentEncoding',\n 'contentMediaType',\n '$defs',\n 'definitions',\n] as const;\n\nconst TYPE_UPPER: Record<string, string> = {\n string: 'STRING',\n number: 'NUMBER',\n integer: 'INTEGER',\n boolean: 'BOOLEAN',\n array: 'ARRAY',\n object: 'OBJECT',\n null: 'NULL',\n};\n\ninterface GeminiOptions {\n uppercaseTypes?: boolean;\n}\n\n/**\n * Gemini function calling, route A (`parameters` as an OpenAPI 3.0 subset).\n * Inlines `$ref`, strips unsupported keywords, converts nullable unions to\n * `nullable: true`, collapses `anyOf` null branches, and coerces enum values to\n * strings. Use the `gemini-jsonschema` target for the richer\n * `parametersJsonSchema` route.\n */\nexport function toGemini(input: JSONSchema, options: GeminiOptions = {}): TransformResult {\n const warnings = new Warnings();\n const dereferenced = dereference(clone(input), warnings);\n\n const transform = (node: JSONSchema, path: string): JSONSchema => {\n if (!isPlainObject(node)) return node;\n let s: JSONSchema = { ...node };\n\n for (const kw of STRIP) {\n if (kw in s) {\n delete s[kw];\n warnings.add(path, 'stripped-keyword', `'${kw}' is not supported by Gemini (route A); removed.`);\n }\n }\n\n s = collapseNullableUnion(s, path, warnings);\n s = mapChildren(s, path, transform);\n s = collapseAnyOf(s, path, warnings);\n coerceEnum(s, path, warnings);\n return s;\n };\n\n let schema = ensureObjectRoot(transform(dereferenced, '#'), warnings, 'Gemini');\n if (options.uppercaseTypes) schema = uppercaseTypes(schema);\n return { schema, warnings: warnings.list, lossy: warnings.lossy };\n}\n\n/** Final pass: rewrite JSON Schema type names to Gemini's upper case enum. */\nfunction uppercaseTypes(node: JSONSchema): JSONSchema {\n if (!isPlainObject(node)) return node;\n const out: JSONSchema = { ...node };\n if (typeof out.type === 'string') {\n out.type = TYPE_UPPER[out.type] ?? out.type;\n } else if (Array.isArray(out.type)) {\n out.type = out.type.map((t) => TYPE_UPPER[t] ?? t);\n }\n return mapChildren(out, '#', (child) => uppercaseTypes(child));\n}\n\n/** Gemini route B (`parametersJsonSchema`): richer JSON Schema, object root only. */\nexport function toGeminiJsonSchema(input: JSONSchema): TransformResult {\n const warnings = new Warnings();\n const schema = ensureObjectRoot(clone(input), warnings, 'Gemini (parametersJsonSchema)');\n return { schema, warnings: warnings.list, lossy: warnings.lossy };\n}\n\n/** Converts `type: ['string', 'null']` into `type: 'string', nullable: true`. */\nfunction collapseNullableUnion(node: JSONSchema, path: string, warnings: Warnings): JSONSchema {\n if (!Array.isArray(node.type)) return node;\n const nonNull = node.type.filter((t) => t !== 'null');\n const hadNull = node.type.includes('null');\n const out: JSONSchema = { ...node };\n if (nonNull.length === 0) {\n out.type = 'string';\n } else {\n out.type = nonNull[0];\n if (nonNull.length > 1) {\n warnings.add(\n path,\n 'union-types',\n `Gemini cannot express a union of types [${nonNull.join(', ')}]; kept '${nonNull[0]}'.`,\n );\n }\n }\n if (hadNull) {\n out.nullable = true;\n warnings.add(path, 'collapsed-nullable', \"Converted nullable type union into 'nullable: true'.\", false);\n }\n return out;\n}\n\n/** Removes `{ type: 'null' }` branches from `anyOf`, mapping them to `nullable`. */\nfunction collapseAnyOf(node: JSONSchema, path: string, warnings: Warnings): JSONSchema {\n if (!Array.isArray(node.anyOf)) return node;\n const branches = node.anyOf as JSONSchema[];\n const nonNull = branches.filter((b) => !(typesOf(b).length === 1 && typesOf(b)[0] === 'null'));\n const hadNull = nonNull.length !== branches.length;\n const out: JSONSchema = { ...node };\n\n if (hadNull) {\n out.nullable = true;\n warnings.add(path, 'collapsed-nullable', \"Converted an anyOf null branch into 'nullable: true'.\", false);\n }\n\n if (nonNull.length === 0) {\n delete out.anyOf;\n if (!out.type) out.type = 'string';\n } else if (nonNull.length === 1) {\n // Flatten a single remaining branch into the parent.\n delete out.anyOf;\n const branch = nonNull[0];\n for (const [k, v] of Object.entries(branch)) {\n if (k === 'description' && out.description) continue;\n out[k] = v;\n }\n } else {\n out.anyOf = nonNull;\n }\n return out;\n}\n\n/** Gemini enum values must be strings. Coerces and reports when they were not. */\nfunction coerceEnum(node: JSONSchema, path: string, warnings: Warnings): void {\n if (!Array.isArray(node.enum)) return;\n const allStrings = node.enum.every((v) => typeof v === 'string');\n if (!allStrings) {\n node.enum = node.enum.map((v) => String(v));\n warnings.add(`${path}/enum`, 'enum-coerced', 'Gemini enum values must be strings; coerced non string values.');\n }\n if (!node.type) node.type = 'string';\n}\n","import type { JSONSchema, TransformResult } from '../types.js';\nimport { Warnings, clone, ensureObjectRoot } from '../util.js';\n\n/**\n * MCP (Model Context Protocol) tools. The most permissive input target:\n * `inputSchema` is standard JSON Schema and the spec only requires the root to\n * be an object. All input keywords are preserved. MCP `outputSchema` is handled\n * at the tool envelope layer because it describes `structuredContent` and does\n * not share the input object-root constraint.\n */\nexport function toMcp(input: JSONSchema): TransformResult {\n const warnings = new Warnings();\n const schema = ensureObjectRoot(clone(input), warnings, 'MCP');\n return { schema, warnings: warnings.list, lossy: warnings.lossy };\n}\n","import type {\n JSONSchema,\n LintResult,\n Target,\n ToolDefinition,\n ToolResult,\n ToolSchemaOptions,\n TransformResult,\n Warning,\n} from './types.js';\nimport { toOpenAI, toOpenAIStrict } from './targets/openai.js';\nimport { toAnthropic } from './targets/anthropic.js';\nimport { toGemini, toGeminiJsonSchema } from './targets/gemini.js';\nimport { toMcp } from './targets/mcp.js';\nimport { clone } from './util.js';\n\nconst EMPTY_OBJECT_SCHEMA: JSONSchema = { type: 'object', properties: {} };\n\n/**\n * Convert any JSON Schema into a schema that is valid for a provider's tool /\n * function calling parameters.\n *\n * @example\n * const { schema, warnings } = toToolSchema(mySchema, { target: 'openai-strict' });\n */\nexport function toToolSchema(schema: JSONSchema, options: ToolSchemaOptions = {}): TransformResult {\n const target = options.target ?? 'openai';\n switch (target) {\n case 'openai':\n return toOpenAI(schema);\n case 'openai-strict':\n return toOpenAIStrict(schema);\n case 'anthropic':\n return toAnthropic(schema);\n case 'gemini':\n return toGemini(schema, { uppercaseTypes: options.geminiUppercaseTypes });\n case 'gemini-jsonschema':\n return toGeminiJsonSchema(schema);\n case 'mcp':\n return toMcp(schema);\n default:\n throw new Error(`Unknown target: ${String(target satisfies never)}`);\n }\n}\n\n/**\n * Build a complete, provider shaped tool / function declaration: the right\n * wrapper keys (`function`, `input_schema`, `parameters`, `inputSchema`), the\n * converted parameter schema, and provider specific extras such as `strict` or\n * MCP `annotations`.\n */\nexport function toTool(def: ToolDefinition, options: ToolSchemaOptions = {}): ToolResult {\n const target = options.target ?? 'openai';\n const result = toToolSchema(def.schema ?? EMPTY_OBJECT_SCHEMA, options);\n const warnings: Warning[] = [...result.warnings];\n validateName(def.name, target, warnings);\n\n const tool = buildTool(def, result.schema, target, options);\n return { tool, warnings, lossy: result.lossy };\n}\n\n/**\n * Report what would change to make `schema` valid for a target, without\n * applying it. `ok` is true when the schema is already conformant.\n */\nexport function lintToolSchema(schema: JSONSchema, options: ToolSchemaOptions = {}): LintResult {\n const { warnings } = toToolSchema(schema, options);\n return { ok: warnings.length === 0, issues: warnings };\n}\n\nfunction buildTool(\n def: ToolDefinition,\n schema: JSONSchema,\n target: Target,\n options: ToolSchemaOptions,\n): Record<string, unknown> {\n const { name, description } = def;\n\n switch (target) {\n case 'openai':\n case 'openai-strict': {\n const strict = target === 'openai-strict';\n if (options.openaiResponses) {\n return {\n type: 'function',\n name,\n ...(description ? { description } : {}),\n parameters: schema,\n ...(strict ? { strict: true } : {}),\n };\n }\n return {\n type: 'function',\n function: {\n name,\n ...(description ? { description } : {}),\n parameters: schema,\n ...(strict ? { strict: true } : {}),\n },\n };\n }\n case 'anthropic':\n return {\n name,\n ...(description ? { description } : {}),\n input_schema: schema,\n ...(options.anthropicStrict ? { strict: true } : {}),\n };\n case 'gemini':\n return {\n name,\n ...(description ? { description } : {}),\n parameters: schema,\n };\n case 'gemini-jsonschema':\n return {\n name,\n ...(description ? { description } : {}),\n parametersJsonSchema: schema,\n };\n case 'mcp':\n return {\n name,\n ...(description ? { description } : {}),\n inputSchema: schema,\n ...(def.outputSchema ? { outputSchema: clone(def.outputSchema) } : {}),\n ...(def.annotations ? { annotations: def.annotations } : {}),\n };\n default:\n throw new Error(`Unknown target: ${String(target satisfies never)}`);\n }\n}\n\nconst NAME_RULES: Record<Target, { pattern: RegExp; label: string }> = {\n openai: { pattern: /^[a-zA-Z0-9_-]{1,64}$/, label: 'OpenAI (letters, digits, _ and -, max 64)' },\n 'openai-strict': { pattern: /^[a-zA-Z0-9_-]{1,64}$/, label: 'OpenAI (letters, digits, _ and -, max 64)' },\n anthropic: { pattern: /^[a-zA-Z0-9_-]{1,64}$/, label: 'Anthropic (letters, digits, _ and -, max 64)' },\n gemini: { pattern: /^[a-zA-Z0-9_:.-]{1,128}$/, label: 'Gemini (letters, digits, _ : . -, max 128)' },\n 'gemini-jsonschema': { pattern: /^[a-zA-Z0-9_:.-]{1,128}$/, label: 'Gemini (letters, digits, _ : . -, max 128)' },\n mcp: { pattern: /^[a-zA-Z0-9_-]{1,128}$/, label: 'MCP (letters, digits, _ and -)' },\n};\n\nfunction validateName(name: string, target: Target, warnings: Warning[]): void {\n const rule = NAME_RULES[target];\n if (!rule.pattern.test(name)) {\n warnings.push({\n path: '#/name',\n code: 'invalid-name',\n message: `Tool name '${name}' does not match the ${rule.label} naming rule.`,\n });\n }\n}\n"],"mappings":"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","names":[]}
package/dist/cli.cjs CHANGED
@@ -33,11 +33,11 @@ function isObjectSchema(schema) {
33
33
  function makeNullable(schema) {
34
34
  if (typeof schema.type === "string") {
35
35
  if (schema.type === "null") return schema;
36
- return { ...schema, type: [schema.type, "null"] };
36
+ return withNullEnum({ ...schema, type: [schema.type, "null"] });
37
37
  }
38
38
  if (Array.isArray(schema.type)) {
39
- if (schema.type.includes("null")) return schema;
40
- return { ...schema, type: [...schema.type, "null"] };
39
+ if (schema.type.includes("null")) return withNullEnum(schema);
40
+ return withNullEnum({ ...schema, type: [...schema.type, "null"] });
41
41
  }
42
42
  if (Array.isArray(schema.anyOf)) {
43
43
  if (schema.anyOf.some((b) => typesOf(b).includes("null"))) return schema;
@@ -45,16 +45,22 @@ function makeNullable(schema) {
45
45
  }
46
46
  return { anyOf: [schema, { type: "null" }] };
47
47
  }
48
+ function withNullEnum(schema) {
49
+ if (!Array.isArray(schema.enum) || schema.enum.some((value) => value === null)) {
50
+ return schema;
51
+ }
52
+ return { ...schema, enum: [...schema.enum, null] };
53
+ }
48
54
  function dereference(root, warnings) {
49
- const defs = {
50
- ...isPlainObject(root.definitions) ? root.definitions : {},
51
- ...isPlainObject(root.$defs) ? root.$defs : {}
52
- };
53
55
  const resolve = (ref) => {
54
- const m = /^#\/(?:\$defs|definitions)\/(.+)$/.exec(ref);
55
- if (!m) return void 0;
56
- const key = decodeURIComponent(m[1].replace(/~1/g, "/").replace(/~0/g, "~"));
57
- return defs[key];
56
+ if (ref === "#") return root;
57
+ if (!ref.startsWith("#/")) return void 0;
58
+ let current = root;
59
+ for (const segment of ref.slice(2).split("/").map(decodePointerSegment)) {
60
+ if (!isPlainObject(current) && !Array.isArray(current)) return void 0;
61
+ current = current[segment];
62
+ }
63
+ return isPlainObject(current) ? current : void 0;
58
64
  };
59
65
  const walk = (node, path, seen) => {
60
66
  if (!isPlainObject(node)) return node;
@@ -72,44 +78,60 @@ function dereference(root, warnings) {
72
78
  const merged = { ...clone(target), ...rest };
73
79
  return walk(merged, path, /* @__PURE__ */ new Set([...seen, ref]));
74
80
  }
75
- return mapChildren(node, path, (child, childPath) => walk(child, childPath, seen));
81
+ const { $defs: _defs, definitions: _definitions, ...withoutDefinitions } = node;
82
+ void _defs;
83
+ void _definitions;
84
+ return mapChildren(withoutDefinitions, path, (child, childPath) => walk(child, childPath, seen));
76
85
  };
77
86
  const out = walk(clone(root), "#", /* @__PURE__ */ new Set());
78
87
  delete out.$defs;
79
88
  delete out.definitions;
80
89
  return out;
81
90
  }
91
+ function decodePointerSegment(segment) {
92
+ try {
93
+ return decodeURIComponent(segment).replace(/~1/g, "/").replace(/~0/g, "~");
94
+ } catch {
95
+ return segment.replace(/~1/g, "/").replace(/~0/g, "~");
96
+ }
97
+ }
98
+ function encodePointerSegment(segment) {
99
+ return segment.replace(/~/g, "~0").replace(/\//g, "~1");
100
+ }
101
+ function pointerPath(path, ...segments) {
102
+ return `${path}/${segments.map((segment) => encodePointerSegment(String(segment))).join("/")}`;
103
+ }
82
104
  function mapChildren(node, path, fn) {
83
105
  const out = { ...node };
84
106
  if (isPlainObject(out.properties)) {
85
107
  const props = {};
86
108
  for (const [k, v] of Object.entries(out.properties)) {
87
- props[k] = fn(v, `${path}/properties/${k}`);
109
+ props[k] = fn(v, pointerPath(path, "properties", k));
88
110
  }
89
111
  out.properties = props;
90
112
  }
91
113
  if (Array.isArray(out.items)) {
92
- out.items = out.items.map((it, i) => fn(it, `${path}/items/${i}`));
114
+ out.items = out.items.map((it, i) => fn(it, pointerPath(path, "items", i)));
93
115
  } else if (isPlainObject(out.items)) {
94
- out.items = fn(out.items, `${path}/items`);
116
+ out.items = fn(out.items, pointerPath(path, "items"));
95
117
  }
96
118
  if (isPlainObject(out.additionalProperties)) {
97
- out.additionalProperties = fn(out.additionalProperties, `${path}/additionalProperties`);
119
+ out.additionalProperties = fn(out.additionalProperties, pointerPath(path, "additionalProperties"));
98
120
  }
99
121
  for (const key of ["anyOf", "oneOf", "allOf"]) {
100
122
  const arr = out[key];
101
123
  if (Array.isArray(arr)) {
102
- out[key] = arr.map((b, i) => fn(b, `${path}/${key}/${i}`));
124
+ out[key] = arr.map((b, i) => fn(b, pointerPath(path, key, i)));
103
125
  }
104
126
  }
105
- if (isPlainObject(out.not)) out.not = fn(out.not, `${path}/not`);
127
+ if (isPlainObject(out.not)) out.not = fn(out.not, pointerPath(path, "not"));
106
128
  for (const key of ["if", "then", "else"]) {
107
- if (isPlainObject(out[key])) out[key] = fn(out[key], `${path}/${key}`);
129
+ if (isPlainObject(out[key])) out[key] = fn(out[key], pointerPath(path, key));
108
130
  }
109
131
  if (isPlainObject(out.patternProperties)) {
110
132
  const pp = {};
111
133
  for (const [k, v] of Object.entries(out.patternProperties)) {
112
- pp[k] = fn(v, `${path}/patternProperties/${k}`);
134
+ pp[k] = fn(v, pointerPath(path, "patternProperties", k));
113
135
  }
114
136
  out.patternProperties = pp;
115
137
  }
@@ -118,7 +140,7 @@ function mapChildren(node, path, fn) {
118
140
  if (isPlainObject(map)) {
119
141
  const next = {};
120
142
  for (const [k, v] of Object.entries(map)) {
121
- next[k] = fn(v, `${path}/${key}/${k}`);
143
+ next[k] = fn(v, pointerPath(path, key, k));
122
144
  }
123
145
  out[key] = next;
124
146
  }
@@ -204,7 +226,7 @@ function toOpenAIStrict(input) {
204
226
  if (!originalRequired.has(key)) {
205
227
  child = makeNullable(child);
206
228
  warnings.add(
207
- `${path}/properties/${key}`,
229
+ pointerPath(path, "properties", key),
208
230
  "forced-required",
209
231
  `Optional property '${key}' was made required and nullable for OpenAI strict mode.`
210
232
  );