SPB Git

spb/zyquo-cloud-web Public MIT

Zyquo Cloud Web — every cloud model, one beautiful chat, entirely in your browser.

TypeScript 81.9% CSS 8.9% JavaScript 7.5% Shell 1.1% HTML 0.6%
4.5 KB · 152 lines typescript
Raw Blame History
1/*2 *  registry.ts3 *  Zyquo Cloud Web4 *5 *  Author: Simon-Pierre Boucher6 *  Mail: contact@spboucher.ai7 *8 *  Provider metadata + client resolution, ported from ProviderID.swift and9 *  ProviderRegistry.swift. The only place that knows which wire format each10 *  provider speaks and where its API lives.11 */1213import type { AIModel, Provider, WireFormat } from '../types'1415export interface ProviderMeta {16  displayName: string17  wireFormat: WireFormat18  /** Base URL of the provider's API (chat + models live under this root). */19  defaultBaseURL: string | null20  /** Whether the provider exposes a usable `/models` listing endpoint. */21  supportsModelListing: boolean22  /**23   * Providers whose final streamed chunk carries usage only when asked via24   * stream_options. Mistral rejects unknown params; Qwen/DeepInfra/Perplexity25   * include usage automatically.26   */27  wantsStreamOptions: boolean28  /** CORS verdict from docs/CORS-MATRIX.md (all 12 work; Anthropic needs a header). */29  corsDirect: boolean30}3132export const PROVIDER_META: Record<Provider, ProviderMeta> = {33  openai: {34    displayName: 'OpenAI',35    wireFormat: 'openAIChatCompletions',36    defaultBaseURL: 'https://api.openai.com/v1',37    supportsModelListing: true,38    wantsStreamOptions: true,39    corsDirect: true,40  },41  anthropic: {42    displayName: 'Anthropic',43    wireFormat: 'anthropicMessages',44    defaultBaseURL: 'https://api.anthropic.com/v1',45    supportsModelListing: true,46    wantsStreamOptions: false,47    corsDirect: true,48  },49  xai: {50    displayName: 'xAI',51    wireFormat: 'openAIChatCompletions',52    defaultBaseURL: 'https://api.x.ai/v1',53    supportsModelListing: true,54    wantsStreamOptions: true,55    corsDirect: true,56  },57  mistral: {58    displayName: 'Mistral',59    wireFormat: 'openAIChatCompletions',60    defaultBaseURL: 'https://api.mistral.ai/v1',61    supportsModelListing: true,62    wantsStreamOptions: false,63    corsDirect: true,64  },65  gemini: {66    displayName: 'Google Gemini',67    wireFormat: 'openAIChatCompletions',68    defaultBaseURL: 'https://generativelanguage.googleapis.com/v1beta/openai',69    supportsModelListing: true,70    wantsStreamOptions: true,71    corsDirect: true,72  },73  qwen: {74    displayName: 'Alibaba Qwen',75    wireFormat: 'openAIChatCompletions',76    defaultBaseURL: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1',77    supportsModelListing: true,78    wantsStreamOptions: false,79    corsDirect: true,80  },81  deepseek: {82    displayName: 'DeepSeek',83    wireFormat: 'openAIChatCompletions',84    defaultBaseURL: 'https://api.deepseek.com',85    supportsModelListing: true,86    wantsStreamOptions: true,87    corsDirect: true,88  },89  kimi: {90    displayName: 'Kimi',91    wireFormat: 'openAIChatCompletions',92    defaultBaseURL: 'https://api.moonshot.ai/v1',93    supportsModelListing: true,94    wantsStreamOptions: true,95    corsDirect: true,96  },97  perplexity: {98    displayName: 'Perplexity',99    wireFormat: 'openAIChatCompletions',100    defaultBaseURL: 'https://api.perplexity.ai',101    supportsModelListing: false,102    wantsStreamOptions: false,103    corsDirect: true,104  },105  together: {106    displayName: 'Together AI',107    wireFormat: 'openAIChatCompletions',108    defaultBaseURL: 'https://api.together.xyz/v1',109    supportsModelListing: true,110    wantsStreamOptions: true,111    corsDirect: true,112  },113  deepinfra: {114    displayName: 'DeepInfra',115    wireFormat: 'openAIChatCompletions',116    defaultBaseURL: 'https://api.deepinfra.com/v1/openai',117    supportsModelListing: true,118    wantsStreamOptions: false,119    corsDirect: true,120  },121  cerebras: {122    displayName: 'Cerebras',123    wireFormat: 'openAIChatCompletions',124    defaultBaseURL: 'https://api.cerebras.ai/v1',125    supportsModelListing: true,126    wantsStreamOptions: true,127    corsDirect: true,128  },129  custom: {130    displayName: 'Custom',131    wireFormat: 'openAIChatCompletions',132    defaultBaseURL: null,133    supportsModelListing: true,134    wantsStreamOptions: true,135    corsDirect: true,136  },137}138139import type { ProviderClient } from './types'140import { OpenAICompatibleClient } from './openaiCompatible'141import { AnthropicClient } from './anthropic'142143/** Resolves the right client for a provider or custom model. */144export function clientFor(providerOrModel: Provider | AIModel): ProviderClient {145  const provider =146    typeof providerOrModel === 'string' ? providerOrModel : providerOrModel.provider147  if (PROVIDER_META[provider].wireFormat === 'anthropicMessages') {148    return new AnthropicClient()149  }150  return new OpenAICompatibleClient(provider)151}152