diff --git a/packages/llms/src/OpenAIClient.ts b/packages/llms/src/OpenAIClient.ts index fd40f38..57be760 100644 --- a/packages/llms/src/OpenAIClient.ts +++ b/packages/llms/src/OpenAIClient.ts @@ -112,11 +112,20 @@ export class OpenAIClient implements LLMClient { } // 4. Parse and validate response - const data = await response.json() + let data: any + try { + data = await response.json() + } catch (error) { + throw new InvokeError( + InvokeErrorTypes.INVALID_RESPONSE, + 'Response body is not valid JSON', + error + ) + } const choice = data.choices?.[0] if (!choice) { - throw new InvokeError(InvokeErrorTypes.UNKNOWN, 'No choices in response', data) + throw new InvokeError(InvokeErrorTypes.INVALID_SCHEMA, 'No choices in response', data) } // Check finish_reason @@ -141,7 +150,7 @@ export class OpenAIClient implements LLMClient { ) default: throw new InvokeError( - InvokeErrorTypes.UNKNOWN, + InvokeErrorTypes.INVALID_SCHEMA, `Unexpected finish_reason: ${choice.finish_reason}`, undefined, data diff --git a/packages/llms/src/errors.ts b/packages/llms/src/errors.ts index ee4f1d6..936693e 100644 --- a/packages/llms/src/errors.ts +++ b/packages/llms/src/errors.ts @@ -10,6 +10,8 @@ export const InvokeErrorTypes = { NO_TOOL_CALL: 'no_tool_call', // Model did not call tool INVALID_TOOL_ARGS: 'invalid_tool_args', // Tool args don't match schema TOOL_EXECUTION_ERROR: 'tool_execution_error', // Tool execution error + INVALID_RESPONSE: 'invalid_response', // Response body is not valid JSON + INVALID_SCHEMA: 'invalid_schema', // Response is valid JSON but doesn't match expected shape UNKNOWN: 'unknown', @@ -29,6 +31,8 @@ const RETRYABLE_TYPES: readonly InvokeErrorType[] = [ InvokeErrorTypes.NO_TOOL_CALL, InvokeErrorTypes.INVALID_TOOL_ARGS, InvokeErrorTypes.TOOL_EXECUTION_ERROR, + InvokeErrorTypes.INVALID_RESPONSE, + InvokeErrorTypes.INVALID_SCHEMA, InvokeErrorTypes.UNKNOWN, ]