import json import logging from pr.config import DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE from pr.core.context import auto_slim_messages from pr.core.http_client import http_client logger = logging.getLogger("pr") async def call_api(messages, model, api_url, api_key, use_tools, tools_definition, verbose=False): try: messages = auto_slim_messages(messages, verbose=verbose) logger.debug(f"=== API CALL START ===") logger.debug(f"Model: {model}") logger.debug(f"API URL: {api_url}") logger.debug(f"Use tools: {use_tools}") logger.debug(f"Message count: {len(messages)}") headers = { "Content-Type": "application/json", } if api_key: headers["Authorization"] = f"Bearer {api_key}" data = { "model": model, "messages": messages, "temperature": DEFAULT_TEMPERATURE, "max_tokens": DEFAULT_MAX_TOKENS, } if "gpt-5" in model: del data["temperature"] del data["max_tokens"] logger.debug("GPT-5 detected: removed temperature and max_tokens") if use_tools: data["tools"] = tools_definition data["tool_choice"] = "auto" logger.debug(f"Tool calling enabled with {len(tools_definition)} tools") request_json = data logger.debug(f"Request payload size: {len(request_json)} bytes") logger.debug("Sending HTTP request...") response = await http_client.post(api_url, headers=headers, json_data=request_json) if response.get("error"): if "status" in response: logger.error(f"API HTTP Error: {response['status']} - {response.get('text', '')}") logger.debug("=== API CALL FAILED ===") return { "error": f"API Error: {response['status']}", "message": response.get("text", ""), } else: logger.error(f"API call failed: {response.get('exception', 'Unknown error')}") logger.debug("=== API CALL FAILED ===") return {"error": response.get("exception", "Unknown error")} response_data = response["text"] logger.debug(f"Response received: {len(response_data)} bytes") result = json.loads(response_data) if "usage" in result: logger.debug(f"Token usage: {result['usage']}") if "choices" in result and result["choices"]: choice = result["choices"][0] if "message" in choice: msg = choice["message"] logger.debug(f"Response role: {msg.get('role', 'N/A')}") if "content" in msg and msg["content"]: logger.debug(f"Response content length: {len(msg['content'])} chars") if "tool_calls" in msg: logger.debug(f"Response contains {len(msg['tool_calls'])} tool call(s)") if verbose and "usage" in result: from pr.core.usage_tracker import UsageTracker usage = result["usage"] input_t = usage.get("prompt_tokens", 0) output_t = usage.get("completion_tokens", 0) UsageTracker._calculate_cost(model, input_t, output_t) logger.debug("=== API CALL END ===") return result except Exception as e: logger.error(f"API call failed: {e}") logger.debug("=== API CALL FAILED ===") return {"error": str(e)} async def list_models(model_list_url, api_key): try: headers = {} if api_key: headers["Authorization"] = f"Bearer {api_key}" response = await http_client.get(model_list_url, headers=headers) if response.get("error"): return {"error": response.get("text", "HTTP error")} data = json.loads(response["text"]) return data.get("data", []) except Exception as e: return {"error": str(e)}