From 3fee4395ca053231cb8e6947be61bf9e1846e290 Mon Sep 17 00:00:00 2001 From: majiayu000 <1835304752@qq.com> Date: Sat, 21 Mar 2026 22:19:50 +0800 Subject: [PATCH 01/18] fix: allow Bedrock provider to use AWS SDK default credential chain Remove hard requirement for explicit AWS credentials in Bedrock provider. When access key and secret key are not provided, the AWS SDK automatically falls back to its default credential chain (env vars, instance profile, ECS task role, EKS IRSA, SSO). Closes #3694 Signed-off-by: majiayu000 <1835304752@qq.com> --- apps/sim/blocks/blocks/agent.ts | 8 ++++---- apps/sim/providers/bedrock/index.ts | 27 ++++++++++++--------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/sim/blocks/blocks/agent.ts b/apps/sim/blocks/blocks/agent.ts index b44ef4658c3..3f7bdc96712 100644 --- a/apps/sim/blocks/blocks/agent.ts +++ b/apps/sim/blocks/blocks/agent.ts @@ -370,9 +370,9 @@ Return ONLY the JSON array.`, title: 'AWS Access Key ID', type: 'short-input', password: true, - placeholder: 'Enter your AWS Access Key ID', + placeholder: 'Optional - uses AWS default credential chain if empty', connectionDroppable: false, - required: true, + required: false, condition: { field: 'model', value: BEDROCK_MODELS, @@ -383,9 +383,9 @@ Return ONLY the JSON array.`, title: 'AWS Secret Access Key', type: 'short-input', password: true, - placeholder: 'Enter your AWS Secret Access Key', + placeholder: 'Optional - uses AWS default credential chain if empty', connectionDroppable: false, - required: true, + required: false, condition: { field: 'model', value: BEDROCK_MODELS, diff --git a/apps/sim/providers/bedrock/index.ts b/apps/sim/providers/bedrock/index.ts index ec0af6ab04b..6464c7662c5 100644 --- a/apps/sim/providers/bedrock/index.ts +++ b/apps/sim/providers/bedrock/index.ts @@ -50,14 +50,6 @@ export const bedrockProvider: ProviderConfig = { executeRequest: async ( request: ProviderRequest ): Promise => { - if (!request.bedrockAccessKeyId) { - throw new Error('AWS Access Key ID is required for Bedrock') - } - - if (!request.bedrockSecretKey) { - throw new Error('AWS Secret Access Key is required for Bedrock') - } - const region = request.bedrockRegion || 'us-east-1' const bedrockModelId = getBedrockInferenceProfileId(request.model, region) @@ -67,13 +59,18 @@ export const bedrockProvider: ProviderConfig = { region, }) - const client = new BedrockRuntimeClient({ - region, - credentials: { - accessKeyId: request.bedrockAccessKeyId || '', - secretAccessKey: request.bedrockSecretKey || '', - }, - }) + const clientConfig: { + region: string + credentials?: { accessKeyId: string; secretAccessKey: string } + } = { region } + if (request.bedrockAccessKeyId && request.bedrockSecretKey) { + clientConfig.credentials = { + accessKeyId: request.bedrockAccessKeyId, + secretAccessKey: request.bedrockSecretKey, + } + } + + const client = new BedrockRuntimeClient(clientConfig) const messages: BedrockMessage[] = [] const systemContent: SystemContentBlock[] = [] From dc04f4d34f3850581e7e3584b35e4c61c85d2d57 Mon Sep 17 00:00:00 2001 From: majiayu000 <1835304752@qq.com> Date: Sat, 21 Mar 2026 22:24:30 +0800 Subject: [PATCH 02/18] fix: add partial credential guard for Bedrock provider Reject configurations where only one of bedrockAccessKeyId or bedrockSecretKey is provided, preventing silent fallback to the default credential chain with a potentially different identity. Add tests covering all credential configuration scenarios. Signed-off-by: majiayu000 <1835304752@qq.com> --- apps/sim/providers/bedrock/index.test.ts | 110 +++++++++++++++++++++++ apps/sim/providers/bedrock/index.ts | 9 ++ 2 files changed, 119 insertions(+) create mode 100644 apps/sim/providers/bedrock/index.test.ts diff --git a/apps/sim/providers/bedrock/index.test.ts b/apps/sim/providers/bedrock/index.test.ts new file mode 100644 index 00000000000..f49b01e29a0 --- /dev/null +++ b/apps/sim/providers/bedrock/index.test.ts @@ -0,0 +1,110 @@ +/** + * @vitest-environment node + */ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const mockSend = vi.fn() + +vi.mock('@aws-sdk/client-bedrock-runtime', () => ({ + BedrockRuntimeClient: vi.fn().mockImplementation((config: any) => { + mockSend._lastConfig = config + return { send: mockSend } + }), + ConverseCommand: vi.fn(), + ConverseStreamCommand: vi.fn(), +})) + +vi.mock('@/providers/bedrock/utils', () => ({ + getBedrockInferenceProfileId: vi.fn().mockReturnValue('us.anthropic.claude-3-5-sonnet-20241022-v2:0'), + checkForForcedToolUsage: vi.fn(), + createReadableStreamFromBedrockStream: vi.fn(), + generateToolUseId: vi.fn().mockReturnValue('tool-1'), +})) + +vi.mock('@/providers/models', () => ({ + getProviderModels: vi.fn().mockReturnValue([]), + getProviderDefaultModel: vi.fn().mockReturnValue('us.anthropic.claude-3-5-sonnet-20241022-v2:0'), +})) + +vi.mock('@/providers/utils', () => ({ + calculateCost: vi.fn().mockReturnValue({ input: 0, output: 0, total: 0, pricing: null }), + prepareToolExecution: vi.fn(), + prepareToolsWithUsageControl: vi.fn(), + sumToolCosts: vi.fn().mockReturnValue(0), +})) + +vi.mock('@/tools', () => ({ + executeTool: vi.fn(), +})) + +import { BedrockRuntimeClient } from '@aws-sdk/client-bedrock-runtime' +import { bedrockProvider } from '@/providers/bedrock/index' + +describe('bedrockProvider credential handling', () => { + beforeEach(() => { + vi.clearAllMocks() + mockSend.mockResolvedValue({ + output: { message: { content: [{ text: 'response' }] } }, + usage: { inputTokens: 10, outputTokens: 5 }, + }) + }) + + const baseRequest = { + model: 'us.anthropic.claude-3-5-sonnet-20241022-v2:0', + systemPrompt: 'You are helpful.', + messages: [{ role: 'user' as const, content: 'Hello' }], + } + + it('throws when only bedrockAccessKeyId is provided', async () => { + await expect( + bedrockProvider.executeRequest({ + ...baseRequest, + bedrockAccessKeyId: 'AKIAIOSFODNN7EXAMPLE', + }) + ).rejects.toThrow('Both bedrockAccessKeyId and bedrockSecretKey must be provided together') + }) + + it('throws when only bedrockSecretKey is provided', async () => { + await expect( + bedrockProvider.executeRequest({ + ...baseRequest, + bedrockSecretKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', + }) + ).rejects.toThrow('Both bedrockAccessKeyId and bedrockSecretKey must be provided together') + }) + + it('creates client with explicit credentials when both are provided', async () => { + await bedrockProvider.executeRequest({ + ...baseRequest, + bedrockAccessKeyId: 'AKIAIOSFODNN7EXAMPLE', + bedrockSecretKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', + }) + + expect(BedrockRuntimeClient).toHaveBeenCalledWith({ + region: 'us-east-1', + credentials: { + accessKeyId: 'AKIAIOSFODNN7EXAMPLE', + secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', + }, + }) + }) + + it('creates client without credentials when neither is provided', async () => { + await bedrockProvider.executeRequest(baseRequest) + + expect(BedrockRuntimeClient).toHaveBeenCalledWith({ + region: 'us-east-1', + }) + }) + + it('uses custom region when provided', async () => { + await bedrockProvider.executeRequest({ + ...baseRequest, + bedrockRegion: 'eu-west-1', + }) + + expect(BedrockRuntimeClient).toHaveBeenCalledWith({ + region: 'eu-west-1', + }) + }) +}) diff --git a/apps/sim/providers/bedrock/index.ts b/apps/sim/providers/bedrock/index.ts index 6464c7662c5..7bc15a360a0 100644 --- a/apps/sim/providers/bedrock/index.ts +++ b/apps/sim/providers/bedrock/index.ts @@ -59,6 +59,15 @@ export const bedrockProvider: ProviderConfig = { region, }) + const hasAccessKey = Boolean(request.bedrockAccessKeyId) + const hasSecretKey = Boolean(request.bedrockSecretKey) + if (hasAccessKey !== hasSecretKey) { + throw new Error( + 'Both bedrockAccessKeyId and bedrockSecretKey must be provided together. ' + + 'Provide both for explicit credentials, or omit both to use the AWS default credential chain.' + ) + } + const clientConfig: { region: string credentials?: { accessKeyId: string; secretAccessKey: string } From c364bee41119f82762c501959fe44adf5e8e8034 Mon Sep 17 00:00:00 2001 From: majiayu000 <1835304752@qq.com> Date: Sun, 22 Mar 2026 11:54:12 +0800 Subject: [PATCH 03/18] fix: clean up bedrock test lint and dead code Remove unused config parameter and dead _lastConfig assignment from mock factory. Break long mockReturnValue chain to satisfy biome line-length rule. Signed-off-by: majiayu000 <1835304752@qq.com> --- apps/sim/providers/bedrock/index.test.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/sim/providers/bedrock/index.test.ts b/apps/sim/providers/bedrock/index.test.ts index f49b01e29a0..045837a5829 100644 --- a/apps/sim/providers/bedrock/index.test.ts +++ b/apps/sim/providers/bedrock/index.test.ts @@ -6,8 +6,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' const mockSend = vi.fn() vi.mock('@aws-sdk/client-bedrock-runtime', () => ({ - BedrockRuntimeClient: vi.fn().mockImplementation((config: any) => { - mockSend._lastConfig = config + BedrockRuntimeClient: vi.fn().mockImplementation(() => { return { send: mockSend } }), ConverseCommand: vi.fn(), @@ -15,7 +14,9 @@ vi.mock('@aws-sdk/client-bedrock-runtime', () => ({ })) vi.mock('@/providers/bedrock/utils', () => ({ - getBedrockInferenceProfileId: vi.fn().mockReturnValue('us.anthropic.claude-3-5-sonnet-20241022-v2:0'), + getBedrockInferenceProfileId: vi + .fn() + .mockReturnValue('us.anthropic.claude-3-5-sonnet-20241022-v2:0'), checkForForcedToolUsage: vi.fn(), createReadableStreamFromBedrockStream: vi.fn(), generateToolUseId: vi.fn().mockReturnValue('tool-1'), From fe8fd73af84c6993a8d33fe6b98d3062ce2b3c11 Mon Sep 17 00:00:00 2001 From: majiayu000 <1835304752@qq.com> Date: Sun, 22 Mar 2026 12:51:49 +0800 Subject: [PATCH 04/18] fix: address greptile review feedback on PR #3708 Use BedrockRuntimeClientConfig from SDK instead of inline type. Add default return value for prepareToolsWithUsageControl mock. Signed-off-by: majiayu000 <1835304752@qq.com> --- apps/sim/providers/bedrock/index.test.ts | 6 +++++- apps/sim/providers/bedrock/index.ts | 6 ++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/sim/providers/bedrock/index.test.ts b/apps/sim/providers/bedrock/index.test.ts index 045837a5829..8c938e01c87 100644 --- a/apps/sim/providers/bedrock/index.test.ts +++ b/apps/sim/providers/bedrock/index.test.ts @@ -30,7 +30,11 @@ vi.mock('@/providers/models', () => ({ vi.mock('@/providers/utils', () => ({ calculateCost: vi.fn().mockReturnValue({ input: 0, output: 0, total: 0, pricing: null }), prepareToolExecution: vi.fn(), - prepareToolsWithUsageControl: vi.fn(), + prepareToolsWithUsageControl: vi.fn().mockReturnValue({ + tools: [], + toolChoice: 'auto', + forcedTools: [], + }), sumToolCosts: vi.fn().mockReturnValue(0), })) diff --git a/apps/sim/providers/bedrock/index.ts b/apps/sim/providers/bedrock/index.ts index 7bc15a360a0..d3223cfebd0 100644 --- a/apps/sim/providers/bedrock/index.ts +++ b/apps/sim/providers/bedrock/index.ts @@ -1,6 +1,7 @@ import { type Message as BedrockMessage, BedrockRuntimeClient, + type BedrockRuntimeClientConfig, type ContentBlock, type ConversationRole, ConverseCommand, @@ -68,10 +69,7 @@ export const bedrockProvider: ProviderConfig = { ) } - const clientConfig: { - region: string - credentials?: { accessKeyId: string; secretAccessKey: string } - } = { region } + const clientConfig: BedrockRuntimeClientConfig = { region } if (request.bedrockAccessKeyId && request.bedrockSecretKey) { clientConfig.credentials = { accessKeyId: request.bedrockAccessKeyId, From bcb7b45958969541e74e7126e0e0d7e457cb844f Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 11:23:44 -0700 Subject: [PATCH 05/18] feat(providers): server-side credential hiding for Azure and Bedrock --- .cursor/skills/add-hosted-key/SKILL.md | 2 +- apps/sim/.env.example | 8 +++ .../hooks/use-editor-subblock-layout.ts | 6 +- .../workflow-block/workflow-block.tsx | 4 +- apps/sim/blocks/blocks/agent.ts | 17 +++-- apps/sim/blocks/blocks/function.ts | 2 +- apps/sim/blocks/types.ts | 3 +- apps/sim/blocks/utils.ts | 21 ++++-- apps/sim/lib/api-key/byok.ts | 11 ++- apps/sim/lib/copilot/vfs/serializers.ts | 4 +- apps/sim/lib/core/config/env.ts | 4 ++ apps/sim/lib/core/config/feature-flags.ts | 8 +++ .../sim/lib/workflows/subblocks/visibility.ts | 18 +++-- apps/sim/providers/azure-anthropic/index.ts | 17 +++-- apps/sim/providers/azure-openai/index.ts | 68 +++++++++++-------- apps/sim/providers/utils.ts | 9 ++- apps/sim/serializer/index.ts | 4 +- apps/sim/tools/params.ts | 8 +-- helm/sim/examples/values-aws.yaml | 4 ++ helm/sim/examples/values-azure.yaml | 11 +++ helm/sim/values.yaml | 25 ++++++- 21 files changed, 185 insertions(+), 69 deletions(-) diff --git a/.cursor/skills/add-hosted-key/SKILL.md b/.cursor/skills/add-hosted-key/SKILL.md index a6e0f07052d..2181910f8d9 100644 --- a/.cursor/skills/add-hosted-key/SKILL.md +++ b/.cursor/skills/add-hosted-key/SKILL.md @@ -192,7 +192,7 @@ In the block config (`blocks/blocks/{service}.ts`), add `hideWhenHosted: true` t }, ``` -The visibility is controlled by `isSubBlockHiddenByHostedKey()` in `lib/workflows/subblocks/visibility.ts`, which checks the `isHosted` feature flag. +The visibility is controlled by `isSubBlockHidden()` in `lib/workflows/subblocks/visibility.ts`, which checks both the `isHosted` feature flag (`hideWhenHosted`) and optional env var conditions (`hideWhenEnvSet`). ### Excluding Specific Operations from Hosted Key Support diff --git a/apps/sim/.env.example b/apps/sim/.env.example index 8db5d82c1af..fe9514e358e 100644 --- a/apps/sim/.env.example +++ b/apps/sim/.env.example @@ -29,6 +29,14 @@ API_ENCRYPTION_KEY=your_api_encryption_key # Use `openssl rand -hex 32` to gener # VLLM_BASE_URL=http://localhost:8000 # Base URL for your self-hosted vLLM (OpenAI-compatible) # VLLM_API_KEY= # Optional bearer token if your vLLM instance requires auth # FIREWORKS_API_KEY= # Optional Fireworks AI API key for model listing +# NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS=true # Set when using AWS default credential chain (IAM roles, ECS task roles, IRSA). Hides credential fields in Agent block UI. +# AZURE_OPENAI_ENDPOINT= # Azure OpenAI endpoint (hides field in UI when set alongside NEXT_PUBLIC_AZURE_CONFIGURED) +# AZURE_OPENAI_API_KEY= # Azure OpenAI API key +# AZURE_OPENAI_API_VERSION= # Azure OpenAI API version +# AZURE_ANTHROPIC_ENDPOINT= # Azure Anthropic endpoint (AI Foundry) +# AZURE_ANTHROPIC_API_KEY= # Azure Anthropic API key +# AZURE_ANTHROPIC_API_VERSION= # Azure Anthropic API version (e.g., 2023-06-01) +# NEXT_PUBLIC_AZURE_CONFIGURED=true # Set when Azure credentials are pre-configured above. Hides endpoint/key/version fields in Agent block UI. # Admin API (Optional - for self-hosted GitOps) # ADMIN_API_KEY= # Use `openssl rand -hex 32` to generate. Enables admin API for workflow export/import. diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/hooks/use-editor-subblock-layout.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/hooks/use-editor-subblock-layout.ts index 0cf118e428e..1ebc925262e 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/hooks/use-editor-subblock-layout.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/hooks/use-editor-subblock-layout.ts @@ -3,7 +3,7 @@ import { buildCanonicalIndex, evaluateSubBlockCondition, isSubBlockFeatureEnabled, - isSubBlockHiddenByHostedKey, + isSubBlockHidden, isSubBlockVisibleForMode, } from '@/lib/workflows/subblocks/visibility' import type { BlockConfig, SubBlockConfig, SubBlockType } from '@/blocks/types' @@ -109,8 +109,8 @@ export function useEditorSubblockLayout( // Check required feature if specified - declarative feature gating if (!isSubBlockFeatureEnabled(block)) return false - // Hide tool API key fields when hosted - if (isSubBlockHiddenByHostedKey(block)) return false + // Hide tool API key fields when hosted or when env var is set + if (isSubBlockHidden(block)) return false // Special handling for trigger-config type (legacy trigger configuration UI) if (block.type === ('trigger-config' as SubBlockType)) { diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx index 70ddefc95e8..b7b04f38bb2 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx @@ -17,7 +17,7 @@ import { evaluateSubBlockCondition, hasAdvancedValues, isSubBlockFeatureEnabled, - isSubBlockHiddenByHostedKey, + isSubBlockHidden, isSubBlockVisibleForMode, resolveDependencyValue, } from '@/lib/workflows/subblocks/visibility' @@ -980,7 +980,7 @@ export const WorkflowBlock = memo(function WorkflowBlock({ if (block.hidden) return false if (block.hideFromPreview) return false if (!isSubBlockFeatureEnabled(block)) return false - if (isSubBlockHiddenByHostedKey(block)) return false + if (isSubBlockHidden(block)) return false const isPureTriggerBlock = config?.triggers?.enabled && config.category === 'triggers' diff --git a/apps/sim/blocks/blocks/agent.ts b/apps/sim/blocks/blocks/agent.ts index 3f7bdc96712..0ac51ced426 100644 --- a/apps/sim/blocks/blocks/agent.ts +++ b/apps/sim/blocks/blocks/agent.ts @@ -3,7 +3,14 @@ import { AgentIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' import { AuthMode, IntegrationType } from '@/blocks/types' -import { getApiKeyCondition, getModelOptions, RESPONSE_FORMAT_WAND_CONFIG } from '@/blocks/utils' +import { + AZURE_MODELS, + BEDROCK_MODELS, + getApiKeyCondition, + getModelOptions, + RESPONSE_FORMAT_WAND_CONFIG, + VERTEX_MODELS, +} from '@/blocks/utils' import { getBaseModelProviders, getMaxTemperature, @@ -12,7 +19,6 @@ import { getModelsWithReasoningEffort, getModelsWithThinking, getModelsWithVerbosity, - getProviderModels, getReasoningEffortValuesForModel, getThinkingLevelsForModel, getVerbosityValuesForModel, @@ -23,9 +29,6 @@ import { useSubBlockStore } from '@/stores/workflows/subblock/store' import type { ToolResponse } from '@/tools/types' const logger = createLogger('AgentBlock') -const VERTEX_MODELS = getProviderModels('vertex') -const BEDROCK_MODELS = getProviderModels('bedrock') -const AZURE_MODELS = [...getProviderModels('azure-openai'), ...getProviderModels('azure-anthropic')] const MODELS_WITH_REASONING_EFFORT = getModelsWithReasoningEffort() const MODELS_WITH_VERBOSITY = getModelsWithVerbosity() const MODELS_WITH_THINKING = getModelsWithThinking() @@ -325,6 +328,7 @@ Return ONLY the JSON array.`, password: true, placeholder: 'https://your-resource.services.ai.azure.com', connectionDroppable: false, + hideWhenEnvSet: 'NEXT_PUBLIC_AZURE_CONFIGURED', condition: { field: 'model', value: AZURE_MODELS, @@ -336,6 +340,7 @@ Return ONLY the JSON array.`, type: 'short-input', placeholder: 'Enter API version', connectionDroppable: false, + hideWhenEnvSet: 'NEXT_PUBLIC_AZURE_CONFIGURED', condition: { field: 'model', value: AZURE_MODELS, @@ -373,6 +378,7 @@ Return ONLY the JSON array.`, placeholder: 'Optional - uses AWS default credential chain if empty', connectionDroppable: false, required: false, + hideWhenEnvSet: 'NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS', condition: { field: 'model', value: BEDROCK_MODELS, @@ -386,6 +392,7 @@ Return ONLY the JSON array.`, placeholder: 'Optional - uses AWS default credential chain if empty', connectionDroppable: false, required: false, + hideWhenEnvSet: 'NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS', condition: { field: 'model', value: BEDROCK_MODELS, diff --git a/apps/sim/blocks/blocks/function.ts b/apps/sim/blocks/blocks/function.ts index bdfc15ab11c..341f6482456 100644 --- a/apps/sim/blocks/blocks/function.ts +++ b/apps/sim/blocks/blocks/function.ts @@ -29,7 +29,7 @@ export const FunctionBlock: BlockConfig = { ], placeholder: 'Select language', value: () => CodeLanguage.JavaScript, - requiresFeature: 'NEXT_PUBLIC_E2B_ENABLED', + showWhenEnvSet: 'NEXT_PUBLIC_E2B_ENABLED', }, { id: 'code', diff --git a/apps/sim/blocks/types.ts b/apps/sim/blocks/types.ts index 614c686ec54..a471af5aada 100644 --- a/apps/sim/blocks/types.ts +++ b/apps/sim/blocks/types.ts @@ -327,8 +327,9 @@ export interface SubBlockConfig { connectionDroppable?: boolean hidden?: boolean hideFromPreview?: boolean // Hide this subblock from the workflow block preview - requiresFeature?: string // Environment variable name that must be truthy for this subblock to be visible + showWhenEnvSet?: string // Show this subblock only when the named NEXT_PUBLIC_ env var is truthy hideWhenHosted?: boolean // Hide this subblock when running on hosted sim + hideWhenEnvSet?: string // Hide this subblock when the named NEXT_PUBLIC_ env var is truthy description?: string tooltip?: string // Tooltip text displayed via info icon next to the title value?: (params: Record) => string diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index e06dbdf5add..2bd946d6b5e 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -1,4 +1,4 @@ -import { isHosted } from '@/lib/core/config/feature-flags' +import { isAzureConfigured, isHosted } from '@/lib/core/config/feature-flags' import type { BlockOutput, OutputFieldDefinition, SubBlockConfig } from '@/blocks/types' import { getHostedModels, @@ -8,9 +8,12 @@ import { } from '@/providers/models' import { useProvidersStore } from '@/stores/providers/store' -const VERTEX_MODELS = getProviderModels('vertex') -const BEDROCK_MODELS = getProviderModels('bedrock') -const AZURE_MODELS = [...getProviderModels('azure-openai'), ...getProviderModels('azure-anthropic')] +export const VERTEX_MODELS = getProviderModels('vertex') +export const BEDROCK_MODELS = getProviderModels('bedrock') +export const AZURE_MODELS = [ + ...getProviderModels('azure-openai'), + ...getProviderModels('azure-anthropic'), +] /** * Returns model options for combobox subblocks, combining all provider sources. @@ -105,6 +108,16 @@ function shouldRequireApiKeyForModel(model: string): boolean { return false } + if ( + isAzureConfigured && + (normalizedModel.startsWith('azure/') || + normalizedModel.startsWith('azure-openai/') || + normalizedModel.startsWith('azure-anthropic/') || + AZURE_MODELS.some((m) => m.toLowerCase() === normalizedModel)) + ) { + return false + } + if (normalizedModel.startsWith('vllm/')) { return false } diff --git a/apps/sim/lib/api-key/byok.ts b/apps/sim/lib/api-key/byok.ts index 901d86af5fe..a2aa198e859 100644 --- a/apps/sim/lib/api-key/byok.ts +++ b/apps/sim/lib/api-key/byok.ts @@ -8,6 +8,7 @@ import { isHosted } from '@/lib/core/config/feature-flags' import { decryptSecret } from '@/lib/core/security/encryption' import { getWorkspaceById } from '@/lib/workspaces/permissions/utils' import { getHostedModels } from '@/providers/models' +import { PROVIDER_PLACEHOLDER_KEY } from '@/providers/utils' import { useProvidersStore } from '@/stores/providers/store' import type { BYOKProviderId } from '@/tools/types' @@ -95,7 +96,15 @@ export async function getApiKeyWithBYOK( const isBedrockModel = provider === 'bedrock' || model.startsWith('bedrock/') if (isBedrockModel) { - return { apiKey: 'bedrock-uses-own-credentials', isBYOK: false } + return { apiKey: PROVIDER_PLACEHOLDER_KEY, isBYOK: false } + } + + if (provider === 'azure-openai') { + return { apiKey: userProvidedKey || env.AZURE_OPENAI_API_KEY || '', isBYOK: false } + } + + if (provider === 'azure-anthropic') { + return { apiKey: userProvidedKey || env.AZURE_ANTHROPIC_API_KEY || '', isBYOK: false } } const isOpenAIModel = provider === 'openai' diff --git a/apps/sim/lib/copilot/vfs/serializers.ts b/apps/sim/lib/copilot/vfs/serializers.ts index e1d282d0d55..524e8567e01 100644 --- a/apps/sim/lib/copilot/vfs/serializers.ts +++ b/apps/sim/lib/copilot/vfs/serializers.ts @@ -1,6 +1,6 @@ import { getCopilotToolDescription } from '@/lib/copilot/tool-descriptions' import { isHosted } from '@/lib/core/config/feature-flags' -import { isSubBlockHiddenByHostedKey } from '@/lib/workflows/subblocks/visibility' +import { isSubBlockHidden } from '@/lib/workflows/subblocks/visibility' import type { BlockConfig, SubBlockConfig } from '@/blocks/types' import { PROVIDER_DEFINITIONS } from '@/providers/models' import type { ToolConfig } from '@/tools/types' @@ -369,7 +369,7 @@ function serializeSubBlock(sb: SubBlockConfig): Record { * Serialize a block schema for VFS components/blocks/{type}.json */ export function serializeBlockSchema(block: BlockConfig): string { - const hiddenIds = new Set(block.subBlocks.filter(isSubBlockHiddenByHostedKey).map((sb) => sb.id)) + const hiddenIds = new Set(block.subBlocks.filter(isSubBlockHidden).map((sb) => sb.id)) const subBlocks = block.subBlocks .filter((sb) => !hiddenIds.has(sb.id)) diff --git a/apps/sim/lib/core/config/env.ts b/apps/sim/lib/core/config/env.ts index d58892e6887..84ffe503d4e 100644 --- a/apps/sim/lib/core/config/env.ts +++ b/apps/sim/lib/core/config/env.ts @@ -404,6 +404,8 @@ export const env = createEnv({ NEXT_PUBLIC_SUPPORT_EMAIL: z.string().email().optional(), // Custom support email NEXT_PUBLIC_E2B_ENABLED: z.string().optional(), + NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS: z.string().optional(), // Hide Bedrock credential fields when deployment uses AWS default credential chain (IAM roles, instance profiles, ECS task roles, IRSA) + NEXT_PUBLIC_AZURE_CONFIGURED: z.string().optional(), // Hide Azure credential fields when endpoint/key/version are pre-configured server-side NEXT_PUBLIC_COPILOT_TRAINING_ENABLED: z.string().optional(), NEXT_PUBLIC_ENABLE_PLAYGROUND: z.string().optional(), // Enable component playground at /playground NEXT_PUBLIC_DOCUMENTATION_URL: z.string().url().optional(), // Custom documentation URL @@ -462,6 +464,8 @@ export const env = createEnv({ NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED: process.env.NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED, NEXT_PUBLIC_TURNSTILE_SITE_KEY: process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY, NEXT_PUBLIC_E2B_ENABLED: process.env.NEXT_PUBLIC_E2B_ENABLED, + NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS: process.env.NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS, + NEXT_PUBLIC_AZURE_CONFIGURED: process.env.NEXT_PUBLIC_AZURE_CONFIGURED, NEXT_PUBLIC_COPILOT_TRAINING_ENABLED: process.env.NEXT_PUBLIC_COPILOT_TRAINING_ENABLED, NEXT_PUBLIC_ENABLE_PLAYGROUND: process.env.NEXT_PUBLIC_ENABLE_PLAYGROUND, NEXT_PUBLIC_POSTHOG_ENABLED: process.env.NEXT_PUBLIC_POSTHOG_ENABLED, diff --git a/apps/sim/lib/core/config/feature-flags.ts b/apps/sim/lib/core/config/feature-flags.ts index 012d1d5e026..b688924afed 100644 --- a/apps/sim/lib/core/config/feature-flags.ts +++ b/apps/sim/lib/core/config/feature-flags.ts @@ -122,6 +122,14 @@ export const isInboxEnabled = isTruthy(env.INBOX_ENABLED) */ export const isE2bEnabled = isTruthy(env.E2B_ENABLED) +/** + * Whether Azure OpenAI / Azure Anthropic credentials are pre-configured at the server level + * (via AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_API_KEY, AZURE_ANTHROPIC_ENDPOINT, etc.). + * When true, the endpoint, API key, and API version fields are hidden in the Agent block UI. + * Set NEXT_PUBLIC_AZURE_CONFIGURED=true in self-hosted deployments on Azure. + */ +export const isAzureConfigured = isTruthy(getEnv('NEXT_PUBLIC_AZURE_CONFIGURED')) + /** * Are invitations disabled globally * When true, workspace invitations are disabled for all users diff --git a/apps/sim/lib/workflows/subblocks/visibility.ts b/apps/sim/lib/workflows/subblocks/visibility.ts index 44cddf1224d..356ab0507bf 100644 --- a/apps/sim/lib/workflows/subblocks/visibility.ts +++ b/apps/sim/lib/workflows/subblocks/visibility.ts @@ -285,15 +285,19 @@ export function resolveDependencyValue( * Check if a subblock is gated by a feature flag. */ export function isSubBlockFeatureEnabled(subBlock: SubBlockConfig): boolean { - if (!subBlock.requiresFeature) return true - return isTruthy(getEnv(subBlock.requiresFeature)) + if (!subBlock.showWhenEnvSet) return true + return isTruthy(getEnv(subBlock.showWhenEnvSet)) } /** - * Check if a subblock should be hidden because we're running on hosted Sim. - * Used for tool API key fields that should be hidden when Sim provides hosted keys. + * Check if a subblock should be hidden based on environment conditions. + * Covers two cases: + * - `hideWhenHosted`: hidden when running on hosted Sim (tool API key fields) + * - `hideWhenEnvSet`: hidden when a specific NEXT_PUBLIC_ env var is truthy + * (credential fields hidden when the deployment provides them server-side) */ -export function isSubBlockHiddenByHostedKey(subBlock: SubBlockConfig): boolean { - if (!subBlock.hideWhenHosted) return false - return isHosted +export function isSubBlockHidden(subBlock: SubBlockConfig): boolean { + if (subBlock.hideWhenHosted && isHosted) return true + if (subBlock.hideWhenEnvSet && isTruthy(getEnv(subBlock.hideWhenEnvSet))) return true + return false } diff --git a/apps/sim/providers/azure-anthropic/index.ts b/apps/sim/providers/azure-anthropic/index.ts index 721e363394a..710d1ba90e8 100644 --- a/apps/sim/providers/azure-anthropic/index.ts +++ b/apps/sim/providers/azure-anthropic/index.ts @@ -1,5 +1,6 @@ import Anthropic from '@anthropic-ai/sdk' import { createLogger } from '@sim/logger' +import { env } from '@/lib/core/config/env' import type { StreamingExecution } from '@/executor/types' import { executeAnthropicProviderRequest } from '@/providers/anthropic/core' import { getProviderDefaultModel, getProviderModels } from '@/providers/models' @@ -18,14 +19,16 @@ export const azureAnthropicProvider: ProviderConfig = { executeRequest: async ( request: ProviderRequest ): Promise => { - if (!request.azureEndpoint) { + const azureEndpoint = request.azureEndpoint || env.AZURE_ANTHROPIC_ENDPOINT + if (!azureEndpoint) { throw new Error( - 'Azure endpoint is required for Azure Anthropic. Please provide it via the azureEndpoint parameter.' + 'Azure endpoint is required for Azure Anthropic. Please provide it via the azureEndpoint parameter or AZURE_ANTHROPIC_ENDPOINT environment variable.' ) } - if (!request.apiKey) { - throw new Error('API key is required for Azure Anthropic') + const apiKey = request.apiKey + if (!apiKey) { + throw new Error('API key is required for Azure Anthropic.') } // Strip the azure-anthropic/ prefix from the model name if present @@ -33,14 +36,16 @@ export const azureAnthropicProvider: ProviderConfig = { // Azure AI Foundry hosts Anthropic models at {endpoint}/anthropic // The SDK appends /v1/messages automatically - const baseURL = `${request.azureEndpoint.replace(/\/$/, '')}/anthropic` + const baseURL = `${azureEndpoint.replace(/\/$/, '')}/anthropic` - const anthropicVersion = request.azureApiVersion || '2023-06-01' + const anthropicVersion = + request.azureApiVersion || env.AZURE_ANTHROPIC_API_VERSION || '2023-06-01' return executeAnthropicProviderRequest( { ...request, model: modelName, + apiKey, }, { providerId: 'azure-anthropic', diff --git a/apps/sim/providers/azure-openai/index.ts b/apps/sim/providers/azure-openai/index.ts index 930c31035a3..72ee513e80e 100644 --- a/apps/sim/providers/azure-openai/index.ts +++ b/apps/sim/providers/azure-openai/index.ts @@ -65,7 +65,7 @@ async function executeChatCompletionsRequest( }) const azureOpenAI = new AzureOpenAI({ - apiKey: request.apiKey, + apiKey: request.apiKey!, apiVersion: azureApiVersion, endpoint: azureEndpoint, }) @@ -623,8 +623,9 @@ export const azureOpenAIProvider: ProviderConfig = { ) } - if (!request.apiKey) { - throw new Error('API key is required for Azure OpenAI') + const apiKey = request.apiKey + if (!apiKey) { + throw new Error('API key is required for Azure OpenAI.') } // Check if the endpoint is a full chat completions URL @@ -653,7 +654,12 @@ export const azureOpenAIProvider: ProviderConfig = { apiVersion: azureApiVersion, }) - return executeChatCompletionsRequest(request, baseUrl, azureApiVersion, deploymentName) + return executeChatCompletionsRequest( + { ...request, apiKey }, + baseUrl, + azureApiVersion, + deploymentName + ) } // Check if the endpoint is already a full responses API URL @@ -663,18 +669,21 @@ export const azureOpenAIProvider: ProviderConfig = { const deploymentName = request.model.replace('azure/', '') // Use the URL as-is since it's already complete - return executeResponsesProviderRequest(request, { - providerId: 'azure-openai', - providerLabel: 'Azure OpenAI', - modelName: deploymentName, - endpoint: azureEndpoint, - headers: { - 'Content-Type': 'application/json', - 'OpenAI-Beta': 'responses=v1', - 'api-key': request.apiKey, - }, - logger, - }) + return executeResponsesProviderRequest( + { ...request, apiKey }, + { + providerId: 'azure-openai', + providerLabel: 'Azure OpenAI', + modelName: deploymentName, + endpoint: azureEndpoint, + headers: { + 'Content-Type': 'application/json', + 'OpenAI-Beta': 'responses=v1', + 'api-key': apiKey, + }, + logger, + } + ) } // Default: base URL provided, construct the responses API URL @@ -684,17 +693,20 @@ export const azureOpenAIProvider: ProviderConfig = { const deploymentName = request.model.replace('azure/', '') const apiUrl = `${azureEndpoint.replace(/\/$/, '')}/openai/v1/responses?api-version=${azureApiVersion}` - return executeResponsesProviderRequest(request, { - providerId: 'azure-openai', - providerLabel: 'Azure OpenAI', - modelName: deploymentName, - endpoint: apiUrl, - headers: { - 'Content-Type': 'application/json', - 'OpenAI-Beta': 'responses=v1', - 'api-key': request.apiKey, - }, - logger, - }) + return executeResponsesProviderRequest( + { ...request, apiKey }, + { + providerId: 'azure-openai', + providerLabel: 'Azure OpenAI', + modelName: deploymentName, + endpoint: apiUrl, + headers: { + 'Content-Type': 'application/json', + 'OpenAI-Beta': 'responses=v1', + 'api-key': apiKey, + }, + logger, + } + ) }, } diff --git a/apps/sim/providers/utils.ts b/apps/sim/providers/utils.ts index 30fe1467eb1..40d4a0ebdf7 100644 --- a/apps/sim/providers/utils.ts +++ b/apps/sim/providers/utils.ts @@ -718,6 +718,13 @@ export function shouldBillModelUsage(model: string): boolean { return hostedModels.some((hostedModel) => model.toLowerCase() === hostedModel.toLowerCase()) } +/** + * Placeholder returned for providers that use their own credential mechanism + * rather than a user-supplied API key (e.g. AWS Bedrock via IAM/instance profiles). + * Must be truthy so upstream key-presence checks don't reject it. + */ +export const PROVIDER_PLACEHOLDER_KEY = 'provider-uses-own-credentials' + /** * Get an API key for a specific provider, handling rotation and fallbacks * For use server-side only @@ -740,7 +747,7 @@ export function getApiKey(provider: string, model: string, userProvidedKey?: str // Bedrock uses its own credentials (bedrockAccessKeyId/bedrockSecretKey), not apiKey const isBedrockModel = provider === 'bedrock' || model.startsWith('bedrock/') if (isBedrockModel) { - return 'bedrock-uses-own-credentials' + return PROVIDER_PLACEHOLDER_KEY } const isOpenAIModel = provider === 'openai' diff --git a/apps/sim/serializer/index.ts b/apps/sim/serializer/index.ts index 9c21661deb5..485b4e3cc2c 100644 --- a/apps/sim/serializer/index.ts +++ b/apps/sim/serializer/index.ts @@ -9,7 +9,7 @@ import { isCanonicalPair, isNonEmptyValue, isSubBlockFeatureEnabled, - isSubBlockHiddenByHostedKey, + isSubBlockHidden, resolveCanonicalMode, } from '@/lib/workflows/subblocks/visibility' import { getBlock } from '@/blocks' @@ -49,7 +49,7 @@ function shouldSerializeSubBlock( canonicalModeOverrides?: CanonicalModeOverrides ): boolean { if (!isSubBlockFeatureEnabled(subBlockConfig)) return false - if (isSubBlockHiddenByHostedKey(subBlockConfig)) return false + if (isSubBlockHidden(subBlockConfig)) return false if (subBlockConfig.mode === 'trigger') { if (!isTriggerContext && !isTriggerCategory) return false diff --git a/apps/sim/tools/params.ts b/apps/sim/tools/params.ts index 925e4fe6f50..9cc8c883655 100644 --- a/apps/sim/tools/params.ts +++ b/apps/sim/tools/params.ts @@ -5,7 +5,7 @@ import { type CanonicalModeOverrides, evaluateSubBlockCondition, isCanonicalPair, - isSubBlockHiddenByHostedKey, + isSubBlockHidden, resolveCanonicalMode, type SubBlockCondition, } from '@/lib/workflows/subblocks/visibility' @@ -320,7 +320,7 @@ export function getToolParametersConfig( ) if (subBlock) { - if (isSubBlockHiddenByHostedKey(subBlock)) { + if (isSubBlockHidden(subBlock)) { toolParam.visibility = 'hidden' } @@ -946,8 +946,8 @@ export function getSubBlocksForToolInput( // Skip trigger-mode-only subblocks if (sb.mode === 'trigger') continue - // Hide tool API key fields when running on hosted Sim - if (isSubBlockHiddenByHostedKey(sb)) continue + // Hide tool API key fields when running on hosted Sim or when env var is set + if (isSubBlockHidden(sb)) continue // Determine the effective param ID (canonical or subblock id) const effectiveParamId = sb.canonicalParamId || sb.id diff --git a/helm/sim/examples/values-aws.yaml b/helm/sim/examples/values-aws.yaml index c8451efc2a9..a5f21eb2294 100644 --- a/helm/sim/examples/values-aws.yaml +++ b/helm/sim/examples/values-aws.yaml @@ -45,6 +45,10 @@ app: NODE_ENV: "production" NEXT_TELEMETRY_DISABLED: "1" + # AWS Bedrock - when using IRSA (see serviceAccount below), the default credential chain + # resolves automatically. Setting this hides the credential fields in the Agent block UI. + NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS: "true" # Uncomment if using Bedrock with IRSA + # AWS S3 Cloud Storage Configuration (RECOMMENDED for production) # Create S3 buckets in your AWS account and configure IAM permissions AWS_REGION: "us-west-2" diff --git a/helm/sim/examples/values-azure.yaml b/helm/sim/examples/values-azure.yaml index a11b55adc93..30c97798bfa 100644 --- a/helm/sim/examples/values-azure.yaml +++ b/helm/sim/examples/values-azure.yaml @@ -47,6 +47,17 @@ app: NODE_ENV: "production" NEXT_TELEMETRY_DISABLED: "1" + # Azure OpenAI / Azure Anthropic (Azure AI Foundry) — set to use server-side credentials. + # When NEXT_PUBLIC_AZURE_CONFIGURED is true, the endpoint/key/version fields are hidden in + # the Agent block UI so users just pick a model and run. + AZURE_OPENAI_ENDPOINT: "" # e.g. https://your-resource.openai.azure.com + AZURE_OPENAI_API_KEY: "" # Azure OpenAI API key + AZURE_OPENAI_API_VERSION: "" # e.g. 2024-07-01-preview + AZURE_ANTHROPIC_ENDPOINT: "" # Azure AI Foundry endpoint for Anthropic models + AZURE_ANTHROPIC_API_KEY: "" # Azure Anthropic API key + AZURE_ANTHROPIC_API_VERSION: "" # Azure Anthropic API version (e.g., 2023-06-01) + NEXT_PUBLIC_AZURE_CONFIGURED: "true" # Set to "true" once credentials are configured above + # Azure Blob Storage Configuration (RECOMMENDED for production) # Create a storage account and containers in your Azure subscription AZURE_ACCOUNT_NAME: "simstudiostorageacct" # Azure storage account name diff --git a/helm/sim/values.yaml b/helm/sim/values.yaml index 92c163b4222..9fbe6195b67 100644 --- a/helm/sim/values.yaml +++ b/helm/sim/values.yaml @@ -113,13 +113,24 @@ app: # Google Vertex AI Configuration VERTEX_PROJECT: "" # Google Cloud project ID for Vertex AI VERTEX_LOCATION: "us-central1" # Google Cloud region for Vertex AI (e.g., "us-central1") - + + # Azure OpenAI Configuration (leave empty if not using Azure OpenAI) + AZURE_OPENAI_ENDPOINT: "" # Azure OpenAI service endpoint (e.g., https://your-resource.openai.azure.com) + AZURE_OPENAI_API_KEY: "" # Azure OpenAI API key + AZURE_OPENAI_API_VERSION: "" # Azure OpenAI API version (e.g., 2024-07-01-preview) + + # Azure Anthropic Configuration (leave empty if not using Azure Anthropic via AI Foundry) + AZURE_ANTHROPIC_ENDPOINT: "" # Azure AI Foundry endpoint for Anthropic models + AZURE_ANTHROPIC_API_KEY: "" # Azure Anthropic API key + AZURE_ANTHROPIC_API_VERSION: "" # Azure Anthropic API version (e.g., 2023-06-01) + # AI Provider API Keys (leave empty if not using) OPENAI_API_KEY: "" # Primary OpenAI API key OPENAI_API_KEY_1: "" # Additional OpenAI API key for load balancing OPENAI_API_KEY_2: "" # Additional OpenAI API key for load balancing OPENAI_API_KEY_3: "" # Additional OpenAI API key for load balancing MISTRAL_API_KEY: "" # Mistral AI API key + FIREWORKS_API_KEY: "" # Fireworks AI API key (for hosted model access) ANTHROPIC_API_KEY_1: "" # Primary Anthropic Claude API key ANTHROPIC_API_KEY_2: "" # Additional Anthropic API key for load balancing ANTHROPIC_API_KEY_3: "" # Additional Anthropic API key for load balancing @@ -223,6 +234,18 @@ app: SSO_ENABLED: "" # Enable SSO authentication ("true" to enable) NEXT_PUBLIC_SSO_ENABLED: "" # Show SSO login button in UI ("true" to enable) + # AWS Bedrock Credential Mode + # Set to "true" when the deployment uses AWS default credential chain (IAM roles, instance + # profiles, ECS task roles, IRSA, etc.) instead of explicit access key/secret per workflow. + # When enabled, the AWS Access Key ID and Secret fields are hidden in the Agent block UI. + NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS: "" # Set to "true" to hide Bedrock credential fields + + # Azure Provider Credential Mode + # Set to "true" when AZURE_OPENAI_ENDPOINT/API_KEY (and/or AZURE_ANTHROPIC_*) are configured + # server-side. When enabled, the Azure endpoint, API key, and API version fields are hidden + # in the Agent block UI — users just pick an Azure model and run. + NEXT_PUBLIC_AZURE_CONFIGURED: "" # Set to "true" to hide Azure credential fields + # AWS S3 Cloud Storage Configuration (optional - for file storage) # If configured, files will be stored in S3 instead of local storage AWS_REGION: "" # AWS region (e.g., "us-east-1") From e74025b46920b8d7dd6783466552be5317ffbeb1 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 11:26:43 -0700 Subject: [PATCH 06/18] fix(providers): revert Bedrock credential fields to required with original placeholders --- apps/sim/blocks/blocks/agent.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/sim/blocks/blocks/agent.ts b/apps/sim/blocks/blocks/agent.ts index 0ac51ced426..2cf3cfb608c 100644 --- a/apps/sim/blocks/blocks/agent.ts +++ b/apps/sim/blocks/blocks/agent.ts @@ -375,9 +375,9 @@ Return ONLY the JSON array.`, title: 'AWS Access Key ID', type: 'short-input', password: true, - placeholder: 'Optional - uses AWS default credential chain if empty', + placeholder: 'Enter your AWS Access Key ID', connectionDroppable: false, - required: false, + required: true, hideWhenEnvSet: 'NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS', condition: { field: 'model', @@ -389,9 +389,9 @@ Return ONLY the JSON array.`, title: 'AWS Secret Access Key', type: 'short-input', password: true, - placeholder: 'Optional - uses AWS default credential chain if empty', + placeholder: 'Enter your AWS Secret Access Key', connectionDroppable: false, - required: false, + required: true, hideWhenEnvSet: 'NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS', condition: { field: 'model', From 5232efc39555e8214b0c348e193e9f1cc242a46a Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 11:39:26 -0700 Subject: [PATCH 07/18] fix(blocks): add hideWhenEnvSet to getProviderCredentialSubBlocks for Azure and Bedrock --- apps/sim/blocks/utils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index 2bd946d6b5e..3fe243e01ac 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -196,6 +196,7 @@ export function getProviderCredentialSubBlocks(): SubBlockConfig[] { password: true, placeholder: 'https://your-resource.services.ai.azure.com', connectionDroppable: false, + hideWhenEnvSet: 'NEXT_PUBLIC_AZURE_CONFIGURED', condition: { field: 'model', value: AZURE_MODELS, @@ -207,6 +208,7 @@ export function getProviderCredentialSubBlocks(): SubBlockConfig[] { type: 'short-input', placeholder: 'Enter API version', connectionDroppable: false, + hideWhenEnvSet: 'NEXT_PUBLIC_AZURE_CONFIGURED', condition: { field: 'model', value: AZURE_MODELS, @@ -244,6 +246,7 @@ export function getProviderCredentialSubBlocks(): SubBlockConfig[] { placeholder: 'Enter your AWS Access Key ID', connectionDroppable: false, required: true, + hideWhenEnvSet: 'NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS', condition: { field: 'model', value: BEDROCK_MODELS, @@ -257,6 +260,7 @@ export function getProviderCredentialSubBlocks(): SubBlockConfig[] { placeholder: 'Enter your AWS Secret Access Key', connectionDroppable: false, required: true, + hideWhenEnvSet: 'NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS', condition: { field: 'model', value: BEDROCK_MODELS, From d8f75dd7217b2de5d0163ba31128ca6e59141680 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 12:11:00 -0700 Subject: [PATCH 08/18] fix(agent): use getProviderCredentialSubBlocks() instead of duplicating credential subblocks --- apps/sim/blocks/blocks/agent.ts | 105 ++------------------------------ 1 file changed, 4 insertions(+), 101 deletions(-) diff --git a/apps/sim/blocks/blocks/agent.ts b/apps/sim/blocks/blocks/agent.ts index 2cf3cfb608c..af9ec7ae07c 100644 --- a/apps/sim/blocks/blocks/agent.ts +++ b/apps/sim/blocks/blocks/agent.ts @@ -4,10 +4,8 @@ import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' import { AuthMode, IntegrationType } from '@/blocks/types' import { - AZURE_MODELS, - BEDROCK_MODELS, - getApiKeyCondition, getModelOptions, + getProviderCredentialSubBlocks, RESPONSE_FORMAT_WAND_CONFIG, VERTEX_MODELS, } from '@/blocks/utils' @@ -321,104 +319,9 @@ Return ONLY the JSON array.`, }, }, - { - id: 'azureEndpoint', - title: 'Azure Endpoint', - type: 'short-input', - password: true, - placeholder: 'https://your-resource.services.ai.azure.com', - connectionDroppable: false, - hideWhenEnvSet: 'NEXT_PUBLIC_AZURE_CONFIGURED', - condition: { - field: 'model', - value: AZURE_MODELS, - }, - }, - { - id: 'azureApiVersion', - title: 'Azure API Version', - type: 'short-input', - placeholder: 'Enter API version', - connectionDroppable: false, - hideWhenEnvSet: 'NEXT_PUBLIC_AZURE_CONFIGURED', - condition: { - field: 'model', - value: AZURE_MODELS, - }, - }, - { - id: 'vertexProject', - title: 'Vertex AI Project', - type: 'short-input', - placeholder: 'your-gcp-project-id', - connectionDroppable: false, - required: true, - condition: { - field: 'model', - value: VERTEX_MODELS, - }, - }, - { - id: 'vertexLocation', - title: 'Vertex AI Location', - type: 'short-input', - placeholder: 'us-central1', - connectionDroppable: false, - required: true, - condition: { - field: 'model', - value: VERTEX_MODELS, - }, - }, - { - id: 'bedrockAccessKeyId', - title: 'AWS Access Key ID', - type: 'short-input', - password: true, - placeholder: 'Enter your AWS Access Key ID', - connectionDroppable: false, - required: true, - hideWhenEnvSet: 'NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS', - condition: { - field: 'model', - value: BEDROCK_MODELS, - }, - }, - { - id: 'bedrockSecretKey', - title: 'AWS Secret Access Key', - type: 'short-input', - password: true, - placeholder: 'Enter your AWS Secret Access Key', - connectionDroppable: false, - required: true, - hideWhenEnvSet: 'NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS', - condition: { - field: 'model', - value: BEDROCK_MODELS, - }, - }, - { - id: 'bedrockRegion', - title: 'AWS Region', - type: 'short-input', - placeholder: 'us-east-1', - connectionDroppable: false, - condition: { - field: 'model', - value: BEDROCK_MODELS, - }, - }, - { - id: 'apiKey', - title: 'API Key', - type: 'short-input', - placeholder: 'Enter your API key', - password: true, - connectionDroppable: false, - required: true, - condition: getApiKeyCondition(), - }, + // Agent has its own vertexCredential/manualCredential above (with canonicalParamId + basic/advanced mode). + // Spread the rest of the shared credential subblocks, skipping the simple vertexCredential. + ...getProviderCredentialSubBlocks().filter((s) => s.id !== 'vertexCredential'), { id: 'tools', title: 'Tools', From 2694390abe83a466f0c99573811a45f450057412 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 12:38:07 -0700 Subject: [PATCH 09/18] fix(blocks): consolidate Vertex credential into shared factory with basic/advanced mode --- apps/sim/blocks/blocks/agent.ts | 36 ++------------------------------- apps/sim/blocks/utils.ts | 20 ++++++++++++++++-- 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/apps/sim/blocks/blocks/agent.ts b/apps/sim/blocks/blocks/agent.ts index af9ec7ae07c..caad30d9e2d 100644 --- a/apps/sim/blocks/blocks/agent.ts +++ b/apps/sim/blocks/blocks/agent.ts @@ -1,13 +1,11 @@ import { createLogger } from '@sim/logger' import { AgentIcon } from '@/components/icons' -import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' import { AuthMode, IntegrationType } from '@/blocks/types' import { getModelOptions, getProviderCredentialSubBlocks, RESPONSE_FORMAT_WAND_CONFIG, - VERTEX_MODELS, } from '@/blocks/utils' import { getBaseModelProviders, @@ -135,34 +133,6 @@ Return ONLY the JSON array.`, defaultValue: 'claude-sonnet-4-5', options: getModelOptions, }, - { - id: 'vertexCredential', - title: 'Google Cloud Account', - type: 'oauth-input', - serviceId: 'vertex-ai', - canonicalParamId: 'oauthCredential', - mode: 'basic', - requiredScopes: getScopesForService('vertex-ai'), - placeholder: 'Select Google Cloud account', - required: true, - condition: { - field: 'model', - value: VERTEX_MODELS, - }, - }, - { - id: 'manualCredential', - title: 'Google Cloud Account', - type: 'short-input', - canonicalParamId: 'oauthCredential', - mode: 'advanced', - placeholder: 'Enter credential ID', - required: true, - condition: { - field: 'model', - value: VERTEX_MODELS, - }, - }, { id: 'reasoningEffort', title: 'Reasoning Effort', @@ -319,9 +289,7 @@ Return ONLY the JSON array.`, }, }, - // Agent has its own vertexCredential/manualCredential above (with canonicalParamId + basic/advanced mode). - // Spread the rest of the shared credential subblocks, skipping the simple vertexCredential. - ...getProviderCredentialSubBlocks().filter((s) => s.id !== 'vertexCredential'), + ...getProviderCredentialSubBlocks(), { id: 'tools', title: 'Tools', @@ -571,7 +539,7 @@ Return ONLY the JSON array.`, apiKey: { type: 'string', description: 'Provider API key' }, azureEndpoint: { type: 'string', description: 'Azure endpoint URL' }, azureApiVersion: { type: 'string', description: 'Azure API version' }, - oauthCredential: { type: 'string', description: 'OAuth credential for Vertex AI' }, + vertexCredential: { type: 'string', description: 'OAuth credential for Vertex AI' }, vertexProject: { type: 'string', description: 'Google Cloud project ID for Vertex AI' }, vertexLocation: { type: 'string', description: 'Google Cloud location for Vertex AI' }, bedrockAccessKeyId: { type: 'string', description: 'AWS Access Key ID for Bedrock' }, diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index 3fe243e01ac..94661b13318 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -1,4 +1,5 @@ import { isAzureConfigured, isHosted } from '@/lib/core/config/feature-flags' +import { getScopesForService } from '@/lib/oauth/utils' import type { BlockOutput, OutputFieldDefinition, SubBlockConfig } from '@/blocks/types' import { getHostedModels, @@ -167,11 +168,13 @@ export function getApiKeyCondition() { export function getProviderCredentialSubBlocks(): SubBlockConfig[] { return [ { - id: 'vertexCredential', + id: 'vertexOauthCredential', title: 'Google Cloud Account', type: 'oauth-input', serviceId: 'vertex-ai', - requiredScopes: ['https://www.googleapis.com/auth/cloud-platform'], + canonicalParamId: 'vertexCredential', + mode: 'basic', + requiredScopes: getScopesForService('vertex-ai'), placeholder: 'Select Google Cloud account', required: true, condition: { @@ -179,6 +182,19 @@ export function getProviderCredentialSubBlocks(): SubBlockConfig[] { value: VERTEX_MODELS, }, }, + { + id: 'vertexManualCredential', + title: 'Google Cloud Account', + type: 'short-input', + canonicalParamId: 'vertexCredential', + mode: 'advanced', + placeholder: 'Enter credential ID', + required: true, + condition: { + field: 'model', + value: VERTEX_MODELS, + }, + }, { id: 'apiKey', title: 'API Key', From 28d8dcf36cb111bfcb907a9340805f4eb13c41ab Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 14:00:50 -0700 Subject: [PATCH 10/18] fix(types): resolve pre-existing TypeScript errors across auth, secrets, and copilot --- apps/sim/app/api/auth/socket-token/route.ts | 5 ++++- apps/sim/app/api/auth/sso/register/route.ts | 8 +++++++- apps/sim/app/api/tools/secrets_manager/utils.ts | 5 +++-- apps/sim/lib/auth/auth.ts | 8 ++++---- .../lib/copilot/orchestrator/tool-executor/index.ts | 10 ++++++++-- apps/sim/socket/middleware/auth.ts | 10 +++++++++- 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/apps/sim/app/api/auth/socket-token/route.ts b/apps/sim/app/api/auth/socket-token/route.ts index 85503a3af2d..5d82ee37d2c 100644 --- a/apps/sim/app/api/auth/socket-token/route.ts +++ b/apps/sim/app/api/auth/socket-token/route.ts @@ -10,7 +10,10 @@ export async function POST() { try { const hdrs = await headers() - const response = await auth.api.generateOneTimeToken({ + const api = auth.api as typeof auth.api & { + generateOneTimeToken: (ctx: { headers: Headers }) => Promise<{ token: string }> + } + const response = await api.generateOneTimeToken({ headers: hdrs, }) diff --git a/apps/sim/app/api/auth/sso/register/route.ts b/apps/sim/app/api/auth/sso/register/route.ts index 94c57c93478..00426252404 100644 --- a/apps/sim/app/api/auth/sso/register/route.ts +++ b/apps/sim/app/api/auth/sso/register/route.ts @@ -377,7 +377,13 @@ export async function POST(request: NextRequest) { ), }) - const registration = await auth.api.registerSSOProvider({ + const api = auth.api as typeof auth.api & { + registerSSOProvider: (ctx: { + body: unknown + headers: Headers + }) => Promise<{ providerId: string }> + } + const registration = await api.registerSSOProvider({ body: providerConfig, headers, }) diff --git a/apps/sim/app/api/tools/secrets_manager/utils.ts b/apps/sim/app/api/tools/secrets_manager/utils.ts index 331197fceca..dacbbc30be1 100644 --- a/apps/sim/app/api/tools/secrets_manager/utils.ts +++ b/apps/sim/app/api/tools/secrets_manager/utils.ts @@ -1,3 +1,4 @@ +import type { SecretListEntry, Tag } from '@aws-sdk/client-secrets-manager' import { CreateSecretCommand, DeleteSecretCommand, @@ -61,7 +62,7 @@ export async function listSecrets( }) const response = await client.send(command) - const secrets = (response.SecretList ?? []).map((secret) => ({ + const secrets = (response.SecretList ?? []).map((secret: SecretListEntry) => ({ name: secret.Name ?? '', arn: secret.ARN ?? '', description: secret.Description ?? null, @@ -69,7 +70,7 @@ export async function listSecrets( lastChangedDate: secret.LastChangedDate?.toISOString() ?? null, lastAccessedDate: secret.LastAccessedDate?.toISOString() ?? null, rotationEnabled: secret.RotationEnabled ?? false, - tags: secret.Tags?.map((t) => ({ key: t.Key ?? '', value: t.Value ?? '' })) ?? [], + tags: secret.Tags?.map((t: Tag) => ({ key: t.Key ?? '', value: t.Value ?? '' })) ?? [], })) return { diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index 7bfaa64889d..4f60bb4733e 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -19,6 +19,7 @@ import { oneTimeToken, organization, } from 'better-auth/plugins' +import type { BetterAuthPlugin } from 'better-auth/types' import { emailHarmony } from 'better-auth-harmony' import { and, eq, inArray, sql } from 'drizzle-orm' import { headers } from 'next/headers' @@ -559,12 +560,12 @@ export const auth = betterAuth({ github: { clientId: env.GITHUB_CLIENT_ID as string, clientSecret: env.GITHUB_CLIENT_SECRET as string, - scopes: ['user:email', 'repo'], + scope: ['user:email', 'repo'], }, google: { clientId: env.GOOGLE_CLIENT_ID as string, clientSecret: env.GOOGLE_CLIENT_SECRET as string, - scopes: [ + scope: [ 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile', ], @@ -602,7 +603,6 @@ export const auth = betterAuth({ emailAndPassword: { enabled: true, requireEmailVerification: isEmailVerificationEnabled, - sendVerificationOnSignUp: isEmailVerificationEnabled, // Auto-send verification OTP on signup when verification is required throwOnMissingCredentials: true, throwOnInvalidCredentials: true, sendResetPassword: async ({ user, url, token }, request) => { @@ -712,7 +712,7 @@ export const auth = betterAuth({ }, plugins: [ nextCookies(), - ...(isSignupEmailValidationEnabled ? [emailHarmony()] : []), + ...(isSignupEmailValidationEnabled ? [emailHarmony() as BetterAuthPlugin] : []), ...(env.TURNSTILE_SECRET_KEY ? [ captcha({ diff --git a/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts b/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts index 95252daf8bf..869bae29bd5 100644 --- a/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts +++ b/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts @@ -954,10 +954,16 @@ async function generateOAuthLink( const { headers: getHeaders } = await import('next/headers') const reqHeaders = await getHeaders() - const data = (await auth.api.oAuth2LinkAccount({ + const api = auth.api as typeof auth.api & { + oAuth2LinkAccount: (ctx: { + body: { providerId: string; callbackURL: string } + headers: Headers + }) => Promise<{ url?: string; redirect?: boolean }> + } + const data = await api.oAuth2LinkAccount({ body: { providerId, callbackURL }, headers: reqHeaders, - })) as { url?: string; redirect?: boolean } + }) if (!data?.url) { throw new Error('oAuth2LinkAccount did not return an authorization URL') diff --git a/apps/sim/socket/middleware/auth.ts b/apps/sim/socket/middleware/auth.ts index b334902d8cd..ad99766239a 100644 --- a/apps/sim/socket/middleware/auth.ts +++ b/apps/sim/socket/middleware/auth.ts @@ -55,7 +55,15 @@ export async function authenticateSocket(socket: AuthenticatedSocket, next: (err origin, }) - const session = await auth.api.verifyOneTimeToken({ + const api = auth.api as typeof auth.api & { + verifyOneTimeToken: (ctx: { + body: { token: string } + }) => Promise<{ + user: { id: string; name: string; email: string; image?: string | null } + session: { activeOrganizationId?: string | null } + }> + } + const session = await api.verifyOneTimeToken({ body: { token, }, From 0c90a344a0cb648b991347cea69abd933ea114b0 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 14:03:44 -0700 Subject: [PATCH 11/18] lint --- apps/sim/socket/middleware/auth.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/sim/socket/middleware/auth.ts b/apps/sim/socket/middleware/auth.ts index ad99766239a..f2774f0692a 100644 --- a/apps/sim/socket/middleware/auth.ts +++ b/apps/sim/socket/middleware/auth.ts @@ -56,9 +56,7 @@ export async function authenticateSocket(socket: AuthenticatedSocket, next: (err }) const api = auth.api as typeof auth.api & { - verifyOneTimeToken: (ctx: { - body: { token: string } - }) => Promise<{ + verifyOneTimeToken: (ctx: { body: { token: string } }) => Promise<{ user: { id: string; name: string; email: string; image?: string | null } session: { activeOrganizationId?: string | null } }> From 69fbcab2fbd65bc0e8336c11537a6374fcbf4968 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 14:48:28 -0700 Subject: [PATCH 12/18] improvement(blocks): make Vertex AI project ID a password field --- apps/sim/blocks/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index 94661b13318..4e9130669ea 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -234,6 +234,7 @@ export function getProviderCredentialSubBlocks(): SubBlockConfig[] { id: 'vertexProject', title: 'Vertex AI Project', type: 'short-input', + password: true, placeholder: 'your-gcp-project-id', connectionDroppable: false, required: true, From 9fe6f87fac45f0877bae0ef8e3df7873d8c1c1d1 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 14:50:27 -0700 Subject: [PATCH 13/18] fix(blocks): preserve vertexCredential subblock ID for backwards compatibility --- apps/sim/blocks/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index 4e9130669ea..3817d9e693a 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -168,11 +168,10 @@ export function getApiKeyCondition() { export function getProviderCredentialSubBlocks(): SubBlockConfig[] { return [ { - id: 'vertexOauthCredential', + id: 'vertexCredential', title: 'Google Cloud Account', type: 'oauth-input', serviceId: 'vertex-ai', - canonicalParamId: 'vertexCredential', mode: 'basic', requiredScopes: getScopesForService('vertex-ai'), placeholder: 'Select Google Cloud account', From 2e32ee9eaf5af34569ab4734b6c9352452739f52 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 14:51:23 -0700 Subject: [PATCH 14/18] fix(blocks): follow canonicalParamId pattern correctly for vertex credential subblocks --- apps/sim/blocks/utils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index 3817d9e693a..4e9130669ea 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -168,10 +168,11 @@ export function getApiKeyCondition() { export function getProviderCredentialSubBlocks(): SubBlockConfig[] { return [ { - id: 'vertexCredential', + id: 'vertexOauthCredential', title: 'Google Cloud Account', type: 'oauth-input', serviceId: 'vertex-ai', + canonicalParamId: 'vertexCredential', mode: 'basic', requiredScopes: getScopesForService('vertex-ai'), placeholder: 'Select Google Cloud account', From d611c3399de34e20d1eb68a29d04a6e18924363c Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 15:06:46 -0700 Subject: [PATCH 15/18] fix(blocks): keep vertexCredential subblock ID stable to preserve saved workflow state --- apps/sim/blocks/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index 4e9130669ea..3817d9e693a 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -168,11 +168,10 @@ export function getApiKeyCondition() { export function getProviderCredentialSubBlocks(): SubBlockConfig[] { return [ { - id: 'vertexOauthCredential', + id: 'vertexCredential', title: 'Google Cloud Account', type: 'oauth-input', serviceId: 'vertex-ai', - canonicalParamId: 'vertexCredential', mode: 'basic', requiredScopes: getScopesForService('vertex-ai'), placeholder: 'Select Google Cloud account', From 2ee6cba9c68d56fda269eb878651acb41628b226 Mon Sep 17 00:00:00 2001 From: waleed Date: Wed, 1 Apr 2026 15:08:06 -0700 Subject: [PATCH 16/18] fix(blocks): add canonicalParamId to vertexCredential basic subblock to complete the swap pair --- apps/sim/blocks/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index 3817d9e693a..b68ac4cbbbe 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -172,6 +172,7 @@ export function getProviderCredentialSubBlocks(): SubBlockConfig[] { title: 'Google Cloud Account', type: 'oauth-input', serviceId: 'vertex-ai', + canonicalParamId: 'vertexCredential', mode: 'basic', requiredScopes: getScopesForService('vertex-ai'), placeholder: 'Select Google Cloud account', From 564ebfd8e741a2b9b2b99c454115f1809db57343 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Wed, 1 Apr 2026 16:03:41 -0700 Subject: [PATCH 17/18] fix types --- apps/sim/app/api/auth/socket-token/route.ts | 5 +---- apps/sim/app/api/auth/sso/register/route.ts | 8 +------- apps/sim/lib/auth/auth.ts | 3 +-- bun.lock | 1 - 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/apps/sim/app/api/auth/socket-token/route.ts b/apps/sim/app/api/auth/socket-token/route.ts index 5d82ee37d2c..85503a3af2d 100644 --- a/apps/sim/app/api/auth/socket-token/route.ts +++ b/apps/sim/app/api/auth/socket-token/route.ts @@ -10,10 +10,7 @@ export async function POST() { try { const hdrs = await headers() - const api = auth.api as typeof auth.api & { - generateOneTimeToken: (ctx: { headers: Headers }) => Promise<{ token: string }> - } - const response = await api.generateOneTimeToken({ + const response = await auth.api.generateOneTimeToken({ headers: hdrs, }) diff --git a/apps/sim/app/api/auth/sso/register/route.ts b/apps/sim/app/api/auth/sso/register/route.ts index 00426252404..94c57c93478 100644 --- a/apps/sim/app/api/auth/sso/register/route.ts +++ b/apps/sim/app/api/auth/sso/register/route.ts @@ -377,13 +377,7 @@ export async function POST(request: NextRequest) { ), }) - const api = auth.api as typeof auth.api & { - registerSSOProvider: (ctx: { - body: unknown - headers: Headers - }) => Promise<{ providerId: string }> - } - const registration = await api.registerSSOProvider({ + const registration = await auth.api.registerSSOProvider({ body: providerConfig, headers, }) diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index 4f60bb4733e..69a308eccc7 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -19,7 +19,6 @@ import { oneTimeToken, organization, } from 'better-auth/plugins' -import type { BetterAuthPlugin } from 'better-auth/types' import { emailHarmony } from 'better-auth-harmony' import { and, eq, inArray, sql } from 'drizzle-orm' import { headers } from 'next/headers' @@ -712,7 +711,7 @@ export const auth = betterAuth({ }, plugins: [ nextCookies(), - ...(isSignupEmailValidationEnabled ? [emailHarmony() as BetterAuthPlugin] : []), + ...(isSignupEmailValidationEnabled ? [emailHarmony()] : []), ...(env.TURNSTILE_SECRET_KEY ? [ captcha({ diff --git a/bun.lock b/bun.lock index 181248e1ee7..c04ff1f5e07 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,5 @@ { "lockfileVersion": 1, - "configVersion": 0, "workspaces": { "": { "name": "simstudio", From 97a9a289de7f0eb20f95365c4417b9410f084ed6 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Wed, 1 Apr 2026 16:05:23 -0700 Subject: [PATCH 18/18] more types --- apps/sim/lib/copilot/orchestrator/tool-executor/index.ts | 8 +------- apps/sim/socket/middleware/auth.ts | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts b/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts index 869bae29bd5..cf6b623717e 100644 --- a/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts +++ b/apps/sim/lib/copilot/orchestrator/tool-executor/index.ts @@ -954,13 +954,7 @@ async function generateOAuthLink( const { headers: getHeaders } = await import('next/headers') const reqHeaders = await getHeaders() - const api = auth.api as typeof auth.api & { - oAuth2LinkAccount: (ctx: { - body: { providerId: string; callbackURL: string } - headers: Headers - }) => Promise<{ url?: string; redirect?: boolean }> - } - const data = await api.oAuth2LinkAccount({ + const data = await auth.api.oAuth2LinkAccount({ body: { providerId, callbackURL }, headers: reqHeaders, }) diff --git a/apps/sim/socket/middleware/auth.ts b/apps/sim/socket/middleware/auth.ts index f2774f0692a..b334902d8cd 100644 --- a/apps/sim/socket/middleware/auth.ts +++ b/apps/sim/socket/middleware/auth.ts @@ -55,13 +55,7 @@ export async function authenticateSocket(socket: AuthenticatedSocket, next: (err origin, }) - const api = auth.api as typeof auth.api & { - verifyOneTimeToken: (ctx: { body: { token: string } }) => Promise<{ - user: { id: string; name: string; email: string; image?: string | null } - session: { activeOrganizationId?: string | null } - }> - } - const session = await api.verifyOneTimeToken({ + const session = await auth.api.verifyOneTimeToken({ body: { token, },