diff --git a/libs/openant-core/context/application_context.py b/libs/openant-core/context/application_context.py index f7fa55d..5769b63 100644 --- a/libs/openant-core/context/application_context.py +++ b/libs/openant-core/context/application_context.py @@ -32,6 +32,14 @@ from anthropic import Anthropic from dotenv import load_dotenv +# Ensure libs/openant-core is on sys.path so `utilities.*` imports resolve +# regardless of how this module is loaded. +_OPENANT_CORE_ROOT = str(Path(__file__).parent.parent) +if _OPENANT_CORE_ROOT not in sys.path: + sys.path.insert(0, _OPENANT_CORE_ROOT) + +from utilities.model_config import MODEL_AUXILIARY # noqa: E402 + # Load environment variables load_dotenv() @@ -462,7 +470,7 @@ def _build_type_descriptions() -> str: def generate_application_context( repo_path: Path, - model: str = "claude-sonnet-4-20250514", + model: str = MODEL_AUXILIARY, force_regenerate: bool = False, ) -> ApplicationContext: """Generate application context using LLM analysis. diff --git a/libs/openant-core/context/generate_context.py b/libs/openant-core/context/generate_context.py index 78e21d3..47916f0 100644 --- a/libs/openant-core/context/generate_context.py +++ b/libs/openant-core/context/generate_context.py @@ -14,6 +14,7 @@ # Add parent directory to path for imports sys.path.insert(0, str(Path(__file__).parent.parent)) +from utilities.model_config import MODEL_AUXILIARY from context.application_context import ( ApplicationType, APPLICATION_TYPE_INFO, @@ -78,8 +79,8 @@ def main(): parser.add_argument( "--model", "-m", - default="claude-sonnet-4-20250514", - help="Anthropic model to use (default: claude-sonnet-4-20250514)", + default=MODEL_AUXILIARY, + help=f"Anthropic model to use (default: {MODEL_AUXILIARY})", ) parser.add_argument( diff --git a/libs/openant-core/core/analyzer.py b/libs/openant-core/core/analyzer.py index 7fb5966..a6564ba 100644 --- a/libs/openant-core/core/analyzer.py +++ b/libs/openant-core/core/analyzer.py @@ -313,7 +313,8 @@ def run_analysis( checkpoint.dir = checkpoint_path # Select model - model_id = "claude-opus-4-6" if model == "opus" else "claude-sonnet-4-20250514" + from utilities.model_config import MODEL_AUXILIARY, MODEL_PRIMARY + model_id = MODEL_PRIMARY if model == "opus" else MODEL_AUXILIARY print(f"[Analyze] Model: {model_id}", file=sys.stderr) # Initialize client diff --git a/libs/openant-core/core/enhancer.py b/libs/openant-core/core/enhancer.py index fef1453..49e5d2d 100644 --- a/libs/openant-core/core/enhancer.py +++ b/libs/openant-core/core/enhancer.py @@ -50,7 +50,8 @@ def enhance_dataset( # Configure global rate limiter configure_rate_limiter(backoff_seconds=float(backoff_seconds)) - model_id = "claude-sonnet-4-20250514" if model == "sonnet" else "claude-opus-4-6" + from utilities.model_config import MODEL_AUXILIARY, MODEL_PRIMARY + model_id = MODEL_AUXILIARY if model == "sonnet" else MODEL_PRIMARY print(f"[Enhance] Mode: {mode}", file=sys.stderr) print(f"[Enhance] Model: {model_id}", file=sys.stderr) diff --git a/libs/openant-core/core/reporter.py b/libs/openant-core/core/reporter.py index 7153dab..6513647 100644 --- a/libs/openant-core/core/reporter.py +++ b/libs/openant-core/core/reporter.py @@ -587,11 +587,12 @@ def _record_usage_in_tracker(usage: dict): """Record usage in the global TokenTracker so step_context captures it.""" try: from utilities.llm_client import get_global_tracker + from utilities.model_config import MODEL_PRIMARY tracker = get_global_tracker() # Record as a single aggregated call if usage.get("total_tokens", 0) > 0: tracker.record_call( - model="claude-opus-4-6", + model=MODEL_PRIMARY, input_tokens=usage["input_tokens"], output_tokens=usage["output_tokens"], ) diff --git a/libs/openant-core/experiment.py b/libs/openant-core/experiment.py index 359d41f..69992ea 100644 --- a/libs/openant-core/experiment.py +++ b/libs/openant-core/experiment.py @@ -474,7 +474,8 @@ def run_experiment( Experiment results with metrics """ # Select model - model_id = "claude-opus-4-20250514" if model == "opus" else "claude-sonnet-4-20250514" + from utilities.model_config import MODEL_AUXILIARY, MODEL_PRIMARY + model_id = MODEL_PRIMARY if model == "opus" else MODEL_AUXILIARY print(f"Using model: {model_id}") print(f"Enhanced context: {enhanced}") print(f"Context correction: {correct_context}") diff --git a/libs/openant-core/generate_report.py b/libs/openant-core/generate_report.py index 633cd9b..9dd3ee0 100644 --- a/libs/openant-core/generate_report.py +++ b/libs/openant-core/generate_report.py @@ -27,16 +27,26 @@ import json import html import os +import sys from datetime import datetime +from pathlib import Path import anthropic from dotenv import load_dotenv +# Ensure libs/openant-core is on sys.path so `utilities.*` imports resolve +# regardless of the caller's working directory. +_OPENANT_CORE_ROOT = str(Path(__file__).parent) +if _OPENANT_CORE_ROOT not in sys.path: + sys.path.insert(0, _OPENANT_CORE_ROOT) + +from utilities.model_config import MODEL_AUXILIARY # noqa: E402 + # Load environment variables from .env file load_dotenv() -REPORT_MODEL = "claude-sonnet-4-20250514" +REPORT_MODEL = MODEL_AUXILIARY MAX_TOKENS = 4096 diff --git a/libs/openant-core/openant/cli.py b/libs/openant-core/openant/cli.py index b0ce345..27bcd22 100644 --- a/libs/openant-core/openant/cli.py +++ b/libs/openant-core/openant/cli.py @@ -810,9 +810,10 @@ def cmd_report_data(args): {findings_text} """ print("[Report] Generating remediation guidance (LLM)...", file=sys.stderr) + from utilities.model_config import MODEL_AUXILIARY client = anthropic.Anthropic() response = client.messages.create( - model="claude-sonnet-4-20250514", + model=MODEL_AUXILIARY, max_tokens=4096, messages=[{"role": "user", "content": prompt}], ) @@ -829,7 +830,7 @@ def _linkify_finding(m): usage = response.usage tracker = get_global_tracker() tracker.record_call( - model="claude-sonnet-4-20250514", + model=MODEL_AUXILIARY, input_tokens=usage.input_tokens, output_tokens=usage.output_tokens, ) diff --git a/libs/openant-core/report/generator.py b/libs/openant-core/report/generator.py index c996250..ffea259 100644 --- a/libs/openant-core/report/generator.py +++ b/libs/openant-core/report/generator.py @@ -12,18 +12,25 @@ from pathlib import Path from dotenv import load_dotenv +# Ensure libs/openant-core is on sys.path so `utilities.*` imports resolve. +_OPENANT_CORE_ROOT = str(Path(__file__).parent.parent) +if _OPENANT_CORE_ROOT not in sys.path: + sys.path.insert(0, _OPENANT_CORE_ROOT) + +from utilities.model_config import MODEL_PRIMARY, MODEL_AUXILIARY # noqa: E402 + from .schema import validate_pipeline_output, ValidationError load_dotenv() PROMPTS_DIR = Path(__file__).parent / "prompts" -MODEL = "claude-opus-4-6" +MODEL = MODEL_PRIMARY -# Pricing per million tokens +# Pricing per million tokens. Aliased opus keys retained for backward +# compatibility with any cached/legacy responses that recorded the literal. _PRICING = { - "claude-opus-4-6": {"input": 15.00, "output": 75.00}, - "claude-opus-4-20250514": {"input": 15.00, "output": 75.00}, - "claude-sonnet-4-20250514": {"input": 3.00, "output": 15.00}, + MODEL_PRIMARY: {"input": 15.00, "output": 75.00}, + MODEL_AUXILIARY: {"input": 3.00, "output": 15.00}, } _DEFAULT_PRICING = {"input": 3.00, "output": 15.00} diff --git a/libs/openant-core/tests/test_model_config.py b/libs/openant-core/tests/test_model_config.py new file mode 100644 index 0000000..bab1970 --- /dev/null +++ b/libs/openant-core/tests/test_model_config.py @@ -0,0 +1,93 @@ +"""Tests for the central model configuration module.""" +import re +from pathlib import Path + +import pytest + +from utilities import model_config +from utilities.model_config import MODEL_AUXILIARY, MODEL_DEFAULT, MODEL_PRIMARY + + +# Regex for a valid Claude model identifier (e.g. claude-opus-4-20250514, +# claude-sonnet-4-6, claude-haiku-4-5). +_MODEL_ID_RE = re.compile(r"^claude-(opus|sonnet|haiku)-[0-9A-Za-z-]+$") + +# Regex used by the regression test to detect any hardcoded +# claude-opus-* / claude-sonnet-* string literal. +_HARDCODED_LITERAL_RE = re.compile(r"claude-(?:opus|sonnet)-[0-9][0-9A-Za-z-]*") + + +class TestModelConstants: + """Constants must exist, be non-empty strings, and match Claude model id format.""" + + def test_model_primary_is_valid_string(self): + assert isinstance(MODEL_PRIMARY, str) + assert MODEL_PRIMARY, "MODEL_PRIMARY must be non-empty" + assert _MODEL_ID_RE.match(MODEL_PRIMARY), ( + f"MODEL_PRIMARY={MODEL_PRIMARY!r} does not match expected " + f"claude-(opus|sonnet|haiku)-... format" + ) + + def test_model_auxiliary_is_valid_string(self): + assert isinstance(MODEL_AUXILIARY, str) + assert MODEL_AUXILIARY, "MODEL_AUXILIARY must be non-empty" + assert _MODEL_ID_RE.match(MODEL_AUXILIARY), ( + f"MODEL_AUXILIARY={MODEL_AUXILIARY!r} does not match expected " + f"claude-(opus|sonnet|haiku)-... format" + ) + + def test_model_default_is_valid_string(self): + assert isinstance(MODEL_DEFAULT, str) + assert MODEL_DEFAULT, "MODEL_DEFAULT must be non-empty" + assert _MODEL_ID_RE.match(MODEL_DEFAULT) + + def test_module_exposes_all_three_constants(self): + for name in ("MODEL_PRIMARY", "MODEL_AUXILIARY", "MODEL_DEFAULT"): + assert hasattr(model_config, name), f"model_config missing {name}" + + +class TestNoHardcodedModelLiterals: + """Regression test: no hardcoded claude-opus-*/claude-sonnet-* literals + may reappear in libs/openant-core/*.py outside of model_config.py. + + If this test fails, replace the offending literal with an import of + MODEL_PRIMARY / MODEL_AUXILIARY / MODEL_DEFAULT from utilities.model_config. + """ + + # Path to libs/openant-core (this file is at libs/openant-core/tests/...) + _CORE_ROOT = Path(__file__).parent.parent + + # Files exempt from the scan (the constants live here, by design) + _EXEMPT = { + _CORE_ROOT / "utilities" / "model_config.py", + # The regression test itself contains the regex pattern source. + Path(__file__).resolve(), + } + + def test_no_hardcoded_model_strings_outside_model_config(self): + offenders: list[tuple[Path, int, str]] = [] + + for py_path in self._CORE_ROOT.rglob("*.py"): + resolved = py_path.resolve() + if resolved in {p.resolve() for p in self._EXEMPT}: + continue + + try: + text = py_path.read_text(encoding="utf-8") + except (OSError, UnicodeDecodeError): + continue + + for lineno, line in enumerate(text.splitlines(), start=1): + if _HARDCODED_LITERAL_RE.search(line): + offenders.append((py_path, lineno, line.strip())) + + if offenders: + details = "\n".join( + f" {path.relative_to(self._CORE_ROOT)}:{lineno}: {snippet}" + for path, lineno, snippet in offenders + ) + pytest.fail( + "Found hardcoded claude-opus-*/claude-sonnet-* literals outside " + "utilities/model_config.py. Replace them with imports from " + "utilities.model_config:\n" + details + ) diff --git a/libs/openant-core/tests/test_token_tracker.py b/libs/openant-core/tests/test_token_tracker.py index 08fdc9c..410bdbf 100644 --- a/libs/openant-core/tests/test_token_tracker.py +++ b/libs/openant-core/tests/test_token_tracker.py @@ -1,5 +1,6 @@ """Tests for TokenTracker.""" from utilities.llm_client import TokenTracker, MODEL_PRICING +from utilities.model_config import MODEL_PRIMARY, MODEL_AUXILIARY class TestTokenTracker: @@ -13,9 +14,9 @@ def test_initial_state(self): def test_record_call_known_model(self): tracker = TokenTracker() - result = tracker.record_call("claude-sonnet-4-20250514", 1000, 500) + result = tracker.record_call(MODEL_AUXILIARY, 1000, 500) - assert result["model"] == "claude-sonnet-4-20250514" + assert result["model"] == MODEL_AUXILIARY assert result["input_tokens"] == 1000 assert result["output_tokens"] == 500 # Sonnet: $3/M input, $15/M output @@ -31,8 +32,8 @@ def test_record_call_unknown_model_uses_default(self): def test_cumulative_tracking(self): tracker = TokenTracker() - tracker.record_call("claude-sonnet-4-20250514", 1000, 500) - tracker.record_call("claude-sonnet-4-20250514", 2000, 1000) + tracker.record_call(MODEL_AUXILIARY, 1000, 500) + tracker.record_call(MODEL_AUXILIARY, 2000, 1000) assert tracker.total_input_tokens == 3000 assert tracker.total_output_tokens == 1500 @@ -41,7 +42,7 @@ def test_cumulative_tracking(self): def test_reset(self): tracker = TokenTracker() - tracker.record_call("claude-sonnet-4-20250514", 1000, 500) + tracker.record_call(MODEL_AUXILIARY, 1000, 500) tracker.reset() assert tracker.total_input_tokens == 0 @@ -51,7 +52,7 @@ def test_reset(self): def test_get_summary_includes_calls(self): tracker = TokenTracker() - tracker.record_call("claude-sonnet-4-20250514", 100, 50) + tracker.record_call(MODEL_AUXILIARY, 100, 50) summary = tracker.get_summary() assert summary["total_calls"] == 1 @@ -60,7 +61,7 @@ def test_get_summary_includes_calls(self): def test_get_totals_excludes_calls(self): tracker = TokenTracker() - tracker.record_call("claude-sonnet-4-20250514", 100, 50) + tracker.record_call(MODEL_AUXILIARY, 100, 50) totals = tracker.get_totals() assert totals["total_calls"] == 1 @@ -68,6 +69,6 @@ def test_get_totals_excludes_calls(self): def test_opus_pricing(self): tracker = TokenTracker() - result = tracker.record_call("claude-opus-4-20250514", 1_000_000, 1_000_000) + result = tracker.record_call(MODEL_PRIMARY, 1_000_000, 1_000_000) # Opus: $15/M input, $75/M output assert result["cost_usd"] == 90.0 diff --git a/libs/openant-core/utilities/agentic_enhancer/agent.py b/libs/openant-core/utilities/agentic_enhancer/agent.py index 62061b7..ed9e0c9 100644 --- a/libs/openant-core/utilities/agentic_enhancer/agent.py +++ b/libs/openant-core/utilities/agentic_enhancer/agent.py @@ -17,6 +17,7 @@ import anthropic from ..llm_client import TokenTracker, get_global_tracker +from ..model_config import MODEL_AUXILIARY from ..rate_limiter import get_rate_limiter from .repository_index import RepositoryIndex from .tools import TOOL_DEFINITIONS, ToolExecutor @@ -26,7 +27,7 @@ # Use Sonnet for exploration (cost-effective) -AGENT_MODEL = "claude-sonnet-4-20250514" +AGENT_MODEL = MODEL_AUXILIARY # Safety limits MAX_ITERATIONS = 20 diff --git a/libs/openant-core/utilities/context_corrector.py b/libs/openant-core/utilities/context_corrector.py index 918dda6..d451cad 100644 --- a/libs/openant-core/utilities/context_corrector.py +++ b/libs/openant-core/utilities/context_corrector.py @@ -17,6 +17,7 @@ from typing import Optional from .llm_client import AnthropicClient, TokenTracker, get_global_tracker +from .model_config import MODEL_AUXILIARY # Maximum characters per batch (leaving room for prompt overhead) @@ -102,7 +103,7 @@ def parse_missing_context_with_llm( prompt = get_missing_context_prompt(reasoning) try: - llm_response = client.analyze_sync(prompt, model="claude-sonnet-4-20250514") + llm_response = client.analyze_sync(prompt, model=MODEL_AUXILIARY) parsed = _parse_json_response(llm_response) if parsed and "missing_context" in parsed: @@ -254,7 +255,7 @@ def search_files_for_context( prompt = get_file_search_prompt(missing_context, files_content, batch_info) try: - response = client.analyze_sync(prompt, model="claude-sonnet-4-20250514") + response = client.analyze_sync(prompt, model=MODEL_AUXILIARY) result = _parse_json_response(response) if result and result.get("found_files"): diff --git a/libs/openant-core/utilities/context_enhancer.py b/libs/openant-core/utilities/context_enhancer.py index 2ffbfe6..f1506de 100644 --- a/libs/openant-core/utilities/context_enhancer.py +++ b/libs/openant-core/utilities/context_enhancer.py @@ -27,6 +27,7 @@ from .llm_client import AnthropicClient, TokenTracker, get_global_tracker, reset_global_tracker from .agentic_enhancer import RepositoryIndex, enhance_unit_with_agent, load_index_from_file +from .model_config import MODEL_AUXILIARY from .rate_limiter import get_rate_limiter, is_rate_limit_error, is_retryable_error # Avoid circular import — import checkpoint at usage site @@ -45,7 +46,7 @@ def _get_step_checkpoint(): # Use Sonnet for context enhancement (cost-effective auxiliary task) -CONTEXT_ENHANCEMENT_MODEL = "claude-sonnet-4-20250514" +CONTEXT_ENHANCEMENT_MODEL = MODEL_AUXILIARY def _build_error_info(exc: Exception) -> dict: @@ -568,7 +569,7 @@ def enhance_dataset_agentic( remaining = total - len(processed_ids) self._log("info", f"Enhancing {remaining} units with agentic analysis ({len(processed_ids)} already done)", units=remaining) self._log("info", "Mode: Iterative tool use (traces call paths)") - self._log("info", "Model: claude-sonnet-4-20250514") + self._log("info", f"Model: {CONTEXT_ENHANCEMENT_MODEL}") mode = "sequential" if workers <= 1 else f"parallel ({workers} workers)" self._log("info", f"Workers: {mode}") if checkpoint_dir: diff --git a/libs/openant-core/utilities/context_reviewer.py b/libs/openant-core/utilities/context_reviewer.py index b17107d..5b9aa3c 100644 --- a/libs/openant-core/utilities/context_reviewer.py +++ b/libs/openant-core/utilities/context_reviewer.py @@ -13,6 +13,7 @@ from typing import Optional from .llm_client import AnthropicClient +from .model_config import MODEL_AUXILIARY from .context_corrector import gather_source_files, search_files_for_context @@ -176,7 +177,7 @@ def review_context( prompt = get_context_review_prompt(code, route, handler, files_included) try: - response = self.client.analyze_sync(prompt, model="claude-sonnet-4-20250514") + response = self.client.analyze_sync(prompt, model=MODEL_AUXILIARY) review = self._parse_json_response(response) if not review: diff --git a/libs/openant-core/utilities/dynamic_tester/test_generator.py b/libs/openant-core/utilities/dynamic_tester/test_generator.py index c95b88a..9d76869 100644 --- a/libs/openant-core/utilities/dynamic_tester/test_generator.py +++ b/libs/openant-core/utilities/dynamic_tester/test_generator.py @@ -15,8 +15,9 @@ from concurrent.futures import ThreadPoolExecutor, as_completed from utilities.llm_client import AnthropicClient, TokenTracker +from utilities.model_config import MODEL_AUXILIARY -SONNET_MODEL = "claude-sonnet-4-20250514" +SONNET_MODEL = MODEL_AUXILIARY # Map language strings to Dockerfile template names LANGUAGE_MAP = { diff --git a/libs/openant-core/utilities/finding_verifier.py b/libs/openant-core/utilities/finding_verifier.py index 2e66b7c..151d53f 100644 --- a/libs/openant-core/utilities/finding_verifier.py +++ b/libs/openant-core/utilities/finding_verifier.py @@ -41,6 +41,7 @@ import anthropic from .llm_client import TokenTracker, get_global_tracker +from .model_config import MODEL_PRIMARY from .rate_limiter import get_rate_limiter # Null logger that discards all messages (used when no logger provided) @@ -62,7 +63,7 @@ ApplicationContext = None -VERIFIER_MODEL = "claude-opus-4-6" +VERIFIER_MODEL = MODEL_PRIMARY MAX_ITERATIONS = 20 MAX_TOKENS_PER_RESPONSE = 4096 diff --git a/libs/openant-core/utilities/ground_truth_challenger.py b/libs/openant-core/utilities/ground_truth_challenger.py index b0ad1db..bb808ed 100644 --- a/libs/openant-core/utilities/ground_truth_challenger.py +++ b/libs/openant-core/utilities/ground_truth_challenger.py @@ -19,6 +19,7 @@ from dataclasses import dataclass from .llm_client import AnthropicClient +from .model_config import MODEL_AUXILIARY @dataclass @@ -209,7 +210,7 @@ class GroundTruthChallenger: 2. Validate false negatives - did the model miss something, or is the ground truth wrong? """ - def __init__(self, client: AnthropicClient, model: str = "claude-sonnet-4-20250514"): + def __init__(self, client: AnthropicClient, model: str = MODEL_AUXILIARY): """ Initialize the challenger. diff --git a/libs/openant-core/utilities/json_corrector.py b/libs/openant-core/utilities/json_corrector.py index dd35cda..30002ca 100644 --- a/libs/openant-core/utilities/json_corrector.py +++ b/libs/openant-core/utilities/json_corrector.py @@ -16,6 +16,7 @@ from typing import Optional from .llm_client import AnthropicClient +from .model_config import MODEL_AUXILIARY def get_json_extraction_prompt(raw_response: str) -> str: @@ -83,7 +84,7 @@ def extract_json_with_llm( # Use Sonnet for extraction (faster/cheaper) llm_response = client.analyze_sync( prompt, - model="claude-sonnet-4-20250514", + model=MODEL_AUXILIARY, max_tokens=2048 ) return _parse_json_response(llm_response) diff --git a/libs/openant-core/utilities/llm_client.py b/libs/openant-core/utilities/llm_client.py index ea356bf..44ba515 100644 --- a/libs/openant-core/utilities/llm_client.py +++ b/libs/openant-core/utilities/llm_client.py @@ -10,7 +10,7 @@ Usage: from utilities.llm_client import AnthropicClient, get_global_tracker - client = AnthropicClient(model="claude-opus-4-20250514") + client = AnthropicClient() # uses MODEL_DEFAULT response = client.analyze_sync("Analyze this code...") tracker = get_global_tracker() @@ -24,12 +24,13 @@ from dotenv import load_dotenv from .rate_limiter import get_rate_limiter +from .model_config import MODEL_PRIMARY, MODEL_AUXILIARY, MODEL_DEFAULT # Pricing per million tokens (as of December 2024) MODEL_PRICING = { - "claude-opus-4-20250514": {"input": 15.00, "output": 75.00}, - "claude-sonnet-4-20250514": {"input": 3.00, "output": 15.00}, + MODEL_PRIMARY: {"input": 15.00, "output": 75.00}, + MODEL_AUXILIARY: {"input": 3.00, "output": 15.00}, # Fallback for unknown models (use Sonnet pricing as conservative estimate) "default": {"input": 3.00, "output": 15.00} } @@ -189,13 +190,14 @@ class AnthropicClient: Tracks token usage and costs for all calls. """ - def __init__(self, model: str = "claude-opus-4-20250514", tracker: TokenTracker = None): + def __init__(self, model: str = MODEL_DEFAULT, tracker: TokenTracker = None): """ Initialize the Anthropic client. Args: - model: Model identifier. Default is Claude Opus 4 (highest capability). - Use "claude-sonnet-4-20250514" for cost-effective option. + model: Model identifier. Defaults to MODEL_DEFAULT from model_config + (Claude Opus 4, highest capability). Use MODEL_AUXILIARY for + the cost-effective option. tracker: Optional TokenTracker instance. Uses global tracker if not provided. """ load_dotenv() diff --git a/libs/openant-core/utilities/model_config.py b/libs/openant-core/utilities/model_config.py new file mode 100644 index 0000000..ebef3b7 --- /dev/null +++ b/libs/openant-core/utilities/model_config.py @@ -0,0 +1,15 @@ +""" +Central model configuration. + +All Claude model IDs are defined here. Change these to update which models +are used across the entire pipeline. +""" + +# Primary model — high capability, used for critical analysis and verification +MODEL_PRIMARY = "claude-opus-4-20250514" + +# Auxiliary model — cost-effective, used for enhancement, consistency, context +MODEL_AUXILIARY = "claude-sonnet-4-20250514" + +# Default fallback when no model is specified +MODEL_DEFAULT = MODEL_PRIMARY diff --git a/libs/openant-core/utilities/stage1_consistency.py b/libs/openant-core/utilities/stage1_consistency.py index 96b54b3..bb219a8 100644 --- a/libs/openant-core/utilities/stage1_consistency.py +++ b/libs/openant-core/utilities/stage1_consistency.py @@ -15,10 +15,11 @@ from dataclasses import dataclass from utilities.llm_client import AnthropicClient, TokenTracker +from utilities.model_config import MODEL_AUXILIARY # Use a cheaper/faster model for consistency checks -CONSISTENCY_MODEL = "claude-sonnet-4-20250514" +CONSISTENCY_MODEL = MODEL_AUXILIARY MAX_TOKENS = 4096