mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-02 00:09:30 +01:00
Log recovery after timeout (#306751)
This commit is contained in:
@@ -368,15 +368,16 @@ export class SetupAgent extends Disposable implements IChatAgentImplementation {
|
||||
const disposables = new DisposableStore();
|
||||
disposables.add(toDisposable(() => clearTimeout(timeoutHandle)));
|
||||
try {
|
||||
const allReady = Promise.allSettled([
|
||||
whenAgentActivated,
|
||||
whenAgentReady,
|
||||
whenLanguageModelReady,
|
||||
whenToolsModelReady
|
||||
]);
|
||||
const ready = await Promise.race([
|
||||
timeout(this.environmentService.remoteAuthority ? 60000 /* increase for remote scenarios */ : 20000).then(() => 'timedout'),
|
||||
this.whenPanelAgentHasGuidance(disposables).then(() => 'panelGuidance'),
|
||||
Promise.allSettled([
|
||||
whenAgentActivated,
|
||||
whenAgentReady,
|
||||
whenLanguageModelReady,
|
||||
whenToolsModelReady
|
||||
])
|
||||
allReady
|
||||
]);
|
||||
|
||||
if (ready === 'panelGuidance') {
|
||||
@@ -401,41 +402,9 @@ export class SetupAgent extends Disposable implements IChatAgentImplementation {
|
||||
warningMessage = localize('chatTookLongWarning', "Chat took too long to get ready. Please ensure you are signed in to {0} and that the extension `{1}` is installed and enabled. Click restart to try again if this issue persists.", defaultChat.provider.default.name, defaultChat.chatExtensionId);
|
||||
}
|
||||
|
||||
// Compute language model diagnostic info
|
||||
const languageModelIds = languageModelsService.getLanguageModelIds();
|
||||
let languageModelDefaultCount = 0;
|
||||
for (const id of languageModelIds) {
|
||||
const model = languageModelsService.lookupLanguageModel(id);
|
||||
if (model?.isDefaultForLocation[ChatAgentLocation.Chat]) {
|
||||
languageModelDefaultCount++;
|
||||
}
|
||||
}
|
||||
const diagnosticInfo = this.computeDiagnosticInfo(agentActivated, agentReady, languageModelReady, toolsModelReady, requestModel, languageModelsService, chatAgentService, modeInfo);
|
||||
|
||||
// Compute agent diagnostic info
|
||||
const defaultAgent = chatAgentService.getDefaultAgent(this.location, modeInfo?.kind);
|
||||
const agentHasDefault = !!defaultAgent;
|
||||
const agentDefaultIsCore = defaultAgent?.isCore ?? false;
|
||||
const contributedDefaultAgent = chatAgentService.getContributedDefaultAgent(this.location);
|
||||
const agentHasContributedDefault = !!contributedDefaultAgent;
|
||||
const agentContributedDefaultIsCore = contributedDefaultAgent?.isCore ?? false;
|
||||
const agentActivatedCount = chatAgentService.getActivatedAgents().length;
|
||||
|
||||
this.logService.warn(warningMessage, {
|
||||
agentActivated,
|
||||
agentReady,
|
||||
agentHasDefault,
|
||||
agentDefaultIsCore,
|
||||
agentHasContributedDefault,
|
||||
agentContributedDefaultIsCore,
|
||||
agentActivatedCount,
|
||||
agentLocation: this.location,
|
||||
agentModeKind: modeInfo?.kind,
|
||||
languageModelReady,
|
||||
languageModelCount: languageModelIds.length,
|
||||
languageModelDefaultCount,
|
||||
languageModelHasRequestedModel: !!requestModel.modelId,
|
||||
toolsModelReady
|
||||
});
|
||||
this.logService.warn(`[chat setup] ${warningMessage}`, diagnosticInfo);
|
||||
|
||||
type ChatSetupTimeoutClassification = {
|
||||
owner: 'chrmarti';
|
||||
@@ -477,28 +446,8 @@ export class SetupAgent extends Disposable implements IChatAgentImplementation {
|
||||
isAnonymous: boolean;
|
||||
matchingWelcomeViewWhen: string;
|
||||
};
|
||||
const chatViewPane = this.viewsService.getActiveViewWithId(ChatViewId) as ChatViewPane | undefined;
|
||||
const matchingWelcomeView = chatViewPane?.getMatchingWelcomeView();
|
||||
|
||||
this.telemetryService.publicLog2<ChatSetupTimeoutEvent, ChatSetupTimeoutClassification>('chatSetup.timeout', {
|
||||
agentActivated,
|
||||
agentReady,
|
||||
agentHasDefault,
|
||||
agentDefaultIsCore,
|
||||
agentHasContributedDefault,
|
||||
agentContributedDefaultIsCore,
|
||||
agentActivatedCount,
|
||||
agentLocation: this.location,
|
||||
agentModeKind: modeInfo?.kind ?? '',
|
||||
languageModelReady,
|
||||
languageModelCount: languageModelIds.length,
|
||||
languageModelDefaultCount,
|
||||
languageModelHasRequestedModel: !!requestModel.modelId,
|
||||
toolsModelReady,
|
||||
isRemote: !!this.environmentService.remoteAuthority,
|
||||
isAnonymous: this.chatEntitlementService.anonymous,
|
||||
matchingWelcomeViewWhen: matchingWelcomeView?.when.serialize() ?? (chatViewPane ? 'noWelcomeView' : 'noChatViewPane'),
|
||||
});
|
||||
this.telemetryService.publicLog2<ChatSetupTimeoutEvent, ChatSetupTimeoutClassification>('chatSetup.timeout', diagnosticInfo);
|
||||
|
||||
progress({
|
||||
kind: 'warning',
|
||||
@@ -527,10 +476,56 @@ export class SetupAgent extends Disposable implements IChatAgentImplementation {
|
||||
});
|
||||
}
|
||||
|
||||
// This means Chat is unhealthy and we cannot retry the
|
||||
// request. Signal this to the outside via an event.
|
||||
this._onUnresolvableError.fire();
|
||||
return;
|
||||
// Wait for all readiness signals and log/send
|
||||
// telemetry about recovery after the timeout.
|
||||
await allReady;
|
||||
|
||||
const recoveryDiagnosticInfo = this.computeDiagnosticInfo(agentActivated, agentReady, languageModelReady, toolsModelReady, requestModel, languageModelsService, chatAgentService, modeInfo);
|
||||
|
||||
this.logService.info('[chat setup] Chat setup timeout recovered', recoveryDiagnosticInfo);
|
||||
|
||||
type ChatSetupTimeoutRecoveryClassification = {
|
||||
owner: 'chrmarti';
|
||||
comment: 'Provides insight into chat setup timeout recovery.';
|
||||
agentActivated: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the agent was activated.' };
|
||||
agentReady: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the agent was ready.' };
|
||||
agentHasDefault: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether a default agent exists for the location and mode.' };
|
||||
agentDefaultIsCore: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the default agent is a core agent.' };
|
||||
agentHasContributedDefault: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether a contributed default agent exists for the location.' };
|
||||
agentContributedDefaultIsCore: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the contributed default agent is a core agent.' };
|
||||
agentActivatedCount: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Number of activated agents at recovery time.' };
|
||||
agentLocation: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The chat agent location.' };
|
||||
agentModeKind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The chat mode kind.' };
|
||||
languageModelReady: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the language model was ready.' };
|
||||
languageModelCount: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Number of registered language models at recovery time.' };
|
||||
languageModelDefaultCount: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Number of language models with isDefaultForLocation[Chat] set at recovery time.' };
|
||||
languageModelHasRequestedModel: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether a specific model ID was requested.' };
|
||||
toolsModelReady: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the tools model was ready.' };
|
||||
isRemote: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether this is a remote scenario.' };
|
||||
isAnonymous: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether anonymous access is enabled.' };
|
||||
matchingWelcomeViewWhen: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The when clause of the matching extension welcome view, if any.' };
|
||||
};
|
||||
type ChatSetupTimeoutRecoveryEvent = {
|
||||
agentActivated: boolean;
|
||||
agentReady: boolean;
|
||||
agentHasDefault: boolean;
|
||||
agentDefaultIsCore: boolean;
|
||||
agentHasContributedDefault: boolean;
|
||||
agentContributedDefaultIsCore: boolean;
|
||||
agentActivatedCount: number;
|
||||
agentLocation: string;
|
||||
agentModeKind: string;
|
||||
languageModelReady: boolean;
|
||||
languageModelCount: number;
|
||||
languageModelDefaultCount: number;
|
||||
languageModelHasRequestedModel: boolean;
|
||||
toolsModelReady: boolean;
|
||||
isRemote: boolean;
|
||||
isAnonymous: boolean;
|
||||
matchingWelcomeViewWhen: string;
|
||||
};
|
||||
|
||||
this.telemetryService.publicLog2<ChatSetupTimeoutRecoveryEvent, ChatSetupTimeoutRecoveryClassification>('chatSetup.timeoutRecovery', recoveryDiagnosticInfo);
|
||||
}
|
||||
} finally {
|
||||
disposables.dispose();
|
||||
@@ -647,6 +642,42 @@ export class SetupAgent extends Disposable implements IChatAgentImplementation {
|
||||
}
|
||||
}
|
||||
|
||||
private computeDiagnosticInfo(agentActivated: boolean, agentReady: boolean, languageModelReady: boolean, toolsModelReady: boolean, requestModel: IChatRequestModel, languageModelsService: ILanguageModelsService, chatAgentService: IChatAgentService, modeInfo: { kind?: ChatModeKind } | undefined) {
|
||||
const languageModelIds = languageModelsService.getLanguageModelIds();
|
||||
let languageModelDefaultCount = 0;
|
||||
for (const id of languageModelIds) {
|
||||
const model = languageModelsService.lookupLanguageModel(id);
|
||||
if (model?.isDefaultForLocation[ChatAgentLocation.Chat]) {
|
||||
languageModelDefaultCount++;
|
||||
}
|
||||
}
|
||||
|
||||
const defaultAgent = chatAgentService.getDefaultAgent(this.location, modeInfo?.kind);
|
||||
const contributedDefaultAgent = chatAgentService.getContributedDefaultAgent(this.location);
|
||||
const chatViewPane = this.viewsService.getActiveViewWithId(ChatViewId) as ChatViewPane | undefined;
|
||||
const matchingWelcomeView = chatViewPane?.getMatchingWelcomeView();
|
||||
|
||||
return {
|
||||
agentActivated,
|
||||
agentReady,
|
||||
agentHasDefault: !!defaultAgent,
|
||||
agentDefaultIsCore: defaultAgent?.isCore ?? false,
|
||||
agentHasContributedDefault: !!contributedDefaultAgent,
|
||||
agentContributedDefaultIsCore: contributedDefaultAgent?.isCore ?? false,
|
||||
agentActivatedCount: chatAgentService.getActivatedAgents().length,
|
||||
agentLocation: this.location,
|
||||
agentModeKind: modeInfo?.kind ?? '',
|
||||
languageModelReady,
|
||||
languageModelCount: languageModelIds.length,
|
||||
languageModelDefaultCount,
|
||||
languageModelHasRequestedModel: !!requestModel.modelId,
|
||||
toolsModelReady,
|
||||
isRemote: !!this.environmentService.remoteAuthority,
|
||||
isAnonymous: this.chatEntitlementService.anonymous,
|
||||
matchingWelcomeViewWhen: matchingWelcomeView?.when.serialize() ?? (chatViewPane ? 'noWelcomeView' : 'noChatViewPane'),
|
||||
};
|
||||
}
|
||||
|
||||
private async doInvokeWithSetup(request: IChatAgentRequest, progress: (part: IChatProgress) => void, chatService: IChatService, languageModelsService: ILanguageModelsService, chatWidgetService: IChatWidgetService, chatAgentService: IChatAgentService, languageModelToolsService: ILanguageModelToolsService, defaultAccountService: IDefaultAccountService): Promise<IChatAgentResult> {
|
||||
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: CHAT_SETUP_ACTION_ID, from: 'chat' });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user