mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 18:16:08 +00:00
86 lines
3.2 KiB
TypeScript
86 lines
3.2 KiB
TypeScript
import { describe, expect, it } from 'bun:test';
|
|
import {
|
|
isAnthropicPassthroughProfile,
|
|
resolveOpenAIChatCompletionsUrl,
|
|
resolveOpenAIModelsUrl,
|
|
} from '../../../src/proxy/upstream-url';
|
|
|
|
describe('OpenAI-compatible upstream URL resolution', () => {
|
|
it('routes current OpenRouter API roots through /api/v1', () => {
|
|
expect(resolveOpenAIChatCompletionsUrl('https://openrouter.ai/api/v1')).toBe(
|
|
'https://openrouter.ai/api/v1/chat/completions'
|
|
);
|
|
expect(resolveOpenAIModelsUrl('https://openrouter.ai/api/v1')).toBe(
|
|
'https://openrouter.ai/api/v1/models'
|
|
);
|
|
});
|
|
|
|
it('repairs legacy OpenRouter /api roots before appending OpenAI endpoints', () => {
|
|
expect(resolveOpenAIChatCompletionsUrl('https://openrouter.ai/api')).toBe(
|
|
'https://openrouter.ai/api/v1/chat/completions'
|
|
);
|
|
expect(resolveOpenAIModelsUrl('https://openrouter.ai/api')).toBe(
|
|
'https://openrouter.ai/api/v1/models'
|
|
);
|
|
});
|
|
|
|
it('does not rewrite non-OpenRouter /api roots', () => {
|
|
expect(resolveOpenAIChatCompletionsUrl('https://example.test/api')).toBe(
|
|
'https://example.test/api/chat/completions'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('Anthropic passthrough URL resolution', () => {
|
|
it('resolves to /v1/messages when forcePassthrough is set', () => {
|
|
expect(
|
|
resolveOpenAIChatCompletionsUrl('https://api.kimi.com/coding/', {
|
|
passthrough: true,
|
|
})
|
|
).toBe('https://api.kimi.com/coding/v1/messages');
|
|
});
|
|
|
|
it('drops a duplicated /v1 prefix when the base URL already ends in /v1', () => {
|
|
expect(
|
|
resolveOpenAIChatCompletionsUrl('https://api.kimi.com/coding/v1', {
|
|
passthrough: true,
|
|
})
|
|
).toBe('https://api.kimi.com/coding/v1/messages');
|
|
});
|
|
|
|
it('routes /v1/models in passthrough mode', () => {
|
|
expect(
|
|
resolveOpenAIModelsUrl('https://api.kimi.com/coding/v1', {
|
|
passthrough: true,
|
|
})
|
|
).toBe('https://api.kimi.com/coding/v1/models');
|
|
});
|
|
|
|
it('auto-detects known Anthropic-style hosts', () => {
|
|
expect(isAnthropicPassthroughProfile('https://api.kimi.com/coding/')).toBe(true);
|
|
expect(isAnthropicPassthroughProfile('https://api.kimi.com/coding/v1')).toBe(true);
|
|
expect(isAnthropicPassthroughProfile('https://api.anthropic.com')).toBe(true);
|
|
});
|
|
|
|
it('does not treat generic /v1 roots as Anthropic-style passthrough', () => {
|
|
expect(isAnthropicPassthroughProfile('https://example.test/v1')).toBe(false);
|
|
expect(isAnthropicPassthroughProfile('https://example.test/v1/')).toBe(false);
|
|
expect(isAnthropicPassthroughProfile('https://example.test/api/v1')).toBe(false);
|
|
expect(isAnthropicPassthroughProfile('https://api.openai.com/v1')).toBe(false);
|
|
expect(isAnthropicPassthroughProfile('https://api.minimax.io/v1')).toBe(false);
|
|
});
|
|
|
|
it('does not auto-detect OpenAI-style base URLs as Anthropic-style', () => {
|
|
expect(isAnthropicPassthroughProfile('https://api.fireworks.ai/inference')).toBe(false);
|
|
expect(isAnthropicPassthroughProfile('https://api.openai.com/v1')).toBe(false);
|
|
});
|
|
|
|
it('honors explicit force passthrough for unknown mirrors', () => {
|
|
expect(
|
|
isAnthropicPassthroughProfile('https://anthropic-mirror.example.test/v1', {
|
|
forcePassthrough: true,
|
|
})
|
|
).toBe(true);
|
|
});
|
|
});
|