All files / packages/gemini-core/src/core prompts.ts

17.5% Statements 7/40
0% Branches 0/19
0% Functions 0/2
17.5% Lines 7/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109            6x 6x 6x 6x   6x   6x                                                                                                   6x                                                                                          
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
 
import path from 'node:path';
import fs from 'node:fs';
import os from 'node:os';
import process from 'node:process';
 
export const GEMINI_CONFIG_DIR = '.gemini';
 
export function resolvePathFromEnv(envVar?: string): {
  isSwitch: boolean;
  value: string | null;
  isDisabled: boolean;
} {
  // Handle the case where the environment variable is not set, empty, or just whitespace.
  const trimmedEnvVar = envVar?.trim();
  Iif (!trimmedEnvVar) {
    return { isSwitch: false, value: null, isDisabled: false };
  }
 
  const lowerEnvVar = trimmedEnvVar.toLowerCase();
  // Check if the input is a common boolean-like string.
  Iif (['0', 'false', '1', 'true'].includes(lowerEnvVar)) {
    // If so, identify it as a "switch" and return its value.
    const isDisabled = ['0', 'false'].includes(lowerEnvVar);
    return { isSwitch: true, value: lowerEnvVar, isDisabled };
  }
 
  // If it's not a switch, treat it as a potential file path.
  let customPath = trimmedEnvVar;
 
  // Safely expand the tilde (~) character to the user's home directory.
  Iif (customPath.startsWith('~/') || customPath === '~') {
    try {
      const home = os.homedir(); // This is the call that can throw an error.
      if (customPath === '~') {
        customPath = home;
      } else {
        customPath = path.join(home, customPath.slice(2));
      }
    } catch (error) {
      // If os.homedir() fails, we catch the error instead of crashing.
      console.warn(
        `Could not resolve home directory for path: ${trimmedEnvVar}`,
        error,
      );
      // Return null to indicate the path resolution failed.
      return { isSwitch: false, value: null, isDisabled: false };
    }
  }
 
  // Return it as a non-switch with the fully resolved absolute path.
  return {
    isSwitch: false,
    value: path.resolve(customPath),
    isDisabled: false,
  };
}
 
export function getCoreSystemPrompt(): string {
  // A flag to indicate whether the system prompt override is active.
  let systemMdEnabled = false;
  // The default path for the system prompt file. This can be overridden.
  let systemMdPath = path.resolve(path.join(GEMINI_CONFIG_DIR, 'system.md'));
  // Resolve the environment variable to get either a path or a switch value.
  const systemMdResolution = resolvePathFromEnv(
    process.env['GEMINI_SYSTEM_MD'],
  );
 
  // Proceed only if the environment variable is set and is not disabled.
  Iif (systemMdResolution.value && !systemMdResolution.isDisabled) {
    systemMdEnabled = true;
 
    // We update systemMdPath to this new custom path.
    Iif (!systemMdResolution.isSwitch) {
      systemMdPath = systemMdResolution.value;
    }
 
    // require file to exist when override is enabled
    Iif (!fs.existsSync(systemMdPath)) {
      throw new Error(`missing system prompt file '${systemMdPath}'`);
    }
  }
  const basePrompt = systemMdEnabled
    ? fs.readFileSync(systemMdPath, 'utf8')
    : `You are a helpful assistant.`;
 
  // if GEMINI_WRITE_SYSTEM_MD is set (and not 0|false), write base system prompt to file
  const writeSystemMdResolution = resolvePathFromEnv(
    process.env['GEMINI_WRITE_SYSTEM_MD'],
  );
 
  // Check if the feature is enabled. This proceeds only if the environment
  // variable is set and is not explicitly '0' or 'false'.
  Iif (writeSystemMdResolution.value && !writeSystemMdResolution.isDisabled) {
    const writePath = writeSystemMdResolution.isSwitch
      ? systemMdPath
      : writeSystemMdResolution.value;
 
    fs.mkdirSync(path.dirname(writePath), { recursive: true });
    fs.writeFileSync(writePath, basePrompt);
  }
 
  return basePrompt;
}