fix(extensions): use safe legacy multimodel capability fallback
This commit is contained in:
parent
5007f3eebb
commit
8423656b97
4 changed files with 125 additions and 4 deletions
|
|
@ -1,7 +1,10 @@
|
|||
import { execCli } from '@main/utils/childProcess';
|
||||
import { resolveInteractiveShellEnv } from '@main/utils/shellEnv';
|
||||
import { createLogger } from '@shared/utils/logger';
|
||||
import { createDefaultCliExtensionCapabilities } from '@shared/utils/providerExtensionCapabilities';
|
||||
import {
|
||||
createDefaultCliExtensionCapabilities,
|
||||
createLegacyRuntimeFallbackCliExtensionCapabilities,
|
||||
} from '@shared/utils/providerExtensionCapabilities';
|
||||
|
||||
import { resolveGeminiRuntimeAuth } from './geminiRuntimeAuth';
|
||||
import { buildProviderAwareCliEnv } from './providerAwareCliEnv';
|
||||
|
|
@ -145,7 +148,7 @@ function createDefaultProviderStatus(providerId: CliProviderId): CliProviderStat
|
|||
capabilities: {
|
||||
teamLaunch: false,
|
||||
oneShot: false,
|
||||
extensions: createDefaultCliExtensionCapabilities(),
|
||||
extensions: createLegacyRuntimeFallbackCliExtensionCapabilities(),
|
||||
},
|
||||
selectedBackendId: null,
|
||||
resolvedBackendId: null,
|
||||
|
|
@ -159,7 +162,9 @@ function createDefaultProviderStatus(providerId: CliProviderId): CliProviderStat
|
|||
function mapRuntimeExtensionCapabilities(
|
||||
capabilities?: RuntimeExtensionCapabilitiesResponse
|
||||
): CliProviderStatus['capabilities']['extensions'] {
|
||||
const defaults = createDefaultCliExtensionCapabilities();
|
||||
const defaults = capabilities
|
||||
? createDefaultCliExtensionCapabilities()
|
||||
: createLegacyRuntimeFallbackCliExtensionCapabilities();
|
||||
|
||||
return {
|
||||
plugins: {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,27 @@ const SUPPORTED_SHARED_CAPABILITY: CliExtensionCapability = {
|
|||
reason: null,
|
||||
};
|
||||
|
||||
const LEGACY_MULTIMODEL_FALLBACK_CAPABILITIES: CliExtensionCapabilities = {
|
||||
plugins: {
|
||||
status: 'unsupported',
|
||||
ownership: 'shared',
|
||||
reason:
|
||||
'This runtime does not declare plugin capability support. Upgrade the runtime to manage plugins here.',
|
||||
},
|
||||
mcp: {
|
||||
status: 'read-only',
|
||||
ownership: 'shared',
|
||||
reason:
|
||||
'This runtime does not declare MCP management support. Upgrade the runtime to install or remove MCP servers here.',
|
||||
},
|
||||
skills: {
|
||||
...SUPPORTED_SHARED_CAPABILITY,
|
||||
},
|
||||
apiKeys: {
|
||||
...SUPPORTED_SHARED_CAPABILITY,
|
||||
},
|
||||
};
|
||||
|
||||
export function createDefaultCliExtensionCapabilities(
|
||||
overrides?: Partial<CliExtensionCapabilities>
|
||||
): CliExtensionCapabilities {
|
||||
|
|
@ -22,10 +43,22 @@ export function createDefaultCliExtensionCapabilities(
|
|||
};
|
||||
}
|
||||
|
||||
export function createLegacyRuntimeFallbackCliExtensionCapabilities(
|
||||
overrides?: Partial<CliExtensionCapabilities>
|
||||
): CliExtensionCapabilities {
|
||||
return {
|
||||
plugins: { ...LEGACY_MULTIMODEL_FALLBACK_CAPABILITIES.plugins },
|
||||
mcp: { ...LEGACY_MULTIMODEL_FALLBACK_CAPABILITIES.mcp },
|
||||
skills: { ...LEGACY_MULTIMODEL_FALLBACK_CAPABILITIES.skills },
|
||||
apiKeys: { ...LEGACY_MULTIMODEL_FALLBACK_CAPABILITIES.apiKeys },
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
export function getCliProviderExtensionCapabilities(
|
||||
provider: Pick<CliProviderStatus, 'capabilities'>
|
||||
): CliExtensionCapabilities {
|
||||
return provider.capabilities.extensions ?? createDefaultCliExtensionCapabilities();
|
||||
return provider.capabilities.extensions ?? createLegacyRuntimeFallbackCliExtensionCapabilities();
|
||||
}
|
||||
|
||||
export function getCliProviderExtensionCapability(
|
||||
|
|
|
|||
|
|
@ -254,4 +254,43 @@ describe('ClaudeMultimodelBridgeService', () => {
|
|||
});
|
||||
expect(provider.statusMessage).toContain('ANTHROPIC_API_KEY');
|
||||
});
|
||||
|
||||
it('falls back conservatively when the runtime omits extension capability metadata', async () => {
|
||||
execCliMock.mockResolvedValue({
|
||||
stdout: JSON.stringify({
|
||||
providers: {
|
||||
codex: {
|
||||
supported: true,
|
||||
authenticated: true,
|
||||
verificationState: 'verified',
|
||||
canLoginFromUi: true,
|
||||
capabilities: {
|
||||
teamLaunch: true,
|
||||
oneShot: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
stderr: '',
|
||||
exitCode: 0,
|
||||
});
|
||||
|
||||
const { ClaudeMultimodelBridgeService } =
|
||||
await import('@main/services/runtime/ClaudeMultimodelBridgeService');
|
||||
const service = new ClaudeMultimodelBridgeService();
|
||||
|
||||
const provider = await service.getProviderStatus('/mock/agent_teams_orchestrator', 'codex');
|
||||
|
||||
expect(provider).toMatchObject({
|
||||
providerId: 'codex',
|
||||
capabilities: {
|
||||
extensions: {
|
||||
plugins: { status: 'unsupported' },
|
||||
mcp: { status: 'read-only' },
|
||||
skills: { status: 'supported' },
|
||||
apiKeys: { status: 'supported' },
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
44
test/shared/utils/providerExtensionCapabilities.test.ts
Normal file
44
test/shared/utils/providerExtensionCapabilities.test.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
createLegacyRuntimeFallbackCliExtensionCapabilities,
|
||||
getCliProviderExtensionCapabilities,
|
||||
} from '@shared/utils/providerExtensionCapabilities';
|
||||
|
||||
import type { CliProviderStatus } from '@shared/types';
|
||||
|
||||
function makeProvider(
|
||||
overrides?: Partial<CliProviderStatus>
|
||||
): Pick<CliProviderStatus, 'capabilities'> {
|
||||
return {
|
||||
capabilities: {
|
||||
teamLaunch: false,
|
||||
oneShot: false,
|
||||
...(overrides?.capabilities ?? {}),
|
||||
} as CliProviderStatus['capabilities'],
|
||||
};
|
||||
}
|
||||
|
||||
describe('providerExtensionCapabilities', () => {
|
||||
it('returns conservative fallback capabilities when runtime omits extension metadata', () => {
|
||||
const capabilities = getCliProviderExtensionCapabilities(
|
||||
makeProvider({
|
||||
capabilities: {
|
||||
teamLaunch: true,
|
||||
oneShot: true,
|
||||
} as CliProviderStatus['capabilities'],
|
||||
})
|
||||
);
|
||||
|
||||
expect(capabilities).toEqual(createLegacyRuntimeFallbackCliExtensionCapabilities());
|
||||
});
|
||||
|
||||
it('keeps plugins unsupported and mcp read-only in the legacy multimodel fallback', () => {
|
||||
const capabilities = createLegacyRuntimeFallbackCliExtensionCapabilities();
|
||||
|
||||
expect(capabilities.plugins.status).toBe('unsupported');
|
||||
expect(capabilities.mcp.status).toBe('read-only');
|
||||
expect(capabilities.skills.status).toBe('supported');
|
||||
expect(capabilities.apiKeys.status).toBe('supported');
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue