Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions codeframe/adapters/llm/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ class Purpose(str, Enum):


# Default model aliases (use valid Anthropic model identifiers)
DEFAULT_PLANNING_MODEL = "claude-sonnet-4-20250514"
DEFAULT_EXECUTION_MODEL = "claude-sonnet-4-20250514"
DEFAULT_GENERATION_MODEL = "claude-3-5-haiku-20241022"
DEFAULT_CORRECTION_MODEL = "claude-opus-4-20250514" # Step up for fixing errors
DEFAULT_SUPERVISION_MODEL = "claude-opus-4-20250514" # Strong model for supervisor decisions
DEFAULT_PLANNING_MODEL = "claude-sonnet-4-5"
DEFAULT_EXECUTION_MODEL = "claude-sonnet-4-5"
DEFAULT_GENERATION_MODEL = "claude-haiku-4-5"
DEFAULT_CORRECTION_MODEL = "claude-sonnet-4-5" # Use same tier; override via CODEFRAME_CORRECTION_MODEL for a stronger model
DEFAULT_SUPERVISION_MODEL = "claude-sonnet-4-5" # Use same tier; override via CODEFRAME_SUPERVISION_MODEL for a stronger model


@dataclass
Expand Down
11 changes: 6 additions & 5 deletions codeframe/core/adapters/streaming_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
# Default model (matches DEFAULT_PLANNING_MODEL in base.py)
# ---------------------------------------------------------------------------

_DEFAULT_MODEL = "claude-sonnet-4-20250514"
_DEFAULT_MODEL = "claude-sonnet-4-5"

# Maximum token budget for conversation history passed to the API.
# claude-sonnet-4 context window is 200k; leave 20k for response headroom.
Expand Down Expand Up @@ -465,15 +465,16 @@ async def _stream_turn(
def _estimate_cost(input_tokens: int, output_tokens: int, model: str) -> float:
"""Rough cost estimate in USD.

Uses approximate pricing for claude-sonnet-4. Returns 0.0 for unknown models
Uses approximate pricing for claude-sonnet-4-5. Returns 0.0 for unknown models
rather than raising — cost tracking is best-effort.
"""
# Per-million-token pricing (input, output) in USD.
# Last verified: 2026-03-31. Anthropic pricing changes without notice —
# Last verified: 2026-06-21. Anthropic pricing changes without notice —
# treat these as best-effort estimates, not billing-accurate figures.
_PRICING: dict[str, tuple[float, float]] = {
"claude-sonnet-4-20250514": (3.0, 15.0),
"claude-opus-4-20250514": (15.0, 75.0),
"claude-sonnet-4-5": (3.0, 15.0),
"claude-opus-4-5": (15.0, 75.0),
"claude-haiku-4-5": (0.8, 4.0),
"claude-3-5-haiku-20241022": (0.8, 4.0),
}
# Match by prefix to handle minor model variant suffixes
Expand Down
23 changes: 22 additions & 1 deletion tests/lifecycle/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,27 @@

SAMPLE_PROJECT_DIR = Path(__file__).parent / "sample_project"

# Map the CODEFRAME_LIFECYCLE_MODEL shorthand (haiku/sonnet) to actual model IDs.
# These are passed to all `cf` subprocesses via per-purpose env vars so the agent
# uses the requested model class instead of the compiled-in defaults.
_LIFECYCLE_MODEL_MAP: dict[str, str] = {
"haiku": "claude-haiku-4-5",
"sonnet": "claude-sonnet-4-5",
}


def _lifecycle_model_env() -> dict[str, str]:
"""Return per-purpose model env vars based on CODEFRAME_LIFECYCLE_MODEL."""
alias = os.getenv("CODEFRAME_LIFECYCLE_MODEL", "haiku")
model = _LIFECYCLE_MODEL_MAP.get(alias, "claude-haiku-4-5")
return {
"CODEFRAME_PLANNING_MODEL": model,
"CODEFRAME_EXECUTION_MODEL": model,
"CODEFRAME_GENERATION_MODEL": model,
"CODEFRAME_CORRECTION_MODEL": model,
"CODEFRAME_SUPERVISION_MODEL": model,
}


def pytest_configure(config):
config.addinivalue_line(
Expand Down Expand Up @@ -83,7 +104,7 @@ def run(*args, cwd=None, timeout=60, **kwargs):
capture_output=True,
text=True,
timeout=timeout,
env={**os.environ},
env={**os.environ, **_lifecycle_model_env()},
)
return run

Expand Down
Loading