Skip to content

Commit b78df1a

Browse files
committed
Differentiate output from additional info, fix outputLineCount
Fixes microsoft#257442
1 parent ebd5fb1 commit b78df1a

File tree

5 files changed

+55
-35
lines changed

5 files changed

+55
-35
lines changed

src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/basicExecuteStrategy.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { isNumber } from '../../../../../../base/common/types.js';
1111
import type { ICommandDetectionCapability } from '../../../../../../platform/terminal/common/capabilities/capabilities.js';
1212
import { ITerminalLogService } from '../../../../../../platform/terminal/common/terminal.js';
1313
import type { ITerminalInstance } from '../../../../terminal/browser/terminal.js';
14-
import { trackIdleOnPrompt, waitForIdle, type ITerminalExecuteStrategy } from './executeStrategy.js';
14+
import { trackIdleOnPrompt, waitForIdle, type ITerminalExecuteStrategy, type ITerminalExecuteStrategyResult } from './executeStrategy.js';
1515

1616
/**
1717
* This strategy is used when shell integration is enabled, but rich command detection was not
@@ -45,7 +45,7 @@ export class BasicExecuteStrategy implements ITerminalExecuteStrategy {
4545
) {
4646
}
4747

48-
async execute(commandLine: string, token: CancellationToken): Promise<{ result: string; exitCode?: number; error?: string }> {
48+
async execute(commandLine: string, token: CancellationToken): Promise<ITerminalExecuteStrategyResult> {
4949
const store = new DisposableStore();
5050
try {
5151
const idlePromptPromise = trackIdleOnPrompt(this._instance, 1000, store);
@@ -107,35 +107,37 @@ export class BasicExecuteStrategy implements ITerminalExecuteStrategy {
107107
const endMarker = store.add(xterm.raw.registerMarker());
108108

109109
// Assemble final result
110-
let result: string | undefined;
110+
let output: string | undefined;
111+
const additionalInformationLines: string[] = [];
111112
if (finishedCommand) {
112113
const commandOutput = finishedCommand?.getOutput();
113114
if (commandOutput !== undefined) {
114115
this._logService.debug('RunInTerminalTool#Basic: Fetched output via finished command');
115-
result = commandOutput;
116+
output = commandOutput;
116117
}
117118
}
118-
if (result === undefined) {
119+
if (output === undefined) {
119120
try {
120-
result = xterm.getContentsAsText(startMarker, endMarker);
121+
output = xterm.getContentsAsText(startMarker, endMarker);
121122
this._logService.debug('RunInTerminalTool#Basic: Fetched output via markers');
122123
} catch {
123124
this._logService.debug('RunInTerminalTool#Basic: Failed to fetch output via markers');
124-
result = 'Failed to retrieve command output';
125+
additionalInformationLines.push('Failed to retrieve command output');
125126
}
126127
}
127128

128-
if (result.trim().length === 0) {
129-
result = 'Command produced no output';
129+
if (output !== undefined && output.trim().length === 0) {
130+
additionalInformationLines.push('Command produced no output');
130131
}
131132

132133
const exitCode = finishedCommand?.exitCode;
133134
if (isNumber(exitCode) && exitCode > 0) {
134-
result += `\n\nCommand exited with code ${exitCode}`;
135+
additionalInformationLines.push(`Command exited with code ${exitCode}`);
135136
}
136137

137138
return {
138-
result,
139+
output,
140+
additionalInformation: additionalInformationLines.length > 0 ? additionalInformationLines.join('\n') : undefined,
139141
exitCode,
140142
};
141143
} finally {

src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/executeStrategy.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ export interface ITerminalExecuteStrategy {
1515
* Executes a command line and gets a result designed to be passed directly to an LLM. The
1616
* result will include information about the exit code.
1717
*/
18-
execute(commandLine: string, token: CancellationToken): Promise<{ result: string; exitCode?: number; error?: string }>;
18+
execute(commandLine: string, token: CancellationToken): Promise<ITerminalExecuteStrategyResult>;
19+
}
20+
21+
export interface ITerminalExecuteStrategyResult {
22+
output: string | undefined;
23+
additionalInformation?: string;
24+
exitCode?: number;
25+
error?: string;
1926
}
2027

