Skip to content

Commit

Permalink
[Vertex AI] Renamed RPCError to BackendError (#14027)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewheard authored Nov 5, 2024
1 parent 0a49232 commit fb856dc
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 63 deletions.
53 changes: 0 additions & 53 deletions FirebaseVertexAI/Sources/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,59 +14,6 @@

import Foundation

struct RPCError: Error {
let httpResponseCode: Int
let message: String
let status: RPCStatus
let details: [ErrorDetails]

private var errorInfo: ErrorDetails? {
return details.first { $0.isErrorInfo() }
}

init(httpResponseCode: Int, message: String, status: RPCStatus, details: [ErrorDetails]) {
self.httpResponseCode = httpResponseCode
self.message = message
self.status = status
self.details = details
}

func isVertexAIInFirebaseServiceDisabledError() -> Bool {
return details.contains { $0.isVertexAIInFirebaseServiceDisabledErrorDetails() }
}
}

extension RPCError: Decodable {
enum CodingKeys: CodingKey {
case error
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let status = try container.decode(ErrorStatus.self, forKey: .error)

if let code = status.code {
httpResponseCode = code
} else {
httpResponseCode = -1
}

if let message = status.message {
self.message = message
} else {
message = "Unknown error."
}

if let rpcStatus = status.status {
self.status = rpcStatus
} else {
self.status = .unknown
}

details = status.details
}
}

struct ErrorStatus {
let code: Int?
let message: String?
Expand Down
4 changes: 2 additions & 2 deletions FirebaseVertexAI/Sources/GenerativeAIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ struct GenerativeAIService {

private func parseError(responseData: Data) -> Error {
do {
let rpcError = try JSONDecoder().decode(RPCError.self, from: responseData)
let rpcError = try JSONDecoder().decode(BackendError.self, from: responseData)
logRPCError(rpcError)
return rpcError
} catch {
Expand All @@ -262,7 +262,7 @@ struct GenerativeAIService {

// Log specific RPC errors that cannot be mitigated or handled by user code.
// These errors do not produce specific GenerateContentError or CountTokensError cases.
private func logRPCError(_ error: RPCError) {
private func logRPCError(_ error: BackendError) {
if error.isVertexAIInFirebaseServiceDisabledError() {
VertexLog.error(code: .vertexAIInFirebaseAPIDisabled, """
The Vertex AI in Firebase SDK requires the Vertex AI in Firebase API \
Expand Down
68 changes: 68 additions & 0 deletions FirebaseVertexAI/Sources/Types/Internal/Errors/BackendError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Foundation

struct BackendError: Error {
let httpResponseCode: Int
let message: String
let status: RPCStatus
let details: [ErrorDetails]

private var errorInfo: ErrorDetails? {
return details.first { $0.isErrorInfo() }
}

init(httpResponseCode: Int, message: String, status: RPCStatus, details: [ErrorDetails]) {
self.httpResponseCode = httpResponseCode
self.message = message
self.status = status
self.details = details
}

func isVertexAIInFirebaseServiceDisabledError() -> Bool {
return details.contains { $0.isVertexAIInFirebaseServiceDisabledErrorDetails() }
}
}

extension BackendError: Decodable {
enum CodingKeys: CodingKey {
case error
}

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let status = try container.decode(ErrorStatus.self, forKey: .error)

if let code = status.code {
httpResponseCode = code
} else {
httpResponseCode = -1
}

if let message = status.message {
self.message = message
} else {
message = "Unknown error."
}

if let rpcStatus = status.status {
self.status = rpcStatus
} else {
self.status = .unknown
}

details = status.details
}
}
16 changes: 8 additions & 8 deletions FirebaseVertexAI/Tests/Unit/GenerativeModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ final class GenerativeModelTests: XCTestCase {
do {
_ = try await model.generateContent(testPrompt)
XCTFail("Should throw GenerateContentError.internalError; no error thrown.")
} catch let GenerateContentError.internalError(error as RPCError) {
} catch let GenerateContentError.internalError(error as BackendError) {
XCTAssertEqual(error.httpResponseCode, 400)
XCTAssertEqual(error.status, .invalidArgument)
XCTAssertEqual(error.message, "API key not valid. Please pass a valid API key.")
Expand All @@ -524,7 +524,7 @@ final class GenerativeModelTests: XCTestCase {
do {
_ = try await model.generateContent(testPrompt)
XCTFail("Should throw GenerateContentError.internalError; no error thrown.")
} catch let GenerateContentError.internalError(error as RPCError) {
} catch let GenerateContentError.internalError(error as BackendError) {
XCTAssertEqual(error.httpResponseCode, expectedStatusCode)
XCTAssertEqual(error.status, .permissionDenied)
XCTAssertTrue(error.message
Expand Down Expand Up @@ -607,7 +607,7 @@ final class GenerativeModelTests: XCTestCase {
do {
_ = try await model.generateContent(testPrompt)
XCTFail("Should throw GenerateContentError.internalError; no error thrown.")
} catch let GenerateContentError.internalError(underlying: rpcError as RPCError) {
} catch let GenerateContentError.internalError(underlying: rpcError as BackendError) {
XCTAssertEqual(rpcError.status, .invalidArgument)
XCTAssertEqual(rpcError.httpResponseCode, expectedStatusCode)
XCTAssertEqual(rpcError.message, "Request contains an invalid argument.")
Expand Down Expand Up @@ -706,7 +706,7 @@ final class GenerativeModelTests: XCTestCase {
do {
_ = try await model.generateContent(testPrompt)
XCTFail("Should throw GenerateContentError.internalError; no error thrown.")
} catch let GenerateContentError.internalError(underlying: rpcError as RPCError) {
} catch let GenerateContentError.internalError(underlying: rpcError as BackendError) {
XCTAssertEqual(rpcError.status, .notFound)
XCTAssertEqual(rpcError.httpResponseCode, expectedStatusCode)
XCTAssertTrue(rpcError.message.hasPrefix("models/unknown is not found"))
Expand Down Expand Up @@ -849,7 +849,7 @@ final class GenerativeModelTests: XCTestCase {
for try await _ in stream {
XCTFail("No content is there, this shouldn't happen.")
}
} catch let GenerateContentError.internalError(error as RPCError) {
} catch let GenerateContentError.internalError(error as BackendError) {
XCTAssertEqual(error.httpResponseCode, 400)
XCTAssertEqual(error.status, .invalidArgument)
XCTAssertEqual(error.message, "API key not valid. Please pass a valid API key.")
Expand All @@ -873,7 +873,7 @@ final class GenerativeModelTests: XCTestCase {
for try await _ in stream {
XCTFail("No content is there, this shouldn't happen.")
}
} catch let GenerateContentError.internalError(error as RPCError) {
} catch let GenerateContentError.internalError(error as BackendError) {
XCTAssertEqual(error.httpResponseCode, expectedStatusCode)
XCTAssertEqual(error.status, .permissionDenied)
XCTAssertTrue(error.message
Expand Down Expand Up @@ -1190,7 +1190,7 @@ final class GenerativeModelTests: XCTestCase {
XCTAssertNotNil(content.text)
responseCount += 1
}
} catch let GenerateContentError.internalError(rpcError as RPCError) {
} catch let GenerateContentError.internalError(rpcError as BackendError) {
XCTAssertEqual(rpcError.httpResponseCode, 499)
XCTAssertEqual(rpcError.status, .cancelled)

Expand Down Expand Up @@ -1374,7 +1374,7 @@ final class GenerativeModelTests: XCTestCase {
do {
_ = try await model.countTokens("Why is the sky blue?")
XCTFail("Request should not have succeeded.")
} catch let rpcError as RPCError {
} catch let rpcError as BackendError {
XCTAssertEqual(rpcError.httpResponseCode, 404)
XCTAssertEqual(rpcError.status, .notFound)
XCTAssert(rpcError.message.hasPrefix("models/test-model-name is not found"))
Expand Down

0 comments on commit fb856dc

Please sign in to comment.