sam-coder-cli 1.0.45 → 1.0.46

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
@@ -15,42 +15,8 @@ let OPENROUTER_API_KEY;
15
15
  let MODEL = 'deepseek/deepseek-chat-v3-0324:free';
16
16
  let API_BASE_URL = 'https://openrouter.ai/api/v1';
17
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
-
36
18
  // Tool/Function definitions for the AI
37
19
  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
- },
54
20
  {
55
21
  type: 'function',
56
22
  function: {
@@ -224,19 +190,12 @@ const tools = [
224
190
  // System prompt for the AI Assistant when using tool calling
225
191
  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.
226
192
 
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
-
233
193
  TOOLS AVAILABLE:
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
194
+ 1. readFile - Read the contents of a file
195
+ 2. writeFile - Write content to a file
196
+ 3. editFile - Edit specific parts of a file
197
+ 4. runCommand - Execute a shell command
198
+ 5. searchFiles - Search for files using a glob pattern
240
199
 
241
200
  ENVIRONMENT:
242
201
  - OS: ${process.platform}
@@ -396,28 +355,6 @@ const agentUtils = {
396
355
  }
397
356
  };
398
357
 
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
-
421
358
  // Extract JSON from markdown code blocks
422
359
  function extractJsonFromMarkdown(text) {
423
360
  // Try to find a markdown code block with JSON content
@@ -491,29 +428,7 @@ async function callOpenRouter(messages, currentModel, useJson = false) {
491
428
  // Process a query with tool calling
492
429
  async function processQueryWithTools(query, conversation = [], currentModel) {
493
430
  const userMessage = { role: 'user', content: query };
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
- }
431
+ const messages = [...conversation, userMessage];
517
432
 
518
433
  ui.startThinking();
519
434
 
@@ -556,20 +471,12 @@ async function processQueryWithTools(query, conversation = [], currentModel) {
556
471
  async function handleToolCalls(toolCalls, messages) {
557
472
  const results = [];
558
473
 
559
- // Load knowledge at the start of processing tool calls
560
- const knowledge = await loadKnowledge();
561
-
562
474
  for (const toolCall of toolCalls) {
563
475
  const functionName = toolCall.function.name;
564
476
  let args;
565
477
 
566
478
  try {
567
479
  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
- }
573
480
  } catch (error) {
574
481
  console.error('❌ Failed to parse tool arguments:', error);
575
482
  results.push({
@@ -740,28 +647,18 @@ async function chat(rl, useToolCalling, initialModel) {
740
647
  if (input.toLowerCase() === '/setup') {
741
648
  await runSetup(rl, true);
742
649
  console.log('\nSetup complete. Please restart the application to apply changes.');
743
- rl.prompt();
650
+ rl.close();
744
651
  return;
745
652
  }
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();
653
+
654
+ if (input.toLowerCase() === 'exit') {
655
+ rl.close();
759
656
  return;
760
657
  }
761
658
 
762
659
  const result = useToolCalling
763
- ? await processQueryWithTools(query, conversation, currentModel)
764
- : await processQuery(query, conversation, currentModel);
660
+ ? await processQueryWithTools(input, conversation, currentModel)
661
+ : await processQuery(input, conversation, currentModel);
765
662
  ui.stopThinking();
766
663
  ui.showResponse(result.response);
767
664
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sam-coder-cli",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
4
4
  "description": "SAM-CODER: An animated command-line AI assistant with agency capabilities.",
5
5
  "main": "bin/agi-cli.js",
6
6
  "bin": {
@@ -1,218 +0,0 @@
1
- import pygame
2
- import random
3
-
4
- # Initialize pygame
5
- pygame.init()
6
-
7
- # Constants
8
- SCREEN_WIDTH = 300
9
- SCREEN_HEIGHT = 600
10
- BLOCK_SIZE = 30
11
- GRID_WIDTH = 10
12
- GRID_HEIGHT = 20
13
- GAME_AREA_LEFT = (SCREEN_WIDTH - GRID_WIDTH * BLOCK_SIZE) // 2
14
- GAME_AREA_TOP = SCREEN_HEIGHT - GRID_HEIGHT * BLOCK_SIZE
15
-
16
- # Colors
17
- BLACK = (0, 0, 0)
18
- WHITE = (255, 255, 255)
19
- GRAY = (128, 128, 128)
20
- COLORS = [
21
- (0, 255, 255), # Cyan (I)
22
- (0, 0, 255), # Blue (J)
23
- (255, 165, 0), # Orange (L)
24
- (255, 255, 0), # Yellow (O)
25
- (0, 255, 0), # Green (S)
26
- (128, 0, 128), # Purple (T)
27
- (255, 0, 0) # Red (Z)
28
- ]
29
-
30
- # Tetrimino shapes
31
- SHAPES = [
32
- [[1, 1, 1, 1]], # I
33
- [[1, 0, 0], [1, 1, 1]], # J
34
- [[0, 0, 1], [1, 1, 1]], # L
35
- [[1, 1], [1, 1]], # O
36
- [[0, 1, 1], [1, 1, 0]], # S
37
- [[0, 1, 0], [1, 1, 1]], # T
38
- [[1, 1, 0], [0, 1, 1]] # Z
39
- ]
40
-
41
- # Set up the display
42
- screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
43
- pygame.display.set_caption("Tetris")
44
-
45
- clock = pygame.time.Clock()
46
-
47
- # Game variables
48
- grid = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
49
- current_piece = None
50
- next_piece = None
51
- current_x = GRID_WIDTH // 2
52
- current_y = 0
53
- score = 0
54
- game_over = False
55
- fall_time = 0
56
- fall_speed = 0.5 # seconds
57
-
58
- def new_piece():
59
- global current_piece, next_piece, current_x, current_y
60
- if next_piece is None:
61
- next_piece = random.randint(0, len(SHAPES) - 1)
62
- current_piece = next_piece
63
- next_piece = random.randint(0, len(SHAPES) - 1)
64
- current_x = GRID_WIDTH // 2 - len(SHAPES[current_piece][0]) // 2
65
- current_y = 0
66
- if check_collision():
67
- return False
68
- return True
69
-
70
- def check_collision():
71
- for y, row in enumerate(SHAPES[current_piece]):
72
- for x, cell in enumerate(row):
73
- if cell:
74
- if (current_y + y >= GRID_HEIGHT or
75
- current_x + x < 0 or
76
- current_x + x >= GRID_WIDTH or
77
- grid[current_y + y][current_x + x]):
78
- return True
79
- return False
80
-
81
- def merge_piece():
82
- for y, row in enumerate(SHAPES[current_piece]):
83
- for x, cell in enumerate(row):
84
- if cell:
85
- grid[current_y + y][current_x + x] = current_piece + 1
86
-
87
- def clear_lines():
88
- global grid, score
89
- lines_cleared = 0
90
- for y in range(GRID_HEIGHT - 1, -1, -1):
91
- if all(grid[y]):
92
- lines_cleared += 1
93
- for y2 in range(y, 0, -1):
94
- grid[y2] = grid[y2 - 1][:]
95
- grid[0] = [0] * GRID_WIDTH
96
- score += lines_cleared ** 2 * 100
97
-
98
- def draw_grid():
99
- for y in range(GRID_HEIGHT):
100
- for x in range(GRID_WIDTH):
101
- if grid[y][x]:
102
- pygame.draw.rect(
103
- screen, COLORS[grid[y][x] - 1],
104
- (GAME_AREA_LEFT + x * BLOCK_SIZE, GAME_AREA_TOP + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
105
- )
106
- pygame.draw.rect(
107
- screen, WHITE,
108
- (GAME_AREA_LEFT + x * BLOCK_SIZE, GAME_AREA_TOP + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
109
- 1
110
- )
111
-
112
- def draw_piece():
113
- for y, row in enumerate(SHAPES[current_piece]):
114
- for x, cell in enumerate(row):
115
- if cell:
116
- pygame.draw.rect(
117
- screen, COLORS[current_piece],
118
- (GAME_AREA_LEFT + (current_x + x) * BLOCK_SIZE, GAME_AREA_TOP + (current_y + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
119
- )
120
- pygame.draw.rect(
121
- screen, WHITE,
122
- (GAME_AREA_LEFT + (current_x + x) * BLOCK_SIZE, GAME_AREA_TOP + (current_y + y) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
123
- 1
124
- )
125
-
126
- def draw_next_piece():
127
- if next_piece is not None:
128
- font = pygame.font.SysFont(None, 24)
129
- text = font.render("Next:", True, WHITE)
130
- screen.blit(text, (20, 20))
131
- for y, row in enumerate(SHAPES[next_piece]):
132
- for x, cell in enumerate(row):
133
- if cell:
134
- pygame.draw.rect(
135
- screen, COLORS[next_piece],
136
- (40 + x * BLOCK_SIZE, 50 + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
137
- )
138
- pygame.draw.rect(
139
- screen, WHITE,
140
- (40 + x * BLOCK_SIZE, 50 + y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE),
141
- 1
142
- )
143
-
144
- def draw_score():
145
- font = pygame.font.SysFont(None, 36)
146
- text = font.render(f"Score: {score}", True, WHITE)
147
- screen.blit(text, (20, SCREEN_HEIGHT - 50))
148
-
149
- def rotate_piece():
150
- global current_piece
151
- rotated = list(zip(*reversed(SHAPES[current_piece])))
152
- for y in range(len(rotated)):
153
- rotated[y] = list(rotated[y])
154
- old_shape = SHAPES[current_piece]
155
- SHAPES[current_piece] = rotated
156
- if check_collision():
157
- SHAPES[current_piece] = old_shape
158
-
159
- # Main game loop
160
- new_piece()
161
- running = True
162
- while running:
163
- screen.fill(BLACK)
164
- fall_time += clock.get_rawtime() / 1000 # Convert to seconds
165
- clock.tick()
166
-
167
- if fall_time >= fall_speed:
168
- fall_time = 0
169
- current_y += 1
170
- if check_collision():
171
- current_y -= 1
172
- merge_piece()
173
- clear_lines()
174
- if not new_piece():
175
- game_over = True
176
-
177
- for event in pygame.event.get():
178
- if event.type == pygame.QUIT:
179
- running = False
180
- if event.type == pygame.KEYDOWN:
181
- if event.key == pygame.K_LEFT:
182
- current_x -= 1
183
- if check_collision():
184
- current_x += 1
185
- if event.key == pygame.K_RIGHT:
186
- current_x += 1
187
- if check_collision():
188
- current_x -= 1
189
- if event.key == pygame.K_DOWN:
190
- current_y += 1
191
- if check_collision():
192
- current_y -= 1
193
- if event.key == pygame.K_UP:
194
- rotate_piece()
195
- if event.key == pygame.K_SPACE:
196
- while not check_collision():
197
- current_y += 1
198
- current_y -= 1
199
- merge_piece()
200
- clear_lines()
201
- if not new_piece():
202
- game_over = True
203
-
204
- draw_grid()
205
- draw_piece()
206
- draw_next_piece()
207
- draw_score()
208
- pygame.display.update()
209
-
210
- if game_over:
211
- font = pygame.font.SysFont(None, 48)
212
- text = font.render("GAME OVER", True, WHITE)
213
- screen.blit(text, (SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 - 24))
214
- pygame.display.update()
215
- pygame.time.wait(2000)
216
- running = False
217
-
218
- pygame.quit()