650b1038b6
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Failing after 19s
CI / typecheck (pull_request) Failing after 56s
CI / security (pull_request) Failing after 56s
CI / coverage (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped
CI / unit_tests (pull_request) Failing after 2m4s
CI / docker (pull_request) Has been skipped
CI / build (pull_request) Successful in 16s
CI / helm (pull_request) Successful in 23s
CI / quality (pull_request) Successful in 3m42s
CI / e2e_tests (pull_request) Failing after 15m14s
CI / integration_tests (pull_request) Failing after 22m3s
CI / status-check (pull_request) Failing after 1s
Introduce DomainBaseModel in src/cleveragents/domain/models/base.py that defines the single shared model_config (str_strip_whitespace, validate_assignment, arbitrary_types_allowed=False, populate_by_name, use_enum_values) previously duplicated verbatim across five domain model files. Update 14 classes across five files to inherit from DomainBaseModel instead of pydantic.BaseModel directly, removing all inline model_config duplication: - aimodelscredentials/ai_models_credentials.py (ModelProviderOption) - aimodelserrors/ai_models_errors.py (ModelError, FallbackResult) - aimodelsproviders/ai_models_providers.py (ModelProviderExtraAuthVars, ModelProviderConfigSchema) - auth/auth.py (AuthHeader, TrialPlansExceededError, TrialMessagesExceededError, BillingError, ApiError, ClientAccount, ClientAuth) - planconfig/plan_config.py (PlanConfig, ConfigSetting) Pure structural refactor — no behavioral changes. Models with different configurations (acms, aimodels_custom, etc.) are left untouched. Add BDD feature (22 scenarios) and Robot integration tests (8 test cases) verifying inheritance, config correctness, and no-duplication invariants. ISSUES CLOSED: #1941
240 lines
7.2 KiB
Python
240 lines
7.2 KiB
Python
"""Helper script for DomainBaseModel Robot integration tests.
|
|
|
|
Verifies that the structural refactor (extracting shared model_config into
|
|
DomainBaseModel) has not changed the observable behaviour of any affected
|
|
domain model class.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
|
|
from pydantic import BaseModel
|
|
|
|
from cleveragents.domain.models.base import DomainBaseModel
|
|
|
|
|
|
def _test_domain_base_model_importable() -> None:
|
|
"""DomainBaseModel is importable and is a pydantic BaseModel subclass."""
|
|
assert issubclass(DomainBaseModel, BaseModel)
|
|
print("domain-base-model-importable-ok")
|
|
|
|
|
|
def _test_domain_base_model_config() -> None:
|
|
"""DomainBaseModel carries the expected shared model_config."""
|
|
cfg = DomainBaseModel.model_config
|
|
assert cfg.get("str_strip_whitespace") is True
|
|
assert cfg.get("validate_assignment") is True
|
|
assert cfg.get("arbitrary_types_allowed") is False
|
|
assert cfg.get("populate_by_name") is True
|
|
assert cfg.get("use_enum_values") is True
|
|
print("domain-base-model-config-ok")
|
|
|
|
|
|
def _test_model_provider_option() -> None:
|
|
"""ModelProviderOption behaviour is unchanged after refactor."""
|
|
from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import (
|
|
ModelProviderOption,
|
|
)
|
|
from cleveragents.domain.models.aimodelsproviders.ai_models_providers import (
|
|
ModelProviderConfigSchema,
|
|
)
|
|
from cleveragents.domain.models.core.enums import ModelProvider, ModelPublisher
|
|
|
|
assert issubclass(ModelProviderOption, DomainBaseModel)
|
|
|
|
config = ModelProviderConfigSchema(
|
|
provider=ModelProvider.OPENAI, baseUrl="https://api.openai.com/v1"
|
|
)
|
|
publishers = {"primary": {ModelPublisher.OPENAI: True}}
|
|
model = ModelProviderOption(publishers=publishers, config=config, priority=1)
|
|
|
|
assert model.priority == 1
|
|
assert model.config is not None
|
|
assert model.config.base_url == "https://api.openai.com/v1"
|
|
# Verify str_strip_whitespace is active via inherited config
|
|
assert model.model_config.get("str_strip_whitespace") is True
|
|
print("model-provider-option-ok")
|
|
|
|
|
|
def _test_model_error() -> None:
|
|
"""ModelError behaviour is unchanged after refactor."""
|
|
from cleveragents.domain.models.aimodelserrors.ai_models_errors import ModelError
|
|
from cleveragents.domain.models.core.enums import ModelErrKind
|
|
|
|
assert issubclass(ModelError, DomainBaseModel)
|
|
|
|
err = ModelError(kind=ModelErrKind.OVERLOADED, retriable=True, retryafterseconds=30)
|
|
assert err.retriable is True
|
|
assert err.retryafterseconds == 30
|
|
print("model-error-ok")
|
|
|
|
|
|
def _test_fallback_result() -> None:
|
|
"""FallbackResult behaviour is unchanged after refactor."""
|
|
from cleveragents.domain.models.aimodelserrors.ai_models_errors import (
|
|
FallbackResult,
|
|
)
|
|
from cleveragents.domain.models.core.enums import FallbackType
|
|
|
|
assert issubclass(FallbackResult, DomainBaseModel)
|
|
|
|
result = FallbackResult(
|
|
fallbacktype=FallbackType.ERROR,
|
|
isfallback=True,
|
|
modelroleconfig=None,
|
|
basemodelconfig=None,
|
|
)
|
|
assert result.isfallback is True
|
|
print("fallback-result-ok")
|
|
|
|
|
|
def _test_auth_models() -> None:
|
|
"""Auth model behaviour is unchanged after refactor."""
|
|
from cleveragents.domain.models.auth.auth import (
|
|
ApiError,
|
|
ApiErrorType,
|
|
AuthHeader,
|
|
BillingError,
|
|
ClientAccount,
|
|
ClientAuth,
|
|
TrialMessagesExceededError,
|
|
TrialPlansExceededError,
|
|
)
|
|
|
|
for cls in (
|
|
AuthHeader,
|
|
TrialPlansExceededError,
|
|
TrialMessagesExceededError,
|
|
BillingError,
|
|
ApiError,
|
|
ClientAccount,
|
|
ClientAuth,
|
|
):
|
|
assert issubclass(cls, DomainBaseModel), f"{cls.__name__} not DomainBaseModel"
|
|
|
|
header = AuthHeader(token="tok", orgId="org-1", hash="abc")
|
|
assert header.org_id == "org-1"
|
|
|
|
trial_plans = TrialPlansExceededError(maxPlans=5)
|
|
assert trial_plans.max_plans == 5
|
|
|
|
trial_msgs = TrialMessagesExceededError(maxMessages=100)
|
|
assert trial_msgs.max_messages == 100
|
|
|
|
billing = BillingError(hasBillingPermission=False, isTrial=True)
|
|
assert billing.is_trial is True
|
|
|
|
api_err = ApiError(type_=ApiErrorType.AUTH, status=401, msg="Unauthorized")
|
|
assert api_err.status == 401
|
|
|
|
account = ClientAccount(
|
|
isCloud=True,
|
|
host="app.cleverthis.com",
|
|
email="user@example.com",
|
|
userName="testuser",
|
|
userId="uid-1",
|
|
token="tok-1",
|
|
isLocalMode=False,
|
|
isTrial=False,
|
|
)
|
|
assert account.is_cloud is True
|
|
|
|
auth = ClientAuth(
|
|
orgId="org-1",
|
|
orgName="Test Org",
|
|
orgIsTrial=False,
|
|
integratedModelsMode=True,
|
|
)
|
|
assert auth.org_name == "Test Org"
|
|
|
|
print("auth-models-ok")
|
|
|
|
|
|
def _test_plan_config_models() -> None:
|
|
"""PlanConfig and ConfigSetting behaviour is unchanged after refactor."""
|
|
from cleveragents.domain.models.planconfig.plan_config import (
|
|
AutoModeType,
|
|
ConfigSetting,
|
|
PlanConfig,
|
|
)
|
|
|
|
assert issubclass(PlanConfig, DomainBaseModel)
|
|
assert issubclass(ConfigSetting, DomainBaseModel)
|
|
|
|
plan = PlanConfig(
|
|
autoMode=AutoModeType.AUTO,
|
|
editor="vim",
|
|
editorCommand="vim",
|
|
editorOpenManually=False,
|
|
autoContinue=True,
|
|
autoBuild=False,
|
|
autoUpdateContext=True,
|
|
autoContext=True,
|
|
smartContext=True,
|
|
autoApply=False,
|
|
autoCommit=False,
|
|
skipCommit=False,
|
|
canExec=True,
|
|
autoExec=False,
|
|
autoDebug=False,
|
|
autoDebugTries=3,
|
|
autoRevertOnRewind=False,
|
|
skipChangesMenu=False,
|
|
)
|
|
assert plan.editor == "vim"
|
|
assert plan.auto_mode == AutoModeType.AUTO
|
|
|
|
setting = ConfigSetting(
|
|
name="autoMode",
|
|
desc="Auto mode setting",
|
|
hascustomchoice=False,
|
|
sortkey="a",
|
|
)
|
|
assert setting.name == "autoMode"
|
|
|
|
print("plan-config-models-ok")
|
|
|
|
|
|
def _test_whitespace_stripping() -> None:
|
|
"""str_strip_whitespace is active on all refactored models."""
|
|
from cleveragents.domain.models.aimodelsproviders.ai_models_providers import (
|
|
ModelProviderConfigSchema,
|
|
)
|
|
from cleveragents.domain.models.core.enums import ModelProvider
|
|
|
|
schema = ModelProviderConfigSchema(
|
|
provider=ModelProvider.OPENAI,
|
|
baseUrl=" https://api.openai.com/v1 ",
|
|
)
|
|
assert schema.base_url == "https://api.openai.com/v1", (
|
|
f"Expected stripped URL, got: {schema.base_url!r}"
|
|
)
|
|
print("whitespace-stripping-ok")
|
|
|
|
|
|
_COMMANDS: dict[str, object] = {
|
|
"importable": _test_domain_base_model_importable,
|
|
"config": _test_domain_base_model_config,
|
|
"model-provider-option": _test_model_provider_option,
|
|
"model-error": _test_model_error,
|
|
"fallback-result": _test_fallback_result,
|
|
"auth-models": _test_auth_models,
|
|
"plan-config-models": _test_plan_config_models,
|
|
"whitespace-stripping": _test_whitespace_stripping,
|
|
}
|
|
|
|
|
|
def main() -> None:
|
|
if len(sys.argv) < 2:
|
|
raise SystemExit("Expected command argument")
|
|
command = sys.argv[1]
|
|
fn = _COMMANDS.get(command)
|
|
if fn is None:
|
|
raise SystemExit(f"Unknown helper command: {command!r}")
|
|
fn() # type: ignore[operator]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|