2128
export async function waitForIdle(onData: Event<unknown>, idleDurationMs: number): Promise<void> {

src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/noneExecuteStrategy.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { CancellationError } from '../../../../../../base/common/errors.js';
88
import { DisposableStore } from '../../../../../../base/common/lifecycle.js';
99
import { ITerminalLogService } from '../../../../../../platform/terminal/common/terminal.js';
1010
import type { ITerminalInstance } from '../../../../terminal/browser/terminal.js';
11-
import { waitForIdle, type ITerminalExecuteStrategy } from './executeStrategy.js';
11+
import { waitForIdle, type ITerminalExecuteStrategy, type ITerminalExecuteStrategyResult } from './executeStrategy.js';
1212

1313
/**
1414
* This strategy is used when no shell integration is available. There are very few extension APIs
@@ -25,7 +25,7 @@ export class NoneExecuteStrategy implements ITerminalExecuteStrategy {
2525
) {
2626
}
2727

28-
async execute(commandLine: string, token: CancellationToken): Promise<{ result: string; exitCode?: number; error?: string }> {
28+
async execute(commandLine: string, token: CancellationToken): Promise<ITerminalExecuteStrategyResult> {
2929
const store = new DisposableStore();
3030
try {
3131
if (token.isCancellationRequested) {
@@ -68,16 +68,18 @@ export class NoneExecuteStrategy implements ITerminalExecuteStrategy {
6868
const endMarker = store.add(xterm.raw.registerMarker());
6969

7070
// Assemble final result - exit code is not available without shell integration
71-
let result: string;
71+
let output: string | undefined;
72+
const additionalInformationLines: string[] = [];
7273
try {
73-
result = xterm.getContentsAsText(startMarker, endMarker);
74+
output = xterm.getContentsAsText(startMarker, endMarker);
7475
this._logService.debug('RunInTerminalTool#None: Fetched output via markers');
7576
} catch {
7677
this._logService.debug('RunInTerminalTool#None: Failed to fetch output via markers');
77-
result = 'Failed to retrieve command output';
78+
additionalInformationLines.push('Failed to retrieve command output');
7879
}
7980
return {
80-
result,
81+
output,
82+
additionalInformation: additionalInformationLines.length > 0 ? additionalInformationLines.join('\n') : undefined,
8183
exitCode: undefined,
8284
};
8385
} finally {

src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/richExecuteStrategy.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { isNumber } from '../../../../../../base/common/types.js';
1111
import type { ICommandDetectionCapability, ITerminalCommand } from '../../../../../../platform/terminal/common/capabilities/capabilities.js';
1212
import { ITerminalLogService } from '../../../../../../platform/terminal/common/terminal.js';
1313
import type { ITerminalInstance } from '../../../../terminal/browser/terminal.js';
14-
import { trackIdleOnPrompt, type ITerminalExecuteStrategy } from './executeStrategy.js';
14+
import { trackIdleOnPrompt, type ITerminalExecuteStrategy, type ITerminalExecuteStrategyResult } from './executeStrategy.js';
1515

1616
/**
1717
* This strategy is used when the terminal has rich shell integration/command detection is
@@ -30,7 +30,7 @@ export class RichExecuteStrategy implements ITerminalExecuteStrategy {
3030
) {
3131
}
3232

33-
async execute(commandLine: string, token: CancellationToken): Promise<{ result: string; exitCode?: number; error?: string }> {
33+
async execute(commandLine: string, token: CancellationToken): Promise<ITerminalExecuteStrategyResult> {
3434
const store = new DisposableStore();
3535
try {
3636
// Ensure xterm is available
@@ -66,42 +66,46 @@ export class RichExecuteStrategy implements ITerminalExecuteStrategy {
6666
this._logService.debug(`RunInTerminalTool#Rich: Executing command line \`${commandLine}\``);
6767
this._instance.runCommand(commandLine, true);
6868

69+
// Wait for the terminal to idle
6970
this._logService.debug(`RunInTerminalTool#Rich: Waiting for done event`);
7071
const finishedCommand = await onDone;
7172
if (token.isCancellationRequested) {
7273
throw new CancellationError();
7374
}
7475
const endMarker = store.add(xterm.raw.registerMarker());
7576

76-
let result: string | undefined;
77+
// Assemble final result
78+
let output: string | undefined;
79+
const additionalInformationLines: string[] = [];
7780
if (finishedCommand) {
7881
const commandOutput = finishedCommand?.getOutput();
7982
if (commandOutput !== undefined) {
8083
this._logService.debug('RunInTerminalTool#Rich: Fetched output via finished command');
81-
result = commandOutput;
84+
output = commandOutput;
8285
}
8386
}
84-
if (result === undefined) {
87+
if (output === undefined) {
8588
try {
86-
result = xterm.getContentsAsText(startMarker, endMarker);
89+
output = xterm.getContentsAsText(startMarker, endMarker);
8790
this._logService.debug('RunInTerminalTool#Rich: Fetched output via markers');
8891
} catch {
8992
this._logService.debug('RunInTerminalTool#Basic: Failed to fetch output via markers');
90-
result = 'Failed to retrieve command output';
93+
additionalInformationLines.push('Failed to retrieve command output');
9194
}
9295
}
9396

94-
if (result.trim().length === 0) {
95-
result = 'Command produced no output';
97+
if (output !== undefined && output.trim().length === 0) {
98+
additionalInformationLines.push('Command produced no output');
9699
}
97100

98101
const exitCode = finishedCommand?.exitCode;
99102
if (isNumber(exitCode) && exitCode > 0) {
100-
result += `\n\nCommand exited with code ${exitCode}`;
103+
additionalInformationLines.push(`Command exited with code ${exitCode}`);
101104
}
102105

103106
return {
104-
result,
107+
output,
108+
additionalInformation: additionalInformationLines.length > 0 ? additionalInformationLines.join('\n') : undefined,
105109
exitCode,
106110
};
107111
} finally {

src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/runInTerminalTool.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -390,15 +390,20 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
390390
}
391391
this._logService.debug(`RunInTerminalTool: Using \`${strategy.type}\` execute strategy for command \`${command}\``);
392392
const executeResult = await strategy.execute(command, token);
393-
this._logService.debug(`RunInTerminalTool: Finished \`${strategy.type}\` execute strategy with exitCode \`${executeResult.exitCode}\`, result.length \`${executeResult.result.length}\`, error \`${executeResult.error}\``);
394-
outputLineCount = count(executeResult.result, '\n');
393+
this._logService.debug(`RunInTerminalTool: Finished \`${strategy.type}\` execute strategy with exitCode \`${executeResult.exitCode}\`, result.length \`${executeResult.output?.length}\`, error \`${executeResult.error}\``);
394+
outputLineCount = executeResult.output === undefined ? 0 : count(executeResult.output, '\n') + 1;
395395
exitCode = executeResult.exitCode;
396396
error = executeResult.error;
397-
if (typeof executeResult.result === 'string') {
398-
terminalResult = executeResult.result;
399-
} else {
400-
return executeResult.result;
397+
398+
const resultArr: string[] = [];
399+
if (executeResult.output !== undefined) {
400+
resultArr.push(executeResult.output);
401401
}
402+
if (executeResult.additionalInformation) {
403+
resultArr.push(executeResult.additionalInformation);
404+
}
405+
terminalResult = resultArr.join('\n\n');
406+
402407
} catch (e) {
403408
this._logService.debug(`RunInTerminalTool: Threw exception`);
404409
toolTerminal.instance.dispose();

0 commit comments

Comments
 (0)