diff --git a/apps/sim/app/api/users/me/settings/route.ts b/apps/sim/app/api/users/me/settings/route.ts index cb4256bf9d..3944b21d78 100644 --- a/apps/sim/app/api/users/me/settings/route.ts +++ b/apps/sim/app/api/users/me/settings/route.ts @@ -12,7 +12,7 @@ const logger = createLogger('UserSettingsAPI') const SettingsSchema = z.object({ theme: z.enum(['system', 'light', 'dark']).optional(), autoConnect: z.boolean().optional(), - autoFillEnvVars: z.boolean().optional(), + autoFillEnvVars: z.boolean().optional(), // DEPRECATED: kept for backwards compatibility autoPan: z.boolean().optional(), consoleExpandedByDefault: z.boolean().optional(), telemetryEnabled: z.boolean().optional(), @@ -31,7 +31,7 @@ const SettingsSchema = z.object({ const defaultSettings = { theme: 'system', autoConnect: true, - autoFillEnvVars: true, + autoFillEnvVars: true, // DEPRECATED: kept for backwards compatibility, always true autoPan: true, consoleExpandedByDefault: true, telemetryEnabled: true, @@ -65,7 +65,7 @@ export async function GET() { data: { theme: userSettings.theme, autoConnect: userSettings.autoConnect, - autoFillEnvVars: userSettings.autoFillEnvVars, + autoFillEnvVars: userSettings.autoFillEnvVars, // DEPRECATED: kept for backwards compatibility autoPan: userSettings.autoPan, consoleExpandedByDefault: userSettings.consoleExpandedByDefault, telemetryEnabled: userSettings.telemetryEnabled, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx index 28a866ff07..53c471d9dc 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx @@ -17,7 +17,6 @@ import { cn } from '@/lib/utils' import { getAllBlocks } from '@/blocks' import { getProviderFromModel, supportsToolUsageControl } from '@/providers/utils' import { useCustomToolsStore } from '@/stores/custom-tools/store' -import { useGeneralStore } from '@/stores/settings/general/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' import { useWorkflowStore } from '@/stores/workflows/workflow/store' import { @@ -400,7 +399,6 @@ export function ToolInput({ const isWide = useWorkflowStore((state) => state.blocks[blockId]?.isWide) const customTools = useCustomToolsStore((state) => state.getAllTools()) const subBlockStore = useSubBlockStore() - const isAutoFillEnvVarsEnabled = useGeneralStore((state) => state.isAutoFillEnvVarsEnabled) // Get the current model from the 'model' subblock const modelValue = useSubBlockStore.getState().getValue(blockId, 'model') @@ -507,26 +505,13 @@ export function ToolInput({ return block.tools.access[0] } - // Initialize tool parameters with auto-fill if enabled + // Initialize tool parameters - no autofill, just return empty params const initializeToolParams = ( toolId: string, params: ToolParameterConfig[], instanceId?: string ): Record => { - const initialParams: Record = {} - - // Only auto-fill parameters if the setting is enabled - if (isAutoFillEnvVarsEnabled) { - // For each parameter, check if we have a stored/resolved value - params.forEach((param) => { - const resolvedValue = subBlockStore.resolveToolParamValue(toolId, param.id, instanceId) - if (resolvedValue) { - initialParams[param.id] = resolvedValue - } - }) - } - - return initialParams + return {} } const handleSelectTool = (toolBlock: (typeof toolBlocks)[0]) => { @@ -682,11 +667,6 @@ export function ToolInput({ const tool = selectedTools[toolIndex] - // Store the value in the tool params store for future use - if (paramValue.trim()) { - subBlockStore.setToolParam(tool.toolId, paramId, paramValue) - } - // Update the value in the workflow setStoreValue( selectedTools.map((tool, index) => diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/hooks/use-sub-block-value.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/hooks/use-sub-block-value.ts index 652b420982..44fde169ac 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/hooks/use-sub-block-value.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/hooks/use-sub-block-value.ts @@ -3,161 +3,12 @@ import { isEqual } from 'lodash' import { createLogger } from '@/lib/logs/console-logger' import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow' import { getProviderFromModel } from '@/providers/utils' -import { useGeneralStore } from '@/stores/settings/general/store' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' import { useWorkflowStore } from '@/stores/workflows/workflow/store' const logger = createLogger('SubBlockValue') -// Helper function to dispatch collaborative subblock updates -const dispatchSubblockUpdate = (blockId: string, subBlockId: string, value: any) => { - const event = new CustomEvent('update-subblock-value', { - detail: { - blockId, - subBlockId, - value, - }, - }) - window.dispatchEvent(event) -} - -/** - * Helper to handle API key auto-fill for provider-based blocks - * Used for agent, router, evaluator, and any other blocks that use LLM providers - */ -function handleProviderBasedApiKey( - blockId: string, - subBlockId: string, - modelValue: string | null | undefined, - storeValue: any, - isModelChange = false -) { - // Only proceed if we have a model selected - if (!modelValue) return - - // Get the provider for this model - const provider = getProviderFromModel(modelValue) - - // Skip if we couldn't determine a provider - if (!provider || provider === 'ollama') return - - const subBlockStore = useSubBlockStore.getState() - const isAutoFillEnabled = useGeneralStore.getState().isAutoFillEnvVarsEnabled - - // Try to get a saved API key for this provider (only if auto-fill is enabled) - const savedValue = isAutoFillEnabled - ? subBlockStore.resolveToolParamValue(provider, 'apiKey', blockId) - : null - - // If we have a valid saved API key and auto-fill is enabled, use it - if (savedValue && savedValue !== '' && isAutoFillEnabled) { - // Only update if the current value is different to avoid unnecessary updates - if (storeValue !== savedValue) { - dispatchSubblockUpdate(blockId, subBlockId, savedValue) - } - } else if (isModelChange && (!storeValue || storeValue === '')) { - // Only clear the field when switching models AND the field is already empty - // Don't clear existing user-entered values on initial load - dispatchSubblockUpdate(blockId, subBlockId, '') - } - // If no saved value and this is initial load, preserve existing value -} - -/** - * Helper to handle API key auto-fill for non-agent blocks - */ -function handleStandardBlockApiKey( - blockId: string, - subBlockId: string, - blockType: string | undefined, - storeValue: any -) { - if (!blockType) return - - const subBlockStore = useSubBlockStore.getState() - - // Only auto-fill if the field is empty - if (!storeValue || storeValue === '') { - // Pass the blockId as instanceId to check if this specific instance has been cleared - const savedValue = subBlockStore.resolveToolParamValue(blockType, 'apiKey', blockId) - - if (savedValue && savedValue !== '' && savedValue !== storeValue) { - // Auto-fill the API key from the param store - dispatchSubblockUpdate(blockId, subBlockId, savedValue) - } - } - // Handle environment variable references - else if ( - storeValue && - typeof storeValue === 'string' && - storeValue.startsWith('{{') && - storeValue.endsWith('}}') - ) { - // Pass the blockId as instanceId - const currentValue = subBlockStore.resolveToolParamValue(blockType, 'apiKey', blockId) - - if (currentValue !== storeValue) { - // If we got a replacement or null, update the field - if (currentValue) { - // Replacement found - update to new reference - dispatchSubblockUpdate(blockId, subBlockId, currentValue) - } - } - } -} - -/** - * Helper to store API key values - */ -function storeApiKeyValue( - blockId: string, - blockType: string | undefined, - modelValue: string | null | undefined, - newValue: any, - storeValue: any -) { - if (!blockType) return - - const subBlockStore = useSubBlockStore.getState() - - // Check if this is user explicitly clearing a field that had a value - // We only want to mark it as cleared if it's a user action, not an automatic - // clearing from model switching - if ( - storeValue && - storeValue !== '' && - (newValue === null || newValue === '' || String(newValue).trim() === '') - ) { - // Mark this specific instance as cleared so we don't auto-fill it - subBlockStore.markParamAsCleared(blockId, 'apiKey') - return - } - - // Only store non-empty values - if (!newValue || String(newValue).trim() === '') return - - // If user enters a value, we should clear any "cleared" flag - // to ensure auto-fill will work in the future - if (subBlockStore.isParamCleared(blockId, 'apiKey')) { - subBlockStore.unmarkParamAsCleared(blockId, 'apiKey') - } - - // For provider-based blocks, store the API key under the provider name - if ( - (blockType === 'agent' || blockType === 'router' || blockType === 'evaluator') && - modelValue - ) { - const provider = getProviderFromModel(modelValue) - if (provider && provider !== 'ollama') { - subBlockStore.setToolParam(provider, 'apiKey', String(newValue)) - } - } else { - // For other blocks, store under the block type - subBlockStore.setToolParam(blockType, 'apiKey', String(newValue)) - } -} - interface UseSubBlockValueOptions { debounceMs?: number isStreaming?: boolean // Explicit streaming state @@ -199,9 +50,6 @@ export function useSubBlockValue( // Keep a ref to the latest value to prevent unnecessary re-renders const valueRef = useRef(null) - // Previous model reference for detecting model changes - const prevModelRef = useRef(null) - // Streaming refs const lastEmittedValueRef = useRef(null) const streamingValueRef = useRef(null) @@ -216,9 +64,6 @@ export function useSubBlockValue( const isApiKey = subBlockId === 'apiKey' || (subBlockId?.toLowerCase().includes('apikey') ?? false) - // Check if auto-fill environment variables is enabled - always call this hook unconditionally - const isAutoFillEnvVarsEnabled = useGeneralStore((state) => state.isAutoFillEnvVarsEnabled) - // Always call this hook unconditionally - don't wrap it in a condition const modelSubBlockValue = useSubBlockStore((state) => blockId ? state.getValue(blockId, 'model') : null @@ -276,6 +121,29 @@ export function useSubBlockValue( }, })) + // Handle model changes for provider-based blocks - clear API key when provider changes + if ( + subBlockId === 'model' && + isProviderBasedBlock && + newValue && + typeof newValue === 'string' + ) { + const currentApiKeyValue = useSubBlockStore.getState().getValue(blockId, 'apiKey') + + // Only clear if there's currently an API key value + if (currentApiKeyValue && currentApiKeyValue !== '') { + const oldModelValue = storeValue as string + const oldProvider = oldModelValue ? getProviderFromModel(oldModelValue) : null + const newProvider = getProviderFromModel(newValue) + + // Clear API key if provider changed + if (oldProvider !== newProvider) { + // Use collaborative function to clear the API key + collaborativeSetSubblockValue(blockId, 'apiKey', '') + } + } + } + // Ensure we're passing the actual value, not a reference that might change const valueCopy = newValue === null @@ -284,11 +152,6 @@ export function useSubBlockValue( ? JSON.parse(JSON.stringify(newValue)) : newValue - // Handle API key storage for reuse across blocks - if (isApiKey && blockType) { - storeApiKeyValue(blockId, blockType, modelValue, newValue, storeValue) - } - // If streaming, just store the value without emitting if (isStreaming) { streamingValueRef.current = valueCopy @@ -320,61 +183,6 @@ export function useSubBlockValue( valueRef.current = storeValue !== undefined ? storeValue : initialValue }, []) - // When component mounts, check for existing API key in toolParamsStore - useEffect(() => { - // Skip autofill if the feature is disabled in settings - if (!isAutoFillEnvVarsEnabled) return - - // Only process API key fields - if (!isApiKey) return - - // Handle different block types - if (isProviderBasedBlock) { - handleProviderBasedApiKey(blockId, subBlockId, modelValue, storeValue, false) - } else { - // Normal handling for non-provider blocks - handleStandardBlockApiKey(blockId, subBlockId, blockType, storeValue) - } - }, [ - blockId, - subBlockId, - blockType, - storeValue, - isApiKey, - isAutoFillEnvVarsEnabled, - modelValue, - isProviderBasedBlock, - ]) - - // Monitor for model changes in provider-based blocks - useEffect(() => { - // Only process API key fields in model-based blocks - if (!isApiKey || !isProviderBasedBlock) return - - // Check if the model has changed - if (modelValue !== prevModelRef.current) { - // Update the previous model reference - prevModelRef.current = modelValue - - // Handle API key auto-fill for model changes - if (modelValue) { - handleProviderBasedApiKey(blockId, subBlockId, modelValue, storeValue, true) - } else { - // If no model is selected, clear the API key field - dispatchSubblockUpdate(blockId, subBlockId, '') - } - } - }, [ - blockId, - subBlockId, - blockType, - isApiKey, - modelValue, - isAutoFillEnvVarsEnabled, - storeValue, - isProviderBasedBlock, - ]) - // Update the ref if the store value changes // This ensures we're always working with the latest value useEffect(() => { diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/general/general.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/general/general.tsx index 59207fcc05..c6600b18ed 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/general/general.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/general/general.tsx @@ -17,7 +17,6 @@ import { useGeneralStore } from '@/stores/settings/general/store' const TOOLTIPS = { autoConnect: 'Automatically connect nodes.', - autoFillEnvVars: 'Automatically fill API keys.', autoPan: 'Automatically pan to active blocks during workflow execution.', consoleExpandedByDefault: 'Show console entries expanded by default. When disabled, entries will be collapsed by default.', @@ -30,13 +29,13 @@ export function General() { const error = useGeneralStore((state) => state.error) const theme = useGeneralStore((state) => state.theme) const isAutoConnectEnabled = useGeneralStore((state) => state.isAutoConnectEnabled) - const isAutoFillEnvVarsEnabled = useGeneralStore((state) => state.isAutoFillEnvVarsEnabled) + const isAutoPanEnabled = useGeneralStore((state) => state.isAutoPanEnabled) const isConsoleExpandedByDefault = useGeneralStore((state) => state.isConsoleExpandedByDefault) // Loading states const isAutoConnectLoading = useGeneralStore((state) => state.isAutoConnectLoading) - const isAutoFillEnvVarsLoading = useGeneralStore((state) => state.isAutoFillEnvVarsLoading) + const isAutoPanLoading = useGeneralStore((state) => state.isAutoPanLoading) const isConsoleExpandedByDefaultLoading = useGeneralStore( (state) => state.isConsoleExpandedByDefaultLoading @@ -45,7 +44,7 @@ export function General() { const setTheme = useGeneralStore((state) => state.setTheme) const toggleAutoConnect = useGeneralStore((state) => state.toggleAutoConnect) - const toggleAutoFillEnvVars = useGeneralStore((state) => state.toggleAutoFillEnvVars) + const toggleAutoPan = useGeneralStore((state) => state.toggleAutoPan) const toggleConsoleExpandedByDefault = useGeneralStore( (state) => state.toggleConsoleExpandedByDefault @@ -69,12 +68,6 @@ export function General() { } } - const handleAutoFillEnvVarsChange = async (checked: boolean) => { - if (checked !== isAutoFillEnvVarsEnabled && !isAutoFillEnvVarsLoading) { - await toggleAutoFillEnvVars() - } - } - const handleAutoPanChange = async (checked: boolean) => { if (checked !== isAutoPanEnabled && !isAutoPanLoading) { await toggleAutoPan() @@ -167,35 +160,7 @@ export function General() { disabled={isLoading || isAutoConnectLoading} /> -
-
- - - - - - -

{TOOLTIPS.autoFillEnvVars}

-
-
-
- -
+