Add AI request error states
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
public enum AIRequestState: Equatable, Sendable {
|
||||||
|
case idle
|
||||||
|
case loading
|
||||||
|
case failed(AIProviderErrorState)
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AIProviderErrorState: Equatable, Sendable {
|
||||||
|
case offline
|
||||||
|
case missingConfiguration
|
||||||
|
case rateLimited(retryAfter: TimeInterval?)
|
||||||
|
case unavailable
|
||||||
|
case invalidResponse
|
||||||
|
case unsupportedCapability
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AIProviderErrorPresenter: Sendable {
|
||||||
|
public init() {}
|
||||||
|
|
||||||
|
public func state(for error: Error) -> AIProviderErrorState {
|
||||||
|
if let urlError = error as? URLError,
|
||||||
|
urlError.code == .notConnectedToInternet || urlError.code == .networkConnectionLost {
|
||||||
|
return .offline
|
||||||
|
}
|
||||||
|
|
||||||
|
if let clientError = error as? OpenAIClientError {
|
||||||
|
switch clientError {
|
||||||
|
case .missingAPIKey:
|
||||||
|
return .missingConfiguration
|
||||||
|
case let .rateLimited(retryAfter):
|
||||||
|
return .rateLimited(retryAfter: retryAfter)
|
||||||
|
case .serverError, .unacceptableStatusCode:
|
||||||
|
return .unavailable
|
||||||
|
case .invalidResponse:
|
||||||
|
return .invalidResponse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if error as? AIServiceCapabilityError != nil {
|
||||||
|
return .unsupportedCapability
|
||||||
|
}
|
||||||
|
|
||||||
|
return .unavailable
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import MusicAssistantCore
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
final class AIRequestStateTests: XCTestCase {
|
||||||
|
func testPresenterMapsOfflineAndProviderFailures() {
|
||||||
|
let presenter = AIProviderErrorPresenter()
|
||||||
|
|
||||||
|
XCTAssertEqual(presenter.state(for: URLError(.notConnectedToInternet)), .offline)
|
||||||
|
XCTAssertEqual(presenter.state(for: OpenAIClientError.missingAPIKey), .missingConfiguration)
|
||||||
|
XCTAssertEqual(presenter.state(for: OpenAIClientError.rateLimited(retryAfter: 30)), .rateLimited(retryAfter: 30))
|
||||||
|
XCTAssertEqual(presenter.state(for: OpenAIClientError.serverError(503)), .unavailable)
|
||||||
|
XCTAssertEqual(presenter.state(for: OpenAIClientError.invalidResponse), .invalidResponse)
|
||||||
|
XCTAssertEqual(presenter.state(for: AIServiceCapabilityError.discussionNotSupported), .unsupportedCapability)
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -113,7 +113,7 @@ requirement is missing and blocks implementation, record it in
|
|||||||
## Phase 9 --- Quality
|
## Phase 9 --- Quality
|
||||||
|
|
||||||
- [x] Add validation for contradictory/invalid project settings.
|
- [x] Add validation for contradictory/invalid project settings.
|
||||||
- [ ] Add loading, offline and provider-error states.
|
- [x] Add loading, offline and provider-error states.
|
||||||
- [ ] Add accessibility labels and keyboard navigation.
|
- [ ] Add accessibility labels and keyboard navigation.
|
||||||
- [ ] Test project/version recovery.
|
- [ ] Test project/version recovery.
|
||||||
- [ ] Test AI output against locked user choices.
|
- [ ] Test AI output against locked user choices.
|
||||||
|
|||||||
Reference in New Issue
Block a user