feat(core): Resolve GEMINI_SYSTEM_MD case-insensitively (#4538)

Co-authored-by: Jacob Richman <jacob314@gmail.com>
This commit is contained in:
Oliver Kowalke 2025-07-22 19:23:04 +02:00 committed by GitHub
parent e306b34a6e
commit 5dce1df5db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 202 additions and 16 deletions

View File

@ -4,9 +4,13 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, it, expect, vi } from 'vitest';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { getCoreSystemPrompt } from './prompts.js';
import { isGitRepository } from '../utils/gitUtils.js';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { GEMINI_CONFIG_DIR } from '../tools/memoryTool.js';
// Mock tool names if they are dynamically generated or complex
vi.mock('../tools/ls', () => ({ LSTool: { Name: 'list_directory' } }));
@ -26,8 +30,15 @@ vi.mock('../tools/write-file', () => ({
vi.mock('../utils/gitUtils', () => ({
isGitRepository: vi.fn(),
}));
vi.mock('node:fs');
describe('Core System Prompt (prompts.ts)', () => {
beforeEach(() => {
vi.resetAllMocks();
vi.stubEnv('GEMINI_SYSTEM_MD', undefined);
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', undefined);
});
it('should return the base prompt when no userMemory is provided', () => {
vi.stubEnv('SANDBOX', undefined);
const prompt = getCoreSystemPrompt();
@ -105,4 +116,157 @@ describe('Core System Prompt (prompts.ts)', () => {
expect(prompt).not.toContain('# Git Repository');
expect(prompt).toMatchSnapshot();
});
describe('GEMINI_SYSTEM_MD environment variable', () => {
it('should use default prompt when GEMINI_SYSTEM_MD is "false"', () => {
vi.stubEnv('GEMINI_SYSTEM_MD', 'false');
const prompt = getCoreSystemPrompt();
expect(fs.readFileSync).not.toHaveBeenCalled();
expect(prompt).not.toContain('custom system prompt');
});
it('should use default prompt when GEMINI_SYSTEM_MD is "0"', () => {
vi.stubEnv('GEMINI_SYSTEM_MD', '0');
const prompt = getCoreSystemPrompt();
expect(fs.readFileSync).not.toHaveBeenCalled();
expect(prompt).not.toContain('custom system prompt');
});
it('should throw error if GEMINI_SYSTEM_MD points to a non-existent file', () => {
const customPath = '/non/existent/path/system.md';
vi.stubEnv('GEMINI_SYSTEM_MD', customPath);
vi.mocked(fs.existsSync).mockReturnValue(false);
expect(() => getCoreSystemPrompt()).toThrow(
`missing system prompt file '${path.resolve(customPath)}'`,
);
});
it('should read from default path when GEMINI_SYSTEM_MD is "true"', () => {
const defaultPath = path.resolve(
path.join(GEMINI_CONFIG_DIR, 'system.md'),
);
vi.stubEnv('GEMINI_SYSTEM_MD', 'true');
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.readFileSync).mockReturnValue('custom system prompt');
const prompt = getCoreSystemPrompt();
expect(fs.readFileSync).toHaveBeenCalledWith(defaultPath, 'utf8');
expect(prompt).toBe('custom system prompt');
});
it('should read from default path when GEMINI_SYSTEM_MD is "1"', () => {
const defaultPath = path.resolve(
path.join(GEMINI_CONFIG_DIR, 'system.md'),
);
vi.stubEnv('GEMINI_SYSTEM_MD', '1');
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.readFileSync).mockReturnValue('custom system prompt');
const prompt = getCoreSystemPrompt();
expect(fs.readFileSync).toHaveBeenCalledWith(defaultPath, 'utf8');
expect(prompt).toBe('custom system prompt');
});
it('should read from custom path when GEMINI_SYSTEM_MD provides one, preserving case', () => {
const customPath = path.resolve('/custom/path/SyStEm.Md');
vi.stubEnv('GEMINI_SYSTEM_MD', customPath);
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.readFileSync).mockReturnValue('custom system prompt');
const prompt = getCoreSystemPrompt();
expect(fs.readFileSync).toHaveBeenCalledWith(customPath, 'utf8');
expect(prompt).toBe('custom system prompt');
});
it('should expand tilde in custom path when GEMINI_SYSTEM_MD is set', () => {
const homeDir = '/Users/test';
vi.spyOn(os, 'homedir').mockReturnValue(homeDir);
const customPath = '~/custom/system.md';
const expectedPath = path.join(homeDir, 'custom/system.md');
vi.stubEnv('GEMINI_SYSTEM_MD', customPath);
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.readFileSync).mockReturnValue('custom system prompt');
const prompt = getCoreSystemPrompt();
expect(fs.readFileSync).toHaveBeenCalledWith(
path.resolve(expectedPath),
'utf8',
);
expect(prompt).toBe('custom system prompt');
});
});
describe('GEMINI_WRITE_SYSTEM_MD environment variable', () => {
it('should not write to file when GEMINI_WRITE_SYSTEM_MD is "false"', () => {
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', 'false');
getCoreSystemPrompt();
expect(fs.writeFileSync).not.toHaveBeenCalled();
});
it('should not write to file when GEMINI_WRITE_SYSTEM_MD is "0"', () => {
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', '0');
getCoreSystemPrompt();
expect(fs.writeFileSync).not.toHaveBeenCalled();
});
it('should write to default path when GEMINI_WRITE_SYSTEM_MD is "true"', () => {
const defaultPath = path.resolve(
path.join(GEMINI_CONFIG_DIR, 'system.md'),
);
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', 'true');
getCoreSystemPrompt();
expect(fs.writeFileSync).toHaveBeenCalledWith(
defaultPath,
expect.any(String),
);
});
it('should write to default path when GEMINI_WRITE_SYSTEM_MD is "1"', () => {
const defaultPath = path.resolve(
path.join(GEMINI_CONFIG_DIR, 'system.md'),
);
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', '1');
getCoreSystemPrompt();
expect(fs.writeFileSync).toHaveBeenCalledWith(
defaultPath,
expect.any(String),
);
});
it('should write to custom path when GEMINI_WRITE_SYSTEM_MD provides one', () => {
const customPath = path.resolve('/custom/path/system.md');
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', customPath);
getCoreSystemPrompt();
expect(fs.writeFileSync).toHaveBeenCalledWith(
customPath,
expect.any(String),
);
});
it('should expand tilde in custom path when GEMINI_WRITE_SYSTEM_MD is set', () => {
const homeDir = '/Users/test';
vi.spyOn(os, 'homedir').mockReturnValue(homeDir);
const customPath = '~/custom/system.md';
const expectedPath = path.join(homeDir, 'custom/system.md');
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', customPath);
getCoreSystemPrompt();
expect(fs.writeFileSync).toHaveBeenCalledWith(
path.resolve(expectedPath),
expect.any(String),
);
});
it('should expand tilde in custom path when GEMINI_WRITE_SYSTEM_MD is just ~', () => {
const homeDir = '/Users/test';
vi.spyOn(os, 'homedir').mockReturnValue(homeDir);
const customPath = '~';
const expectedPath = homeDir;
vi.stubEnv('GEMINI_WRITE_SYSTEM_MD', customPath);
getCoreSystemPrompt();
expect(fs.writeFileSync).toHaveBeenCalledWith(
path.resolve(expectedPath),
expect.any(String),
);
});
});
});

View File

@ -6,6 +6,7 @@
import path from 'node:path';
import fs from 'node:fs';
import os from 'node:os';
import { LSTool } from '../tools/ls.js';
import { EditTool } from '../tools/edit.js';
import { GlobTool } from '../tools/glob.js';
@ -23,15 +24,24 @@ export function getCoreSystemPrompt(userMemory?: string): string {
// default path is .gemini/system.md but can be modified via custom path in GEMINI_SYSTEM_MD
let systemMdEnabled = false;
let systemMdPath = path.resolve(path.join(GEMINI_CONFIG_DIR, 'system.md'));
const systemMdVar = process.env.GEMINI_SYSTEM_MD?.toLowerCase();
if (systemMdVar && !['0', 'false'].includes(systemMdVar)) {
systemMdEnabled = true; // enable system prompt override
if (!['1', 'true'].includes(systemMdVar)) {
systemMdPath = path.resolve(systemMdVar); // use custom path from GEMINI_SYSTEM_MD
}
// require file to exist when override is enabled
if (!fs.existsSync(systemMdPath)) {
throw new Error(`missing system prompt file '${systemMdPath}'`);
const systemMdVar = process.env.GEMINI_SYSTEM_MD;
if (systemMdVar) {
const systemMdVarLower = systemMdVar.toLowerCase();
if (!['0', 'false'].includes(systemMdVarLower)) {
systemMdEnabled = true; // enable system prompt override
if (!['1', 'true'].includes(systemMdVarLower)) {
let customPath = systemMdVar;
if (customPath.startsWith('~/')) {
customPath = path.join(os.homedir(), customPath.slice(2));
} else if (customPath === '~') {
customPath = os.homedir();
}
systemMdPath = path.resolve(customPath); // use custom path from GEMINI_SYSTEM_MD
}
// require file to exist when override is enabled
if (!fs.existsSync(systemMdPath)) {
throw new Error(`missing system prompt file '${systemMdPath}'`);
}
}
}
const basePrompt = systemMdEnabled
@ -256,12 +266,24 @@ Your core function is efficient and safe assistance. Balance extreme conciseness
`.trim();
// if GEMINI_WRITE_SYSTEM_MD is set (and not 0|false), write base system prompt to file
const writeSystemMdVar = process.env.GEMINI_WRITE_SYSTEM_MD?.toLowerCase();
if (writeSystemMdVar && !['0', 'false'].includes(writeSystemMdVar)) {
if (['1', 'true'].includes(writeSystemMdVar)) {
fs.writeFileSync(systemMdPath, basePrompt); // write to default path, can be modified via GEMINI_SYSTEM_MD
} else {
fs.writeFileSync(path.resolve(writeSystemMdVar), basePrompt); // write to custom path from GEMINI_WRITE_SYSTEM_MD
const writeSystemMdVar = process.env.GEMINI_WRITE_SYSTEM_MD;
if (writeSystemMdVar) {
const writeSystemMdVarLower = writeSystemMdVar.toLowerCase();
if (!['0', 'false'].includes(writeSystemMdVarLower)) {
if (['1', 'true'].includes(writeSystemMdVarLower)) {
fs.mkdirSync(path.dirname(systemMdPath), { recursive: true });
fs.writeFileSync(systemMdPath, basePrompt); // write to default path, can be modified via GEMINI_SYSTEM_MD
} else {
let customPath = writeSystemMdVar;
if (customPath.startsWith('~/')) {
customPath = path.join(os.homedir(), customPath.slice(2));
} else if (customPath === '~') {
customPath = os.homedir();
}
const resolvedPath = path.resolve(customPath);
fs.mkdirSync(path.dirname(resolvedPath), { recursive: true });
fs.writeFileSync(resolvedPath, basePrompt); // write to custom path from GEMINI_WRITE_SYSTEM_MD
}
}
}