New version v2.3.6

This commit is contained in:
2026-03-04 10:19:16 +01:00
parent 65a35cd508
commit 49f842f119
52 changed files with 14034 additions and 358 deletions

View File

@@ -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 {