diff --git a/src/data/providers.json b/src/data/providers.json index fd801fdc5..7dbd83dff 100644 --- a/src/data/providers.json +++ b/src/data/providers.json @@ -247,6 +247,13 @@ "description": "SambaNova Systems provides hardware-software integrated solutions optimized specifically for running large-scale machine learning workloads efficiently. Their technology aims at accelerating model training times while ensuring high performance during inference phases across diverse applications.", "base_url": "https://api.sambanova.ai" }, + { + "id": "saladcloud", + "name": "SaladCloud AI Gateway", + "object": "provider", + "description": "SaladCloud AI Gateway provides OpenAI-compatible access to qwen3.6-35b-a3b with streaming, reasoning, tool calling, structured outputs, and text and image inputs.", + "base_url": "https://ai.salad.cloud/v1" + }, { "id": "segmind", "name": "Segmind", diff --git a/src/globals.ts b/src/globals.ts index 4d6e327e4..48e2a67cc 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -82,6 +82,7 @@ export const SILICONFLOW: string = 'siliconflow'; export const CEREBRAS: string = 'cerebras'; export const INFERENCENET: string = 'inference-net'; export const SAMBANOVA: string = 'sambanova'; +export const SALADCLOUD: string = 'saladcloud'; export const LEMONFOX_AI: string = 'lemonfox-ai'; export const UPSTAGE: string = 'upstage'; export const LAMBDA: string = 'lambda'; @@ -157,6 +158,7 @@ export const VALID_PROVIDERS = [ CEREBRAS, INFERENCENET, SAMBANOVA, + SALADCLOUD, LEMONFOX_AI, UPSTAGE, LAMBDA, diff --git a/src/providers/index.ts b/src/providers/index.ts index 2cd5355f8..a4851d5d1 100644 --- a/src/providers/index.ts +++ b/src/providers/index.ts @@ -74,6 +74,7 @@ import OracleConfig from './oracle'; import IOIntelligenceConfig from './iointelligence'; import AIBadgrConfig from './aibadgr'; import OVHcloudConfig from './ovhcloud'; +import SaladCloudConfig from './saladcloud'; const Providers: { [key: string]: ProviderConfigs } = { openai: OpenAIConfig, @@ -148,6 +149,7 @@ const Providers: { [key: string]: ProviderConfigs } = { iointelligence: IOIntelligenceConfig, aibadgr: AIBadgrConfig, ovhcloud: OVHcloudConfig, + saladcloud: SaladCloudConfig, }; export default Providers; diff --git a/src/providers/saladcloud/api.ts b/src/providers/saladcloud/api.ts new file mode 100644 index 000000000..6696ee6a4 --- /dev/null +++ b/src/providers/saladcloud/api.ts @@ -0,0 +1,20 @@ +import { ProviderAPIConfig } from '../types'; + +const DEFAULT_SALADCLOUD_BASE_URL = 'https://ai.salad.cloud/v1'; + +const SaladCloudAPIConfig: ProviderAPIConfig = { + getBaseURL: () => DEFAULT_SALADCLOUD_BASE_URL, + headers: ({ providerOptions }) => ({ + Authorization: `Bearer ${providerOptions.apiKey}`, + }), + getEndpoint: ({ fn }) => { + switch (fn) { + case 'chatComplete': + return '/chat/completions'; + default: + return ''; + } + }, +}; + +export default SaladCloudAPIConfig; diff --git a/src/providers/saladcloud/chatComplete.ts b/src/providers/saladcloud/chatComplete.ts new file mode 100644 index 000000000..47e1d8d30 --- /dev/null +++ b/src/providers/saladcloud/chatComplete.ts @@ -0,0 +1,31 @@ +import { ProviderConfig } from '../types'; + +export const SaladCloudChatCompleteExcludedParams = [ + 'audio', + 'logit_bias', + 'logprobs', + 'metadata', + 'modalities', + 'parallel_tool_calls', + 'prediction', + 'prompt_cache_key', + 'safety_identifier', + 'service_tier', + 'store', + 'top_logprobs', + 'verbosity', + 'web_search_options', +]; + +export const SaladCloudChatCompleteDefaults = { + model: 'qwen3.6-35b-a3b', +}; + +export const SaladCloudChatCompleteExtraParams: ProviderConfig = { + top_k: { + param: 'top_k', + }, + chat_template_kwargs: { + param: 'chat_template_kwargs', + }, +}; diff --git a/src/providers/saladcloud/index.test.ts b/src/providers/saladcloud/index.test.ts new file mode 100644 index 000000000..545bc5524 --- /dev/null +++ b/src/providers/saladcloud/index.test.ts @@ -0,0 +1,46 @@ +import { SALADCLOUD } from '../../globals'; +import SaladCloudAPIConfig from './api'; +import { + SaladCloudChatCompleteDefaults, + SaladCloudChatCompleteExcludedParams, + SaladCloudChatCompleteExtraParams, +} from './chatComplete'; + +describe('SaladCloud provider', () => { + const providerOptions = { provider: SALADCLOUD, apiKey: 'test-key' }; + + it('uses the SaladCloud OpenAI-compatible chat completions endpoint', () => { + const baseURLArgs = { + providerOptions, + } as Parameters[0]; + const endpointArgs = { + fn: 'chatComplete', + providerOptions, + } as Parameters[0]; + const headerArgs = { + providerOptions, + } as Parameters[0]; + + expect(SaladCloudAPIConfig.getBaseURL(baseURLArgs)).toEqual( + 'https://ai.salad.cloud/v1' + ); + expect(SaladCloudAPIConfig.getEndpoint(endpointArgs)).toEqual( + '/chat/completions' + ); + expect(SaladCloudAPIConfig.headers(headerArgs)).toEqual({ + Authorization: 'Bearer test-key', + }); + }); + + it('defaults to the 35B model without disabling reasoning', () => { + expect(SaladCloudChatCompleteDefaults).toEqual({ + model: 'qwen3.6-35b-a3b', + }); + expect(SaladCloudChatCompleteExcludedParams).not.toContain( + 'reasoning_effort' + ); + expect(SaladCloudChatCompleteExtraParams.chat_template_kwargs).toEqual({ + param: 'chat_template_kwargs', + }); + }); +}); diff --git a/src/providers/saladcloud/index.ts b/src/providers/saladcloud/index.ts new file mode 100644 index 000000000..3c8311a28 --- /dev/null +++ b/src/providers/saladcloud/index.ts @@ -0,0 +1,23 @@ +import { SALADCLOUD } from '../../globals'; +import { chatCompleteParams, responseTransformers } from '../open-ai-base'; +import { ProviderConfigs } from '../types'; +import SaladCloudAPIConfig from './api'; +import { + SaladCloudChatCompleteDefaults, + SaladCloudChatCompleteExcludedParams, + SaladCloudChatCompleteExtraParams, +} from './chatComplete'; + +const SaladCloudConfig: ProviderConfigs = { + chatComplete: chatCompleteParams( + SaladCloudChatCompleteExcludedParams, + SaladCloudChatCompleteDefaults, + SaladCloudChatCompleteExtraParams + ), + api: SaladCloudAPIConfig, + responseTransforms: responseTransformers(SALADCLOUD, { + chatComplete: true, + }), +}; + +export default SaladCloudConfig; diff --git a/src/tests/resources/testVariables.ts b/src/tests/resources/testVariables.ts index 2c5047dc7..2fae4a010 100644 --- a/src/tests/resources/testVariables.ts +++ b/src/tests/resources/testVariables.ts @@ -142,6 +142,10 @@ const testVariables: TestVariables = { model: 'Qwen/Qwen2.5-Coder-3B-Instruct', }, }, + saladcloud: { + apiKey: process.env.SALAD_CLOUD_API_KEY, + chatCompletions: { model: 'qwen3.6-35b-a3b' }, + }, }; export default testVariables;