Several bugs fixed
This commit is contained in:
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user