@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 +3 -0
- package/dist/agent.d.ts +3 -3
- package/dist/agent.js +30 -28
- package/dist/cli.js +30 -9
- package/package.json +2 -2
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
|
|
1
|
+
import { type ToolSet } from '@spec2tools/core';
|
|
2
2
|
interface AgentConfig {
|
|
3
|
-
tools:
|
|
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):
|
|
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,
|
|
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
|
-
|
|
34
|
+
const names = Object.keys(this.tools);
|
|
35
|
+
if (names.length === 0) {
|
|
35
36
|
return 'No tools available.';
|
|
36
37
|
}
|
|
37
|
-
const toolDescriptions =
|
|
38
|
-
|
|
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
|
-
//
|
|
53
|
-
const
|
|
54
|
-
for (const t of this.tools) {
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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:
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
|
|
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.
|
|
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.
|
|
42
|
+
"@spec2tools/core": "0.2.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^22.0.0",
|