Skip to content

Improve compatibility with OpenRouter (DecodingError in CompletionTokensDetails) #21

@ruslanhirychau

Description

@ruslanhirychau

Hi Kevin!

First of all, thanks for the great library! It's very clean and easy to use with OpenAI directly.

I’m currently using it with OpenRouter as an endpoint, and I've encountered a small issue when streaming responses. It seems like OpenRouter (and some other providers) doesn't always include all the fields in the usage object that the standard OpenAI API does.

I used Gemini to help me debug the issue. It identified that the DecodingError (keyNotFound) for accepted_prediction_tokens occurs because the default Swift decoder expects the keys to be present in the JSON if they are defined in CodingKeys, even if the properties are optional.

I’ve created a fork, applied the suggested fix, and confirmed that it works perfectly with OpenRouter.

The Suggested Fix:
Implement a custom init(from decoder: Decoder) using decodeIfPresent for CompletionTokensDetails to make it more robust:

public struct CompletionTokensDetails: Decodable, Sendable {
    public let acceptedPredictionTokens: Int?
    public let rejectedPredictionTokens: Int?
    public let reasoningTokens: Int?
    
    private enum CodingKeys: String, CodingKey {
        case acceptedPredictionTokens = "accepted_prediction_tokens"
        case reasoningTokens = "reasoning_tokens"
        case rejectedPredictionTokens = "rejected_prediction_tokens"
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.acceptedPredictionTokens = try container.decodeIfPresent(Int.self, forKey: .acceptedPredictionTokens)
        self.rejectedPredictionTokens = try container.decodeIfPresent(Int.self, forKey: .rejectedPredictionTokens)
        self.reasoningTokens = try container.decodeIfPresent(Int.self, forKey: .reasoningTokens)
    }
}

Could you please consider incorporating this change (or a similar fix) into your library to improve compatibility with alternative providers?

Keep up the great work! Best regards.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions