Compare commits

..

2 Commits

Author SHA1 Message Date
Jessica Singh
8b9a6301e7 fix(fe): lift fallback icon to module-level constant 2026-03-19 15:05:54 -07:00
Jessica Singh
1a4fb6f1a1 refactor(fe): migrate voice admin page to opal components 2026-03-19 14:53:06 -07:00
16 changed files with 147 additions and 427 deletions

View File

@@ -1,16 +1,16 @@
"use client";
import Image from "next/image";
import { useMemo, useState } from "react";
import { AdminPageTitle } from "@/components/admin/Title";
import {
AzureIcon,
ElevenLabsIcon,
InfoIcon,
IconProps,
OpenAIIcon,
} from "@/components/icons/icons";
import Text from "@/refresh-components/texts/Text";
import Separator from "@/refresh-components/Separator";
import { Select } from "@/refresh-components/cards";
import Message from "@/refresh-components/messages/Message";
import * as SettingsLayouts from "@/layouts/settings-layouts";
import { FetchError } from "@/lib/fetcher";
import {
useVoiceProviders,
@@ -22,32 +22,21 @@ import {
} from "@/lib/admin/voice/svc";
import { ThreeDotsLoader } from "@/components/Loading";
import { Callout } from "@/components/ui/callout";
import Button from "@/refresh-components/buttons/Button";
import { Button as OpalButton } from "@opal/components";
import { cn } from "@/lib/utils";
import {
SvgArrowExchange,
SvgArrowRightCircle,
SvgAudio,
SvgCheckSquare,
SvgEdit,
SvgMicrophone,
SvgX,
} from "@opal/icons";
import { Content } from "@opal/layouts";
import { SvgMicrophone } from "@opal/icons";
import { ADMIN_ROUTES } from "@/lib/admin-routes";
import VoiceProviderSetupModal from "./VoiceProviderSetupModal";
interface ModelDetails {
id: string;
label: string;
subtitle: string;
logoSrc?: string;
providerType: string;
}
interface ProviderGroup {
providerType: string;
providerLabel: string;
logoSrc?: string;
models: ModelDetails[];
}
@@ -57,21 +46,18 @@ const STT_MODELS: ModelDetails[] = [
id: "whisper",
label: "Whisper",
subtitle: "OpenAI's general purpose speech recognition model.",
logoSrc: "/Openai.svg",
providerType: "openai",
},
{
id: "azure-speech-stt",
label: "Azure Speech",
subtitle: "Speech to text in Microsoft Foundry Tools.",
logoSrc: "/Azure.png",
providerType: "azure",
},
{
id: "elevenlabs-stt",
label: "ElevenAPI",
subtitle: "ElevenLabs Speech to Text API.",
logoSrc: "/ElevenLabs.svg",
providerType: "elevenlabs",
},
];
@@ -81,20 +67,17 @@ const TTS_PROVIDER_GROUPS: ProviderGroup[] = [
{
providerType: "openai",
providerLabel: "OpenAI",
logoSrc: "/Openai.svg",
models: [
{
id: "tts-1",
label: "TTS-1",
subtitle: "OpenAI's text-to-speech model optimized for speed.",
logoSrc: "/Openai.svg",
providerType: "openai",
},
{
id: "tts-1-hd",
label: "TTS-1 HD",
subtitle: "OpenAI's text-to-speech model optimized for quality.",
logoSrc: "/Openai.svg",
providerType: "openai",
},
],
@@ -102,13 +85,11 @@ const TTS_PROVIDER_GROUPS: ProviderGroup[] = [
{
providerType: "azure",
providerLabel: "Azure",
logoSrc: "/Azure.png",
models: [
{
id: "azure-speech-tts",
label: "Azure Speech",
subtitle: "Text to speech in Microsoft Foundry Tools.",
logoSrc: "/Azure.png",
providerType: "azure",
},
],
@@ -116,44 +97,42 @@ const TTS_PROVIDER_GROUPS: ProviderGroup[] = [
{
providerType: "elevenlabs",
providerLabel: "ElevenLabs",
logoSrc: "/ElevenLabs.svg",
models: [
{
id: "elevenlabs-tts",
label: "ElevenAPI",
subtitle: "ElevenLabs Text to Speech API.",
logoSrc: "/ElevenLabs.svg",
providerType: "elevenlabs",
},
],
},
];
interface HoverIconButtonProps extends React.ComponentProps<typeof Button> {
isHovered: boolean;
onMouseEnter: () => void;
onMouseLeave: () => void;
children: React.ReactNode;
}
const FallbackMicrophoneIcon = ({ size, className }: IconProps) => (
<SvgMicrophone size={size} className={className} />
);
function HoverIconButton({
isHovered,
onMouseEnter,
onMouseLeave,
children,
...buttonProps
}: HoverIconButtonProps) {
return (
<div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
<Button {...buttonProps} rightIcon={isHovered ? SvgX : SvgCheckSquare}>
{children}
</Button>
</div>
);
function getProviderIcon(
providerType: string
): React.FunctionComponent<IconProps> {
switch (providerType) {
case "openai":
return OpenAIIcon;
case "azure":
return AzureIcon;
case "elevenlabs":
return ElevenLabsIcon;
default:
return FallbackMicrophoneIcon;
}
}
type ProviderMode = "stt" | "tts";
const route = ADMIN_ROUTES.VOICE;
const pageDescription =
"Configure speech-to-text and text-to-speech providers for voice input and spoken responses.";
export default function VoiceConfigurationPage() {
const [modalOpen, setModalOpen] = useState(false);
const [selectedProvider, setSelectedProvider] = useState<string | null>(null);
@@ -167,7 +146,6 @@ export default function VoiceConfigurationPage() {
const [ttsActivationError, setTTSActivationError] = useState<string | null>(
null
);
const [hoveredButtonKey, setHoveredButtonKey] = useState<string | null>(null);
const { providers, error, isLoading, refresh: mutate } = useVoiceProviders();
@@ -261,7 +239,6 @@ export default function VoiceConfigurationPage() {
return !!provider?.has_api_key;
};
// Map provider types to their configured provider data
const providersByType = useMemo(() => {
return new Map((providers ?? []).map((p) => [p.provider_type, p] as const));
}, [providers]);
@@ -271,186 +248,46 @@ export default function VoiceConfigurationPage() {
const hasActiveTTSProvider =
providers?.some((p) => p.is_default_tts) ?? false;
const renderLogo = ({
logoSrc,
providerType,
alt,
size = 16,
}: {
logoSrc?: string;
providerType: string;
alt: string;
size?: number;
}) => {
const containerSizeClass = size === 24 ? "size-7" : "size-5";
return (
<div
className={cn(
"flex items-center justify-center px-0.5 py-0 shrink-0 overflow-clip",
containerSizeClass
)}
>
{providerType === "openai" ? (
<OpenAIIcon size={size} />
) : providerType === "azure" ? (
<AzureIcon size={size} />
) : providerType === "elevenlabs" ? (
<ElevenLabsIcon size={size} />
) : logoSrc ? (
<Image
src={logoSrc}
alt={alt}
width={size}
height={size}
className="object-contain"
/>
) : (
<SvgMicrophone size={size} className="text-text-02" />
)}
</div>
);
};
const renderModelCard = ({
model,
mode,
}: {
model: ModelDetails;
mode: ProviderMode;
}) => {
const getModelStatus = (
model: ModelDetails,
mode: ProviderMode
): "disconnected" | "connected" | "selected" => {
const provider = providersByType.get(model.providerType);
const isConfigured = isProviderConfigured(provider);
// For TTS, also check that this specific model is the default (not just the provider)
if (!provider || !isProviderConfigured(provider)) return "disconnected";
const isActive =
mode === "stt"
? provider?.is_default_stt
: provider?.is_default_tts && provider?.tts_model === model.id;
const isHighlighted = isActive ?? false;
const providerId = provider?.id;
? provider.is_default_stt
: provider.is_default_tts && provider.tts_model === model.id;
const buttonState = (() => {
if (!provider || !isConfigured) {
return {
label: "Connect",
disabled: false,
icon: "arrow" as const,
onClick: () => handleConnect(model.providerType, mode, model.id),
};
}
if (isActive) return "selected";
return "connected";
};
if (isActive) {
return {
label: "Current Default",
disabled: false,
icon: "check" as const,
onClick: providerId
? () => handleDeactivate(providerId, mode)
: undefined,
};
}
return {
label: "Set as Default",
disabled: false,
icon: "arrow-circle" as const,
onClick: providerId
? () => handleSetDefault(providerId, mode, model.id)
: undefined,
};
})();
const buttonKey = `${mode}-${model.id}`;
const isButtonHovered = hoveredButtonKey === buttonKey;
const isCardClickable =
buttonState.icon === "arrow" &&
typeof buttonState.onClick === "function" &&
!buttonState.disabled;
const handleCardClick = () => {
if (isCardClickable) {
buttonState.onClick?.();
}
};
const renderModelSelect = (model: ModelDetails, mode: ProviderMode) => {
const provider = providersByType.get(model.providerType);
const status = getModelStatus(model, mode);
const Icon = getProviderIcon(model.providerType);
return (
<div
<Select
key={`${mode}-${model.id}`}
onClick={isCardClickable ? handleCardClick : undefined}
className={cn(
"flex items-start justify-between gap-4 rounded-16 border p-2 bg-background-neutral-01",
isHighlighted ? "border-action-link-05" : "border-border-01",
isCardClickable &&
"cursor-pointer hover:bg-background-tint-01 transition-colors"
)}
>
<div className="flex flex-1 items-start gap-2.5 p-2">
{renderLogo({
logoSrc: model.logoSrc,
providerType: model.providerType,
alt: `${model.label} logo`,
size: 16,
})}
<div className="flex flex-col gap-0.5">
<Text as="p" mainUiAction text04>
{model.label}
</Text>
<Text as="p" secondaryBody text03>
{model.subtitle}
</Text>
</div>
</div>
<div className="flex items-center justify-end gap-1.5 self-center">
{isConfigured && (
<OpalButton
icon={SvgEdit}
tooltip="Edit"
prominence="tertiary"
size="sm"
onClick={(e) => {
e.stopPropagation();
if (provider) handleEdit(provider, mode, model.id);
}}
aria-label={`Edit ${model.label}`}
/>
)}
{buttonState.icon === "check" ? (
<HoverIconButton
isHovered={isButtonHovered}
onMouseEnter={() => setHoveredButtonKey(buttonKey)}
onMouseLeave={() => setHoveredButtonKey(null)}
action={true}
tertiary
disabled={buttonState.disabled}
onClick={(e) => {
e.stopPropagation();
buttonState.onClick?.();
}}
>
{buttonState.label}
</HoverIconButton>
) : (
<Button
action={false}
tertiary
disabled={buttonState.disabled || !buttonState.onClick}
onClick={(e) => {
e.stopPropagation();
buttonState.onClick?.();
}}
rightIcon={
buttonState.icon === "arrow"
? SvgArrowExchange
: buttonState.icon === "arrow-circle"
? SvgArrowRightCircle
: undefined
}
>
{buttonState.label}
</Button>
)}
</div>
</div>
aria-label={`voice-${mode}-${model.id}`}
icon={Icon}
title={model.label}
description={model.subtitle}
status={status}
onConnect={() => handleConnect(model.providerType, mode, model.id)}
onSelect={() => {
if (provider?.id) handleSetDefault(provider.id, mode, model.id);
}}
onDeselect={() => {
if (provider?.id) handleDeactivate(provider.id, mode);
}}
onEdit={() => {
if (provider) handleEdit(provider, mode, model.id);
}}
/>
);
};
@@ -462,61 +299,56 @@ export default function VoiceConfigurationPage() {
: undefined;
return (
<>
<AdminPageTitle
title="Voice"
icon={SvgMicrophone}
includeDivider={false}
<SettingsLayouts.Root>
<SettingsLayouts.Header
icon={route.icon}
title={route.title}
description={pageDescription}
/>
<Callout type="danger" title="Failed to load voice settings">
{message}
{detail && (
<Text as="p" className="mt-2 text-text-03" mainContentBody text03>
{detail}
</Text>
)}
</Callout>
</>
<SettingsLayouts.Body>
<Callout type="danger" title="Failed to load voice settings">
{message}
{detail && (
<Text as="p" mainContentBody text03>
{detail}
</Text>
)}
</Callout>
</SettingsLayouts.Body>
</SettingsLayouts.Root>
);
}
if (isLoading) {
return (
<>
<AdminPageTitle
title="Voice"
icon={SvgMicrophone}
includeDivider={false}
<SettingsLayouts.Root>
<SettingsLayouts.Header
icon={route.icon}
title={route.title}
description={pageDescription}
/>
<div className="mt-8">
<SettingsLayouts.Body>
<ThreeDotsLoader />
</div>
</>
</SettingsLayouts.Body>
</SettingsLayouts.Root>
);
}
return (
<>
<AdminPageTitle icon={SvgAudio} title="Voice" />
<div className="pt-4 pb-4">
<Text as="p" secondaryBody text03>
Speech to text (STT) and text to speech (TTS) capabilities.
</Text>
</div>
<Separator />
<div className="flex w-full flex-col gap-8 pb-6">
{/* Speech-to-Text Section */}
<div className="flex w-full max-w-[960px] flex-col gap-3">
<div className="flex flex-col">
<Text as="p" mainContentEmphasis text04>
Speech to Text
</Text>
<Text as="p" secondaryBody text03>
Select a model to transcribe speech to text in chats.
</Text>
</div>
<SettingsLayouts.Root>
<SettingsLayouts.Header
icon={route.icon}
title={route.title}
description={pageDescription}
/>
<SettingsLayouts.Body>
<div className="flex flex-col gap-6">
<Content
title="Speech to Text"
description="Select a model to transcribe speech to text in chats."
sizePreset="main-content"
variant="section"
/>
{sttActivationError && (
<Callout type="danger" title="Unable to update STT provider">
@@ -525,46 +357,28 @@ export default function VoiceConfigurationPage() {
)}
{!hasActiveSTTProvider && (
<div
className="flex items-start rounded-16 border p-2"
style={{
backgroundColor: "var(--status-info-00)",
borderColor: "var(--status-info-02)",
}}
>
<div className="flex items-start gap-1 p-2">
<div
className="flex size-5 items-center justify-center rounded-full p-0.5"
style={{
backgroundColor: "var(--status-info-01)",
}}
>
<div style={{ color: "var(--status-text-info-05)" }}>
<InfoIcon size={16} />
</div>
</div>
<Text as="p" className="flex-1 px-0.5" mainUiBody text04>
Connect a speech to text provider to use in chat.
</Text>
</div>
</div>
<Message
info
static
large
close={false}
text="Connect a speech to text provider to use in chat."
className="w-full"
/>
)}
<div className="flex flex-col gap-2">
{STT_MODELS.map((model) => renderModelCard({ model, mode: "stt" }))}
{STT_MODELS.map((model) => renderModelSelect(model, "stt"))}
</div>
</div>
{/* Text-to-Speech Section */}
<div className="flex w-full max-w-[960px] flex-col gap-3">
<div className="flex flex-col">
<Text as="p" mainContentEmphasis text04>
Text to Speech
</Text>
<Text as="p" secondaryBody text03>
Select a model to speak out chat responses.
</Text>
</div>
<div className="flex flex-col gap-6">
<Content
title="Text to Speech"
description="Select a model to speak out chat responses."
sizePreset="main-content"
variant="section"
/>
{ttsActivationError && (
<Callout type="danger" title="Unable to update TTS provider">
@@ -573,47 +387,28 @@ export default function VoiceConfigurationPage() {
)}
{!hasActiveTTSProvider && (
<div
className="flex items-start rounded-16 border p-2"
style={{
backgroundColor: "var(--status-info-00)",
borderColor: "var(--status-info-02)",
}}
>
<div className="flex items-start gap-1 p-2">
<div
className="flex size-5 items-center justify-center rounded-full p-0.5"
style={{
backgroundColor: "var(--status-info-01)",
}}
>
<div style={{ color: "var(--status-text-info-05)" }}>
<InfoIcon size={16} />
</div>
</div>
<Text as="p" className="flex-1 px-0.5" mainUiBody text04>
Connect a text to speech provider to use in chat.
</Text>
</div>
</div>
<Message
info
static
large
close={false}
text="Connect a text to speech provider to use in chat."
className="w-full"
/>
)}
<div className="flex flex-col gap-4">
{TTS_PROVIDER_GROUPS.map((group) => (
<div key={group.providerType} className="flex flex-col gap-2">
<Text as="p" secondaryBody text03 className="px-0.5">
{group.providerLabel}
</Text>
<div className="flex flex-col gap-2">
{group.models.map((model) =>
renderModelCard({ model, mode: "tts" })
)}
</div>
{TTS_PROVIDER_GROUPS.map((group) => (
<div key={group.providerType} className="flex flex-col gap-2">
<Text secondaryBody text03>
{group.providerLabel}
</Text>
<div className="flex flex-col gap-2">
{group.models.map((model) => renderModelSelect(model, "tts"))}
</div>
))}
</div>
</div>
))}
</div>
</div>
</SettingsLayouts.Body>
{modalOpen && selectedProvider && (
<VoiceProviderSetupModal
@@ -625,6 +420,6 @@ export default function VoiceConfigurationPage() {
onSuccess={handleModalSuccess}
/>
)}
</>
</SettingsLayouts.Root>
);
}

View File

@@ -45,6 +45,7 @@ const SETTINGS_LAYOUT_PREFIXES = [
ADMIN_ROUTES.GROUPS.path,
ADMIN_ROUTES.PERFORMANCE.path,
ADMIN_ROUTES.SCIM.path,
ADMIN_ROUTES.VOICE.path,
];
export function ClientLayout({ children, enableCloud }: ClientLayoutProps) {

View File

@@ -123,9 +123,6 @@ export interface LLMProviderFormProps {
open?: boolean;
onOpenChange?: (open: boolean) => void;
/** The current default model name for this provider (from the global default). */
defaultModelName?: string;
// Onboarding-specific (only when variant === "onboarding")
onboardingState?: OnboardingState;
onboardingActions?: OnboardingActions;

View File

@@ -148,14 +148,12 @@ interface ExistingProviderCardProps {
provider: LLMProviderView;
isDefault: boolean;
isLastProvider: boolean;
defaultModelName?: string;
}
function ExistingProviderCard({
provider,
isDefault,
isLastProvider,
defaultModelName,
}: ExistingProviderCardProps) {
const { mutate } = useSWRConfig();
const [isOpen, setIsOpen] = useState(false);
@@ -232,12 +230,7 @@ function ExistingProviderCard({
</Section>
}
/>
{getModalForExistingProvider(
provider,
isOpen,
setIsOpen,
defaultModelName
)}
{getModalForExistingProvider(provider, isOpen, setIsOpen)}
</Card>
</Hoverable.Root>
</>
@@ -453,11 +446,6 @@ export default function LLMConfigurationPage() {
provider={provider}
isDefault={defaultText?.provider_id === provider.id}
isLastProvider={sortedProviders.length === 1}
defaultModelName={
defaultText?.provider_id === provider.id
? defaultText.model_name
: undefined
}
/>
))}
</div>

View File

@@ -35,7 +35,6 @@ export default function AnthropicModal({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
@@ -65,15 +64,10 @@ export default function AnthropicModal({
default_model_name: DEFAULT_DEFAULT_MODEL_NAME,
}
: {
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
api_key: existingLlmProvider?.api_key ?? "",
api_base: existingLlmProvider?.api_base ?? undefined,
default_model_name:
defaultModelName ??
wellKnownLLMProvider?.recommended_default_model?.name ??
DEFAULT_DEFAULT_MODEL_NAME,
is_auto_mode: existingLlmProvider?.is_auto_mode ?? true,

View File

@@ -81,7 +81,6 @@ export default function AzureModal({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
@@ -110,11 +109,7 @@ export default function AzureModal({
default_model_name: "",
} as AzureModalValues)
: {
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
api_key: existingLlmProvider?.api_key ?? "",
target_uri: buildTargetUri(existingLlmProvider),
};

View File

@@ -315,7 +315,6 @@ export default function BedrockModal({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
@@ -352,11 +351,7 @@ export default function BedrockModal({
},
} as BedrockModalValues)
: {
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
custom_config: {
AWS_REGION_NAME:
(existingLlmProvider?.custom_config?.AWS_REGION_NAME as string) ??

View File

@@ -197,7 +197,6 @@ export default function CustomModal({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
}: LLMProviderFormProps) {
@@ -210,11 +209,7 @@ export default function CustomModal({
const onClose = () => onOpenChange?.(false);
const initialValues = {
...buildDefaultInitialValues(
existingLlmProvider,
undefined,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider),
...(isOnboarding ? buildOnboardingInitialValues() : {}),
provider: existingLlmProvider?.provider ?? "",
model_configurations: existingLlmProvider?.model_configurations.map(

View File

@@ -192,7 +192,6 @@ export default function LMStudioForm({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
@@ -226,11 +225,7 @@ export default function LMStudioForm({
},
} as LMStudioFormValues)
: {
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
api_base: existingLlmProvider?.api_base ?? DEFAULT_API_BASE,
custom_config: {
LM_STUDIO_API_KEY:

View File

@@ -159,7 +159,6 @@ export default function LiteLLMProxyModal({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
@@ -191,11 +190,7 @@ export default function LiteLLMProxyModal({
default_model_name: "",
} as LiteLLMProxyModalValues)
: {
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
api_key: existingLlmProvider?.api_key ?? "",
api_base: existingLlmProvider?.api_base ?? DEFAULT_API_BASE,
};

View File

@@ -212,7 +212,6 @@ export default function OllamaModal({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
@@ -245,11 +244,7 @@ export default function OllamaModal({
},
} as OllamaModalValues)
: {
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
api_base: existingLlmProvider?.api_base ?? DEFAULT_API_BASE,
custom_config: {
OLLAMA_API_KEY:

View File

@@ -35,7 +35,6 @@ export default function OpenAIModal({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
@@ -64,14 +63,9 @@ export default function OpenAIModal({
default_model_name: DEFAULT_DEFAULT_MODEL_NAME,
}
: {
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
api_key: existingLlmProvider?.api_key ?? "",
default_model_name:
defaultModelName ??
wellKnownLLMProvider?.recommended_default_model?.name ??
DEFAULT_DEFAULT_MODEL_NAME,
is_auto_mode: existingLlmProvider?.is_auto_mode ?? true,

View File

@@ -158,7 +158,6 @@ export default function OpenRouterModal({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
@@ -190,11 +189,7 @@ export default function OpenRouterModal({
default_model_name: "",
} as OpenRouterModalValues)
: {
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
api_key: existingLlmProvider?.api_key ?? "",
api_base: existingLlmProvider?.api_base ?? DEFAULT_API_BASE,
};

View File

@@ -48,7 +48,6 @@ export default function VertexAIModal({
shouldMarkAsDefault,
open,
onOpenChange,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
@@ -81,13 +80,8 @@ export default function VertexAIModal({
},
} as VertexAIModalValues)
: {
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
default_model_name:
defaultModelName ??
wellKnownLLMProvider?.recommended_default_model?.name ??
VERTEXAI_DEFAULT_MODEL,
is_auto_mode: existingLlmProvider?.is_auto_mode ?? true,

View File

@@ -22,15 +22,9 @@ function detectIfRealOpenAIProvider(provider: LLMProviderView) {
export function getModalForExistingProvider(
provider: LLMProviderView,
open?: boolean,
onOpenChange?: (open: boolean) => void,
defaultModelName?: string
onOpenChange?: (open: boolean) => void
) {
const props = {
existingLlmProvider: provider,
open,
onOpenChange,
defaultModelName,
};
const props = { existingLlmProvider: provider, open, onOpenChange };
switch (provider.provider) {
case LLMProviderName.OPENAI:

View File

@@ -12,11 +12,9 @@ export const LLM_FORM_CLASS_NAME = "flex flex-col gap-y-4 items-stretch mt-6";
export const buildDefaultInitialValues = (
existingLlmProvider?: LLMProviderView,
modelConfigurations?: ModelConfiguration[],
currentDefaultModelName?: string
modelConfigurations?: ModelConfiguration[]
) => {
const defaultModelName =
currentDefaultModelName ??
existingLlmProvider?.model_configurations?.[0]?.name ??
modelConfigurations?.[0]?.name ??
"";