Compare commits

..

2 Commits

Author SHA1 Message Date
Justin Tahara
d50a5e0e27 chore(helm): Bumping Python Sandbox to v0.3.2 (#9955) 2026-04-06 22:55:14 +00:00
Evan Lohn
697a679409 chore: context gitignore (#9949) 2026-04-06 22:44:23 +00:00
20 changed files with 145 additions and 411 deletions

3
.gitignore vendored
View File

@@ -59,3 +59,6 @@ node_modules
# plans
plans/
# Added context for LLMs
onyx-llm-context/

View File

@@ -19,6 +19,6 @@ dependencies:
version: 5.4.0
- name: code-interpreter
repository: https://onyx-dot-app.github.io/python-sandbox/
version: 0.3.1
digest: sha256:4965b6ea3674c37163832a2192cd3bc8004f2228729fca170af0b9f457e8f987
generated: "2026-03-02T15:29:39.632344-08:00"
version: 0.3.2
digest: sha256:74908ea45ace2b4be913ff762772e6d87e40bab64e92c6662aa51730eaeb9d87
generated: "2026-04-06T15:34:02.597166-07:00"

View File

@@ -45,6 +45,6 @@ dependencies:
repository: https://charts.min.io/
condition: minio.enabled
- name: code-interpreter
version: 0.3.1
version: 0.3.2
repository: https://onyx-dot-app.github.io/python-sandbox/
condition: codeInterpreter.enabled

View File

@@ -125,8 +125,8 @@ export interface LLMProviderFormProps {
open?: boolean;
onOpenChange?: (open: boolean) => void;
/** The current global default model (provider_id + model_name). */
globalDefault?: DefaultModel | null;
/** The current default model name for this provider (from the global default). */
defaultModelName?: string;
// Onboarding-specific (only when variant === "onboarding")
onboardingState?: OnboardingState;

View File

@@ -31,7 +31,6 @@ import ConfirmationModalLayout from "@/refresh-components/layouts/ConfirmationMo
import { useCreateModal } from "@/refresh-components/contexts/ModalContext";
import Separator from "@/refresh-components/Separator";
import {
DefaultModel,
LLMProviderView,
WellKnownLLMProviderDescriptor,
} from "@/interfaces/llm";
@@ -156,14 +155,16 @@ const PROVIDER_MODAL_MAP: Record<
interface ExistingProviderCardProps {
provider: LLMProviderView;
isDefault: boolean;
isLastProvider: boolean;
globalDefault?: DefaultModel | null;
defaultModelName?: string;
}
function ExistingProviderCard({
provider,
isDefault,
isLastProvider,
globalDefault,
defaultModelName,
}: ExistingProviderCardProps) {
const { mutate } = useSWRConfig();
const [isOpen, setIsOpen] = useState(false);
@@ -222,6 +223,7 @@ function ExistingProviderCard({
description={getProviderDisplayName(provider.provider)}
sizePreset="main-ui"
variant="section"
tag={isDefault ? { title: "Default", color: "blue" } : undefined}
rightChildren={
<div className="flex flex-row">
<Hoverable.Item
@@ -254,7 +256,7 @@ function ExistingProviderCard({
provider,
isOpen,
setIsOpen,
globalDefault
defaultModelName
)}
</SelectCard>
</Hoverable.Root>
@@ -379,6 +381,15 @@ export default function LLMConfigurationPage() {
const hasProviders = existingLlmProviders.length > 0;
const isFirstProvider = !hasProviders;
// Pre-sort providers so the default appears first
const sortedProviders = [...existingLlmProviders].sort((a, b) => {
const aIsDefault = defaultText?.provider_id === a.id;
const bIsDefault = defaultText?.provider_id === b.id;
if (aIsDefault && !bIsDefault) return -1;
if (!aIsDefault && bIsDefault) return 1;
return 0;
});
// Pre-filter to providers that have at least one visible model
const providersWithVisibleModels = existingLlmProviders
.map((provider) => ({
@@ -472,12 +483,17 @@ export default function LLMConfigurationPage() {
/>
<div className="flex flex-col gap-2">
{existingLlmProviders.map((provider) => (
{sortedProviders.map((provider) => (
<ExistingProviderCard
key={provider.id}
provider={provider}
isLastProvider={existingLlmProviders.length === 1}
globalDefault={defaultText}
isDefault={defaultText?.provider_id === provider.id}
isLastProvider={sortedProviders.length === 1}
defaultModelName={
defaultText?.provider_id === provider.id
? defaultText.model_name
: undefined
}
/>
))}
</div>

View File

@@ -25,9 +25,6 @@ import {
SingleDefaultModelField,
LLMConfigurationModalWrapper,
} from "@/sections/modals/llmConfig/shared";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
import { toast } from "@/hooks/useToast";
const ANTHROPIC_PROVIDER_NAME = "anthropic";
const DEFAULT_DEFAULT_MODEL_NAME = "claude-sonnet-4-5";
@@ -38,14 +35,13 @@ export default function AnthropicModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const isOnboarding = variant === "onboarding";
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } = useWellKnownLLMProvider(
ANTHROPIC_PROVIDER_NAME
@@ -69,11 +65,18 @@ export default function AnthropicModal({
default_model_name: DEFAULT_DEFAULT_MODEL_NAME,
}
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
api_key: existingLlmProvider?.api_key ?? "",
api_base: existingLlmProvider?.api_base ?? undefined,
default_model_name:
existingLlmProvider?.model_configurations?.[0]?.name ??
(defaultModelName &&
modelConfigurations.some((m) => m.name === defaultModelName)
? defaultModelName
: undefined) ??
wellKnownLLMProvider?.recommended_default_model?.name ??
DEFAULT_DEFAULT_MODEL_NAME,
is_auto_mode: existingLlmProvider?.is_auto_mode ?? true,
@@ -119,9 +122,7 @@ export default function AnthropicModal({
initialValues,
modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault ? values.default_model_name : undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -160,26 +161,6 @@ export default function AnthropicModal({
wellKnownLLMProvider?.recommended_default_model ?? null
}
shouldShowAutoUpdateToggle={true}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(
existingLlmProvider.id,
modelName
);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
/>
)}

View File

@@ -38,8 +38,6 @@ import {
parseAzureTargetUri,
} from "@/lib/azureTargetUri";
import { toast } from "@/hooks/useToast";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
const AZURE_PROVIDER_NAME = "azure";
@@ -87,14 +85,13 @@ export default function AzureModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const isOnboarding = variant === "onboarding";
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } = useWellKnownLLMProvider(AZURE_PROVIDER_NAME);
@@ -129,7 +126,11 @@ export default function AzureModal({
default_model_name: "",
} as AzureModalValues)
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
api_key: existingLlmProvider?.api_key ?? "",
target_uri: buildTargetUri(existingLlmProvider),
};
@@ -188,11 +189,7 @@ export default function AzureModal({
initialValues,
modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault
? processedValues.default_model_name
: undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -243,26 +240,6 @@ export default function AzureModal({
formikProps={formikProps}
recommendedDefaultModel={null}
shouldShowAutoUpdateToggle={false}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(
existingLlmProvider.id,
modelName
);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
onAddModel={(modelName) => {
const newModel: ModelConfiguration = {
name: modelName,

View File

@@ -40,8 +40,6 @@ import { Card } from "@opal/components";
import { Section } from "@/layouts/general-layouts";
import { SvgAlertCircle } from "@opal/icons";
import { Content } from "@opal/layouts";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
import { toast } from "@/hooks/useToast";
import useOnMount from "@/hooks/useOnMount";
@@ -89,9 +87,6 @@ interface BedrockModalInternalsProps {
isTesting: boolean;
onClose: () => void;
isOnboarding: boolean;
onSetGlobalDefault?: (modelName: string) => void;
globalDefault?: { provider_id: number; model_name: string } | null;
providerId?: number;
}
function BedrockModalInternals({
@@ -103,9 +98,6 @@ function BedrockModalInternals({
isTesting,
onClose,
isOnboarding,
onSetGlobalDefault,
globalDefault,
providerId,
}: BedrockModalInternalsProps) {
const authMethod = formikProps.values.custom_config?.BEDROCK_AUTH_METHOD;
@@ -304,9 +296,6 @@ function BedrockModalInternals({
recommendedDefaultModel={null}
shouldShowAutoUpdateToggle={false}
onRefetch={isFetchDisabled ? undefined : handleFetchModels}
globalDefault={globalDefault}
providerId={providerId}
onSetGlobalDefault={onSetGlobalDefault}
/>
)}
@@ -326,14 +315,13 @@ export default function BedrockModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const [fetchedModels, setFetchedModels] = useState<ModelConfiguration[]>([]);
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const isOnboarding = variant === "onboarding";
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } = useWellKnownLLMProvider(
@@ -364,7 +352,11 @@ export default function BedrockModal({
},
} as BedrockModalValues)
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
custom_config: {
AWS_REGION_NAME:
(existingLlmProvider?.custom_config?.AWS_REGION_NAME as string) ??
@@ -439,11 +431,7 @@ export default function BedrockModal({
modelConfigurations:
fetchedModels.length > 0 ? fetchedModels : modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault
? submitValues.default_model_name
: undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -462,23 +450,6 @@ export default function BedrockModal({
isTesting={isTesting}
onClose={onClose}
isOnboarding={isOnboarding}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(existingLlmProvider.id, modelName);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
/>
)}
</Formik>

View File

@@ -37,8 +37,6 @@ import {
LLMConfigurationModalWrapper,
} from "@/sections/modals/llmConfig/shared";
import { toast } from "@/hooks/useToast";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
const BIFROST_PROVIDER_NAME = LLMProviderName.BIFROST;
const DEFAULT_API_BASE = "";
@@ -57,9 +55,6 @@ interface BifrostModalInternalsProps {
isTesting: boolean;
onClose: () => void;
isOnboarding: boolean;
onSetGlobalDefault?: (modelName: string) => void;
globalDefault?: { provider_id: number; model_name: string } | null;
providerId?: number;
}
function BifrostModalInternals({
@@ -71,9 +66,6 @@ function BifrostModalInternals({
isTesting,
onClose,
isOnboarding,
onSetGlobalDefault,
globalDefault,
providerId,
}: BifrostModalInternalsProps) {
const currentModels =
fetchedModels.length > 0
@@ -161,9 +153,6 @@ function BifrostModalInternals({
recommendedDefaultModel={null}
shouldShowAutoUpdateToggle={false}
onRefetch={isFetchDisabled ? undefined : handleFetchModels}
globalDefault={globalDefault}
providerId={providerId}
onSetGlobalDefault={onSetGlobalDefault}
/>
)}
@@ -183,14 +172,13 @@ export default function BifrostModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const [fetchedModels, setFetchedModels] = useState<ModelConfiguration[]>([]);
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const isOnboarding = variant === "onboarding";
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } = useWellKnownLLMProvider(
@@ -216,7 +204,11 @@ export default function BifrostModal({
default_model_name: "",
} as BifrostModalValues)
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
api_key: existingLlmProvider?.api_key ?? "",
api_base: existingLlmProvider?.api_base ?? DEFAULT_API_BASE,
};
@@ -260,9 +252,7 @@ export default function BifrostModal({
modelConfigurations:
fetchedModels.length > 0 ? fetchedModels : modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault ? values.default_model_name : undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -281,23 +271,6 @@ export default function BifrostModal({
isTesting={isTesting}
onClose={onClose}
isOnboarding={isOnboarding}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(existingLlmProvider.id, modelName);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
/>
)}
</Formik>

View File

@@ -212,13 +212,12 @@ export default function CustomModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
}: LLMProviderFormProps) {
const isOnboarding = variant === "onboarding";
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const { mutate } = useSWRConfig();
if (open === false) return null;
@@ -226,7 +225,11 @@ export default function CustomModal({
const onClose = () => onOpenChange?.(false);
const initialValues = {
...buildDefaultInitialValues(existingLlmProvider, undefined),
...buildDefaultInitialValues(
existingLlmProvider,
undefined,
defaultModelName
),
...(isOnboarding ? buildOnboardingInitialValues() : {}),
provider: existingLlmProvider?.provider ?? "",
model_configurations: existingLlmProvider?.model_configurations.map(
@@ -346,11 +349,7 @@ export default function CustomModal({
},
modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault
? values.default_model_name || modelConfigurations[0]?.name
: undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,

View File

@@ -37,8 +37,6 @@ import {
import { fetchModels } from "@/app/admin/configuration/llm/utils";
import debounce from "lodash/debounce";
import { toast } from "@/hooks/useToast";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
const DEFAULT_API_BASE = "http://localhost:1234";
@@ -57,9 +55,6 @@ interface LMStudioFormInternalsProps {
isTesting: boolean;
onClose: () => void;
isOnboarding: boolean;
onSetGlobalDefault?: (modelName: string) => void;
globalDefault?: { provider_id: number; model_name: string } | null;
providerId?: number;
}
function LMStudioFormInternals({
@@ -70,9 +65,6 @@ function LMStudioFormInternals({
isTesting,
onClose,
isOnboarding,
onSetGlobalDefault,
globalDefault,
providerId,
}: LMStudioFormInternalsProps) {
const initialApiKey =
(existingLlmProvider?.custom_config?.LM_STUDIO_API_KEY as string) ?? "";
@@ -181,9 +173,6 @@ function LMStudioFormInternals({
formikProps={formikProps}
recommendedDefaultModel={null}
shouldShowAutoUpdateToggle={false}
globalDefault={globalDefault}
providerId={providerId}
onSetGlobalDefault={onSetGlobalDefault}
/>
)}
@@ -203,14 +192,13 @@ export default function LMStudioForm({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const [fetchedModels, setFetchedModels] = useState<ModelConfiguration[]>([]);
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const isOnboarding = variant === "onboarding";
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } = useWellKnownLLMProvider(
@@ -238,7 +226,11 @@ export default function LMStudioForm({
},
} as LMStudioFormValues)
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
api_base: existingLlmProvider?.api_base ?? DEFAULT_API_BASE,
custom_config: {
LM_STUDIO_API_KEY:
@@ -298,11 +290,7 @@ export default function LMStudioForm({
modelConfigurations:
fetchedModels.length > 0 ? fetchedModels : modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault
? submitValues.default_model_name
: undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -320,23 +308,6 @@ export default function LMStudioForm({
isTesting={isTesting}
onClose={onClose}
isOnboarding={isOnboarding}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(existingLlmProvider.id, modelName);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
/>
)}
</Formik>

View File

@@ -36,8 +36,6 @@ import {
LLMConfigurationModalWrapper,
} from "@/sections/modals/llmConfig/shared";
import { toast } from "@/hooks/useToast";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
const DEFAULT_API_BASE = "http://localhost:4000";
@@ -55,9 +53,6 @@ interface LiteLLMProxyModalInternalsProps {
isTesting: boolean;
onClose: () => void;
isOnboarding: boolean;
onSetGlobalDefault?: (modelName: string) => void;
globalDefault?: { provider_id: number; model_name: string } | null;
providerId?: number;
}
function LiteLLMProxyModalInternals({
@@ -69,9 +64,6 @@ function LiteLLMProxyModalInternals({
isTesting,
onClose,
isOnboarding,
onSetGlobalDefault,
globalDefault,
providerId,
}: LiteLLMProxyModalInternalsProps) {
const currentModels =
fetchedModels.length > 0
@@ -148,9 +140,6 @@ function LiteLLMProxyModalInternals({
recommendedDefaultModel={null}
shouldShowAutoUpdateToggle={false}
onRefetch={isFetchDisabled ? undefined : handleFetchModels}
globalDefault={globalDefault}
providerId={providerId}
onSetGlobalDefault={onSetGlobalDefault}
/>
)}
@@ -170,14 +159,13 @@ export default function LiteLLMProxyModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const [fetchedModels, setFetchedModels] = useState<ModelConfiguration[]>([]);
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const isOnboarding = variant === "onboarding";
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } = useWellKnownLLMProvider(
@@ -203,7 +191,11 @@ export default function LiteLLMProxyModal({
default_model_name: "",
} as LiteLLMProxyModalValues)
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
api_key: existingLlmProvider?.api_key ?? "",
api_base: existingLlmProvider?.api_base ?? DEFAULT_API_BASE,
};
@@ -249,9 +241,7 @@ export default function LiteLLMProxyModal({
modelConfigurations:
fetchedModels.length > 0 ? fetchedModels : modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault ? values.default_model_name : undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -270,23 +260,6 @@ export default function LiteLLMProxyModal({
isTesting={isTesting}
onClose={onClose}
isOnboarding={isOnboarding}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(existingLlmProvider.id, modelName);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
/>
)}
</Formik>

View File

@@ -37,8 +37,6 @@ import debounce from "lodash/debounce";
import Tabs from "@/refresh-components/Tabs";
import { Card } from "@opal/components";
import { toast } from "@/hooks/useToast";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
const OLLAMA_PROVIDER_NAME = "ollama_chat";
const DEFAULT_API_BASE = "http://127.0.0.1:11434";
@@ -60,9 +58,6 @@ interface OllamaModalInternalsProps {
isTesting: boolean;
onClose: () => void;
isOnboarding: boolean;
onSetGlobalDefault?: (modelName: string) => void;
globalDefault?: { provider_id: number; model_name: string } | null;
providerId?: number;
}
function OllamaModalInternals({
@@ -73,9 +68,6 @@ function OllamaModalInternals({
isTesting,
onClose,
isOnboarding,
onSetGlobalDefault,
globalDefault,
providerId,
}: OllamaModalInternalsProps) {
const isInitialMount = useRef(true);
@@ -201,9 +193,6 @@ function OllamaModalInternals({
formikProps={formikProps}
recommendedDefaultModel={null}
shouldShowAutoUpdateToggle={false}
globalDefault={globalDefault}
providerId={providerId}
onSetGlobalDefault={onSetGlobalDefault}
/>
)}
@@ -223,14 +212,13 @@ export default function OllamaModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const [fetchedModels, setFetchedModels] = useState<ModelConfiguration[]>([]);
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const isOnboarding = variant === "onboarding";
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } =
@@ -257,7 +245,11 @@ export default function OllamaModal({
},
} as OllamaModalValues)
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
api_base: existingLlmProvider?.api_base ?? DEFAULT_API_BASE,
custom_config: {
OLLAMA_API_KEY:
@@ -317,11 +309,7 @@ export default function OllamaModal({
modelConfigurations:
fetchedModels.length > 0 ? fetchedModels : modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault
? submitValues.default_model_name
: undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -339,23 +327,6 @@ export default function OllamaModal({
isTesting={isTesting}
onClose={onClose}
isOnboarding={isOnboarding}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(existingLlmProvider.id, modelName);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
/>
)}
</Formik>

View File

@@ -25,9 +25,6 @@ import {
SingleDefaultModelField,
LLMConfigurationModalWrapper,
} from "@/sections/modals/llmConfig/shared";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
import { toast } from "@/hooks/useToast";
const OPENAI_PROVIDER_NAME = "openai";
const DEFAULT_DEFAULT_MODEL_NAME = "gpt-5.2";
@@ -38,14 +35,13 @@ export default function OpenAIModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const isOnboarding = variant === "onboarding";
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } =
useWellKnownLLMProvider(OPENAI_PROVIDER_NAME);
@@ -68,10 +64,17 @@ export default function OpenAIModal({
default_model_name: DEFAULT_DEFAULT_MODEL_NAME,
}
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
api_key: existingLlmProvider?.api_key ?? "",
default_model_name:
existingLlmProvider?.model_configurations?.[0]?.name ??
(defaultModelName &&
modelConfigurations.some((m) => m.name === defaultModelName)
? defaultModelName
: undefined) ??
wellKnownLLMProvider?.recommended_default_model?.name ??
DEFAULT_DEFAULT_MODEL_NAME,
is_auto_mode: existingLlmProvider?.is_auto_mode ?? true,
@@ -117,9 +120,7 @@ export default function OpenAIModal({
initialValues,
modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault ? values.default_model_name : undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -158,26 +159,6 @@ export default function OpenAIModal({
wellKnownLLMProvider?.recommended_default_model ?? null
}
shouldShowAutoUpdateToggle={true}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(
existingLlmProvider.id,
modelName
);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
/>
)}

View File

@@ -35,8 +35,6 @@ import {
LLMConfigurationModalWrapper,
} from "@/sections/modals/llmConfig/shared";
import { toast } from "@/hooks/useToast";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
const OPENROUTER_PROVIDER_NAME = "openrouter";
const DEFAULT_API_BASE = "https://openrouter.ai/api/v1";
@@ -54,9 +52,6 @@ interface OpenRouterModalInternalsProps {
isTesting: boolean;
onClose: () => void;
isOnboarding: boolean;
onSetGlobalDefault?: (modelName: string) => void;
globalDefault?: { provider_id: number; model_name: string } | null;
providerId?: number;
}
function OpenRouterModalInternals({
@@ -68,9 +63,6 @@ function OpenRouterModalInternals({
isTesting,
onClose,
isOnboarding,
onSetGlobalDefault,
globalDefault,
providerId,
}: OpenRouterModalInternalsProps) {
const currentModels =
fetchedModels.length > 0
@@ -147,9 +139,6 @@ function OpenRouterModalInternals({
recommendedDefaultModel={null}
shouldShowAutoUpdateToggle={false}
onRefetch={isFetchDisabled ? undefined : handleFetchModels}
globalDefault={globalDefault}
providerId={providerId}
onSetGlobalDefault={onSetGlobalDefault}
/>
)}
@@ -169,14 +158,13 @@ export default function OpenRouterModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const [fetchedModels, setFetchedModels] = useState<ModelConfiguration[]>([]);
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const isOnboarding = variant === "onboarding";
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } = useWellKnownLLMProvider(
@@ -202,7 +190,11 @@ export default function OpenRouterModal({
default_model_name: "",
} as OpenRouterModalValues)
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
api_key: existingLlmProvider?.api_key ?? "",
api_base: existingLlmProvider?.api_base ?? DEFAULT_API_BASE,
};
@@ -248,9 +240,7 @@ export default function OpenRouterModal({
modelConfigurations:
fetchedModels.length > 0 ? fetchedModels : modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault ? values.default_model_name : undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -269,23 +259,6 @@ export default function OpenRouterModal({
isTesting={isTesting}
onClose={onClose}
isOnboarding={isOnboarding}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(existingLlmProvider.id, modelName);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
/>
)}
</Formik>

View File

@@ -29,9 +29,6 @@ import {
SingleDefaultModelField,
LLMConfigurationModalWrapper,
} from "@/sections/modals/llmConfig/shared";
import { setDefaultLlmModel } from "@/lib/llmConfig/svc";
import { refreshLlmProviderCaches } from "@/lib/llmConfig/cache";
import { toast } from "@/hooks/useToast";
const VERTEXAI_PROVIDER_NAME = "vertex_ai";
const VERTEXAI_DISPLAY_NAME = "Google Cloud Vertex AI";
@@ -51,14 +48,13 @@ export default function VertexAIModal({
shouldMarkAsDefault,
open,
onOpenChange,
globalDefault,
defaultModelName,
onboardingState,
onboardingActions,
llmDescriptor,
}: LLMProviderFormProps) {
const isOnboarding = variant === "onboarding";
const [isTesting, setIsTesting] = useState(false);
const [pendingDefault, setPendingDefault] = useState<string | null>(null);
const { mutate } = useSWRConfig();
const { wellKnownLLMProvider } = useWellKnownLLMProvider(
VERTEXAI_PROVIDER_NAME
@@ -85,9 +81,16 @@ export default function VertexAIModal({
},
} as VertexAIModalValues)
: {
...buildDefaultInitialValues(existingLlmProvider, modelConfigurations),
...buildDefaultInitialValues(
existingLlmProvider,
modelConfigurations,
defaultModelName
),
default_model_name:
existingLlmProvider?.model_configurations?.[0]?.name ??
(defaultModelName &&
modelConfigurations.some((m) => m.name === defaultModelName)
? defaultModelName
: undefined) ??
wellKnownLLMProvider?.recommended_default_model?.name ??
VERTEXAI_DEFAULT_MODEL,
is_auto_mode: existingLlmProvider?.is_auto_mode ?? true,
@@ -165,11 +168,7 @@ export default function VertexAIModal({
initialValues,
modelConfigurations,
existingLlmProvider,
pendingDefaultModelName:
pendingDefault ??
(shouldMarkAsDefault
? submitValues.default_model_name
: undefined),
shouldMarkAsDefault,
setIsTesting,
mutate,
onClose,
@@ -233,26 +232,6 @@ export default function VertexAIModal({
wellKnownLLMProvider?.recommended_default_model ?? null
}
shouldShowAutoUpdateToggle={true}
globalDefault={globalDefault}
providerId={existingLlmProvider?.id}
onSetGlobalDefault={
existingLlmProvider
? async (modelName) => {
try {
await setDefaultLlmModel(
existingLlmProvider.id,
modelName
);
await refreshLlmProviderCaches(mutate);
toast.success("Default model updated successfully!");
} catch (e) {
const msg =
e instanceof Error ? e.message : "Unknown error";
toast.error(`Failed to set default model: ${msg}`);
}
}
: (modelName) => setPendingDefault(modelName)
}
/>
)}

View File

@@ -1,8 +1,4 @@
import {
DefaultModel,
LLMProviderName,
LLMProviderView,
} from "@/interfaces/llm";
import { LLMProviderName, LLMProviderView } from "@/interfaces/llm";
import AnthropicModal from "@/sections/modals/llmConfig/AnthropicModal";
import OpenAIModal from "@/sections/modals/llmConfig/OpenAIModal";
import OllamaModal from "@/sections/modals/llmConfig/OllamaModal";
@@ -28,13 +24,13 @@ export function getModalForExistingProvider(
provider: LLMProviderView,
open?: boolean,
onOpenChange?: (open: boolean) => void,
globalDefault?: DefaultModel | null
defaultModelName?: string
) {
const props = {
existingLlmProvider: provider,
open,
onOpenChange,
globalDefault,
defaultModelName,
};
switch (provider.provider) {

View File

@@ -5,11 +5,7 @@ import { Form, FormikProps } from "formik";
import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidEnterpriseFeaturesEnabled";
import { useAgents } from "@/hooks/useAgents";
import { useUserGroups } from "@/lib/hooks";
import {
DefaultModel,
ModelConfiguration,
SimpleKnownModel,
} from "@/interfaces/llm";
import { ModelConfiguration, SimpleKnownModel } from "@/interfaces/llm";
import * as InputLayouts from "@/layouts/input-layouts";
import Checkbox from "@/refresh-components/inputs/Checkbox";
import InputTypeInField from "@/refresh-components/form/InputTypeInField";
@@ -379,12 +375,6 @@ export interface ModelsFieldProps<T> {
modelConfigurations: ModelConfiguration[];
recommendedDefaultModel: SimpleKnownModel | null;
shouldShowAutoUpdateToggle: boolean;
/** The current global default model. */
globalDefault?: DefaultModel | null;
/** The provider ID for this modal (set for existing providers). */
providerId?: number;
/** Called when the user clicks "Set as default" on a model. */
onSetGlobalDefault?: (modelName: string) => void;
/** Called when the user clicks the refresh button to re-fetch models. */
onRefetch?: () => Promise<void> | void;
/** Called when the user adds a custom model by name. Enables the "Add Model" input. */
@@ -396,23 +386,13 @@ export function ModelsField<T extends BaseLLMFormValues>({
modelConfigurations,
recommendedDefaultModel,
shouldShowAutoUpdateToggle,
globalDefault,
providerId,
onSetGlobalDefault,
onRefetch,
onAddModel,
}: ModelsFieldProps<T>) {
const [newModelName, setNewModelName] = useState("");
const isAutoMode = formikProps.values.is_auto_mode;
const selectedModels = formikProps.values.selected_model_names ?? [];
// A model is the global default if it belongs to this provider and matches
// the global default model name.
const isGlobalDefault = (modelName: string) =>
globalDefault != null &&
providerId != null &&
globalDefault.provider_id === providerId &&
globalDefault.model_name === modelName;
const defaultModel = formikProps.values.default_model_name;
function handleCheckboxChange(modelName: string, checked: boolean) {
// Read current values inside the handler to avoid stale closure issues
@@ -531,27 +511,10 @@ export function ModelsField<T extends BaseLLMFormValues>({
icon={() => <Checkbox checked />}
title={model.display_name || model.name}
rightChildren={
isGlobalDefault(model.name) ? (
model.name === defaultModel ? (
<Section>
<Tag title="Default Model" color="blue" />
</Section>
) : onSetGlobalDefault ? (
<Hoverable.Item
group="LLMConfigurationButton"
variant="opacity-on-hover"
>
<Button
size="sm"
prominence="internal"
onClick={(e) => {
e.stopPropagation();
onSetGlobalDefault(model.name);
}}
type="button"
>
Set as default
</Button>
</Hoverable.Item>
) : undefined
}
/>
@@ -562,6 +525,7 @@ export function ModelsField<T extends BaseLLMFormValues>({
const isSelected = selectedModels.includes(
modelConfiguration.name
);
const isDefault = defaultModel === modelConfiguration.name;
return (
<Hoverable.Root
@@ -584,11 +548,11 @@ export function ModelsField<T extends BaseLLMFormValues>({
}
rightChildren={
isSelected ? (
isGlobalDefault(modelConfiguration.name) ? (
isDefault ? (
<Section>
<Tag color="blue" title="Default Model" />
</Section>
) : onSetGlobalDefault ? (
) : (
<Hoverable.Item
group="LLMConfigurationButton"
variant="opacity-on-hover"
@@ -598,14 +562,14 @@ export function ModelsField<T extends BaseLLMFormValues>({
prominence="internal"
onClick={(e) => {
e.stopPropagation();
onSetGlobalDefault(modelConfiguration.name);
handleSetDefault(modelConfiguration.name);
}}
type="button"
>
Set as default
</Button>
</Hoverable.Item>
) : undefined
)
) : undefined
}
/>

View File

@@ -56,7 +56,7 @@ export const submitLLMProvider = async <T extends BaseLLMFormValues>({
initialValues,
modelConfigurations,
existingLlmProvider,
pendingDefaultModelName,
shouldMarkAsDefault,
hideSuccess,
setIsTesting,
mutate,
@@ -166,7 +166,7 @@ export const submitLLMProvider = async <T extends BaseLLMFormValues>({
return;
}
if (pendingDefaultModelName) {
if (shouldMarkAsDefault) {
const newLlmProvider = (await response.json()) as LLMProviderView;
const setDefaultResponse = await fetch(`${LLM_ADMIN_URL}/default`, {
method: "POST",
@@ -175,12 +175,12 @@ export const submitLLMProvider = async <T extends BaseLLMFormValues>({
},
body: JSON.stringify({
provider_id: newLlmProvider.id,
model_name: pendingDefaultModelName,
model_name: finalDefaultModelName,
}),
});
if (!setDefaultResponse.ok) {
const errorMsg = (await setDefaultResponse.json()).detail;
toast.error(`Failed to set default model: ${errorMsg}`);
toast.error(`Failed to set provider as default: ${errorMsg}`);
return;
}
}

View File

@@ -12,9 +12,16 @@ export const LLM_FORM_CLASS_NAME = "flex flex-col gap-y-4 items-stretch mt-6";
export const buildDefaultInitialValues = (
existingLlmProvider?: LLMProviderView,
modelConfigurations?: ModelConfiguration[]
modelConfigurations?: ModelConfiguration[],
currentDefaultModelName?: string
) => {
const defaultModelName =
(currentDefaultModelName &&
existingLlmProvider?.model_configurations?.some(
(m) => m.name === currentDefaultModelName
)
? currentDefaultModelName
: undefined) ??
existingLlmProvider?.model_configurations?.[0]?.name ??
modelConfigurations?.[0]?.name ??
"";
@@ -97,8 +104,7 @@ export interface SubmitLLMProviderParams<
initialValues: T;
modelConfigurations: ModelConfiguration[];
existingLlmProvider?: LLMProviderView;
/** When set, the given model will be marked as the global default after provider creation. */
pendingDefaultModelName?: string;
shouldMarkAsDefault?: boolean;
hideSuccess?: boolean;
setIsTesting: (testing: boolean) => void;
mutate: ScopedMutator;