New version v2.3.6
This commit is contained in:
@@ -27,6 +27,16 @@ import Foundation
|
||||
|
||||
// MARK: - API Request
|
||||
|
||||
struct ReasoningAPIConfig: Codable {
|
||||
let effort: String
|
||||
let exclude: Bool?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case effort
|
||||
case exclude
|
||||
}
|
||||
}
|
||||
|
||||
struct OpenRouterChatRequest: Codable {
|
||||
let model: String
|
||||
let messages: [APIMessage]
|
||||
@@ -37,6 +47,7 @@ struct OpenRouterChatRequest: Codable {
|
||||
let tools: [Tool]?
|
||||
let toolChoice: String?
|
||||
let modalities: [String]?
|
||||
let reasoning: ReasoningAPIConfig?
|
||||
|
||||
struct APIMessage: Codable {
|
||||
let role: String
|
||||
@@ -126,6 +137,7 @@ struct OpenRouterChatRequest: Codable {
|
||||
case tools
|
||||
case toolChoice = "tool_choice"
|
||||
case modalities
|
||||
case reasoning
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +217,46 @@ struct OpenRouterStreamChunk: Codable {
|
||||
struct Delta: Codable {
|
||||
let role: String?
|
||||
let content: String?
|
||||
let reasoning: String?
|
||||
// images[] from top-level delta field (custom OpenRouter format)
|
||||
let images: [OpenRouterChatResponse.ImageOutput]?
|
||||
// images extracted from content[] array (standard OpenAI content-block format)
|
||||
let contentBlockImages: [OpenRouterChatResponse.ImageOutput]
|
||||
|
||||
private struct ContentBlock: Codable {
|
||||
let type: String
|
||||
let text: String?
|
||||
let imageUrl: OpenRouterChatResponse.ImageOutput.ImageURL?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case type, text
|
||||
case imageUrl = "image_url"
|
||||
}
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case role, content, images, reasoning
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let c = try decoder.container(keyedBy: CodingKeys.self)
|
||||
role = try c.decodeIfPresent(String.self, forKey: .role)
|
||||
images = try c.decodeIfPresent([OpenRouterChatResponse.ImageOutput].self, forKey: .images)
|
||||
reasoning = try c.decodeIfPresent(String.self, forKey: .reasoning)
|
||||
// content can be a plain String OR an array of content blocks
|
||||
if let text = try? c.decodeIfPresent(String.self, forKey: .content) {
|
||||
content = text
|
||||
contentBlockImages = []
|
||||
} else if let blocks = try? c.decodeIfPresent([ContentBlock].self, forKey: .content) {
|
||||
content = blocks.compactMap { $0.text }.joined().nonEmptyOrNil
|
||||
contentBlockImages = blocks.compactMap { block in
|
||||
guard block.type == "image_url", let url = block.imageUrl else { return nil }
|
||||
return OpenRouterChatResponse.ImageOutput(imageUrl: url)
|
||||
}
|
||||
} else {
|
||||
content = nil
|
||||
contentBlockImages = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
|
||||
Reference in New Issue
Block a user