ak-gemini 2.1.5 → 2.3.0

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/index.cjs CHANGED
@@ -35,6 +35,7 @@ __export(index_exports, {
35
35
  Embedding: () => Embedding,
36
36
  HarmBlockThreshold: () => import_genai2.HarmBlockThreshold,
37
37
  HarmCategory: () => import_genai2.HarmCategory,
38
+ ImageGenerator: () => ImageGenerator,
38
39
  Message: () => message_default,
39
40
  RagAgent: () => rag_agent_default,
40
41
  ThinkingLevel: () => import_genai2.ThinkingLevel,
@@ -322,29 +323,46 @@ var DEFAULT_THINKING_CONFIG = {
322
323
  };
323
324
  var DEFAULT_MAX_OUTPUT_TOKENS = 5e4;
324
325
  var THINKING_SUPPORTED_MODELS = [
325
- /^gemini-3-flash(-preview)?$/,
326
- /^gemini-3-pro(-preview|-image-preview)?$/,
326
+ /^gemini-3(\.\d+)?-pro(-preview)?$/,
327
+ /^gemini-3(\.\d+)?-flash(-preview)?$/,
328
+ /^gemini-3(\.\d+)?-flash-lite(-preview)?$/,
327
329
  /^gemini-2\.5-pro/,
328
330
  /^gemini-2\.5-flash(-preview)?$/,
329
331
  /^gemini-2\.5-flash-lite(-preview)?$/,
330
332
  /^gemini-2\.0-flash$/
331
333
  ];
332
334
  var MODEL_PRICING = {
333
- "gemini-2.5-flash": { input: 0.15, output: 0.6 },
334
- "gemini-2.5-flash-lite": { input: 0.02, output: 0.1 },
335
- "gemini-2.5-pro": { input: 2.5, output: 10 },
336
- "gemini-3-pro": { input: 2, output: 12 },
337
- "gemini-3-pro-preview": { input: 2, output: 12 },
335
+ // Gemini 3.x stable
336
+ "gemini-3.5-flash": { input: 1.5, output: 9 },
337
+ "gemini-3.1-flash-lite": { input: 0.25, output: 1.5 },
338
+ // Gemini 3.x preview
339
+ "gemini-3.1-pro-preview": { input: 2, output: 12 },
340
+ // ≤200k tier
341
+ "gemini-3-flash-preview": { input: 0.5, output: 3 },
342
+ "gemini-3.1-flash-lite-preview": { input: 0.25, output: 1.5 },
343
+ "gemini-3.1-flash-image-preview": { input: 0.5, output: 3 },
344
+ // text-only; image-output is $60/M
345
+ "gemini-3-pro-image-preview": { input: 2, output: 12 },
346
+ // text-only; image-output is $120/M
347
+ // Gemini 2.5 stable
348
+ "gemini-2.5-flash": { input: 0.3, output: 2.5 },
349
+ "gemini-2.5-flash-lite": { input: 0.1, output: 0.4 },
350
+ "gemini-2.5-pro": { input: 1.25, output: 10 },
351
+ // ≤200k tier
352
+ "gemini-2.5-flash-image": { input: 0.3, output: 0 },
353
+ // image-output is ~$0.039/image (1290 tokens)
354
+ // Deprecated but kept for back-compat (shut down June 2026)
338
355
  "gemini-2.0-flash": { input: 0.1, output: 0.4 },
339
356
  "gemini-2.0-flash-lite": { input: 0.02, output: 0.1 },
340
- "gemini-embedding-001": { input: 6e-3, output: 0 }
357
+ // Embeddings
358
+ "gemini-embedding-001": { input: 0.15, output: 0 }
341
359
  };
342
360
  var BaseGemini = class {
343
361
  /**
344
362
  * @param {BaseGeminiOptions} [options={}]
345
363
  */
346
364
  constructor(options = {}) {
347
- this.modelName = options.modelName || "gemini-2.5-flash";
365
+ this.modelName = options.modelName || "gemini-3-flash-preview";
348
366
  if (options.systemPrompt !== void 0) {
349
367
  this.systemPrompt = options.systemPrompt;
350
368
  } else {
@@ -369,6 +387,8 @@ var BaseGemini = class {
369
387
  this.enableGrounding = options.enableGrounding || false;
370
388
  this.groundingConfig = options.groundingConfig || {};
371
389
  this.cachedContent = options.cachedContent || null;
390
+ this.serviceTier = options.serviceTier || null;
391
+ this.includeServerSideToolInvocations = options.includeServerSideToolInvocations ?? false;
372
392
  this.chatConfig = {
373
393
  temperature: 0.7,
374
394
  topP: 0.95,
@@ -376,6 +396,8 @@ var BaseGemini = class {
376
396
  safetySettings: DEFAULT_SAFETY_SETTINGS,
377
397
  ...options.chatConfig
378
398
  };
399
+ if (this.serviceTier) this.chatConfig["serviceTier"] = this.serviceTier;
400
+ if (this.includeServerSideToolInvocations) this.chatConfig["includeServerSideToolInvocations"] = true;
379
401
  if (this.systemPrompt) {
380
402
  this.chatConfig.systemInstruction = this.systemPrompt;
381
403
  } else if (this.systemPrompt === null && options.systemPrompt === void 0) {
@@ -573,6 +595,7 @@ ${contextText}
573
595
  * @protected
574
596
  */
575
597
  _captureMetadata(response) {
598
+ const modelStatus = response?.modelStatus || null;
576
599
  this.lastResponseMetadata = {
577
600
  modelVersion: response.modelVersion || null,
578
601
  requestedModel: this.modelName,
@@ -580,8 +603,13 @@ ${contextText}
580
603
  responseTokens: response.usageMetadata?.candidatesTokenCount || 0,
581
604
  totalTokens: response.usageMetadata?.totalTokenCount || 0,
582
605
  timestamp: Date.now(),
583
- groundingMetadata: response.candidates?.[0]?.groundingMetadata || null
606
+ groundingMetadata: response.candidates?.[0]?.groundingMetadata || null,
607
+ modelStatus
584
608
  };
609
+ if (modelStatus === "DEPRECATED" && !this._deprecationWarned) {
610
+ logger_default.warn(`Model "${this.modelName}" is marked DEPRECATED by Google. Plan migration.`);
611
+ this._deprecationWarned = true;
612
+ }
585
613
  }
586
614
  /**
587
615
  * Returns structured usage data from the last API call for billing verification.
@@ -601,7 +629,8 @@ ${contextText}
601
629
  modelVersion: meta.modelVersion,
602
630
  requestedModel: meta.requestedModel,
603
631
  timestamp: meta.timestamp,
604
- groundingMetadata: meta.groundingMetadata || null
632
+ groundingMetadata: meta.groundingMetadata || null,
633
+ modelStatus: meta.modelStatus || null
605
634
  };
606
635
  }
607
636
  // ── Token Estimation ─────────────────────────────────────────────────────
@@ -1626,7 +1655,55 @@ var import_node_path = require("node:path");
1626
1655
  var import_node_crypto = require("node:crypto");
1627
1656
  var MAX_OUTPUT_CHARS = 5e4;
1628
1657
  var MAX_FILE_TREE_LINES = 500;
1629
- var IGNORE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "coverage", ".next", "build", "__pycache__"]);
1658
+ var IGNORE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "coverage", ".next", "build", "__pycache__", ".venv"]);
1659
+ var LANG_CONFIG = {
1660
+ javascript: {
1661
+ 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.",
1662
+ 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.",
1663
+ codeParamDesc: "JavaScript code to execute. Use console.log() for output. Use import syntax (ES modules).",
1664
+ codeRules: `- Your code runs in a Node.js child process with access to all built-in modules
1665
+ - IMPORTANT: Your code runs as an ES module (.mjs). Use import syntax, NOT require():
1666
+ - import fs from 'fs';
1667
+ - import path from 'path';
1668
+ - import { execSync } from 'child_process';
1669
+ - Use console.log() to produce output \u2014 that's how results are returned to you
1670
+ - Write efficient scripts that do multiple things per execution when possible
1671
+ - For parallel async operations, use Promise.all()
1672
+ - Handle errors in your scripts with try/catch so you get useful error messages
1673
+ - Top-level await is supported`,
1674
+ commentsEnabled: `- Add a JSDoc @fileoverview comment at the top of each script explaining what it does
1675
+ - Add brief JSDoc @param comments for any functions you define`,
1676
+ commentsDisabled: `- Do NOT write any comments in your code \u2014 save tokens. The code should be self-explanatory.`,
1677
+ packageLabel: "Available Packages",
1678
+ packageIntro: "These npm packages are installed and can be imported",
1679
+ bashExamples: "ls, grep, curl, git, npm, cat",
1680
+ codeBlockLang: "javascript",
1681
+ 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.",
1682
+ writeRunToolSummary: "Write a fresh solution from scratch and execute it in one step. The autonomous, end-to-end tool for solving problems with code."
1683
+ },
1684
+ python: {
1685
+ 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.",
1686
+ 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.",
1687
+ codeParamDesc: "Python code to execute. Use print() for output.",
1688
+ codeRules: `- Your code runs in a Python 3 child process
1689
+ - Use print() to produce output \u2014 that's how results are returned to you
1690
+ - Use standard Python imports (import os, import json, from pathlib import Path, etc.)
1691
+ - Write efficient scripts; prefer list comprehensions and built-in functions
1692
+ - For async operations, use asyncio
1693
+ - Handle errors with try/except so you get useful error messages
1694
+ - A virtual environment is active \u2014 you can install packages using run_bash with: pip install <package>
1695
+ - Installed packages persist across executions in this session`,
1696
+ commentsEnabled: `- Add a module-level docstring at the top of each script explaining what it does
1697
+ - Add brief docstrings for any functions you define`,
1698
+ commentsDisabled: `- Do NOT write any comments in your code \u2014 save tokens. The code should be self-explanatory.`,
1699
+ packageLabel: "Available Packages",
1700
+ packageIntro: "These Python packages are available for import",
1701
+ bashExamples: "ls, grep, curl, git, pip, cat",
1702
+ codeBlockLang: "python",
1703
+ 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.",
1704
+ 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."
1705
+ }
1706
+ };
1630
1707
  var EXECUTING_TOOLS = /* @__PURE__ */ new Set(["execute_code", "write_and_run_code", "run_bash"]);
1631
1708
  var CodeAgent = class extends base_default {
1632
1709
  /**
@@ -1638,6 +1715,8 @@ var CodeAgent = class extends base_default {
1638
1715
  }
1639
1716
  super(options);
1640
1717
  this.workingDirectory = options.workingDirectory || process.cwd();
1718
+ this.language = options.language || "javascript";
1719
+ this.pythonPath = options.pythonPath || null;
1641
1720
  this.maxRounds = options.maxRounds || 10;
1642
1721
  this.timeout = options.timeout || 3e4;
1643
1722
  this.onBeforeExecution = options.onBeforeExecution || null;
@@ -1649,6 +1728,9 @@ var CodeAgent = class extends base_default {
1649
1728
  this.maxRetries = options.maxRetries ?? 3;
1650
1729
  this.skills = options.skills || [];
1651
1730
  this.envOverview = options.envOverview || "";
1731
+ this._pythonBinary = null;
1732
+ this._venvPath = null;
1733
+ this._venvEnv = null;
1652
1734
  this.customTools = (options.tools || []).map((t) => ({
1653
1735
  name: t.name,
1654
1736
  description: t.description,
@@ -1677,6 +1759,7 @@ var CodeAgent = class extends base_default {
1677
1759
  * @returns {{ functionDeclarations: Array<Object> }}
1678
1760
  */
1679
1761
  _buildToolDefinitions() {
1762
+ const lang = LANG_CONFIG[this.language] || LANG_CONFIG.javascript;
1680
1763
  const declarations = [
1681
1764
  {
1682
1765
  name: "write_code",
@@ -1693,11 +1776,11 @@ var CodeAgent = class extends base_default {
1693
1776
  },
1694
1777
  {
1695
1778
  name: "execute_code",
1696
- description: "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.",
1779
+ description: lang.toolDescExecute,
1697
1780
  parametersJsonSchema: {
1698
1781
  type: "object",
1699
1782
  properties: {
1700
- code: { type: "string", description: "JavaScript code to execute. Use console.log() for output. Use import syntax (ES modules)." },
1783
+ code: { type: "string", description: lang.codeParamDesc },
1701
1784
  purpose: { type: "string", description: 'A short 2-4 word slug describing what this script does (e.g., "read-config", "parse-logs").' }
1702
1785
  },
1703
1786
  required: ["code"]
@@ -1705,11 +1788,11 @@ var CodeAgent = class extends base_default {
1705
1788
  },
1706
1789
  {
1707
1790
  name: "write_and_run_code",
1708
- description: "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.",
1791
+ description: lang.toolDescWriteAndRun,
1709
1792
  parametersJsonSchema: {
1710
1793
  type: "object",
1711
1794
  properties: {
1712
- code: { type: "string", description: "JavaScript code to write and execute. Use console.log() for output. Use import syntax (ES modules)." },
1795
+ code: { type: "string", description: lang.codeParamDesc },
1713
1796
  purpose: { type: "string", description: 'A short 2-4 word slug describing what this script does (e.g., "fetch-api-data", "generate-report").' }
1714
1797
  },
1715
1798
  required: ["code"]
@@ -1731,7 +1814,7 @@ var CodeAgent = class extends base_default {
1731
1814
  },
1732
1815
  {
1733
1816
  name: "run_bash",
1734
- description: "Execute a shell command in the working directory. Use this for file operations, git commands, installing packages, or any shell task. Prefer this over execute_code for simple shell operations.",
1817
+ 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
1818
  parametersJsonSchema: {
1736
1819
  type: "object",
1737
1820
  properties: {
@@ -1770,6 +1853,10 @@ var CodeAgent = class extends base_default {
1770
1853
  if (this.skills.length > 0 && (this._skillRegistry.size === 0 || force)) {
1771
1854
  await this._loadSkills();
1772
1855
  }
1856
+ if (this.language === "python" && (!this._pythonBinary || force)) {
1857
+ await this._resolvePython();
1858
+ await this._setupVenv();
1859
+ }
1773
1860
  this.chatConfig.tools = [this._buildToolDefinitions()];
1774
1861
  if (!this._contextGathered || force) {
1775
1862
  await this._gatherCodebaseContext();
@@ -1797,6 +1884,70 @@ var CodeAgent = class extends base_default {
1797
1884
  }
1798
1885
  }
1799
1886
  }
1887
+ // ── Python Resolution ───────────────────────────────────────────────────
1888
+ /**
1889
+ * Resolve the Python 3 binary path.
1890
+ * @private
1891
+ */
1892
+ async _resolvePython() {
1893
+ const tryBinary = (bin) => new Promise((resolve2) => {
1894
+ (0, import_node_child_process.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout, stderr) => {
1895
+ if (err) return resolve2(null);
1896
+ const output = (stdout || "") + (stderr || "");
1897
+ if (output.includes("Python 3.")) return resolve2(bin);
1898
+ resolve2(null);
1899
+ });
1900
+ });
1901
+ if (this.pythonPath) {
1902
+ const result = await tryBinary(this.pythonPath);
1903
+ if (result) {
1904
+ this._pythonBinary = result;
1905
+ return;
1906
+ }
1907
+ throw new Error(`CodeAgent: pythonPath "${this.pythonPath}" is not a valid Python 3 binary.`);
1908
+ }
1909
+ const python3 = await tryBinary("python3");
1910
+ if (python3) {
1911
+ this._pythonBinary = python3;
1912
+ return;
1913
+ }
1914
+ const python = await tryBinary("python");
1915
+ if (python) {
1916
+ this._pythonBinary = python;
1917
+ return;
1918
+ }
1919
+ throw new Error('CodeAgent: language is "python" but python3 was not found on PATH. Install Python 3 or provide the pythonPath option.');
1920
+ }
1921
+ /**
1922
+ * Create a virtual environment for Python execution.
1923
+ * @private
1924
+ */
1925
+ async _setupVenv() {
1926
+ await (0, import_promises2.mkdir)(this.writeDir, { recursive: true });
1927
+ this._venvPath = (0, import_node_path.join)(this.writeDir, ".venv");
1928
+ const isWin = process.platform === "win32";
1929
+ const venvBin = isWin ? (0, import_node_path.join)(this._venvPath, "Scripts") : (0, import_node_path.join)(this._venvPath, "bin");
1930
+ const venvPython = (0, import_node_path.join)(venvBin, isWin ? "python.exe" : "python");
1931
+ try {
1932
+ await (0, import_promises2.readFile)(venvPython);
1933
+ } catch {
1934
+ logger_default.debug(`Creating Python venv at ${this._venvPath}`);
1935
+ await new Promise((resolve2, reject) => {
1936
+ (0, import_node_child_process.execFile)(this._pythonBinary, ["-m", "venv", this._venvPath], {
1937
+ timeout: 3e4
1938
+ }, (err) => {
1939
+ if (err) return reject(new Error(`CodeAgent: failed to create venv: ${err.message}`));
1940
+ resolve2();
1941
+ });
1942
+ });
1943
+ }
1944
+ const env = Object.assign({}, process.env);
1945
+ env.VIRTUAL_ENV = this._venvPath;
1946
+ env.PATH = venvBin + (isWin ? ";" : ":") + (process.env.PATH || "");
1947
+ this._venvEnv = env;
1948
+ this._pythonBinary = venvPython;
1949
+ logger_default.debug(`Python venv ready at ${this._venvPath}`);
1950
+ }
1800
1951
  // ── Context Gathering ────────────────────────────────────────────────────
1801
1952
  /**
1802
1953
  * @private
@@ -1815,15 +1966,35 @@ var CodeAgent = class extends base_default {
1815
1966
  fileTree = `${truncated}
1816
1967
  ... (${lines.length - MAX_FILE_TREE_LINES} more files)`;
1817
1968
  }
1818
- let npmPackages = [];
1819
- try {
1820
- const pkgPath = (0, import_node_path.join)(this.workingDirectory, "package.json");
1821
- const pkg = JSON.parse(await (0, import_promises2.readFile)(pkgPath, "utf-8"));
1822
- npmPackages = [
1823
- ...Object.keys(pkg.dependencies || {}),
1824
- ...Object.keys(pkg.devDependencies || {})
1825
- ];
1826
- } catch {
1969
+ let packages = [];
1970
+ if (this.language === "python") {
1971
+ try {
1972
+ const reqPath = (0, import_node_path.join)(this.workingDirectory, "requirements.txt");
1973
+ const content = await (0, import_promises2.readFile)(reqPath, "utf-8");
1974
+ packages = content.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#") && !l.startsWith("-")).map((l) => l.split(/[>=<!\[;\s]/)[0]);
1975
+ } catch {
1976
+ }
1977
+ if (packages.length === 0) {
1978
+ try {
1979
+ const ppPath = (0, import_node_path.join)(this.workingDirectory, "pyproject.toml");
1980
+ const content = await (0, import_promises2.readFile)(ppPath, "utf-8");
1981
+ const depMatch = content.match(/dependencies\s*=\s*\[([\s\S]*?)\]/);
1982
+ if (depMatch) {
1983
+ packages = (depMatch[1].match(/"([^"]+)"/g) || []).map((s) => s.replace(/"/g, "").split(/[>=<!\[;\s]/)[0]);
1984
+ }
1985
+ } catch {
1986
+ }
1987
+ }
1988
+ } else {
1989
+ try {
1990
+ const pkgPath = (0, import_node_path.join)(this.workingDirectory, "package.json");
1991
+ const pkg = JSON.parse(await (0, import_promises2.readFile)(pkgPath, "utf-8"));
1992
+ packages = [
1993
+ ...Object.keys(pkg.dependencies || {}),
1994
+ ...Object.keys(pkg.devDependencies || {})
1995
+ ];
1996
+ } catch {
1997
+ }
1827
1998
  }
1828
1999
  const importantFileContents = [];
1829
2000
  if (this.importantFiles.length > 0) {
@@ -1843,7 +2014,7 @@ var CodeAgent = class extends base_default {
1843
2014
  }
1844
2015
  }
1845
2016
  }
1846
- this._codebaseContext = { fileTree, npmPackages, importantFileContents };
2017
+ this._codebaseContext = { fileTree, npmPackages: packages, packages, importantFileContents };
1847
2018
  this._contextGathered = true;
1848
2019
  }
1849
2020
  /**
@@ -1901,7 +2072,8 @@ var CodeAgent = class extends base_default {
1901
2072
  * @private
1902
2073
  */
1903
2074
  _buildSystemPrompt() {
1904
- const { fileTree, npmPackages, importantFileContents } = this._codebaseContext || { fileTree: "", npmPackages: [], importantFileContents: [] };
2075
+ const { fileTree, packages, importantFileContents } = this._codebaseContext || { fileTree: "", packages: [], importantFileContents: [] };
2076
+ const lang = LANG_CONFIG[this.language] || LANG_CONFIG.javascript;
1905
2077
  let prompt = `You are a coding agent working in ${this.workingDirectory}.
1906
2078
 
1907
2079
  ## Available Tools
@@ -1910,16 +2082,16 @@ var CodeAgent = class extends base_default {
1910
2082
  Output code without executing it. Use when showing, proposing, or presenting code to the user.
1911
2083
 
1912
2084
  ### execute_code
1913
- 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.
2085
+ ${lang.execToolSummary}
1914
2086
 
1915
2087
  ### write_and_run_code
1916
- Write a fresh solution from scratch and execute it in one step. The autonomous, end-to-end tool for solving problems with code.
2088
+ ${lang.writeRunToolSummary}
1917
2089
 
1918
2090
  ### fix_code
1919
2091
  Fix broken code by providing original and fixed versions. Set execute=true to verify the fix works.
1920
2092
 
1921
2093
  ### run_bash
1922
- Run shell commands directly (e.g., ls, grep, curl, git, npm, cat). Prefer this over execute_code for simple shell operations.`;
2094
+ Run shell commands directly (e.g., ${lang.bashExamples}). Prefer this over execute_code for simple shell operations.`;
1923
2095
  if (this._skillRegistry.size > 0) {
1924
2096
  prompt += `
1925
2097
 
@@ -1931,24 +2103,14 @@ Load a skill by name to get detailed instructions and templates. Available skill
1931
2103
  ## Code Execution Rules
1932
2104
  These rules apply when using execute_code, write_and_run_code, or fix_code (with execute=true):
1933
2105
  - Always provide a short descriptive \`purpose\` parameter (2-4 word slug like "read-config")
1934
- - Your code runs in a Node.js child process with access to all built-in modules
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
2106
+ ${lang.codeRules}
1944
2107
  - The working directory is: ${this.workingDirectory}`;
1945
2108
  if (this.comments) {
1946
2109
  prompt += `
1947
- - Add a JSDoc @fileoverview comment at the top of each script explaining what it does
1948
- - Add brief JSDoc @param comments for any functions you define`;
2110
+ ${lang.commentsEnabled}`;
1949
2111
  } else {
1950
2112
  prompt += `
1951
- - Do NOT write any comments in your code \u2014 save tokens. The code should be self-explanatory.`;
2113
+ ${lang.commentsDisabled}`;
1952
2114
  }
1953
2115
  if (fileTree) {
1954
2116
  prompt += `
@@ -1958,11 +2120,11 @@ These rules apply when using execute_code, write_and_run_code, or fix_code (with
1958
2120
  ${fileTree}
1959
2121
  \`\`\``;
1960
2122
  }
1961
- if (npmPackages.length > 0) {
2123
+ if (packages && packages.length > 0) {
1962
2124
  prompt += `
1963
2125
 
1964
- ## Available Packages
1965
- These npm packages are installed and can be imported: ${npmPackages.join(", ")}`;
2126
+ ## ${lang.packageLabel}
2127
+ ${lang.packageIntro}: ${packages.join(", ")}`;
1966
2128
  }
1967
2129
  if (importantFileContents && importantFileContents.length > 0) {
1968
2130
  prompt += `
@@ -1972,7 +2134,7 @@ These npm packages are installed and can be imported: ${npmPackages.join(", ")}`
1972
2134
  prompt += `
1973
2135
 
1974
2136
  ### ${filePath}
1975
- \`\`\`javascript
2137
+ \`\`\`${lang.codeBlockLang}
1976
2138
  ${content}
1977
2139
  \`\`\``;
1978
2140
  }
@@ -2018,14 +2180,17 @@ ${this.envOverview}`;
2018
2180
  }
2019
2181
  await (0, import_promises2.mkdir)(this.writeDir, { recursive: true });
2020
2182
  const slug = this._slugify(purpose);
2021
- const tempFile = (0, import_node_path.join)(this.writeDir, `agent-${slug}-${Date.now()}.mjs`);
2183
+ const ext = this.language === "python" ? ".py" : ".mjs";
2184
+ const tempFile = (0, import_node_path.join)(this.writeDir, `agent-${slug}-${Date.now()}${ext}`);
2022
2185
  try {
2023
2186
  await (0, import_promises2.writeFile)(tempFile, code, "utf-8");
2187
+ const binary = this.language === "python" ? this._pythonBinary : "node";
2188
+ const execEnv = this.language === "python" && this._venvEnv ? this._venvEnv : process.env;
2024
2189
  const result = await new Promise((resolve2) => {
2025
- const child = (0, import_node_child_process.execFile)("node", [tempFile], {
2190
+ const child = (0, import_node_child_process.execFile)(binary, [tempFile], {
2026
2191
  cwd: this.workingDirectory,
2027
2192
  timeout: this.timeout,
2028
- env: process.env,
2193
+ env: execEnv,
2029
2194
  maxBuffer: 10 * 1024 * 1024
2030
2195
  }, (err, stdout, stderr) => {
2031
2196
  this._activeProcess = null;
@@ -2096,11 +2261,12 @@ ${this.envOverview}`;
2096
2261
  logger_default.warn(`onBeforeExecution callback error: ${e.message}`);
2097
2262
  }
2098
2263
  }
2264
+ const execEnv = this.language === "python" && this._venvEnv ? this._venvEnv : process.env;
2099
2265
  const result = await new Promise((resolve2) => {
2100
2266
  const child = (0, import_node_child_process.execFile)("bash", ["-c", command], {
2101
2267
  cwd: this.workingDirectory,
2102
2268
  timeout: this.timeout,
2103
- env: process.env,
2269
+ env: execEnv,
2104
2270
  maxBuffer: 10 * 1024 * 1024
2105
2271
  }, (err, stdout, stderr) => {
2106
2272
  this._activeProcess = null;
@@ -2480,8 +2646,9 @@ ${this.envOverview}`;
2480
2646
  * @returns {Array<{fileName: string, purpose: string|null, script: string, filePath: string|null, tool: string}>}
2481
2647
  */
2482
2648
  dump() {
2649
+ const ext = this.language === "python" ? ".py" : ".mjs";
2483
2650
  return this._allExecutions.map((exec, i) => ({
2484
- fileName: exec.purpose ? `agent-${exec.purpose}.mjs` : `script-${i + 1}.mjs`,
2651
+ fileName: exec.purpose ? `agent-${exec.purpose}${ext}` : `script-${i + 1}${ext}`,
2485
2652
  purpose: exec.purpose || null,
2486
2653
  script: exec.code,
2487
2654
  filePath: exec.filePath || null,
@@ -2897,9 +3064,155 @@ var Embedding = class extends base_default {
2897
3064
  }
2898
3065
  };
2899
3066
 
3067
+ // image-generator.js
3068
+ var import_node_fs = require("node:fs");
3069
+ var DEFAULT_IMAGE_MODEL = "gemini-3.1-flash-image-preview";
3070
+ var ImageGenerator = class extends base_default {
3071
+ /**
3072
+ * @param {import('./types.d.ts').ImageGeneratorOptions} [options={}]
3073
+ */
3074
+ constructor(options = {}) {
3075
+ if (options.modelName === void 0) {
3076
+ options = { ...options, modelName: DEFAULT_IMAGE_MODEL };
3077
+ }
3078
+ if (options.systemPrompt === void 0) {
3079
+ options = { ...options, systemPrompt: null };
3080
+ }
3081
+ super(options);
3082
+ this.aspectRatio = options.aspectRatio || null;
3083
+ this.imageSize = options.imageSize || null;
3084
+ this.personGeneration = options.personGeneration || null;
3085
+ this.includeText = options.includeText ?? false;
3086
+ logger_default.debug(`ImageGenerator created with model: ${this.modelName}`);
3087
+ }
3088
+ /**
3089
+ * Validate API connection only; no chat session (stateless).
3090
+ * @param {boolean} [force=false]
3091
+ */
3092
+ async init(force = false) {
3093
+ if (this._initialized && !force) return;
3094
+ logger_default.debug(`Initializing ${this.constructor.name} with model: ${this.modelName}...`);
3095
+ try {
3096
+ await this.genAIClient.models.list();
3097
+ logger_default.debug(`${this.constructor.name}: API connection successful.`);
3098
+ } catch (e) {
3099
+ throw new Error(`${this.constructor.name} initialization failed: ${e.message}`);
3100
+ }
3101
+ this._initialized = true;
3102
+ }
3103
+ /**
3104
+ * Build a FRESH config — Gemini image models reject safetySettings/temp/topK/topP/thinkingConfig.
3105
+ * Do NOT spread this.chatConfig.
3106
+ * @private
3107
+ */
3108
+ _buildConfig(overrides = {}) {
3109
+ const includeText = overrides.includeText ?? this.includeText;
3110
+ const config = { responseModalities: includeText ? ["IMAGE", "TEXT"] : ["IMAGE"] };
3111
+ const imageConfig = {};
3112
+ const aspectRatio = overrides.aspectRatio || this.aspectRatio;
3113
+ const imageSize = overrides.imageSize || this.imageSize;
3114
+ const personGeneration = overrides.personGeneration || this.personGeneration;
3115
+ if (aspectRatio) imageConfig.aspectRatio = aspectRatio;
3116
+ if (imageSize) imageConfig.imageSize = imageSize;
3117
+ if (personGeneration) imageConfig.personGeneration = personGeneration;
3118
+ if (Object.keys(imageConfig).length > 0) config.imageConfig = imageConfig;
3119
+ return config;
3120
+ }
3121
+ /**
3122
+ * Generate one or more images from a text prompt.
3123
+ * Optionally accepts `inputImages` for image editing / multi-image composition.
3124
+ *
3125
+ * @param {string} prompt
3126
+ * @param {import('./types.d.ts').ImageGenerateOptions} [opts={}]
3127
+ * @returns {Promise<import('./types.d.ts').ImageGenerationResult>}
3128
+ */
3129
+ async generate(prompt, opts = {}) {
3130
+ if (!this._initialized) await this.init();
3131
+ const parts = [{ text: prompt }];
3132
+ if (Array.isArray(opts.inputImages)) {
3133
+ for (const img of opts.inputImages) {
3134
+ parts.push({ inlineData: { data: img.data, mimeType: img.mimeType } });
3135
+ }
3136
+ }
3137
+ const result = await this._withRetry(() => this.genAIClient.models.generateContent({
3138
+ model: this.modelName,
3139
+ contents: [{ role: "user", parts }],
3140
+ config: this._buildConfig(opts)
3141
+ }));
3142
+ this._captureMetadata(result);
3143
+ this._cumulativeUsage = {
3144
+ promptTokens: this.lastResponseMetadata.promptTokens,
3145
+ responseTokens: this.lastResponseMetadata.responseTokens,
3146
+ totalTokens: this.lastResponseMetadata.totalTokens,
3147
+ attempts: 1
3148
+ };
3149
+ const images = [];
3150
+ let text = "";
3151
+ const responseParts = result.candidates?.[0]?.content?.parts || [];
3152
+ for (const part of responseParts) {
3153
+ if (part.inlineData?.data) {
3154
+ images.push({
3155
+ data: part.inlineData.data,
3156
+ mimeType: part.inlineData.mimeType || "image/png"
3157
+ });
3158
+ } else if (part.text) {
3159
+ text += part.text;
3160
+ }
3161
+ }
3162
+ if (images.length === 0) {
3163
+ logger_default.warn("ImageGenerator: no images returned. Check prompt or safety filters.");
3164
+ }
3165
+ return { images, text: text || null, usage: this.getLastUsage() };
3166
+ }
3167
+ /**
3168
+ * Convenience: write one or all images to disk.
3169
+ * If multiple images, suffixes with `_N` before extension.
3170
+ * @param {import('./types.d.ts').ImageGenerationResult} result
3171
+ * @param {string} filePath
3172
+ * @returns {string[]} Written file paths
3173
+ */
3174
+ save(result, filePath) {
3175
+ if (!result?.images?.length) {
3176
+ logger_default.warn("ImageGenerator.save(): no images to save.");
3177
+ return [];
3178
+ }
3179
+ const paths = [];
3180
+ const dot = filePath.lastIndexOf(".");
3181
+ const base = dot >= 0 ? filePath.slice(0, dot) : filePath;
3182
+ const ext = dot >= 0 ? filePath.slice(dot) : ".png";
3183
+ result.images.forEach((img, i) => {
3184
+ const out = result.images.length === 1 ? filePath : `${base}_${i}${ext}`;
3185
+ (0, import_node_fs.writeFileSync)(out, Buffer.from(img.data, "base64"));
3186
+ paths.push(out);
3187
+ });
3188
+ return paths;
3189
+ }
3190
+ // ── No-ops (image gen is stateless) ──
3191
+ /** @returns {any[]} Always returns empty array */
3192
+ getHistory() {
3193
+ return [];
3194
+ }
3195
+ /** No-op for ImageGenerator */
3196
+ async clearHistory() {
3197
+ }
3198
+ /** No-op for ImageGenerator */
3199
+ async seed() {
3200
+ logger_default.warn("ImageGenerator.seed() is a no-op \u2014 image generation does not support few-shot.");
3201
+ return [];
3202
+ }
3203
+ /**
3204
+ * @param {any} _nextPayload
3205
+ * @throws {Error} ImageGenerator does not support token estimation
3206
+ * @returns {Promise<{ inputTokens: number }>}
3207
+ */
3208
+ async estimate(_nextPayload) {
3209
+ throw new Error("ImageGenerator does not support token estimation. Use generate() directly.");
3210
+ }
3211
+ };
3212
+
2900
3213
  // index.js
2901
3214
  var import_genai2 = require("@google/genai");
2902
- var index_default = { Transformer: transformer_default, Chat: chat_default, Message: message_default, ToolAgent: tool_agent_default, CodeAgent: code_agent_default, RagAgent: rag_agent_default, Embedding };
3215
+ var index_default = { Transformer: transformer_default, Chat: chat_default, Message: message_default, ToolAgent: tool_agent_default, CodeAgent: code_agent_default, RagAgent: rag_agent_default, Embedding, ImageGenerator };
2903
3216
  // Annotate the CommonJS export names for ESM import in node:
2904
3217
  0 && (module.exports = {
2905
3218
  BaseGemini,
@@ -2908,6 +3221,7 @@ var index_default = { Transformer: transformer_default, Chat: chat_default, Mess
2908
3221
  Embedding,
2909
3222
  HarmBlockThreshold,
2910
3223
  HarmCategory,
3224
+ ImageGenerator,
2911
3225
  Message,
2912
3226
  RagAgent,
2913
3227
  ThinkingLevel,
package/index.js CHANGED
@@ -27,6 +27,7 @@ export { default as ToolAgent } from './tool-agent.js';
27
27
  export { default as CodeAgent } from './code-agent.js';
28
28
  export { default as RagAgent } from './rag-agent.js';
29
29
  export { default as Embedding } from './embedding.js';
30
+ export { default as ImageGenerator } from './image-generator.js';
30
31
  export { default as BaseGemini } from './base.js';
31
32
  export { default as log } from './logger.js';
32
33
  export { ThinkingLevel, HarmCategory, HarmBlockThreshold } from '@google/genai';
@@ -41,5 +42,6 @@ import ToolAgent from './tool-agent.js';
41
42
  import CodeAgent from './code-agent.js';
42
43
  import RagAgent from './rag-agent.js';
43
44
  import Embedding from './embedding.js';
45
+ import ImageGenerator from './image-generator.js';
44
46
 
45
- export default { Transformer, Chat, Message, ToolAgent, CodeAgent, RagAgent, Embedding };
47
+ export default { Transformer, Chat, Message, ToolAgent, CodeAgent, RagAgent, Embedding, ImageGenerator };