Compare commits

..

2 Commits

Author SHA1 Message Date
claude[bot]
b367eeb2ab style(backend): format run_block.py with black
Co-authored-by: Nicholas Tindle <ntindle@users.noreply.github.com>
2026-01-30 21:49:07 +00:00
Otto
604703c064 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'
2026-01-30 16:20:58 +00:00

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,30 @@ 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 +138,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 +207,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: