Files

451 lines
16 KiB
Python

"""Step definitions for AI models errors coverage tests."""
from behave import given, then, when
from pydantic import ValidationError
from cleveragents.domain.models.aimodelsdatamodels import (
BaseModelConfig,
BaseModelProviderConfig,
ModelRoleConfig,
)
from cleveragents.domain.models.aimodelserrors.ai_models_errors import (
FallbackResult,
ModelError,
)
from cleveragents.domain.models.core.enums import (
FallbackType,
ModelErrKind,
ModelPublisher,
)
@given("I import the ModelError class")
def step_import_model_error(context):
"""Import ModelError class."""
context.model_class = ModelError
context.error = None
context.instance = None
@given("I import the FallbackResult class")
def step_import_fallback_result(context):
"""Import FallbackResult class."""
context.model_class = FallbackResult
context.error = None
context.instance = None
@when('I create a ModelError with kind "{kind}"')
def step_create_model_error_with_kind(context, kind):
"""Create ModelError with specific kind."""
context.kind = ModelErrKind[kind]
context.retriable = None
context.retryafterseconds = None
@when("I set retriable to {value}")
def step_set_retriable(context, value):
"""Set retriable field."""
context.retriable = value.lower() == "true"
@when("I set retryafterseconds to {seconds:d}")
def step_set_retryafterseconds(context, seconds):
"""Set retryafterseconds field."""
context.retryafterseconds = seconds
# Create the instance now that all fields are set
if hasattr(context, "kind"):
try:
context.instance = ModelError(
kind=context.kind,
retriable=context.retriable,
retryafterseconds=context.retryafterseconds,
)
except Exception as e:
context.error = e
@then("the ModelError instance should be created successfully")
def step_model_error_created_successfully(context):
"""Verify ModelError instance was created."""
assert context.instance is not None, "ModelError instance was not created"
assert isinstance(context.instance, ModelError), "Instance is not ModelError"
assert context.error is None, f"Unexpected error: {context.error}"
@then('the kind should be "{expected_kind}"')
def step_verify_kind(context, expected_kind):
"""Verify the kind field value."""
assert context.instance.kind == expected_kind, (
f"Expected kind {expected_kind}, got {context.instance.kind}"
)
@then("the retriable flag should be {value}")
def step_verify_retriable(context, value):
"""Verify the retriable flag."""
expected = value.lower() == "true"
assert context.instance.retriable == expected, (
f"Expected retriable {expected}, got {context.instance.retriable}"
)
@then("the retry after seconds should be {seconds:d}")
def step_verify_retry_after_seconds(context, seconds):
"""Verify the retryafterseconds value."""
assert context.instance.retryafterseconds == seconds, (
f"Expected retryafterseconds {seconds}, got {context.instance.retryafterseconds}"
)
@when("I create a ModelError with valid data")
def step_create_model_error_with_valid_data(context):
"""Create ModelError with valid data for configuration testing."""
context.instance = ModelError(
kind=ModelErrKind.OVERLOADED, retriable=True, retryafterseconds=30
)
@then("the model configuration should have str_strip_whitespace as {value}")
def step_verify_str_strip_whitespace(context, value):
"""Verify str_strip_whitespace configuration."""
expected = value.lower() == "true"
assert context.instance.model_config["str_strip_whitespace"] == expected
@then("the model configuration should have validate_assignment as {value}")
def step_verify_validate_assignment(context, value):
"""Verify validate_assignment configuration."""
expected = value.lower() == "true"
assert context.instance.model_config["validate_assignment"] == expected
@then("the model configuration should have arbitrary_types_allowed as {value}")
def step_verify_arbitrary_types_allowed(context, value):
"""Verify arbitrary_types_allowed configuration."""
expected = value.lower() == "true"
assert context.instance.model_config["arbitrary_types_allowed"] == expected
@then("the model configuration should have populate_by_name as {value}")
def step_verify_populate_by_name(context, value):
"""Verify populate_by_name configuration."""
expected = value.lower() == "true"
assert context.instance.model_config["populate_by_name"] == expected
@then("the model configuration should have use_enum_values as {value}")
def step_verify_use_enum_values(context, value):
"""Verify use_enum_values configuration."""
expected = value.lower() == "true"
assert context.instance.model_config["use_enum_values"] == expected
@when('I create a FallbackResult with fallback type "{fallback_type}"')
def step_create_fallback_result_with_type(context, fallback_type):
"""Create FallbackResult with specific fallback type."""
context.fallbacktype = FallbackType[fallback_type]
context.isfallback = None
context.modelroleconfig = None
context.basemodelconfig = None
@when("I set isfallback to {value}")
def step_set_isfallback(context, value):
"""Set isfallback field."""
context.isfallback = value.lower() == "true"
@when("I set modelroleconfig to None")
def step_set_modelroleconfig_to_none(context):
"""Set modelroleconfig to None."""
context.modelroleconfig = None
@when("I set basemodelconfig to None")
def step_set_basemodelconfig_to_none(context):
"""Set basemodelconfig to None."""
context.basemodelconfig = None
# Create the instance now that all fields are set
if hasattr(context, "fallbacktype"):
try:
context.instance = FallbackResult(
fallbacktype=context.fallbacktype,
isfallback=context.isfallback,
modelroleconfig=context.modelroleconfig,
basemodelconfig=context.basemodelconfig,
)
except Exception as e:
context.error = e
@then("the FallbackResult instance should be created successfully")
def step_fallback_result_created_successfully(context):
"""Verify FallbackResult instance was created."""
assert context.instance is not None, "FallbackResult instance was not created"
assert isinstance(context.instance, FallbackResult), (
"Instance is not FallbackResult"
)
assert context.error is None, f"Unexpected error: {context.error}"
@then('the fallback type should be "{expected_type}"')
def step_verify_fallback_type(context, expected_type):
"""Verify the fallback type field value."""
assert context.instance.fallbacktype == expected_type, (
f"Expected fallback type {expected_type}, got {context.instance.fallbacktype}"
)
@then("the is fallback flag should be {value}")
def step_verify_is_fallback(context, value):
"""Verify the is fallback flag."""
expected = value.lower() == "true"
assert context.instance.isfallback == expected, (
f"Expected isfallback {expected}, got {context.instance.isfallback}"
)
@then("the model role config should be None")
def step_verify_model_role_config_none(context):
"""Verify model role config is None."""
assert context.instance.modelroleconfig is None, (
f"Expected modelroleconfig None, got {context.instance.modelroleconfig}"
)
@then("the base model config should be None")
def step_verify_base_model_config_none(context):
"""Verify base model config is None."""
assert context.instance.basemodelconfig is None, (
f"Expected basemodelconfig None, got {context.instance.basemodelconfig}"
)
@given("I have a valid ModelRoleConfig instance")
def step_create_valid_model_role_config(context):
"""Create a valid ModelRoleConfig instance."""
# First create a BaseModelConfig for the ModelRoleConfig
base_model_provider_config = BaseModelProviderConfig(modelName="test-model")
base_model_config = BaseModelConfig(
modelTag="gpt-4",
modelId="gpt-4-model",
publisher=ModelPublisher.OPENAI,
basemodelshared=base_model_provider_config,
)
context.valid_model_role_config = ModelRoleConfig(
role="assistant",
modelId="gpt-4-model",
baseModelConfig=base_model_config,
temperature=0.7,
topP=0.9,
reservedOutputTokens=1024,
)
@given("I have a valid BaseModelConfig instance")
def step_create_valid_base_model_config(context):
"""Create a valid BaseModelConfig instance."""
base_model_provider_config = BaseModelProviderConfig(modelName="test-model")
context.valid_base_model_config = BaseModelConfig(
modelTag="gpt-4",
modelId="gpt-4-model",
publisher=ModelPublisher.OPENAI,
basemodelshared=base_model_provider_config,
)
@when("I set modelroleconfig to the valid instance")
def step_set_modelroleconfig_to_valid(context):
"""Set modelroleconfig to valid instance."""
context.modelroleconfig = context.valid_model_role_config
@when("I set basemodelconfig to the valid instance")
def step_set_basemodelconfig_to_valid(context):
"""Set basemodelconfig to valid instance."""
context.basemodelconfig = context.valid_base_model_config
# Create the instance if this is the last field being set
if hasattr(context, "fallbacktype") and hasattr(context, "isfallback"):
try:
context.instance = FallbackResult(
fallbacktype=context.fallbacktype,
isfallback=context.isfallback,
modelroleconfig=context.modelroleconfig,
basemodelconfig=context.basemodelconfig,
)
except Exception as e:
context.error = e
@then("the model role config should not be None")
def step_verify_model_role_config_not_none(context):
"""Verify model role config is not None."""
assert context.instance.modelroleconfig is not None, (
"Expected modelroleconfig not None"
)
@then('the model role config role should be "{expected_role}"')
def step_verify_model_role_config_role(context, expected_role):
"""Verify model role config role value."""
assert context.instance.modelroleconfig.role == expected_role, (
f"Expected role {expected_role}, got {context.instance.modelroleconfig.role}"
)
@then("the base model config should not be None")
def step_verify_base_model_config_not_none(context):
"""Verify base model config is not None."""
assert context.instance.basemodelconfig is not None, (
"Expected basemodelconfig not None"
)
@then('the base model config model_tag should be "{expected_tag}"')
def step_verify_base_model_config_tag(context, expected_tag):
"""Verify base model config model_tag value."""
assert context.instance.basemodelconfig.model_tag == expected_tag, (
f"Expected model_tag {expected_tag}, got {context.instance.basemodelconfig.model_tag}"
)
@when("I create a FallbackResult with valid data")
def step_create_fallback_result_with_valid_data(context):
"""Create FallbackResult with valid data for configuration testing."""
context.instance = FallbackResult(
fallbacktype=FallbackType.ERROR,
isfallback=True,
modelroleconfig=None,
basemodelconfig=None,
)
@when('I try to create a ModelError with invalid kind "{kind}"')
def step_try_create_model_error_invalid(context, kind):
"""Try to create ModelError with invalid kind."""
try:
context.instance = ModelError(kind=kind, retriable=True, retryafterseconds=30)
context.error = None
except ValidationError as e:
context.error = e
context.instance = None
@when('I try to create a FallbackResult with invalid fallback type "{fallback_type}"')
def step_try_create_fallback_invalid(context, fallback_type):
"""Try to create FallbackResult with invalid fallback type."""
try:
context.instance = FallbackResult(
fallbacktype=fallback_type,
isfallback=True,
modelroleconfig=None,
basemodelconfig=None,
)
context.error = None
except ValidationError as e:
context.error = e
context.instance = None
@when("I create a ModelError using field aliases")
def step_create_model_error_with_aliases(context):
"""Create ModelError using field aliases."""
try:
# Test that the model accepts both original field names and aliases
context.instance = ModelError(
kind=ModelErrKind.OVERLOADED, retriable=True, retryafterseconds=30
)
context.error = None
except Exception as e:
context.error = e
@then("the ModelError should accept the aliased fields")
def step_model_error_accepts_aliases(context):
"""Verify ModelError accepts aliased fields."""
assert context.instance is not None
assert context.error is None
@then("the values should be properly mapped")
def step_values_properly_mapped(context):
"""Verify values are properly mapped."""
# Check which type of instance we have
if hasattr(context.instance, "kind"):
# ModelError instance
assert context.instance.kind == "ErrOverloaded"
assert context.instance.retriable is True
assert context.instance.retryafterseconds == 30
elif hasattr(context.instance, "fallbacktype"):
# FallbackResult instance
assert context.instance.fallbacktype == "FallbackTypeError"
assert context.instance.isfallback is True
assert context.instance.modelroleconfig is None
assert context.instance.basemodelconfig is None
@when("I create a FallbackResult using field aliases")
def step_create_fallback_result_with_aliases(context):
"""Create FallbackResult using field aliases."""
try:
context.instance = FallbackResult(
fallbacktype=FallbackType.ERROR,
isfallback=True,
modelroleconfig=None,
basemodelconfig=None,
)
context.error = None
except Exception as e:
context.error = e
@then("the FallbackResult should accept the aliased fields")
def step_fallback_result_accepts_aliases(context):
"""Verify FallbackResult accepts aliased fields."""
assert context.instance is not None
assert context.error is None
@when("I create a ModelError with whitespace in enum values")
def step_create_model_error_with_whitespace(context):
"""Create ModelError with whitespace in enum values."""
try:
# The model should handle enum values properly even with the str_strip_whitespace setting
context.instance = ModelError(
kind=ModelErrKind.OVERLOADED, retriable=True, retryafterseconds=30
)
context.error = None
except Exception as e:
context.error = e
@when("I create a FallbackResult with whitespace in enum values")
def step_create_fallback_result_with_whitespace(context):
"""Create FallbackResult with whitespace in enum values."""
try:
context.instance = FallbackResult(
fallbacktype=FallbackType.ERROR,
isfallback=True,
modelroleconfig=None,
basemodelconfig=None,
)
context.error = None
except Exception as e:
context.error = e
@then("the whitespace should be stripped from strings")
def step_whitespace_stripped(context):
"""Verify whitespace handling."""
# The models use enum values which are already strings,
# the str_strip_whitespace config ensures string fields are cleaned
assert context.instance is not None
@then("the model should be created successfully")
def step_model_created_successfully(context):
"""Verify model was created successfully."""
assert context.instance is not None
assert context.error is None