AddisonJi/claude-code-training
0
1"""2LLM utility - thin wrapper around Anthropic Claude API.3All agent LLM calls go through here.4"""5import os6import json7from anthropic import Anthropic8 9 10def get_client() -> Anthropic:11 api_key = os.getenv("ANTHROPIC_API_KEY")12 if not api_key:13 raise ValueError("ANTHROPIC_API_KEY not set in environment")14 return Anthropic(api_key=api_key)15 16 17MODEL = "claude-sonnet-4-20250514"18 19 20def chat(system_prompt: str, user_message: str, json_mode: bool = False) -> str:21 """22 Simple single-turn LLM call.23 If json_mode=True, instructs model to return valid JSON.24 """25 client = get_client()26 27 if json_mode:28 system_prompt += "\n\nYou MUST respond with valid JSON only. No markdown, no explanation, just JSON."29 30 response = client.messages.create(31 model=MODEL,32 max_tokens=1024,33 system=system_prompt,34 messages=[{"role": "user", "content": user_message}],35 )36 return response.content[0].text37 38 39def parse_json_response(text: str) -> dict:40 """Try to parse JSON from LLM response, handling common issues."""41 # Strip markdown code fences if present42 text = text.strip()43 if text.startswith("```"):44 text = text.split("\n", 1)[1] if "\n" in text else text[3:]45 if text.endswith("```"):46 text = text[:-3]47 text = text.strip()48 return json.loads(text)49 