feat: gate Moonshot AI provider behind Kimi launch flag (#432)

* feat: gate Moonshot AI provider behind VITE_PUBLIC_KIMI_LAUNCH flag

Hide all Moonshot/Kimi provider UI when the launch flag is off:
- Filter moonshot from provider templates and type dropdown
- Gate Kimi flare badges in HubProviderRow
- Gate Kimi auto-insertion in LLM hub storage
- Add analytics events for Kimi API key configuration and guide clicks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: allow editing existing moonshot providers when launch flag is off

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nikhil
2026-03-06 14:21:34 -08:00
committed by GitHub
parent dafad1dd14
commit db3d38ae3c
5 changed files with 35 additions and 4 deletions

View File

@@ -33,7 +33,12 @@ import {
import { Feature } from '@/lib/browseros/capabilities'
import { useAgentServerUrl } from '@/lib/browseros/useBrowserOSProviders'
import { useCapabilities } from '@/lib/browseros/useCapabilities'
import { AI_PROVIDER_ADDED_EVENT } from '@/lib/constants/analyticsEvents'
import {
AI_PROVIDER_ADDED_EVENT,
KIMI_API_KEY_CONFIGURED_EVENT,
KIMI_API_KEY_GUIDE_CLICKED_EVENT,
} from '@/lib/constants/analyticsEvents'
import { useKimiLaunch } from '@/lib/feature-flags/useKimiLaunch'
import {
getDefaultBaseUrlForProviders,
getProviderTemplate,
@@ -174,8 +179,11 @@ export const NewProviderDialog: FC<NewProviderDialogProps> = ({
const [testResult, setTestResult] = useState<TestResult | null>(null)
const { supports } = useCapabilities()
const { baseUrl: agentServerUrl } = useAgentServerUrl()
const kimiLaunch = useKimiLaunch()
const filteredProviderTypeOptions = providerTypeOptions.filter((opt) => {
if (opt.value === 'moonshot')
return kimiLaunch || initialValues?.type === 'moonshot'
if (opt.value === 'openai-compatible') {
return supports(Feature.OPENAI_COMPATIBLE_SUPPORT)
}
@@ -341,6 +349,12 @@ export const NewProviderDialog: FC<NewProviderDialogProps> = ({
model: values.modelId,
})
}
if (values.type === 'moonshot') {
track(KIMI_API_KEY_CONFIGURED_EVENT, {
model: values.modelId,
is_new: isNewProvider,
})
}
form.reset()
onOpenChange(false)
}
@@ -423,6 +437,9 @@ export const NewProviderDialog: FC<NewProviderDialogProps> = ({
const handleSetupGuideClick = (e: React.MouseEvent) => {
e.preventDefault()
if (watchedType === 'moonshot') {
track(KIMI_API_KEY_GUIDE_CLICKED_EVENT)
}
if (setupGuideUrl) chrome.tabs.create({ url: setupGuideUrl })
}

View File

@@ -7,6 +7,7 @@ import {
} from '@/components/ui/collapsible'
import { Feature } from '@/lib/browseros/capabilities'
import { useCapabilities } from '@/lib/browseros/useCapabilities'
import { useKimiLaunch } from '@/lib/feature-flags/useKimiLaunch'
import {
type ProviderTemplate,
providerTemplates,
@@ -22,8 +23,10 @@ export const ProviderTemplatesSection: FC<ProviderTemplatesSectionProps> = ({
onUseTemplate,
}) => {
const { supports } = useCapabilities()
const kimiLaunch = useKimiLaunch()
const filteredTemplates = providerTemplates.filter((template) => {
if (template.id === 'moonshot') return kimiLaunch
if (template.id === 'openai-compatible') {
return supports(Feature.OPENAI_COMPATIBLE_SUPPORT)
}

View File

@@ -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 { useKimiLaunch } from '@/lib/feature-flags/useKimiLaunch'
import { cn } from '@/lib/utils'
import { getFaviconUrl, type LlmHubProvider } from './models'
@@ -19,10 +20,11 @@ export const HubProviderRow: FC<HubProviderRowProps> = ({
onDelete,
}) => {
const iconUrl = useMemo(() => getFaviconUrl(provider.url), [provider.url])
const kimiLaunch = useKimiLaunch()
const normalizedName = provider.name.trim().toLowerCase()
const normalizedUrl = provider.url.trim().toLowerCase()
const isKimi = normalizedName === 'kimi' || normalizedUrl.includes('kimi.com')
const showKimiFlare = isKimi
const showKimiFlare = isKimi && kimiLaunch
return (
<div

View File

@@ -206,3 +206,10 @@ export const ONBOARDING_FEATURE_CLICKED_EVENT = 'onboarding.feature.clicked'
/** @public */
export const ONBOARDING_COMPLETED_EVENT = 'onboarding.completed'
/** @public */
export const KIMI_API_KEY_CONFIGURED_EVENT = 'settings.kimi.api_key_configured'
/** @public */
export const KIMI_API_KEY_GUIDE_CLICKED_EVENT =
'settings.kimi.api_key_guide_clicked'

View File

@@ -1,5 +1,6 @@
import { getBrowserOSAdapter } from '@/lib/browseros/adapter'
import { BROWSEROS_PREFS } from '@/lib/browseros/prefs'
import { isKimiLaunchEnabled } from '@/lib/feature-flags/kimi-launch'
/** @public */
export interface LlmHubProvider {
@@ -13,6 +14,7 @@ const KIMI_PROVIDER: LlmHubProvider = {
}
function ensureKimiFirst(providers: LlmHubProvider[]): LlmHubProvider[] {
if (!isKimiLaunchEnabled()) return providers
const hasKimi = providers.some(
(p) => p.name === 'Kimi' || p.url.includes('kimi.com'),
)
@@ -28,12 +30,12 @@ export async function loadProviders(): Promise<LlmHubProvider[]> {
const providers = (providersPref?.value as LlmHubProvider[]) || []
if (providers.length === 0) {
return [KIMI_PROVIDER]
return isKimiLaunchEnabled() ? [KIMI_PROVIDER] : []
}
return ensureKimiFirst(providers)
} catch {
return [KIMI_PROVIDER]
return isKimiLaunchEnabled() ? [KIMI_PROVIDER] : []
}
}