From e13eb9b0fac82ef70c8ec032ad422b027edcd9e6 Mon Sep 17 00:00:00 2001 From: Osvaldo Ortega <48293249+osortega@users.noreply.github.com> Date: Thu, 9 Apr 2026 15:53:30 -0700 Subject: [PATCH] sessions: fix "Generate New Task" no-op on existing sessions (#308883) * Fix 'Generate New Task' no-op on existing sessions sendAndCreateChat only works for new (untitled) sessions or when multi-chat is enabled. For existing/completed sessions it threw an error that was silently swallowed, making the action appear to do nothing. Add a _generateNewTask helper that checks the session status: - Untitled sessions: use sendAndCreateChat (existing first-chat flow) - Existing sessions: send /generate-run-commands directly to the active chat widget via acceptInput Fixes #308805 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: use passed-in session, add sendAndCreateChat fallback - Use session.mainChat.resource instead of re-reading activeSession from global state, avoiding stale-reference bugs. - Fall back to sendAndCreateChat when no chat widget is found for the session, so the action is never a silent no-op. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify _generateNewTask: consolidate sendAndCreateChat fallback Both the untitled and widget-not-found paths called sendAndCreateChat, so collapse the if/else into a single widget-first-then-fallback flow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../contrib/chat/browser/runScriptAction.ts | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/vs/sessions/contrib/chat/browser/runScriptAction.ts b/src/vs/sessions/contrib/chat/browser/runScriptAction.ts index b6dfcba72fc..ccb692bd917 100644 --- a/src/vs/sessions/contrib/chat/browser/runScriptAction.ts +++ b/src/vs/sessions/contrib/chat/browser/runScriptAction.ts @@ -32,6 +32,7 @@ import { SessionsCategories } from '../../../common/categories.js'; import { ISessionsManagementService } from '../../../services/sessions/common/sessionsManagement.js'; import { IsActiveSessionBackgroundProviderContext, SessionsWelcomeVisibleContext } from '../../../common/contextkeys.js'; import { ISession } from '../../../services/sessions/common/session.js'; +import { IChatWidgetService } from '../../../../workbench/contrib/chat/browser/chat.js'; import { Menus } from '../../../browser/menus.js'; import { INonSessionTaskEntry, ISessionsConfigurationService, ISessionTaskWithTarget, ITaskEntry, TaskStorageTarget } from './sessionsConfigurationService.js'; import { IsAuxiliaryWindowContext } from '../../../../workbench/common/contextkeys.js'; @@ -123,6 +124,7 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr @IActionViewItemService private readonly _actionViewItemService: IActionViewItemService, @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, @ITelemetryService private readonly _telemetryService: ITelemetryService, + @IChatWidgetService private readonly _chatWidgetService: IChatWidgetService, ) { super(); @@ -171,6 +173,7 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr that._activeRunState, (session: ISession) => that._showConfigureQuickPick(session), (session: ISession, existingTask: INonSessionTaskEntry, mode?: TaskConfigurationMode) => that._showCustomCommandInput(session, existingTask, mode), + (session: ISession) => that._generateNewTask(session), ); }, )); @@ -267,12 +270,24 @@ export class RunScriptContribution extends Disposable implements IWorkbenchContr async run(): Promise { logSessionsInteraction(that._telemetryService, 'generateNewTask', 'menu'); - await that._sessionManagementService.sendAndCreateChat(session, { query: '/generate-run-commands' }); + await that._generateNewTask(session); } })); })); } + private async _generateNewTask(session: ISession): Promise { + const query = '/generate-run-commands'; + // Prefer sending to the already-open chat widget for the session; + // fall back to sendAndCreateChat for untitled sessions or when no widget is loaded. + const widget = this._chatWidgetService.getWidgetBySessionResource(session.mainChat.resource); + if (widget) { + await widget.acceptInput(query); + } else { + await this._sessionManagementService.sendAndCreateChat(session, { query }); + } + } + private async _showConfigureQuickPick(session: ISession): Promise { const nonSessionTasks = await this._sessionsConfigService.getNonSessionTasks(session); if (nonSessionTasks.length === 0) { @@ -480,13 +495,13 @@ class RunScriptActionViewItem extends BaseActionViewItem { private readonly _activeRunState: IObservable, private readonly _showConfigureQuickPick: (session: ISession) => Promise, private readonly _showCustomCommandInput: (session: ISession, existingTask: INonSessionTaskEntry, mode?: TaskConfigurationMode) => Promise, + private readonly _generateNewTask: (session: ISession) => Promise, @ICommandService private readonly _commandService: ICommandService, @ISessionsConfigurationService private readonly _sessionsConfigService: ISessionsConfigurationService, @IKeybindingService private readonly _keybindingService: IKeybindingService, @IActionWidgetService private readonly _actionWidgetService: IActionWidgetService, @IContextKeyService contextKeyService: IContextKeyService, @ITelemetryService private readonly _telemetryService: ITelemetryService, - @ISessionsManagementService private readonly _sessionsManagementService: ISessionsManagementService, ) { super(undefined, action); @@ -706,7 +721,7 @@ class RunScriptActionViewItem extends BaseActionViewItem { category: tasksCategory, run: async () => { logSessionsInteraction(this._telemetryService, 'generateNewTask', 'actionWidget'); - await this._sessionsManagementService.sendAndCreateChat(session, { query: '/generate-run-commands' }); + await this._generateNewTask(session); }, });