Skip to content

Bring xterm headless to agent host #315187

Draft
anthonykim1 wants to merge 2 commits intomainfrom
anthonykim1/bringXtermToAgentHost
Draft

Bring xterm headless to agent host #315187
anthonykim1 wants to merge 2 commits intomainfrom
anthonykim1/bringXtermToAgentHost

Conversation

@anthonykim1
Copy link
Copy Markdown
Contributor

WIP

@anthonykim1 anthonykim1 self-assigned this May 8, 2026
Copilot AI review requested due to automatic review settings May 8, 2026 06:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a headless xterm “mirror” to the agent host terminal pipeline so the agent host can (a) provide rendered terminal snapshots and (b) track/normalize terminal input semantics (eg bracketed paste), and then wires Copilot shell tools to use these new capabilities.

Changes:

  • Introduces AgentHostHeadlessTerminal (xterm headless-backed) and integrates it into AgentHostTerminalManager to keep a rendered/mode-aware mirror of PTY output.
  • Adds writeCommandInput + formatTerminalCommandInput to normalize command writing (newline normalization and optional bracketed paste wrapping).
  • Updates Copilot shell tools and tests to prefer rendered reads and to route command execution through the command-input helper.
Show a summary per file
File Description
src/vs/platform/agentHost/test/node/copilotShellTools.test.ts Expands terminal manager mock and adds coverage for command formatting, read/write tool behavior, and timeout slicing.
src/vs/platform/agentHost/test/node/copilotAgent.test.ts Updates agent host terminal manager test stub to satisfy new terminal manager surface area.
src/vs/platform/agentHost/test/node/agentHostHeadlessTerminal.test.ts Adds unit tests for the new headless terminal mirror (responses, modes, rendering, resize/clear).
src/vs/platform/agentHost/node/copilot/copilotShellTools.ts Switches command execution to writeCommandInput and makes read prefer rendered output.
src/vs/platform/agentHost/node/agentHostTerminalManager.ts Adds headless xterm mirror, new command-write API, rendered content access, and bracketed paste mode tracking.
src/vs/platform/agentHost/node/agentHostHeadlessTerminal.ts New headless xterm mirror implementation (rendered snapshots + limited terminal query responses).

Copilot's findings

Comments suppressed due to low confidence (1)

src/vs/platform/agentHost/node/copilot/copilotShellTools.ts:413

  • Same trimming/offset issue as above: slicing fullContent using Math.min(offsetBefore, fullContent.length) can drop all partial output on timeout in some trim scenarios. Adjust the offset logic so timeout failures still include whatever output is currently retained in the buffer.
			logService.warn(`[ShellTool] Command timed out after ${timeoutMs}ms`);
			const fullContent = terminalManager.getContent(shell.terminalUri) ?? '';
			const newContent = fullContent.substring(Math.min(offsetBefore, fullContent.length));
			const output = prepareOutputForModel(newContent);
  • Files reviewed: 6/6 changed files
  • Comments generated: 3

Comment on lines 396 to 399
const fullContent = terminalManager.getContent(shell.terminalUri) ?? '';
const output = prepareOutputForModel(fullContent);
const newContent = fullContent.substring(Math.min(offsetBefore, fullContent.length));
const output = prepareOutputForModel(newContent);
finish(makeFailureResult(`Shell exited with code ${exitCode}\n${output}`));

import { Emitter, Event } from '../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import { ILogService } from '../../log/common/log.js';
Comment on lines +59 to +75
test('write failure does not poison later writes', async () => {
const terminal = createTerminal();
const inner = (terminal as unknown as { _terminal: { write: (data: string, callback: () => void) => void } })._terminal;
const originalWrite = inner.write.bind(inner);
let shouldThrow = true;
inner.write = (data: string, callback: () => void) => {
if (shouldThrow) {
shouldThrow = false;
throw new Error('synthetic write failure');
}
originalWrite(data, callback);
};

await terminal.writePtyData('first');
await terminal.writePtyData('second');

assert.strictEqual(await terminal.getRecentRenderedText(), 'second');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants