diff --git a/src/vs/platform/agentHost/node/copilot/copilotAgent.ts b/src/vs/platform/agentHost/node/copilot/copilotAgent.ts index bf4ea118f95..688f70c6220 100644 --- a/src/vs/platform/agentHost/node/copilot/copilotAgent.ts +++ b/src/vs/platform/agentHost/node/copilot/copilotAgent.ts @@ -105,7 +105,7 @@ export class CopilotAgent extends Disposable implements IAgent { } } env['COPILOT_CLI_RUN_AS_NODE'] = '1'; - env['USE_BUILTIN_RIPGREP'] = '0'; + env['USE_BUILTIN_RIPGREP'] = 'false'; // Resolve the CLI entry point from node_modules. We can't use require.resolve() // because @github/copilot's exports map blocks direct subpath access. diff --git a/src/vs/sessions/contrib/changes/browser/changesView.ts b/src/vs/sessions/contrib/changes/browser/changesView.ts index 16e11f83457..2686c334ee5 100644 --- a/src/vs/sessions/contrib/changes/browser/changesView.ts +++ b/src/vs/sessions/contrib/changes/browser/changesView.ts @@ -644,8 +644,8 @@ export class ChangesViewPane extends ViewPane { const ciWidget = this.ciStatusWidget; const ciPane: IView = { element: ciElement, - minimumSize: ciMinHeight, - maximumSize: Number.POSITIVE_INFINITY, + get minimumSize() { return ciWidget.collapsed ? CIStatusWidget.HEADER_HEIGHT : ciMinHeight; }, + get maximumSize() { return ciWidget.collapsed ? CIStatusWidget.HEADER_HEIGHT : Number.POSITIVE_INFINITY; }, onDidChange: Event.map(this.ciStatusWidget.onDidChangeHeight, () => undefined), layout: (height) => { ciElement.style.height = `${height}px`; @@ -668,6 +668,25 @@ export class ChangesViewPane extends ViewPane { // Initially hide CI pane until checks arrive this.splitView.setViewVisible(1, false); + let savedCIPaneHeight = CIStatusWidget.HEADER_HEIGHT + CIStatusWidget.PREFERRED_BODY_HEIGHT; + this._register(this.ciStatusWidget.onDidToggleCollapsed(collapsed => { + if (!this.splitView || !this.ciStatusWidget) { + return; + } + if (collapsed) { + // Save current size before collapsing + const currentSize = this.splitView.getViewSize(1); + if (currentSize > CIStatusWidget.HEADER_HEIGHT) { + savedCIPaneHeight = currentSize; + } + this.splitView.resizeView(1, CIStatusWidget.HEADER_HEIGHT); + } else { + // Restore saved size on expand + this.splitView.resizeView(1, savedCIPaneHeight); + } + this.layoutSplitView(); + })); + this._register(this.ciStatusWidget.onDidChangeHeight(() => { if (!this.splitView || !this.ciStatusWidget) { return; @@ -1001,12 +1020,6 @@ export class ChangesViewPane extends ViewPane { ? { args: [sessionResource, this.agentSessionsService.getSession(sessionResource)?.metadata] } : { shouldForwardArgs: true }, buttonConfigProvider: (action) => { - if ( - action.id === 'chatEditing.viewAllSessionChanges' || - action.id === 'github.copilot.chat.openPullRequestCopilotCLIAgentSession.openPR' - ) { - return { showIcon: true, showLabel: false, isSecondary: true }; - } if (action.id === 'github.copilot.chat.createPullRequestCopilotCLIAgentSession.updatePR') { const customLabel = outgoingChanges > 0 ? `${action.label} ${outgoingChanges}↑` @@ -1022,9 +1035,20 @@ export class ChangesViewPane extends ViewPane { } return { showIcon: true, showLabel: false, isSecondary: true }; } + if ( + action.id === 'chatEditing.viewAllSessionChanges' || + action.id === 'github.copilot.chat.openPullRequestCopilotCLIAgentSession.openPR' + ) { + return { showIcon: true, showLabel: false, isSecondary: true }; + } + if (action.id === 'agentFeedbackEditor.action.submitActiveSession') { + return { showIcon: false, showLabel: true, isSecondary: false }; + } if ( action.id === 'github.copilot.chat.createPullRequestCopilotCLIAgentSession.createPR' || action.id === 'github.copilot.chat.mergeCopilotCLIAgentSessionChanges.merge' || + action.id === 'github.copilot.chat.checkoutPullRequestReroute' || + action.id === 'pr.checkoutFromChat' || action.id === 'github.copilot.sessions.initializeRepository' || action.id === 'github.copilot.sessions.commitChanges' || action.id === 'agentSession.markAsDone' @@ -1032,6 +1056,16 @@ export class ChangesViewPane extends ViewPane { return { showIcon: true, showLabel: true, isSecondary: false }; } + // Unknown actions (e.g. extension-contributed): only hide the label when an icon is present. + if (action instanceof MenuItemAction) { + const icon = action.item.icon; + if (icon) { + // Icon-only button (no forced secondary state so primary/secondary can be inferred). + return { showIcon: true, showLabel: false }; + } + } + + // Fall back to default button behavior for actions without an icon. return undefined; } } diff --git a/src/vs/sessions/contrib/changes/browser/ciStatusWidget.ts b/src/vs/sessions/contrib/changes/browser/ciStatusWidget.ts index f83c243b5b2..d9f7aecdff7 100644 --- a/src/vs/sessions/contrib/changes/browser/ciStatusWidget.ts +++ b/src/vs/sessions/contrib/changes/browser/ciStatusWidget.ts @@ -148,7 +148,7 @@ class CICheckListRenderer implements IListRenderer()); readonly onDidChangeHeight = this._onDidChangeHeight.event; + private readonly _onDidToggleCollapsed = this._register(new Emitter()); + readonly onDidToggleCollapsed = this._onDidToggleCollapsed.event; + private _checkCount = 0; + private _collapsed = false; private _model: GitHubPullRequestCIModel | undefined; private _sessionResource: URI | undefined; + private readonly _chevronNode: HTMLElement; get element(): HTMLElement { return this._domNode; @@ -181,6 +186,9 @@ export class CIStatusWidget extends Disposable { if (this._checkCount === 0) { return 0; } + if (this._collapsed) { + return CIStatusWidget.HEADER_HEIGHT; + } return CIStatusWidget.HEADER_HEIGHT + this._checkCount * CICheckListDelegate.ITEM_HEIGHT; } @@ -189,6 +197,11 @@ export class CIStatusWidget extends Disposable { return this._checkCount > 0; } + /** Whether the body is collapsed (header-only). */ + get collapsed(): boolean { + return this._collapsed; + } + constructor( container: HTMLElement, @IOpenerService private readonly _openerService: IOpenerService, @@ -201,11 +214,11 @@ export class CIStatusWidget extends Disposable { this._domNode = dom.append(container, $('.ci-status-widget')); this._domNode.style.display = 'none'; - // Header (always visible) + // Header (always visible, click to collapse/expand) this._headerNode = dom.append(this._domNode, $('.ci-status-widget-header')); this._titleNode = dom.append(this._headerNode, $('.ci-status-widget-title')); this._titleLabelNode = dom.append(this._titleNode, $('.ci-status-widget-title-label')); - this._titleLabelNode.textContent = localize('ci.checksLabel', "PR Checks"); + this._titleLabelNode.textContent = localize('ci.checksLabel', "Checks"); this._countsNode = dom.append(this._titleNode, $('.ci-status-widget-counts')); this._headerActionBarContainer = dom.append(this._headerNode, $('.ci-status-widget-header-actions')); this._headerActionBar = this._register(new ActionBar(this._headerActionBarContainer)); @@ -213,9 +226,33 @@ export class CIStatusWidget extends Disposable { e.preventDefault(); e.stopPropagation(); })); + this._chevronNode = dom.append(this._headerNode, $('.group-chevron')); + this._chevronNode.classList.add(...ThemeIcon.asClassNameArray(Codicon.chevronDown)); + + this._headerNode.setAttribute('role', 'button'); + this._headerNode.setAttribute('aria-label', localize('ci.toggleChecks', "Toggle PR Checks")); + this._headerNode.setAttribute('aria-expanded', 'true'); + this._headerNode.tabIndex = 0; + + this._register(dom.addDisposableListener(this._headerNode, dom.EventType.CLICK, e => { + // Don't toggle when clicking the action bar + if (dom.isAncestor(e.target as HTMLElement, this._headerActionBarContainer)) { + return; + } + this._toggleCollapsed(); + })); + this._register(dom.addDisposableListener(this._headerNode, dom.EventType.KEY_DOWN, e => { + if ((e.key === 'Enter' || e.key === ' ') && e.target === this._headerNode) { + e.preventDefault(); + this._toggleCollapsed(); + } + })); // Body (list of checks) - this._bodyNode = dom.append(this._domNode, $('.ci-status-widget-body')); + const bodyId = 'ci-status-widget-body'; + this._bodyNode = dom.append(this._domNode, $(`.${bodyId}`)); + this._bodyNode.id = bodyId; + this._headerNode.setAttribute('aria-controls', bodyId); const listContainer = $('.ci-status-widget-list'); this._list = this._register(this._instantiationService.createInstance( @@ -250,6 +287,7 @@ export class CIStatusWidget extends Disposable { this._model = model; if (!model) { this._checkCount = 0; + this._setCollapsed(false); this._renderBody([]); this._renderHeaderActions([]); this._domNode.style.display = 'none'; @@ -261,6 +299,7 @@ export class CIStatusWidget extends Disposable { if (checks.length === 0) { this._checkCount = 0; + this._setCollapsed(false); this._renderBody([]); this._renderHeaderActions([]); this._domNode.style.display = 'none'; @@ -344,9 +383,36 @@ export class CIStatusWidget extends Disposable { * Called by the parent view after computing available space. */ layout(height: number): void { + if (this._collapsed) { + this._bodyNode.style.display = 'none'; + return; + } + this._bodyNode.style.display = ''; this._list.layout(height); } + private _toggleCollapsed(): void { + this._setCollapsed(!this._collapsed); + this._onDidToggleCollapsed.fire(this._collapsed); + // Also fires onDidChangeHeight so the SplitView pane updates its min/max constraints + this._onDidChangeHeight.fire(); + } + + private _setCollapsed(collapsed: boolean): void { + this._collapsed = collapsed; + this._updateChevron(); + this._headerNode.setAttribute('aria-expanded', String(!collapsed)); + } + + private _updateChevron(): void { + this._chevronNode.className = 'group-chevron'; + this._chevronNode.classList.add( + ...ThemeIcon.asClassNameArray( + this._collapsed ? Codicon.chevronRight : Codicon.chevronDown + ) + ); + } + private _renderBody(checks: readonly ICICheckListItem[]): void { this._list.splice(0, this._list.length, checks); } @@ -421,7 +487,7 @@ function getCheckCounts(checks: readonly IGitHubCICheck[]): ICICheckCounts { function getCheckIcon(check: IGitHubCICheck): ThemeIcon { switch (check.status) { case GitHubCheckStatus.InProgress: - return Codicon.clock; + return Codicon.sync; case GitHubCheckStatus.Queued: return Codicon.circleFilled; case GitHubCheckStatus.Completed: diff --git a/src/vs/sessions/contrib/changes/browser/media/changesView.css b/src/vs/sessions/contrib/changes/browser/media/changesView.css index 104e6ed094f..056e1c31e2b 100644 --- a/src/vs/sessions/contrib/changes/browser/media/changesView.css +++ b/src/vs/sessions/contrib/changes/browser/media/changesView.css @@ -7,7 +7,7 @@ display: flex; flex-direction: column; height: 100%; - padding: 8px; + padding: 4px 8px 8px 8px; box-sizing: border-box; } @@ -136,7 +136,7 @@ display: flex; flex-direction: row; flex-wrap: nowrap; - gap: 6px; + gap: 4px; align-items: center; } @@ -149,7 +149,7 @@ /* Larger action buttons matching SCM ActionButton style */ .changes-view-body .chat-editing-session-actions.outside-card .monaco-button { height: 26px; - padding: 4px 14px; + padding: 4px; font-size: 12px; line-height: 18px; } @@ -157,19 +157,34 @@ /* Primary button grows to fill available space */ .changes-view-body .chat-editing-session-actions.outside-card .monaco-button:not(.secondary) { flex: 1; + min-width: 0; +} + +.changes-view-body .chat-editing-session-actions.outside-card .monaco-button:not(.secondary) > span:not(.codicon) { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } /* ButtonWithDropdown container grows to fill available space */ .changes-view-body .chat-editing-session-actions.outside-card .monaco-button-dropdown { flex: 1; + min-width: 0; display: flex; } .changes-view-body .chat-editing-session-actions.outside-card .monaco-button-dropdown > .monaco-button { flex: 1; + min-width: 0; box-sizing: border-box; } +.changes-view-body .chat-editing-session-actions.outside-card .monaco-button-dropdown > .monaco-button > span:not(.codicon) { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + .changes-view-body .chat-editing-session-actions.outside-card .monaco-button-dropdown > .monaco-button-dropdown-separator { flex: 0; } diff --git a/src/vs/sessions/contrib/changes/browser/media/ciStatusWidget.css b/src/vs/sessions/contrib/changes/browser/media/ciStatusWidget.css index 199b1b933ed..a435ec0c1f9 100644 --- a/src/vs/sessions/contrib/changes/browser/media/ciStatusWidget.css +++ b/src/vs/sessions/contrib/changes/browser/media/ciStatusWidget.css @@ -18,10 +18,50 @@ position: relative; display: flex; align-items: center; - gap: 6px; - padding: 2px 0; + /* gap: 6px; */ + padding: 6px 4px; + margin-top: 4px; + border-radius: 8px; min-height: 22px; font-weight: 500; + cursor: pointer; + user-select: none; +} + +.ci-status-widget-header:hover { + background-color: var(--vscode-list-hoverBackground); + padding-right: 22px; +} + +.ci-status-widget-header:focus { + padding-right: 22px; +} + +.ci-status-widget-header:focus-visible { + outline: 1px solid var(--vscode-focusBorder); + outline-offset: -1px; +} + +/* Chevron — right-aligned, visible on hover only */ +.ci-status-widget-header .group-chevron { + position: absolute; + right: 4px; + top: 50%; + transform: translateY(-50%); + width: 16px; + height: 16px; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + visibility: hidden; + opacity: 0; +} + +.ci-status-widget-header:hover .group-chevron, +.ci-status-widget-header:focus-within .group-chevron { + visibility: visible; + opacity: 0.7; } /* Title - single line, overflow ellipsis */ @@ -50,8 +90,7 @@ padding-right: 8px; } -.ci-status-widget.has-fix-actions:hover .ci-status-widget-counts, -.ci-status-widget.has-fix-actions:focus-within .ci-status-widget-counts { +.ci-status-widget-header:hover .ci-status-widget-counts, .ci-status-widget-header:focus .ci-status-widget-counts { visibility: hidden; } @@ -84,15 +123,9 @@ } .ci-status-widget-header-actions { - position: absolute; - right: 0; - display: none; - align-items: center; -} - -.ci-status-widget:hover .ci-status-widget-header-actions.has-actions, -.ci-status-widget:focus-within .ci-status-widget-header-actions.has-actions { + flex-shrink: 0; display: flex; + align-items: center; } .ci-status-widget-header-actions .monaco-action-bar { @@ -151,6 +184,12 @@ width: 100%; } +.ci-status-widget-check-label .monaco-icon-label::before { + font-size: 14px; + width: 14px; + height: 14px; +} + .ci-status-widget-check-label .monaco-icon-label-container, .ci-status-widget-check-label .monaco-icon-name-container { display: block; diff --git a/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupProviders.ts b/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupProviders.ts index 38de1e8d6b3..92c42cc9dce 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupProviders.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupProviders.ts @@ -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('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('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('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 { this.telemetryService.publicLog2('workbenchActionExecuted', { id: CHAT_SETUP_ACTION_ID, from: 'chat' }); diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/delegationSessionPickerActionItem.ts b/src/vs/workbench/contrib/chat/browser/widget/input/delegationSessionPickerActionItem.ts index 97d7049abd8..68a8717ba0a 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/delegationSessionPickerActionItem.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/delegationSessionPickerActionItem.ts @@ -122,9 +122,6 @@ export class DelegationSessionPickerActionItem extends SessionTypePickerActionIt } protected override _getSessionDescription(sessionTypeItem: ISessionTypeItem): string | undefined { - if (this._isSessionsWindow && sessionTypeItem.type === AgentSessionProviders.Cloud && !this._hasGitRepository()) { - return localize('chat.cloudRequiresGit', "Requires a Git repository"); - } return undefined; }