Skip to content
Closed
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
8 changes: 3 additions & 5 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ jobs:
python-version: "3.11"
cache: "pip"
cache-dependency-path: |
libs/openant-core/requirements.txt
libs/openant-core/pyproject.toml

- name: Set up Node.js
Expand All @@ -35,7 +34,7 @@ jobs:

- name: Install Python dependencies
working-directory: libs/openant-core
run: pip install -r requirements.txt && pip install ".[dev]"
run: pip install -e ".[dev]"

- name: Cache JS parser node_modules
id: cache-node-modules
Expand All @@ -51,7 +50,7 @@ jobs:

- name: Run Python and parser tests
working-directory: libs/openant-core
run: python -m pytest tests/test_token_tracker.py tests/test_parser_adapter.py tests/test_python_parser.py tests/test_js_parser.py -v
run: python -m pytest tests/test_token_tracker.py tests/test_parser_adapter.py tests/test_python_parser.py tests/test_js_parser.py tests/test_declared_dependencies.py -v

go-tests:
name: Go build + integration (${{ matrix.os }})
Expand Down Expand Up @@ -79,7 +78,6 @@ jobs:
python-version: "3.11"
cache: "pip"
cache-dependency-path: |
libs/openant-core/requirements.txt
libs/openant-core/pyproject.toml

- name: Set up Node.js
Expand Down Expand Up @@ -115,7 +113,7 @@ jobs:

- name: Install Python dependencies
working-directory: libs/openant-core
run: pip install -r requirements.txt && pip install ".[dev]"
run: pip install -e ".[dev]"

- name: Cache JS parser node_modules
id: cache-node-modules
Expand Down
2 changes: 1 addition & 1 deletion libs/openant-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ git clone https://github.com/your-org/openant.git
cd openant

# Install Python dependencies
pip install -r requirements.txt
pip install -e .

# Set API key
echo "ANTHROPIC_API_KEY=your-key-here" > .env
Expand Down
27 changes: 15 additions & 12 deletions libs/openant-core/context/application_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,17 @@
from pathlib import Path
from typing import Any

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
from utilities.llm_client import AnthropicClient # noqa: E402

# Load environment variables
load_dotenv()

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -503,19 +511,14 @@ def generate_application_context(

# Call LLM
print(f"Generating context with {model}...", file=sys.stderr)
client = Anthropic()
response = client.messages.create(
model=model,
# AnthropicClient is the SDK-backed wrapper; routes through the Claude
# Agent SDK so this works with both API keys and local Claude Code sessions.
client = AnthropicClient(model=model)
response_text = client.analyze_sync(
CONTEXT_GENERATION_PROMPT.format(sources=sources_text),
max_tokens=2000,
messages=[{
"role": "user",
"content": CONTEXT_GENERATION_PROMPT.format(sources=sources_text)
}]
)

# Parse response
response_text = response.content[0].text

# Extract JSON from response
json_match = re.search(r'```json\s*(.*?)\s*```', response_text, re.DOTALL)
if json_match:
Expand Down
5 changes: 3 additions & 2 deletions libs/openant-core/context/generate_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down
3 changes: 2 additions & 1 deletion libs/openant-core/core/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion libs/openant-core/core/enhancer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
3 changes: 2 additions & 1 deletion libs/openant-core/core/reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
)
Expand Down
3 changes: 2 additions & 1 deletion libs/openant-core/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand Down
30 changes: 16 additions & 14 deletions libs/openant-core/generate_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
from utilities.llm_client import AnthropicClient # noqa: E402

# Load environment variables from .env file
load_dotenv()


REPORT_MODEL = "claude-sonnet-4-20250514"
REPORT_MODEL = MODEL_AUXILIARY
MAX_TOKENS = 4096


Expand Down Expand Up @@ -198,18 +208,10 @@ def generate_remediation_guidance(findings: list) -> str:
{findings_text}
"""

api_key = os.getenv("ANTHROPIC_API_KEY")
if not api_key:
raise ValueError("ANTHROPIC_API_KEY not found in environment")

client = anthropic.Anthropic(api_key=api_key)
response = client.messages.create(
model=REPORT_MODEL,
max_tokens=MAX_TOKENS,
messages=[{"role": "user", "content": prompt}]
)

return response.content[0].text
# AnthropicClient is the SDK-backed wrapper; it handles auth (API key
# or local Claude Code session) and surfaces structured SDK errors.
client = AnthropicClient(model=REPORT_MODEL)
return client.analyze_sync(prompt, max_tokens=MAX_TOKENS)


def _build_pipeline_costs_html(step_reports: list[dict]) -> str:
Expand Down
26 changes: 9 additions & 17 deletions libs/openant-core/openant/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,10 +587,9 @@ def cmd_report_data(args):
and step reports — everything display-ready.
"""
import html as html_mod
import anthropic
from core.schemas import success, error
from core.step_report import step_context
from utilities.llm_client import get_global_tracker
from utilities.llm_client import AnthropicClient, get_global_tracker

results_path = args.results
dataset_path = args.dataset
Expand Down Expand Up @@ -810,13 +809,10 @@ def cmd_report_data(args):
{findings_text}
"""
print("[Report] Generating remediation guidance (LLM)...", file=sys.stderr)
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=4096,
messages=[{"role": "user", "content": prompt}],
)
remediation_html = response.content[0].text
from utilities.model_config import MODEL_AUXILIARY
# AnthropicClient handles usage tracking via the global TokenTracker.
remediation_client = AnthropicClient(model=MODEL_AUXILIARY)
remediation_html = remediation_client.analyze_sync(prompt, max_tokens=4096)

# Post-process: linkify finding references like #4, #12-#14
import re
Expand All @@ -825,15 +821,11 @@ def _linkify_finding(m):
return f'<a href="#finding-{num}" class="finding-ref">#{num}</a>'
remediation_html = re.sub(r'#(\d+)', _linkify_finding, remediation_html)

# Track usage
usage = response.usage
tracker = get_global_tracker()
tracker.record_call(
model="claude-sonnet-4-20250514",
input_tokens=usage.input_tokens,
output_tokens=usage.output_tokens,
last = remediation_client.get_last_call() or {}
print(
f" Remediation cost: ${last.get('cost_usd', 0.0):.4f}",
file=sys.stderr,
)
print(f" Remediation cost: ${(usage.input_tokens / 1e6) * 3.0 + (usage.output_tokens / 1e6) * 15.0:.4f}", file=sys.stderr)

# --- Step reports ---
step_reports_data = []
Expand Down
Loading
Loading