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>
This commit is contained in:
Osvaldo Ortega
2026-04-09 22:53:30 +00:00
committed by GitHub
co-authored by Copilot
parent e4749092e1
commit e13eb9b0fa
@@ -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<void> {
logSessionsInteraction(that._telemetryService, 'generateNewTask', 'menu');
await that._sessionManagementService.sendAndCreateChat(session, { query: '/generate-run-commands' });
await that._generateNewTask(session);
}
}));
}));
}
private async _generateNewTask(session: ISession): Promise<void> {
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<ITaskEntry | undefined> {
const nonSessionTasks = await this._sessionsConfigService.getNonSessionTasks(session);
if (nonSessionTasks.length === 0) {
@@ -480,13 +495,13 @@ class RunScriptActionViewItem extends BaseActionViewItem {
private readonly _activeRunState: IObservable<IRunScriptActionContext | undefined>,
private readonly _showConfigureQuickPick: (session: ISession) => Promise<ITaskEntry | undefined>,
private readonly _showCustomCommandInput: (session: ISession, existingTask: INonSessionTaskEntry, mode?: TaskConfigurationMode) => Promise<ITaskEntry | undefined>,
private readonly _generateNewTask: (session: ISession) => Promise<void>,
@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);
},
});