run_in_terminal: promote sync command to background after idle output#315885
Conversation
If a synchronous run_in_terminal call produces no output for N ms, win the foreground race with a new idleSilence candidate that mirrors the existing timeout handler: promote the execution to background, return the terminal ID + output collected so far, append a steering hint. The process is never killed. Gated on chat.tools.terminal.idleSilenceTimeoutMs (default 60000, 0 disables). Listener and scheduler are owned by the existing raceCleanup DisposableStore so they go away when another candidate wins. Async (waitStrategy === 'idle') path is unchanged. Fixes #315884
|
/requires-eval-assessment terminalbench2 gpt-5.4,claude-opus-4.6,claude-opus-4.7 |
There was a problem hiding this comment.
Pull request overview
This PR updates the run_in_terminal tool’s synchronous (foreground) execution path to avoid indefinite blocking when a command produces no output for an extended period, by promoting the execution to a background terminal after an “idle output” threshold and returning partial output plus steering guidance.
Changes:
- Added a new setting
chat.tools.terminal.idleSilenceTimeoutMs(default60000,0disables) to control idle-silence promotion behavior. - Extended the foreground
Promise.raceinrunInTerminalTool.tswith anidleSilencecandidate driven by aRunOnceSchedulerthat resets on terminal output. - Added a new steering note for the idle-silence promotion result so the model can continue via
get_terminal_output, provide input, or terminate if needed.
Show a summary per file
| File | Description |
|---|---|
| src/vs/workbench/contrib/terminalContrib/chatAgentTools/common/terminalChatAgentToolsConfiguration.ts | Registers the new chat.tools.terminal.idleSilenceTimeoutMs configuration setting and schema metadata. |
| src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/tools/runInTerminalTool.ts | Implements the idle-output promotion race candidate and emits an idle-silence steering note when it wins. |
Copilot's findings
- Files reviewed: 2/2 changed files
- Comments generated: 2
|
⏳ Queued vscode build for
|
Replace the boolean mentionTimeout parameter on _buildInputNeededSteeringText with a 'none' | 'timeout' | 'idleSilence' discriminator so the idle-silence promotion result no longer reuses the timeout wording. Add focused unit tests covering each mode.
|
Addressed both review comments in 6127d25: Comment 1 (idle-silence wording): Replaced the Comment 2 (test coverage): Added a focused
A full integration test of the race candidate itself would require extending the mock terminal with an |
|
⏳ Queued vscode build for
|
|
⏳ Queued vscode build for
|
|
🔄 First vscode build failed; retried failed stages: https://dev.azure.com/monacotools/Monaco/_build/results?buildId=438396 |
|
❌ Failed to queue vscode build for The federated identity Fix: in Azure DevOps, open the pipeline → ⋮ → Security, and grant az pipelines run output |
Fixes #315884
If a synchronous
run_in_terminalcall produces no output for N ms, win the foreground race with a newidleSilencecandidate that mirrors the existingtimeouthandler: promote the execution to background, return the terminal ID + output collected so far, and append a steering hint. The process is never killed. The model can then callget_terminal_outputto keep watching,send_to_terminalif it suspects an input prompt, orkill_terminalif it judges the command stuck.Gated on a new setting
chat.tools.terminal.idleSilenceTimeoutMs(default60000;0disables).Why this is safe
waitStrategy === 'idle') path is unchanged — it already has the OutputMonitor idle signal.RunOnceSchedulerare owned by the existingraceCleanupDisposableStore, so they go away when another race candidate wins.Cases this catches
Silent long-running commands the foreground path has no answer for today:
jjsnapshotting a Firefox-sized checkout (the real repro that motivated this), stalled SSH handshakes,git fetchagainst a dead remote, etc. See #315884 for the full repro.