mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-17 09:30:58 -07:00
fix(core): prevent hangs in non-interactive mode and improve agent guidance
- Injects headless-safe environment variables into non-interactive subprocesses to prevent credential prompt deadlocks (fixes #16567). - Updates system instructions for non-interactive mode to discourage impossible user questions (addresses #5724). - Adds unit tests to verify environment injection.
This commit is contained in:
@@ -851,7 +851,7 @@ Use the following guidelines to optimize your search and read patterns.
|
||||
- **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked.
|
||||
- **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes.
|
||||
- **Explain Before Acting:** Never call tools in silence. You MUST provide a concise, one-sentence explanation of your intent or strategy immediately before executing tool calls. This is essential for transparency, especially when confirming a request or answering a question. Silence is only acceptable for repetitive, low-level discovery operations (e.g., sequential file reads) where narration would be noisy.
|
||||
- **Continue the work** You are not to interact with the user. Do your best to complete the task at hand, using your best judgement and avoid asking user for any additional information.
|
||||
- **Non-Interactive Environment:** You are running in a headless/CI environment and cannot interact with the user. Do not ask the user questions or request additional information, as the session will terminate. Use your best judgment to complete the task. If a tool fails because it requires interactive authentication or user input, do not retry it indefinitely; instead, explain the limitation and suggest how the user can provide the required data (e.g., via environment variables).
|
||||
|
||||
# Hook Context
|
||||
|
||||
@@ -973,7 +973,7 @@ Use the following guidelines to optimize your search and read patterns.
|
||||
- **Explaining Changes:** After completing a code modification or file operation *do not* provide summaries unless asked.
|
||||
- **Do Not revert changes:** Do not revert changes to the codebase unless asked to do so by the user. Only revert changes made by you if they have resulted in an error or if the user has explicitly asked you to revert the changes.
|
||||
- **Explain Before Acting:** Never call tools in silence. You MUST provide a concise, one-sentence explanation of your intent or strategy immediately before executing tool calls. This is essential for transparency, especially when confirming a request or answering a question. Silence is only acceptable for repetitive, low-level discovery operations (e.g., sequential file reads) where narration would be noisy.
|
||||
- **Continue the work** You are not to interact with the user. Do your best to complete the task at hand, using your best judgement and avoid asking user for any additional information.
|
||||
- **Non-Interactive Environment:** You are running in a headless/CI environment and cannot interact with the user. Do not ask the user questions or request additional information, as the session will terminate. Use your best judgment to complete the task. If a tool fails because it requires interactive authentication or user input, do not retry it indefinitely; instead, explain the limitation and suggest how the user can provide the required data (e.g., via environment variables).
|
||||
|
||||
# Hook Context
|
||||
|
||||
|
||||
@@ -573,7 +573,7 @@ function mandateConflictResolution(hasHierarchicalMemory: boolean): string {
|
||||
function mandateContinueWork(interactive: boolean): string {
|
||||
if (interactive) return '';
|
||||
return `
|
||||
- **Continue the work** You are not to interact with the user. Do your best to complete the task at hand, using your best judgement and avoid asking user for any additional information.`;
|
||||
- **Non-Interactive Environment:** You are running in a headless/CI environment and cannot interact with the user. Do not ask the user questions or request additional information, as the session will terminate. Use your best judgment to complete the task. If a tool fails because it requires interactive authentication or user input, do not retry it indefinitely; instead, explain the limitation and suggest how the user can provide the required data (e.g., via environment variables).`;
|
||||
}
|
||||
|
||||
function workflowStepResearch(options: PrimaryWorkflowsOptions): string {
|
||||
|
||||
@@ -1703,4 +1703,39 @@ describe('ShellExecutionService environment variables', () => {
|
||||
mockChildProcess.emit('close', 0, null);
|
||||
await new Promise(process.nextTick);
|
||||
});
|
||||
|
||||
it('should include headless git and gh environment variables in non-interactive mode', async () => {
|
||||
vi.resetModules();
|
||||
const { ShellExecutionService } = await import(
|
||||
'./shellExecutionService.js'
|
||||
);
|
||||
|
||||
mockGetPty.mockResolvedValue(null); // Force child_process fallback
|
||||
await ShellExecutionService.execute(
|
||||
'test-cp-headless-git',
|
||||
'/',
|
||||
vi.fn(),
|
||||
new AbortController().signal,
|
||||
false, // non-interactive
|
||||
shellExecutionConfig,
|
||||
);
|
||||
|
||||
expect(mockCpSpawn).toHaveBeenCalled();
|
||||
const cpEnv = mockCpSpawn.mock.calls[0][2].env;
|
||||
expect(cpEnv).toHaveProperty('GIT_TERMINAL_PROMPT', '0');
|
||||
expect(cpEnv).toHaveProperty('GIT_ASKPASS', '');
|
||||
expect(cpEnv).toHaveProperty('SSH_ASKPASS', '');
|
||||
expect(cpEnv).toHaveProperty('GH_PROMPT_DISABLED', '1');
|
||||
expect(cpEnv).toHaveProperty('GCM_INTERACTIVE', 'never');
|
||||
expect(cpEnv).toHaveProperty('DISPLAY', '');
|
||||
expect(cpEnv).toHaveProperty('DBUS_SESSION_BUS_ADDRESS', '');
|
||||
expect(cpEnv).toHaveProperty('GIT_CONFIG_COUNT', '1');
|
||||
expect(cpEnv).toHaveProperty('GIT_CONFIG_KEY_0', 'credential.helper');
|
||||
expect(cpEnv).toHaveProperty('GIT_CONFIG_VALUE_0', '');
|
||||
|
||||
// Ensure child_process exits
|
||||
mockChildProcess.emit('exit', 0, null);
|
||||
mockChildProcess.emit('close', 0, null);
|
||||
await new Promise(process.nextTick);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -316,6 +316,18 @@ export class ShellExecutionService {
|
||||
[GEMINI_CLI_IDENTIFICATION_ENV_VAR]:
|
||||
GEMINI_CLI_IDENTIFICATION_ENV_VAR_VALUE,
|
||||
TERM: 'xterm-256color',
|
||||
// Disable interactive prompts and session-linked credential helpers
|
||||
// in non-interactive mode to prevent hangs in detached process groups.
|
||||
GIT_TERMINAL_PROMPT: '0',
|
||||
GIT_ASKPASS: '',
|
||||
SSH_ASKPASS: '',
|
||||
GH_PROMPT_DISABLED: '1',
|
||||
GCM_INTERACTIVE: 'never',
|
||||
DISPLAY: '',
|
||||
DBUS_SESSION_BUS_ADDRESS: '',
|
||||
GIT_CONFIG_COUNT: '1',
|
||||
GIT_CONFIG_KEY_0: 'credential.helper',
|
||||
GIT_CONFIG_VALUE_0: '',
|
||||
PAGER: 'cat',
|
||||
GIT_PAGER: 'cat',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user