Parse the API response into an LLMResponse.
(self, data: dict)
| 272 | )) |
| 273 | |
| 274 | def _parse_response(self, data: dict) -> LLMResponse: |
| 275 | """Parse the API response into an LLMResponse.""" |
| 276 | # Check for API-level errors in the response |
| 277 | if 'error' in data: |
| 278 | error_info = data['error'] |
| 279 | raise LLMClientError(LLMError( |
| 280 | message=error_info.get('message', 'Unknown API error'), |
| 281 | code=error_info.get('code', 'unknown'), |
| 282 | provider=self.provider_name, |
| 283 | retryable=False |
| 284 | )) |
| 285 | |
| 286 | choices = data.get('choices', []) |
| 287 | if not choices: |
| 288 | raise LLMClientError(LLMError( |
| 289 | message='No response choices returned from API', |
| 290 | provider=self.provider_name, |
| 291 | retryable=False |
| 292 | )) |
| 293 | |
| 294 | choice = choices[0] |
| 295 | message = choice.get('message', {}) |
| 296 | |
| 297 | # Check for refusal (content moderation) |
| 298 | if message.get('refusal'): |
| 299 | raise LLMClientError(LLMError( |
| 300 | message=f"Request refused: {message.get('refusal')}", |
| 301 | provider=self.provider_name, |
| 302 | retryable=False |
| 303 | )) |
| 304 | |
| 305 | content = message.get('content', '') or '' |
| 306 | tool_calls = [] |
| 307 | |
| 308 | # Parse tool calls if present |
| 309 | for tc in message.get('tool_calls', []): |
| 310 | if tc.get('type') == 'function': |
| 311 | func = tc.get('function', {}) |
| 312 | try: |
| 313 | arguments = json.loads(func.get('arguments', '{}')) |
| 314 | except json.JSONDecodeError: |
| 315 | arguments = {} |
| 316 | |
| 317 | tool_calls.append(ToolCall( |
| 318 | id=tc.get('id', str(uuid.uuid4())), |
| 319 | name=func.get('name', ''), |
| 320 | arguments=arguments |
| 321 | )) |
| 322 | |
| 323 | # Map finish reasons to our enum |
| 324 | finish_reason = choice.get('finish_reason', '') |
| 325 | stop_reason_map = { |
| 326 | 'stop': StopReason.END_TURN, |
| 327 | 'tool_calls': StopReason.TOOL_USE, |
| 328 | 'length': StopReason.MAX_TOKENS, |
| 329 | 'content_filter': StopReason.STOP_SEQUENCE |
| 330 | } |
| 331 | stop_reason = stop_reason_map.get(finish_reason, StopReason.UNKNOWN) |
no test coverage detected