Files
llm-connect/tests/test_models.py
Bernd Worsch d71f4114d1 feat: WP-0001 foundation + WP-0002 core extensions
WP-0001 — Foundation & GAAF Baseline
- SCOPE.md, ARCHITECTURE-LAYERS.md, contracts/ tree
- .claude/rules/ stubs filled (architecture, stack, boundary)
- 57 tests (pytest), pyproject.toml with ruff+mypy, CI workflow

WP-0002 — Core Extensions (FR-4 + FR-3)
- FR-4: BudgetTracker (thread-safe) + LLMBudgetExceededError +
  optional RunConfig.budget_tracker + enforcement in all adapters
- FR-3: async_execute_prompt on LLMAdapter ABC (asyncio.to_thread
  fallback) + native asyncio.create_subprocess_exec in ClaudeCodeAdapter

81 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 22:24:14 +00:00

87 lines
2.9 KiB
Python

"""
Tests for RunConfig and LLMResponse (Core models).
"""
import pytest
from llm_connect.models import RunConfig, LLMResponse
class TestRunConfig:
def test_defaults(self):
cfg = RunConfig()
assert cfg.model_name == "gpt-4"
assert cfg.temperature == 0.7
assert cfg.max_tokens == 2000
assert cfg.model_params == {}
assert cfg.max_depth == 3
assert cfg.skip_if_exists is True
assert cfg.timeout_seconds == 300
def test_custom_values(self):
cfg = RunConfig(model_name="gemini-2.5-flash", temperature=0.1, max_tokens=500)
assert cfg.model_name == "gemini-2.5-flash"
assert cfg.temperature == 0.1
assert cfg.max_tokens == 500
def test_to_dict_roundtrip(self):
cfg = RunConfig(model_name="gpt-4o", temperature=0.3, max_tokens=1000)
d = cfg.to_dict()
assert d["model_name"] == "gpt-4o"
assert d["temperature"] == 0.3
assert d["max_tokens"] == 1000
def test_from_dict_roundtrip(self):
original = RunConfig(model_name="claude-3", temperature=0.5, max_tokens=800)
restored = RunConfig.from_dict(original.to_dict())
assert restored.model_name == original.model_name
assert restored.temperature == original.temperature
assert restored.max_tokens == original.max_tokens
def test_from_dict_uses_defaults_for_missing_keys(self):
cfg = RunConfig.from_dict({})
assert cfg.model_name == "gpt-4"
assert cfg.temperature == 0.7
def test_model_params_default_is_independent(self):
a = RunConfig()
b = RunConfig()
a.model_params["x"] = 1
assert "x" not in b.model_params
class TestLLMResponse:
def test_minimal_construction(self):
r = LLMResponse(content="hello", model="test-model")
assert r.content == "hello"
assert r.model == "test-model"
assert r.usage == {}
assert r.finish_reason == "stop"
assert r.metadata == {}
def test_full_construction(self):
r = LLMResponse(
content="response text",
model="gpt-4",
usage={"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15},
finish_reason="length",
metadata={"provider": "openai", "latency_seconds": 1.2},
)
assert r.usage["total_tokens"] == 15
assert r.finish_reason == "length"
assert r.metadata["provider"] == "openai"
def test_to_dict(self):
r = LLMResponse(content="hi", model="m", finish_reason="stop")
d = r.to_dict()
assert d["content"] == "hi"
assert d["model"] == "m"
assert d["finish_reason"] == "stop"
assert "usage" in d
assert "metadata" in d
def test_metadata_default_is_independent(self):
a = LLMResponse(content="a", model="m")
b = LLMResponse(content="b", model="m")
a.metadata["x"] = 1
assert "x" not in b.metadata