Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/web/src/app/api/openrouter/[...path]/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ const mockedGetEffectiveModelDecision = jest.mocked(getEffectiveModelDecision);
const provider = {
id: 'openrouter',
apiUrl: 'https://openrouter.ai/api/v1',
apiUrlOverrides: {},
apiKey: 'test-key',
supportedChatApis: ['chat_completions', 'responses', 'messages'],
responseTransforms: null,
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/app/api/openrouter/[...path]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,7 @@ export async function POST(request: NextRequest): Promise<NextResponseType<unkno
}

const upstreamResult = await upstreamRequest({
chatApi: requestBodyParsed.kind,
path,
search: url.search,
method: request.method,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export function buildDirectProvider(
return {
id,
apiUrl: upstream.base_url,
apiUrlOverrides: {},
apiKey: upstream.api_key,
supportedChatApis,
responseTransforms: upstream.use_gemini_reasoning_transform
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'alibaba-token-plan',
base_url: 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest() {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const BYTEPLUS_CODING_MODEL_IDS = BYTEPLUS_CODING_MODELS.map(
export default {
id: BYTEPLUS_CODING_PROVIDER_ID,
base_url: 'https://ark.ap-southeast.bytepluses.com/api/coding/v3',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'chutes-byok',
base_url: 'https://llm.chutes.ai/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'crofai',
base_url: 'https://crof.ai/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import alibabaTokenPlan from './alibaba-token-plan';
import byteplusCoding from './byteplus-coding';
import chutesByok from './chutes-byok';
import crofai from './crofai';
import edenai from './edenai';
import inceptronByok from './inceptron-byok';
import kimiCoding from './kimi-coding';
import martian from './martian';
Expand All @@ -22,6 +23,7 @@ export default [
byteplusCoding,
chutesByok,
crofai,
edenai,
inceptronByok,
kimiCoding,
martian,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const DIRECT_BYOK_PROVIDERS_META = {
'byteplus-coding': 'BytePlus Coding Plan',
'chutes-byok': 'Chutes BYOK',
crofai: 'CrofAI',
edenai: 'Eden AI',
'kimi-coding': 'Kimi Code',
'inceptron-byok': 'Inceptron BYOK',
martian: 'Martian',
Expand Down
37 changes: 37 additions & 0 deletions apps/web/src/lib/ai-gateway/providers/direct-byok/edenai.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { getAiSdkProvider } from '../model-settings';
import type { GatewayRequest } from '../openrouter/types';
import type { TransformRequestContext } from '../types';
import edenai from './edenai';

describe('Eden AI direct BYOK provider', () => {
test('supports all chat APIs with the nested Anthropic Messages base URL', () => {
expect(edenai.base_url).toBe('https://api.edenai.run/v3');
expect(edenai.base_url_overrides).toEqual({ messages: 'https://api.edenai.run/v3/v1' });
expect(edenai.supported_chat_apis).toEqual(['chat_completions', 'messages', 'responses']);
});

test.each([
['edenai/openai/gpt-5.6-luna', 'openai'],
['edenai/anthropic/claude-sonnet-5', 'anthropic'],
['edenai/xai/grok-4.6', 'openai'],
['edenai/google/gemini-flash-latest', undefined],
] as const)('selects the model-family API for %s', (model, expectedProvider) => {
expect(getAiSdkProvider(model, 'edenai')).toBe(expectedProvider);
});

test.each([
[{ reasoning: { effort: 'high' } }, 'high'],
[{ reasoning: { enabled: false } }, 'none'],
[{ reasoning: { effort: 'low' }, reasoning_effort: 'medium' }, 'medium'],
] as const)('translates reasoning settings for Chat Completions', (body, expectedEffort) => {
const request: GatewayRequest = {
kind: 'chat_completions',
body: { model: 'test', messages: [], ...body },
};

edenai.transformRequest({ request } as TransformRequestContext);

expect(request.body).toMatchObject({ reasoning_effort: expectedEffort });
expect(request.body).not.toHaveProperty('reasoning');
});
});
32 changes: 32 additions & 0 deletions apps/web/src/lib/ai-gateway/providers/direct-byok/edenai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { cachedEnhancedDirectByokModelList } from '@/lib/ai-gateway/providers/direct-byok/model-list';
import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/types';

export default {
id: 'edenai',
base_url: 'https://api.edenai.run/v3',
base_url_overrides: { messages: 'https://api.edenai.run/v3/v1' },
supported_chat_apis: ['chat_completions', 'messages', 'responses'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
const { request } = context;
if (request.kind !== 'chat_completions') {
return;
}
request.body.reasoning_effort ??=
request.body.reasoning?.effort ??
(request.body.reasoning?.enabled === false ? 'none' : undefined);
delete request.body.reasoning;
},
models: cachedEnhancedDirectByokModelList({
providerId: 'edenai',
recommendedModels: [
{
id: 'openai/gpt-5.6-luna',
name: 'GPT-5.6 Luna',
flags: ['vision', 'reasoning'],
context_length: 1_050_000,
max_completion_tokens: 128_000,
},
],
}),
} satisfies DirectByokProvider;
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'inceptron-byok',
base_url: 'https://api.inceptron.io/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jest.mock('./direct-byok-definitions', () => ({
{
id: 'chutes-byok',
base_url: 'https://chutes.example.com/v1',
base_url_overrides: {},
models: jest.fn(async () => [
{
id: 'supported-model',
Expand All @@ -52,6 +53,7 @@ jest.mock('./direct-byok-definitions', () => ({
{
id: 'crofai',
base_url: 'https://crofai.example.com/v1',
base_url_overrides: {},
models: jest.fn(async () => [
{
id: 'other-model',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { isRooCodeBasedClient } from '@/lib/utils';
export default {
id: 'kimi-coding',
base_url: 'https://api.kimi.com/coding/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'martian',
base_url: 'https://api.withmartian.com/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions', 'messages', 'responses'],
default_ai_sdk_provider: 'openrouter',
transformRequest() {},
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/lib/ai-gateway/providers/direct-byok/morph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'morph-byok',
base_url: 'https://api.morphllm.com/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest() {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'neuralwatt',
base_url: 'https://api.neuralwatt.com/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(_context) {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'nvidia-byok',
base_url: 'https://integrate.api.nvidia.com/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'ollama-cloud',
base_url: 'https://ollama.com/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'opencode-go',
base_url: 'https://opencode.ai/zen/go/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions', 'messages', 'responses'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'orcarouter',
base_url: 'https://api.orcarouter.ai/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions', 'messages', 'responses'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ describe('parseOpenAICompatibleProviderModels', () => {
id: 'morph-minimax3-428b',
max_model_len: 256000,
},
{
id: 'provider-with-null-context',
context_length: null,
},
],
});

Expand All @@ -40,6 +44,14 @@ describe('parseOpenAICompatibleProviderModels', () => {
input_modalities: undefined,
flags: ['reasoning'],
},
{
id: 'provider-with-null-context',
name: undefined,
context_length: undefined,
max_completion_tokens: undefined,
input_modalities: undefined,
flags: ['reasoning'],
},
]);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const OpenAICompatibleModelsResponseSchema = z.object({
z.object({
id: z.string(),
name: z.string().optional(),
context_length: z.number().optional(),
context_length: z.number().nullish(),
max_model_len: z.number().optional(),
max_output_length: z.number().optional(),
input_modalities: z.array(ModalitySchema).optional(),
Expand Down Expand Up @@ -294,6 +294,7 @@ const FETCHERS: ReadonlyArray<ProviderFetcher> = [
url: 'https://www.morphllm.com/api/models/json',
}),
modelsDevFetcher('alibaba-token-plan', 'alibaba-token-plan'),
modelsDevFetcher('edenai', 'edenai', 'https://api.edenai.run/v3/models'),
modelsDevFetcher('zai-coding', 'zai-coding-plan'),
modelsDevFetcher('ollama-cloud', 'ollama-cloud', 'https://ollama.com/v1/models'),
modelsDevFetcher('opencode-go', 'opencode-go', 'https://opencode.ai/zen/go/v1/models'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { DirectByokProvider } from '@/lib/ai-gateway/providers/direct-byok/
export default {
id: 'synthetic',
base_url: 'https://api.synthetic.new/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
7 changes: 6 additions & 1 deletion apps/web/src/lib/ai-gateway/providers/direct-byok/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import * as z from 'zod';
import type { DirectByokProviderMetaId } from '@/lib/ai-gateway/providers/direct-byok/direct-byok-meta';
import type { GatewayChatApiKind, TransformRequestContext } from '@/lib/ai-gateway/providers/types';
import type {
GatewayChatApiKind,
ProviderApiUrlOverrides,
TransformRequestContext,
} from '@/lib/ai-gateway/providers/types';
import type { CustomLlmProvider } from '@kilocode/db';
import { OpenCodeVariantSchema } from '@kilocode/db/schema-types';

Expand All @@ -24,6 +28,7 @@ export type DirectByokModel = z.infer<typeof DirectByokModelSchema>;
export type DirectByokProvider = {
id: DirectByokProviderMetaId;
base_url: string;
base_url_overrides: ProviderApiUrlOverrides;
models: () => Promise<ReadonlyArray<DirectByokModel>>;
supported_chat_apis: ReadonlyArray<GatewayChatApiKind>;
default_ai_sdk_provider: CustomLlmProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { cachedEnhancedDirectByokModelList } from '@/lib/ai-gateway/providers/di
export default {
id: 'xiaomi-token-plan-ams',
base_url: 'https://token-plan-ams.xiaomimimo.com/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest() {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { cachedEnhancedDirectByokModelList } from '@/lib/ai-gateway/providers/di
export default {
id: 'xiaomi-token-plan-sgp',
base_url: 'https://token-plan-sgp.xiaomimimo.com/v1',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest() {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { cachedEnhancedDirectByokModelList } from '@/lib/ai-gateway/providers/di
export default {
id: 'zai-coding',
base_url: 'https://api.z.ai/api/coding/paas/v4',
base_url_overrides: {},
supported_chat_apis: ['chat_completions'],
default_ai_sdk_provider: 'openai-compatible',
transformRequest(context) {
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/lib/ai-gateway/providers/get-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ async function checkDirectBYOK(
provider: {
id: 'direct-byok',
apiUrl: directByok.base_url,
apiUrlOverrides: directByok.base_url_overrides,
apiKey: userByok[0].decryptedAPIKey,
supportedChatApis: directByok.supported_chat_apis,
responseTransforms: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export const DirectUserByokInferenceProviderIdSchema = z.enum([
'chutes-byok',
'codestral',
'crofai',
'edenai',
'inceptron-byok',
'kimi-coding',
'martian',
Expand Down Expand Up @@ -152,6 +153,7 @@ export const UserByokTestModels = {
[DirectUserByokInferenceProviderIdSchema.enum['byteplus-coding']]: 'bytedance-seed-code',
[DirectUserByokInferenceProviderIdSchema.enum['chutes-byok']]: 'Qwen/Qwen3-30B-A3B',
[DirectUserByokInferenceProviderIdSchema.enum.codestral]: 'mistral/codestral',
[DirectUserByokInferenceProviderIdSchema.enum.edenai]: 'openai/gpt-5.6-luna',
[DirectUserByokInferenceProviderIdSchema.enum['kimi-coding']]: 'kimi-for-coding',
[DirectUserByokInferenceProviderIdSchema.enum['inceptron-byok']]: 'moonshotai/Kimi-K2.6',
[DirectUserByokInferenceProviderIdSchema.enum.martian]: 'google/gemini-3.5-flash',
Expand Down
Loading