Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Sources/Conduit/Core/Types/GeneratedContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ public struct GeneratedContent: Sendable, Equatable, Generable, CustomDebugStrin
case .bool(let value):
return value
case .number(let value):
return value
// JSON cannot represent NaN or infinities; map them to null.
return value.isFinite ? value : NSNull()
case .string(let value):
return value
case .array(let elements):
Expand Down
7 changes: 4 additions & 3 deletions Sources/Conduit/ModelManagement/ModelRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ public enum ModelRegistry {
/// - 7 MLX text generation models
/// - 3 MLX embedding models
/// - 5 HuggingFace cloud models
/// - 3 Kimi cloud models
/// - 1 Apple Foundation Model
/// - 3 Kimi cloud models
///
Expand Down Expand Up @@ -539,8 +540,7 @@ public enum ModelRegistry {

/// Get all models for a specific provider.
///
/// Filters the model catalog by provider type (MLX, HuggingFace, or
/// Apple Foundation Models).
/// Filters the model catalog by provider type.
///
/// ## Usage
/// ```swift
Expand Down Expand Up @@ -614,7 +614,8 @@ public enum ModelRegistry {

/// Get all cloud-based models requiring network access.
///
/// Cloud models include all HuggingFace inference API models.
/// Cloud models include providers that require network access
/// (for example HuggingFace and Kimi).
/// These models require an internet connection and API key.
///
/// ## Usage
Expand Down
17 changes: 17 additions & 0 deletions Tests/ConduitTests/Core/GeneratedContentTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Testing
@testable import Conduit

@Suite("GeneratedContent")
struct GeneratedContentTests {
@Test("jsonString serializes finite numbers")
func jsonStringFiniteNumber() {
let content = GeneratedContent(kind: .number(42.5))
#expect(content.jsonString == "42.5")
}

@Test("jsonString maps non-finite numbers to null")
func jsonStringNonFiniteNumber() {
let content = GeneratedContent(kind: .number(.nan))
#expect(content.jsonString == "null")
}
}
8 changes: 4 additions & 4 deletions Tests/ConduitTests/Core/ModelIdentifierTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ final class ModelIdentifierTests: XCTestCase {
let reasoningModels = ModelRegistry.models(with: .reasoning)
let transcriptionModels = ModelRegistry.models(with: .transcription)

XCTAssertEqual(textGenModels.count, 15) // Most models support text generation
XCTAssertEqual(textGenModels.count, 15) // Includes Kimi cloud models
XCTAssertEqual(embeddingModels.count, 3) // BGE small, BGE large, Nomic
XCTAssertEqual(codeGenModels.count, 5) // Phi-3 Mini, Phi-4, Llama 3.1 70B, Kimi K2.5, Kimi K2
XCTAssertEqual(reasoningModels.count, 6) // Phi-3 Mini, Phi-4, Llama 3.1 70B, DeepSeek R1, Kimi K2.5, Kimi K1.5
Expand Down Expand Up @@ -522,15 +522,15 @@ final class ModelIdentifierTests: XCTestCase {
func testRegistryCloudModels() {
let cloudModels = ModelRegistry.cloudModels()

// Cloud models include HuggingFace + Kimi models.
// Cloud models should include HuggingFace and Kimi.
XCTAssertEqual(cloudModels.count, 8)

// All should require network
XCTAssertTrue(cloudModels.allSatisfy { $0.identifier.requiresNetwork })
XCTAssertTrue(cloudModels.allSatisfy { !$0.identifier.isLocal })

let providers = Set(cloudModels.map { $0.identifier.provider })
XCTAssertEqual(providers, [.huggingFace, .kimi])
// All should be cloud providers currently represented by HuggingFace or Kimi.
XCTAssertTrue(cloudModels.allSatisfy { [.huggingFace, .kimi].contains($0.identifier.provider) })
}

// MARK: - ProviderType Tests
Expand Down
Loading