ak-gemini 2.1.5 → 2.2.1
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/code-agent.js +190 -40
- package/index.cjs +180 -42
- package/package.json +1 -1
- package/types.d.ts +6 -0
package/code-agent.js
CHANGED
|
@@ -19,7 +19,54 @@ import { randomUUID } from 'node:crypto';
|
|
|
19
19
|
|
|
20
20
|
const MAX_OUTPUT_CHARS = 50_000;
|
|
21
21
|
const MAX_FILE_TREE_LINES = 500;
|
|
22
|
-
const IGNORE_DIRS = new Set(['node_modules', '.git', 'dist', 'coverage', '.next', 'build', '__pycache__']);
|
|
22
|
+
const IGNORE_DIRS = new Set(['node_modules', '.git', 'dist', 'coverage', '.next', 'build', '__pycache__', '.venv']);
|
|
23
|
+
|
|
24
|
+
const LANG_CONFIG = {
|
|
25
|
+
javascript: {
|
|
26
|
+
toolDescExecute: 'Execute a given piece of JavaScript code in a Node.js child process. Use this when you already have code to run — e.g., running code from a previous write_code call, re-running a snippet, or executing code the user provided. Use console.log() for output.',
|
|
27
|
+
toolDescWriteAndRun: 'Write a fresh solution from scratch and execute it in one step. Use this when you need to figure out the code AND run it — the autonomous, end-to-end tool for solving problems with code.',
|
|
28
|
+
codeParamDesc: 'JavaScript code to execute. Use console.log() for output. Use import syntax (ES modules).',
|
|
29
|
+
codeRules: `- Your code runs in a Node.js child process with access to all built-in modules
|
|
30
|
+
- IMPORTANT: Your code runs as an ES module (.mjs). Use import syntax, NOT require():
|
|
31
|
+
- import fs from 'fs';
|
|
32
|
+
- import path from 'path';
|
|
33
|
+
- import { execSync } from 'child_process';
|
|
34
|
+
- Use console.log() to produce output — that's how results are returned to you
|
|
35
|
+
- Write efficient scripts that do multiple things per execution when possible
|
|
36
|
+
- For parallel async operations, use Promise.all()
|
|
37
|
+
- Handle errors in your scripts with try/catch so you get useful error messages
|
|
38
|
+
- Top-level await is supported`,
|
|
39
|
+
commentsEnabled: `- Add a JSDoc @fileoverview comment at the top of each script explaining what it does\n- Add brief JSDoc @param comments for any functions you define`,
|
|
40
|
+
commentsDisabled: `- Do NOT write any comments in your code — save tokens. The code should be self-explanatory.`,
|
|
41
|
+
packageLabel: 'Available Packages',
|
|
42
|
+
packageIntro: 'These npm packages are installed and can be imported',
|
|
43
|
+
bashExamples: 'ls, grep, curl, git, npm, cat',
|
|
44
|
+
codeBlockLang: 'javascript',
|
|
45
|
+
execToolSummary: 'Run a given piece of JavaScript code. Use when you already have code to run — e.g., from a previous write_code call, re-running a snippet, or executing user-provided code.',
|
|
46
|
+
writeRunToolSummary: 'Write a fresh solution from scratch and execute it in one step. The autonomous, end-to-end tool for solving problems with code.',
|
|
47
|
+
},
|
|
48
|
+
python: {
|
|
49
|
+
toolDescExecute: 'Execute a given piece of Python code in a child process. Use this when you already have code to run — e.g., running code from a previous write_code call, re-running a snippet, or executing code the user provided. Use print() for output.',
|
|
50
|
+
toolDescWriteAndRun: 'Write a fresh Python solution from scratch and execute it in one step. Use this when you need to figure out the code AND run it — the autonomous, end-to-end tool for solving problems with code.',
|
|
51
|
+
codeParamDesc: 'Python code to execute. Use print() for output.',
|
|
52
|
+
codeRules: `- Your code runs in a Python 3 child process
|
|
53
|
+
- Use print() to produce output — that's how results are returned to you
|
|
54
|
+
- Use standard Python imports (import os, import json, from pathlib import Path, etc.)
|
|
55
|
+
- Write efficient scripts; prefer list comprehensions and built-in functions
|
|
56
|
+
- For async operations, use asyncio
|
|
57
|
+
- Handle errors with try/except so you get useful error messages
|
|
58
|
+
- A virtual environment is active — you can install packages using run_bash with: pip install <package>
|
|
59
|
+
- Installed packages persist across executions in this session`,
|
|
60
|
+
commentsEnabled: `- Add a module-level docstring at the top of each script explaining what it does\n- Add brief docstrings for any functions you define`,
|
|
61
|
+
commentsDisabled: `- Do NOT write any comments in your code — save tokens. The code should be self-explanatory.`,
|
|
62
|
+
packageLabel: 'Available Packages',
|
|
63
|
+
packageIntro: 'These Python packages are available for import',
|
|
64
|
+
bashExamples: 'ls, grep, curl, git, pip, cat',
|
|
65
|
+
codeBlockLang: 'python',
|
|
66
|
+
execToolSummary: 'Run a given piece of Python code. Use when you already have code to run — e.g., from a previous write_code call, re-running a snippet, or executing user-provided code.',
|
|
67
|
+
writeRunToolSummary: 'Write a fresh Python solution from scratch and execute it in one step. The autonomous, end-to-end tool for solving problems with code.',
|
|
68
|
+
}
|
|
69
|
+
};
|
|
23
70
|
|
|
24
71
|
/** Tools that execute code/commands and can fail */
|
|
25
72
|
const EXECUTING_TOOLS = new Set(['execute_code', 'write_and_run_code', 'run_bash']);
|
|
@@ -37,6 +84,8 @@ class CodeAgent extends BaseGemini {
|
|
|
37
84
|
|
|
38
85
|
// ── Agent config ──
|
|
39
86
|
this.workingDirectory = options.workingDirectory || process.cwd();
|
|
87
|
+
this.language = options.language || 'javascript';
|
|
88
|
+
this.pythonPath = options.pythonPath || null;
|
|
40
89
|
this.maxRounds = options.maxRounds || 10;
|
|
41
90
|
this.timeout = options.timeout || 30_000;
|
|
42
91
|
this.onBeforeExecution = options.onBeforeExecution || null;
|
|
@@ -49,6 +98,11 @@ class CodeAgent extends BaseGemini {
|
|
|
49
98
|
this.skills = options.skills || [];
|
|
50
99
|
this.envOverview = options.envOverview || '';
|
|
51
100
|
|
|
101
|
+
// ── Python state (resolved during init) ──
|
|
102
|
+
this._pythonBinary = null;
|
|
103
|
+
this._venvPath = null;
|
|
104
|
+
this._venvEnv = null;
|
|
105
|
+
|
|
52
106
|
// ── Custom tools ──
|
|
53
107
|
this.customTools = (options.tools || []).map(t => ({
|
|
54
108
|
name: t.name,
|
|
@@ -85,6 +139,8 @@ class CodeAgent extends BaseGemini {
|
|
|
85
139
|
* @returns {{ functionDeclarations: Array<Object> }}
|
|
86
140
|
*/
|
|
87
141
|
_buildToolDefinitions() {
|
|
142
|
+
const lang = LANG_CONFIG[this.language] || LANG_CONFIG.javascript;
|
|
143
|
+
|
|
88
144
|
/** @type {Array<Object>} */
|
|
89
145
|
const declarations = [
|
|
90
146
|
{
|
|
@@ -102,11 +158,11 @@ class CodeAgent extends BaseGemini {
|
|
|
102
158
|
},
|
|
103
159
|
{
|
|
104
160
|
name: 'execute_code',
|
|
105
|
-
description:
|
|
161
|
+
description: lang.toolDescExecute,
|
|
106
162
|
parametersJsonSchema: {
|
|
107
163
|
type: 'object',
|
|
108
164
|
properties: {
|
|
109
|
-
code: { type: 'string', description:
|
|
165
|
+
code: { type: 'string', description: lang.codeParamDesc },
|
|
110
166
|
purpose: { type: 'string', description: 'A short 2-4 word slug describing what this script does (e.g., "read-config", "parse-logs").' }
|
|
111
167
|
},
|
|
112
168
|
required: ['code']
|
|
@@ -114,11 +170,11 @@ class CodeAgent extends BaseGemini {
|
|
|
114
170
|
},
|
|
115
171
|
{
|
|
116
172
|
name: 'write_and_run_code',
|
|
117
|
-
description:
|
|
173
|
+
description: lang.toolDescWriteAndRun,
|
|
118
174
|
parametersJsonSchema: {
|
|
119
175
|
type: 'object',
|
|
120
176
|
properties: {
|
|
121
|
-
code: { type: 'string', description:
|
|
177
|
+
code: { type: 'string', description: lang.codeParamDesc },
|
|
122
178
|
purpose: { type: 'string', description: 'A short 2-4 word slug describing what this script does (e.g., "fetch-api-data", "generate-report").' }
|
|
123
179
|
},
|
|
124
180
|
required: ['code']
|
|
@@ -140,7 +196,7 @@ class CodeAgent extends BaseGemini {
|
|
|
140
196
|
},
|
|
141
197
|
{
|
|
142
198
|
name: 'run_bash',
|
|
143
|
-
description:
|
|
199
|
+
description: `Execute a shell command in the working directory. Use this for file operations, git commands, installing packages, or any shell task (e.g., ${lang.bashExamples}). Prefer this over execute_code for simple shell operations.`,
|
|
144
200
|
parametersJsonSchema: {
|
|
145
201
|
type: 'object',
|
|
146
202
|
properties: {
|
|
@@ -189,6 +245,12 @@ class CodeAgent extends BaseGemini {
|
|
|
189
245
|
await this._loadSkills();
|
|
190
246
|
}
|
|
191
247
|
|
|
248
|
+
// Resolve Python and set up venv if needed
|
|
249
|
+
if (this.language === 'python' && (!this._pythonBinary || force)) {
|
|
250
|
+
await this._resolvePython();
|
|
251
|
+
await this._setupVenv();
|
|
252
|
+
}
|
|
253
|
+
|
|
192
254
|
// Rebuild tools (use_skill may now be included)
|
|
193
255
|
this.chatConfig.tools = [this._buildToolDefinitions()];
|
|
194
256
|
|
|
@@ -227,6 +289,73 @@ class CodeAgent extends BaseGemini {
|
|
|
227
289
|
}
|
|
228
290
|
}
|
|
229
291
|
|
|
292
|
+
// ── Python Resolution ───────────────────────────────────────────────────
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Resolve the Python 3 binary path.
|
|
296
|
+
* @private
|
|
297
|
+
*/
|
|
298
|
+
async _resolvePython() {
|
|
299
|
+
const tryBinary = (bin) => new Promise((resolve) => {
|
|
300
|
+
execFile(bin, ['--version'], { timeout: 5000 }, (err, stdout, stderr) => {
|
|
301
|
+
if (err) return resolve(null);
|
|
302
|
+
const output = (stdout || '') + (stderr || '');
|
|
303
|
+
if (output.includes('Python 3.')) return resolve(bin);
|
|
304
|
+
resolve(null);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
if (this.pythonPath) {
|
|
309
|
+
const result = await tryBinary(this.pythonPath);
|
|
310
|
+
if (result) { this._pythonBinary = result; return; }
|
|
311
|
+
throw new Error(`CodeAgent: pythonPath "${this.pythonPath}" is not a valid Python 3 binary.`);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const python3 = await tryBinary('python3');
|
|
315
|
+
if (python3) { this._pythonBinary = python3; return; }
|
|
316
|
+
|
|
317
|
+
const python = await tryBinary('python');
|
|
318
|
+
if (python) { this._pythonBinary = python; return; }
|
|
319
|
+
|
|
320
|
+
throw new Error('CodeAgent: language is "python" but python3 was not found on PATH. Install Python 3 or provide the pythonPath option.');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Create a virtual environment for Python execution.
|
|
325
|
+
* @private
|
|
326
|
+
*/
|
|
327
|
+
async _setupVenv() {
|
|
328
|
+
await mkdir(this.writeDir, { recursive: true });
|
|
329
|
+
this._venvPath = join(this.writeDir, '.venv');
|
|
330
|
+
const isWin = process.platform === 'win32';
|
|
331
|
+
const venvBin = isWin ? join(this._venvPath, 'Scripts') : join(this._venvPath, 'bin');
|
|
332
|
+
const venvPython = join(venvBin, isWin ? 'python.exe' : 'python');
|
|
333
|
+
|
|
334
|
+
// Create venv if it doesn't exist
|
|
335
|
+
try {
|
|
336
|
+
await readFile(venvPython);
|
|
337
|
+
} catch {
|
|
338
|
+
log.debug(`Creating Python venv at ${this._venvPath}`);
|
|
339
|
+
await new Promise((resolve, reject) => {
|
|
340
|
+
execFile(this._pythonBinary, ['-m', 'venv', this._venvPath], {
|
|
341
|
+
timeout: 30_000
|
|
342
|
+
}, (err) => {
|
|
343
|
+
if (err) return reject(new Error(`CodeAgent: failed to create venv: ${err.message}`));
|
|
344
|
+
resolve();
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Build env with venv activated
|
|
350
|
+
const env = Object.assign({}, process.env);
|
|
351
|
+
env.VIRTUAL_ENV = this._venvPath;
|
|
352
|
+
env.PATH = venvBin + (isWin ? ';' : ':') + (process.env.PATH || '');
|
|
353
|
+
this._venvEnv = env;
|
|
354
|
+
this._pythonBinary = venvPython;
|
|
355
|
+
|
|
356
|
+
log.debug(`Python venv ready at ${this._venvPath}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
230
359
|
// ── Context Gathering ────────────────────────────────────────────────────
|
|
231
360
|
|
|
232
361
|
/**
|
|
@@ -248,15 +377,37 @@ class CodeAgent extends BaseGemini {
|
|
|
248
377
|
fileTree = `${truncated}\n... (${lines.length - MAX_FILE_TREE_LINES} more files)`;
|
|
249
378
|
}
|
|
250
379
|
|
|
251
|
-
let
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
380
|
+
let packages = [];
|
|
381
|
+
if (this.language === 'python') {
|
|
382
|
+
try {
|
|
383
|
+
const reqPath = join(this.workingDirectory, 'requirements.txt');
|
|
384
|
+
const content = await readFile(reqPath, 'utf-8');
|
|
385
|
+
packages = content.split('\n')
|
|
386
|
+
.map(l => l.trim())
|
|
387
|
+
.filter(l => l && !l.startsWith('#') && !l.startsWith('-'))
|
|
388
|
+
.map(l => l.split(/[>=<!\[;\s]/)[0]);
|
|
389
|
+
} catch { /* no requirements.txt */ }
|
|
390
|
+
if (packages.length === 0) {
|
|
391
|
+
try {
|
|
392
|
+
const ppPath = join(this.workingDirectory, 'pyproject.toml');
|
|
393
|
+
const content = await readFile(ppPath, 'utf-8');
|
|
394
|
+
const depMatch = content.match(/dependencies\s*=\s*\[([\s\S]*?)\]/);
|
|
395
|
+
if (depMatch) {
|
|
396
|
+
packages = (depMatch[1].match(/"([^"]+)"/g) || [])
|
|
397
|
+
.map(s => s.replace(/"/g, '').split(/[>=<!\[;\s]/)[0]);
|
|
398
|
+
}
|
|
399
|
+
} catch { /* no pyproject.toml */ }
|
|
400
|
+
}
|
|
401
|
+
} else {
|
|
402
|
+
try {
|
|
403
|
+
const pkgPath = join(this.workingDirectory, 'package.json');
|
|
404
|
+
const pkg = JSON.parse(await readFile(pkgPath, 'utf-8'));
|
|
405
|
+
packages = [
|
|
406
|
+
...Object.keys(pkg.dependencies || {}),
|
|
407
|
+
...Object.keys(pkg.devDependencies || {})
|
|
408
|
+
];
|
|
409
|
+
} catch { /* no package.json */ }
|
|
410
|
+
}
|
|
260
411
|
|
|
261
412
|
const importantFileContents = [];
|
|
262
413
|
if (this.importantFiles.length > 0) {
|
|
@@ -277,7 +428,7 @@ class CodeAgent extends BaseGemini {
|
|
|
277
428
|
}
|
|
278
429
|
}
|
|
279
430
|
|
|
280
|
-
this._codebaseContext = { fileTree, npmPackages, importantFileContents };
|
|
431
|
+
this._codebaseContext = { fileTree, npmPackages: packages, packages, importantFileContents };
|
|
281
432
|
this._contextGathered = true;
|
|
282
433
|
}
|
|
283
434
|
|
|
@@ -343,7 +494,8 @@ class CodeAgent extends BaseGemini {
|
|
|
343
494
|
* @private
|
|
344
495
|
*/
|
|
345
496
|
_buildSystemPrompt() {
|
|
346
|
-
const { fileTree,
|
|
497
|
+
const { fileTree, packages, importantFileContents } = this._codebaseContext || { fileTree: '', packages: [], importantFileContents: [] };
|
|
498
|
+
const lang = LANG_CONFIG[this.language] || LANG_CONFIG.javascript;
|
|
347
499
|
|
|
348
500
|
let prompt = `You are a coding agent working in ${this.workingDirectory}.
|
|
349
501
|
|
|
@@ -353,16 +505,16 @@ class CodeAgent extends BaseGemini {
|
|
|
353
505
|
Output code without executing it. Use when showing, proposing, or presenting code to the user.
|
|
354
506
|
|
|
355
507
|
### execute_code
|
|
356
|
-
|
|
508
|
+
${lang.execToolSummary}
|
|
357
509
|
|
|
358
510
|
### write_and_run_code
|
|
359
|
-
|
|
511
|
+
${lang.writeRunToolSummary}
|
|
360
512
|
|
|
361
513
|
### fix_code
|
|
362
514
|
Fix broken code by providing original and fixed versions. Set execute=true to verify the fix works.
|
|
363
515
|
|
|
364
516
|
### run_bash
|
|
365
|
-
Run shell commands directly (e.g.,
|
|
517
|
+
Run shell commands directly (e.g., ${lang.bashExamples}). Prefer this over execute_code for simple shell operations.`;
|
|
366
518
|
|
|
367
519
|
if (this._skillRegistry.size > 0) {
|
|
368
520
|
prompt += `
|
|
@@ -376,36 +528,27 @@ Load a skill by name to get detailed instructions and templates. Available skill
|
|
|
376
528
|
## Code Execution Rules
|
|
377
529
|
These rules apply when using execute_code, write_and_run_code, or fix_code (with execute=true):
|
|
378
530
|
- Always provide a short descriptive \`purpose\` parameter (2-4 word slug like "read-config")
|
|
379
|
-
|
|
380
|
-
- IMPORTANT: Your code runs as an ES module (.mjs). Use import syntax, NOT require():
|
|
381
|
-
- import fs from 'fs';
|
|
382
|
-
- import path from 'path';
|
|
383
|
-
- import { execSync } from 'child_process';
|
|
384
|
-
- Use console.log() to produce output — that's how results are returned to you
|
|
385
|
-
- Write efficient scripts that do multiple things per execution when possible
|
|
386
|
-
- For parallel async operations, use Promise.all()
|
|
387
|
-
- Handle errors in your scripts with try/catch so you get useful error messages
|
|
388
|
-
- Top-level await is supported
|
|
531
|
+
${lang.codeRules}
|
|
389
532
|
- The working directory is: ${this.workingDirectory}`;
|
|
390
533
|
|
|
391
534
|
if (this.comments) {
|
|
392
|
-
prompt += `\n
|
|
535
|
+
prompt += `\n${lang.commentsEnabled}`;
|
|
393
536
|
} else {
|
|
394
|
-
prompt += `\n
|
|
537
|
+
prompt += `\n${lang.commentsDisabled}`;
|
|
395
538
|
}
|
|
396
539
|
|
|
397
540
|
if (fileTree) {
|
|
398
541
|
prompt += `\n\n## File Tree\n\`\`\`\n${fileTree}\n\`\`\``;
|
|
399
542
|
}
|
|
400
543
|
|
|
401
|
-
if (
|
|
402
|
-
prompt += `\n\n##
|
|
544
|
+
if (packages && packages.length > 0) {
|
|
545
|
+
prompt += `\n\n## ${lang.packageLabel}\n${lang.packageIntro}: ${packages.join(', ')}`;
|
|
403
546
|
}
|
|
404
547
|
|
|
405
548
|
if (importantFileContents && importantFileContents.length > 0) {
|
|
406
549
|
prompt += `\n\n## Key Files`;
|
|
407
550
|
for (const { path: filePath, content } of importantFileContents) {
|
|
408
|
-
prompt += `\n\n### ${filePath}\n
|
|
551
|
+
prompt += `\n\n### ${filePath}\n\`\`\`${lang.codeBlockLang}\n${content}\n\`\`\``;
|
|
409
552
|
}
|
|
410
553
|
}
|
|
411
554
|
|
|
@@ -452,16 +595,20 @@ These rules apply when using execute_code, write_and_run_code, or fix_code (with
|
|
|
452
595
|
await mkdir(this.writeDir, { recursive: true });
|
|
453
596
|
|
|
454
597
|
const slug = this._slugify(purpose);
|
|
455
|
-
const
|
|
598
|
+
const ext = this.language === 'python' ? '.py' : '.mjs';
|
|
599
|
+
const tempFile = join(this.writeDir, `agent-${slug}-${Date.now()}${ext}`);
|
|
456
600
|
|
|
457
601
|
try {
|
|
458
602
|
await writeFile(tempFile, code, 'utf-8');
|
|
459
603
|
|
|
604
|
+
const binary = this.language === 'python' ? this._pythonBinary : 'node';
|
|
605
|
+
const execEnv = this.language === 'python' && this._venvEnv ? this._venvEnv : process.env;
|
|
606
|
+
|
|
460
607
|
const result = await new Promise((resolve) => {
|
|
461
|
-
const child = execFile(
|
|
608
|
+
const child = execFile(binary, [tempFile], {
|
|
462
609
|
cwd: this.workingDirectory,
|
|
463
610
|
timeout: this.timeout,
|
|
464
|
-
env:
|
|
611
|
+
env: execEnv,
|
|
465
612
|
maxBuffer: 10 * 1024 * 1024
|
|
466
613
|
}, (err, stdout, stderr) => {
|
|
467
614
|
this._activeProcess = null;
|
|
@@ -531,11 +678,13 @@ These rules apply when using execute_code, write_and_run_code, or fix_code (with
|
|
|
531
678
|
}
|
|
532
679
|
}
|
|
533
680
|
|
|
681
|
+
const execEnv = this.language === 'python' && this._venvEnv ? this._venvEnv : process.env;
|
|
682
|
+
|
|
534
683
|
const result = await new Promise((resolve) => {
|
|
535
684
|
const child = execFile('bash', ['-c', command], {
|
|
536
685
|
cwd: this.workingDirectory,
|
|
537
686
|
timeout: this.timeout,
|
|
538
|
-
env:
|
|
687
|
+
env: execEnv,
|
|
539
688
|
maxBuffer: 10 * 1024 * 1024
|
|
540
689
|
}, (err, stdout, stderr) => {
|
|
541
690
|
this._activeProcess = null;
|
|
@@ -963,8 +1112,9 @@ These rules apply when using execute_code, write_and_run_code, or fix_code (with
|
|
|
963
1112
|
* @returns {Array<{fileName: string, purpose: string|null, script: string, filePath: string|null, tool: string}>}
|
|
964
1113
|
*/
|
|
965
1114
|
dump() {
|
|
1115
|
+
const ext = this.language === 'python' ? '.py' : '.mjs';
|
|
966
1116
|
return this._allExecutions.map((exec, i) => ({
|
|
967
|
-
fileName: exec.purpose ? `agent-${exec.purpose}
|
|
1117
|
+
fileName: exec.purpose ? `agent-${exec.purpose}${ext}` : `script-${i + 1}${ext}`,
|
|
968
1118
|
purpose: exec.purpose || null,
|
|
969
1119
|
script: exec.code,
|
|
970
1120
|
filePath: exec.filePath || null,
|
package/index.cjs
CHANGED
|
@@ -1626,7 +1626,55 @@ var import_node_path = require("node:path");
|
|
|
1626
1626
|
var import_node_crypto = require("node:crypto");
|
|
1627
1627
|
var MAX_OUTPUT_CHARS = 5e4;
|
|
1628
1628
|
var MAX_FILE_TREE_LINES = 500;
|
|
1629
|
-
var IGNORE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "coverage", ".next", "build", "__pycache__"]);
|
|
1629
|
+
var IGNORE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "coverage", ".next", "build", "__pycache__", ".venv"]);
|
|
1630
|
+
var LANG_CONFIG = {
|
|
1631
|
+
javascript: {
|
|
1632
|
+
toolDescExecute: "Execute a given piece of JavaScript code in a Node.js child process. Use this when you already have code to run \u2014 e.g., running code from a previous write_code call, re-running a snippet, or executing code the user provided. Use console.log() for output.",
|
|
1633
|
+
toolDescWriteAndRun: "Write a fresh solution from scratch and execute it in one step. Use this when you need to figure out the code AND run it \u2014 the autonomous, end-to-end tool for solving problems with code.",
|
|
1634
|
+
codeParamDesc: "JavaScript code to execute. Use console.log() for output. Use import syntax (ES modules).",
|
|
1635
|
+
codeRules: `- Your code runs in a Node.js child process with access to all built-in modules
|
|
1636
|
+
- IMPORTANT: Your code runs as an ES module (.mjs). Use import syntax, NOT require():
|
|
1637
|
+
- import fs from 'fs';
|
|
1638
|
+
- import path from 'path';
|
|
1639
|
+
- import { execSync } from 'child_process';
|
|
1640
|
+
- Use console.log() to produce output \u2014 that's how results are returned to you
|
|
1641
|
+
- Write efficient scripts that do multiple things per execution when possible
|
|
1642
|
+
- For parallel async operations, use Promise.all()
|
|
1643
|
+
- Handle errors in your scripts with try/catch so you get useful error messages
|
|
1644
|
+
- Top-level await is supported`,
|
|
1645
|
+
commentsEnabled: `- Add a JSDoc @fileoverview comment at the top of each script explaining what it does
|
|
1646
|
+
- Add brief JSDoc @param comments for any functions you define`,
|
|
1647
|
+
commentsDisabled: `- Do NOT write any comments in your code \u2014 save tokens. The code should be self-explanatory.`,
|
|
1648
|
+
packageLabel: "Available Packages",
|
|
1649
|
+
packageIntro: "These npm packages are installed and can be imported",
|
|
1650
|
+
bashExamples: "ls, grep, curl, git, npm, cat",
|
|
1651
|
+
codeBlockLang: "javascript",
|
|
1652
|
+
execToolSummary: "Run a given piece of JavaScript code. Use when you already have code to run \u2014 e.g., from a previous write_code call, re-running a snippet, or executing user-provided code.",
|
|
1653
|
+
writeRunToolSummary: "Write a fresh solution from scratch and execute it in one step. The autonomous, end-to-end tool for solving problems with code."
|
|
1654
|
+
},
|
|
1655
|
+
python: {
|
|
1656
|
+
toolDescExecute: "Execute a given piece of Python code in a child process. Use this when you already have code to run \u2014 e.g., running code from a previous write_code call, re-running a snippet, or executing code the user provided. Use print() for output.",
|
|
1657
|
+
toolDescWriteAndRun: "Write a fresh Python solution from scratch and execute it in one step. Use this when you need to figure out the code AND run it \u2014 the autonomous, end-to-end tool for solving problems with code.",
|
|
1658
|
+
codeParamDesc: "Python code to execute. Use print() for output.",
|
|
1659
|
+
codeRules: `- Your code runs in a Python 3 child process
|
|
1660
|
+
- Use print() to produce output \u2014 that's how results are returned to you
|
|
1661
|
+
- Use standard Python imports (import os, import json, from pathlib import Path, etc.)
|
|
1662
|
+
- Write efficient scripts; prefer list comprehensions and built-in functions
|
|
1663
|
+
- For async operations, use asyncio
|
|
1664
|
+
- Handle errors with try/except so you get useful error messages
|
|
1665
|
+
- A virtual environment is active \u2014 you can install packages using run_bash with: pip install <package>
|
|
1666
|
+
- Installed packages persist across executions in this session`,
|
|
1667
|
+
commentsEnabled: `- Add a module-level docstring at the top of each script explaining what it does
|
|
1668
|
+
- Add brief docstrings for any functions you define`,
|
|
1669
|
+
commentsDisabled: `- Do NOT write any comments in your code \u2014 save tokens. The code should be self-explanatory.`,
|
|
1670
|
+
packageLabel: "Available Packages",
|
|
1671
|
+
packageIntro: "These Python packages are available for import",
|
|
1672
|
+
bashExamples: "ls, grep, curl, git, pip, cat",
|
|
1673
|
+
codeBlockLang: "python",
|
|
1674
|
+
execToolSummary: "Run a given piece of Python code. Use when you already have code to run \u2014 e.g., from a previous write_code call, re-running a snippet, or executing user-provided code.",
|
|
1675
|
+
writeRunToolSummary: "Write a fresh Python solution from scratch and execute it in one step. The autonomous, end-to-end tool for solving problems with code."
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1630
1678
|
var EXECUTING_TOOLS = /* @__PURE__ */ new Set(["execute_code", "write_and_run_code", "run_bash"]);
|
|
1631
1679
|
var CodeAgent = class extends base_default {
|
|
1632
1680
|
/**
|
|
@@ -1638,6 +1686,8 @@ var CodeAgent = class extends base_default {
|
|
|
1638
1686
|
}
|
|
1639
1687
|
super(options);
|
|
1640
1688
|
this.workingDirectory = options.workingDirectory || process.cwd();
|
|
1689
|
+
this.language = options.language || "javascript";
|
|
1690
|
+
this.pythonPath = options.pythonPath || null;
|
|
1641
1691
|
this.maxRounds = options.maxRounds || 10;
|
|
1642
1692
|
this.timeout = options.timeout || 3e4;
|
|
1643
1693
|
this.onBeforeExecution = options.onBeforeExecution || null;
|
|
@@ -1649,6 +1699,9 @@ var CodeAgent = class extends base_default {
|
|
|
1649
1699
|
this.maxRetries = options.maxRetries ?? 3;
|
|
1650
1700
|
this.skills = options.skills || [];
|
|
1651
1701
|
this.envOverview = options.envOverview || "";
|
|
1702
|
+
this._pythonBinary = null;
|
|
1703
|
+
this._venvPath = null;
|
|
1704
|
+
this._venvEnv = null;
|
|
1652
1705
|
this.customTools = (options.tools || []).map((t) => ({
|
|
1653
1706
|
name: t.name,
|
|
1654
1707
|
description: t.description,
|
|
@@ -1677,6 +1730,7 @@ var CodeAgent = class extends base_default {
|
|
|
1677
1730
|
* @returns {{ functionDeclarations: Array<Object> }}
|
|
1678
1731
|
*/
|
|
1679
1732
|
_buildToolDefinitions() {
|
|
1733
|
+
const lang = LANG_CONFIG[this.language] || LANG_CONFIG.javascript;
|
|
1680
1734
|
const declarations = [
|
|
1681
1735
|
{
|
|
1682
1736
|
name: "write_code",
|
|
@@ -1693,11 +1747,11 @@ var CodeAgent = class extends base_default {
|
|
|
1693
1747
|
},
|
|
1694
1748
|
{
|
|
1695
1749
|
name: "execute_code",
|
|
1696
|
-
description:
|
|
1750
|
+
description: lang.toolDescExecute,
|
|
1697
1751
|
parametersJsonSchema: {
|
|
1698
1752
|
type: "object",
|
|
1699
1753
|
properties: {
|
|
1700
|
-
code: { type: "string", description:
|
|
1754
|
+
code: { type: "string", description: lang.codeParamDesc },
|
|
1701
1755
|
purpose: { type: "string", description: 'A short 2-4 word slug describing what this script does (e.g., "read-config", "parse-logs").' }
|
|
1702
1756
|
},
|
|
1703
1757
|
required: ["code"]
|
|
@@ -1705,11 +1759,11 @@ var CodeAgent = class extends base_default {
|
|
|
1705
1759
|
},
|
|
1706
1760
|
{
|
|
1707
1761
|
name: "write_and_run_code",
|
|
1708
|
-
description:
|
|
1762
|
+
description: lang.toolDescWriteAndRun,
|
|
1709
1763
|
parametersJsonSchema: {
|
|
1710
1764
|
type: "object",
|
|
1711
1765
|
properties: {
|
|
1712
|
-
code: { type: "string", description:
|
|
1766
|
+
code: { type: "string", description: lang.codeParamDesc },
|
|
1713
1767
|
purpose: { type: "string", description: 'A short 2-4 word slug describing what this script does (e.g., "fetch-api-data", "generate-report").' }
|
|
1714
1768
|
},
|
|
1715
1769
|
required: ["code"]
|
|
@@ -1731,7 +1785,7 @@ var CodeAgent = class extends base_default {
|
|
|
1731
1785
|
},
|
|
1732
1786
|
{
|
|
1733
1787
|
name: "run_bash",
|
|
1734
|
-
description:
|
|
1788
|
+
description: `Execute a shell command in the working directory. Use this for file operations, git commands, installing packages, or any shell task (e.g., ${lang.bashExamples}). Prefer this over execute_code for simple shell operations.`,
|
|
1735
1789
|
parametersJsonSchema: {
|
|
1736
1790
|
type: "object",
|
|
1737
1791
|
properties: {
|
|
@@ -1770,6 +1824,10 @@ var CodeAgent = class extends base_default {
|
|
|
1770
1824
|
if (this.skills.length > 0 && (this._skillRegistry.size === 0 || force)) {
|
|
1771
1825
|
await this._loadSkills();
|
|
1772
1826
|
}
|
|
1827
|
+
if (this.language === "python" && (!this._pythonBinary || force)) {
|
|
1828
|
+
await this._resolvePython();
|
|
1829
|
+
await this._setupVenv();
|
|
1830
|
+
}
|
|
1773
1831
|
this.chatConfig.tools = [this._buildToolDefinitions()];
|
|
1774
1832
|
if (!this._contextGathered || force) {
|
|
1775
1833
|
await this._gatherCodebaseContext();
|
|
@@ -1797,6 +1855,70 @@ var CodeAgent = class extends base_default {
|
|
|
1797
1855
|
}
|
|
1798
1856
|
}
|
|
1799
1857
|
}
|
|
1858
|
+
// ── Python Resolution ───────────────────────────────────────────────────
|
|
1859
|
+
/**
|
|
1860
|
+
* Resolve the Python 3 binary path.
|
|
1861
|
+
* @private
|
|
1862
|
+
*/
|
|
1863
|
+
async _resolvePython() {
|
|
1864
|
+
const tryBinary = (bin) => new Promise((resolve2) => {
|
|
1865
|
+
(0, import_node_child_process.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout, stderr) => {
|
|
1866
|
+
if (err) return resolve2(null);
|
|
1867
|
+
const output = (stdout || "") + (stderr || "");
|
|
1868
|
+
if (output.includes("Python 3.")) return resolve2(bin);
|
|
1869
|
+
resolve2(null);
|
|
1870
|
+
});
|
|
1871
|
+
});
|
|
1872
|
+
if (this.pythonPath) {
|
|
1873
|
+
const result = await tryBinary(this.pythonPath);
|
|
1874
|
+
if (result) {
|
|
1875
|
+
this._pythonBinary = result;
|
|
1876
|
+
return;
|
|
1877
|
+
}
|
|
1878
|
+
throw new Error(`CodeAgent: pythonPath "${this.pythonPath}" is not a valid Python 3 binary.`);
|
|
1879
|
+
}
|
|
1880
|
+
const python3 = await tryBinary("python3");
|
|
1881
|
+
if (python3) {
|
|
1882
|
+
this._pythonBinary = python3;
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1885
|
+
const python = await tryBinary("python");
|
|
1886
|
+
if (python) {
|
|
1887
|
+
this._pythonBinary = python;
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
throw new Error('CodeAgent: language is "python" but python3 was not found on PATH. Install Python 3 or provide the pythonPath option.');
|
|
1891
|
+
}
|
|
1892
|
+
/**
|
|
1893
|
+
* Create a virtual environment for Python execution.
|
|
1894
|
+
* @private
|
|
1895
|
+
*/
|
|
1896
|
+
async _setupVenv() {
|
|
1897
|
+
await (0, import_promises2.mkdir)(this.writeDir, { recursive: true });
|
|
1898
|
+
this._venvPath = (0, import_node_path.join)(this.writeDir, ".venv");
|
|
1899
|
+
const isWin = process.platform === "win32";
|
|
1900
|
+
const venvBin = isWin ? (0, import_node_path.join)(this._venvPath, "Scripts") : (0, import_node_path.join)(this._venvPath, "bin");
|
|
1901
|
+
const venvPython = (0, import_node_path.join)(venvBin, isWin ? "python.exe" : "python");
|
|
1902
|
+
try {
|
|
1903
|
+
await (0, import_promises2.readFile)(venvPython);
|
|
1904
|
+
} catch {
|
|
1905
|
+
logger_default.debug(`Creating Python venv at ${this._venvPath}`);
|
|
1906
|
+
await new Promise((resolve2, reject) => {
|
|
1907
|
+
(0, import_node_child_process.execFile)(this._pythonBinary, ["-m", "venv", this._venvPath], {
|
|
1908
|
+
timeout: 3e4
|
|
1909
|
+
}, (err) => {
|
|
1910
|
+
if (err) return reject(new Error(`CodeAgent: failed to create venv: ${err.message}`));
|
|
1911
|
+
resolve2();
|
|
1912
|
+
});
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
const env = Object.assign({}, process.env);
|
|
1916
|
+
env.VIRTUAL_ENV = this._venvPath;
|
|
1917
|
+
env.PATH = venvBin + (isWin ? ";" : ":") + (process.env.PATH || "");
|
|
1918
|
+
this._venvEnv = env;
|
|
1919
|
+
this._pythonBinary = venvPython;
|
|
1920
|
+
logger_default.debug(`Python venv ready at ${this._venvPath}`);
|
|
1921
|
+
}
|
|
1800
1922
|
// ── Context Gathering ────────────────────────────────────────────────────
|
|
1801
1923
|
/**
|
|
1802
1924
|
* @private
|
|
@@ -1815,15 +1937,35 @@ var CodeAgent = class extends base_default {
|
|
|
1815
1937
|
fileTree = `${truncated}
|
|
1816
1938
|
... (${lines.length - MAX_FILE_TREE_LINES} more files)`;
|
|
1817
1939
|
}
|
|
1818
|
-
let
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1940
|
+
let packages = [];
|
|
1941
|
+
if (this.language === "python") {
|
|
1942
|
+
try {
|
|
1943
|
+
const reqPath = (0, import_node_path.join)(this.workingDirectory, "requirements.txt");
|
|
1944
|
+
const content = await (0, import_promises2.readFile)(reqPath, "utf-8");
|
|
1945
|
+
packages = content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#") && !l.startsWith("-")).map((l) => l.split(/[>=<!\[;\s]/)[0]);
|
|
1946
|
+
} catch {
|
|
1947
|
+
}
|
|
1948
|
+
if (packages.length === 0) {
|
|
1949
|
+
try {
|
|
1950
|
+
const ppPath = (0, import_node_path.join)(this.workingDirectory, "pyproject.toml");
|
|
1951
|
+
const content = await (0, import_promises2.readFile)(ppPath, "utf-8");
|
|
1952
|
+
const depMatch = content.match(/dependencies\s*=\s*\[([\s\S]*?)\]/);
|
|
1953
|
+
if (depMatch) {
|
|
1954
|
+
packages = (depMatch[1].match(/"([^"]+)"/g) || []).map((s) => s.replace(/"/g, "").split(/[>=<!\[;\s]/)[0]);
|
|
1955
|
+
}
|
|
1956
|
+
} catch {
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
} else {
|
|
1960
|
+
try {
|
|
1961
|
+
const pkgPath = (0, import_node_path.join)(this.workingDirectory, "package.json");
|
|
1962
|
+
const pkg = JSON.parse(await (0, import_promises2.readFile)(pkgPath, "utf-8"));
|
|
1963
|
+
packages = [
|
|
1964
|
+
...Object.keys(pkg.dependencies || {}),
|
|
1965
|
+
...Object.keys(pkg.devDependencies || {})
|
|
1966
|
+
];
|
|
1967
|
+
} catch {
|
|
1968
|
+
}
|
|
1827
1969
|
}
|
|
1828
1970
|
const importantFileContents = [];
|
|
1829
1971
|
if (this.importantFiles.length > 0) {
|
|
@@ -1843,7 +1985,7 @@ var CodeAgent = class extends base_default {
|
|
|
1843
1985
|
}
|
|
1844
1986
|
}
|
|
1845
1987
|
}
|
|
1846
|
-
this._codebaseContext = { fileTree, npmPackages, importantFileContents };
|
|
1988
|
+
this._codebaseContext = { fileTree, npmPackages: packages, packages, importantFileContents };
|
|
1847
1989
|
this._contextGathered = true;
|
|
1848
1990
|
}
|
|
1849
1991
|
/**
|
|
@@ -1901,7 +2043,8 @@ var CodeAgent = class extends base_default {
|
|
|
1901
2043
|
* @private
|
|
1902
2044
|
*/
|
|
1903
2045
|
_buildSystemPrompt() {
|
|
1904
|
-
const { fileTree,
|
|
2046
|
+
const { fileTree, packages, importantFileContents } = this._codebaseContext || { fileTree: "", packages: [], importantFileContents: [] };
|
|
2047
|
+
const lang = LANG_CONFIG[this.language] || LANG_CONFIG.javascript;
|
|
1905
2048
|
let prompt = `You are a coding agent working in ${this.workingDirectory}.
|
|
1906
2049
|
|
|
1907
2050
|
## Available Tools
|
|
@@ -1910,16 +2053,16 @@ var CodeAgent = class extends base_default {
|
|
|
1910
2053
|
Output code without executing it. Use when showing, proposing, or presenting code to the user.
|
|
1911
2054
|
|
|
1912
2055
|
### execute_code
|
|
1913
|
-
|
|
2056
|
+
${lang.execToolSummary}
|
|
1914
2057
|
|
|
1915
2058
|
### write_and_run_code
|
|
1916
|
-
|
|
2059
|
+
${lang.writeRunToolSummary}
|
|
1917
2060
|
|
|
1918
2061
|
### fix_code
|
|
1919
2062
|
Fix broken code by providing original and fixed versions. Set execute=true to verify the fix works.
|
|
1920
2063
|
|
|
1921
2064
|
### run_bash
|
|
1922
|
-
Run shell commands directly (e.g.,
|
|
2065
|
+
Run shell commands directly (e.g., ${lang.bashExamples}). Prefer this over execute_code for simple shell operations.`;
|
|
1923
2066
|
if (this._skillRegistry.size > 0) {
|
|
1924
2067
|
prompt += `
|
|
1925
2068
|
|
|
@@ -1931,24 +2074,14 @@ Load a skill by name to get detailed instructions and templates. Available skill
|
|
|
1931
2074
|
## Code Execution Rules
|
|
1932
2075
|
These rules apply when using execute_code, write_and_run_code, or fix_code (with execute=true):
|
|
1933
2076
|
- Always provide a short descriptive \`purpose\` parameter (2-4 word slug like "read-config")
|
|
1934
|
-
|
|
1935
|
-
- IMPORTANT: Your code runs as an ES module (.mjs). Use import syntax, NOT require():
|
|
1936
|
-
- import fs from 'fs';
|
|
1937
|
-
- import path from 'path';
|
|
1938
|
-
- import { execSync } from 'child_process';
|
|
1939
|
-
- Use console.log() to produce output \u2014 that's how results are returned to you
|
|
1940
|
-
- Write efficient scripts that do multiple things per execution when possible
|
|
1941
|
-
- For parallel async operations, use Promise.all()
|
|
1942
|
-
- Handle errors in your scripts with try/catch so you get useful error messages
|
|
1943
|
-
- Top-level await is supported
|
|
2077
|
+
${lang.codeRules}
|
|
1944
2078
|
- The working directory is: ${this.workingDirectory}`;
|
|
1945
2079
|
if (this.comments) {
|
|
1946
2080
|
prompt += `
|
|
1947
|
-
|
|
1948
|
-
- Add brief JSDoc @param comments for any functions you define`;
|
|
2081
|
+
${lang.commentsEnabled}`;
|
|
1949
2082
|
} else {
|
|
1950
2083
|
prompt += `
|
|
1951
|
-
|
|
2084
|
+
${lang.commentsDisabled}`;
|
|
1952
2085
|
}
|
|
1953
2086
|
if (fileTree) {
|
|
1954
2087
|
prompt += `
|
|
@@ -1958,11 +2091,11 @@ These rules apply when using execute_code, write_and_run_code, or fix_code (with
|
|
|
1958
2091
|
${fileTree}
|
|
1959
2092
|
\`\`\``;
|
|
1960
2093
|
}
|
|
1961
|
-
if (
|
|
2094
|
+
if (packages && packages.length > 0) {
|
|
1962
2095
|
prompt += `
|
|
1963
2096
|
|
|
1964
|
-
##
|
|
1965
|
-
|
|
2097
|
+
## ${lang.packageLabel}
|
|
2098
|
+
${lang.packageIntro}: ${packages.join(", ")}`;
|
|
1966
2099
|
}
|
|
1967
2100
|
if (importantFileContents && importantFileContents.length > 0) {
|
|
1968
2101
|
prompt += `
|
|
@@ -1972,7 +2105,7 @@ These npm packages are installed and can be imported: ${npmPackages.join(", ")}`
|
|
|
1972
2105
|
prompt += `
|
|
1973
2106
|
|
|
1974
2107
|
### ${filePath}
|
|
1975
|
-
|
|
2108
|
+
\`\`\`${lang.codeBlockLang}
|
|
1976
2109
|
${content}
|
|
1977
2110
|
\`\`\``;
|
|
1978
2111
|
}
|
|
@@ -2018,14 +2151,17 @@ ${this.envOverview}`;
|
|
|
2018
2151
|
}
|
|
2019
2152
|
await (0, import_promises2.mkdir)(this.writeDir, { recursive: true });
|
|
2020
2153
|
const slug = this._slugify(purpose);
|
|
2021
|
-
const
|
|
2154
|
+
const ext = this.language === "python" ? ".py" : ".mjs";
|
|
2155
|
+
const tempFile = (0, import_node_path.join)(this.writeDir, `agent-${slug}-${Date.now()}${ext}`);
|
|
2022
2156
|
try {
|
|
2023
2157
|
await (0, import_promises2.writeFile)(tempFile, code, "utf-8");
|
|
2158
|
+
const binary = this.language === "python" ? this._pythonBinary : "node";
|
|
2159
|
+
const execEnv = this.language === "python" && this._venvEnv ? this._venvEnv : process.env;
|
|
2024
2160
|
const result = await new Promise((resolve2) => {
|
|
2025
|
-
const child = (0, import_node_child_process.execFile)(
|
|
2161
|
+
const child = (0, import_node_child_process.execFile)(binary, [tempFile], {
|
|
2026
2162
|
cwd: this.workingDirectory,
|
|
2027
2163
|
timeout: this.timeout,
|
|
2028
|
-
env:
|
|
2164
|
+
env: execEnv,
|
|
2029
2165
|
maxBuffer: 10 * 1024 * 1024
|
|
2030
2166
|
}, (err, stdout, stderr) => {
|
|
2031
2167
|
this._activeProcess = null;
|
|
@@ -2096,11 +2232,12 @@ ${this.envOverview}`;
|
|
|
2096
2232
|
logger_default.warn(`onBeforeExecution callback error: ${e.message}`);
|
|
2097
2233
|
}
|
|
2098
2234
|
}
|
|
2235
|
+
const execEnv = this.language === "python" && this._venvEnv ? this._venvEnv : process.env;
|
|
2099
2236
|
const result = await new Promise((resolve2) => {
|
|
2100
2237
|
const child = (0, import_node_child_process.execFile)("bash", ["-c", command], {
|
|
2101
2238
|
cwd: this.workingDirectory,
|
|
2102
2239
|
timeout: this.timeout,
|
|
2103
|
-
env:
|
|
2240
|
+
env: execEnv,
|
|
2104
2241
|
maxBuffer: 10 * 1024 * 1024
|
|
2105
2242
|
}, (err, stdout, stderr) => {
|
|
2106
2243
|
this._activeProcess = null;
|
|
@@ -2480,8 +2617,9 @@ ${this.envOverview}`;
|
|
|
2480
2617
|
* @returns {Array<{fileName: string, purpose: string|null, script: string, filePath: string|null, tool: string}>}
|
|
2481
2618
|
*/
|
|
2482
2619
|
dump() {
|
|
2620
|
+
const ext = this.language === "python" ? ".py" : ".mjs";
|
|
2483
2621
|
return this._allExecutions.map((exec, i) => ({
|
|
2484
|
-
fileName: exec.purpose ? `agent-${exec.purpose}
|
|
2622
|
+
fileName: exec.purpose ? `agent-${exec.purpose}${ext}` : `script-${i + 1}${ext}`,
|
|
2485
2623
|
purpose: exec.purpose || null,
|
|
2486
2624
|
script: exec.code,
|
|
2487
2625
|
filePath: exec.filePath || null,
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -302,6 +302,10 @@ export interface RagAgentOptions extends BaseGeminiOptions {
|
|
|
302
302
|
export interface CodeAgentOptions extends BaseGeminiOptions {
|
|
303
303
|
/** Working directory for code execution (default: process.cwd()) */
|
|
304
304
|
workingDirectory?: string;
|
|
305
|
+
/** Programming language for code execution: 'javascript' (default) or 'python' */
|
|
306
|
+
language?: 'javascript' | 'python';
|
|
307
|
+
/** Path to the Python binary (only used when language is 'python'; default: auto-detect python3/python) */
|
|
308
|
+
pythonPath?: string;
|
|
305
309
|
/** Max code execution loop iterations (default: 10) */
|
|
306
310
|
maxRounds?: number;
|
|
307
311
|
/** Per-execution timeout in milliseconds (default: 30000) */
|
|
@@ -633,6 +637,8 @@ export declare class CodeAgent extends BaseGemini {
|
|
|
633
637
|
constructor(options?: CodeAgentOptions);
|
|
634
638
|
|
|
635
639
|
workingDirectory: string;
|
|
640
|
+
language: 'javascript' | 'python';
|
|
641
|
+
pythonPath: string | null;
|
|
636
642
|
maxRounds: number;
|
|
637
643
|
timeout: number;
|
|
638
644
|
onBeforeExecution: ((content: string, toolName: string) => Promise<boolean> | boolean) | null;
|