sam-coder-cli 1.0.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.
Files changed (43) hide show
  1. package/README.md +59 -0
  2. package/ai-assistant-0.0.1.vsix +0 -0
  3. package/bin/agi-cli.js +815 -0
  4. package/bin/agi-cli.js.bak +352 -0
  5. package/bin/agi-cli.js.new +328 -0
  6. package/bin/config.json +3 -0
  7. package/bin/ui.js +42 -0
  8. package/dist/agentUtils.js +539 -0
  9. package/dist/agentUtils.js.map +1 -0
  10. package/dist/aiAssistantViewProvider.js +2098 -0
  11. package/dist/aiAssistantViewProvider.js.map +1 -0
  12. package/dist/extension.js +117 -0
  13. package/dist/extension.js.map +1 -0
  14. package/dist/fetch-polyfill.js +9 -0
  15. package/dist/fetch-polyfill.js.map +1 -0
  16. package/foldersnake/snake_game.py +125 -0
  17. package/media/ai-icon.png +0 -0
  18. package/media/ai-icon.svg +5 -0
  19. package/media/infinity-icon.svg +4 -0
  20. package/out/agentUtils.d.ts +28 -0
  21. package/out/agentUtils.d.ts.map +1 -0
  22. package/out/agentUtils.js +539 -0
  23. package/out/agentUtils.js.map +1 -0
  24. package/out/aiAssistantViewProvider.d.ts +58 -0
  25. package/out/aiAssistantViewProvider.d.ts.map +1 -0
  26. package/out/aiAssistantViewProvider.js +2098 -0
  27. package/out/aiAssistantViewProvider.js.map +1 -0
  28. package/out/extension.d.ts +4 -0
  29. package/out/extension.d.ts.map +1 -0
  30. package/out/extension.js +117 -0
  31. package/out/extension.js.map +1 -0
  32. package/out/fetch-polyfill.d.ts +11 -0
  33. package/out/fetch-polyfill.d.ts.map +1 -0
  34. package/out/fetch-polyfill.js +9 -0
  35. package/out/fetch-polyfill.js.map +1 -0
  36. package/package.json +31 -0
  37. package/src/agentUtils.ts +583 -0
  38. package/src/aiAssistantViewProvider.ts +2264 -0
  39. package/src/cliAgentUtils.js +73 -0
  40. package/src/extension.ts +112 -0
  41. package/src/fetch-polyfill.ts +11 -0
  42. package/tsconfig.json +24 -0
  43. package/webpack.config.js +45 -0
@@ -0,0 +1,352 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fetch = require('node-fetch');
4
+ const readline = require('readline');
5
+ const path = require('path');
6
+ const { CLIAgentUtils } = require('../src/cliAgentUtils');
7
+
8
+ // Initialize CLIAgentUtils
9
+ const agentUtils = new CLIAgentUtils();
10
+
11
+ // OpenRouter configuration
12
+ const OPENROUTER_API_KEY = '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';
13
+ const MODEL = 'deepseek/deepseek-chat-v3-0324:free';
14
+ const API_BASE_URL = 'https://openrouter.ai/api/v1';
15
+
16
+ // System prompt matching the VS Code extension
17
+ const SYSTEM_PROMPT = `You are a VS Code AI Assistant with agency capabilities. You can perform actions on the user's workspace.
18
+
19
+ ENVIRONMENT CONTEXT:
20
+ - OS: ${process.platform}
21
+ - Working Directory: ${process.cwd()}
22
+
23
+ When you need to perform actions, respond with JSON in the following format:
24
+ \`\`\`json
25
+ {
26
+ "thoughts": "Your reasoning about what needs to be done",
27
+ "actions": [
28
+ {
29
+ "type": "read|write|search|command|analyze|execute|stop",
30
+ "data": { ... action specific data ... }
31
+ }
32
+ ]
33
+ }
34
+ \`\`\`
35
+
36
+ Action types and their data:
37
+ - read: { "path": "relative/or/absolute/path" }
38
+ - write: { "path": "relative/or/absolute/path", "content": "file content" }
39
+ - search: { "type": "files", "pattern": "glob pattern" } or { "type": "text", "text": "search text" }
40
+ - command: { "command": "command string to execute in terminal" }
41
+ - execute: { "language": "js|python|bash|...", "code": "code to execute" }
42
+ - analyze: { "code": "code to analyze", "question": "what you want to analyze" }
43
+ - browse: { "query": "search query", "numResults": 5 } (free web search using DuckDuckGo, optional numResults)
44
+ - edit: {
45
+ "path": "relative/or/absolute/path",
46
+ "edits": {
47
+ "operations": [
48
+ { "type": "replace", "startLine": 10, "endLine": 15, "newText": "new code here" },
49
+ { "type": "replace", "pattern": "oldFunction\\(\\)", "replacement": "newFunction()", "flags": "g" },
50
+ { "type": "insert", "line": 20, "text": "new line of code here" },
51
+ { "type": "insert", "position": "start", "text": "// Header comment" },
52
+ { "type": "insert", "position": "end", "text": "// Footer comment" },
53
+ { "type": "delete", "startLine": 25, "endLine": 30 }
54
+ ]
55
+ }
56
+ } (edit specific parts of an existing file)
57
+ - stop: {} (use this to indicate you're done with the task and no more actions are needed)
58
+
59
+ By default, you will continue to take actions in a loop until you decide to stop with the 'stop' action type.
60
+ Always wrap your JSON in markdown code blocks with the json language specifier.
61
+ When executing code or commands that might be potentially harmful, explain what the code does before executing it.`;
62
+
63
+ async function callOpenRouter(messages, toolCalls = null) {
64
+ const body = {
65
+ model: MODEL,
66
+ messages: messages.map(msg => ({
67
+ role: msg.role,
68
+ content: msg.content || '',
69
+ ...(msg.name && { name: msg.name })
70
+ })),
71
+ ...(!toolCalls && { tools }),
72
+ ...(toolCalls && { tool_calls: toolCalls })
73
+ };
74
+
75
+ // Remove any undefined values
76
+ const cleanBody = JSON.parse(JSON.stringify(body));
77
+
78
+ try {
79
+ console.log('Sending request to OpenRouter API...');
80
+ console.log('Model:', MODEL);
81
+ console.log('Headers:', {
82
+ 'Content-Type': 'application/json',
83
+ 'Authorization': 'Bearer ' + (OPENROUTER_API_KEY ? '***' + OPENROUTER_API_KEY.slice(-4) : 'undefined'),
84
+ 'HTTP-Referer': 'https://github.com/yourusername/agi-cli',
85
+ 'X-Title': 'AGI-CLI'
86
+ });
87
+
88
+ console.log('Request body:', JSON.stringify(cleanBody, null, 2));
89
+
90
+ const response = await fetch(`${API_BASE_URL}/chat/completions`, {
91
+ method: 'POST',
92
+ headers: {
93
+ 'Content-Type': 'application/json',
94
+ 'Authorization': `Bearer ${OPENROUTER_API_KEY}`,
95
+ 'HTTP-Referer': 'https://github.com/yourusername/agi-cli',
96
+ 'X-Title': 'AGI-CLI'
97
+ },
98
+ body: JSON.stringify(cleanBody)
99
+ });
100
+
101
+ console.log('Response status:', response.status, response.statusText);
102
+
103
+ if (!response.ok) {
104
+ let errorText;
105
+ try {
106
+ const errorData = await response.text();
107
+ console.error('Error response body:', errorData);
108
+ const parsedError = JSON.parse(errorData);
109
+ errorText = parsedError.error?.message || JSON.stringify(parsedError);
110
+ } catch (e) {
111
+ errorText = await response.text();
112
+ }
113
+ throw new Error(`API request failed with status ${response.status}: ${errorText}`);
114
+ }
115
+
116
+ const responseData = await response.json();
117
+ console.log('API Response:', JSON.stringify(responseData, null, 2));
118
+ return responseData;
119
+ } catch (error) {
120
+ console.error('Error in callOpenRouter:', error);
121
+ throw new Error(`Failed to call OpenRouter API: ${error.message}`);
122
+ }
123
+ }
124
+
125
+ async function handleToolCalls(toolCalls, messages) {
126
+ const results = [];
127
+
128
+ for (const toolCall of toolCalls) {
129
+ const { name, arguments: args } = toolCall.function;
130
+ let result;
131
+
132
+ try {
133
+ switch (name) {
134
+ case 'readFile':
135
+ result = await agentUtils.readFile(args.path);
136
+ break;
137
+ case 'writeFile':
138
+ await agentUtils.writeFile(args.path, args.content);
139
+
140
+ results.push({
141
+ tool_call_id: toolCall.id,
142
+ role: 'tool',
143
+ name: functionName,
144
+ content: JSON.stringify(result)
145
+ });
146
+ } catch (error) {
147
+ console.error('āŒ Tool execution failed:', error);
148
+
149
+ results.push({
150
+ tool_call_id: toolCall.id,
151
+ role: 'tool',
152
+ name: functionName,
153
+ content: JSON.stringify({ error: error.message })
154
+ });
155
+ }
156
+ }
157
+
158
+ return results;
159
+ }
160
+
161
+ async function extractJsonFromMarkdown(text) {
162
+ // Try to find a markdown code block with JSON content
163
+ const codeBlockRegex = /```json\n([\s\S]*?)\n```/g;
164
+ const match = codeBlockRegex.exec(text);
165
+
166
+ if (match) {
167
+ try {
168
+ return JSON.parse(match[1]);
169
+ } catch (error) {
170
+ console.error('Error parsing JSON from markdown:', error);
171
+ }
172
+ }
173
+
174
+ // If no code block, try to parse the entire text as JSON
175
+ try {
176
+ return JSON.parse(text);
177
+ } catch (error) {
178
+ console.error('Error parsing JSON:', error);
179
+ return null;
180
+ }
181
+ }
182
+
183
+ async function processQuery(query, conversation = []) {
184
+ try {
185
+ // Add user message to conversation
186
+ const userMessage = { role: 'user', content: query };
187
+ const messages = [...conversation, userMessage];
188
+
189
+ // Add system message if this is the first message
190
+ if (conversation.length === 0) {
191
+ messages.unshift({
192
+ role: 'system',
193
+ content: SYSTEM_PROMPT
194
+ });
195
+ }
196
+
197
+ let shouldContinue = true;
198
+ let iteration = 0;
199
+ const maxIterations = 10; // Prevent infinite loops
200
+ let finalResponse = '';
201
+
202
+ while (shouldContinue && iteration < maxIterations) {
203
+ iteration++;
204
+ console.log('šŸ¤– Thinking...');
205
+
206
+ const response = await callOpenRouter(messages);
207
+ const assistantMessage = response.choices[0].message;
208
+
209
+ // Add assistant's message to the conversation
210
+ messages.push(assistantMessage);
211
+
212
+ // Check if the response contains actions
213
+ const actionData = await extractJsonFromMarkdown(assistantMessage.content);
214
+
215
+ if (actionData && actionData.actions && Array.isArray(actionData.actions)) {
216
+ console.log(`šŸ”§ Processing ${actionData.actions.length} actions...`);
217
+ if (actionData.thoughts) {
218
+ console.log(`šŸ’­ ${actionData.thoughts}`);
219
+ }
220
+
221
+ const actionResults = [];
222
+
223
+ for (const action of actionData.actions) {
224
+ console.log(`šŸ› ļø Executing action: ${action.type}`);
225
+
226
+ // Handle stop action
227
+ if (action.type === 'stop') {
228
+ console.log('šŸ›‘ Stop action received, ending action processing');
229
+ shouldContinue = false;
230
+ finalResponse = 'Task completed successfully.';
231
+ break;
232
+ }
233
+
234
+ try {
235
+ let result;
236
+
237
+ switch (action.type) {
238
+ case 'read':
239
+ result = await agentUtils.readFile(action.data.path);
240
+ break;
241
+
242
+ case 'write':
243
+ await agentUtils.writeFile(action.data.path, action.data.content);
244
+ result = `Successfully wrote to ${action.data.path}`;
245
+ break;
246
+
247
+ case 'command':
248
+ result = await agentUtils.runCommand(action.data.command);
249
+ break;
250
+
251
+ case 'search':
252
+ if (action.data.type === 'files') {
253
+ result = await agentUtils.searchFiles(action.data.pattern);
254
+ } else {
255
+ result = 'Text search not yet implemented';
256
+ }
257
+ break;
258
+
259
+ default:
260
+ result = `Action type '${action.type}' is not supported yet.`;
261
+ }
262
+
263
+ actionResults.push({
264
+ type: action.type,
265
+ success: true,
266
+ result: result
267
+ });
268
+
269
+ console.log(`āœ… Action ${action.type} completed successfully`);
270
+
271
+ } catch (error) {
272
+ console.error(`āŒ Action ${action.type} failed:`, error);
273
+ actionResults.push({
274
+ type: action.type,
275
+ success: false,
276
+ error: error.message
277
+ });
278
+ }
279
+ }
280
+
281
+ // Add action results to the conversation
282
+ messages.push({
283
+ role: 'system',
284
+ content: `Action results:\n\`\`\`json\n${JSON.stringify(actionResults, null, 2)}\n\`\`\`\n` +
285
+ `Based on these results, determine what to do next. You can:\n` +
286
+ `1. Continue with more actions by returning a new JSON with "actions" array\n` +
287
+ `2. Stop the iteration by including an action with "type": "stop" if the task is completed\n` +
288
+ `3. Provide a final response to the user with your findings`
289
+ });
290
+
291
+ } else {
292
+ // No actions, this is a regular response
293
+ shouldContinue = false;
294
+ finalResponse = assistantMessage.content;
295
+ }
296
+ }
297
+
298
+ // If we hit max iterations, add a note
299
+ if (iteration >= maxIterations) {
300
+ finalResponse += '\n\nāš ļø Reached maximum number of iterations. Stopping execution.';
301
+ }
302
+
303
+ return {
304
+ response: finalResponse,
305
+ conversation: messages
306
+ };
307
+
308
+ } catch (error) {
309
+ console.error('Error processing query:', error);
310
+ return {
311
+ response: `Error: ${error.message}`,
312
+ conversation
313
+ };
314
+ }
315
+ }
316
+
317
+ async function chat() {
318
+ const conversation = [];
319
+ console.log('Welcome to AGI-CLI. Type your message, or "exit" to quit.');
320
+
321
+ const rl = readline.createInterface({
322
+ input: process.stdin,
323
+ output: process.stdout,
324
+ prompt: '> '
325
+ });
326
+
327
+ rl.prompt();
328
+
329
+ rl.on('line', async (line) => {
330
+ const input = line.trim();
331
+
332
+ if (input.toLowerCase() === 'exit') {
333
+ rl.close();
334
+ return;
335
+ }
336
+
337
+ if (!input) {
338
+ rl.prompt();
339
+ return;
340
+ }
341
+
342
+ const result = await processQuery(input, conversation);
343
+ console.log(result.response);
344
+ rl.prompt();
345
+ }).on('close', () => {
346
+ console.log('Goodbye!');
347
+ process.exit(0);
348
+ });
349
+ }
350
+
351
+ // Start the chat
352
+ chat();
@@ -0,0 +1,328 @@
1
+ #!/usr/bin/env node
2
+
3
+ const readline = require('readline');
4
+ const path = require('path');
5
+ const fs = require('fs').promises;
6
+ const { exec } = require('child_process');
7
+ const util = require('util');
8
+ const execAsync = util.promisify(exec);
9
+
10
+ // Configuration
11
+ const MODEL = 'deepseek/deepseek-chat-v3-0324:free';
12
+ const API_BASE_URL = 'https://openrouter.ai/api/v1';
13
+
14
+ // System prompt matching the VS Code extension
15
+ const SYSTEM_PROMPT = `You are a VS Code AI Assistant with agency capabilities. You can perform actions on the user's workspace.
16
+
17
+ ENVIRONMENT CONTEXT:
18
+ - OS: ${process.platform}
19
+ - Working Directory: ${process.cwd()}
20
+
21
+ When you need to perform actions, respond with JSON in the following format:
22
+ \`\`\`json
23
+ {
24
+ "thoughts": "Your reasoning about what needs to be done",
25
+ "actions": [
26
+ {
27
+ "type": "read|write|search|command|analyze|execute|stop",
28
+ "data": { ... action specific data ... }
29
+ }
30
+ ]
31
+ }
32
+ \`\`\`
33
+
34
+ Action types and their data:
35
+ - read: { "path": "relative/or/absolute/path" }
36
+ - write: { "path": "relative/or/absolute/path", "content": "file content" }
37
+ - search: { "type": "files", "pattern": "glob pattern" } or { "type": "text", "text": "search text" }
38
+ - command: { "command": "command string to execute in terminal" }
39
+ - execute: { "language": "js|python|bash|...", "code": "code to execute" }
40
+ - analyze: { "code": "code to analyze", "question": "what you want to analyze" }
41
+ - browse: { "query": "search query", "numResults": 5 } (free web search using DuckDuckGo, optional numResults)
42
+ - edit: {
43
+ "path": "relative/or/absolute/path",
44
+ "edits": {
45
+ "operations": [
46
+ { "type": "replace", "startLine": 10, "endLine": 15, "newText": "new code here" },
47
+ { "type": "replace", "pattern": "oldFunction\\(\\)", "replacement": "newFunction()", "flags": "g" },
48
+ { "type": "insert", "line": 20, "text": "new line of code here" },
49
+ { "type": "insert", "position": "start", "text": "// Header comment" },
50
+ { "type": "insert", "position": "end", "text": "// Footer comment" },
51
+ { "type": "delete", "startLine": 25, "endLine": 30 }
52
+ ]
53
+ }
54
+ } (edit specific parts of an existing file)
55
+ - stop: {} (use this to indicate you're done with the task and no more actions are needed)
56
+
57
+ By default, you will continue to take actions in a loop until you decide to stop with the 'stop' action type.
58
+ Always wrap your JSON in markdown code blocks with the json language specifier.
59
+ When executing code or commands that might be potentially harmful, explain what the code does before executing it.`;
60
+
61
+ // Agent utilities
62
+ const agentUtils = {
63
+ async readFile(filePath) {
64
+ try {
65
+ const content = await fs.readFile(filePath, 'utf-8');
66
+ return content;
67
+ } catch (error) {
68
+ throw new Error(`Failed to read file ${filePath}: ${error.message}`);
69
+ }
70
+ },
71
+
72
+ async writeFile(filePath, content) {
73
+ try {
74
+ await fs.writeFile(filePath, content, 'utf-8');
75
+ return `Successfully wrote to ${filePath}`;
76
+ } catch (error) {
77
+ throw new Error(`Failed to write to file ${filePath}: ${error.message}`);
78
+ }
79
+ },
80
+
81
+ async runCommand(command) {
82
+ try {
83
+ const { stdout, stderr } = await execAsync(command, { cwd: process.cwd() });
84
+ if (stderr) {
85
+ console.error('Command stderr:', stderr);
86
+ }
87
+ return stdout || 'Command executed successfully (no output)';
88
+ } catch (error) {
89
+ throw new Error(`Command failed: ${error.message}`);
90
+ }
91
+ },
92
+
93
+ async searchFiles(pattern) {
94
+ try {
95
+ const { stdout } = await execAsync(`find . -name "${pattern}"`, { cwd: process.cwd() });
96
+ return stdout || 'No files found';
97
+ } catch (error) {
98
+ throw new Error(`Search failed: ${error.message}`);
99
+ }
100
+ }
101
+ };
102
+
103
+ // Extract JSON from markdown code blocks
104
+ function extractJsonFromMarkdown(text) {
105
+ // Try to find a markdown code block with JSON content
106
+ const codeBlockRegex = /```json\s*([\s\S]*?)\s*```/;
107
+ const match = text.match(codeBlockRegex);
108
+
109
+ if (match) {
110
+ try {
111
+ return JSON.parse(match[1]);
112
+ } catch (error) {
113
+ console.error('Error parsing JSON from markdown:', error);
114
+ }
115
+ }
116
+
117
+ // If no code block, try to parse the entire text as JSON
118
+ try {
119
+ return JSON.parse(text);
120
+ } catch (error) {
121
+ console.error('Error parsing JSON:', error);
122
+ return null;
123
+ }
124
+ }
125
+
126
+ // Call OpenRouter API
127
+ async function callOpenRouter(messages) {
128
+ const apiKey = process.env.OPENROUTER_API_KEY;
129
+
130
+ if (!apiKey) {
131
+ throw new Error('OPENROUTER_API_KEY environment variable is not set');
132
+ }
133
+
134
+ try {
135
+ const response = await fetch(API_BASE_URL + '/chat/completions', {
136
+ method: 'POST',
137
+ headers: {
138
+ 'Content-Type': 'application/json',
139
+ 'Authorization': `Bearer ${apiKey}`,
140
+ 'HTTP-Referer': 'https://github.com/yourusername/agi-cli'
141
+ },
142
+ body: JSON.stringify({
143
+ model: MODEL,
144
+ messages: messages
145
+ })
146
+ });
147
+
148
+ if (!response.ok) {
149
+ const error = await response.json();
150
+ throw new Error(`API error: ${error.error?.message || response.statusText}`);
151
+ }
152
+
153
+ return await response.json();
154
+ } catch (error) {
155
+ console.error('API call failed:', error);
156
+ throw new Error(`Failed to call OpenRouter API: ${error.message}`);
157
+ }
158
+ }
159
+
160
+ // Process a query with action handling
161
+ async function processQuery(query, conversation = []) {
162
+ try {
163
+ // Add user message to conversation
164
+ const userMessage = { role: 'user', content: query };
165
+ const messages = [...conversation, userMessage];
166
+
167
+ // Add system message if this is the first message
168
+ if (conversation.length === 0) {
169
+ messages.unshift({
170
+ role: 'system',
171
+ content: SYSTEM_PROMPT
172
+ });
173
+ }
174
+
175
+ let shouldContinue = true;
176
+ let iteration = 0;
177
+ const maxIterations = 10; // Prevent infinite loops
178
+ let finalResponse = '';
179
+
180
+ while (shouldContinue && iteration < maxIterations) {
181
+ iteration++;
182
+ console.log('šŸ¤– Thinking...');
183
+
184
+ const response = await callOpenRouter(messages);
185
+ const assistantMessage = response.choices[0].message;
186
+
187
+ // Add assistant's message to the conversation
188
+ messages.push(assistantMessage);
189
+
190
+ // Check if the response contains actions
191
+ const actionData = extractJsonFromMarkdown(assistantMessage.content);
192
+
193
+ if (actionData && actionData.actions && Array.isArray(actionData.actions)) {
194
+ console.log(`šŸ”§ Processing ${actionData.actions.length} actions...`);
195
+ if (actionData.thoughts) {
196
+ console.log(`šŸ’­ ${actionData.thoughts}`);
197
+ }
198
+
199
+ const actionResults = [];
200
+
201
+ for (const action of actionData.actions) {
202
+ console.log(`šŸ› ļø Executing action: ${action.type}`);
203
+
204
+ // Handle stop action
205
+ if (action.type === 'stop') {
206
+ console.log('šŸ›‘ Stop action received, ending action processing');
207
+ shouldContinue = false;
208
+ finalResponse = 'Task completed successfully.';
209
+ break;
210
+ }
211
+
212
+ try {
213
+ let result;
214
+
215
+ switch (action.type) {
216
+ case 'read':
217
+ result = await agentUtils.readFile(action.data.path);
218
+ break;
219
+
220
+ case 'write':
221
+ result = await agentUtils.writeFile(action.data.path, action.data.content);
222
+ break;
223
+
224
+ case 'command':
225
+ result = await agentUtils.runCommand(action.data.command);
226
+ break;
227
+
228
+ case 'search':
229
+ if (action.data.type === 'files') {
230
+ result = await agentUtils.searchFiles(action.data.pattern);
231
+ } else {
232
+ result = 'Text search not yet implemented';
233
+ }
234
+ break;
235
+
236
+ default:
237
+ result = `Action type '${action.type}' is not supported yet.`;
238
+ }
239
+
240
+ actionResults.push({
241
+ type: action.type,
242
+ success: true,
243
+ result: result
244
+ });
245
+
246
+ console.log(`āœ… Action ${action.type} completed successfully`);
247
+
248
+ } catch (error) {
249
+ console.error(`āŒ Action ${action.type} failed:`, error);
250
+ actionResults.push({
251
+ type: action.type,
252
+ success: false,
253
+ error: error.message
254
+ });
255
+ }
256
+ }
257
+
258
+ // Add action results to the conversation
259
+ messages.push({
260
+ role: 'system',
261
+ content: `Action results:\n\`\`\`json\n${JSON.stringify(actionResults, null, 2)}\n\`\`\`\n` +
262
+ `Based on these results, determine what to do next. You can:\n` +
263
+ `1. Continue with more actions by returning a new JSON with "actions" array\n` +
264
+ `2. Stop the iteration by including an action with "type": "stop" if the task is completed\n` +
265
+ `3. Provide a final response to the user with your findings`
266
+ });
267
+
268
+ } else {
269
+ // No actions, this is a regular response
270
+ shouldContinue = false;
271
+ finalResponse = assistantMessage.content;
272
+ }
273
+ }
274
+
275
+ // If we hit max iterations, add a note
276
+ if (iteration >= maxIterations) {
277
+ finalResponse += '\n\nāš ļø Reached maximum number of iterations. Stopping execution.';
278
+ }
279
+
280
+ return {
281
+ response: finalResponse,
282
+ conversation: messages
283
+ };
284
+
285
+ } catch (error) {
286
+ console.error('Error processing query:', error);
287
+ return {
288
+ response: `Error: ${error.message}`,
289
+ conversation
290
+ };
291
+ }
292
+ }
293
+
294
+ // Main chat loop
295
+ async function chat() {
296
+ const conversation = [];
297
+ console.log('Welcome to AGI-CLI. Type your message, or "exit" to quit.');
298
+
299
+ const rl = readline.createInterface({
300
+ input: process.stdin,
301
+ output: process.stdout,
302
+ prompt: '> '
303
+ });
304
+
305
+ rl.prompt();
306
+
307
+ rl.on('line', async (input) => {
308
+ if (input.toLowerCase() === 'exit') {
309
+ rl.close();
310
+ return;
311
+ }
312
+
313
+ const result = await processQuery(input, conversation);
314
+ console.log(result.response);
315
+
316
+ // Update conversation with the full context
317
+ conversation.length = 0; // Clear the array
318
+ result.conversation.forEach(msg => conversation.push(msg));
319
+
320
+ rl.prompt();
321
+ }).on('close', () => {
322
+ console.log('Goodbye!');
323
+ process.exit(0);
324
+ });
325
+ }
326
+
327
+ // Start the chat
328
+ chat().catch(console.error);
@@ -0,0 +1,3 @@
1
+ {
2
+ "OPENROUTER_API_KEY": "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"
3
+ }