tool-schema 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/LICENSE +21 -0
- package/README.md +149 -0
- package/dist/chunk-OI5FY7ML.js +568 -0
- package/dist/chunk-OI5FY7ML.js.map +1 -0
- package/dist/cli.cjs +687 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +130 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +596 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +125 -0
- package/dist/index.d.ts +125 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/package.json +78 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
|
|
5
|
+
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-06-01
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Initial release.
|
|
12
|
+
- `toToolSchema(schema, { target })` converts any JSON Schema into a provider
|
|
13
|
+
valid schema for `openai`, `openai-strict`, `anthropic`, `gemini`,
|
|
14
|
+
`gemini-jsonschema` and `mcp`.
|
|
15
|
+
- `toTool(def, { target })` builds a full provider shaped tool / function
|
|
16
|
+
declaration (`function`, `input_schema`, `parameters`, `inputSchema`),
|
|
17
|
+
including `strict` and MCP `annotations`.
|
|
18
|
+
- `lintToolSchema(schema, { target })` reports what would change without applying.
|
|
19
|
+
- `tool-schema` CLI: convert a schema file or stdin for any target.
|
|
20
|
+
- Zero runtime dependencies.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sebastian Legarraga
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# tool-schema
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/tool-schema)
|
|
4
|
+
[](https://github.com/slegarraga/tool-schema/actions/workflows/ci.yml)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[](./package.json)
|
|
7
|
+
|
|
8
|
+
One JSON Schema in, a valid tool / function calling schema out, for **OpenAI**, **Anthropic**, **Gemini** and **MCP**. Zero dependencies.
|
|
9
|
+
|
|
10
|
+
Every provider accepts a slightly different subset of JSON Schema for tool calling, and the differences are exactly the kind that fail at runtime with a `400 invalid schema`:
|
|
11
|
+
|
|
12
|
+
- **OpenAI** strict mode demands `additionalProperties: false` on every object and every property listed in `required`, and rejects `allOf`, `not` and `if/then/else`.
|
|
13
|
+
- **Gemini** does not understand `$ref`, `oneOf`, `allOf` or `additionalProperties`, and expresses nullability as `nullable: true` instead of `type: ["string", "null"]`.
|
|
14
|
+
- **Anthropic** and **MCP** are permissive but still require an object at the root.
|
|
15
|
+
|
|
16
|
+
`tool-schema` knows these rules so you do not have to. Write your schema once, target any provider.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm install tool-schema
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requires Node 18+. Ships ESM and CommonJS with full TypeScript types.
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { toTool } from 'tool-schema';
|
|
30
|
+
|
|
31
|
+
const schema = {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
city: { type: 'string', description: 'City name' },
|
|
35
|
+
units: { type: 'string', enum: ['c', 'f'] }, // optional
|
|
36
|
+
},
|
|
37
|
+
required: ['city'],
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// OpenAI (Chat Completions) with Structured Outputs
|
|
41
|
+
const { tool } = toTool({ name: 'get_weather', description: 'Get the weather', schema }, { target: 'openai-strict' });
|
|
42
|
+
// tool -> { type: 'function', function: { name, description, parameters, strict: true } }
|
|
43
|
+
// `units` becomes required and nullable, additionalProperties:false is added everywhere.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The same definition, four providers:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
toTool(def, { target: 'openai' }); // { type: 'function', function: { ... } }
|
|
50
|
+
toTool(def, { target: 'anthropic' }); // { name, description, input_schema }
|
|
51
|
+
toTool(def, { target: 'gemini' }); // { name, description, parameters }
|
|
52
|
+
toTool(def, { target: 'mcp' }); // { name, description, inputSchema, annotations? }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Convert just the schema
|
|
56
|
+
|
|
57
|
+
When you already build the tool envelope yourself and only need a provider valid
|
|
58
|
+
parameter schema, use `toToolSchema`:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { toToolSchema } from 'tool-schema';
|
|
62
|
+
|
|
63
|
+
const { schema, warnings, lossy } = toToolSchema(mySchema, { target: 'gemini' });
|
|
64
|
+
|
|
65
|
+
// schema -> the Gemini valid schema ($ref inlined, oneOf stripped, nullable applied)
|
|
66
|
+
// warnings -> every adjustment made, with a JSON Pointer path and a stable code
|
|
67
|
+
// lossy -> true if any information had to be dropped
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Works with Zod
|
|
71
|
+
|
|
72
|
+
Zod 4 emits JSON Schema natively, so there is nothing extra to install:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { z } from 'zod';
|
|
76
|
+
import { toTool } from 'tool-schema';
|
|
77
|
+
|
|
78
|
+
const schema = z.toJSONSchema(z.object({ city: z.string(), units: z.enum(['c', 'f']).optional() }));
|
|
79
|
+
|
|
80
|
+
const { tool } = toTool({ name: 'get_weather', schema }, { target: 'openai-strict' });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Lint without transforming
|
|
84
|
+
|
|
85
|
+
Want to know whether a schema is already valid for a provider, for example in a
|
|
86
|
+
test or a CI check?
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { lintToolSchema } from 'tool-schema';
|
|
90
|
+
|
|
91
|
+
const { ok, issues } = lintToolSchema(mySchema, { target: 'openai-strict' });
|
|
92
|
+
if (!ok) {
|
|
93
|
+
for (const issue of issues) console.warn(`${issue.path}: ${issue.message}`);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Targets
|
|
98
|
+
|
|
99
|
+
| Target | Output key | What it does |
|
|
100
|
+
| ------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
101
|
+
| `openai` | `function.parameters` | Ensures an object root. Otherwise pass through. |
|
|
102
|
+
| `openai-strict` | `function.parameters` | Structured Outputs: `additionalProperties:false`, all required, optionals nullable, unsupported keywords stripped, `allOf` merged. |
|
|
103
|
+
| `anthropic` | `input_schema` | Permissive. Ensures an object root. |
|
|
104
|
+
| `gemini` | `parameters` | OpenAPI subset: inlines `$ref`, strips `oneOf`/`allOf`/`additionalProperties`, `nullable: true`, string enums. |
|
|
105
|
+
| `gemini-jsonschema` | `parametersJsonSchema` | Gemini's richer route. Keeps `$ref` and more. |
|
|
106
|
+
| `mcp` | `inputSchema` | Most permissive. Ensures an object root. Supports `annotations`. |
|
|
107
|
+
|
|
108
|
+
## Provider rules at a glance
|
|
109
|
+
|
|
110
|
+
| Constraint | openai | openai-strict | anthropic | gemini | mcp |
|
|
111
|
+
| ------------------------------------ | -------------- | ------------------------ | -------------- | ---------------- | ---- |
|
|
112
|
+
| Root must be object | yes | yes | yes | yes | yes |
|
|
113
|
+
| `additionalProperties: false` forced | no | yes (every object) | no | removed | no |
|
|
114
|
+
| All properties required | no | yes (optionals nullable) | no | no | no |
|
|
115
|
+
| `$ref` / `$defs` | keep | keep | keep | inlined | keep |
|
|
116
|
+
| `oneOf` / `allOf` / `not` | keep | stripped / merged | keep | stripped | keep |
|
|
117
|
+
| Nullability | `["t","null"]` | `["t","null"]` | `["t","null"]` | `nullable: true` | any |
|
|
118
|
+
|
|
119
|
+
## CLI
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
# Convert a schema file for a target
|
|
123
|
+
npx tool-schema schema.json --target openai-strict
|
|
124
|
+
|
|
125
|
+
# Pipe a schema and wrap it as a full tool definition
|
|
126
|
+
cat schema.json | npx tool-schema --target gemini --tool get_weather --description "Get the weather"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The converted JSON goes to stdout. Warnings go to stderr, so the output is always
|
|
130
|
+
safe to pipe into another tool. Run `npx tool-schema --help` for all options.
|
|
131
|
+
|
|
132
|
+
## Warnings
|
|
133
|
+
|
|
134
|
+
Every conversion returns a list of `warnings`. Each one has a `path` (JSON Pointer
|
|
135
|
+
to the node), a stable `code`, and a human readable `message`. Codes include
|
|
136
|
+
`stripped-keyword`, `forced-required`, `forced-additional-properties`,
|
|
137
|
+
`inlined-ref`, `collapsed-nullable`, `enum-coerced`, `merged-allof`,
|
|
138
|
+
`unsupported-format`, `limit-exceeded` and `invalid-name`. `lossy` is `true`
|
|
139
|
+
whenever a keyword or constraint had to be dropped.
|
|
140
|
+
|
|
141
|
+
## Why zero dependencies
|
|
142
|
+
|
|
143
|
+
This library is meant to sit deep in agent and tool pipelines. No transitive
|
|
144
|
+
dependencies means no supply chain surface, no version conflicts, and a tiny
|
|
145
|
+
install. It uses only the JSON Schema you pass in and the platform `structuredClone`.
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT (c) Sebastian Legarraga. See [LICENSE](./LICENSE).
|