ai-tool-adapter 1.0.0 → 1.0.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/README.md +444 -0
- package/dist/adapters/anthropic.d.ts +36 -0
- package/dist/adapters/anthropic.js +57 -0
- package/dist/adapters/anthropic.test.d.ts +4 -0
- package/dist/adapters/anthropic.test.js +173 -0
- package/dist/adapters/gemini.d.ts +36 -0
- package/dist/adapters/gemini.js +63 -0
- package/dist/adapters/gemini.test.d.ts +4 -0
- package/dist/adapters/gemini.test.js +189 -0
- package/dist/adapters/mistral.d.ts +40 -0
- package/dist/adapters/mistral.js +60 -0
- package/dist/adapters/mistral.test.d.ts +4 -0
- package/dist/adapters/mistral.test.js +176 -0
- package/dist/adapters/openai.d.ts +40 -0
- package/dist/adapters/openai.js +60 -0
- package/dist/adapters/openai.test.d.ts +4 -0
- package/dist/adapters/openai.test.js +176 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.js +105 -0
- package/dist/index.test.d.ts +4 -0
- package/dist/index.test.js +215 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.js +8 -0
- package/package.json +5 -3
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for OpenAI adapter
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const openai_1 = require("./openai");
|
|
8
|
+
(0, vitest_1.describe)('openaiAdapter', () => {
|
|
9
|
+
(0, vitest_1.it)('should convert a basic tool with required params', () => {
|
|
10
|
+
const tool = {
|
|
11
|
+
name: 'get_weather',
|
|
12
|
+
description: 'Get current weather for a location',
|
|
13
|
+
params: {
|
|
14
|
+
location: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'City name',
|
|
17
|
+
required: true,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
const result = (0, openai_1.openaiAdapter)(tool);
|
|
22
|
+
(0, vitest_1.expect)(result).toEqual({
|
|
23
|
+
type: 'function',
|
|
24
|
+
function: {
|
|
25
|
+
name: 'get_weather',
|
|
26
|
+
description: 'Get current weather for a location',
|
|
27
|
+
parameters: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
location: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'City name',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
required: ['location'],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.it)('should handle enum values', () => {
|
|
41
|
+
const tool = {
|
|
42
|
+
name: 'set_temperature',
|
|
43
|
+
description: 'Set temperature unit',
|
|
44
|
+
params: {
|
|
45
|
+
unit: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
enum: ['celsius', 'fahrenheit', 'kelvin'],
|
|
48
|
+
required: true,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
const result = (0, openai_1.openaiAdapter)(tool);
|
|
53
|
+
(0, vitest_1.expect)(result.function.parameters.properties.unit).toEqual({
|
|
54
|
+
type: 'string',
|
|
55
|
+
enum: ['celsius', 'fahrenheit', 'kelvin'],
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
(0, vitest_1.it)('should handle array types with items', () => {
|
|
59
|
+
const tool = {
|
|
60
|
+
name: 'process_items',
|
|
61
|
+
description: 'Process a list of items',
|
|
62
|
+
params: {
|
|
63
|
+
items: {
|
|
64
|
+
type: 'array',
|
|
65
|
+
description: 'List of items',
|
|
66
|
+
items: { type: 'string' },
|
|
67
|
+
required: true,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
const result = (0, openai_1.openaiAdapter)(tool);
|
|
72
|
+
(0, vitest_1.expect)(result.function.parameters.properties.items).toEqual({
|
|
73
|
+
type: 'array',
|
|
74
|
+
description: 'List of items',
|
|
75
|
+
items: { type: 'string' },
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
(0, vitest_1.it)('should handle default values', () => {
|
|
79
|
+
const tool = {
|
|
80
|
+
name: 'paginate',
|
|
81
|
+
description: 'Get paginated results',
|
|
82
|
+
params: {
|
|
83
|
+
page: {
|
|
84
|
+
type: 'number',
|
|
85
|
+
default: 1,
|
|
86
|
+
},
|
|
87
|
+
limit: {
|
|
88
|
+
type: 'number',
|
|
89
|
+
default: 10,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
const result = (0, openai_1.openaiAdapter)(tool);
|
|
94
|
+
(0, vitest_1.expect)(result.function.parameters.properties.page).toEqual({
|
|
95
|
+
type: 'number',
|
|
96
|
+
default: 1,
|
|
97
|
+
});
|
|
98
|
+
(0, vitest_1.expect)(result.function.parameters.properties.limit).toEqual({
|
|
99
|
+
type: 'number',
|
|
100
|
+
default: 10,
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
(0, vitest_1.it)('should handle mixed required and optional params', () => {
|
|
104
|
+
const tool = {
|
|
105
|
+
name: 'search',
|
|
106
|
+
description: 'Search for items',
|
|
107
|
+
params: {
|
|
108
|
+
query: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
description: 'Search query',
|
|
111
|
+
required: true,
|
|
112
|
+
},
|
|
113
|
+
limit: {
|
|
114
|
+
type: 'number',
|
|
115
|
+
description: 'Result limit',
|
|
116
|
+
default: 10,
|
|
117
|
+
},
|
|
118
|
+
exact: {
|
|
119
|
+
type: 'boolean',
|
|
120
|
+
description: 'Exact match',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
const result = (0, openai_1.openaiAdapter)(tool);
|
|
125
|
+
(0, vitest_1.expect)(result.function.parameters.required).toEqual(['query']);
|
|
126
|
+
(0, vitest_1.expect)(result.function.parameters.properties).toHaveProperty('query');
|
|
127
|
+
(0, vitest_1.expect)(result.function.parameters.properties).toHaveProperty('limit');
|
|
128
|
+
(0, vitest_1.expect)(result.function.parameters.properties).toHaveProperty('exact');
|
|
129
|
+
});
|
|
130
|
+
(0, vitest_1.it)('should handle empty params', () => {
|
|
131
|
+
const tool = {
|
|
132
|
+
name: 'get_status',
|
|
133
|
+
description: 'Get current status',
|
|
134
|
+
params: {},
|
|
135
|
+
};
|
|
136
|
+
const result = (0, openai_1.openaiAdapter)(tool);
|
|
137
|
+
(0, vitest_1.expect)(result.function.parameters).toEqual({
|
|
138
|
+
type: 'object',
|
|
139
|
+
properties: {},
|
|
140
|
+
required: [],
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
(0, vitest_1.it)('should use lowercase type names', () => {
|
|
144
|
+
const tool = {
|
|
145
|
+
name: 'test_types',
|
|
146
|
+
description: 'Test all types',
|
|
147
|
+
params: {
|
|
148
|
+
str: { type: 'string' },
|
|
149
|
+
num: { type: 'number' },
|
|
150
|
+
bool: { type: 'boolean' },
|
|
151
|
+
arr: { type: 'array', items: { type: 'string' } },
|
|
152
|
+
obj: { type: 'object' },
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
const result = (0, openai_1.openaiAdapter)(tool);
|
|
156
|
+
const props = result.function.parameters.properties;
|
|
157
|
+
(0, vitest_1.expect)(props.str.type).toBe('string');
|
|
158
|
+
(0, vitest_1.expect)(props.num.type).toBe('number');
|
|
159
|
+
(0, vitest_1.expect)(props.bool.type).toBe('boolean');
|
|
160
|
+
(0, vitest_1.expect)(props.arr.type).toBe('array');
|
|
161
|
+
(0, vitest_1.expect)(props.obj.type).toBe('object');
|
|
162
|
+
});
|
|
163
|
+
(0, vitest_1.it)('should wrap in function object', () => {
|
|
164
|
+
const tool = {
|
|
165
|
+
name: 'test',
|
|
166
|
+
description: 'Test tool',
|
|
167
|
+
params: {},
|
|
168
|
+
};
|
|
169
|
+
const result = (0, openai_1.openaiAdapter)(tool);
|
|
170
|
+
(0, vitest_1.expect)(result).toHaveProperty('type', 'function');
|
|
171
|
+
(0, vitest_1.expect)(result).toHaveProperty('function');
|
|
172
|
+
(0, vitest_1.expect)(result.function).toHaveProperty('name');
|
|
173
|
+
(0, vitest_1.expect)(result.function).toHaveProperty('description');
|
|
174
|
+
(0, vitest_1.expect)(result.function).toHaveProperty('parameters');
|
|
175
|
+
});
|
|
176
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal AI Tool Schema Adapter
|
|
3
|
+
*
|
|
4
|
+
* Write tool definitions once, convert to any LLM provider format.
|
|
5
|
+
* Eliminates duplication and provider lock-in.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { adapt } from 'ai-tool-adapter';
|
|
10
|
+
*
|
|
11
|
+
* const tool = {
|
|
12
|
+
* name: 'get_weather',
|
|
13
|
+
* description: 'Get current weather for a location',
|
|
14
|
+
* params: {
|
|
15
|
+
* location: { type: 'string', required: true },
|
|
16
|
+
* units: { type: 'string', enum: ['celsius', 'fahrenheit'] }
|
|
17
|
+
* }
|
|
18
|
+
* };
|
|
19
|
+
*
|
|
20
|
+
* const openaiTool = adapt(tool, 'openai');
|
|
21
|
+
* const anthropicTool = adapt(tool, 'anthropic');
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import { UniversalTool, Provider } from './types';
|
|
25
|
+
/**
|
|
26
|
+
* Convert a universal tool definition to a specific provider's format
|
|
27
|
+
*
|
|
28
|
+
* @param tool - Universal tool definition
|
|
29
|
+
* @param provider - Target AI provider
|
|
30
|
+
* @returns Provider-specific tool format
|
|
31
|
+
* @throws {Error} If provider is not supported
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const tool = {
|
|
36
|
+
* name: 'calculate',
|
|
37
|
+
* description: 'Perform arithmetic calculation',
|
|
38
|
+
* params: {
|
|
39
|
+
* operation: { type: 'string', required: true, enum: ['add', 'subtract'] },
|
|
40
|
+
* a: { type: 'number', required: true },
|
|
41
|
+
* b: { type: 'number', required: true }
|
|
42
|
+
* }
|
|
43
|
+
* };
|
|
44
|
+
*
|
|
45
|
+
* const openaiTool = adapt(tool, 'openai');
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function adapt(tool: UniversalTool, provider: Provider): unknown;
|
|
49
|
+
/**
|
|
50
|
+
* Convert multiple universal tool definitions to a specific provider's format
|
|
51
|
+
*
|
|
52
|
+
* @param tools - Array of universal tool definitions
|
|
53
|
+
* @param provider - Target AI provider
|
|
54
|
+
* @returns Array of provider-specific tool formats
|
|
55
|
+
* @throws {Error} If provider is not supported
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const tools = [
|
|
60
|
+
* { name: 'get_weather', description: 'Get weather', params: {...} },
|
|
61
|
+
* { name: 'get_time', description: 'Get time', params: {...} }
|
|
62
|
+
* ];
|
|
63
|
+
*
|
|
64
|
+
* const openaiTools = adaptAll(tools, 'openai');
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function adaptAll(tools: UniversalTool[], provider: Provider): unknown[];
|
|
68
|
+
/**
|
|
69
|
+
* Get list of all supported AI providers
|
|
70
|
+
*
|
|
71
|
+
* @returns Array of supported provider names
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const providers = getProviders();
|
|
76
|
+
* console.log(providers); // ['openai', 'anthropic', 'gemini', 'mistral']
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function getProviders(): Provider[];
|
|
80
|
+
/**
|
|
81
|
+
* Export types for TypeScript consumers
|
|
82
|
+
*/
|
|
83
|
+
export type { UniversalTool, ToolParam, Provider, ParamType } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1 +1,106 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Universal AI Tool Schema Adapter
|
|
4
|
+
*
|
|
5
|
+
* Write tool definitions once, convert to any LLM provider format.
|
|
6
|
+
* Eliminates duplication and provider lock-in.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { adapt } from 'ai-tool-adapter';
|
|
11
|
+
*
|
|
12
|
+
* const tool = {
|
|
13
|
+
* name: 'get_weather',
|
|
14
|
+
* description: 'Get current weather for a location',
|
|
15
|
+
* params: {
|
|
16
|
+
* location: { type: 'string', required: true },
|
|
17
|
+
* units: { type: 'string', enum: ['celsius', 'fahrenheit'] }
|
|
18
|
+
* }
|
|
19
|
+
* };
|
|
20
|
+
*
|
|
21
|
+
* const openaiTool = adapt(tool, 'openai');
|
|
22
|
+
* const anthropicTool = adapt(tool, 'anthropic');
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.adapt = adapt;
|
|
27
|
+
exports.adaptAll = adaptAll;
|
|
28
|
+
exports.getProviders = getProviders;
|
|
29
|
+
const openai_1 = require("./adapters/openai");
|
|
30
|
+
const anthropic_1 = require("./adapters/anthropic");
|
|
31
|
+
const gemini_1 = require("./adapters/gemini");
|
|
32
|
+
const mistral_1 = require("./adapters/mistral");
|
|
33
|
+
/**
|
|
34
|
+
* Adapter registry mapping provider names to their adapter functions
|
|
35
|
+
*/
|
|
36
|
+
const adapters = {
|
|
37
|
+
openai: openai_1.openaiAdapter,
|
|
38
|
+
anthropic: anthropic_1.anthropicAdapter,
|
|
39
|
+
gemini: gemini_1.geminiAdapter,
|
|
40
|
+
mistral: mistral_1.mistralAdapter,
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Convert a universal tool definition to a specific provider's format
|
|
44
|
+
*
|
|
45
|
+
* @param tool - Universal tool definition
|
|
46
|
+
* @param provider - Target AI provider
|
|
47
|
+
* @returns Provider-specific tool format
|
|
48
|
+
* @throws {Error} If provider is not supported
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const tool = {
|
|
53
|
+
* name: 'calculate',
|
|
54
|
+
* description: 'Perform arithmetic calculation',
|
|
55
|
+
* params: {
|
|
56
|
+
* operation: { type: 'string', required: true, enum: ['add', 'subtract'] },
|
|
57
|
+
* a: { type: 'number', required: true },
|
|
58
|
+
* b: { type: 'number', required: true }
|
|
59
|
+
* }
|
|
60
|
+
* };
|
|
61
|
+
*
|
|
62
|
+
* const openaiTool = adapt(tool, 'openai');
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
function adapt(tool, provider) {
|
|
66
|
+
const adapter = adapters[provider];
|
|
67
|
+
if (!adapter) {
|
|
68
|
+
throw new Error(`Unknown provider: ${provider}. Supported providers: ${getProviders().join(', ')}`);
|
|
69
|
+
}
|
|
70
|
+
return adapter(tool);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Convert multiple universal tool definitions to a specific provider's format
|
|
74
|
+
*
|
|
75
|
+
* @param tools - Array of universal tool definitions
|
|
76
|
+
* @param provider - Target AI provider
|
|
77
|
+
* @returns Array of provider-specific tool formats
|
|
78
|
+
* @throws {Error} If provider is not supported
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const tools = [
|
|
83
|
+
* { name: 'get_weather', description: 'Get weather', params: {...} },
|
|
84
|
+
* { name: 'get_time', description: 'Get time', params: {...} }
|
|
85
|
+
* ];
|
|
86
|
+
*
|
|
87
|
+
* const openaiTools = adaptAll(tools, 'openai');
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
function adaptAll(tools, provider) {
|
|
91
|
+
return tools.map((tool) => adapt(tool, provider));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get list of all supported AI providers
|
|
95
|
+
*
|
|
96
|
+
* @returns Array of supported provider names
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const providers = getProviders();
|
|
101
|
+
* console.log(providers); // ['openai', 'anthropic', 'gemini', 'mistral']
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
function getProviders() {
|
|
105
|
+
return Object.keys(adapters);
|
|
106
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Integration tests for the public API
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const index_1 = require("./index");
|
|
8
|
+
(0, vitest_1.describe)('adapt', () => {
|
|
9
|
+
const sampleTool = {
|
|
10
|
+
name: 'get_weather',
|
|
11
|
+
description: 'Get current weather for a location',
|
|
12
|
+
params: {
|
|
13
|
+
location: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'City name',
|
|
16
|
+
required: true,
|
|
17
|
+
},
|
|
18
|
+
units: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
enum: ['celsius', 'fahrenheit'],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
(0, vitest_1.it)('should adapt tool to OpenAI format', () => {
|
|
25
|
+
const result = (0, index_1.adapt)(sampleTool, 'openai');
|
|
26
|
+
(0, vitest_1.expect)(result).toHaveProperty('type', 'function');
|
|
27
|
+
(0, vitest_1.expect)(result).toHaveProperty('function');
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.it)('should adapt tool to Anthropic format', () => {
|
|
30
|
+
const result = (0, index_1.adapt)(sampleTool, 'anthropic');
|
|
31
|
+
(0, vitest_1.expect)(result).toHaveProperty('name', 'get_weather');
|
|
32
|
+
(0, vitest_1.expect)(result).toHaveProperty('input_schema');
|
|
33
|
+
(0, vitest_1.expect)(result).not.toHaveProperty('type');
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.it)('should adapt tool to Gemini format', () => {
|
|
36
|
+
const result = (0, index_1.adapt)(sampleTool, 'gemini');
|
|
37
|
+
(0, vitest_1.expect)(result).toHaveProperty('name', 'get_weather');
|
|
38
|
+
(0, vitest_1.expect)(result).toHaveProperty('parameters');
|
|
39
|
+
(0, vitest_1.expect)(result).not.toHaveProperty('type');
|
|
40
|
+
});
|
|
41
|
+
(0, vitest_1.it)('should adapt tool to Mistral format', () => {
|
|
42
|
+
const result = (0, index_1.adapt)(sampleTool, 'mistral');
|
|
43
|
+
(0, vitest_1.expect)(result).toHaveProperty('type', 'function');
|
|
44
|
+
(0, vitest_1.expect)(result).toHaveProperty('function');
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.it)('should throw error for unknown provider', () => {
|
|
47
|
+
(0, vitest_1.expect)(() => {
|
|
48
|
+
(0, index_1.adapt)(sampleTool, 'unknown');
|
|
49
|
+
}).toThrow('Unknown provider: unknown');
|
|
50
|
+
});
|
|
51
|
+
(0, vitest_1.it)('should include list of supported providers in error message', () => {
|
|
52
|
+
(0, vitest_1.expect)(() => {
|
|
53
|
+
(0, index_1.adapt)(sampleTool, 'invalid');
|
|
54
|
+
}).toThrow(/openai.*anthropic.*gemini.*mistral/);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
(0, vitest_1.describe)('adaptAll', () => {
|
|
58
|
+
const tools = [
|
|
59
|
+
{
|
|
60
|
+
name: 'get_weather',
|
|
61
|
+
description: 'Get weather',
|
|
62
|
+
params: {
|
|
63
|
+
location: { type: 'string', required: true },
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'get_time',
|
|
68
|
+
description: 'Get current time',
|
|
69
|
+
params: {
|
|
70
|
+
timezone: { type: 'string' },
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'calculate',
|
|
75
|
+
description: 'Perform calculation',
|
|
76
|
+
params: {
|
|
77
|
+
operation: { type: 'string', enum: ['add', 'subtract'], required: true },
|
|
78
|
+
a: { type: 'number', required: true },
|
|
79
|
+
b: { type: 'number', required: true },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
(0, vitest_1.it)('should adapt multiple tools to OpenAI format', () => {
|
|
84
|
+
const results = (0, index_1.adaptAll)(tools, 'openai');
|
|
85
|
+
(0, vitest_1.expect)(results).toHaveLength(3);
|
|
86
|
+
results.forEach((result) => {
|
|
87
|
+
(0, vitest_1.expect)(result).toHaveProperty('type', 'function');
|
|
88
|
+
(0, vitest_1.expect)(result).toHaveProperty('function');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
(0, vitest_1.it)('should adapt multiple tools to Anthropic format', () => {
|
|
92
|
+
const results = (0, index_1.adaptAll)(tools, 'anthropic');
|
|
93
|
+
(0, vitest_1.expect)(results).toHaveLength(3);
|
|
94
|
+
results.forEach((result) => {
|
|
95
|
+
(0, vitest_1.expect)(result).toHaveProperty('name');
|
|
96
|
+
(0, vitest_1.expect)(result).toHaveProperty('input_schema');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
(0, vitest_1.it)('should adapt multiple tools to Gemini format', () => {
|
|
100
|
+
const results = (0, index_1.adaptAll)(tools, 'gemini');
|
|
101
|
+
(0, vitest_1.expect)(results).toHaveLength(3);
|
|
102
|
+
results.forEach((result) => {
|
|
103
|
+
(0, vitest_1.expect)(result).toHaveProperty('name');
|
|
104
|
+
(0, vitest_1.expect)(result).toHaveProperty('parameters');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
(0, vitest_1.it)('should adapt multiple tools to Mistral format', () => {
|
|
108
|
+
const results = (0, index_1.adaptAll)(tools, 'mistral');
|
|
109
|
+
(0, vitest_1.expect)(results).toHaveLength(3);
|
|
110
|
+
results.forEach((result) => {
|
|
111
|
+
(0, vitest_1.expect)(result).toHaveProperty('type', 'function');
|
|
112
|
+
(0, vitest_1.expect)(result).toHaveProperty('function');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
(0, vitest_1.it)('should handle empty array', () => {
|
|
116
|
+
const results = (0, index_1.adaptAll)([], 'openai');
|
|
117
|
+
(0, vitest_1.expect)(results).toEqual([]);
|
|
118
|
+
});
|
|
119
|
+
(0, vitest_1.it)('should throw error for unknown provider', () => {
|
|
120
|
+
(0, vitest_1.expect)(() => {
|
|
121
|
+
(0, index_1.adaptAll)(tools, 'invalid');
|
|
122
|
+
}).toThrow('Unknown provider');
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
(0, vitest_1.describe)('getProviders', () => {
|
|
126
|
+
(0, vitest_1.it)('should return array of all supported providers', () => {
|
|
127
|
+
const providers = (0, index_1.getProviders)();
|
|
128
|
+
(0, vitest_1.expect)(providers).toBeInstanceOf(Array);
|
|
129
|
+
(0, vitest_1.expect)(providers).toHaveLength(4);
|
|
130
|
+
});
|
|
131
|
+
(0, vitest_1.it)('should include all four providers', () => {
|
|
132
|
+
const providers = (0, index_1.getProviders)();
|
|
133
|
+
(0, vitest_1.expect)(providers).toContain('openai');
|
|
134
|
+
(0, vitest_1.expect)(providers).toContain('anthropic');
|
|
135
|
+
(0, vitest_1.expect)(providers).toContain('gemini');
|
|
136
|
+
(0, vitest_1.expect)(providers).toContain('mistral');
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
(0, vitest_1.describe)('Cross-provider consistency', () => {
|
|
140
|
+
const tool = {
|
|
141
|
+
name: 'test_tool',
|
|
142
|
+
description: 'A test tool for validation',
|
|
143
|
+
params: {
|
|
144
|
+
required_param: {
|
|
145
|
+
type: 'string',
|
|
146
|
+
description: 'A required parameter',
|
|
147
|
+
required: true,
|
|
148
|
+
},
|
|
149
|
+
optional_param: {
|
|
150
|
+
type: 'number',
|
|
151
|
+
description: 'An optional parameter',
|
|
152
|
+
default: 42,
|
|
153
|
+
},
|
|
154
|
+
enum_param: {
|
|
155
|
+
type: 'string',
|
|
156
|
+
enum: ['option1', 'option2', 'option3'],
|
|
157
|
+
},
|
|
158
|
+
array_param: {
|
|
159
|
+
type: 'array',
|
|
160
|
+
items: { type: 'string' },
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
(0, vitest_1.it)('should preserve tool name across all providers', () => {
|
|
165
|
+
const openai = (0, index_1.adapt)(tool, 'openai');
|
|
166
|
+
const anthropic = (0, index_1.adapt)(tool, 'anthropic');
|
|
167
|
+
const gemini = (0, index_1.adapt)(tool, 'gemini');
|
|
168
|
+
const mistral = (0, index_1.adapt)(tool, 'mistral');
|
|
169
|
+
(0, vitest_1.expect)(openai.function.name).toBe('test_tool');
|
|
170
|
+
(0, vitest_1.expect)(anthropic.name).toBe('test_tool');
|
|
171
|
+
(0, vitest_1.expect)(gemini.name).toBe('test_tool');
|
|
172
|
+
(0, vitest_1.expect)(mistral.function.name).toBe('test_tool');
|
|
173
|
+
});
|
|
174
|
+
(0, vitest_1.it)('should preserve tool description across all providers', () => {
|
|
175
|
+
const openai = (0, index_1.adapt)(tool, 'openai');
|
|
176
|
+
const anthropic = (0, index_1.adapt)(tool, 'anthropic');
|
|
177
|
+
const gemini = (0, index_1.adapt)(tool, 'gemini');
|
|
178
|
+
const mistral = (0, index_1.adapt)(tool, 'mistral');
|
|
179
|
+
(0, vitest_1.expect)(openai.function.description).toBe('A test tool for validation');
|
|
180
|
+
(0, vitest_1.expect)(anthropic.description).toBe('A test tool for validation');
|
|
181
|
+
(0, vitest_1.expect)(gemini.description).toBe('A test tool for validation');
|
|
182
|
+
(0, vitest_1.expect)(mistral.function.description).toBe('A test tool for validation');
|
|
183
|
+
});
|
|
184
|
+
(0, vitest_1.it)('should preserve required params across all providers', () => {
|
|
185
|
+
const openai = (0, index_1.adapt)(tool, 'openai');
|
|
186
|
+
const anthropic = (0, index_1.adapt)(tool, 'anthropic');
|
|
187
|
+
const gemini = (0, index_1.adapt)(tool, 'gemini');
|
|
188
|
+
const mistral = (0, index_1.adapt)(tool, 'mistral');
|
|
189
|
+
(0, vitest_1.expect)(openai.function.parameters.required).toContain('required_param');
|
|
190
|
+
(0, vitest_1.expect)(anthropic.input_schema.required).toContain('required_param');
|
|
191
|
+
(0, vitest_1.expect)(gemini.parameters.required).toContain('required_param');
|
|
192
|
+
(0, vitest_1.expect)(mistral.function.parameters.required).toContain('required_param');
|
|
193
|
+
});
|
|
194
|
+
(0, vitest_1.it)('should preserve enum values across all providers', () => {
|
|
195
|
+
const openai = (0, index_1.adapt)(tool, 'openai');
|
|
196
|
+
const anthropic = (0, index_1.adapt)(tool, 'anthropic');
|
|
197
|
+
const gemini = (0, index_1.adapt)(tool, 'gemini');
|
|
198
|
+
const mistral = (0, index_1.adapt)(tool, 'mistral');
|
|
199
|
+
const expectedEnum = ['option1', 'option2', 'option3'];
|
|
200
|
+
(0, vitest_1.expect)(openai.function.parameters.properties.enum_param.enum).toEqual(expectedEnum);
|
|
201
|
+
(0, vitest_1.expect)(anthropic.input_schema.properties.enum_param.enum).toEqual(expectedEnum);
|
|
202
|
+
(0, vitest_1.expect)(gemini.parameters.properties.enum_param.enum).toEqual(expectedEnum);
|
|
203
|
+
(0, vitest_1.expect)(mistral.function.parameters.properties.enum_param.enum).toEqual(expectedEnum);
|
|
204
|
+
});
|
|
205
|
+
(0, vitest_1.it)('should preserve default values across all providers', () => {
|
|
206
|
+
const openai = (0, index_1.adapt)(tool, 'openai');
|
|
207
|
+
const anthropic = (0, index_1.adapt)(tool, 'anthropic');
|
|
208
|
+
const gemini = (0, index_1.adapt)(tool, 'gemini');
|
|
209
|
+
const mistral = (0, index_1.adapt)(tool, 'mistral');
|
|
210
|
+
(0, vitest_1.expect)(openai.function.parameters.properties.optional_param.default).toBe(42);
|
|
211
|
+
(0, vitest_1.expect)(anthropic.input_schema.properties.optional_param.default).toBe(42);
|
|
212
|
+
(0, vitest_1.expect)(gemini.parameters.properties.optional_param.default).toBe(42);
|
|
213
|
+
(0, vitest_1.expect)(mistral.function.parameters.properties.optional_param.default).toBe(42);
|
|
214
|
+
});
|
|
215
|
+
});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal AI Tool Schema Adapter - Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* This is the Single Source of Truth for the data contract.
|
|
5
|
+
* All adapters import from here to ensure consistency.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Supported parameter types in the universal schema
|
|
9
|
+
*/
|
|
10
|
+
export type ParamType = 'string' | 'number' | 'boolean' | 'array' | 'object';
|
|
11
|
+
/**
|
|
12
|
+
* Parameter definition in the universal tool schema
|
|
13
|
+
*/
|
|
14
|
+
export interface ToolParam {
|
|
15
|
+
/** The type of this parameter */
|
|
16
|
+
type: ParamType;
|
|
17
|
+
/** Human-readable description of what this parameter does */
|
|
18
|
+
description?: string;
|
|
19
|
+
/** Whether this parameter is required (default: false) */
|
|
20
|
+
required?: boolean;
|
|
21
|
+
/** Default value for this parameter */
|
|
22
|
+
default?: unknown;
|
|
23
|
+
/** Allowed values for this parameter (for enum-like behavior) */
|
|
24
|
+
enum?: string[];
|
|
25
|
+
/** For array types, defines the type of array items */
|
|
26
|
+
items?: {
|
|
27
|
+
type: ParamType;
|
|
28
|
+
};
|
|
29
|
+
/** For object types, defines nested properties */
|
|
30
|
+
properties?: Record<string, ToolParam>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Universal tool definition that can be converted to any provider format
|
|
34
|
+
*
|
|
35
|
+
* This is the core data contract. Changes to this interface require
|
|
36
|
+
* a MAJOR version bump per semantic versioning rules.
|
|
37
|
+
*/
|
|
38
|
+
export interface UniversalTool {
|
|
39
|
+
/** Function/tool name - must be valid identifier */
|
|
40
|
+
name: string;
|
|
41
|
+
/** Human-readable description of what this tool does */
|
|
42
|
+
description: string;
|
|
43
|
+
/** Parameter definitions for this tool */
|
|
44
|
+
params: Record<string, ToolParam>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Supported AI provider platforms
|
|
48
|
+
*
|
|
49
|
+
* Adding new providers requires:
|
|
50
|
+
* 1. Adding the provider name to this union type
|
|
51
|
+
* 2. Creating a new adapter in src/adapters/
|
|
52
|
+
* 3. Registering the adapter in src/index.ts
|
|
53
|
+
* 4. Adding test coverage
|
|
54
|
+
*/
|
|
55
|
+
export type Provider = 'openai' | 'anthropic' | 'gemini' | 'mistral';
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Universal AI Tool Schema Adapter - Type Definitions
|
|
4
|
+
*
|
|
5
|
+
* This is the Single Source of Truth for the data contract.
|
|
6
|
+
* All adapters import from here to ensure consistency.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-tool-adapter",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Universal tool schema adapter for AI providers (OpenAI, Anthropic, Gemini, Mistral)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"prepublishOnly": "npm run build",
|
|
13
|
-
"test": "
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest"
|
|
14
15
|
},
|
|
15
16
|
"keywords": [
|
|
16
17
|
"ai",
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
"license": "ISC",
|
|
28
29
|
"type": "commonjs",
|
|
29
30
|
"devDependencies": {
|
|
30
|
-
"typescript": "^5.0.0"
|
|
31
|
+
"typescript": "^5.0.0",
|
|
32
|
+
"vitest": "4.0.17"
|
|
31
33
|
}
|
|
32
34
|
}
|