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
package/README.md
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
# ai-tool-adapter
|
|
2
|
+
|
|
3
|
+
Universal AI tool schema adapter for function calling across multiple LLM providers.
|
|
4
|
+
|
|
5
|
+
Write your tool definitions once, convert to any provider format instantly. No more duplicating schemas for OpenAI, Anthropic, Google, and Mistral.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Zero dependencies** - Lightweight and secure
|
|
10
|
+
- **Type-safe** - Full TypeScript support with strict typing
|
|
11
|
+
- **Provider-agnostic** - One schema, multiple formats
|
|
12
|
+
- **Pure functions** - Predictable transformations with no side effects
|
|
13
|
+
- **Well-tested** - Comprehensive test coverage across all adapters
|
|
14
|
+
|
|
15
|
+
## Supported Providers
|
|
16
|
+
|
|
17
|
+
- **OpenAI** - GPT-4, GPT-3.5 function calling
|
|
18
|
+
- **Anthropic** - Claude tool use
|
|
19
|
+
- **Google Gemini** - Gemini function calling
|
|
20
|
+
- **Mistral** - Mistral AI function calling
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install ai-tool-adapter
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { adapt } from 'ai-tool-adapter';
|
|
32
|
+
|
|
33
|
+
// Define your tool once using the universal schema
|
|
34
|
+
const weatherTool = {
|
|
35
|
+
name: 'get_weather',
|
|
36
|
+
description: 'Get current weather for a location',
|
|
37
|
+
params: {
|
|
38
|
+
location: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'City name',
|
|
41
|
+
required: true,
|
|
42
|
+
},
|
|
43
|
+
units: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Temperature units',
|
|
46
|
+
enum: ['celsius', 'fahrenheit'],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Convert to any provider format
|
|
52
|
+
const openaiTool = adapt(weatherTool, 'openai');
|
|
53
|
+
const anthropicTool = adapt(weatherTool, 'anthropic');
|
|
54
|
+
const geminiTool = adapt(weatherTool, 'gemini');
|
|
55
|
+
const mistralTool = adapt(weatherTool, 'mistral');
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## API Reference
|
|
59
|
+
|
|
60
|
+
### `adapt(tool, provider)`
|
|
61
|
+
|
|
62
|
+
Convert a single universal tool definition to a specific provider's format.
|
|
63
|
+
|
|
64
|
+
**Parameters:**
|
|
65
|
+
- `tool` (UniversalTool) - Your universal tool definition
|
|
66
|
+
- `provider` (Provider) - Target provider: `'openai'` | `'anthropic'` | `'gemini'` | `'mistral'`
|
|
67
|
+
|
|
68
|
+
**Returns:** Provider-specific tool format
|
|
69
|
+
|
|
70
|
+
**Throws:** Error if provider is not supported
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const tool = {
|
|
74
|
+
name: 'calculate',
|
|
75
|
+
description: 'Perform arithmetic calculation',
|
|
76
|
+
params: {
|
|
77
|
+
operation: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
enum: ['add', 'subtract', 'multiply', 'divide'],
|
|
80
|
+
required: true,
|
|
81
|
+
},
|
|
82
|
+
a: { type: 'number', required: true },
|
|
83
|
+
b: { type: 'number', required: true },
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const openaiTool = adapt(tool, 'openai');
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### `adaptAll(tools, provider)`
|
|
91
|
+
|
|
92
|
+
Convert multiple tools at once.
|
|
93
|
+
|
|
94
|
+
**Parameters:**
|
|
95
|
+
- `tools` (UniversalTool[]) - Array of universal tool definitions
|
|
96
|
+
- `provider` (Provider) - Target provider
|
|
97
|
+
|
|
98
|
+
**Returns:** Array of provider-specific tool formats
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const tools = [weatherTool, calculatorTool, searchTool];
|
|
102
|
+
const openaiTools = adaptAll(tools, 'openai');
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `getProviders()`
|
|
106
|
+
|
|
107
|
+
Get list of all supported providers.
|
|
108
|
+
|
|
109
|
+
**Returns:** Array of provider names
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const providers = getProviders();
|
|
113
|
+
console.log(providers); // ['openai', 'anthropic', 'gemini', 'mistral']
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Universal Tool Schema
|
|
117
|
+
|
|
118
|
+
### Basic Structure
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
interface UniversalTool {
|
|
122
|
+
name: string; // Function name
|
|
123
|
+
description: string; // What the tool does
|
|
124
|
+
params: Record<string, ToolParam>; // Parameter definitions
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Parameter Definition
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
interface ToolParam {
|
|
132
|
+
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
|
|
133
|
+
description?: string; // Parameter description
|
|
134
|
+
required?: boolean; // Whether required (default: false)
|
|
135
|
+
default?: unknown; // Default value
|
|
136
|
+
enum?: string[]; // Allowed values
|
|
137
|
+
items?: { // For array types
|
|
138
|
+
type: ParamType;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Examples
|
|
144
|
+
|
|
145
|
+
### Simple Tool
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const statusTool = {
|
|
149
|
+
name: 'get_status',
|
|
150
|
+
description: 'Get current system status',
|
|
151
|
+
params: {}, // No parameters
|
|
152
|
+
};
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Tool with Required Parameters
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
const searchTool = {
|
|
159
|
+
name: 'search',
|
|
160
|
+
description: 'Search for items',
|
|
161
|
+
params: {
|
|
162
|
+
query: {
|
|
163
|
+
type: 'string',
|
|
164
|
+
description: 'Search query',
|
|
165
|
+
required: true,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Tool with Enums
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const sortTool = {
|
|
175
|
+
name: 'sort_results',
|
|
176
|
+
description: 'Sort search results',
|
|
177
|
+
params: {
|
|
178
|
+
order: {
|
|
179
|
+
type: 'string',
|
|
180
|
+
enum: ['asc', 'desc'],
|
|
181
|
+
default: 'asc',
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Tool with Array Parameters
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
const batchTool = {
|
|
191
|
+
name: 'process_batch',
|
|
192
|
+
description: 'Process multiple items',
|
|
193
|
+
params: {
|
|
194
|
+
items: {
|
|
195
|
+
type: 'array',
|
|
196
|
+
description: 'Items to process',
|
|
197
|
+
items: { type: 'string' },
|
|
198
|
+
required: true,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Complex Tool
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
const apiTool = {
|
|
208
|
+
name: 'api_request',
|
|
209
|
+
description: 'Make an API request',
|
|
210
|
+
params: {
|
|
211
|
+
endpoint: {
|
|
212
|
+
type: 'string',
|
|
213
|
+
description: 'API endpoint path',
|
|
214
|
+
required: true,
|
|
215
|
+
},
|
|
216
|
+
method: {
|
|
217
|
+
type: 'string',
|
|
218
|
+
description: 'HTTP method',
|
|
219
|
+
enum: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
220
|
+
default: 'GET',
|
|
221
|
+
},
|
|
222
|
+
headers: {
|
|
223
|
+
type: 'object',
|
|
224
|
+
description: 'Request headers',
|
|
225
|
+
},
|
|
226
|
+
params: {
|
|
227
|
+
type: 'array',
|
|
228
|
+
description: 'Query parameters',
|
|
229
|
+
items: { type: 'string' },
|
|
230
|
+
},
|
|
231
|
+
timeout: {
|
|
232
|
+
type: 'number',
|
|
233
|
+
description: 'Request timeout in milliseconds',
|
|
234
|
+
default: 5000,
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Provider Output Formats
|
|
241
|
+
|
|
242
|
+
### OpenAI
|
|
243
|
+
|
|
244
|
+
Wraps function definition in a type object:
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"type": "function",
|
|
249
|
+
"function": {
|
|
250
|
+
"name": "get_weather",
|
|
251
|
+
"description": "Get weather",
|
|
252
|
+
"parameters": {
|
|
253
|
+
"type": "object",
|
|
254
|
+
"properties": {...},
|
|
255
|
+
"required": [...]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Anthropic
|
|
262
|
+
|
|
263
|
+
Flat structure with `input_schema`:
|
|
264
|
+
|
|
265
|
+
```json
|
|
266
|
+
{
|
|
267
|
+
"name": "get_weather",
|
|
268
|
+
"description": "Get weather",
|
|
269
|
+
"input_schema": {
|
|
270
|
+
"type": "object",
|
|
271
|
+
"properties": {...},
|
|
272
|
+
"required": [...]
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Gemini
|
|
278
|
+
|
|
279
|
+
Flat structure with UPPERCASE types:
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{
|
|
283
|
+
"name": "get_weather",
|
|
284
|
+
"description": "Get weather",
|
|
285
|
+
"parameters": {
|
|
286
|
+
"type": "OBJECT",
|
|
287
|
+
"properties": {
|
|
288
|
+
"location": { "type": "STRING" }
|
|
289
|
+
},
|
|
290
|
+
"required": [...]
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Mistral
|
|
296
|
+
|
|
297
|
+
OpenAI-compatible format:
|
|
298
|
+
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"type": "function",
|
|
302
|
+
"function": {
|
|
303
|
+
"name": "get_weather",
|
|
304
|
+
"description": "Get weather",
|
|
305
|
+
"parameters": {...}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Real-World Usage
|
|
311
|
+
|
|
312
|
+
### With OpenAI SDK
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
import OpenAI from 'openai';
|
|
316
|
+
import { adapt } from 'ai-tool-adapter';
|
|
317
|
+
|
|
318
|
+
const client = new OpenAI();
|
|
319
|
+
|
|
320
|
+
const tools = [weatherTool, calculatorTool].map(tool =>
|
|
321
|
+
adapt(tool, 'openai')
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
const response = await client.chat.completions.create({
|
|
325
|
+
model: 'gpt-4',
|
|
326
|
+
messages: [{ role: 'user', content: 'What\'s the weather in Paris?' }],
|
|
327
|
+
tools,
|
|
328
|
+
});
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### With Anthropic SDK
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
335
|
+
import { adaptAll } from 'ai-tool-adapter';
|
|
336
|
+
|
|
337
|
+
const client = new Anthropic();
|
|
338
|
+
|
|
339
|
+
const tools = adaptAll([weatherTool, calculatorTool], 'anthropic');
|
|
340
|
+
|
|
341
|
+
const response = await client.messages.create({
|
|
342
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
343
|
+
max_tokens: 1024,
|
|
344
|
+
messages: [{ role: 'user', content: 'What\'s the weather in Paris?' }],
|
|
345
|
+
tools,
|
|
346
|
+
});
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Multi-Provider Support
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
import { adapt } from 'ai-tool-adapter';
|
|
353
|
+
|
|
354
|
+
// Single source of truth for your tools
|
|
355
|
+
const myTools = [weatherTool, calculatorTool, searchTool];
|
|
356
|
+
|
|
357
|
+
// Support all providers effortlessly
|
|
358
|
+
const providerClients = {
|
|
359
|
+
openai: { tools: myTools.map(t => adapt(t, 'openai')) },
|
|
360
|
+
anthropic: { tools: myTools.map(t => adapt(t, 'anthropic')) },
|
|
361
|
+
gemini: { tools: myTools.map(t => adapt(t, 'gemini')) },
|
|
362
|
+
mistral: { tools: myTools.map(t => adapt(t, 'mistral')) },
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
// Use whichever provider you need
|
|
366
|
+
function callLLM(provider: string, prompt: string) {
|
|
367
|
+
const config = providerClients[provider];
|
|
368
|
+
// Make API call with provider-specific tools
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## TypeScript Support
|
|
373
|
+
|
|
374
|
+
Full type definitions included:
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
import type {
|
|
378
|
+
UniversalTool,
|
|
379
|
+
ToolParam,
|
|
380
|
+
Provider,
|
|
381
|
+
ParamType
|
|
382
|
+
} from 'ai-tool-adapter';
|
|
383
|
+
|
|
384
|
+
const tool: UniversalTool = {
|
|
385
|
+
name: 'my_tool',
|
|
386
|
+
description: 'My custom tool',
|
|
387
|
+
params: {
|
|
388
|
+
param1: {
|
|
389
|
+
type: 'string',
|
|
390
|
+
required: true,
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
};
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Development
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Install dependencies
|
|
400
|
+
npm install
|
|
401
|
+
|
|
402
|
+
# Build
|
|
403
|
+
npm run build
|
|
404
|
+
|
|
405
|
+
# Run tests
|
|
406
|
+
npm test
|
|
407
|
+
|
|
408
|
+
# Watch mode for tests
|
|
409
|
+
npm run test:watch
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## Architecture
|
|
413
|
+
|
|
414
|
+
This library follows the **Strategy Pattern** with each provider adapter as an independent, interchangeable strategy. This design ensures:
|
|
415
|
+
|
|
416
|
+
- **Orthogonality** - Adapters are completely independent
|
|
417
|
+
- **Open/Closed Principle** - Easy to add new providers without modifying existing code
|
|
418
|
+
- **Single Responsibility** - Each adapter handles exactly one provider's format
|
|
419
|
+
- **Pure Functions** - Predictable, testable transformations
|
|
420
|
+
|
|
421
|
+
For detailed architecture documentation, see [CLAUDE.md](./CLAUDE.md).
|
|
422
|
+
|
|
423
|
+
## Contributing
|
|
424
|
+
|
|
425
|
+
Contributions are welcome! To add a new provider:
|
|
426
|
+
|
|
427
|
+
1. Create adapter in `src/adapters/yourprovider.ts`
|
|
428
|
+
2. Add provider to `Provider` type in `src/types.ts`
|
|
429
|
+
3. Register adapter in `src/index.ts`
|
|
430
|
+
4. Add comprehensive tests
|
|
431
|
+
5. Update documentation
|
|
432
|
+
|
|
433
|
+
See [CLAUDE.md](./CLAUDE.md) for detailed guidelines.
|
|
434
|
+
|
|
435
|
+
## License
|
|
436
|
+
|
|
437
|
+
ISC
|
|
438
|
+
|
|
439
|
+
## Related
|
|
440
|
+
|
|
441
|
+
- [OpenAI Function Calling](https://platform.openai.com/docs/guides/function-calling)
|
|
442
|
+
- [Anthropic Tool Use](https://docs.anthropic.com/claude/docs/tool-use)
|
|
443
|
+
- [Google Gemini Function Calling](https://ai.google.dev/docs/function_calling)
|
|
444
|
+
- [Mistral AI Function Calling](https://docs.mistral.ai/capabilities/function_calling/)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic (Claude) Tool Adapter
|
|
3
|
+
*
|
|
4
|
+
* Converts UniversalTool to Anthropic's tool format.
|
|
5
|
+
* Output structure is flat with input_schema instead of parameters.
|
|
6
|
+
*
|
|
7
|
+
* @see https://docs.anthropic.com/claude/docs/tool-use
|
|
8
|
+
*/
|
|
9
|
+
import { UniversalTool } from '../types';
|
|
10
|
+
interface AnthropicProperty {
|
|
11
|
+
type: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
enum?: string[];
|
|
14
|
+
default?: unknown;
|
|
15
|
+
items?: {
|
|
16
|
+
type: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
interface AnthropicInputSchema {
|
|
20
|
+
type: 'object';
|
|
21
|
+
properties: Record<string, AnthropicProperty>;
|
|
22
|
+
required: string[];
|
|
23
|
+
}
|
|
24
|
+
interface AnthropicTool {
|
|
25
|
+
name: string;
|
|
26
|
+
description: string;
|
|
27
|
+
input_schema: AnthropicInputSchema;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Converts a UniversalTool to Anthropic tool format
|
|
31
|
+
*
|
|
32
|
+
* @param tool - Universal tool definition
|
|
33
|
+
* @returns Anthropic-formatted tool object
|
|
34
|
+
*/
|
|
35
|
+
export declare function anthropicAdapter(tool: UniversalTool): AnthropicTool;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Anthropic (Claude) Tool Adapter
|
|
4
|
+
*
|
|
5
|
+
* Converts UniversalTool to Anthropic's tool format.
|
|
6
|
+
* Output structure is flat with input_schema instead of parameters.
|
|
7
|
+
*
|
|
8
|
+
* @see https://docs.anthropic.com/claude/docs/tool-use
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.anthropicAdapter = anthropicAdapter;
|
|
12
|
+
/**
|
|
13
|
+
* Convert a single parameter to Anthropic property format
|
|
14
|
+
*/
|
|
15
|
+
function convertParam(param) {
|
|
16
|
+
const property = {
|
|
17
|
+
type: param.type,
|
|
18
|
+
};
|
|
19
|
+
if (param.description) {
|
|
20
|
+
property.description = param.description;
|
|
21
|
+
}
|
|
22
|
+
if (param.enum) {
|
|
23
|
+
property.enum = param.enum;
|
|
24
|
+
}
|
|
25
|
+
if (param.default !== undefined) {
|
|
26
|
+
property.default = param.default;
|
|
27
|
+
}
|
|
28
|
+
if (param.type === 'array' && param.items) {
|
|
29
|
+
property.items = { type: param.items.type };
|
|
30
|
+
}
|
|
31
|
+
return property;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Converts a UniversalTool to Anthropic tool format
|
|
35
|
+
*
|
|
36
|
+
* @param tool - Universal tool definition
|
|
37
|
+
* @returns Anthropic-formatted tool object
|
|
38
|
+
*/
|
|
39
|
+
function anthropicAdapter(tool) {
|
|
40
|
+
const properties = {};
|
|
41
|
+
const required = [];
|
|
42
|
+
for (const [paramName, paramDef] of Object.entries(tool.params)) {
|
|
43
|
+
properties[paramName] = convertParam(paramDef);
|
|
44
|
+
if (paramDef.required) {
|
|
45
|
+
required.push(paramName);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
name: tool.name,
|
|
50
|
+
description: tool.description,
|
|
51
|
+
input_schema: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties,
|
|
54
|
+
required,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for Anthropic (Claude) adapter
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const vitest_1 = require("vitest");
|
|
7
|
+
const anthropic_1 = require("./anthropic");
|
|
8
|
+
(0, vitest_1.describe)('anthropicAdapter', () => {
|
|
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, anthropic_1.anthropicAdapter)(tool);
|
|
22
|
+
(0, vitest_1.expect)(result).toEqual({
|
|
23
|
+
name: 'get_weather',
|
|
24
|
+
description: 'Get current weather for a location',
|
|
25
|
+
input_schema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
location: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'City name',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
required: ['location'],
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
(0, vitest_1.it)('should handle enum values', () => {
|
|
38
|
+
const tool = {
|
|
39
|
+
name: 'set_temperature',
|
|
40
|
+
description: 'Set temperature unit',
|
|
41
|
+
params: {
|
|
42
|
+
unit: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
enum: ['celsius', 'fahrenheit', 'kelvin'],
|
|
45
|
+
required: true,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
const result = (0, anthropic_1.anthropicAdapter)(tool);
|
|
50
|
+
(0, vitest_1.expect)(result.input_schema.properties.unit).toEqual({
|
|
51
|
+
type: 'string',
|
|
52
|
+
enum: ['celsius', 'fahrenheit', 'kelvin'],
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
(0, vitest_1.it)('should handle array types with items', () => {
|
|
56
|
+
const tool = {
|
|
57
|
+
name: 'process_items',
|
|
58
|
+
description: 'Process a list of items',
|
|
59
|
+
params: {
|
|
60
|
+
items: {
|
|
61
|
+
type: 'array',
|
|
62
|
+
description: 'List of items',
|
|
63
|
+
items: { type: 'string' },
|
|
64
|
+
required: true,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
const result = (0, anthropic_1.anthropicAdapter)(tool);
|
|
69
|
+
(0, vitest_1.expect)(result.input_schema.properties.items).toEqual({
|
|
70
|
+
type: 'array',
|
|
71
|
+
description: 'List of items',
|
|
72
|
+
items: { type: 'string' },
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.it)('should handle default values', () => {
|
|
76
|
+
const tool = {
|
|
77
|
+
name: 'paginate',
|
|
78
|
+
description: 'Get paginated results',
|
|
79
|
+
params: {
|
|
80
|
+
page: {
|
|
81
|
+
type: 'number',
|
|
82
|
+
default: 1,
|
|
83
|
+
},
|
|
84
|
+
limit: {
|
|
85
|
+
type: 'number',
|
|
86
|
+
default: 10,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
const result = (0, anthropic_1.anthropicAdapter)(tool);
|
|
91
|
+
(0, vitest_1.expect)(result.input_schema.properties.page).toEqual({
|
|
92
|
+
type: 'number',
|
|
93
|
+
default: 1,
|
|
94
|
+
});
|
|
95
|
+
(0, vitest_1.expect)(result.input_schema.properties.limit).toEqual({
|
|
96
|
+
type: 'number',
|
|
97
|
+
default: 10,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
(0, vitest_1.it)('should handle mixed required and optional params', () => {
|
|
101
|
+
const tool = {
|
|
102
|
+
name: 'search',
|
|
103
|
+
description: 'Search for items',
|
|
104
|
+
params: {
|
|
105
|
+
query: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
description: 'Search query',
|
|
108
|
+
required: true,
|
|
109
|
+
},
|
|
110
|
+
limit: {
|
|
111
|
+
type: 'number',
|
|
112
|
+
description: 'Result limit',
|
|
113
|
+
default: 10,
|
|
114
|
+
},
|
|
115
|
+
exact: {
|
|
116
|
+
type: 'boolean',
|
|
117
|
+
description: 'Exact match',
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
const result = (0, anthropic_1.anthropicAdapter)(tool);
|
|
122
|
+
(0, vitest_1.expect)(result.input_schema.required).toEqual(['query']);
|
|
123
|
+
(0, vitest_1.expect)(result.input_schema.properties).toHaveProperty('query');
|
|
124
|
+
(0, vitest_1.expect)(result.input_schema.properties).toHaveProperty('limit');
|
|
125
|
+
(0, vitest_1.expect)(result.input_schema.properties).toHaveProperty('exact');
|
|
126
|
+
});
|
|
127
|
+
(0, vitest_1.it)('should handle empty params', () => {
|
|
128
|
+
const tool = {
|
|
129
|
+
name: 'get_status',
|
|
130
|
+
description: 'Get current status',
|
|
131
|
+
params: {},
|
|
132
|
+
};
|
|
133
|
+
const result = (0, anthropic_1.anthropicAdapter)(tool);
|
|
134
|
+
(0, vitest_1.expect)(result.input_schema).toEqual({
|
|
135
|
+
type: 'object',
|
|
136
|
+
properties: {},
|
|
137
|
+
required: [],
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
(0, vitest_1.it)('should use lowercase type names', () => {
|
|
141
|
+
const tool = {
|
|
142
|
+
name: 'test_types',
|
|
143
|
+
description: 'Test all types',
|
|
144
|
+
params: {
|
|
145
|
+
str: { type: 'string' },
|
|
146
|
+
num: { type: 'number' },
|
|
147
|
+
bool: { type: 'boolean' },
|
|
148
|
+
arr: { type: 'array', items: { type: 'string' } },
|
|
149
|
+
obj: { type: 'object' },
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
const result = (0, anthropic_1.anthropicAdapter)(tool);
|
|
153
|
+
const props = result.input_schema.properties;
|
|
154
|
+
(0, vitest_1.expect)(props.str.type).toBe('string');
|
|
155
|
+
(0, vitest_1.expect)(props.num.type).toBe('number');
|
|
156
|
+
(0, vitest_1.expect)(props.bool.type).toBe('boolean');
|
|
157
|
+
(0, vitest_1.expect)(props.arr.type).toBe('array');
|
|
158
|
+
(0, vitest_1.expect)(props.obj.type).toBe('object');
|
|
159
|
+
});
|
|
160
|
+
(0, vitest_1.it)('should use flat structure with input_schema', () => {
|
|
161
|
+
const tool = {
|
|
162
|
+
name: 'test',
|
|
163
|
+
description: 'Test tool',
|
|
164
|
+
params: {},
|
|
165
|
+
};
|
|
166
|
+
const result = (0, anthropic_1.anthropicAdapter)(tool);
|
|
167
|
+
(0, vitest_1.expect)(result).toHaveProperty('name');
|
|
168
|
+
(0, vitest_1.expect)(result).toHaveProperty('description');
|
|
169
|
+
(0, vitest_1.expect)(result).toHaveProperty('input_schema');
|
|
170
|
+
(0, vitest_1.expect)(result).not.toHaveProperty('type');
|
|
171
|
+
(0, vitest_1.expect)(result).not.toHaveProperty('function');
|
|
172
|
+
});
|
|
173
|
+
});
|