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:
cocosheng-g
2026-03-02 17:14:33 -05:00
committed by Coco Sheng
parent 1b69637032
commit 050fefe0c7
4 changed files with 50 additions and 3 deletions

View File

@@ -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

View File

@@ -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 {

View File

@@ -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);
});
});

View File

@@ -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',
},