diff --git a/src/targets/droid-provider.ts b/src/targets/droid-provider.ts index 1c5f9850..311a5eac 100644 --- a/src/targets/droid-provider.ts +++ b/src/targets/droid-provider.ts @@ -76,7 +76,19 @@ export function inferDroidProviderFromBaseUrl( return 'openai'; } - if (host.includes('anthropic.com') || pathname.includes('/anthropic')) { + if ( + pathname.includes('/compatible-mode') || + pathname.includes('/openai') || + pathname.includes('/chat/completions') + ) { + return 'generic-chat-completion-api'; + } + + if ( + host.includes('anthropic.com') || + pathname.includes('/anthropic') || + host.includes('ollama.com') + ) { return 'anthropic'; } @@ -87,11 +99,7 @@ export function inferDroidProviderFromBaseUrl( host.includes('api.fireworks.ai') || host.includes('inference.baseten.co') || host.includes('dashscope') || - host.includes('huggingface.co') || - host.includes('ollama.com') || - pathname.includes('/compatible-mode') || - pathname.includes('/openai') || - pathname.includes('/chat/completions') + host.includes('huggingface.co') ) { return 'generic-chat-completion-api'; } diff --git a/tests/unit/proxy/profile-router.test.ts b/tests/unit/proxy/profile-router.test.ts index ba523ed9..18f0d398 100644 --- a/tests/unit/proxy/profile-router.test.ts +++ b/tests/unit/proxy/profile-router.test.ts @@ -50,4 +50,33 @@ describe('resolveOpenAICompatProfileConfig', () => { expect(result?.provider).toBe('generic-chat-completion-api'); expect(result?.model).toBe('qwen3.6-plus'); }); + + it('does not proxy bare ollama.com profiles that are anthropic-native', () => { + const result = resolveOpenAICompatProfileConfig( + 'ollama-cloud', + '/tmp/ollama-cloud.settings.json', + { + ANTHROPIC_BASE_URL: 'https://ollama.com', + ANTHROPIC_AUTH_TOKEN: 'ollama-token', + ANTHROPIC_MODEL: 'qwen3-coder-plus', + } + ); + + expect(result).toBeNull(); + }); + + it('still proxies explicit ollama.com chat-completions endpoints', () => { + const result = resolveOpenAICompatProfileConfig( + 'ollama-cloud-chat-completions', + '/tmp/ollama-cloud-chat-completions.settings.json', + { + ANTHROPIC_BASE_URL: 'https://ollama.com/v1/chat/completions', + ANTHROPIC_AUTH_TOKEN: 'ollama-token', + ANTHROPIC_MODEL: 'qwen3-coder-plus', + } + ); + + expect(result).not.toBeNull(); + expect(result?.provider).toBe('generic-chat-completion-api'); + }); }); diff --git a/tests/unit/targets/droid-provider.test.ts b/tests/unit/targets/droid-provider.test.ts index 2a9c5a3b..6e54d40a 100644 --- a/tests/unit/targets/droid-provider.test.ts +++ b/tests/unit/targets/droid-provider.test.ts @@ -94,5 +94,31 @@ describe('droid-provider', () => { expect(resolveDroidProvider({ baseUrl: 'http://127.0.0.1:8317' })).toBe('anthropic'); expect(resolveDroidProvider({})).toBe('anthropic'); }); + + it('defaults ollama.com to anthropic', () => { + expect(resolveDroidProvider({ baseUrl: 'https://ollama.com' })).toBe('anthropic'); + expect(resolveDroidProvider({ baseUrl: 'https://ollama.com/v1/messages' })).toBe('anthropic'); + }); + + it('keeps ollama.com anthropic even for generic model families', () => { + expect( + resolveDroidProvider({ + baseUrl: 'https://ollama.com', + model: 'qwen3-coder-plus', + }) + ).toBe('anthropic'); + expect( + resolveDroidProvider({ + baseUrl: 'https://ollama.com/v1/messages', + model: 'deepseek-v3.1', + }) + ).toBe('anthropic'); + }); + + it('routes ollama.com /chat/completions to generic', () => { + expect(resolveDroidProvider({ baseUrl: 'https://ollama.com/v1/chat/completions' })).toBe( + 'generic-chat-completion-api' + ); + }); }); });