@spec2tools/cli 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
@@ -38,6 +38,9 @@ npx @spec2tools/cli start --spec ./openapi.yaml --no-auth
38
38
 
39
39
  # Provide API key directly
40
40
  npx @spec2tools/cli start --spec ./openapi.yaml --api-key "your-api-key"
41
+
42
+ # Enable code mode (2 tools: search + execute)
43
+ npx @spec2tools/cli start --spec ./openapi.yaml --code-mode
41
44
  ```
42
45
 
43
46
  ### Chat Mode
package/dist/agent.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { type Tool } from '@spec2tools/core';
1
+ import { type ToolSet } from '@spec2tools/core';
2
2
  interface AgentConfig {
3
- tools: Tool[];
3
+ tools: ToolSet;
4
4
  model?: string;
5
5
  maxSteps?: number;
6
6
  }
@@ -32,7 +32,7 @@ export declare class Agent {
32
32
  /**
33
33
  * Get a specific tool by name
34
34
  */
35
- getTool(name: string): Tool | undefined;
35
+ getTool(name: string): ToolSet[string] | undefined;
36
36
  }
37
37
  export {};
38
38
  //# sourceMappingURL=agent.d.ts.map
package/dist/agent.js CHANGED
@@ -1,4 +1,4 @@
1
- import { generateText, tool, stepCountIs } from 'ai';
1
+ import { generateText, stepCountIs } from 'ai';
2
2
  import { openai } from '@ai-sdk/openai';
3
3
  import { ToolExecutionError } from '@spec2tools/core';
4
4
  import chalk from 'chalk';
@@ -31,11 +31,14 @@ export class Agent {
31
31
  * Get available tools description for the agent
32
32
  */
33
33
  getToolsDescription() {
34
- if (this.tools.length === 0) {
34
+ const names = Object.keys(this.tools);
35
+ if (names.length === 0) {
35
36
  return 'No tools available.';
36
37
  }
37
- const toolDescriptions = this.tools.map((tool) => {
38
- return `- ${tool.name}: ${tool.description}`;
38
+ const toolDescriptions = names.map((name) => {
39
+ const t = this.tools[name];
40
+ const desc = 'description' in t ? t.description : '';
41
+ return `- ${name}: ${desc}`;
39
42
  });
40
43
  return `I have access to the following tools:\n${toolDescriptions.join('\n')}`;
41
44
  }
@@ -49,30 +52,29 @@ export class Agent {
49
52
  content: userMessage,
50
53
  });
51
54
  try {
52
- // Build AI SDK tools from our tool definitions
53
- const aiTools = {};
54
- for (const t of this.tools) {
55
- const toolExecute = t.execute;
56
- const toolName = t.name;
57
- aiTools[t.name] = tool({
58
- description: t.description,
59
- inputSchema: t.parameters,
60
- execute: async (params) => {
61
- console.log(chalk.dim(`\n[Calling ${toolName} with ${JSON.stringify(params)}]`));
62
- try {
63
- const result = await toolExecute(params);
64
- console.log(chalk.dim(`[${toolName} returned: ${trimOutput(result)}]\n`));
65
- return result;
66
- }
67
- catch (error) {
68
- if (error instanceof ToolExecutionError) {
69
- console.log(chalk.red(`[${toolName} failed: ${error.message}]\n`));
55
+ // Wrap each tool to add CLI logging
56
+ const wrappedTools = {};
57
+ for (const [name, t] of Object.entries(this.tools)) {
58
+ const originalExecute = 'execute' in t ? t.execute : undefined;
59
+ wrappedTools[name] = {
60
+ ...t,
61
+ execute: originalExecute
62
+ ? async (params, options) => {
63
+ console.log(chalk.dim(`\n[Calling ${name} with ${JSON.stringify(params)}]`));
64
+ try {
65
+ const result = await originalExecute(params, options);
66
+ console.log(chalk.dim(`[${name} returned: ${trimOutput(result)}]\n`));
67
+ return result;
68
+ }
69
+ catch (error) {
70
+ if (error instanceof ToolExecutionError) {
71
+ console.log(chalk.red(`[${name} failed: ${error.message}]\n`));
72
+ }
70
73
  throw error;
71
74
  }
72
- throw error;
73
75
  }
74
- },
75
- });
76
+ : undefined,
77
+ };
76
78
  }
77
79
  // Build system prompt
78
80
  const systemPrompt = `You are a helpful AI assistant with access to various API tools.
@@ -84,7 +86,7 @@ If a tool call fails, explain the error to the user.`;
84
86
  model: openai(this.model),
85
87
  system: systemPrompt,
86
88
  messages: this.conversationHistory,
87
- tools: aiTools,
89
+ tools: wrappedTools,
88
90
  stopWhen: stepCountIs(this.maxSteps),
89
91
  });
90
92
  // Add assistant response to history
@@ -114,13 +116,13 @@ If a tool call fails, explain the error to the user.`;
114
116
  * Get the list of tool names
115
117
  */
116
118
  getToolNames() {
117
- return this.tools.map((t) => t.name);
119
+ return Object.keys(this.tools);
118
120
  }
119
121
  /**
120
122
  * Get a specific tool by name
121
123
  */
122
124
  getTool(name) {
123
- return this.tools.find((t) => t.name === name);
125
+ return this.tools[name];
124
126
  }
125
127
  }
126
128
  //# sourceMappingURL=agent.js.map
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@ import { Command } from 'commander';
2
2
  import chalk from 'chalk';
3
3
  import ora from 'ora';
4
4
  import * as readline from 'readline';
