From cf6d783545dceda9c7e45e23d07dfe525bd902b3 Mon Sep 17 00:00:00 2001 From: Dmitry Zhuravlev Date: Wed, 11 Mar 2026 16:59:25 +0100 Subject: [PATCH] [agent-workbench]: EP-driven extension tab auto-selection in prompt palette (IJPL-233558) IJ-MR-197006 Move auto-selection decision to the EP side: add shouldAutoSelect() to AgentPromptPaletteExtension so each extension can declare whether it should be auto-selected given the context. Alt+Cmd+\ queries matching extensions to autoselect tab. GitOrigin-RevId: 550b96b2cba505e1b20c665ce47f34e77d90132b --- .../com/intellij/keymap/KeymapsTestCase.java | 1 + .../intellij.agent.workbench.prompt.xml | 8 ++++ .../messages/AgentPromptBundle.properties | 2 + ...ntWorkbenchGlobalPromptAutoSelectAction.kt | 44 +++++++++++++++++++ .../prompt/src/ui/AgentPromptPalettePopup.kt | 12 ++--- .../src/prompt/AgentPromptPaletteExtension.kt | 7 +++ .../spec/actions/global-prompt-entry.spec.md | 16 +++++++ 7 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 plugins/agent-workbench/prompt/src/actions/AgentWorkbenchGlobalPromptAutoSelectAction.kt diff --git a/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java b/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java index cba8c4d2a5ce..bd93a004462a 100644 --- a/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java +++ b/platform/testFramework/extensions/src/com/intellij/keymap/KeymapsTestCase.java @@ -458,6 +458,7 @@ public abstract class KeymapsTestCase extends KeymapsTestCaseBase { "Git.Rename.Local.Branch", "ShelvedChanges.Rename", "ChangesView.Rename", "Terminal.SearchInCommandHistory"}, {"control U", SECOND_STROKE, "CommanderSwapPanels", "org.intellij.plugins.markdown.ui.actions.styling.InsertImageAction"}, {"control W", "CloseContent", "Terminal.DeletePreviousWord"}, + {"ctrl alt BACK_SLASH", "AgentWorkbenchPrompt.OpenGlobalPaletteAutoSelect", "ClassNameCompletion"}, {"control alt DOWN", "MethodDown", "NextOccurence", "Console.TableResult.NextPage"}, {"control alt E", "Console.History.Browse", "ExecuteInPyConsoleAction", "PerforceDirect.Edit", "ToggleFindInSelection"}, {"shift alt U", "ActivateFindToolWindow", "ToggleCamelSnakeCase"}, diff --git a/plugins/agent-workbench/prompt/resources/intellij.agent.workbench.prompt.xml b/plugins/agent-workbench/prompt/resources/intellij.agent.workbench.prompt.xml index 3eab5edbfd1b..49b00bc9587c 100644 --- a/plugins/agent-workbench/prompt/resources/intellij.agent.workbench.prompt.xml +++ b/plugins/agent-workbench/prompt/resources/intellij.agent.workbench.prompt.xml @@ -24,5 +24,13 @@ + + + + + + diff --git a/plugins/agent-workbench/prompt/resources/messages/AgentPromptBundle.properties b/plugins/agent-workbench/prompt/resources/messages/AgentPromptBundle.properties index 76d21fb7796f..c8ce062d8c89 100644 --- a/plugins/agent-workbench/prompt/resources/messages/AgentPromptBundle.properties +++ b/plugins/agent-workbench/prompt/resources/messages/AgentPromptBundle.properties @@ -56,4 +56,6 @@ context.paths.title=Paths popup.preview.toggle.tooltip=Toggle markdown preview action.AgentWorkbenchPrompt.OpenGlobalPalette.text=Ask Agent with Context action.AgentWorkbenchPrompt.OpenGlobalPalette.description=Open global prompt palette with context from the current IDE state +action.AgentWorkbenchPrompt.OpenGlobalPaletteAutoSelect.text=Ask Agent Depending on Context +action.AgentWorkbenchPrompt.OpenGlobalPaletteAutoSelect.description=Open global prompt palette and auto-select the extension tab that matches the context context.tree.selection.title=Tree Selection ({0}) diff --git a/plugins/agent-workbench/prompt/src/actions/AgentWorkbenchGlobalPromptAutoSelectAction.kt b/plugins/agent-workbench/prompt/src/actions/AgentWorkbenchGlobalPromptAutoSelectAction.kt new file mode 100644 index 000000000000..d0815de6d60b --- /dev/null +++ b/plugins/agent-workbench/prompt/src/actions/AgentWorkbenchGlobalPromptAutoSelectAction.kt @@ -0,0 +1,44 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.agent.workbench.prompt.actions + +// @spec community/plugins/agent-workbench/spec/actions/global-prompt-entry.spec.md + +import com.intellij.agent.workbench.prompt.context.AGENT_PROMPT_INVOCATION_ACTION_EVENT_KEY +import com.intellij.agent.workbench.prompt.ui.AgentPromptPalettePopup +import com.intellij.agent.workbench.sessions.core.prompt.AGENT_PROMPT_INVOCATION_DATA_CONTEXT_KEY +import com.intellij.agent.workbench.sessions.core.prompt.AGENT_PROMPT_INVOCATION_PREFER_EXTENSIONS_KEY +import com.intellij.agent.workbench.sessions.core.prompt.AgentPromptInvocationData +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.project.DumbAware + +internal class AgentWorkbenchGlobalPromptAutoSelectAction : AnAction(), DumbAware { + companion object { + private const val ACTION_ID: String = "AgentWorkbenchPrompt.OpenGlobalPaletteAutoSelect" + } + + override fun actionPerformed(e: AnActionEvent) { + val project = e.project ?: return + AgentPromptPalettePopup( + invocationData = AgentPromptInvocationData( + project = project, + actionId = ACTION_ID, + actionText = e.presentation.text, + actionPlace = e.place, + invokedAtMs = System.currentTimeMillis(), + attributes = mapOf( + AGENT_PROMPT_INVOCATION_DATA_CONTEXT_KEY to e.dataContext, + AGENT_PROMPT_INVOCATION_ACTION_EVENT_KEY to e, + AGENT_PROMPT_INVOCATION_PREFER_EXTENSIONS_KEY to true, + ), + ) + ).show() + } + + override fun update(e: AnActionEvent) { + e.presentation.isEnabledAndVisible = e.project != null + } + + override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT +} diff --git a/plugins/agent-workbench/prompt/src/ui/AgentPromptPalettePopup.kt b/plugins/agent-workbench/prompt/src/ui/AgentPromptPalettePopup.kt index a86d35b91de9..9c5331650c2c 100644 --- a/plugins/agent-workbench/prompt/src/ui/AgentPromptPalettePopup.kt +++ b/plugins/agent-workbench/prompt/src/ui/AgentPromptPalettePopup.kt @@ -17,6 +17,7 @@ import com.intellij.agent.workbench.sessions.core.prompt.AgentPromptContextEnvel import com.intellij.agent.workbench.sessions.core.prompt.AgentPromptContextItem import com.intellij.agent.workbench.sessions.core.prompt.AgentPromptInitialMessageRequest import com.intellij.agent.workbench.sessions.core.prompt.AgentPromptInvocationData +import com.intellij.agent.workbench.sessions.core.prompt.AGENT_PROMPT_INVOCATION_PREFER_EXTENSIONS_KEY import com.intellij.agent.workbench.sessions.core.prompt.AgentPromptLaunchError import com.intellij.agent.workbench.sessions.core.prompt.AgentPromptLaunchRequest import com.intellij.agent.workbench.sessions.core.prompt.AgentPromptLauncherBridge @@ -185,8 +186,8 @@ internal class AgentPromptPalettePopup( restoreTaskDrafts(draft) refreshExtensionTaskDraftsFromContext() val preferExtensions = invocationData.attributes[AGENT_PROMPT_INVOCATION_PREFER_EXTENSIONS_KEY] == true - if (preferExtensions && activeExtensionTabs.isNotEmpty()) { - selectFirstExtensionTab() + if (preferExtensions) { + selectAutoSelectExtensionTab() } val initialText = invocationData.dataContextOrNull()?.getData(AGENT_PROMPT_INITIAL_TEXT_DATA_KEY) if (!initialText.isNullOrBlank()) { @@ -412,9 +413,10 @@ internal class AgentPromptPalettePopup( } } - private fun selectFirstExtensionTab() { - val firstExtension = activeExtensionTabs.firstOrNull() ?: return - val index = (0 until tabbedPane.tabCount).firstOrNull { tabbedPane.getComponentAt(it) === firstExtension.tabPanel } + private fun selectAutoSelectExtensionTab() { + val items = contextEntries.map { it.item } + val target = activeExtensionTabs.firstOrNull { it.extension.shouldAutoSelect(items) } ?: return + val index = (0 until tabbedPane.tabCount).firstOrNull { tabbedPane.getComponentAt(it) === target.tabPanel } if (index != null) { tabbedPane.selectedIndex = index } diff --git a/plugins/agent-workbench/sessions-core/src/prompt/AgentPromptPaletteExtension.kt b/plugins/agent-workbench/sessions-core/src/prompt/AgentPromptPaletteExtension.kt index 2879f3b233bf..df501464bc0e 100644 --- a/plugins/agent-workbench/sessions-core/src/prompt/AgentPromptPaletteExtension.kt +++ b/plugins/agent-workbench/sessions-core/src/prompt/AgentPromptPaletteExtension.kt @@ -60,6 +60,13 @@ interface AgentPromptPaletteExtension { * or `null` to use the default hint. */ fun getFooterHint(): @Nls String? + + /** + * Returns `true` if this extension's tab should be auto-selected when the popup + * is invoked with the "prefer extensions" shortcut and this extension [matches] the context. + * When multiple extensions return `true`, the first one wins. + */ + fun shouldAutoSelect(contextItems: List): Boolean = matches(contextItems) } object AgentPromptPaletteExtensions { diff --git a/plugins/agent-workbench/spec/actions/global-prompt-entry.spec.md b/plugins/agent-workbench/spec/actions/global-prompt-entry.spec.md index 9a3a8e99a063..85e7bea14783 100644 --- a/plugins/agent-workbench/spec/actions/global-prompt-entry.spec.md +++ b/plugins/agent-workbench/spec/actions/global-prompt-entry.spec.md @@ -3,6 +3,7 @@ name: Global Prompt Entry description: Requirements for global prompt action behavior, target routing, keyboard semantics, validation, and launcher handoff. targets: - ../../prompt/src/actions/AgentWorkbenchGlobalPromptAction.kt + - ../../prompt/src/actions/AgentWorkbenchGlobalPromptAutoSelectAction.kt - ../../prompt/src/ui/AgentPromptPalettePopup.kt - ../../prompt/src/ui/AgentPromptPaletteView.kt - ../../prompt/src/ui/AgentPromptPaletteModels.kt @@ -10,6 +11,7 @@ targets: - ../../prompt/resources/intellij.agent.workbench.prompt.xml - ../../prompt/resources/messages/AgentPromptBundle.properties - ../../sessions-core/src/prompt/AgentPromptLauncherBridge.kt + - ../../sessions-core/src/prompt/AgentPromptPaletteExtension.kt - ../../sessions/src/service/AgentSessionPromptLauncherBridge.kt - ../../prompt/testSrc/ui/AgentPromptProviderSelectionDecisionsTest.kt - ../../prompt/testSrc/ui/AgentPromptSubmitValidationDecisionsTest.kt @@ -44,6 +46,8 @@ Prompt-context collection and rendering contracts are specified separately in `s ## Requirements - Global action id `AgentWorkbenchPrompt.OpenGlobalPalette` must be available only when a project is open. +- Global action id `AgentWorkbenchPrompt.OpenGlobalPaletteAutoSelect` must be available only when a project is open. It opens the same popup but with EP-driven extension tab auto-selection (see below). + - Prompt target mode must support exactly: - `PromptTargetMode.NEW_TASK`, - `PromptTargetMode.EXISTING_TASK`. @@ -112,6 +116,18 @@ Prompt-context collection and rendering contracts are specified separately in `s - Context block soft-cap limit is `12_000` characters. When exceeded, user must explicitly choose send-full, auto-trim, or cancel before launch. +- Extension tab auto-selection (`Alt+Cmd+\` / `Alt+Ctrl+\`): + - When the popup is opened via `AgentWorkbenchPrompt.OpenGlobalPaletteAutoSelect`, the `AGENT_PROMPT_INVOCATION_PREFER_EXTENSIONS_KEY` attribute is set to `true`. + - When `preferExtensions` is true, the popup calls `AgentPromptPaletteExtension.shouldAutoSelect(contextItems)` on each active extension tab in order. + - The first extension that returns `true` from `shouldAutoSelect` has its tab auto-selected. + - If no extension returns `true`, the default "New Task" tab remains selected. + - `shouldAutoSelect` defaults to `false` in the EP interface; each extension opts in independently. + - When the popup is opened via the standard `AgentWorkbenchPrompt.OpenGlobalPalette` (`Cmd+\` / `Ctrl+\`), no auto-selection occurs regardless of extension tab state. + +- Extension tab submit flow: + - When an extension tab is active, submit delegates to the action returned by `AgentPromptPaletteExtension.getSubmitActionId()`. + - Provider options, plan mode, and existing-task routing are bypassed for extension tabs. + ## User Experience - Popup opens as a project-scoped launcher for both new and existing task targets. - Existing-task mode exposes provider-scoped thread list with loading/empty/error states.