Skip to content

PR 3: Ollama Provider Protocol Conformance #4

Description

@gilmanb1

Overview

Update the existing OllamaCategorizationProvider to conform to the new LLMCategorizationProvider protocol. This preserves all existing Ollama functionality while enabling it to participate in the provider cascade.

Dependencies

Note: Can be developed in parallel with PR 2 (Apple Intelligence Provider).

Files to Modify

File Action Description
Sources/SortAI/Core/LLM/OllamaCategorizationProvider.swift Modify Add protocol conformance
Sources/SortAI/Core/LLM/OllamaModelManager.swift Minor updates Ensure compatibility

Implementation Details

1. Protocol Conformance

The existing Ollama provider needs these additions:

extension OllamaCategorizationProvider: LLMCategorizationProvider {
    var identifier: String { "ollama" }
    var priority: Int { 2 }  // After Apple Intelligence
    
    var supportsModelSelection: Bool { true }
    var supportsTemperature: Bool { true }
    var supportsCustomPrompts: Bool { true }
    
    func isAvailable() async -> Bool {
        // Use existing OllamaModelManager availability check
        return await modelManager.isServerAvailable()
    }
    
    func categorize(signature: FileSignature) async throws -> CategorizationResult {
        // Wrap existing categorization logic
        let response = try await performCategorization(signature)
        
        return CategorizationResult(
            categoryPath: response.categoryPath,
            confidence: response.confidence,
            rationale: response.rationale,
            extractedKeywords: response.keywords,
            provider: identifier,
            escalationThreshold: escalationThreshold
        )
    }
}

2. Preserve Existing Features

These existing features must continue to work:

  • Model fallback chain: deepseek-r1:8bllama3.2llama3.1mistralphi3
  • Auto-download missing models
  • Custom server URL configuration
  • Health monitoring with exponential backoff
  • Temperature and model selection

3. Response Mapping

Map existing Ollama response format to new CategorizationResult:

private func mapOllamaResponse(_ response: OllamaResponse) -> CategorizationResult {
    // Parse category path from Ollama's JSON response
    let categoryPath = CategoryPath(path: response.category)
    
    // Map confidence (Ollama often returns 0-100, normalize to 0-1)
    let normalizedConfidence = response.confidence > 1.0 
        ? response.confidence / 100.0 
        : response.confidence
    
    return CategorizationResult(
        categoryPath: categoryPath,
        confidence: normalizedConfidence,
        rationale: response.explanation ?? "Categorized by Ollama",
        extractedKeywords: response.keywords ?? [],
        provider: identifier,
        escalationThreshold: escalationThreshold
    )
}

Acceptance Criteria

  • Implements LLMCategorizationProvider protocol
  • All existing Ollama functionality preserved
  • Model fallback chain continues to work
  • Returns proper CategorizationResult with provider tracking
  • Existing tests continue to pass
  • No breaking changes to existing API

Testing

func testOllamaProtocolConformance() async {
    let provider = OllamaCategorizationProvider()
    
    XCTAssertEqual(provider.identifier, "ollama")
    XCTAssertEqual(provider.priority, 2)
    XCTAssertTrue(provider.supportsModelSelection)
    XCTAssertTrue(provider.supportsTemperature)
}

func testOllamaAvailabilityCheck() async {
    let provider = OllamaCategorizationProvider()
    let available = await provider.isAvailable()
    // Result depends on whether Ollama server is running
    XCTAssertNotNil(available)
}

func testOllamaCategorizationReturnsResult() async throws {
    // Only run if Ollama is available
    let provider = OllamaCategorizationProvider()
    guard await provider.isAvailable() else {
        throw XCTSkip("Ollama not available")
    }
    
    let signature = FileSignature.mock(filename: "test.pdf")
    let result = try await provider.categorize(signature: signature)
    
    XCTAssertEqual(result.provider, "ollama")
}

Backward Compatibility

This PR must maintain backward compatibility:

Feature Before After
Direct Ollama usage ✅ Works ✅ Still works
Model selection ✅ Works ✅ Still works
Server URL config ✅ Works ✅ Still works
Health checks ✅ Works ✅ Still works

Estimated Size

~50-100 lines of code (mostly protocol conformance additions)

Risk Assessment

Low - No functional changes, just interface adaptation. Existing tests serve as regression safety net.

Metadata

Metadata

Assignees

No one assigned

    Labels

    llm-providerLLM provider infrastructurephase-2Phase 2 - Parallel development

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions