mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-18 11:06:19 +00:00
feat: add Kimi/Moonshot partnership branding with feature flag
## Summary - Add `VITE_PUBLIC_KIMI_LAUNCH` feature flag controlling Kimi partnership branding - BrowserOS provider card shows "Powered by Kimi K2.5 from Moonshot AI" badge and "Extended usage limits for the next 2 weeks!" when flag is on - Moonshot/Kimi highlighted as "Recommended" in provider templates - LLM Hub defaults to Kimi, ChatGPT, Claude, Gemini (with legacy defaults migration) - Kimi hub row shows "Powered by Moonshot AI" flare - Model selector locked to kimi-k2.5 - "How to get a Kimi API key" link in provider dialog - Moonshot provider fully integrated across frontend and backend
This commit is contained in:
@@ -15,6 +15,9 @@ VITE_PUBLIC_SENTRY_DSN=
|
||||
# BrowserOS API URL
|
||||
VITE_PUBLIC_BROWSEROS_API=https://api.browseros.com
|
||||
|
||||
# Launch feature flags
|
||||
VITE_PUBLIC_KIMI_LAUNCH=false
|
||||
|
||||
# GraphQL Schema Path (optional — falls back to schema/schema.graphql)
|
||||
GRAPHQL_SCHEMA_PATH=
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import { track } from '@/lib/metrics/track'
|
||||
import { getModelContextLength, getModelOptions } from './models'
|
||||
|
||||
const providerTypeEnum = z.enum([
|
||||
'moonshot',
|
||||
'anthropic',
|
||||
'openai',
|
||||
'openai-compatible',
|
||||
@@ -413,6 +414,12 @@ export const NewProviderDialog: FC<NewProviderDialogProps> = ({
|
||||
const providerTemplate = getProviderTemplate(watchedType as ProviderType)
|
||||
const setupGuideUrl = providerTemplate?.setupGuideUrl
|
||||
const providerName = providerTemplate?.name
|
||||
const setupGuideText =
|
||||
watchedType === 'moonshot'
|
||||
? 'How to get a Kimi API key'
|
||||
: providerName
|
||||
? `${providerName} setup guide`
|
||||
: 'Provider setup guide'
|
||||
|
||||
const handleSetupGuideClick = (e: React.MouseEvent) => {
|
||||
e.preventDefault()
|
||||
@@ -596,7 +603,7 @@ export const NewProviderDialog: FC<NewProviderDialogProps> = ({
|
||||
className="inline-flex cursor-pointer items-center gap-1 text-primary hover:underline"
|
||||
>
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
{providerName} setup guide
|
||||
{setupGuideText}
|
||||
</a>
|
||||
)}
|
||||
</FormDescription>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Check, Loader2, Trash2 } from 'lucide-react'
|
||||
import type { FC } from 'react'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useKimiLaunch } from '@/lib/feature-flags/useKimiLaunch'
|
||||
import { BrowserOSIcon, ProviderIcon } from '@/lib/llm-providers/providerIcons'
|
||||
import type { LlmProviderConfig } from '@/lib/llm-providers/types'
|
||||
import { cn } from '@/lib/utils'
|
||||
@@ -29,6 +30,7 @@ export const ProviderCard: FC<ProviderCardProps> = ({
|
||||
isTesting = false,
|
||||
}) => {
|
||||
const inputId = `provider-${provider.id}`
|
||||
const kimiLaunch = useKimiLaunch()
|
||||
|
||||
return (
|
||||
<label
|
||||
@@ -77,21 +79,30 @@ export const ProviderCard: FC<ProviderCardProps> = ({
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{isBuiltIn && provider.type === 'browseros' && kimiLaunch && (
|
||||
<span className="mb-1 inline-block rounded-full border border-orange-300/60 bg-orange-100/70 px-3 py-0.5 font-semibold text-orange-700 text-xs dark:border-orange-400/40 dark:bg-orange-500/15 dark:text-orange-300">
|
||||
Powered by Kimi K2.5 from Moonshot AI
|
||||
</span>
|
||||
)}
|
||||
<p className="truncate text-muted-foreground text-sm">
|
||||
{isBuiltIn ? (
|
||||
<>
|
||||
BrowserOS-hosted model with strict rate limits.{' '}
|
||||
<a
|
||||
href="https://docs.browseros.com/features/bring-your-own-llm"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline hover:text-foreground"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
Bring your own key
|
||||
</a>{' '}
|
||||
for better performance.
|
||||
</>
|
||||
kimiLaunch ? (
|
||||
'Extended usage limits for the next 2 weeks!'
|
||||
) : (
|
||||
<>
|
||||
BrowserOS-hosted model with strict rate limits.{' '}
|
||||
<a
|
||||
href="https://docs.browseros.com/features/bring-your-own-llm"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline hover:text-foreground"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
Bring your own key
|
||||
</a>{' '}
|
||||
for better performance.
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
`${provider.modelId} • ${provider.baseUrl}`
|
||||
)}
|
||||
|
||||
@@ -2,29 +2,54 @@ import type { FC } from 'react'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { ProviderIcon } from '@/lib/llm-providers/providerIcons'
|
||||
import type { ProviderTemplate } from '@/lib/llm-providers/providerTemplates'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface ProviderTemplateCardProps {
|
||||
template: ProviderTemplate
|
||||
highlighted?: boolean
|
||||
onUseTemplate: (template: ProviderTemplate) => void
|
||||
}
|
||||
|
||||
export const ProviderTemplateCard: FC<ProviderTemplateCardProps> = ({
|
||||
template,
|
||||
highlighted = false,
|
||||
onUseTemplate,
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onUseTemplate(template)}
|
||||
className="group flex w-full items-center justify-between rounded-lg border border-border bg-background p-4 text-left transition-all hover:border-[var(--accent-orange)] hover:shadow-md"
|
||||
className={cn(
|
||||
'group flex w-full items-center gap-3 rounded-lg border bg-background p-4 text-left transition-all hover:border-[var(--accent-orange)] hover:shadow-md',
|
||||
highlighted
|
||||
? 'border-orange-300/80 bg-orange-50/30 shadow-sm ring-1 ring-orange-300/45 dark:bg-orange-500/5'
|
||||
: 'border-border',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-3 text-accent-orange/70 transition-colors group-hover:text-accent-orange">
|
||||
<ProviderIcon type={template.id} size={28} />
|
||||
<span className="font-medium text-foreground">{template.name}</span>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-3">
|
||||
<ProviderIcon
|
||||
type={template.id}
|
||||
size={28}
|
||||
className="shrink-0 text-accent-orange/70 transition-colors group-hover:text-accent-orange"
|
||||
/>
|
||||
<div className="min-w-0">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="font-medium text-foreground">{template.name}</span>
|
||||
{highlighted && (
|
||||
<span className="rounded-full border border-orange-300/60 bg-orange-100/70 px-2 py-0.5 font-semibold text-[10px] text-orange-700 dark:border-orange-400/40 dark:bg-orange-500/15 dark:text-orange-300">
|
||||
Recommended
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="rounded-md px-3 py-1 transition-colors group-hover:border-[var(--accent-orange)] group-hover:text-[var(--accent-orange)]"
|
||||
className={cn(
|
||||
'shrink-0 rounded-md px-3 py-1 transition-colors group-hover:border-[var(--accent-orange)] group-hover:text-[var(--accent-orange)]',
|
||||
highlighted &&
|
||||
'border-[var(--accent-orange)] bg-[var(--accent-orange)]/5 text-[var(--accent-orange)]',
|
||||
)}
|
||||
>
|
||||
USE
|
||||
</Badge>
|
||||
|
||||
@@ -54,6 +54,7 @@ export const ProviderTemplatesSection: FC<ProviderTemplatesSectionProps> = ({
|
||||
<ProviderTemplateCard
|
||||
key={template.id}
|
||||
template={template}
|
||||
highlighted={template.id === 'moonshot'}
|
||||
onUseTemplate={onUseTemplate}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface ModelsData {
|
||||
lmstudio: ModelInfo[]
|
||||
bedrock: ModelInfo[]
|
||||
browseros: ModelInfo[]
|
||||
moonshot: ModelInfo[]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,6 +30,7 @@ export interface ModelsData {
|
||||
* Based on: https://github.com/browseros-ai/BrowserOS-agent/blob/main/src/options/data/models.ts
|
||||
*/
|
||||
export const MODELS_DATA: ModelsData = {
|
||||
moonshot: [{ modelId: 'kimi-k2.5', contextLength: 128000 }],
|
||||
anthropic: [
|
||||
{ modelId: 'claude-opus-4-5-20251101', contextLength: 200000 },
|
||||
{ modelId: 'claude-haiku-4-5-20251001', contextLength: 200000 },
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Globe2, Trash2 } from 'lucide-react'
|
||||
import type { FC } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { getFaviconUrl, type LlmHubProvider } from './models'
|
||||
|
||||
interface HubProviderRowProps {
|
||||
@@ -18,9 +19,19 @@ export const HubProviderRow: FC<HubProviderRowProps> = ({
|
||||
onDelete,
|
||||
}) => {
|
||||
const iconUrl = useMemo(() => getFaviconUrl(provider.url), [provider.url])
|
||||
const normalizedName = provider.name.trim().toLowerCase()
|
||||
const normalizedUrl = provider.url.trim().toLowerCase()
|
||||
const isKimi = normalizedName === 'kimi' || normalizedUrl.includes('kimi.com')
|
||||
const showKimiFlare = isKimi
|
||||
|
||||
return (
|
||||
<div className="group flex w-full items-center gap-4 rounded-xl border border-border bg-card p-4 transition-all hover:border-[var(--accent-orange)] hover:shadow-md">
|
||||
<div
|
||||
className={cn(
|
||||
'group flex w-full items-center gap-4 rounded-xl border border-border bg-card p-4 transition-all hover:border-[var(--accent-orange)] hover:shadow-md',
|
||||
showKimiFlare &&
|
||||
'border-orange-300/80 bg-orange-50/20 shadow-sm ring-1 ring-orange-300/45 dark:bg-orange-500/5',
|
||||
)}
|
||||
>
|
||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted">
|
||||
{iconUrl ? (
|
||||
<img
|
||||
@@ -34,9 +45,19 @@ export const HubProviderRow: FC<HubProviderRowProps> = ({
|
||||
</div>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<span className="mb-0.5 block truncate font-semibold">
|
||||
{provider.name}
|
||||
</span>
|
||||
<div className="mb-0.5 flex items-center gap-2">
|
||||
<span className="block truncate font-semibold">{provider.name}</span>
|
||||
{showKimiFlare && (
|
||||
<div className="flex flex-wrap items-center gap-1">
|
||||
<span className="rounded-full border border-orange-300/60 bg-orange-100/70 px-2 py-0.5 font-semibold text-[11px] text-orange-700 dark:border-orange-400/40 dark:bg-orange-500/15 dark:text-orange-300">
|
||||
Recommended
|
||||
</span>
|
||||
<span className="rounded-full border border-orange-300/60 bg-orange-100/60 px-2.5 py-0.5 font-medium text-orange-700 text-xs dark:border-orange-400/40 dark:bg-orange-500/15 dark:text-orange-300">
|
||||
Powered by Moonshot AI
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<p className="truncate text-muted-foreground/70 text-xs">
|
||||
{provider.url}
|
||||
</p>
|
||||
|
||||
@@ -34,7 +34,7 @@ export const HubProvidersList: FC<HubProvidersListProps> = ({
|
||||
return (
|
||||
<div className="rounded-xl border border-border bg-card p-6 shadow-sm">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h3 className="font-medium">Configured Providers</h3>
|
||||
<h3 className="font-medium">Configured AI Providers</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -57,7 +57,7 @@ export const HubProvidersList: FC<HubProvidersListProps> = ({
|
||||
return (
|
||||
<div className="rounded-xl border border-border bg-card p-6 shadow-sm">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h3 className="font-medium">Configured Providers</h3>
|
||||
<h3 className="font-medium">Configured AI Providers</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export {
|
||||
DEFAULT_PROVIDERS,
|
||||
getFaviconUrl,
|
||||
type LlmHubProvider,
|
||||
} from '@/lib/llm-hub/storage'
|
||||
|
||||
@@ -6,6 +6,7 @@ const EnvSchema = z.object({
|
||||
VITE_PUBLIC_POSTHOG_HOST: z.string().optional(),
|
||||
VITE_PUBLIC_SENTRY_DSN: z.string().optional(),
|
||||
VITE_PUBLIC_BROWSEROS_API: z.string().optional(),
|
||||
VITE_PUBLIC_KIMI_LAUNCH: z.string().optional(),
|
||||
PROD: z.boolean(),
|
||||
})
|
||||
|
||||
|
||||
14
apps/agent/lib/feature-flags/kimi-launch.ts
Normal file
14
apps/agent/lib/feature-flags/kimi-launch.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { env } from '@/lib/env'
|
||||
|
||||
const ENABLED_VALUES = new Set(['1', 'true', 'yes', 'on'])
|
||||
|
||||
function parseKimiLaunchFlag(value: string | undefined): boolean {
|
||||
if (!value) return false
|
||||
return ENABLED_VALUES.has(value.trim().toLowerCase())
|
||||
}
|
||||
|
||||
const kimiLaunchEnabled = parseKimiLaunchFlag(env.VITE_PUBLIC_KIMI_LAUNCH)
|
||||
|
||||
export function isKimiLaunchEnabled(): boolean {
|
||||
return kimiLaunchEnabled
|
||||
}
|
||||
5
apps/agent/lib/feature-flags/useKimiLaunch.ts
Normal file
5
apps/agent/lib/feature-flags/useKimiLaunch.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { isKimiLaunchEnabled } from './kimi-launch'
|
||||
|
||||
export function useKimiLaunch(): boolean {
|
||||
return isKimiLaunchEnabled()
|
||||
}
|
||||
@@ -7,13 +7,17 @@ export interface LlmHubProvider {
|
||||
url: string
|
||||
}
|
||||
|
||||
export const DEFAULT_PROVIDERS: LlmHubProvider[] = [
|
||||
{ name: 'ChatGPT', url: 'https://chatgpt.com' },
|
||||
{ name: 'Claude', url: 'https://claude.ai' },
|
||||
{ name: 'Grok', url: 'https://grok.com' },
|
||||
{ name: 'Gemini', url: 'https://gemini.google.com' },
|
||||
{ name: 'Perplexity', url: 'https://www.perplexity.ai' },
|
||||
]
|
||||
const KIMI_PROVIDER: LlmHubProvider = {
|
||||
name: 'Kimi',
|
||||
url: 'https://www.kimi.com',
|
||||
}
|
||||
|
||||
function ensureKimiFirst(providers: LlmHubProvider[]): LlmHubProvider[] {
|
||||
const hasKimi = providers.some(
|
||||
(p) => p.name === 'Kimi' || p.url.includes('kimi.com'),
|
||||
)
|
||||
return hasKimi ? providers : [KIMI_PROVIDER, ...providers]
|
||||
}
|
||||
|
||||
export async function loadProviders(): Promise<LlmHubProvider[]> {
|
||||
try {
|
||||
@@ -24,12 +28,12 @@ export async function loadProviders(): Promise<LlmHubProvider[]> {
|
||||
const providers = (providersPref?.value as LlmHubProvider[]) || []
|
||||
|
||||
if (providers.length === 0) {
|
||||
return DEFAULT_PROVIDERS
|
||||
return [KIMI_PROVIDER]
|
||||
}
|
||||
|
||||
return providers
|
||||
return ensureKimiFirst(providers)
|
||||
} catch {
|
||||
return DEFAULT_PROVIDERS
|
||||
return [KIMI_PROVIDER]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
DEFAULT_PROVIDERS,
|
||||
type LlmHubProvider,
|
||||
loadProviders,
|
||||
saveProviders,
|
||||
} from './storage'
|
||||
import { type LlmHubProvider, loadProviders, saveProviders } from './storage'
|
||||
|
||||
/** @public */
|
||||
export interface UseLlmHubProvidersReturn {
|
||||
@@ -26,7 +21,7 @@ export function useLlmHubProviders(): UseLlmHubProvidersReturn {
|
||||
const data = await loadProviders()
|
||||
setProviders(data)
|
||||
} catch {
|
||||
setProviders(DEFAULT_PROVIDERS)
|
||||
setProviders([])
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
Azure,
|
||||
Bedrock,
|
||||
Gemini,
|
||||
Kimi,
|
||||
LmStudio,
|
||||
Ollama,
|
||||
OpenAI,
|
||||
@@ -30,6 +31,7 @@ const providerIconMap: Record<ProviderType, IconComponent | null> = {
|
||||
lmstudio: LmStudio,
|
||||
bedrock: Bedrock,
|
||||
browseros: null,
|
||||
moonshot: Kimi,
|
||||
}
|
||||
|
||||
interface ProviderIconProps {
|
||||
|
||||
@@ -20,6 +20,16 @@ export interface ProviderTemplate {
|
||||
* @public
|
||||
*/
|
||||
export const providerTemplates: ProviderTemplate[] = [
|
||||
{
|
||||
id: 'moonshot',
|
||||
name: 'Moonshot AI',
|
||||
defaultBaseUrl: 'https://api.moonshot.ai/v1',
|
||||
defaultModelId: 'kimi-k2.5',
|
||||
supportsImages: true,
|
||||
contextWindow: 128000,
|
||||
apiKeyUrl: 'https://platform.moonshot.ai/console/api-keys',
|
||||
setupGuideUrl: 'https://platform.moonshot.ai/console/api-keys',
|
||||
},
|
||||
{
|
||||
id: 'openai',
|
||||
name: 'OpenAI',
|
||||
@@ -119,6 +129,7 @@ export const providerTemplates: ProviderTemplate[] = [
|
||||
* @public
|
||||
*/
|
||||
export const providerTypeOptions: { value: ProviderType; label: string }[] = [
|
||||
{ value: 'moonshot', label: 'Moonshot AI' },
|
||||
{ value: 'anthropic', label: 'Anthropic' },
|
||||
{ value: 'openai', label: 'OpenAI' },
|
||||
{ value: 'openai-compatible', label: 'OpenAI Compatible' },
|
||||
@@ -146,6 +157,7 @@ export const getProviderTemplate = (
|
||||
* Auto-fills when user selects a provider type
|
||||
*/
|
||||
export const DEFAULT_BASE_URLS: Record<ProviderType, string> = {
|
||||
moonshot: 'https://api.moonshot.ai/v1',
|
||||
anthropic: 'https://api.anthropic.com/v1',
|
||||
openai: 'https://api.openai.com/v1',
|
||||
'openai-compatible': '',
|
||||
|
||||
@@ -13,6 +13,7 @@ export type ProviderType =
|
||||
| 'lmstudio'
|
||||
| 'bedrock'
|
||||
| 'browseros'
|
||||
| 'moonshot'
|
||||
|
||||
/**
|
||||
* LLM Provider configuration
|
||||
|
||||
@@ -160,6 +160,18 @@ function createOpenAICompatibleFactory(
|
||||
})
|
||||
}
|
||||
|
||||
function createMoonshotFactory(
|
||||
config: VercelAIConfig,
|
||||
): (modelId: string) => unknown {
|
||||
if (!config.baseUrl) throw new Error('Moonshot provider requires baseUrl')
|
||||
if (!config.apiKey) throw new Error('Moonshot provider requires apiKey')
|
||||
return createOpenAICompatible({
|
||||
name: 'moonshot',
|
||||
baseURL: config.baseUrl,
|
||||
apiKey: config.apiKey,
|
||||
})
|
||||
}
|
||||
|
||||
const PROVIDER_FACTORIES: Record<string, ProviderFactory> = {
|
||||
[AIProvider.ANTHROPIC]: createAnthropicFactory,
|
||||
[AIProvider.OPENAI]: createOpenAIFactory,
|
||||
@@ -171,6 +183,7 @@ const PROVIDER_FACTORIES: Record<string, ProviderFactory> = {
|
||||
[AIProvider.BEDROCK]: createBedrockFactory,
|
||||
[AIProvider.BROWSEROS]: createBrowserOSFactory,
|
||||
[AIProvider.OPENAI_COMPATIBLE]: createOpenAICompatibleFactory,
|
||||
[AIProvider.MOONSHOT]: createMoonshotFactory,
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -214,6 +214,7 @@ export enum AIProvider {
|
||||
BEDROCK = 'bedrock',
|
||||
BROWSEROS = 'browseros',
|
||||
OPENAI_COMPATIBLE = 'openai-compatible',
|
||||
MOONSHOT = 'moonshot',
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -136,6 +136,18 @@ function createOpenAICompatibleFactory(
|
||||
})
|
||||
}
|
||||
|
||||
function createMoonshotFactory(
|
||||
config: ResolvedAgentConfig,
|
||||
): (modelId: string) => unknown {
|
||||
if (!config.baseUrl) throw new Error('Moonshot provider requires baseUrl')
|
||||
if (!config.apiKey) throw new Error('Moonshot provider requires apiKey')
|
||||
return createOpenAICompatible({
|
||||
name: 'moonshot',
|
||||
baseURL: config.baseUrl,
|
||||
apiKey: config.apiKey,
|
||||
})
|
||||
}
|
||||
|
||||
const PROVIDER_FACTORIES: Record<string, ProviderFactory> = {
|
||||
[LLM_PROVIDERS.ANTHROPIC]: createAnthropicFactory,
|
||||
[LLM_PROVIDERS.OPENAI]: createOpenAIFactory,
|
||||
@@ -147,6 +159,7 @@ const PROVIDER_FACTORIES: Record<string, ProviderFactory> = {
|
||||
[LLM_PROVIDERS.BEDROCK]: createBedrockFactory,
|
||||
[LLM_PROVIDERS.BROWSEROS]: createBrowserOSFactory,
|
||||
[LLM_PROVIDERS.OPENAI_COMPATIBLE]: createOpenAICompatibleFactory,
|
||||
[LLM_PROVIDERS.MOONSHOT]: createMoonshotFactory,
|
||||
}
|
||||
|
||||
export function createLanguageModel(
|
||||
|
||||
@@ -124,6 +124,16 @@ function createOpenAICompatibleModel(config: ResolvedLLMConfig): LanguageModel {
|
||||
})(config.model)
|
||||
}
|
||||
|
||||
function createMoonshotModel(config: ResolvedLLMConfig): LanguageModel {
|
||||
if (!config.baseUrl) throw new Error('Moonshot provider requires baseUrl')
|
||||
if (!config.apiKey) throw new Error('Moonshot provider requires apiKey')
|
||||
return createOpenAICompatible({
|
||||
name: 'moonshot',
|
||||
baseURL: config.baseUrl,
|
||||
apiKey: config.apiKey,
|
||||
})(config.model)
|
||||
}
|
||||
|
||||
const PROVIDER_FACTORIES: Record<string, ProviderFactory> = {
|
||||
[LLM_PROVIDERS.ANTHROPIC]: createAnthropicModel,
|
||||
[LLM_PROVIDERS.OPENAI]: createOpenAIModel,
|
||||
@@ -135,6 +145,7 @@ const PROVIDER_FACTORIES: Record<string, ProviderFactory> = {
|
||||
[LLM_PROVIDERS.BEDROCK]: createBedrockModel,
|
||||
[LLM_PROVIDERS.BROWSEROS]: createBrowserOSModel,
|
||||
[LLM_PROVIDERS.OPENAI_COMPATIBLE]: createOpenAICompatibleModel,
|
||||
[LLM_PROVIDERS.MOONSHOT]: createMoonshotModel,
|
||||
}
|
||||
|
||||
export function createLLMProvider(config: ResolvedLLMConfig): LanguageModel {
|
||||
|
||||
@@ -23,6 +23,7 @@ export const LLM_PROVIDERS = {
|
||||
BEDROCK: 'bedrock',
|
||||
BROWSEROS: 'browseros',
|
||||
OPENAI_COMPATIBLE: 'openai-compatible',
|
||||
MOONSHOT: 'moonshot',
|
||||
} as const
|
||||
|
||||
/**
|
||||
@@ -40,6 +41,7 @@ export const LLMProviderSchema: z.ZodEnum<
|
||||
'bedrock',
|
||||
'browseros',
|
||||
'openai-compatible',
|
||||
'moonshot',
|
||||
]
|
||||
> = z.enum([
|
||||
LLM_PROVIDERS.ANTHROPIC,
|
||||
@@ -52,6 +54,7 @@ export const LLMProviderSchema: z.ZodEnum<
|
||||
LLM_PROVIDERS.BEDROCK,
|
||||
LLM_PROVIDERS.BROWSEROS,
|
||||
LLM_PROVIDERS.OPENAI_COMPATIBLE,
|
||||
LLM_PROVIDERS.MOONSHOT,
|
||||
])
|
||||
|
||||
export type LLMProvider = z.infer<typeof LLMProviderSchema>
|
||||
|
||||
Reference in New Issue
Block a user