protoagent 0.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/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/agentic-loop.js +277 -0
- package/dist/config/client.js +166 -0
- package/dist/config/commands.js +208 -0
- package/dist/config/manager.js +117 -0
- package/dist/config/mcp-commands.js +266 -0
- package/dist/config/mcp-manager.js +240 -0
- package/dist/config/mcp-types.js +28 -0
- package/dist/config/providers.js +170 -0
- package/dist/config/setup.js +175 -0
- package/dist/config/system-prompt.js +301 -0
- package/dist/config/types.js +4 -0
- package/dist/index.js +156 -0
- package/dist/tools/create-directory.js +76 -0
- package/dist/tools/directory-operations.js +195 -0
- package/dist/tools/edit-file.js +144 -0
- package/dist/tools/file-operations.js +211 -0
- package/dist/tools/index.js +95 -0
- package/dist/tools/list-directory.js +84 -0
- package/dist/tools/read-file.js +111 -0
- package/dist/tools/run-shell-command.js +340 -0
- package/dist/tools/search-files.js +177 -0
- package/dist/tools/search-operations.js +179 -0
- package/dist/tools/shell-operations.js +342 -0
- package/dist/tools/todo.js +177 -0
- package/dist/tools/view-directory-tree.js +125 -0
- package/dist/tools/write-file.js +136 -0
- package/dist/tools.js +2 -0
- package/dist/utils/conversation-compactor.js +139 -0
- package/dist/utils/cost-tracker.js +106 -0
- package/dist/utils/file-operations-approval.js +163 -0
- package/dist/utils/logger.js +149 -0
- package/package.json +61 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) Manager
|
|
3
|
+
* Handles connections to MCP servers and tool execution
|
|
4
|
+
*/
|
|
5
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
6
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
7
|
+
import { DEFAULT_MCP_CONFIG } from './mcp-types.js';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import fs from 'fs/promises';
|
|
10
|
+
import { getConfigDirectory } from './manager.js';
|
|
11
|
+
export class MCPManager {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.connections = new Map();
|
|
14
|
+
this.processes = new Map();
|
|
15
|
+
this.config = config || DEFAULT_MCP_CONFIG;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Load MCP configuration from file
|
|
19
|
+
*/
|
|
20
|
+
async loadConfig() {
|
|
21
|
+
try {
|
|
22
|
+
const configPath = path.join(getConfigDirectory(), 'mcp-config.json');
|
|
23
|
+
const configData = await fs.readFile(configPath, 'utf-8');
|
|
24
|
+
this.config = { ...DEFAULT_MCP_CONFIG, ...JSON.parse(configData) };
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
// If no config file exists, use defaults
|
|
28
|
+
console.log('š” Using default MCP configuration');
|
|
29
|
+
this.config = DEFAULT_MCP_CONFIG;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Save MCP configuration to file
|
|
34
|
+
*/
|
|
35
|
+
async saveConfig() {
|
|
36
|
+
try {
|
|
37
|
+
const configPath = path.join(getConfigDirectory(), 'mcp-config.json');
|
|
38
|
+
await fs.writeFile(configPath, JSON.stringify(this.config, null, 2));
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error('ā Failed to save MCP configuration:', error);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Connect to a specific MCP server
|
|
46
|
+
*/
|
|
47
|
+
async connectToServer(serverName) {
|
|
48
|
+
const serverConfig = this.config.servers[serverName];
|
|
49
|
+
if (!serverConfig || !serverConfig.enabled) {
|
|
50
|
+
console.log(`ā ļø Server ${serverName} is not configured or disabled`);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
console.log(`š Connecting to MCP server: ${serverName}`);
|
|
55
|
+
// Create transport for stdio communication
|
|
56
|
+
const transport = new StdioClientTransport({
|
|
57
|
+
command: serverConfig.command,
|
|
58
|
+
args: serverConfig.args || [],
|
|
59
|
+
env: {
|
|
60
|
+
...Object.fromEntries(Object.entries(process.env).filter(([_, v]) => v !== undefined)),
|
|
61
|
+
...serverConfig.env
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
// Create MCP client
|
|
65
|
+
const client = new Client({
|
|
66
|
+
name: 'protoagent',
|
|
67
|
+
version: '1.0.0'
|
|
68
|
+
}, {
|
|
69
|
+
capabilities: {
|
|
70
|
+
tools: {}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
// Connect to the server
|
|
74
|
+
await client.connect(transport);
|
|
75
|
+
// Get server capabilities
|
|
76
|
+
const serverCapabilities = await client.listTools();
|
|
77
|
+
const capabilities = serverCapabilities.tools.map(tool => tool.name);
|
|
78
|
+
const connection = {
|
|
79
|
+
name: serverName,
|
|
80
|
+
client,
|
|
81
|
+
capabilities,
|
|
82
|
+
connected: true
|
|
83
|
+
};
|
|
84
|
+
this.connections.set(serverName, connection);
|
|
85
|
+
console.log(`ā
Connected to ${serverName} with ${capabilities.length} tools`);
|
|
86
|
+
return connection;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
console.error(`ā Failed to connect to MCP server ${serverName}:`, error);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Connect to all enabled MCP servers
|
|
95
|
+
*/
|
|
96
|
+
async connectToAllServers() {
|
|
97
|
+
console.log('š Initializing MCP connections...');
|
|
98
|
+
const enabledServers = Object.keys(this.config.servers).filter(name => this.config.servers[name].enabled);
|
|
99
|
+
if (enabledServers.length === 0) {
|
|
100
|
+
console.log('ā¹ļø No MCP servers enabled');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const connectionPromises = enabledServers.map(serverName => this.connectToServer(serverName).catch(error => {
|
|
104
|
+
console.error(`Failed to connect to ${serverName}:`, error);
|
|
105
|
+
return null;
|
|
106
|
+
}));
|
|
107
|
+
const results = await Promise.all(connectionPromises);
|
|
108
|
+
const successfulConnections = results.filter(conn => conn !== null);
|
|
109
|
+
console.log(`š” MCP Status: ${successfulConnections.length}/${enabledServers.length} servers connected`);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get all available tools from connected servers
|
|
113
|
+
*/
|
|
114
|
+
async getAllTools() {
|
|
115
|
+
const allTools = [];
|
|
116
|
+
for (const [serverName, connection] of this.connections) {
|
|
117
|
+
if (!connection.connected)
|
|
118
|
+
continue;
|
|
119
|
+
try {
|
|
120
|
+
const tools = await connection.client.listTools();
|
|
121
|
+
for (const tool of tools.tools) {
|
|
122
|
+
allTools.push({
|
|
123
|
+
server: serverName,
|
|
124
|
+
name: tool.name,
|
|
125
|
+
description: tool.description,
|
|
126
|
+
schema: tool.inputSchema
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error(`ā Failed to get tools from ${serverName}:`, error);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return allTools;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Execute a tool on a specific MCP server
|
|
138
|
+
*/
|
|
139
|
+
async callTool(serverName, toolName, args) {
|
|
140
|
+
const connection = this.connections.get(serverName);
|
|
141
|
+
if (!connection || !connection.connected) {
|
|
142
|
+
throw new Error(`Server ${serverName} is not connected`);
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
console.log(`š ļø Calling ${serverName}:${toolName}`);
|
|
146
|
+
const result = await connection.client.callTool({
|
|
147
|
+
name: toolName,
|
|
148
|
+
arguments: args
|
|
149
|
+
});
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.error(`ā Tool execution failed ${serverName}:${toolName}:`, error);
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Find which server has a specific tool
|
|
159
|
+
*/
|
|
160
|
+
findToolServer(toolName) {
|
|
161
|
+
for (const [serverName, connection] of this.connections) {
|
|
162
|
+
if (connection.capabilities.includes(toolName)) {
|
|
163
|
+
return serverName;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get connection status
|
|
170
|
+
*/
|
|
171
|
+
getConnectionStatus() {
|
|
172
|
+
const status = {};
|
|
173
|
+
for (const [serverName, connection] of this.connections) {
|
|
174
|
+
status[serverName] = connection.connected;
|
|
175
|
+
}
|
|
176
|
+
return status;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Add a custom MCP server configuration
|
|
180
|
+
*/
|
|
181
|
+
async addCustomServer(config) {
|
|
182
|
+
this.config.servers[config.name] = config;
|
|
183
|
+
await this.saveConfig();
|
|
184
|
+
console.log(`ā
Added custom MCP server: ${config.name}`);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Remove a custom MCP server
|
|
188
|
+
*/
|
|
189
|
+
async removeCustomServer(serverName) {
|
|
190
|
+
const serverConfig = this.config.servers[serverName];
|
|
191
|
+
if (serverConfig?.isBuiltIn) {
|
|
192
|
+
throw new Error('Cannot remove built-in MCP servers');
|
|
193
|
+
}
|
|
194
|
+
// Disconnect if connected
|
|
195
|
+
const connection = this.connections.get(serverName);
|
|
196
|
+
if (connection) {
|
|
197
|
+
await this.disconnectServer(serverName);
|
|
198
|
+
}
|
|
199
|
+
delete this.config.servers[serverName];
|
|
200
|
+
await this.saveConfig();
|
|
201
|
+
console.log(`ā
Removed custom MCP server: ${serverName}`);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Disconnect from a specific server
|
|
205
|
+
*/
|
|
206
|
+
async disconnectServer(serverName) {
|
|
207
|
+
const connection = this.connections.get(serverName);
|
|
208
|
+
if (connection) {
|
|
209
|
+
try {
|
|
210
|
+
await connection.client.close();
|
|
211
|
+
connection.connected = false;
|
|
212
|
+
this.connections.delete(serverName);
|
|
213
|
+
console.log(`š Disconnected from ${serverName}`);
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
console.error(`ā Error disconnecting from ${serverName}:`, error);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Disconnect from all servers
|
|
222
|
+
*/
|
|
223
|
+
async disconnectAll() {
|
|
224
|
+
console.log('š Disconnecting from all MCP servers...');
|
|
225
|
+
const disconnectPromises = Array.from(this.connections.keys()).map(serverName => this.disconnectServer(serverName));
|
|
226
|
+
await Promise.all(disconnectPromises);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get server configuration
|
|
230
|
+
*/
|
|
231
|
+
getServerConfig(serverName) {
|
|
232
|
+
return this.config.servers[serverName] || null;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* List all configured servers
|
|
236
|
+
*/
|
|
237
|
+
listServers() {
|
|
238
|
+
return { ...this.config.servers };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) configuration types
|
|
3
|
+
*/
|
|
4
|
+
// Built-in server configurations
|
|
5
|
+
export const BUILTIN_MCP_SERVERS = {
|
|
6
|
+
filesystem: {
|
|
7
|
+
name: 'filesystem',
|
|
8
|
+
description: 'File system operations via MCP',
|
|
9
|
+
command: 'npx',
|
|
10
|
+
args: ['@modelcontextprotocol/server-filesystem'],
|
|
11
|
+
enabled: true,
|
|
12
|
+
isBuiltIn: true
|
|
13
|
+
},
|
|
14
|
+
'sequential-thinking': {
|
|
15
|
+
name: 'sequential-thinking',
|
|
16
|
+
description: 'Sequential thinking and reasoning tools',
|
|
17
|
+
command: 'npx',
|
|
18
|
+
args: ['@modelcontextprotocol/server-sequential-thinking'],
|
|
19
|
+
enabled: true,
|
|
20
|
+
isBuiltIn: true
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
export const DEFAULT_MCP_CONFIG = {
|
|
24
|
+
servers: { ...BUILTIN_MCP_SERVERS },
|
|
25
|
+
globalTimeout: 30000, // 30 seconds
|
|
26
|
+
maxConcurrentConnections: 5,
|
|
27
|
+
retryAttempts: 3
|
|
28
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI provider configuration for ProtoAgent
|
|
3
|
+
*/
|
|
4
|
+
export const openaiModels = {
|
|
5
|
+
models: [
|
|
6
|
+
'gpt-5-nano-2025-08-07',
|
|
7
|
+
'gpt-5-mini-2025-08-07',
|
|
8
|
+
'gpt-5-2025-08-07',
|
|
9
|
+
'gpt-4o-mini-2024-07-18',
|
|
10
|
+
'gpt-4o',
|
|
11
|
+
'gpt-4o-2024-11-20',
|
|
12
|
+
'gpt-4-turbo',
|
|
13
|
+
'gpt-3.5-turbo'
|
|
14
|
+
],
|
|
15
|
+
defaultModel: 'gpt-5-mini-2025-08-07'
|
|
16
|
+
};
|
|
17
|
+
export const openaiModelConfigs = {
|
|
18
|
+
'gpt-5-nano-2025-08-07': {
|
|
19
|
+
name: 'GPT-5 Nano',
|
|
20
|
+
contextWindow: 128000,
|
|
21
|
+
pricing: { inputTokens: 0.00000005, outputTokens: 0.0000004 } // $0.05/$0.40 per 1M tokens
|
|
22
|
+
},
|
|
23
|
+
'gpt-5-mini-2025-08-07': {
|
|
24
|
+
name: 'GPT-5 Mini',
|
|
25
|
+
contextWindow: 128000,
|
|
26
|
+
pricing: { inputTokens: 0.00000025, outputTokens: 0.000002 } // $0.25/$2.00 per 1M tokens
|
|
27
|
+
},
|
|
28
|
+
'gpt-5-2025-08-07': {
|
|
29
|
+
name: 'GPT-5',
|
|
30
|
+
contextWindow: 128000,
|
|
31
|
+
pricing: { inputTokens: 0.00000125, outputTokens: 0.00001 } // $1.25/$10.00 per 1M tokens
|
|
32
|
+
},
|
|
33
|
+
'gpt-4o-mini-2024-07-18': {
|
|
34
|
+
name: 'GPT-4o Mini',
|
|
35
|
+
contextWindow: 128000,
|
|
36
|
+
pricing: { inputTokens: 0.00000015, outputTokens: 0.0000006 } // $0.15/$0.60 per 1M tokens
|
|
37
|
+
},
|
|
38
|
+
'gpt-4o': {
|
|
39
|
+
name: 'GPT-4o',
|
|
40
|
+
contextWindow: 128000,
|
|
41
|
+
pricing: { inputTokens: 0.0000025, outputTokens: 0.00001 } // $2.50/$10.00 per 1M tokens
|
|
42
|
+
},
|
|
43
|
+
'gpt-4o-2024-11-20': {
|
|
44
|
+
name: 'GPT-4o (2024-11-20)',
|
|
45
|
+
contextWindow: 128000,
|
|
46
|
+
pricing: { inputTokens: 0.0000025, outputTokens: 0.00001 } // $2.50/$10.00 per 1M tokens
|
|
47
|
+
},
|
|
48
|
+
'gpt-4-turbo': {
|
|
49
|
+
name: 'GPT-4 Turbo',
|
|
50
|
+
contextWindow: 128000,
|
|
51
|
+
pricing: { inputTokens: 0.00001, outputTokens: 0.00003 } // $10.00/$30.00 per 1M tokens
|
|
52
|
+
},
|
|
53
|
+
'gpt-3.5-turbo': {
|
|
54
|
+
name: 'GPT-3.5 Turbo',
|
|
55
|
+
contextWindow: 16385,
|
|
56
|
+
pricing: { inputTokens: 0.0000005, outputTokens: 0.0000015 } // $0.50/$1.50 per 1M tokens
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
export const openaiProvider = {
|
|
60
|
+
id: 'openai',
|
|
61
|
+
name: 'OpenAI',
|
|
62
|
+
models: openaiModels.models,
|
|
63
|
+
defaultModel: 'gpt-5-mini-2025-08-07',
|
|
64
|
+
modelConfigs: openaiModelConfigs,
|
|
65
|
+
auth: {
|
|
66
|
+
type: 'api_key',
|
|
67
|
+
envVar: 'OPENAI_API_KEY',
|
|
68
|
+
label: 'OpenAI API Key',
|
|
69
|
+
helpUrl: 'https://platform.openai.com/api-keys'
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
export const geminiModels = {
|
|
73
|
+
models: [
|
|
74
|
+
'models/gemini-2.5-pro',
|
|
75
|
+
'models/gemini-2.5-flash',
|
|
76
|
+
'models/gemini-2.5-flash-lite',
|
|
77
|
+
'models/gemini-2.0-flash',
|
|
78
|
+
'models/gemini-2.0-flash-lite'
|
|
79
|
+
],
|
|
80
|
+
defaultModel: 'models/gemini-2.5-flash'
|
|
81
|
+
};
|
|
82
|
+
export const geminiModelConfigs = {
|
|
83
|
+
'models/gemini-2.5-pro': {
|
|
84
|
+
name: 'Gemini 2.5 Pro',
|
|
85
|
+
contextWindow: 2000000,
|
|
86
|
+
pricing: { inputTokens: 0.00000125, outputTokens: 0.00001 } // $1.25/$10.00 per 1M tokens (<=200k prompts)
|
|
87
|
+
},
|
|
88
|
+
'models/gemini-2.5-flash': {
|
|
89
|
+
name: 'Gemini 2.5 Flash',
|
|
90
|
+
contextWindow: 1000000,
|
|
91
|
+
pricing: { inputTokens: 0.0000003, outputTokens: 0.0000025 } // $0.30/$2.50 per 1M tokens
|
|
92
|
+
},
|
|
93
|
+
'models/gemini-2.5-flash-lite': {
|
|
94
|
+
name: 'Gemini 2.5 Flash Lite',
|
|
95
|
+
contextWindow: 1000000,
|
|
96
|
+
pricing: { inputTokens: 0.0000001, outputTokens: 0.0000004 } // $0.10/$0.40 per 1M tokens
|
|
97
|
+
},
|
|
98
|
+
'models/gemini-2.0-flash': {
|
|
99
|
+
name: 'Gemini 2.0 Flash',
|
|
100
|
+
contextWindow: 1000000,
|
|
101
|
+
pricing: { inputTokens: 0.0000001, outputTokens: 0.0000004 } // $0.10/$0.40 per 1M tokens (text/image/video)
|
|
102
|
+
},
|
|
103
|
+
'models/gemini-2.0-flash-lite': {
|
|
104
|
+
name: 'Gemini 2.0 Flash Lite',
|
|
105
|
+
contextWindow: 1000000,
|
|
106
|
+
pricing: { inputTokens: 0.000000075, outputTokens: 0.0000003 } // $0.075/$0.30 per 1M tokens
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
export const geminiProvider = {
|
|
110
|
+
id: 'gemini',
|
|
111
|
+
name: 'Gemini',
|
|
112
|
+
models: geminiModels.models,
|
|
113
|
+
defaultModel: geminiModels.defaultModel,
|
|
114
|
+
modelConfigs: geminiModelConfigs,
|
|
115
|
+
auth: {
|
|
116
|
+
type: 'api_key',
|
|
117
|
+
envVar: 'GEMINI_API_KEY',
|
|
118
|
+
label: 'Gemini API Key',
|
|
119
|
+
helpUrl: 'https://aistudio.google.com/app/apikey'
|
|
120
|
+
},
|
|
121
|
+
baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai/'
|
|
122
|
+
};
|
|
123
|
+
export const cerebrasModels = {
|
|
124
|
+
models: [
|
|
125
|
+
'gpt-oss-120b',
|
|
126
|
+
'qwen-3-coder-480b'
|
|
127
|
+
],
|
|
128
|
+
defaultModel: 'gpt-oss-120b'
|
|
129
|
+
};
|
|
130
|
+
export const cerebrasModelConfigs = {
|
|
131
|
+
'gpt-oss-120b': {
|
|
132
|
+
name: 'GPT OSS 120B',
|
|
133
|
+
contextWindow: 128000,
|
|
134
|
+
pricing: { inputTokens: 0.00000035, outputTokens: 0.00000075 } // $0.35/$0.75 per 1M tokens
|
|
135
|
+
},
|
|
136
|
+
'qwen-3-coder-480b': {
|
|
137
|
+
name: 'Qwen 3 Coder 480B',
|
|
138
|
+
contextWindow: 128000,
|
|
139
|
+
pricing: { inputTokens: 0.000002, outputTokens: 0.000002 } // $2.00/$2.00 per 1M tokens
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
export const cerebrasProvider = {
|
|
143
|
+
id: 'cerebras',
|
|
144
|
+
name: 'Cerebras',
|
|
145
|
+
models: cerebrasModels.models,
|
|
146
|
+
defaultModel: cerebrasModels.defaultModel,
|
|
147
|
+
modelConfigs: cerebrasModelConfigs,
|
|
148
|
+
auth: {
|
|
149
|
+
type: 'api_key',
|
|
150
|
+
envVar: 'CEREBRAS_API_KEY',
|
|
151
|
+
label: 'Cerebras API Key',
|
|
152
|
+
helpUrl: 'https://cloud.cerebras.ai/platform'
|
|
153
|
+
},
|
|
154
|
+
baseURL: 'https://api.cerebras.ai/v1'
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Get model configuration for any provider
|
|
158
|
+
*/
|
|
159
|
+
export function getModelConfig(provider, model) {
|
|
160
|
+
switch (provider) {
|
|
161
|
+
case 'openai':
|
|
162
|
+
return openaiModelConfigs[model] || null;
|
|
163
|
+
case 'gemini':
|
|
164
|
+
return geminiModelConfigs[model] || null;
|
|
165
|
+
case 'cerebras':
|
|
166
|
+
return cerebrasModelConfigs[model] || null;
|
|
167
|
+
default:
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive configuration setup for ProtoAgent
|
|
3
|
+
*/
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import { openaiProvider, geminiProvider, cerebrasProvider } from './providers.js';
|
|
6
|
+
import { saveConfig, getConfigDirectory } from './manager.js';
|
|
7
|
+
/**
|
|
8
|
+
* Run interactive configuration setup
|
|
9
|
+
*/
|
|
10
|
+
export async function setupConfig() {
|
|
11
|
+
console.log('\nš¤ Welcome to ProtoAgent!');
|
|
12
|
+
console.log("Let's set up your model configuration.\n");
|
|
13
|
+
// Step 1: Select provider and model
|
|
14
|
+
const modelChoices = [
|
|
15
|
+
new inquirer.Separator('--- OpenAI Models ---'),
|
|
16
|
+
...openaiProvider.models.map(model => ({
|
|
17
|
+
name: model === openaiProvider.defaultModel ? `${model} (recommended)` : model,
|
|
18
|
+
value: { provider: 'openai', model }
|
|
19
|
+
})),
|
|
20
|
+
new inquirer.Separator('--- Gemini Models ---'),
|
|
21
|
+
...geminiProvider.models.map(model => ({
|
|
22
|
+
name: model === geminiProvider.defaultModel ? `${model} (recommended)` : model,
|
|
23
|
+
value: { provider: 'gemini', model }
|
|
24
|
+
})),
|
|
25
|
+
new inquirer.Separator('--- Cerebras Models ---'),
|
|
26
|
+
...cerebrasProvider.models.map(model => ({
|
|
27
|
+
name: model === cerebrasProvider.defaultModel ? `${model} (recommended)` : model,
|
|
28
|
+
value: { provider: 'cerebras', model }
|
|
29
|
+
}))
|
|
30
|
+
];
|
|
31
|
+
const { selection } = await inquirer.prompt([
|
|
32
|
+
{
|
|
33
|
+
type: 'list',
|
|
34
|
+
name: 'selection',
|
|
35
|
+
message: 'Select a model:',
|
|
36
|
+
choices: modelChoices,
|
|
37
|
+
default: { provider: 'openai', model: openaiProvider.defaultModel }
|
|
38
|
+
}
|
|
39
|
+
]);
|
|
40
|
+
const provider = selection.provider;
|
|
41
|
+
const model = selection.model;
|
|
42
|
+
// Step 2: Get API credentials
|
|
43
|
+
let apiKey = '';
|
|
44
|
+
let credentials = {
|
|
45
|
+
OPENAI_API_KEY: '',
|
|
46
|
+
GEMINI_API_KEY: '',
|
|
47
|
+
CEREBRAS_API_KEY: ''
|
|
48
|
+
};
|
|
49
|
+
if (provider === 'openai') {
|
|
50
|
+
console.log(`\nš ${openaiProvider.auth.label} Setup`);
|
|
51
|
+
console.log("You'll need an API key from OpenAI.");
|
|
52
|
+
console.log(`Get your API key from: ${openaiProvider.auth.helpUrl}`);
|
|
53
|
+
const response = await inquirer.prompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'password',
|
|
56
|
+
name: 'apiKey',
|
|
57
|
+
message: `Enter your ${openaiProvider.auth.label}:`,
|
|
58
|
+
mask: '*',
|
|
59
|
+
validate: (input) => {
|
|
60
|
+
if (!input || input.trim().length === 0) {
|
|
61
|
+
return 'API key is required';
|
|
62
|
+
}
|
|
63
|
+
if (!input.trim().startsWith('sk-')) {
|
|
64
|
+
return 'OpenAI API keys should start with "sk-"';
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
]);
|
|
70
|
+
apiKey = response.apiKey;
|
|
71
|
+
credentials.OPENAI_API_KEY = apiKey;
|
|
72
|
+
}
|
|
73
|
+
else if (provider === 'gemini') {
|
|
74
|
+
console.log(`\nš ${geminiProvider.auth.label} Setup`);
|
|
75
|
+
console.log("You'll need an API key from Gemini.");
|
|
76
|
+
console.log(`Get your API key from: ${geminiProvider.auth.helpUrl}`);
|
|
77
|
+
const response = await inquirer.prompt([
|
|
78
|
+
{
|
|
79
|
+
type: 'password',
|
|
80
|
+
name: 'apiKey',
|
|
81
|
+
message: `Enter your ${geminiProvider.auth.label}:`,
|
|
82
|
+
mask: '*',
|
|
83
|
+
validate: (input) => {
|
|
84
|
+
if (!input || input.trim().length === 0) {
|
|
85
|
+
return 'API key is required';
|
|
86
|
+
}
|
|
87
|
+
// Gemini keys may have different format, so just check non-empty
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
]);
|
|
92
|
+
apiKey = response.apiKey;
|
|
93
|
+
credentials.GEMINI_API_KEY = apiKey;
|
|
94
|
+
}
|
|
95
|
+
else if (provider === 'cerebras') {
|
|
96
|
+
console.log(`\nš ${cerebrasProvider.auth.label} Setup`);
|
|
97
|
+
console.log("You'll need an API key from Cerebras.");
|
|
98
|
+
console.log(`Get your API key from: ${cerebrasProvider.auth.helpUrl}`);
|
|
99
|
+
const response = await inquirer.prompt([
|
|
100
|
+
{
|
|
101
|
+
type: 'password',
|
|
102
|
+
name: 'apiKey',
|
|
103
|
+
message: `Enter your ${cerebrasProvider.auth.label}:`,
|
|
104
|
+
mask: '*',
|
|
105
|
+
validate: (input) => {
|
|
106
|
+
if (!input || input.trim().length === 0) {
|
|
107
|
+
return 'API key is required';
|
|
108
|
+
}
|
|
109
|
+
// Cerebras keys may have different format, so just check non-empty
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
]);
|
|
114
|
+
apiKey = response.apiKey;
|
|
115
|
+
credentials.CEREBRAS_API_KEY = apiKey;
|
|
116
|
+
}
|
|
117
|
+
// Step 3: Confirm configuration
|
|
118
|
+
console.log('\nš Configuration Summary:');
|
|
119
|
+
let providerName = '';
|
|
120
|
+
if (provider === 'openai') {
|
|
121
|
+
providerName = openaiProvider.name;
|
|
122
|
+
}
|
|
123
|
+
else if (provider === 'gemini') {
|
|
124
|
+
providerName = geminiProvider.name;
|
|
125
|
+
}
|
|
126
|
+
else if (provider === 'cerebras') {
|
|
127
|
+
providerName = cerebrasProvider.name;
|
|
128
|
+
}
|
|
129
|
+
console.log(`Provider: ${providerName}`);
|
|
130
|
+
console.log(`Model: ${model}`);
|
|
131
|
+
console.log(`API Key: ${'*'.repeat(Math.min(apiKey.length, 20))}...`);
|
|
132
|
+
const { confirm } = await inquirer.prompt([
|
|
133
|
+
{
|
|
134
|
+
type: 'confirm',
|
|
135
|
+
name: 'confirm',
|
|
136
|
+
message: 'Save this configuration?',
|
|
137
|
+
default: true
|
|
138
|
+
}
|
|
139
|
+
]);
|
|
140
|
+
if (!confirm) {
|
|
141
|
+
console.log('Configuration cancelled.');
|
|
142
|
+
process.exit(0);
|
|
143
|
+
}
|
|
144
|
+
// Step 4: Save configuration
|
|
145
|
+
const config = {
|
|
146
|
+
provider,
|
|
147
|
+
model,
|
|
148
|
+
credentials
|
|
149
|
+
};
|
|
150
|
+
try {
|
|
151
|
+
await saveConfig(config);
|
|
152
|
+
console.log(`\nā
Configuration saved successfully!`);
|
|
153
|
+
console.log(`Config location: ${getConfigDirectory()}/config.json`);
|
|
154
|
+
console.log("\nYou're all set! ProtoAgent is ready to use.\n");
|
|
155
|
+
return config;
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
console.error(`\nā Failed to save configuration: ${error.message}`);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Prompt to reconfigure
|
|
164
|
+
*/
|
|
165
|
+
export async function promptReconfigure() {
|
|
166
|
+
const { reconfigure } = await inquirer.prompt([
|
|
167
|
+
{
|
|
168
|
+
type: 'confirm',
|
|
169
|
+
name: 'reconfigure',
|
|
170
|
+
message: 'Would you like to reconfigure ProtoAgent?',
|
|
171
|
+
default: false
|
|
172
|
+
}
|
|
173
|
+
]);
|
|
174
|
+
return reconfigure;
|
|
175
|
+
}
|