diff --git a/src/vs/platform/agentHost/node/agentService.ts b/src/vs/platform/agentHost/node/agentService.ts index bab9b35df50..11f8d6b7e91 100644 --- a/src/vs/platform/agentHost/node/agentService.ts +++ b/src/vs/platform/agentHost/node/agentService.ts @@ -1306,12 +1306,18 @@ export class AgentService extends Disposable implements IAgentService { private async _awaitInitialProviderMigration(): Promise { const providers = [...this._providers.values()]; const results = await Promise.allSettled(providers.map(provider => this._initialProviderMigrations.get(provider.id) ?? Promise.resolve())); + const retries: Promise[] = []; for (let index = 0; index < results.length; index++) { const result = results[index]; if (result.status === 'rejected') { - this._logService.warn(`[AgentService] initial provider catalogs: provider ${providers[index].id} failed and will be retried on the next signal`, result.reason); + const provider = providers[index]; + this._logService.warn(`[AgentService] initial provider catalog for ${provider.id} was unavailable; retrying before listing sessions`, result.reason); + const retry = this._ensureLegacyChatsMigrated(provider, true); + this._initialProviderMigrations.set(provider.id, retry); + retries.push(retry); } } + await Promise.all(retries); } /** @@ -1474,7 +1480,7 @@ export class AgentService extends Disposable implements IAgentService { } const sessions = await this._enumerateLegacyProviderSessions(provider); if (sessions === undefined) { - return; + throw new Error(`Provider ${provider.id} cannot enumerate its native session catalog yet`); } const existing = new Map((await this._listRegisteredSessions()).map(session => [session.session.toString(), session.external])); const migrationLimiter = new Limiter(4); diff --git a/src/vs/platform/agentHost/test/node/agentService.test.ts b/src/vs/platform/agentHost/test/node/agentService.test.ts index 996217099ca..c425b3ed923 100644 --- a/src/vs/platform/agentHost/test/node/agentService.test.ts +++ b/src/vs/platform/agentHost/test/node/agentService.test.ts @@ -3965,14 +3965,16 @@ suite('AgentService (node dispatcher)', () => { assert.strictEqual(agent.listExternalChatsCalls, 1); }); - test('a discovery signal does not bypass completed legacy migration semantics', async () => { + test('listSessions rejects an unavailable migration catalog and retries it on the next call', async () => { class NotYetMigratableAgent extends MockAgent { migrationCalls = 0; enumerable = false; } const svc = disposables.add(new AgentService(new NullLogService(), fileService, createSessionDataService(), { _serviceBrand: undefined } as IProductService, createNoopGitService())); + svc.configurationService.updateRootConfig({ [AgentHostShowExternalSessionsConfigKey]: AgentHostExternalSessionsMode.All }); const agent = disposables.add(new NotYetMigratableAgent('copilot')); const legacy = AgentSession.uri('copilot', 'legacy-migration-not-ready'); + (agent as unknown as { _sessions: Map })._sessions.set(AgentSession.id(legacy), legacy); (agent as unknown as { listChatsToMigrate: () => Promise }).listChatsToMigrate = async () => { agent.migrationCalls++; return agent.enumerable @@ -3980,18 +3982,20 @@ suite('AgentService (node dispatcher)', () => { : undefined; }; svc.registerProvider(agent); - await svc.listSessions(); + await assert.rejects(svc.listSessions(), /cannot enumerate its native session catalog yet/); + const callsAfterFailure = agent.migrationCalls; agent.enumerable = true; - agent.fireDiscoveredChats([]); await timeout(0); - + const listed = await svc.listSessions(); assert.deepStrictEqual({ - migrationCalls: agent.migrationCalls, - registered: (await svc.getRegisteredSessions()).map(session => session.toString()), + retriedBeforeFailure: callsAfterFailure > 1, + retriedAfterFailure: agent.migrationCalls > callsAfterFailure, + listed: listed.map(session => session.session.toString()), }, { - migrationCalls: 1, - registered: [], + retriedBeforeFailure: true, + retriedAfterFailure: true, + listed: [legacy.toString()], }); });