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 +12 -115
- package/package.json +1 -1
- package/foldersnake/snake_game.py +0 -218
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.
|
|
235
|
-
2.
|
|
236
|
-
3.
|
|
237
|
-
4.
|
|
238
|
-
5.
|
|
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
|
-
|
|
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.
|
|
650
|
+
rl.close();
|
|
744
651
|
return;
|
|
745
652
|
}
|
|
746
|
-
|
|
747
|
-
if (input.toLowerCase() === '
|
|
748
|
-
|
|
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(
|
|
764
|
-
: await processQuery(
|
|
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,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()
|