Skip to content

Commit 133c07d

Browse files
committed
Finish failed shell init cleanup
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bef9b9c0-98f2-4b26-8b8b-18119efe7b13
1 parent d4e434b commit 133c07d

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3957,7 +3957,9 @@ export class CopilotAgentSession extends Disposable {
39573957
await this._fileService.del(this._shellInitScriptInstanceDirectory(), { recursive: true });
39583958
this._shellInitScriptMaterializationAttempted = false;
39593959
} catch (error) {
3960-
if (!(error instanceof Error) || toFileOperationResult(error) !== FileOperationResult.FILE_NOT_FOUND) {
3960+
if (error instanceof Error && toFileOperationResult(error) === FileOperationResult.FILE_NOT_FOUND) {
3961+
this._shellInitScriptMaterializationAttempted = false;
3962+
} else {
39613963
this._logService.warn(`[Copilot:${this.sessionId}] Failed to remove shell init script: ${getErrorMessage(error)}`);
39623964
}
39633965
}

src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { join, sep } from '../../../../base/common/path.js';
1919
import { URI } from '../../../../base/common/uri.js';
2020
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
2121
import { INativeEnvironmentService } from '../../../environment/common/environment.js';
22-
import { FileSystemProviderCapabilities, IFileService, type IWriteFileOptions } from '../../../files/common/files.js';
22+
import { FileOperationError, FileOperationResult, FileSystemProviderCapabilities, IFileService, type IWriteFileOptions } from '../../../files/common/files.js';
2323
import { InstantiationService } from '../../../instantiation/common/instantiationService.js';
2424
import { ServiceCollection } from '../../../instantiation/common/serviceCollection.js';
2525
import { ILogService, NullLogService } from '../../../log/common/log.js';
@@ -717,6 +717,7 @@ async function createAgentSession(disposables: DisposableStore, options?: {
717717
shellInitWriteGate?: Promise<void>;
718718
onShellInitWrite?: () => void;
719719
shellInitWriteFailureLeavesArtifact?: boolean;
720+
shellInitDeleteMissingThrows?: boolean;
720721
sessionDatabase?: ISessionDatabase;
721722
/** Configure the mock session before {@link CopilotAgentSession.initializeSession} runs. */
722723
configureMockSession?: (session: MockCopilotSession) => void;
@@ -891,6 +892,9 @@ async function createAgentSession(disposables: DisposableStore, options?: {
891892
mockSession.operationLog.push('file.delete:shellInit');
892893
}
893894
const matches = [...storedFileContents.keys()].filter(key => key.startsWith(resource.toString()) || key.startsWith(resource.fsPath));
895+
if (options?.shellInitDeleteMissingThrows && resource.fsPath.includes('/agentHost/shellInit/') && matches.length === 0) {
896+
throw new FileOperationError('not found', FileOperationResult.FILE_NOT_FOUND);
897+
}
894898
// Like the disk provider, a non-recursive delete removes only an
895899
// empty directory and fails while descendants remain.
896900
if (!delOptions?.recursive && matches.some(key => key !== resource.toString() && key !== resource.fsPath)) {
@@ -12385,6 +12389,22 @@ Use the attached image as context.
1238512389
});
1238612390
});
1238712391

12392+
test('does not retry cleanup when a failed write created no directory', async () => {
12393+
const { session, mockSession, setConfigValue } = await createAgentSession(disposables, {
12394+
shellInitWriteFailures: 1,
12395+
shellInitDeleteMissingThrows: true,
12396+
});
12397+
setConfigValue(SessionConfigKey.ShellInitSnippets, [initScript]);
12398+
await session.send('go', undefined, 'turn-1', 'interactive');
12399+
12400+
setConfigValue(SessionConfigKey.ShellInitSnippets, []);
12401+
await session.send('go', undefined, 'turn-2', 'interactive');
12402+
const deletesAfterClear = mockSession.operationLog.filter(operation => operation === 'file.delete:shellInit').length;
12403+
await session.send('go', undefined, 'turn-3', 'interactive');
12404+
12405+
assert.strictEqual(mockSession.operationLog.filter(operation => operation === 'file.delete:shellInit').length, deletesAfterClear);
12406+
});
12407+
1238812408
test('uses atomic writes when the file provider supports them', async () => {
1238912409
const { mockSession, fileWriteOptions } = await createAgentSession(disposables, {
1239012410
configValues: { [SessionConfigKey.ShellInitSnippets]: [initScript] },

0 commit comments

Comments
 (0)