@spec2tools/sdk 0.1.2 → 0.2.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/README.md CHANGED
@@ -27,6 +27,47 @@ const result = await generateText({
27
27
  console.log(result.text);
28
28
  ```
29
29
 
30
+ ### Code Mode
31
+
32
+ Enable code mode to collapse all endpoints into 2 tools (`search` + `execute`), reducing token usage by ~99.9%:
33
+
34
+ ```ts
35
+ const tools = await createTools({
36
+ spec: './openapi.yaml',
37
+ codeMode: true,
38
+ });
39
+ ```
40
+
41
+ ### Code Mode for MCP Clients
42
+
43
+ Use `convertToolsToCodeMode` to apply code mode to tools from any source, such as `createMCPClient` from `@ai-sdk/mcp`:
44
+
45
+ ```ts
46
+ import { createMCPClient } from '@ai-sdk/mcp';
47
+ import { convertToolsToCodeMode } from '@spec2tools/sdk';
48
+ import { generateText, stepCountIs } from 'ai';
49
+ import { openai } from '@ai-sdk/openai';
50
+
51
+ const client = await createMCPClient({
52
+ transport: { type: 'sse', url: 'http://localhost:3000/sse' },
53
+ });
54
+
55
+ try {
56
+ const tools = convertToolsToCodeMode(await client.tools());
57
+
58
+ const result = await generateText({
59
+ model: openai('gpt-4o'),
60
+ tools,
61
+ prompt: 'List all users',
62
+ stopWhen: stepCountIs(3),
63
+ });
64
+
65
+ console.log(result.text);
66
+ } finally {
67
+ await client.close();
68
+ }
69
+ ```
70
+
30
71
  ## API
31
72
 
32
73
  ### `createTools(options: Spec2ToolsOptions): Promise<ToolSet>`
@@ -36,6 +77,7 @@ Creates AI SDK-compatible tools from an OpenAPI specification.
36
77
  #### Options
37
78
 
38
79
  - `spec` (string, required): Path or URL to the OpenAPI specification file (JSON or YAML)
80
+ - `codeMode` (boolean, optional): When `true`, returns 2 code-mode tools instead of one per endpoint
39
81
 
40
82
  #### Returns
41
83
 
@@ -43,12 +85,11 @@ A `Promise` that resolves to an object of AI SDK tools.
43
85
 
44
86
  #### Throws
45
87
 
46
- - `Error` if the API requires authentication. For authenticated APIs, use the `@spec2tools/cli` package instead.
88
+ - `Error` if the API requires authentication (unless `codeMode` is enabled). For authenticated APIs, use the `@spec2tools/cli` package instead.
47
89
 
48
- ## Notes
90
+ ### `convertToolsToCodeMode(tools: ToolSet): ToolSet`
49
91
 
50
- - `createTools()` only works with APIs that don't require authentication
51
- - For authenticated APIs, use the CLI: `npx @spec2tools/cli start --spec ./openapi.yaml`
92
+ Converts an existing AI SDK ToolSet into code mode (2 tools: `search` + `execute`). Useful when you have tools from another source (e.g. `createMCPClient` from `@ai-sdk/mcp`) and want to reduce token usage.
52
93
 
53
94
  ## License
54
95
 
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { createTools, type Spec2ToolsOptions } from './lib.js';
1
+ export { createTools, convertToolsToCodeMode, type Spec2ToolsOptions } from './lib.js';
2
2
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { createTools } from './lib.js';
1
+ export { createTools, convertToolsToCodeMode } from './lib.js';
2
2
  //# sourceMappingURL=index.js.map
package/dist/lib.d.ts CHANGED
@@ -1,8 +1,28 @@
1
- import { generateText } from 'ai';
2
- type ToolSet = NonNullable<Parameters<typeof generateText>[0]['tools']>;
1
+ import { toCodeModeTools, type ToolSet } from '@spec2tools/core';
2
+ /**
3
+ * Convert an existing AI SDK ToolSet into code mode (2 tools: search + execute).
4
+ *
5
+ * Useful when you already have tools from another source (e.g. `createMCPClient`)
6
+ * and want to reduce token usage by collapsing them into code mode.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { createMCPClient } from '@ai-sdk/mcp';
11
+ * import { convertToolsToCodeMode } from '@spec2tools/sdk';
12
+ *
13
+ * const client = await createMCPClient({
14
+ * transport: { type: 'sse', url: 'http://localhost:3000/sse' },
15
+ * });
16
+ * const tools = await client.tools();
17
+ * const codeModeTools = convertToolsToCodeMode(tools);
18
+ * ```
19
+ */
20
+ export declare const convertToolsToCodeMode: typeof toCodeModeTools;
3
21
  export interface Spec2ToolsOptions {
4
22
  /** Path or URL to OpenAPI specification */
5
23
  spec: string;
24
+ /** Use code mode (2 tools: search + execute) instead of one tool per endpoint */
25
+ codeMode?: boolean;
6
26
  }
7
27
  /**
8
28
  * Create AI SDK tools from an OpenAPI specification.
@@ -22,8 +42,7 @@ export interface Spec2ToolsOptions {
22
42
  * });
23
43
  * ```
24
44
  *
25
- * @throws Error if the API requires authentication
45
+ * @throws Error if the API requires authentication (unless codeMode is enabled)
26
46
  */
27
47
  export declare function createTools(options: Spec2ToolsOptions): Promise<ToolSet>;
28
- export {};
29
48
  //# sourceMappingURL=lib.d.ts.map
package/dist/lib.js CHANGED
@@ -1,5 +1,23 @@
1
- import { tool } from 'ai';
2
- import { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, parseOperations, AuthManager, ToolExecutionError, } from '@spec2tools/core';
1
+ import { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, parseOperations, createExecutableTools, toAISDKTools, toCodeModeTools, AuthManager, } from '@spec2tools/core';
2
+ /**
3
+ * Convert an existing AI SDK ToolSet into code mode (2 tools: search + execute).
4
+ *
5
+ * Useful when you already have tools from another source (e.g. `createMCPClient`)
6
+ * and want to reduce token usage by collapsing them into code mode.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { createMCPClient } from '@ai-sdk/mcp';
11
+ * import { convertToolsToCodeMode } from '@spec2tools/sdk';
12
+ *
13
+ * const client = await createMCPClient({
14
+ * transport: { type: 'sse', url: 'http://localhost:3000/sse' },
15
+ * });
16
+ * const tools = await client.tools();
17
+ * const codeModeTools = convertToolsToCodeMode(tools);
18
+ * ```
19
+ */
20
+ export const convertToolsToCodeMode = toCodeModeTools;
3
21
  /**
4
22
  * Create AI SDK tools from an OpenAPI specification.
5
23
  *
@@ -18,80 +36,25 @@ import { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, parseOperations, Au
18
36
  * });
19
37
  * ```
20
38
  *
21
- * @throws Error if the API requires authentication
39
+ * @throws Error if the API requires authentication (unless codeMode is enabled)
22
40
  */
23
41
  export async function createTools(options) {
24
42
  const spec = await loadOpenAPISpec(options.spec);
25
43
  const baseUrl = extractBaseUrl(spec);
26
44
  const authConfig = extractAuthConfig(spec);
27
- // Check if auth is required
28
- if (authConfig.type !== 'none') {
45
+ // Check if auth is required (skip in code mode — auth is handled internally)
46
+ if (!options.codeMode && authConfig.type !== 'none') {
29
47
  throw new Error(`This API requires authentication (${authConfig.type}). ` +
30
48
  `The createTools() function only supports APIs without authentication. ` +
31
49
  `Use the CLI for authenticated APIs: npx @spec2tools/cli start --spec ${options.spec}`);
32
50
  }
33
51
  const toolDefs = parseOperations(spec);
34
52
  const authManager = new AuthManager(authConfig);
35
- // Build AI SDK tools
36
- const tools = {};
37
- for (const toolDef of toolDefs) {
38
- const { name, description, parameters, httpMethod, path } = toolDef;
39
- tools[name] = tool({
40
- description,
41
- inputSchema: parameters,
42
- execute: async (params) => {
43
- // Build URL with path parameters
44
- let url = `${baseUrl}${path}`;
45
- const queryParams = {};
46
- const bodyParams = {};
47
- for (const [key, value] of Object.entries(params)) {
48
- if (value === undefined)
49
- continue;
50
- if (url.includes(`{${key}}`)) {
51
- // Path parameter
52
- url = url.replace(`{${key}}`, encodeURIComponent(String(value)));
53
- }
54
- else if (httpMethod === 'GET' || httpMethod === 'DELETE') {
55
- // Query parameter for GET/DELETE
56
- queryParams[key] = String(value);
57
- }
58
- else {
59
- // Body parameter for POST/PUT/PATCH
60
- bodyParams[key] = value;
61
- }
62
- }
63
- // Add query parameters
64
- const queryString = new URLSearchParams(queryParams).toString();
65
- if (queryString) {
66
- url += `?${queryString}`;
67
- }
68
- // Build request options
69
- const fetchOptions = {
70
- method: httpMethod,
71
- headers: {
72
- 'Content-Type': 'application/json',
73
- ...authManager.getAuthHeaders(),
74
- },
75
- };
76
- // Add body for non-GET/DELETE requests
77
- if (Object.keys(bodyParams).length > 0 &&
78
- httpMethod !== 'GET' &&
79
- httpMethod !== 'DELETE') {
80
- fetchOptions.body = JSON.stringify(bodyParams);
81
- }
82
- const response = await fetch(url, fetchOptions);
83
- if (!response.ok) {
84
- const errorText = await response.text();
85
- throw new ToolExecutionError(name, new Error(`HTTP ${response.status}: ${errorText}`));
86
- }
87
- const contentType = response.headers.get('content-type');
88
- if (contentType?.includes('application/json')) {
89
- return await response.json();
90
- }
91
- return await response.text();
92
- },
93
- });
53
+ const tools = createExecutableTools(toolDefs, baseUrl, authManager);
54
+ let aiTools = toAISDKTools(tools);
55
+ if (options.codeMode) {
56
+ aiTools = toCodeModeTools(aiTools);
94
57
  }
95
- return tools;
58
+ return aiTools;
96
59
  }
97
60
  //# sourceMappingURL=lib.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spec2tools/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Create AI SDK tools from OpenAPI specifications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,14 +32,15 @@
32
32
  "dependencies": {
33
33
  "ai": "^6.0.68",
34
34
  "zod": "^3.24.0",
35
- "@spec2tools/core": "0.1.2"
35
+ "@spec2tools/core": "0.2.0"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "zod": "^3.24.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^22.0.0",
42
- "typescript": "^5.6.0"
42
+ "typescript": "^5.6.0",
43
+ "vitest": "^4.0.18"
43
44
  },
44
45
  "engines": {
45
46
  "node": ">=18.0.0"
@@ -47,6 +48,8 @@
47
48
  "scripts": {
48
49
  "build": "tsc",
49
50
  "dev": "tsc --watch",
50
- "typecheck": "tsc --noEmit"
51
+ "typecheck": "tsc --noEmit",
52
+ "test": "vitest run",
53
+ "test:watch": "vitest"
51
54
  }
52
55
  }