fix: align channel runtime and settings UI

This commit is contained in:
lofyer
2026-08-09 21:54:25 +08:00
parent 66b098ae36
commit 1cc969317d
17 changed files with 288 additions and 1528 deletions
+37 -1
View File
@@ -2,7 +2,8 @@ import type { ResolvedRuntimeSettings } from '../runtime-settings-store'
import { describe, expect, it } from 'vitest'
import {
applyRuntimeSelection,
getConfiguredRuntimeTarget
getConfiguredRuntimeTarget,
resolveConfiguredAgentRuntimeSelection
} from './runtime-selection'
const defaultProfileId = '00000000-0000-4000-8000-000000000001'
@@ -148,6 +149,41 @@ describe('runtime selection', () => {
).toThrow('自动启动')
})
it('resolves Agent Runtime backends from the global Runtime configuration', () => {
const base = settings()
const configured = settings({
opencodeModelProfile: base.modelProfiles[1],
continueModelProfile: base.modelProfiles[2]
})
expect(
resolveConfiguredAgentRuntimeSelection(configured, {
provider: 'opencode',
profileId: defaultProfileId
})
).toEqual({
provider: 'opencode',
profileId: secondProfileId
})
expect(
resolveConfiguredAgentRuntimeSelection(configured, {
provider: 'continue'
})
).toEqual({
provider: 'continue',
profileId: responsesProfileId
})
expect(
resolveConfiguredAgentRuntimeSelection(configured, {
provider: 'model',
profileId: defaultProfileId
})
).toEqual({
provider: 'model',
profileId: defaultProfileId
})
})
it('routes legacy automatic settings through local OpenCode when the Server is blank', () => {
expect(getConfiguredRuntimeTarget(settings())).toBe('opencode')
expect(
+20
View File
@@ -35,6 +35,26 @@ export function getConfiguredRuntimeTarget(
return 'model'
}
export function resolveConfiguredAgentRuntimeSelection(
settings: ResolvedRuntimeSettings,
selection: AgentRuntimeSelection
): AgentRuntimeSelection {
if (
selection.provider !== 'opencode' &&
selection.provider !== 'continue'
) {
return selection
}
const profile =
selection.provider === 'opencode'
? settings.opencodeModelProfile
: settings.continueModelProfile
return {
provider: selection.provider,
...(profile ? { profileId: profile.id } : {})
}
}
export function applyRuntimeSelection(
settings: ResolvedRuntimeSettings,
selection: AgentRuntimeSelection
@@ -1185,8 +1185,8 @@ describe('AssistantDatabase', () => {
rootPath: channelProject.rootPath,
defaultWorkMode: channelProject.defaultWorkMode,
runtimeSelection: {
provider: 'model',
profileId: removedProfileId
provider: 'opencode',
profileId: runtimeProfileId
}
})
const imageChannelProject = database.ensureChannelProjects(
@@ -1257,8 +1257,7 @@ describe('AssistantDatabase', () => {
{ provider: 'model', profileId: runtimeProfileId }
])
expect(database.getProject(channelProject.id).runtimeSelection).toEqual({
provider: 'model',
profileId: defaultProfileId
provider: 'opencode'
})
expect(
database.getProject(imageChannelProject.id).runtimeSelection
+23 -5
View File
@@ -973,15 +973,18 @@ describe('registerIpcHandlers agent terminal state', () => {
respond: vi.fn(),
clear: vi.fn()
}
const getResolvedSettings = vi.fn(
async (): Promise<Record<string, unknown>> => ({
toolApproval,
subagentSmartRoutingEnabled: smartRoutingEnabled
})
)
const dispose = registerIpcHandlers(
window as never,
runtime as never,
'CommandOrControl+Shift+Space',
{
getResolvedSettings: vi.fn(async () => ({
toolApproval,
subagentSmartRoutingEnabled: smartRoutingEnabled
}))
getResolvedSettings
} as never,
{} as never,
contextManager as never,
@@ -1009,6 +1012,7 @@ describe('registerIpcHandlers agent terminal state', () => {
assistantDatabase,
contextManager,
dispose,
getResolvedSettings,
clearHandler: electronMocks.handlers.get(
ipcChannels.appClearLocalData
),
@@ -2240,6 +2244,8 @@ describe('registerIpcHandlers agent terminal state', () => {
it('routes remote Execute to a configured Agent Runtime without a GoodBuddy approval callback', async () => {
let receivedAuthorize: unknown = 'not-called'
const configuredProfileId =
'00000000-0000-4000-8000-000000000019'
const selectedRuntime = {
runtimeId: 'continue',
capability: 'chat',
@@ -2282,6 +2288,11 @@ describe('registerIpcHandlers agent terminal state', () => {
false,
selectedRuntimes
)
harness.getResolvedSettings.mockResolvedValue({
toolApproval: 'always',
subagentSmartRoutingEnabled: false,
continueModelProfile: { id: configuredProfileId }
})
vi.mocked(
harness.assistantDatabase.listProjects
).mockReturnValue([
@@ -2323,9 +2334,16 @@ describe('registerIpcHandlers agent terminal state', () => {
output: 'Continue 已执行'
})
expect(selectedRuntimes.getRuntime).toHaveBeenCalledWith(
{ provider: 'continue' },
{ provider: 'continue', profileId: configuredProfileId },
'C:\\ProjectWorkspace'
)
expect(
harness.assistantDatabase.getOrCreateRemoteConversation
).toHaveBeenCalledWith(
expect.objectContaining({
runtimeSelection: { provider: 'continue' }
})
)
expect(receivedAuthorize).toBeUndefined()
expect(harness.approvalBroker.request).not.toHaveBeenCalled()
await harness.dispose()
+16 -3
View File
@@ -121,6 +121,7 @@ import {
createDefaultModelRuntime,
createModelProfileRuntime
} from './agent/create-runtime'
import { resolveConfiguredAgentRuntimeSelection } from './agent/runtime-selection'
import { safeToolErrorDetail } from './agent/approval-summary'
import { ReasoningTagStreamParser } from './agent/reasoning-stream'
import type { BundledRuntimePaths } from './agent/bundled-runtimes'
@@ -576,6 +577,7 @@ export function registerIpcHandlers(
const resolveRequestRuntime = async (
request: Pick<AgentRequest, 'projectId' | 'runtimeSelection'> & {
workspaceOverride?: string
followConfiguredAgentRuntime?: boolean
}
): Promise<AgentRuntime> => {
const projectWorkspace =
@@ -586,8 +588,14 @@ export function registerIpcHandlers(
if (!selectedRuntimes || (!request.runtimeSelection && !projectWorkspace)) {
return runtime
}
const selection =
let selection =
request.runtimeSelection ?? ({ provider: 'auto' } as const)
if (request.followConfiguredAgentRuntime) {
selection = resolveConfiguredAgentRuntimeSelection(
await settingsStore.getResolvedSettings(),
selection
)
}
return projectWorkspace
? selectedRuntimes.getRuntime(selection, projectWorkspace)
: selectedRuntimes.getRuntime(selection)
@@ -830,6 +838,7 @@ export function registerIpcHandlers(
rootPath: string
conversationId: string
runtimeSelection: AgentRuntimeSelection
followConfiguredAgentRuntime?: boolean
runtime?: AgentRuntime
taskId?: string
contextIds?: string[]
@@ -888,7 +897,9 @@ export function registerIpcHandlers(
(await resolveRequestRuntime({
projectId: schedule.projectId,
runtimeSelection: remoteContext?.runtimeSelection,
workspaceOverride: remoteContext?.rootPath
workspaceOverride: remoteContext?.rootPath,
followConfiguredAgentRuntime:
remoteContext?.followConfiguredAgentRuntime
}))
const agentRuntimeSelected = isAgentRuntime(requestRuntime)
const channelToolPolicy =
@@ -1455,7 +1466,8 @@ export function registerIpcHandlers(
executionRuntime = await resolveRequestRuntime({
projectId: project.id,
runtimeSelection,
workspaceOverride: project.rootPath
workspaceOverride: project.rootPath,
followConfiguredAgentRuntime: true
})
executionStatus = await executionRuntime.getStatus()
} catch (error) {
@@ -1546,6 +1558,7 @@ export function registerIpcHandlers(
rootPath: project.rootPath,
conversationId: remoteConversation.id,
runtimeSelection,
followConfiguredAgentRuntime: true,
runtime: executionRuntime,
taskId: remoteTaskId,
contextIds,