test: expand provider/model resolution matrix coverage

This commit is contained in:
nrslib 2026-02-27 00:30:07 +09:00
parent 644c318295
commit 7e34d5c4c0

View File

@ -122,6 +122,235 @@ describe('resolveMovementProviderModel', () => {
}); });
describe('resolveAgentProviderModel', () => { describe('resolveAgentProviderModel', () => {
it.each([
{
name: 'CLI overrides every other layer and also overrides model',
input: {
cliProvider: 'codex' as const,
cliModel: 'cli-model',
personaProviders: {
coder: { provider: 'mock' as const, model: 'persona-model' },
},
personaDisplayName: 'coder',
stepProvider: 'claude' as const,
stepModel: 'step-model',
localProvider: 'opencode' as const,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'codex' as const, model: 'cli-model' },
},
{
name: 'Step overrides local/global when persona is missing',
input: {
stepProvider: 'claude' as const,
stepModel: 'step-model',
localProvider: 'opencode' as const,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'claude' as const, model: 'step-model' },
},
{
name: 'Persona provider wins when CLI is absent',
input: {
stepProvider: 'claude' as const,
personaProviders: {
coder: { provider: 'mock' as const },
},
personaDisplayName: 'coder',
localProvider: 'opencode' as const,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'mock' as const, model: 'global-model' },
},
{
name: 'Persona model wins when no step model and no CLI model',
input: {
stepProvider: 'claude' as const,
stepModel: undefined,
personaProviders: {
coder: { model: 'persona-only-model' },
},
personaDisplayName: 'coder',
localProvider: 'opencode' as const,
localModel: 'local-model',
globalProvider: 'claude' as const,
globalModel: 'global-model',
},
expected: { provider: 'claude' as const, model: 'persona-only-model' },
},
{
name: 'Step provider wins over local/global provider and step model wins over model-only candidates',
input: {
stepProvider: 'codex' as const,
stepModel: 'step-model',
personaProviders: {
coder: { model: 'persona-model' },
},
personaDisplayName: 'coder',
localProvider: 'claude' as const,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'codex' as const, model: 'persona-model' },
},
{
name: 'Local provider is used when no higher-priority provider exists',
input: {
localProvider: 'opencode' as const,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'opencode' as const, model: 'local-model' },
},
{
name: 'Global is used when local provider is absent',
input: {
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'mock' as const, model: 'global-model' },
},
{
name: 'No CLI provider or higher layer, CLI model still has model-layer priority',
input: {
cliModel: 'cli-model',
stepModel: 'step-model',
localProvider: undefined,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'mock' as const, model: 'cli-model' },
},
{
name: 'All providers absent, earliest defined model in model order is used',
input: {
stepModel: 'step-model',
localProvider: undefined,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'mock' as const, model: 'step-model' },
},
{
name: 'Local model is ignored when it does not match resolved provider',
input: {
stepProvider: 'opencode' as const,
localProvider: 'codex' as const,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'opencode' as const, model: undefined },
},
{
name: 'Global model is used when it matches resolved provider',
input: {
stepProvider: 'claude' as const,
localProvider: 'opencode' as const,
localModel: 'local-model',
globalProvider: 'claude' as const,
globalModel: 'global-model',
},
expected: { provider: 'claude' as const, model: 'global-model' },
},
{
name: 'Local model is preferred when both local and global providers match',
input: {
localProvider: 'mock' as const,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'mock' as const, model: 'local-model' },
},
{
name: 'Global model is used when local exists but does not match resolved provider',
input: {
stepProvider: 'codex' as const,
localProvider: 'opencode' as const,
localModel: 'local-model',
globalProvider: 'codex' as const,
globalModel: 'global-model',
},
expected: { provider: 'codex' as const, model: 'global-model' },
},
{
name: 'CLI model is used even when provider comes from local and no CLI provider',
input: {
cliModel: 'cli-model',
localProvider: 'mock' as const,
localModel: 'local-model',
globalProvider: 'mock' as const,
globalModel: 'global-model',
},
expected: { provider: 'mock' as const, model: 'cli-model' },
},
{
name: 'Persona provider resolves provider, persona model still takes model priority',
input: {
stepProvider: 'codex' as const,
stepModel: 'step-model',
personaProviders: {
coder: {
provider: 'mock' as const,
model: 'persona-model',
},
},
personaDisplayName: 'coder',
localProvider: 'claude' as const,
localModel: 'local-model',
globalProvider: 'opencode' as const,
globalModel: 'global-model',
},
expected: { provider: 'mock' as const, model: 'persona-model' },
},
{
name: 'Unknown persona name falls back to normal chain without persona model/provider',
input: {
stepProvider: 'claude' as const,
stepModel: 'step-model',
personaProviders: {
reviewer: { provider: 'mock' as const, model: 'persona-model' },
},
personaDisplayName: 'coder',
localProvider: 'mock' as const,
localModel: 'local-model',
},
expected: { provider: 'claude' as const, model: 'step-model' },
},
{
name: 'No providers defined and no models defined -> all undefined',
input: {},
expected: { provider: undefined, model: undefined },
},
{
name: 'Only CLI model with persona-only model (no provider match), model remains persona-first',
input: {
cliModel: 'cli-model',
personaProviders: {
coder: { model: 'persona-model' },
},
personaDisplayName: 'coder',
stepProvider: 'mock' as const,
stepModel: 'step-model',
},
expected: { provider: 'mock' as const, model: 'cli-model' },
},
])('should resolve %s', ({ input, expected }) => {
const result = resolveAgentProviderModel(input);
expect(result).toEqual(expected);
});
it('should resolve provider in order: CLI > persona > movement > local > global', () => { it('should resolve provider in order: CLI > persona > movement > local > global', () => {
const result = resolveAgentProviderModel({ const result = resolveAgentProviderModel({
cliProvider: 'opencode', cliProvider: 'opencode',