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 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. readFile - Read the contents of a file
198
- 2. writeFile - Write content to a file
199
- 3. editFile - Edit specific parts of a file
200
- 4. runCommand - Execute a shell command
201
- 5. searchFiles - Search for files using a glob pattern
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
- const messages = [...conversation, userMessage];
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.close();
743
+ rl.prompt();
654
744
  return;
655
745
  }
656
-
657
- if (input.toLowerCase() === 'exit') {
658
- rl.close();
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(input, conversation, currentModel)
664
- : await processQuery(input, conversation, currentModel);
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, includeMultiplayer = false) {
778
+ function askForMode(rl) {
679
779
  return new Promise((resolve) => {
680
- const prompt = includeMultiplayer
681
- ? 'Select mode (1 for tool calling, 2 for function calling, 3 for multiplayer): '
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 mode = await askForMode(rl, true);
814
- if (mode === 'multiplayer') {
815
- // Lazy load MultiplayerMode to avoid circular dependencies
816
- if (!MultiplayerMode) {
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.43",
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!