fix(backend): use discriminator for credential matching in run_block

When executing blocks via the chat interface (run_block tool), the credential
matching logic was not using the discriminator_mapping to determine the correct
provider based on the selected model value.

For example, when a user ran AITextGeneratorBlock with model='gpt-4o-mini':
- The code matched against ALL supported providers (ollama, openai, anthropic...)
- Ollama credentials were always first in the list (since they don't require API key)
- So the FAKE_API_KEY from Ollama was used instead of the actual OpenAI key

This fix:
- Passes input_data to _check_block_credentials
- Uses field_info.discriminate() to narrow to the correct provider
- Matches credentials only for the discriminated provider

Fixes credential mismatch errors like:
'Error code: 401 - invalid_api_key: FAKE_API_KEY'
This commit is contained in:
Otto
2026-01-30 16:17:34 +00:00
parent cc4839bedb
commit 604703c064

View File

@@ -73,15 +73,22 @@ class RunBlockTool(BaseTool):
self,
user_id: str,
block: Any,
input_data: dict[str, Any] | None = None,
) -> tuple[dict[str, CredentialsMetaInput], list[CredentialsMetaInput]]:
"""
Check if user has required credentials for a block.
Args:
user_id: User ID
block: Block to check credentials for
input_data: Input data for the block (used to determine provider via discriminator)
Returns:
tuple[matched_credentials, missing_credentials]
"""
matched_credentials: dict[str, CredentialsMetaInput] = {}
missing_credentials: list[CredentialsMetaInput] = []
input_data = input_data or {}
# Get credential field info from block's input schema
credentials_fields_info = block.input_schema.get_credentials_fields_info()
@@ -94,14 +101,27 @@ class RunBlockTool(BaseTool):
available_creds = await creds_manager.store.get_all_creds(user_id)
for field_name, field_info in credentials_fields_info.items():
# field_info.provider is a frozenset of acceptable providers
# field_info.supported_types is a frozenset of acceptable types
# Use discriminator to narrow down provider if available
# This ensures we match credentials for the correct provider based on
# the actual model/value selected (e.g., gpt-4o-mini -> openai)
effective_field_info = field_info
if field_info.discriminator and field_info.discriminator_mapping:
discriminator_value = input_data.get(field_info.discriminator)
if discriminator_value and discriminator_value in field_info.discriminator_mapping:
effective_field_info = field_info.discriminate(discriminator_value)
logger.debug(
f"Discriminated provider for {field_name}: "
f"{discriminator_value} -> {effective_field_info.provider}"
)
# effective_field_info.provider is a frozenset of acceptable providers
# effective_field_info.supported_types is a frozenset of acceptable types
matching_cred = next(
(
cred
for cred in available_creds
if cred.provider in field_info.provider
and cred.type in field_info.supported_types
if cred.provider in effective_field_info.provider
and cred.type in effective_field_info.supported_types
),
None,
)
@@ -115,8 +135,8 @@ class RunBlockTool(BaseTool):
)
else:
# Create a placeholder for the missing credential
provider = next(iter(field_info.provider), "unknown")
cred_type = next(iter(field_info.supported_types), "api_key")
provider = next(iter(effective_field_info.provider), "unknown")
cred_type = next(iter(effective_field_info.supported_types), "api_key")
missing_credentials.append(
CredentialsMetaInput(
id=field_name,
@@ -184,10 +204,10 @@ class RunBlockTool(BaseTool):
logger.info(f"Executing block {block.name} ({block_id}) for user {user_id}")
# Check credentials
# Check credentials (pass input_data to use discriminator for provider selection)
creds_manager = IntegrationCredentialsManager()
matched_credentials, missing_credentials = await self._check_block_credentials(
user_id, block
user_id, block, input_data
)
if missing_credentials: