Several bugs fixed

This commit is contained in:
2026-02-23 07:54:16 +01:00
parent 56f79a690e
commit 079eccbc4e
5 changed files with 110 additions and 22 deletions

View File

@@ -73,7 +73,11 @@ class AnthropicProvider: AIProvider {
// MARK: - Models
/// Local metadata used to enrich API results (pricing, context length) and as offline fallback.
/// Entries are matched by exact ID first; if no exact match is found, the enrichment step
/// falls back to prefix matching so newly-released model variants (e.g. "claude-sonnet-4-6-20260301")
/// still inherit the correct pricing tier.
private static let knownModels: [ModelInfo] = [
// Claude 4.x series
ModelInfo(
id: "claude-opus-4-6",
name: "Claude Opus 4.6",
@@ -82,6 +86,31 @@ class AnthropicProvider: AIProvider {
pricing: .init(prompt: 15.0, completion: 75.0),
capabilities: .init(vision: true, tools: true, online: true)
),
ModelInfo(
id: "claude-sonnet-4-6",
name: "Claude Sonnet 4.6",
description: "Best balance of speed and capability",
contextLength: 200_000,
pricing: .init(prompt: 3.0, completion: 15.0),
capabilities: .init(vision: true, tools: true, online: true)
),
ModelInfo(
id: "claude-haiku-4-6",
name: "Claude Haiku 4.6",
description: "Fastest and most affordable",
contextLength: 200_000,
pricing: .init(prompt: 0.80, completion: 4.0),
capabilities: .init(vision: true, tools: true, online: true)
),
// Claude 4.5 series
ModelInfo(
id: "claude-opus-4-5",
name: "Claude Opus 4.5",
description: "Previous generation Opus",
contextLength: 200_000,
pricing: .init(prompt: 15.0, completion: 75.0),
capabilities: .init(vision: true, tools: true, online: true)
),
ModelInfo(
id: "claude-opus-4-5-20251101",
name: "Claude Opus 4.5",
@@ -90,6 +119,14 @@ class AnthropicProvider: AIProvider {
pricing: .init(prompt: 15.0, completion: 75.0),
capabilities: .init(vision: true, tools: true, online: true)
),
ModelInfo(
id: "claude-sonnet-4-5",
name: "Claude Sonnet 4.5",
description: "Best balance of speed and capability",
contextLength: 200_000,
pricing: .init(prompt: 3.0, completion: 15.0),
capabilities: .init(vision: true, tools: true, online: true)
),
ModelInfo(
id: "claude-sonnet-4-5-20250929",
name: "Claude Sonnet 4.5",
@@ -98,6 +135,14 @@ class AnthropicProvider: AIProvider {
pricing: .init(prompt: 3.0, completion: 15.0),
capabilities: .init(vision: true, tools: true, online: true)
),
ModelInfo(
id: "claude-haiku-4-5",
name: "Claude Haiku 4.5",
description: "Fastest and most affordable",
contextLength: 200_000,
pricing: .init(prompt: 0.80, completion: 4.0),
capabilities: .init(vision: true, tools: true, online: true)
),
ModelInfo(
id: "claude-haiku-4-5-20251001",
name: "Claude Haiku 4.5",
@@ -106,6 +151,7 @@ class AnthropicProvider: AIProvider {
pricing: .init(prompt: 0.80, completion: 4.0),
capabilities: .init(vision: true, tools: true, online: true)
),
// Claude 3.x series
ModelInfo(
id: "claude-3-7-sonnet-20250219",
name: "Claude 3.7 Sonnet",
@@ -124,6 +170,14 @@ class AnthropicProvider: AIProvider {
),
]
/// Pricing tiers used for fuzzy fallback matching on unknown model IDs.
/// Keyed by model name prefix (longest match wins).
private static let pricingFallback: [(prefix: String, prompt: Double, completion: Double)] = [
("claude-opus", 15.0, 75.0),
("claude-sonnet", 3.0, 15.0),
("claude-haiku", 0.80, 4.0),
]
/// Fetch live model list from GET /v1/models, enriched with local pricing/context metadata.
/// Falls back to knownModels if the request fails (no key, offline, etc.).
func listModels() async throws -> [ModelInfo] {
@@ -158,14 +212,20 @@ class AnthropicProvider: AIProvider {
guard let id = item["id"] as? String,
id.hasPrefix("claude-") else { return nil }
let displayName = item["display_name"] as? String ?? id
// Exact match first
if let known = enrichment[id] { return known }
// Unknown new model use display name and sensible defaults
// Fuzzy fallback: find the longest prefix that matches
let fallback = Self.pricingFallback
.filter { id.hasPrefix($0.prefix) }
.max(by: { $0.prefix.count < $1.prefix.count })
let pricing = fallback.map { ModelInfo.Pricing(prompt: $0.prompt, completion: $0.completion) }
?? ModelInfo.Pricing(prompt: 0, completion: 0)
return ModelInfo(
id: id,
name: displayName,
description: item["description"] as? String ?? "",
contextLength: 200_000,
pricing: .init(prompt: 0, completion: 0),
pricing: pricing,
capabilities: .init(vision: true, tools: true, online: false)
)
}