fix(config): add server_url, server_token, format, and default_estimation_actor fields to Settings
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / security (push) Waiting to run
CI / quality (push) Waiting to run
CI / unit_tests (push) Waiting to run
CI / integration_tests (push) Waiting to run
CI / e2e_tests (push) Waiting to run
CI / coverage (push) Blocked by required conditions
CI / benchmark-regression (push) Blocked by required conditions
CI / benchmark-publish (push) Waiting to run
CI / build (push) Waiting to run
CI / docker (push) Blocked by required conditions
CI / helm (push) Waiting to run
CI / status-check (push) Blocked by required conditions

Reviewed and APPROVED. Closes #2870.
This commit was merged in pull request #3176.
This commit is contained in:
2026-04-05 21:09:46 +00:00
committed by Forgejo
3 changed files with 278 additions and 0 deletions
@@ -0,0 +1,89 @@
Feature: Settings class spec-required env var fields
The Settings class must expose fields for all spec-required environment
variables: CLEVERAGENTS_SERVER_URL, CLEVERAGENTS_SERVER_TOKEN,
CLEVERAGENTS_FORMAT, and CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR.
Background:
Given no CleverAgents spec-field env vars are set
# ── server_url ──────────────────────────────────────────────────────────────
Scenario: server_url defaults to None when env var is absent
When I instantiate Settings for spec fields
Then settings.server_url should be None
Scenario: server_url reads CLEVERAGENTS_SERVER_URL from environment
Given the environment variable "CLEVERAGENTS_SERVER_URL" is set to "https://ca.example.com"
When I instantiate Settings for spec fields
Then settings.server_url should be "https://ca.example.com"
Scenario: server_url accepts any string value
Given the environment variable "CLEVERAGENTS_SERVER_URL" is set to "http://localhost:9000"
When I instantiate Settings for spec fields
Then settings.server_url should be "http://localhost:9000"
# ── server_token ─────────────────────────────────────────────────────────────
Scenario: server_token defaults to None when env var is absent
When I instantiate Settings for spec fields
Then settings.server_token should be None
Scenario: server_token reads CLEVERAGENTS_SERVER_TOKEN from environment
Given the environment variable "CLEVERAGENTS_SERVER_TOKEN" is set to "secret-token-abc"
When I instantiate Settings for spec fields
Then settings.server_token should be "secret-token-abc"
Scenario: server_token accepts any string value
Given the environment variable "CLEVERAGENTS_SERVER_TOKEN" is set to "bearer-xyz-789"
When I instantiate Settings for spec fields
Then settings.server_token should be "bearer-xyz-789"
# ── format ───────────────────────────────────────────────────────────────────
Scenario: format defaults to None when env var is absent
When I instantiate Settings for spec fields
Then settings.format should be None
Scenario: format reads CLEVERAGENTS_FORMAT from environment
Given the environment variable "CLEVERAGENTS_FORMAT" is set to "json"
When I instantiate Settings for spec fields
Then settings.format should be "json"
Scenario: format accepts any string value
Given the environment variable "CLEVERAGENTS_FORMAT" is set to "markdown"
When I instantiate Settings for spec fields
Then settings.format should be "markdown"
# ── default_estimation_actor ─────────────────────────────────────────────────
Scenario: default_estimation_actor defaults to None when env var is absent
When I instantiate Settings for spec fields
Then settings.default_estimation_actor should be None
Scenario: default_estimation_actor reads CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR from environment
Given the environment variable "CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR" is set to "gpt-estimator"
When I instantiate Settings for spec fields
Then settings.default_estimation_actor should be "gpt-estimator"
Scenario: default_estimation_actor accepts any string value
Given the environment variable "CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR" is set to "claude-estimator"
When I instantiate Settings for spec fields
Then settings.default_estimation_actor should be "claude-estimator"
# ── model_fields presence ────────────────────────────────────────────────────
Scenario: all four spec fields appear in Settings.model_fields
When I inspect Settings.model_fields
Then "server_url" should be present in model_fields
And "server_token" should be present in model_fields
And "format" should be present in model_fields
And "default_estimation_actor" should be present in model_fields
# ── type annotation ──────────────────────────────────────────────────────────
Scenario: all four spec fields are typed as str or None
When I instantiate Settings for spec fields
Then settings.server_url should be of type str or None
And settings.server_token should be of type str or None
And settings.format should be of type str or None
And settings.default_estimation_actor should be of type str or None
@@ -0,0 +1,155 @@
"""Step definitions for Settings spec-required env var fields (issue #2866)."""
from __future__ import annotations
import os
from behave import given, then, when
from cleveragents.config.settings import Settings
_SPEC_FIELD_ENV_VARS = [
"CLEVERAGENTS_SERVER_URL",
"CLEVERAGENTS_SERVER_TOKEN",
"CLEVERAGENTS_FORMAT",
"CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR",
]
@given("no CleverAgents spec-field env vars are set")
def step_clear_spec_field_env_vars(context):
"""Remove all spec-field env vars so Settings starts from a clean slate."""
for key in _SPEC_FIELD_ENV_VARS:
os.environ.pop(key, None)
if not hasattr(context, "env_vars_to_clean"):
context.env_vars_to_clean = []
context.env_vars_to_clean.extend(_SPEC_FIELD_ENV_VARS)
@when("I instantiate Settings for spec fields")
def step_instantiate_settings_for_spec_fields(context):
"""Create a fresh Settings instance (bypassing the singleton)."""
Settings._instance = None
context.settings = Settings()
@when("I inspect Settings.model_fields")
def step_inspect_model_fields(context):
"""Capture the model_fields mapping for assertion."""
context.model_fields = Settings.model_fields
# ── server_url assertions ────────────────────────────────────────────────────
@then("settings.server_url should be None")
def step_server_url_is_none(context):
assert context.settings.server_url is None, (
f"Expected server_url to be None, got {context.settings.server_url!r}"
)
@then('settings.server_url should be "{expected}"')
def step_server_url_equals(context, expected):
assert context.settings.server_url == expected, (
f"Expected server_url={expected!r}, got {context.settings.server_url!r}"
)
# ── server_token assertions ──────────────────────────────────────────────────
@then("settings.server_token should be None")
def step_server_token_is_none(context):
assert context.settings.server_token is None, (
f"Expected server_token to be None, got {context.settings.server_token!r}"
)
@then('settings.server_token should be "{expected}"')
def step_server_token_equals(context, expected):
assert context.settings.server_token == expected, (
f"Expected server_token={expected!r}, got {context.settings.server_token!r}"
)
# ── format assertions ────────────────────────────────────────────────────────
@then("settings.format should be None")
def step_format_is_none(context):
assert context.settings.format is None, (
f"Expected format to be None, got {context.settings.format!r}"
)
@then('settings.format should be "{expected}"')
def step_format_equals(context, expected):
assert context.settings.format == expected, (
f"Expected format={expected!r}, got {context.settings.format!r}"
)
# ── default_estimation_actor assertions ──────────────────────────────────────
@then("settings.default_estimation_actor should be None")
def step_default_estimation_actor_is_none(context):
assert context.settings.default_estimation_actor is None, (
"Expected default_estimation_actor to be None, "
f"got {context.settings.default_estimation_actor!r}"
)
@then('settings.default_estimation_actor should be "{expected}"')
def step_default_estimation_actor_equals(context, expected):
assert context.settings.default_estimation_actor == expected, (
f"Expected default_estimation_actor={expected!r}, "
f"got {context.settings.default_estimation_actor!r}"
)
# ── model_fields presence assertions ─────────────────────────────────────────
@then('"{field_name}" should be present in model_fields')
def step_field_in_model_fields(context, field_name):
assert field_name in context.model_fields, (
f"Expected '{field_name}' to be in Settings.model_fields, "
f"but only found: {sorted(context.model_fields.keys())}"
)
# ── type annotation assertions ───────────────────────────────────────────────
@then("settings.server_url should be of type str or None")
def step_server_url_type(context):
value = context.settings.server_url
assert value is None or isinstance(value, str), (
f"Expected server_url to be str | None, got {type(value)}"
)
@then("settings.server_token should be of type str or None")
def step_server_token_type(context):
value = context.settings.server_token
assert value is None or isinstance(value, str), (
f"Expected server_token to be str | None, got {type(value)}"
)
@then("settings.format should be of type str or None")
def step_format_type(context):
value = context.settings.format
assert value is None or isinstance(value, str), (
f"Expected format to be str | None, got {type(value)}"
)
@then("settings.default_estimation_actor should be of type str or None")
def step_default_estimation_actor_type(context):
value = context.settings.default_estimation_actor
assert value is None or isinstance(value, str), (
f"Expected default_estimation_actor to be str | None, got {type(value)}"
)
+34
View File
@@ -111,11 +111,45 @@ class Settings(BaseSettings):
default=False,
validation_alias=AliasChoices("CLEVERAGENTS_SERVER_RELOAD"),
)
server_url: str | None = Field(
default=None,
validation_alias=AliasChoices("CLEVERAGENTS_SERVER_URL"),
description=(
"URL for the CleverAgents server endpoint, enabling server mode. "
"Maps to the spec's server.url config key."
),
)
server_token: str | None = Field(
default=None,
validation_alias=AliasChoices("CLEVERAGENTS_SERVER_TOKEN"),
description=(
"Authentication token for connecting to the CleverAgents server. "
"Maps to the spec's server.token config key."
),
)
debug_enabled: bool = Field(
default=False,
validation_alias=AliasChoices("CLEVERAGENTS_DEBUG_ENABLED"),
)
# Core output and estimation configuration
format: str | None = Field(
default=None,
validation_alias=AliasChoices("CLEVERAGENTS_FORMAT"),
description=(
"Default output format (e.g. 'json', 'markdown', 'text'). "
"Overrides the core.format config key when set."
),
)
default_estimation_actor: str | None = Field(
default=None,
validation_alias=AliasChoices("CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR"),
description=(
"Default actor used for estimation tasks. "
"Maps to the spec's core.default_estimation_actor config key."
),
)
# Logging/paths
log_level: str = Field(
default="INFO",