Feature: Consolidated Ai Models Providers Combined scenarios from: aimodelscredentials_coverage, aimodelserrors_coverage, aimodelsproviders_coverage, anthropic_provider, google_provider, langsmith_config, openrouter_provider # ============================================================ # Originally from: aimodelscredentials_coverage.feature # Feature: AI Models Credentials Domain Model Coverage # ============================================================ Scenario: Import and instantiate ModelProviderOption with all fields Given the cleveragents package is available When I import ModelProviderOption from aimodelscredentials Then the ModelProviderOption class should be available And I can create a ModelProviderOption with publishers, config, and priority Scenario: Create ModelProviderOption with minimal required fields Given the cleveragents package is available When I create a ModelProviderOption with only priority set to 1 Then the ModelProviderOption should have priority 1 And the publishers dictionary should be empty And the config should be None Scenario: Create ModelProviderOption with publishers dictionary Given the cleveragents package is available When I create a ModelProviderOption with complex publishers structure Then the publishers field should contain the expected dictionary structure And the ModelPublisher enum values should be properly handled Scenario: Create ModelProviderOption with ModelProviderConfigSchema Given the cleveragents package is available When I create a ModelProviderOption with a config object Then the config field should contain the ModelProviderConfigSchema instance And the config should be properly validated Scenario: Validate ModelProviderOption strips whitespace Given the cleveragents package is available When I create a ModelProviderOption with strings containing whitespace Then the string fields should have whitespace stripped Scenario: Validate ModelProviderOption assignment validation Given the cleveragents package is available When I create a ModelProviderOption instance And I update its fields with new values Then the assignment validation should be triggered And the values should be properly validated Scenario: Validate ModelProviderOption populate by name Given the cleveragents package is available When I create a ModelProviderOption using field aliases Then the fields should be populated correctly by name Scenario: Validate ModelProviderOption use enum values Given the cleveragents package is available When I create a ModelProviderOption with ModelPublisher enums Then the enum values should be used in serialization And the model should handle enum values properly Scenario: Test ModelProviderOption field defaults Given the cleveragents package is available When I create a ModelProviderOption with default fields Then publishers should default to an empty dictionary And config should default to None Scenario: Test ModelProviderOption field validation with invalid data Given the cleveragents package is available When I try to create a ModelProviderOption with invalid priority Then a ModelProviderOption validation error should be raised And the error should indicate the priority field issue Scenario: Test ModelProviderOption model config settings Given the cleveragents package is available When I examine the ModelProviderOption model_config Then the ModelProviderOption str_strip_whitespace should be True And the ModelProviderOption validate_assignment should be True And the ModelProviderOption arbitrary_types_allowed should be False And the ModelProviderOption populate_by_name should be True And the ModelProviderOption use_enum_values should be True Scenario: Test ModelProviderOption with nested publisher structures Given the cleveragents package is available When I create a ModelProviderOption with nested publisher dictionaries Then the nested structure should be properly maintained And the ModelPublisher boolean values should work correctly Scenario: Test ModelProviderOption serialization and deserialization Given the cleveragents package is available When I serialize a ModelProviderOption to dict And I deserialize it back to ModelProviderOption Then the round-trip should preserve all data Scenario: Test ModelProviderOption with None config field Given the cleveragents package is available When I explicitly set config to None in ModelProviderOption Then the config field should accept None value And the model should be valid Scenario: Test ModelProviderOption priority field requirement Given the cleveragents package is available When I try to create a ModelProviderOption without priority Then a ModelProviderOption validation error should be raised for missing required field # ============================================================ # Originally from: aimodelserrors_coverage.feature # Feature: AI Models Errors Coverage # ============================================================ Scenario: Create ModelError with overloaded error type Given I import the ModelError class When I create a ModelError with kind "OVERLOADED" And I set retriable to true And I set retryafterseconds to 30 Then the ModelError instance should be created successfully And the kind should be "ErrOverloaded" And the retriable flag should be true And the retry after seconds should be 30 Scenario: Create ModelError with context too long error Given I import the ModelError class When I create a ModelError with kind "CONTEXT_TOO_LONG" And I set retriable to false And I set retryafterseconds to 0 Then the ModelError instance should be created successfully And the kind should be "ErrContextTooLong" And the retriable flag should be false And the retry after seconds should be 0 Scenario: Create ModelError with rate limited error Given I import the ModelError class When I create a ModelError with kind "RATE_LIMITED" And I set retriable to true And I set retryafterseconds to 60 Then the ModelError instance should be created successfully And the kind should be "ErrRateLimited" And the retriable flag should be true And the retry after seconds should be 60 Scenario: Create ModelError with subscription quota exhausted Given I import the ModelError class When I create a ModelError with kind "SUBSCRIPTION_QUOTA_EXHAUSTED" And I set retriable to false And I set retryafterseconds to 3600 Then the ModelError instance should be created successfully And the kind should be "ErrSubscriptionQuotaExhausted" And the retriable flag should be false And the retry after seconds should be 3600 Scenario: Create ModelError with other error type Given I import the ModelError class When I create a ModelError with kind "OTHER" And I set retriable to true And I set retryafterseconds to 10 Then the ModelError instance should be created successfully And the kind should be "ErrOther" And the retriable flag should be true And the retry after seconds should be 10 Scenario: Create ModelError with cache support error Given I import the ModelError class When I create a ModelError with kind "CACHE_SUPPORT" And I set retriable to false And I set retryafterseconds to 0 Then the ModelError instance should be created successfully And the kind should be "ErrCacheSupport" And the retriable flag should be false And the retry after seconds should be 0 Scenario: Validate ModelError configuration Given I import the ModelError class When I create a ModelError with valid data Then the model configuration should have str_strip_whitespace as true And the model configuration should have validate_assignment as true And the model configuration should have arbitrary_types_allowed as false And the model configuration should have populate_by_name as true And the model configuration should have use_enum_values as true Scenario: Create FallbackResult with error fallback type Given I import the FallbackResult class When I create a FallbackResult with fallback type "ERROR" And I set isfallback to true And I set modelroleconfig to None And I set basemodelconfig to None Then the FallbackResult instance should be created successfully And the fallback type should be "FallbackTypeError" And the is fallback flag should be true And the model role config should be None And the base model config should be None Scenario: Create FallbackResult with context fallback type Given I import the FallbackResult class When I create a FallbackResult with fallback type "CONTEXT" And I set isfallback to true And I set modelroleconfig to None And I set basemodelconfig to None Then the FallbackResult instance should be created successfully And the fallback type should be "FallbackTypeContext" And the is fallback flag should be true Scenario: Create FallbackResult with provider fallback type Given I import the FallbackResult class When I create a FallbackResult with fallback type "PROVIDER" And I set isfallback to false And I set modelroleconfig to None And I set basemodelconfig to None Then the FallbackResult instance should be created successfully And the fallback type should be "FallbackTypeProvider" And the is fallback flag should be false Scenario: Create FallbackResult with model role config Given I import the FallbackResult class And I have a valid ModelRoleConfig instance When I create a FallbackResult with fallback type "ERROR" And I set isfallback to true And I set modelroleconfig to the valid instance And I set basemodelconfig to None Then the FallbackResult instance should be created successfully And the model role config should not be None And the model role config role should be "assistant" Scenario: Create FallbackResult with base model config Given I import the FallbackResult class And I have a valid BaseModelConfig instance When I create a FallbackResult with fallback type "CONTEXT" And I set isfallback to true And I set modelroleconfig to None And I set basemodelconfig to the valid instance Then the FallbackResult instance should be created successfully And the base model config should not be None And the base model config model_tag should be "gpt-4" Scenario: Create FallbackResult with both configs Given I import the FallbackResult class And I have a valid ModelRoleConfig instance And I have a valid BaseModelConfig instance When I create a FallbackResult with fallback type "PROVIDER" And I set isfallback to false And I set modelroleconfig to the valid instance And I set basemodelconfig to the valid instance Then the FallbackResult instance should be created successfully And the model role config should not be None And the base model config should not be None Scenario: Validate FallbackResult configuration Given I import the FallbackResult class When I create a FallbackResult with valid data Then the model configuration should have str_strip_whitespace as true And the model configuration should have validate_assignment as true And the model configuration should have arbitrary_types_allowed as false And the model configuration should have populate_by_name as true And the model configuration should have use_enum_values as true Scenario: ModelError with invalid kind raises validation error Given I import the ModelError class When I try to create a ModelError with invalid kind "INVALID_KIND" Then a validation error should be raised And the error should mention "Input should be" Scenario: FallbackResult with invalid fallback type raises error Given I import the FallbackResult class When I try to create a FallbackResult with invalid fallback type "INVALID_TYPE" Then a validation error should be raised And the error should mention "Input should be" Scenario: Test ModelError field aliases Given I import the ModelError class When I create a ModelError using field aliases Then the ModelError should accept the aliased fields And the values should be properly mapped Scenario: Test FallbackResult field aliases Given I import the FallbackResult class When I create a FallbackResult using field aliases Then the FallbackResult should accept the aliased fields And the values should be properly mapped Scenario: ModelError strips whitespace from string fields Given I import the ModelError class When I create a ModelError with whitespace in enum values Then the whitespace should be stripped from strings And the model should be created successfully Scenario: FallbackResult strips whitespace from string fields Given I import the FallbackResult class When I create a FallbackResult with whitespace in enum values Then the whitespace should be stripped from strings And the model should be created successfully # ============================================================ # Originally from: aimodelsproviders_coverage.feature # Feature: AI Models Providers Coverage # ============================================================ @unit @models Scenario: Create ModelProviderExtraAuthVars with all fields Given I import the ModelProviderExtraAuthVars class When I create a ModelProviderExtraAuthVars with var "AWS_REGION" And I set maybeJSONFilePath to true And I set required to true And I set default to "us-east-1" Then the var field should equal "AWS_REGION" And the maybe_j_s_o_n_file_path field should be true And the required field should be true And the default field should equal "us-east-1" @unit @models Scenario: Create ModelProviderExtraAuthVars with minimal fields Given I import the ModelProviderExtraAuthVars class When I create a ModelProviderExtraAuthVars with only var "API_KEY" Then the var field should equal "API_KEY" And the maybe_j_s_o_n_file_path field should be None And the required field should be None And the default field should be None @unit @models Scenario: ModelProviderExtraAuthVars field validation Given I import the ModelProviderExtraAuthVars class When I create a ModelProviderExtraAuthVars with var " TRIMMED_VAR " Then the var field should equal "TRIMMED_VAR" And the model should strip whitespace from string fields @unit @models Scenario: ModelProviderExtraAuthVars alias support Given I import the ModelProviderExtraAuthVars class When I create a ModelProviderExtraAuthVars using alias "maybeJSONFilePath" Then the field should be accessible as maybe_j_s_o_n_file_path And the model should populate by name @unit @models Scenario: ModelProviderExtraAuthVars dict export Given I have a ModelProviderExtraAuthVars instance When I export it to dict with aliases Then the dict should contain "maybeJSONFilePath" key And the dict should not contain "maybe_j_s_o_n_file_path" key @unit @models Scenario: Create ModelProviderConfigSchema with all fields Given I import the ModelProviderConfigSchema class When I create a ModelProviderConfigSchema with provider "ModelProviderOpenAI" And I set base_url to "https://api.openai.com" And I set custom_provider to "custom-gpt" And I set has_a_w_s_auth to true And I set has_claude_max_auth to false And I set skip_auth to false And I set local_only to false And I set api_key_env_var to "OPENAI_API_KEY" And I add extra_auth_vars list Then the provider field should equal "ModelProviderOpenAI" And the base_url field should equal "https://api.openai.com" And the custom_provider field should equal "custom-gpt" And the has_a_w_s_auth field should be true And the has_claude_max_auth field should be false And the skip_auth field should be false And the local_only field should be false And the api_key_env_var field should equal "OPENAI_API_KEY" And the extra_auth_vars should be a list @unit @models Scenario: Create ModelProviderConfigSchema with minimal fields Given I import the ModelProviderConfigSchema class When I create a ModelProviderConfigSchema with only required fields Then the provider field should be set And the base_url field should be set And all optional fields should be None @unit @models Scenario: ModelProviderConfigSchema with ModelProvider enum Given I import the ModelProviderConfigSchema class And I import the ModelProvider enum for provider config When I create a ModelProviderConfigSchema with ModelProvider.ANTHROPIC Then the provider field should equal "ModelProviderAnthropic" And the model should use enum values @unit @models Scenario: ModelProviderConfigSchema field validation Given I import the ModelProviderConfigSchema class When I create a ModelProviderConfigSchema with whitespace in fields Then all string fields should have whitespace stripped And the model should validate assignment @unit @models Scenario: ModelProviderConfigSchema alias support Given I import the ModelProviderConfigSchema class When I create a ModelProviderConfigSchema using aliases Then "baseUrl" should map to base_url And "customProvider" should map to custom_provider And "hasAWSAuth" should map to has_a_w_s_auth And "hasClaudeMaxAuth" should map to has_claude_max_auth And "skipAuth" should map to skip_auth And "localOnly" should map to local_only And "apiKeyEnvVar" should map to api_key_env_var And "extraAuthVars" should map to extra_auth_vars @unit @models Scenario: ModelProviderConfigSchema dict export with aliases Given I have a ModelProviderConfigSchema instance When I export it to dict with aliases Then the dict should use camelCase keys And "baseUrl" should be in the dict And "hasAWSAuth" should be in the dict @unit @models Scenario: ModelProviderConfigSchema with empty extra_auth_vars Given I import the ModelProviderConfigSchema class When I create a ModelProviderConfigSchema with empty extra_auth_vars list Then the extra_auth_vars should be an empty list And the model should accept empty lists @unit @models Scenario: ModelProviderConfigSchema with multiple extra_auth_vars Given I import the ModelProviderConfigSchema class When I create a ModelProviderConfigSchema with multiple extra_auth_vars Then each extra_auth_var should be a ModelProviderExtraAuthVars instance And the list should maintain order @unit @models Scenario: ModelProviderConfigSchema JSON serialization Given I have a ModelProviderConfigSchema instance When I serialize it to JSON Then the JSON should be valid And it should contain all set fields And it should use aliases in the output @unit @models Scenario: ModelProviderConfigSchema JSON deserialization Given I have a JSON string with provider config When I deserialize it to ModelProviderConfigSchema Then the object should be correctly populated And aliases should be resolved to field names @unit @models Scenario: ModelProviderExtraAuthVars model config validation Given I import the ModelProviderExtraAuthVars class When I check the model configuration Then str_strip_whitespace should be True And validate_assignment should be True And arbitrary_types_allowed should be False And populate_by_name should be True And use_enum_values should be True @unit @models Scenario: ModelProviderConfigSchema model config validation Given I import the ModelProviderConfigSchema class When I check the model configuration Then str_strip_whitespace should be True And validate_assignment should be True And arbitrary_types_allowed should be False And populate_by_name should be True And use_enum_values should be True @unit @models Scenario: ModelProviderExtraAuthVars field update Given I have a ModelProviderExtraAuthVars instance When I update the var field to "NEW_VAR" Then the var field should equal "NEW_VAR" And the update should be validated @unit @models Scenario: ModelProviderConfigSchema field update Given I have a ModelProviderConfigSchema instance When I update the base_url field to "https://new-api.com" Then the base_url field should equal "https://new-api.com" And the update should be validated @unit @models Scenario: ModelProviderExtraAuthVars copy with update Given I have a ModelProviderExtraAuthVars instance When I create a copy with updated fields Then the copy should have new values And the original should remain unchanged @unit @models Scenario: ModelProviderConfigSchema copy with update Given I have a ModelProviderConfigSchema instance When I create a copy with updated fields Then the copy should have new values And the original should remain unchanged @unit @models Scenario: ModelProviderExtraAuthVars equality comparison Given I have two ModelProviderExtraAuthVars instances When I compare them for equality Then identical instances should be equal And different instances should not be equal @unit @models Scenario: ModelProviderConfigSchema equality comparison Given I have two ModelProviderConfigSchema instances When I compare them for equality Then identical instances should be equal And different instances should not be equal @unit @models Scenario: ModelProviderExtraAuthVars are not hashable Given I have ModelProviderExtraAuthVars instances When I try to use them as dictionary keys Then the instances should not work as dictionary keys And a TypeError should be raised when hashing @unit @models Scenario: ModelProviderConfigSchema validation error Given I import the ModelProviderConfigSchema class When I try to create an instance with missing required fields Then a validation error should be raised for missing fields And the error should indicate missing fields # ============================================================ # Originally from: anthropic_provider.feature # Feature: Anthropic chat provider coverage # ============================================================ @unit @providers @anthropic Scenario: Anthropic provider rejects missing API key Given I have sample provider domain inputs When I attempt to create an Anthropic chat provider without an API key Then the Anthropic provider creation should fail with "Anthropic API key is required" @unit @providers @anthropic Scenario: Anthropic provider forwards keyword overrides to ChatAnthropic Given I have sample provider domain inputs When I create an Anthropic chat provider with API key "sk-anthropic-unit" and model "claude-3-5-sonnet-20241022" with custom overrides And I request plan generation from the Anthropic provider Then the Anthropic provider should construct ChatAnthropic with api key "sk-anthropic-unit" and model "claude-3-5-sonnet-20241022" And the Anthropic provider should apply the custom overrides to ChatAnthropic And the Anthropic provider metadata should report name "anthropic" and model "claude-3-5-sonnet-20241022" # ============================================================ # Originally from: google_provider.feature # Feature: Google provider adapter coverage # ============================================================ @unit @providers @google Scenario: Google provider instantiates ChatGoogleGenerativeAI with provided credentials Given I have sample provider domain inputs When I create a Google chat provider with API key "sk-google-unit" and model "gemini-2.0-flash" And I request plan generation from the Google provider Then the Google provider should construct ChatGoogleGenerativeAI with api key "sk-google-unit" and model "gemini-2.0-flash" And the Google provider metadata should report name "google" and model "gemini-2.0-flash" @unit @providers @google Scenario: Google provider forwards extra kwargs to ChatGoogleGenerativeAI Given I have sample provider domain inputs And I set the Google provider extra kwargs "temperature=0.25,max_output_tokens=2048" When I create a Google chat provider with API key "sk-google-unit" and model "gemini-2.0-pro" And I request plan generation from the Google provider Then the Google provider should construct ChatGoogleGenerativeAI with api key "sk-google-unit" and model "gemini-2.0-pro" And the Google provider should include kwargs "temperature=0.25,max_output_tokens=2048" in the ChatGoogleGenerativeAI call And the Google provider metadata should report name "google" and model "gemini-2.0-pro" @unit @providers @google Scenario: Google provider returns generated changes with token count Given I have sample provider domain inputs And the plan generation graph returns a generated change for "app/google_provider.py" And the Google provider token estimator returns 256 tokens When I create a Google chat provider with API key "sk-google-unit" and model "gemini-2.0-flash" And I request plan generation from the Google provider Then the Google provider response should include 1 generated change for "app/google_provider.py" And the Google provider response token count should equal 256 @unit @providers @google Scenario: Google provider rejects missing API key Given I have sample provider domain inputs When I attempt to create a Google chat provider without an API key Then the Google provider creation should fail with error "Google API key is required" # ============================================================ # Originally from: langsmith_config.feature # Feature: LangSmith configuration detection # ============================================================ Scenario: LangSmith tracing disabled by default Given LangSmith environment is clean When I load CleverAgents settings for LangSmith Then LangSmith tracing should be disabled Scenario: LangSmith tracing enabled via LangChain env vars Given LangSmith environment is clean Given I set environment variable "LANGCHAIN_TRACING_V2" to "true" And I set environment variable "LANGCHAIN_API_KEY" to "demo-key" And I set environment variable "LANGCHAIN_PROJECT" to "langchain-env-project" When I load CleverAgents settings for LangSmith Then LangSmith tracing should be enabled Scenario: Building LangSmith config metadata Given LangSmith environment is clean Given I set environment variable "CLEVERAGENTS_LANGSMITH_ENABLED" to "true" And I set environment variable "CLEVERAGENTS_LANGSMITH_PROJECT" to "cleveragents-core" And I set environment variable "CLEVERAGENTS_LANGSMITH_API_KEY" to "demo-key" When I load CleverAgents settings for LangSmith And I build a LangSmith config with run name "demo-run" Then the LangSmith config should include tag "context-analysis" And the LangSmith config should include metadata key "langsmith_project" Scenario: LangSmith validation fails without API key Given LangSmith environment is clean Given I set environment variable "CLEVERAGENTS_LANGSMITH_ENABLED" to "true" When I load CleverAgents settings for LangSmith Then LangSmith tracing should be disabled And the LangSmith validation errors should mention "API key" Scenario: LangSmith detects LangChain variables Given LangSmith environment is clean Given I set environment variable "LANGCHAIN_TRACING_V2" to "true" And I set environment variable "LANGCHAIN_API_KEY" to "demo-key" And I set environment variable "LANGCHAIN_PROJECT" to "observability-demo" When I load CleverAgents settings for LangSmith And I build a LangSmith config with run name "auto-detected" Then LangSmith tracing should be enabled And the LangSmith config should include metadata key "langsmith_project" And the LangSmith config should include metadata value "observability-demo" for key "langsmith_project" Scenario: LangSmith synchronization sets LangChain env vars Given LangSmith environment is clean Given I set environment variable "CLEVERAGENTS_LANGSMITH_ENABLED" to "true" And I set environment variable "CLEVERAGENTS_LANGSMITH_API_KEY" to "sync-key" And I set environment variable "CLEVERAGENTS_LANGSMITH_PROJECT" to "sync-project" When I load CleverAgents settings for LangSmith Then the environment variable "LANGCHAIN_TRACING_V2" should equal "true" And the environment variable "LANGCHAIN_PROJECT" should equal "sync-project" And the environment variable "LANGCHAIN_API_KEY" should equal "sync-key" Scenario: LangSmith config includes user metadata Given LangSmith environment is clean Given I set environment variable "CLEVERAGENTS_LANGSMITH_ENABLED" to "true" And I set environment variable "CLEVERAGENTS_LANGSMITH_API_KEY" to "user-key" And I set environment variable "CLEVERAGENTS_LANGSMITH_PROJECT" to "user-project" And I set environment variable "CLEVERAGENTS_LANGSMITH_USER_ID" to "user-123" When I load CleverAgents settings for LangSmith And I build a LangSmith config with run name "user-run" Then the LangSmith config should include metadata key "user_id" And the LangSmith config should include metadata value "user-123" for key "user_id" # ============================================================ # Originally from: openrouter_provider.feature # Feature: OpenRouter provider adapter coverage # ============================================================ @unit @providers @openrouter Scenario: OpenRouter provider instantiates ChatOpenAI with provided credentials Given I have sample provider domain inputs When I create an OpenRouter chat provider with API key "sk-openrouter-unit" and model "anthropic/claude-sonnet-4-20250514" And I request plan generation from the OpenRouter provider Then the OpenRouter provider should construct ChatOpenAI with api key "sk-openrouter-unit", model "anthropic/claude-sonnet-4-20250514", and base url "https://openrouter.ai/api/v1" And the OpenRouter provider metadata should report name "openrouter" and model "anthropic/claude-sonnet-4-20250514" @unit @providers @openrouter Scenario: OpenRouter provider forwards extra kwargs and reports token usage Given I have sample provider domain inputs And the plan generation graph returns a generated change for "app/openrouter_provider.py" And the OpenRouter provider token estimator returns 512 tokens And I set the OpenRouter provider extra kwargs "temperature=0.15,max_tokens=2048" When I create an OpenRouter chat provider with API key "sk-openrouter-unit" and model "anthropic/claude-sonnet-4-20250514" And I request plan generation from the OpenRouter provider Then the OpenRouter provider should construct ChatOpenAI with api key "sk-openrouter-unit", model "anthropic/claude-sonnet-4-20250514", and base url "https://openrouter.ai/api/v1" And the OpenRouter provider should include kwargs "temperature=0.15,max_tokens=2048" in the ChatOpenAI call And the OpenRouter provider response should include 1 generated change for "app/openrouter_provider.py" And the OpenRouter provider response token count should equal 512 @unit @providers @openrouter Scenario: OpenRouter provider attaches organization headers when provided Given I have sample provider domain inputs And I set the OpenRouter provider default headers "X-Trace-ID=trace-openrouter" And I set the OpenRouter provider organization "cleveragents.dev" When I create an OpenRouter chat provider with API key "sk-openrouter-unit" and model "anthropic/claude-sonnet-4-20250514" And I request plan generation from the OpenRouter provider Then the OpenRouter provider should include headers "X-Trace-ID=trace-openrouter,HTTP-Referer=cleveragents.dev,X-Title=cleveragents.dev" in the ChatOpenAI call @unit @providers @openrouter Scenario: OpenRouter provider rejects missing API key Given I have sample provider domain inputs When I attempt to create an OpenRouter chat provider without an API key Then the OpenRouter provider creation should fail with error "OpenRouter API key is required"