sam-coder-cli 1.0.43 → 1.0.45
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/bin/agi-cli.js +122 -89
- package/package.json +3 -8
- package/MULTIPLAYER.md +0 -112
- package/bin/agi-cli.js.new +0 -328
- package/bin/ai-collaboration.js +0 -175
- package/bin/ai-team.js +0 -234
- package/bin/collaborate.js +0 -48
- package/bin/multiplayer-client.js +0 -905
- package/bin/multiplayer-mode.js +0 -276
- package/bin/multiplayer-server.js +0 -372
package/bin/agi-cli.js
CHANGED
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
const ui = require('./ui.js');
|
|
4
4
|
const readline = require('readline');
|
|
5
5
|
const path = require('path');
|
|
6
|
-
// Import MultiplayerMode at the top level to avoid reference errors
|
|
7
|
-
let MultiplayerMode;
|
|
8
6
|
const os = require('os');
|
|
9
7
|
const fs = require('fs').promises;
|
|
10
8
|
const { exec } = require('child_process');
|
|
11
9
|
const util = require('util');
|
|
12
10
|
const execAsync = util.promisify(exec);
|
|
13
|
-
// Import MultiplayerMode only when needed to avoid circular dependencies
|
|
14
11
|
|
|
15
12
|
// Configuration
|
|
16
13
|
const CONFIG_PATH = path.join(os.homedir(), '.sam-coder-config.json');
|
|
@@ -18,8 +15,42 @@ let OPENROUTER_API_KEY;
|
|
|
18
15
|
let MODEL = 'deepseek/deepseek-chat-v3-0324:free';
|
|
19
16
|
let API_BASE_URL = 'https://openrouter.ai/api/v1';
|
|
20
17
|
|
|
18
|
+
// Tool/Function definitions for the AI
|
|
19
|
+
// Knowledge management functions
|
|
20
|
+
const KNOWLEDGE_FILE = path.join(os.homedir(), '.sam-coder-knowledge.json');
|
|
21
|
+
|
|
22
|
+
async function loadKnowledge() {
|
|
23
|
+
try {
|
|
24
|
+
const data = await fs.readFile(KNOWLEDGE_FILE, 'utf8');
|
|
25
|
+
return JSON.parse(data);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// If file doesn't exist, return empty knowledge
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function saveKnowledge(knowledge) {
|
|
33
|
+
await fs.writeFile(KNOWLEDGE_FILE, JSON.stringify(knowledge, null, 2), 'utf8');
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
// Tool/Function definitions for the AI
|
|
22
37
|
const tools = [
|
|
38
|
+
{
|
|
39
|
+
type: 'function',
|
|
40
|
+
function: {
|
|
41
|
+
name: 'addKnowledge',
|
|
42
|
+
description: 'Add or update knowledge in the knowledge base',
|
|
43
|
+
parameters: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
key: { type: 'string', description: 'Key/identifier for the knowledge' },
|
|
47
|
+
value: { type: 'string', description: 'The knowledge content' },
|
|
48
|
+
description: { type: 'string', description: 'Description of what this knowledge is about' }
|
|
49
|
+
},
|
|
50
|
+
required: ['key', 'value', 'description']
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
23
54
|
{
|
|
24
55
|
type: 'function',
|
|
25
56
|
function: {
|
|
@@ -193,12 +224,19 @@ const tools = [
|
|
|
193
224
|
// System prompt for the AI Assistant when using tool calling
|
|
194
225
|
const TOOL_CALLING_PROMPT = `You are a helpful AI assistant with agency capabilities. You can perform actions on the user's system using the provided tools.
|
|
195
226
|
|
|
227
|
+
KNOWLEDGE MANAGEMENT:
|
|
228
|
+
- You can store and retrieve knowledge using the 'addKnowledge' tool.
|
|
229
|
+
- Use this to remember user preferences, project details, or any other important information.
|
|
230
|
+
- The knowledge will persist across sessions.
|
|
231
|
+
- Example: If the user mentions they prefer Python for all projects, store this preference.
|
|
232
|
+
|
|
196
233
|
TOOLS AVAILABLE:
|
|
197
|
-
1.
|
|
198
|
-
2.
|
|
199
|
-
3.
|
|
200
|
-
4.
|
|
201
|
-
5.
|
|
234
|
+
1. addKnowledge - Add or update knowledge in the knowledge base
|
|
235
|
+
2. readFile - Read the contents of a file
|
|
236
|
+
3. writeFile - Write content to a file
|
|
237
|
+
4. editFile - Edit specific parts of a file
|
|
238
|
+
5. runCommand - Execute a shell command
|
|
239
|
+
6. searchFiles - Search for files using a glob pattern
|
|
202
240
|
|
|
203
241
|
ENVIRONMENT:
|
|
204
242
|
- OS: ${process.platform}
|
|
@@ -358,6 +396,28 @@ const agentUtils = {
|
|
|
358
396
|
}
|
|
359
397
|
};
|
|
360
398
|
|
|
399
|
+
const toolHandlers = {
|
|
400
|
+
addKnowledge: async ({ key, value, description }) => {
|
|
401
|
+
try {
|
|
402
|
+
const knowledge = await loadKnowledge();
|
|
403
|
+
knowledge[key] = {
|
|
404
|
+
value,
|
|
405
|
+
description,
|
|
406
|
+
timestamp: new Date().toISOString()
|
|
407
|
+
};
|
|
408
|
+
await saveKnowledge(knowledge);
|
|
409
|
+
return { success: true, message: `Knowledge '${key}' added successfully` };
|
|
410
|
+
} catch (error) {
|
|
411
|
+
return { success: false, error: error.message };
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
readFile,
|
|
415
|
+
writeFile,
|
|
416
|
+
editFile,
|
|
417
|
+
runCommand,
|
|
418
|
+
searchFiles
|
|
419
|
+
};
|
|
420
|
+
|
|
361
421
|
// Extract JSON from markdown code blocks
|
|
362
422
|
function extractJsonFromMarkdown(text) {
|
|
363
423
|
// Try to find a markdown code block with JSON content
|
|
@@ -431,7 +491,29 @@ async function callOpenRouter(messages, currentModel, useJson = false) {
|
|
|
431
491
|
// Process a query with tool calling
|
|
432
492
|
async function processQueryWithTools(query, conversation = [], currentModel) {
|
|
433
493
|
const userMessage = { role: 'user', content: query };
|
|
434
|
-
|
|
494
|
+
let messages = [...conversation, userMessage];
|
|
495
|
+
|
|
496
|
+
// Add system message with knowledge if this is the first message
|
|
497
|
+
if (conversation.length === 0) {
|
|
498
|
+
// Load knowledge and include it in the system prompt
|
|
499
|
+
const knowledge = await loadKnowledge();
|
|
500
|
+
let systemPrompt = TOOL_CALLING_PROMPT;
|
|
501
|
+
|
|
502
|
+
// Add knowledge to the system prompt if any exists
|
|
503
|
+
const knowledgeEntries = Object.entries(knowledge);
|
|
504
|
+
if (knowledgeEntries.length > 0) {
|
|
505
|
+
systemPrompt += '\n\nCURRENT KNOWLEDGE BASE:\n';
|
|
506
|
+
systemPrompt += knowledgeEntries.map(([key, { value, description }]) =>
|
|
507
|
+
`- ${key}: ${value} (${description})`
|
|
508
|
+
).join('\n');
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Add system message at the beginning
|
|
512
|
+
messages = [
|
|
513
|
+
{ role: 'system', content: systemPrompt },
|
|
514
|
+
...messages
|
|
515
|
+
];
|
|
516
|
+
}
|
|
435
517
|
|
|
436
518
|
ui.startThinking();
|
|
437
519
|
|
|
@@ -474,12 +556,20 @@ async function processQueryWithTools(query, conversation = [], currentModel) {
|
|
|
474
556
|
async function handleToolCalls(toolCalls, messages) {
|
|
475
557
|
const results = [];
|
|
476
558
|
|
|
559
|
+
// Load knowledge at the start of processing tool calls
|
|
560
|
+
const knowledge = await loadKnowledge();
|
|
561
|
+
|
|
477
562
|
for (const toolCall of toolCalls) {
|
|
478
563
|
const functionName = toolCall.function.name;
|
|
479
564
|
let args;
|
|
480
565
|
|
|
481
566
|
try {
|
|
482
567
|
args = JSON.parse(toolCall.function.arguments);
|
|
568
|
+
|
|
569
|
+
// If we have knowledge that might be relevant, include it in the context
|
|
570
|
+
if (knowledge.defaultLanguage && !args.language) {
|
|
571
|
+
args.language = knowledge.defaultLanguage.value;
|
|
572
|
+
}
|
|
483
573
|
} catch (error) {
|
|
484
574
|
console.error('❌ Failed to parse tool arguments:', error);
|
|
485
575
|
results.push({
|
|
@@ -650,18 +740,28 @@ async function chat(rl, useToolCalling, initialModel) {
|
|
|
650
740
|
if (input.toLowerCase() === '/setup') {
|
|
651
741
|
await runSetup(rl, true);
|
|
652
742
|
console.log('\nSetup complete. Please restart the application to apply changes.');
|
|
653
|
-
rl.
|
|
743
|
+
rl.prompt();
|
|
654
744
|
return;
|
|
655
745
|
}
|
|
656
|
-
|
|
657
|
-
if (input.toLowerCase() === '
|
|
658
|
-
|
|
746
|
+
|
|
747
|
+
if (input.toLowerCase() === '/eraseknowledge') {
|
|
748
|
+
try {
|
|
749
|
+
await fs.unlink(KNOWLEDGE_FILE);
|
|
750
|
+
console.log('✅ All knowledge has been erased.');
|
|
751
|
+
} catch (error) {
|
|
752
|
+
if (error.code === 'ENOENT') {
|
|
753
|
+
console.log('ℹ️ No knowledge to erase.');
|
|
754
|
+
} else {
|
|
755
|
+
console.error('❌ Failed to erase knowledge:', error.message);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
rl.prompt();
|
|
659
759
|
return;
|
|
660
760
|
}
|
|
661
761
|
|
|
662
762
|
const result = useToolCalling
|
|
663
|
-
? await processQueryWithTools(
|
|
664
|
-
: await processQuery(
|
|
763
|
+
? await processQueryWithTools(query, conversation, currentModel)
|
|
764
|
+
: await processQuery(query, conversation, currentModel);
|
|
665
765
|
ui.stopThinking();
|
|
666
766
|
ui.showResponse(result.response);
|
|
667
767
|
|
|
@@ -675,20 +775,10 @@ async function chat(rl, useToolCalling, initialModel) {
|
|
|
675
775
|
});
|
|
676
776
|
}
|
|
677
777
|
|
|
678
|
-
function askForMode(rl
|
|
778
|
+
function askForMode(rl) {
|
|
679
779
|
return new Promise((resolve) => {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
: 'Select mode (1 for tool calling, 2 for function calling): ';
|
|
683
|
-
|
|
684
|
-
rl.question(prompt, (answer) => {
|
|
685
|
-
const choice = answer.trim();
|
|
686
|
-
if (includeMultiplayer) {
|
|
687
|
-
if (choice === '3') resolve('multiplayer');
|
|
688
|
-
else resolve(choice === '1' ? 'tool' : 'function');
|
|
689
|
-
} else {
|
|
690
|
-
resolve(choice === '1');
|
|
691
|
-
}
|
|
780
|
+
rl.question('Select mode (1 for tool calling, 2 for function calling): ', (answer) => {
|
|
781
|
+
resolve(answer.trim() === '1');
|
|
692
782
|
});
|
|
693
783
|
});
|
|
694
784
|
}
|
|
@@ -752,21 +842,6 @@ async function start() {
|
|
|
752
842
|
output: process.stdout
|
|
753
843
|
});
|
|
754
844
|
|
|
755
|
-
// Check for server mode
|
|
756
|
-
if (process.argv.includes('--server')) {
|
|
757
|
-
try {
|
|
758
|
-
const port = parseInt(process.argv[process.argv.indexOf('--port') + 1]) || 8080;
|
|
759
|
-
const MultiplayerServer = require('./multiplayer-server');
|
|
760
|
-
const server = new MultiplayerServer(port);
|
|
761
|
-
await server.start();
|
|
762
|
-
console.log(`Multiplayer server started on ws://localhost:${server.port}`);
|
|
763
|
-
return;
|
|
764
|
-
} catch (error) {
|
|
765
|
-
console.error('Failed to start multiplayer server:', error.message);
|
|
766
|
-
process.exit(1);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
845
|
try {
|
|
771
846
|
let config = await readConfig();
|
|
772
847
|
if (!config || !config.OPENROUTER_API_KEY) {
|
|
@@ -776,62 +851,20 @@ async function start() {
|
|
|
776
851
|
MODEL = config.MODEL || 'deepseek/deepseek-chat-v3-0324:free';
|
|
777
852
|
|
|
778
853
|
OPENROUTER_API_KEY = config.OPENROUTER_API_KEY;
|
|
779
|
-
|
|
780
854
|
if (config.isPro && config.customApiBase) {
|
|
781
855
|
API_BASE_URL = config.customApiBase;
|
|
782
856
|
console.log(`🚀 Using Pro Plan custom endpoint: ${API_BASE_URL}`);
|
|
783
857
|
}
|
|
784
858
|
|
|
785
859
|
ui.showHeader();
|
|
786
|
-
|
|
787
|
-
// Multiplayer mode via CLI flag
|
|
788
|
-
if (process.argv.includes('--multiplayer')) {
|
|
789
|
-
// Lazy load MultiplayerMode to avoid circular dependencies
|
|
790
|
-
if (!MultiplayerMode) {
|
|
791
|
-
MultiplayerMode = require('./multiplayer-mode');
|
|
792
|
-
}
|
|
793
|
-
try {
|
|
794
|
-
const multiplayerMode = new MultiplayerMode({
|
|
795
|
-
rl,
|
|
796
|
-
model: MODEL,
|
|
797
|
-
serverUrl: process.env.MP_SERVER_URL || 'ws://localhost:8080'
|
|
798
|
-
});
|
|
799
|
-
await multiplayerMode.start();
|
|
800
|
-
return;
|
|
801
|
-
} catch (error) {
|
|
802
|
-
console.error('Failed to start multiplayer mode:', error);
|
|
803
|
-
process.exit(1);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
// Standard single-agent mode
|
|
808
860
|
console.log('Select Mode:');
|
|
809
861
|
console.log('1. Tool Calling (for models that support it)');
|
|
810
862
|
console.log('2. Function Calling (legacy)');
|
|
811
|
-
console.log('3. Multiplayer Mode (collaborate with other agents)');
|
|
812
863
|
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
MultiplayerMode = require('./multiplayer-mode');
|
|
818
|
-
}
|
|
819
|
-
try {
|
|
820
|
-
const multiplayerMode = new MultiplayerMode({
|
|
821
|
-
rl,
|
|
822
|
-
model: MODEL,
|
|
823
|
-
serverUrl: process.env.MP_SERVER_URL || 'ws://localhost:8080'
|
|
824
|
-
});
|
|
825
|
-
await multiplayerMode.start();
|
|
826
|
-
} catch (error) {
|
|
827
|
-
console.error('Failed to initialize multiplayer mode:', error);
|
|
828
|
-
process.exit(1);
|
|
829
|
-
}
|
|
830
|
-
} else {
|
|
831
|
-
const useToolCalling = mode === 'tool';
|
|
832
|
-
ui.showResponse(`\nStarting in ${useToolCalling ? 'Tool Calling' : 'Function Calling'} mode...\n`);
|
|
833
|
-
await chat(rl, useToolCalling, MODEL);
|
|
834
|
-
}
|
|
864
|
+
const useToolCalling = await askForMode(rl);
|
|
865
|
+
ui.showResponse(`\nStarting in ${useToolCalling ? 'Tool Calling' : 'Function Calling'} mode...\n`);
|
|
866
|
+
|
|
867
|
+
await chat(rl, useToolCalling, MODEL);
|
|
835
868
|
} catch (error) {
|
|
836
869
|
ui.showError(error);
|
|
837
870
|
rl.close();
|
package/package.json
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sam-coder-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.45",
|
|
4
4
|
"description": "SAM-CODER: An animated command-line AI assistant with agency capabilities.",
|
|
5
5
|
"main": "bin/agi-cli.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"sam-coder": "bin/agi-cli.js"
|
|
8
|
-
"sam-coder-server": "bin/agi-cli.js --server",
|
|
9
|
-
"collaborate": "./bin/collaborate.js"
|
|
7
|
+
"sam-coder": "bin/agi-cli.js"
|
|
10
8
|
},
|
|
11
9
|
"scripts": {
|
|
12
10
|
"start": "node ./bin/agi-cli.js"
|
|
@@ -22,14 +20,11 @@
|
|
|
22
20
|
"license": "MIT",
|
|
23
21
|
"dependencies": {
|
|
24
22
|
"chalk": "^4.1.2",
|
|
25
|
-
"commander": "^11.0.0",
|
|
26
|
-
"node-fetch": "^2.6.7",
|
|
27
23
|
"ora": "^5.4.1",
|
|
28
|
-
"readline": "^1.3.0",
|
|
29
|
-
"uuid": "^9.0.0",
|
|
30
24
|
"ws": "^8.18.3"
|
|
31
25
|
},
|
|
32
26
|
"devDependencies": {
|
|
27
|
+
"@types/vscode": "^1.102.0",
|
|
33
28
|
"eslint": "^7.27.0"
|
|
34
29
|
},
|
|
35
30
|
"engines": {
|
package/MULTIPLAYER.md
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# Multiplayer Mode for SAM-CODER
|
|
2
|
-
|
|
3
|
-
This guide explains how to use the Multiplayer Mode to collaborate with multiple AI agents in real-time.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- Host or join multiplayer sessions
|
|
8
|
-
- Connect 2-4 AI agents in a single session
|
|
9
|
-
- Each agent can have a unique name and role
|
|
10
|
-
- Real-time chat and task coordination
|
|
11
|
-
- Shared work history and task assignment
|
|
12
|
-
- Support for different models/endpoints per agent
|
|
13
|
-
|
|
14
|
-
## Quick Start
|
|
15
|
-
|
|
16
|
-
1. First, install the required dependencies:
|
|
17
|
-
```bash
|
|
18
|
-
npm install
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
2. Start the multiplayer server in a separate terminal:
|
|
22
|
-
```bash
|
|
23
|
-
node bin/multiplayer-server.js
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
3. In a new terminal, start the first agent (host):
|
|
27
|
-
```bash
|
|
28
|
-
node bin/agi-cli.js --multiplayer
|
|
29
|
-
```
|
|
30
|
-
- Press Enter to create a new session
|
|
31
|
-
- Note the session ID shown in the console
|
|
32
|
-
|
|
33
|
-
4. In another terminal, start additional agents (up to 3 more):
|
|
34
|
-
```bash
|
|
35
|
-
node bin/agi-cli.js --multiplayer
|
|
36
|
-
```
|
|
37
|
-
- Enter the session ID from step 3 to join
|
|
38
|
-
|
|
39
|
-
## Multiplayer Commands
|
|
40
|
-
|
|
41
|
-
Once in a multiplayer session, you can use these commands:
|
|
42
|
-
|
|
43
|
-
- `/name [new_name]` - Set or show your agent's name
|
|
44
|
-
- `/role [role]` - Set or show your agent's role
|
|
45
|
-
- `/work [description]` - Update your work status
|
|
46
|
-
- `/task [agent_name] [task]` - Assign a task to another agent
|
|
47
|
-
- `/list` - List all agents in the session
|
|
48
|
-
- `/help` - Show available commands
|
|
49
|
-
- `/exit` - Leave the session
|
|
50
|
-
|
|
51
|
-
## Agent Coordination
|
|
52
|
-
|
|
53
|
-
### Work History
|
|
54
|
-
- All agents can see updates to the shared work history
|
|
55
|
-
- Use `/work` to update what you're working on
|
|
56
|
-
- The work history helps agents coordinate and avoid duplicate work
|
|
57
|
-
|
|
58
|
-
### Task Assignment
|
|
59
|
-
- Use `/task` to assign specific tasks to other agents
|
|
60
|
-
- Example: `/task Coder1 Implement the login function`
|
|
61
|
-
- Assigned tasks appear in the target agent's console
|
|
62
|
-
|
|
63
|
-
### Chat
|
|
64
|
-
- Type any message to send it to all agents in the session
|
|
65
|
-
- Use this to coordinate, ask questions, or share information
|
|
66
|
-
|
|
67
|
-
## Advanced Usage
|
|
68
|
-
|
|
69
|
-
### Custom Server URL
|
|
70
|
-
By default, the client connects to `ws://localhost:8080`. To use a different server:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
MP_SERVER_URL=ws://your-server-address:port node bin/agi-cli.js --multiplayer
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Different Models per Agent
|
|
77
|
-
Each agent can use a different model by setting the `MODEL` environment variable:
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
MODEL=anthropic/claude-2 node bin/agi-cli.js --multiplayer
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Troubleshooting
|
|
84
|
-
|
|
85
|
-
### Connection Issues
|
|
86
|
-
- Ensure the multiplayer server is running
|
|
87
|
-
- Check that the server URL is correct
|
|
88
|
-
- Verify that your firewall allows WebSocket connections on the specified port
|
|
89
|
-
|
|
90
|
-
### Session Full
|
|
91
|
-
- Each session supports up to 4 agents
|
|
92
|
-
- Create a new session if you need more agents
|
|
93
|
-
|
|
94
|
-
### Agent Names
|
|
95
|
-
- Agent names must be unique within a session
|
|
96
|
-
- Use `/name` to change your agent's name if needed
|
|
97
|
-
|
|
98
|
-
## Example Workflow
|
|
99
|
-
|
|
100
|
-
1. Agent 1 creates a session and becomes the host
|
|
101
|
-
2. Agent 2 joins the session with `/join <session-id>`
|
|
102
|
-
3. Agents assign roles:
|
|
103
|
-
- Agent 1: `/role Backend Developer`
|
|
104
|
-
- Agent 2: `/role Frontend Developer`
|
|
105
|
-
4. They coordinate work:
|
|
106
|
-
- Agent 1: `/work Implementing user authentication API`
|
|
107
|
-
- Agent 2: `/work Creating login form UI`
|
|
108
|
-
5. They can assign tasks to each other:
|
|
109
|
-
- Agent 1: `/task Frontend Add form validation`
|
|
110
|
-
- Agent 2: `/task Backend Add rate limiting to auth endpoint`
|
|
111
|
-
|
|
112
|
-
Enjoy collaborating with multiple AI agents in real-time!
|