5
- import { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, parseOperations, formatToolSchema, formatToolSignature, AuthManager, createExecutableTools, executeToolByName, UnsupportedSchemaError, AuthenticationError, ToolExecutionError, SpecLoadError, } from '@spec2tools/core';
5
+ import { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, parseOperations, formatToolSchema, formatToolSignature, AuthManager, createExecutableTools, executeToolByName, toAISDKTools, toCodeModeTools, UnsupportedSchemaError, AuthenticationError, ToolExecutionError, SpecLoadError, } from '@spec2tools/core';
6
6
  import { Agent } from './agent.js';
7
7
  const VERSION = '0.1.6';
8
8
  export function createCLI() {
@@ -17,6 +17,7 @@ export function createCLI() {
17
17
  .requiredOption('-s, --spec <path>', 'Path or URL to OpenAPI specification')
18
18
  .option('--no-auth', 'Skip authentication even if required by spec')
19
19
  .option('--api-key <key>', 'Provide API key or access token directly')
20
+ .option('--code-mode', 'Use code mode (2 tools: search + execute)')
20
21
  .action(async (options) => {
21
22
  await startAgent(options);
22
23
  });
@@ -59,6 +60,12 @@ async function startAgent(options) {
59
60
  }
60
61
  // Create executable tools
61
62
  const tools = createExecutableTools(toolDefs, baseUrl, authManager);
63
+ // Convert to AI SDK tools
64
+ let aiTools = toAISDKTools(tools);
65
+ if (options.codeMode) {
66
+ aiTools = toCodeModeTools(aiTools);
67
+ console.log(chalk.green('Code mode enabled (2 tools: search + execute)'));
68
+ }
62
69
  // Initialize session
63
70
  const session = {
64
71
  baseUrl,
@@ -67,7 +74,7 @@ async function startAgent(options) {
67
74
  accessToken: authManager.getAccessToken(),
68
75
  };
69
76
  // Start chat loop
70
- await startChatLoop(session);
77
+ await startChatLoop(session, aiTools, options.codeMode ?? false);
71
78
  }
72
79
  catch (error) {
73
80
  spinner.fail();
@@ -87,9 +94,9 @@ async function startAgent(options) {
87
94
  process.exit(1);
88
95
  }
89
96
  }
90
- async function startChatLoop(session) {
97
+ async function startChatLoop(session, aiTools, codeMode) {
91
98
  // Initialize agent
92
- const agent = new Agent({ tools: session.tools });
99
+ const agent = new Agent({ tools: aiTools });
93
100
  console.log(chalk.bold('\n--- Spec2Tools ---'));
94
101
  console.log(chalk.dim('Type your message or use special commands:'));
95
102
  console.log(chalk.dim(' /tools - List available tools'));
@@ -112,7 +119,7 @@ async function startChatLoop(session) {
112
119
  // Pause readline during async operations to prevent corruption
113
120
  rl.pause();
114
121
  try {
115
- await handleInput(trimmedInput, session, agent);
122
+ await handleInput(trimmedInput, session, agent, codeMode, aiTools);
116
123
  }
117
124
  catch (error) {
118
125
  console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
@@ -129,10 +136,10 @@ async function startChatLoop(session) {
129
136
  });
130
137
  prompt();
131
138
  }
132
- async function handleInput(input, session, agent) {
139
+ async function handleInput(input, session, agent, codeMode, aiTools) {
133
140
  // Handle special commands
134
141
  if (input.startsWith('/')) {
135
- await handleCommand(input, session, agent);
142
+ await handleCommand(input, session, agent, codeMode, aiTools);
136
143
  return;
137
144
  }
138
145
  // Regular chat message
@@ -147,13 +154,18 @@ async function handleInput(input, session, agent) {
147
154
  throw error;
148
155
  }
149
156
  }
150
- async function handleCommand(input, session, agent) {
157
+ async function handleCommand(input, session, agent, codeMode, aiTools) {
151
158
  const parts = input.slice(1).split(/\s+/);
152
159
  const command = parts[0].toLowerCase();
153
160
  const args = parts.slice(1);
154
161
  switch (command) {
155
162
  case 'tools':
156
- listTools(session.tools);
163
+ if (codeMode) {
164
+ listCodeModeTools(aiTools);
165
+ }
166
+ else {
167
+ listTools(session.tools);
168
+ }
157
169
  break;
158
170
  case 'call':
159
171
  await callTool(session.tools, args);
@@ -186,6 +198,15 @@ function listTools(tools) {
186
198
  });
187
199
  console.log('');
188
200
  }
201
+ function listCodeModeTools(aiTools) {
202
+ console.log(chalk.bold('\nCode mode tools:'));
203
+ Object.entries(aiTools).forEach(([name, t], index) => {
204
+ const desc = 'description' in t ? t.description || '' : '';
205
+ console.log(chalk.cyan(`${index + 1}. ${name}`));
206
+ console.log(chalk.dim(` ${desc}`));
207
+ });
208
+ console.log('');
209
+ }
189
210
  async function callTool(tools, args) {
190
211
  if (args.length === 0) {
191
212
  console.log(chalk.yellow('Usage: /call <toolName> [--param value ...]'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spec2tools/cli",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "CLI for interacting with OpenAPI-based AI tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -39,7 +39,7 @@
39
39
  "commander": "^14.0.0",
40
40
  "dotenv": "^17.2.3",
41
41
  "ora": "^8.1.0",
42
- "@spec2tools/core": "0.1.2"
42
+ "@spec2tools/core": "0.2.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^22.0.0",