From 43d02953a26525e5443e4a1f5d148e3c49f20c64 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 13 Feb 2026 11:30:02 -0800 Subject: [PATCH] fix(model): validate default model against available options --- .../components/combobox/combobox.tsx | 7 ++++- apps/sim/blocks/blocks/agent.ts | 20 ++----------- apps/sim/blocks/blocks/evaluator.ts | 25 +++++------------ apps/sim/blocks/blocks/guardrails.ts | 24 ++++------------ apps/sim/blocks/blocks/router.ts | 28 ++++--------------- apps/sim/blocks/blocks/translate.ts | 21 ++++---------- apps/sim/blocks/utils.ts | 26 ++++++++++++++++- apps/sim/providers/vertex/index.ts | 4 +-- 8 files changed, 60 insertions(+), 95 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx index ea922b3ba..32036c21d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/combobox/combobox.tsx @@ -239,7 +239,12 @@ export const ComboBox = memo(function ComboBox({ */ const defaultOptionValue = useMemo(() => { if (defaultValue !== undefined) { - return defaultValue + // Validate that the default value exists in the available (filtered) options + const defaultInOptions = evaluatedOptions.find((opt) => getOptionValue(opt) === defaultValue) + if (defaultInOptions) { + return defaultValue + } + // Default not available (e.g. provider disabled) — fall through to other fallbacks } // For model field, default to claude-sonnet-4-5 if available diff --git a/apps/sim/blocks/blocks/agent.ts b/apps/sim/blocks/blocks/agent.ts index 84355f92b..a5cf7f887 100644 --- a/apps/sim/blocks/blocks/agent.ts +++ b/apps/sim/blocks/blocks/agent.ts @@ -2,11 +2,10 @@ import { createLogger } from '@sim/logger' import { AgentIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import { AuthMode } from '@/blocks/types' -import { getApiKeyCondition } from '@/blocks/utils' +import { getApiKeyCondition, getModelOptions } from '@/blocks/utils' import { getBaseModelProviders, getMaxTemperature, - getProviderIcon, getReasoningEffortValuesForModel, getThinkingLevelsForModel, getVerbosityValuesForModel, @@ -18,7 +17,6 @@ import { providers, supportsTemperature, } from '@/providers/utils' -import { useProvidersStore } from '@/stores/providers' import type { ToolResponse } from '@/tools/types' const logger = createLogger('AgentBlock') @@ -121,21 +119,7 @@ Return ONLY the JSON array.`, placeholder: 'Type or select a model...', required: true, defaultValue: 'claude-sonnet-4-5', - options: () => { - const providersState = useProvidersStore.getState() - const baseModels = providersState.providers.base.models - const ollamaModels = providersState.providers.ollama.models - const vllmModels = providersState.providers.vllm.models - const openrouterModels = providersState.providers.openrouter.models - const allModels = Array.from( - new Set([...baseModels, ...ollamaModels, ...vllmModels, ...openrouterModels]) - ) - - return allModels.map((model) => { - const icon = getProviderIcon(model) - return { label: model, id: model, ...(icon && { icon }) } - }) - }, + options: getModelOptions, }, { id: 'vertexCredential', diff --git a/apps/sim/blocks/blocks/evaluator.ts b/apps/sim/blocks/blocks/evaluator.ts index 5d584d171..4edb032ba 100644 --- a/apps/sim/blocks/blocks/evaluator.ts +++ b/apps/sim/blocks/blocks/evaluator.ts @@ -1,10 +1,13 @@ import { createLogger } from '@sim/logger' import { ChartBarIcon } from '@/components/icons' import type { BlockConfig, ParamType } from '@/blocks/types' -import { getProviderCredentialSubBlocks, PROVIDER_CREDENTIAL_INPUTS } from '@/blocks/utils' +import { + getModelOptions, + getProviderCredentialSubBlocks, + PROVIDER_CREDENTIAL_INPUTS, +} from '@/blocks/utils' import type { ProviderId } from '@/providers/types' -import { getBaseModelProviders, getProviderIcon } from '@/providers/utils' -import { useProvidersStore } from '@/stores/providers/store' +import { getBaseModelProviders } from '@/providers/utils' import type { ToolResponse } from '@/tools/types' const logger = createLogger('EvaluatorBlock') @@ -175,21 +178,7 @@ export const EvaluatorBlock: BlockConfig = { placeholder: 'Type or select a model...', required: true, defaultValue: 'claude-sonnet-4-5', - options: () => { - const providersState = useProvidersStore.getState() - const baseModels = providersState.providers.base.models - const ollamaModels = providersState.providers.ollama.models - const vllmModels = providersState.providers.vllm.models - const openrouterModels = providersState.providers.openrouter.models - const allModels = Array.from( - new Set([...baseModels, ...ollamaModels, ...vllmModels, ...openrouterModels]) - ) - - return allModels.map((model) => { - const icon = getProviderIcon(model) - return { label: model, id: model, ...(icon && { icon }) } - }) - }, + options: getModelOptions, }, ...getProviderCredentialSubBlocks(), { diff --git a/apps/sim/blocks/blocks/guardrails.ts b/apps/sim/blocks/blocks/guardrails.ts index 4ccf1ccec..5eeacd9a6 100644 --- a/apps/sim/blocks/blocks/guardrails.ts +++ b/apps/sim/blocks/blocks/guardrails.ts @@ -1,8 +1,10 @@ import { ShieldCheckIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { getProviderCredentialSubBlocks, PROVIDER_CREDENTIAL_INPUTS } from '@/blocks/utils' -import { getProviderIcon } from '@/providers/utils' -import { useProvidersStore } from '@/stores/providers/store' +import { + getModelOptions, + getProviderCredentialSubBlocks, + PROVIDER_CREDENTIAL_INPUTS, +} from '@/blocks/utils' import type { ToolResponse } from '@/tools/types' export interface GuardrailsResponse extends ToolResponse { @@ -111,21 +113,7 @@ Return ONLY the regex pattern - no explanations, no quotes, no forward slashes, type: 'combobox', placeholder: 'Type or select a model...', required: true, - options: () => { - const providersState = useProvidersStore.getState() - const baseModels = providersState.providers.base.models - const ollamaModels = providersState.providers.ollama.models - const vllmModels = providersState.providers.vllm.models - const openrouterModels = providersState.providers.openrouter.models - const allModels = Array.from( - new Set([...baseModels, ...ollamaModels, ...vllmModels, ...openrouterModels]) - ) - - return allModels.map((model) => { - const icon = getProviderIcon(model) - return { label: model, id: model, ...(icon && { icon }) } - }) - }, + options: getModelOptions, condition: { field: 'validationType', value: ['hallucination'], diff --git a/apps/sim/blocks/blocks/router.ts b/apps/sim/blocks/blocks/router.ts index 7da50ed98..4fae2383f 100644 --- a/apps/sim/blocks/blocks/router.ts +++ b/apps/sim/blocks/blocks/router.ts @@ -1,9 +1,12 @@ import { ConnectIcon } from '@/components/icons' import { AuthMode, type BlockConfig } from '@/blocks/types' -import { getProviderCredentialSubBlocks, PROVIDER_CREDENTIAL_INPUTS } from '@/blocks/utils' +import { + getModelOptions, + getProviderCredentialSubBlocks, + PROVIDER_CREDENTIAL_INPUTS, +} from '@/blocks/utils' import type { ProviderId } from '@/providers/types' -import { getBaseModelProviders, getProviderIcon } from '@/providers/utils' -import { useProvidersStore } from '@/stores/providers' +import { getBaseModelProviders } from '@/providers/utils' import type { ToolResponse } from '@/tools/types' interface RouterResponse extends ToolResponse { @@ -134,25 +137,6 @@ Respond with a JSON object containing: - reasoning: A brief explanation (1-2 sentences) of why you chose this route` } -/** - * Helper to get model options for both router versions. - */ -const getModelOptions = () => { - const providersState = useProvidersStore.getState() - const baseModels = providersState.providers.base.models - const ollamaModels = providersState.providers.ollama.models - const vllmModels = providersState.providers.vllm.models - const openrouterModels = providersState.providers.openrouter.models - const allModels = Array.from( - new Set([...baseModels, ...ollamaModels, ...vllmModels, ...openrouterModels]) - ) - - return allModels.map((model) => { - const icon = getProviderIcon(model) - return { label: model, id: model, ...(icon && { icon }) } - }) -} - /** * Legacy Router Block (block-based routing). * Hidden from toolbar but still supported for existing workflows. diff --git a/apps/sim/blocks/blocks/translate.ts b/apps/sim/blocks/blocks/translate.ts index 1385075c7..a47a2e06e 100644 --- a/apps/sim/blocks/blocks/translate.ts +++ b/apps/sim/blocks/blocks/translate.ts @@ -1,8 +1,10 @@ import { TranslateIcon } from '@/components/icons' import { AuthMode, type BlockConfig } from '@/blocks/types' -import { getProviderCredentialSubBlocks, PROVIDER_CREDENTIAL_INPUTS } from '@/blocks/utils' -import { getProviderIcon } from '@/providers/utils' -import { useProvidersStore } from '@/stores/providers/store' +import { + getModelOptions, + getProviderCredentialSubBlocks, + PROVIDER_CREDENTIAL_INPUTS, +} from '@/blocks/utils' const getTranslationPrompt = (targetLanguage: string) => `Translate the following text into ${targetLanguage || 'English'}. Output ONLY the translated text with no additional commentary, explanations, or notes.` @@ -38,18 +40,7 @@ export const TranslateBlock: BlockConfig = { type: 'combobox', placeholder: 'Type or select a model...', required: true, - options: () => { - const providersState = useProvidersStore.getState() - const baseModels = providersState.providers.base.models - const ollamaModels = providersState.providers.ollama.models - const openrouterModels = providersState.providers.openrouter.models - const allModels = Array.from(new Set([...baseModels, ...ollamaModels, ...openrouterModels])) - - return allModels.map((model) => { - const icon = getProviderIcon(model) - return { label: model, id: model, ...(icon && { icon }) } - }) - }, + options: getModelOptions, }, ...getProviderCredentialSubBlocks(), { diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index 8c003e0ad..32ab701bb 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -1,8 +1,32 @@ import { isHosted } from '@/lib/core/config/feature-flags' import type { BlockOutput, OutputFieldDefinition, SubBlockConfig } from '@/blocks/types' -import { getHostedModels, getProviderFromModel, providers } from '@/providers/utils' +import { + getHostedModels, + getProviderFromModel, + getProviderIcon, + providers, +} from '@/providers/utils' import { useProvidersStore } from '@/stores/providers/store' +/** + * Returns model options for combobox subblocks, combining all provider sources. + */ +export function getModelOptions() { + const providersState = useProvidersStore.getState() + const baseModels = providersState.providers.base.models + const ollamaModels = providersState.providers.ollama.models + const vllmModels = providersState.providers.vllm.models + const openrouterModels = providersState.providers.openrouter.models + const allModels = Array.from( + new Set([...baseModels, ...ollamaModels, ...vllmModels, ...openrouterModels]) + ) + + return allModels.map((model) => { + const icon = getProviderIcon(model) + return { label: model, id: model, ...(icon && { icon }) } + }) +} + /** * Checks if a field is included in the dependsOn config. * Handles both simple array format and object format with all/any fields. diff --git a/apps/sim/providers/vertex/index.ts b/apps/sim/providers/vertex/index.ts index 6c1e5b1c9..145de1238 100644 --- a/apps/sim/providers/vertex/index.ts +++ b/apps/sim/providers/vertex/index.ts @@ -30,8 +30,8 @@ export const vertexProvider: ProviderConfig = { executeRequest: async ( request: ProviderRequest ): Promise => { - const vertexProject = env.VERTEX_PROJECT || request.vertexProject - const vertexLocation = env.VERTEX_LOCATION || request.vertexLocation || 'us-central1' + const vertexProject = request.vertexProject || env.VERTEX_PROJECT + const vertexLocation = request.vertexLocation || env.VERTEX_LOCATION || 'us-central1' if (!vertexProject) { throw new Error(