diff --git a/src/renderer/src/components/settings/CommitMessageAiPane.test.tsx b/src/renderer/src/components/settings/CommitMessageAiPane.test.tsx index 8e991751f72..4344d5013ff 100644 --- a/src/renderer/src/components/settings/CommitMessageAiPane.test.tsx +++ b/src/renderer/src/components/settings/CommitMessageAiPane.test.tsx @@ -164,6 +164,61 @@ describe('CommitMessageAiPane', () => { expect(getAgentCatalogForAction('fixChecks', null).map((agent) => agent.id)).toContain('aider') }) + it('explains which agents are supported for text-generation recipes', () => { + const markup = renderPane( + buildSettings({ + sourceControlAi: { + enabled: true, + agentId: null, + selectedModelByAgent: {}, + selectedModelByAgentByHost: {}, + discoveredModelsByAgent: {}, + discoveredModelsByAgentByHost: {}, + selectedThinkingByModel: {}, + instructionsByOperation: {}, + customAgentCommand: '', + actions: {}, + prCreationDefaults: {}, + launchActionDefaults: {} + } + }) + ) + + expect(markup).toContain('Supported agents for this recipe:') + expect(markup).toContain('Claude, Codex') + expect(markup).toContain('Custom command') + }) + + it('marks an unsupported saved text-recipe agent with the supported alternatives', () => { + const markup = renderPane( + buildSettings({ + sourceControlAi: { + enabled: true, + agentId: null, + selectedModelByAgent: {}, + selectedModelByAgentByHost: {}, + discoveredModelsByAgent: {}, + discoveredModelsByAgentByHost: {}, + selectedThinkingByModel: {}, + instructionsByOperation: {}, + customAgentCommand: '', + actions: { + commitMessage: { + agentId: 'aider' + } + }, + prCreationDefaults: {}, + launchActionDefaults: {} + } + }) + ) + + expect(markup).toContain( + 'Aider cannot run this text-generation recipe. Pick one of the supported agents below.' + ) + expect(markup).toContain('Supported agents for this recipe:') + }) + it('keeps action agent selectors constrained for long labels', () => { const markup = renderPane( buildSettings({ diff --git a/src/renderer/src/components/settings/RepositorySourceControlAiActionRows.tsx b/src/renderer/src/components/settings/RepositorySourceControlAiActionRows.tsx index 8d7c2958f1b..a44759ff38f 100644 --- a/src/renderer/src/components/settings/RepositorySourceControlAiActionRows.tsx +++ b/src/renderer/src/components/settings/RepositorySourceControlAiActionRows.tsx @@ -20,6 +20,8 @@ import { getActionDescriptions, SOURCE_CONTROL_TEXT_ACTION_ID_SET, getAgentCatalogForAction, + getSourceControlActionAgentSupportText, + getSourceControlActionAgentWarningText, getSourceControlAgentArgsPlaceholder } from './source-control-action-recipe-options' import { @@ -86,6 +88,8 @@ export function RepositorySourceControlAiActionRows({ resolveAgentArgsPlaceholderAgent(effectiveAgent, source, actionId, defaultTuiAgent) ) const agentOptions = getAgentCatalogForAction(actionId, effectiveAgent) + const agentWarningText = getSourceControlActionAgentWarningText(actionId, effectiveAgent) + const agentSupportText = getSourceControlActionAgentSupportText(actionId) return (
@@ -180,6 +184,11 @@ export function RepositorySourceControlAiActionRows({ ))} + {agentWarningText ? ( +

{agentWarningText}

+ ) : agentSupportText ? ( +

{agentSupportText}

+ ) : null}
diff --git a/src/renderer/src/components/settings/source-control-action-recipe-options.ts b/src/renderer/src/components/settings/source-control-action-recipe-options.ts index 242d5a4fb37..78019a4ea2c 100644 --- a/src/renderer/src/components/settings/source-control-action-recipe-options.ts +++ b/src/renderer/src/components/settings/source-control-action-recipe-options.ts @@ -7,6 +7,7 @@ import { CUSTOM_AGENT_ID, type CustomAgentId, getCommitMessageAgentCapability, + isCustomAgentId, listCommitMessageAgentCapabilities } from '../../../../shared/commit-message-agent-spec' import { getAgentCatalog, type AgentCatalogEntry } from '@/lib/agent-catalog' @@ -98,3 +99,49 @@ export function getAgentCatalogForAction( (agent) => TEXT_GENERATION_AGENT_ID_SET.has(agent.id) || agent.id === selectedAgent ) } + +function formatSupportedAgentLabels(): string { + return [ + ...listCommitMessageAgentCapabilities().map((capability) => capability.label), + translate( + 'auto.components.settings.source.control.action.recipe.options.customCommand', + 'Custom command' + ) + ].join(', ') +} + +export function getSourceControlActionAgentSupportText( + actionId: SourceControlActionId +): string | null { + if (!SOURCE_CONTROL_TEXT_ACTION_ID_SET.has(actionId)) { + return null + } + return translate( + 'auto.components.settings.source.control.action.recipe.options.supportedAgents', + 'Supported agents for this recipe: {{value0}}.', + { value0: formatSupportedAgentLabels() } + ) +} + +export function getSourceControlActionAgentWarningText( + actionId: SourceControlActionId, + selectedAgent: TuiAgent | CustomAgentId | null | undefined +): string | null { + if (!SOURCE_CONTROL_TEXT_ACTION_ID_SET.has(actionId)) { + return null + } + + if (selectedAgent && !isCustomAgentId(selectedAgent)) { + if (TEXT_GENERATION_AGENT_ID_SET.has(selectedAgent)) { + return null + } + const agentLabel = getAgentCatalog().find((agent) => agent.id === selectedAgent)?.label + return translate( + 'auto.components.settings.source.control.action.recipe.options.unsupportedSavedAgent', + '{{value0}} cannot run this text-generation recipe. Pick one of the supported agents below.', + { value0: agentLabel ?? selectedAgent } + ) + } + + return null +} diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index 693d49f8310..a8699b51d22 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -7266,7 +7266,10 @@ "branchName": "Rename Orca-created branches from the initial agent task.", "fixCommitFailure": "Start an agent when a commit hook or git commit fails.", "fixChecks": "Start an agent from failed hosted-review checks.", - "resolveConflicts": "Start an agent for local or hosted-review merge conflicts." + "resolveConflicts": "Start an agent for local or hosted-review merge conflicts.", + "customCommand": "Custom command", + "supportedAgents": "Supported agents for this recipe: {{value0}}.", + "unsupportedSavedAgent": "{{value0}} cannot run this text-generation recipe. Pick one of the supported agents below." } } } diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json index 2f41ecd5eca..599d0ccb73b 100644 --- a/src/renderer/src/i18n/locales/es.json +++ b/src/renderer/src/i18n/locales/es.json @@ -7230,7 +7230,10 @@ "branchName": "Cambie el nombre de las ramas creadas por Orca desde la tarea inicial del agente.", "fixCommitFailure": "Inicie un agente cuando falle un enlace de confirmación o una confirmación de git.", "fixChecks": "Inicie un agente a partir de comprobaciones fallidas de revisión alojada.", - "resolveConflicts": "Inicie un agente para conflictos de fusión de revisión local o alojada." + "resolveConflicts": "Inicie un agente para conflictos de fusión de revisión local o alojada.", + "customCommand": "Custom command", + "supportedAgents": "Supported agents for this recipe: {{value0}}.", + "unsupportedSavedAgent": "{{value0}} cannot run this text-generation recipe. Pick one of the supported agents below." } } } diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json index 13f46e9198e..12f8072869b 100644 --- a/src/renderer/src/i18n/locales/ja.json +++ b/src/renderer/src/i18n/locales/ja.json @@ -7251,7 +7251,10 @@ "branchName": "Orca が最初のエージェント タスクから作成したブランチの名前を変更します。", "fixCommitFailure": "コミットフックまたは git コミットが失敗したときにエージェントを開始します。", "fixChecks": "失敗したホスト型レビュー チェックからエージェントを開始します。", - "resolveConflicts": "ローカルまたはホストされたレビューのマージ競合に対してエージェントを開始します。" + "resolveConflicts": "ローカルまたはホストされたレビューのマージ競合に対してエージェントを開始します。", + "customCommand": "Custom command", + "supportedAgents": "Supported agents for this recipe: {{value0}}.", + "unsupportedSavedAgent": "{{value0}} cannot run this text-generation recipe. Pick one of the supported agents below." } } } diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json index 53d749bc621..fd9f2c3c500 100644 --- a/src/renderer/src/i18n/locales/ko.json +++ b/src/renderer/src/i18n/locales/ko.json @@ -7215,7 +7215,10 @@ "branchName": "초기 에이전트 작업에서 Orca가 생성한 브랜치의 이름을 바꿉니다.", "fixCommitFailure": "커밋 후크 또는 git 커밋이 실패하면 에이전트를 시작합니다.", "fixChecks": "실패한 호스팅 PR 체크에서 에이전트를 시작합니다.", - "resolveConflicts": "로컬 또는 호스팅 PR 병합 충돌에 대한 에이전트를 시작합니다." + "resolveConflicts": "로컬 또는 호스팅 PR 병합 충돌에 대한 에이전트를 시작합니다.", + "customCommand": "Custom command", + "supportedAgents": "Supported agents for this recipe: {{value0}}.", + "unsupportedSavedAgent": "{{value0}} cannot run this text-generation recipe. Pick one of the supported agents below." } } } diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json index 681538b1222..dc0bf7f87d5 100644 --- a/src/renderer/src/i18n/locales/zh.json +++ b/src/renderer/src/i18n/locales/zh.json @@ -7215,7 +7215,10 @@ "branchName": "重命名 Orca 从初始代理任务创建的分支。", "fixCommitFailure": "当提交挂钩或 git 提交失败时启动代理。", "fixChecks": "从失败的托管评审检查中启动代理。", - "resolveConflicts": "启动用于解决本地或托管评审合并冲突的代理。" + "resolveConflicts": "启动用于解决本地或托管评审合并冲突的代理。", + "customCommand": "Custom command", + "supportedAgents": "Supported agents for this recipe: {{value0}}.", + "unsupportedSavedAgent": "{{value0}} cannot run this text-generation recipe. Pick one of the supported agents below." } } } diff --git a/src/shared/source-control-ai-action-recipes.test.ts b/src/shared/source-control-ai-action-recipes.test.ts index e285c22f9c9..0df6fa064e5 100644 --- a/src/shared/source-control-ai-action-recipes.test.ts +++ b/src/shared/source-control-ai-action-recipes.test.ts @@ -403,4 +403,31 @@ describe('source-control AI action recipes', () => { error: 'Command template is empty for commit messages.' }) }) + + it('lists supported agents when a text action uses an unsupported saved agent', () => { + const base = settings() + base.sourceControlAi = { + ...base.sourceControlAi!, + actions: { + ...base.sourceControlAi!.actions, + commitMessage: { + agentId: 'aider', + commandInputTemplate: '{basePrompt}' + } + } + } + + expect( + resolveSourceControlAiForOperation({ + settings: base, + repo: null, + operation: 'commitMessage', + discoveryHostKey: 'local' + }) + ).toEqual({ + ok: false, + error: + 'Agent "aider" does not support Source Control AI commit messages. Supported agents: Claude, Codex, OpenCode, Pi, Amp, Cursor, Kimi, GitHub Copilot, Antigravity, or Custom command.' + }) + }) }) diff --git a/src/shared/source-control-ai.ts b/src/shared/source-control-ai.ts index a66aac521b1..260dba6e0af 100644 --- a/src/shared/source-control-ai.ts +++ b/src/shared/source-control-ai.ts @@ -5,6 +5,7 @@ import { CUSTOM_AGENT_ID, getCommitMessageAgentSpec, getCommitMessageModel, + listCommitMessageAgentCapabilities, type CustomAgentId, isCustomAgentId, resolveCommitMessageAgentChoice @@ -104,6 +105,12 @@ const PR_CREATION_DEFAULT_KEYS = [ 'openAfterCreate' ] as const +function supportedSourceControlAiAgentSummary(): string { + return `Supported agents: ${listCommitMessageAgentCapabilities() + .map((capability) => capability.label) + .join(', ')}, or Custom command.` +} + function copyRecord(value: T | undefined): T | undefined { return value === undefined ? undefined : structuredClone(value) } @@ -1171,8 +1178,7 @@ export function resolveSourceControlAiForOperation( if (!agentChoice) { return { ok: false, - error: - 'Choose a supported Source Control AI agent for this action in Settings -> Git -> Source Control AI.' + error: `Choose a supported Source Control AI agent for this action in Settings -> Git -> Source Control AI. ${supportedSourceControlAiAgentSummary()}` } } @@ -1220,14 +1226,14 @@ export function resolveSourceControlAiForOperation( if (!resolvedActionAgentId || isCustomAgentId(resolvedActionAgentId)) { return { ok: false, - error: 'Choose a supported Source Control AI agent for this action.' + error: `Choose a supported Source Control AI agent for this action. ${supportedSourceControlAiAgentSummary()}` } } const spec = getCommitMessageAgentSpec(resolvedActionAgentId) if (!spec) { return { ok: false, - error: `Agent "${resolvedActionAgentId}" does not support Source Control AI ${OPERATION_LABEL[input.operation]}.` + error: `Agent "${resolvedActionAgentId}" does not support Source Control AI ${OPERATION_LABEL[input.operation]}. ${supportedSourceControlAiAgentSummary()}` } }