Skip to content
Merged
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
4 changes: 2 additions & 2 deletions Examples/web-playground/frontend/helpers/chatModelData.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export const chatModels = [
},
{
modelName: "Anthropic Claude 3.5 Haiku",
modelId: "us.anthropic.claude-3-5-haiku-20241022-v1:0",
modelId: "anthropic.claude-3-5-haiku-20241022-v1:0",
temperatureRange: {
default: 1,
min: 0,
Expand Down Expand Up @@ -287,7 +287,7 @@ export const chatModels = [
// DeepSeek
// {
// modelName: "Deep Seek",
// modelId: "us.deepseek.r1-v1:0",
// modelId: "deepseek.r1-v1:0",
// topPRange: {
// max: 1,
// default: 1,
Expand Down
4 changes: 2 additions & 2 deletions Examples/web-playground/frontend/helpers/modelData.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const models = [
},
{
modelName: "Anthropic Claude 3.5 Haiku",
modelId: "us.anthropic.claude-3-5-haiku-20241022-v1:0",
modelId: "anthropic.claude-3-5-haiku-20241022-v1:0",
temperatureRange: {
min: 0,
max: 1,
Expand Down Expand Up @@ -173,7 +173,7 @@ export const models = [
},
// {
// modelName: "Deep Seek",
// modelId: "us.deepseek.r1-v1:0",
// modelId: "deepseek.r1-v1:0",
// temperatureRange: {
// min: 0,
// max: 1,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const defaultModel = {
modelName: "Claude V3.7 Sonnet",
modelId: "us.anthropic.claude-3-7-sonnet-20250219-v1:0",
modelId: "anthropic.claude-3-7-sonnet-20250219-v1:0",
topKRange: {
max: 500,
default: 0,
Expand Down Expand Up @@ -32,7 +32,7 @@ export const models = [
defaultModel,
// {
// modelName: "Deep Seek",
// modelId: "us.deepseek.r1-v1:0",
// modelId: "deepseek.r1-v1:0",
// topPRange: {
// max: 1,
// default: 1,
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ You can now create instances for any of the models that follow the request and r
```swift
extension BedrockModel {
public static let llama3_3_70b_instruct: BedrockModel = BedrockModel(
id: "us.meta.llama3-3-70b-instruct-v1:0",
id: "meta.llama3-3-70b-instruct-v1:0",
name: "Llama 3.3 70B Instruct",
modality: LlamaText(
parameters: TextGenerationParameters(
Expand Down
15 changes: 13 additions & 2 deletions Sources/BedrockModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import Foundation
public struct BedrockModel: Hashable, Sendable, Equatable, RawRepresentable {
public var rawValue: String { id }

public var id: String
public var name: String
public let id: String
public let name: String
public let modality: any Modality

/// Creates a new BedrockModel instance
Expand Down Expand Up @@ -106,6 +106,17 @@ public struct BedrockModel: Hashable, Sendable, Equatable, RawRepresentable {
}
}

// MARK: Cross region inference
public func getModelIdWithCrossRegionInferencePrefix(region: Region) -> String {
// If the model does not support cross region inference, return the model ID as is
guard let crossRegionInferenceModality = modality as? CrossRegionInferenceModality else {
return id
}
// If the model supports cross region inference, return the model ID with the appropriate prefix
let prefix = crossRegionInferenceModality.crossRegionPrefix(forRegion: region)
return "\(prefix)\(id)"
}

// MARK: Modality checks

// MARK - Text completion
Expand Down
2 changes: 1 addition & 1 deletion Sources/Converse/BedrockService+Converse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ extension BedrockService {
)

logger.trace("Creating ConverseInput")
let input = try converseRequest.getConverseInput()
let input = try converseRequest.getConverseInput(forRegion: self.region)

logger.trace(
"Sending ConverseInput to BedrockRuntimeClient",
Expand Down
2 changes: 1 addition & 1 deletion Sources/Converse/BedrockService+ConverseStreaming.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ extension BedrockService {
)

logger.trace("Creating ConverseStreamingInput")
let input = try converseRequest.getConverseStreamingInput()
let input = try converseRequest.getConverseStreamingInput(forRegion: region)

logger.trace(
"Sending ConverseStreaminInput to BedrockRuntimeClient",
Expand Down
4 changes: 2 additions & 2 deletions Sources/Converse/ConverseRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ public struct ConverseRequest {
}
}

func getConverseInput() throws -> ConverseInput {
func getConverseInput(forRegion region: Region) throws -> ConverseInput {
ConverseInput(
additionalModelRequestFields: try getAdditionalModelRequestFields(),
inferenceConfig: inferenceConfig?.getSDKInferenceConfig(),
messages: try getSDKMessages(),
modelId: model.id,
modelId: model.getModelIdWithCrossRegionInferencePrefix(region: region),
system: getSDKSystemPrompts(),
toolConfig: try toolConfig?.getSDKToolConfig()
)
Expand Down
4 changes: 2 additions & 2 deletions Sources/Converse/ConverseRequestStreaming.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@

public typealias ConverseStreamingRequest = ConverseRequest
extension ConverseStreamingRequest {
func getConverseStreamingInput() throws -> ConverseStreamInput {
func getConverseStreamingInput(forRegion region: Region) throws -> ConverseStreamInput {
ConverseStreamInput(
additionalModelRequestFields: try getAdditionalModelRequestFields(),
inferenceConfig: inferenceConfig?.getSDKInferenceConfig(),
messages: try getSDKMessages(),
modelId: model.id,
modelId: model.getModelIdWithCrossRegionInferencePrefix(region: region),
system: getSDKSystemPrompts(),
toolConfig: try toolConfig?.getSDKToolConfig()
)
Expand Down
77 changes: 30 additions & 47 deletions Sources/InvokeModel/BedrockService+InvokeModelImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,31 +77,9 @@ extension BedrockService {
quality: quality,
resolution: resolution
)
let input: InvokeModelInput = try request.getInvokeModelInput()
logger.trace(
"Sending request to invokeModel",
metadata: [
"model": .string(model.id), "request": .string(String(describing: input)),
]
)
let response = try await self.bedrockRuntimeClient.invokeModel(input: input)
guard let responseBody = response.body else {
logger.trace(
"Invalid response",
metadata: [
"response": .string(String(describing: response)),
"hasBody": .stringConvertible(response.body != nil),
]
)
throw BedrockLibraryError.invalidSDKResponse(
"Something went wrong while extracting body from response."
)
}
let invokemodelResponse: InvokeModelResponse = try InvokeModelResponse.createImageResponse(
body: responseBody,
model: model
)
return try invokemodelResponse.getGeneratedImage()

return try await sendRequest(request: request, model: model)

} catch {
try handleCommonError(error, context: "listing foundation models")
}
Expand Down Expand Up @@ -174,34 +152,39 @@ extension BedrockService {
quality: quality,
resolution: resolution
)
let input: InvokeModelInput = try request.getInvokeModelInput()
return try await sendRequest(request: request, model: model)
} catch {
try handleCommonError(error, context: "invoking image model")
}
}

/// Sends the request to invoke the model and returns the generated image(s)
private func sendRequest(request: InvokeModelRequest, model: BedrockModel) async throws -> ImageGenerationOutput {
let input: InvokeModelInput = try request.getInvokeModelInput(forRegion: self.region)
logger.trace(
"Sending request to invokeModel",
metadata: [
"model": .string(model.id), "request": .string(String(describing: input)),
]
)
let response = try await self.bedrockRuntimeClient.invokeModel(input: input)
guard let responseBody = response.body else {
logger.trace(
"Sending request to invokeModel",
"Invalid response",
metadata: [
"model": .string(model.id), "request": .string(String(describing: input)),
"response": .string(String(describing: response)),
"hasBody": .stringConvertible(response.body != nil),
]
)
let response = try await self.bedrockRuntimeClient.invokeModel(input: input)
guard let responseBody = response.body else {
logger.trace(
"Invalid response",
metadata: [
"response": .string(String(describing: response)),
"hasBody": .stringConvertible(response.body != nil),
]
)
throw BedrockLibraryError.invalidSDKResponse(
"Something went wrong while extracting body from response."
)
}
let invokemodelResponse: InvokeModelResponse = try InvokeModelResponse.createImageResponse(
body: responseBody,
model: model
throw BedrockLibraryError.invalidSDKResponse(
"Something went wrong while extracting body from response."
)
return try invokemodelResponse.getGeneratedImage()
} catch {
try handleCommonError(error, context: "listing foundation models")
}
let invokemodelResponse: InvokeModelResponse = try InvokeModelResponse.createImageResponse(
body: responseBody,
model: model
)
return try invokemodelResponse.getGeneratedImage()
}

/// Generates 1 to 5 image variation(s) from reference images and a text prompt using a specific model
Expand Down
2 changes: 1 addition & 1 deletion Sources/InvokeModel/BedrockService+InvokeModelText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ extension BedrockService {
topK: topK,
stopSequences: stopSequences
)
let input: InvokeModelInput = try request.getInvokeModelInput()
let input: InvokeModelInput = try request.getInvokeModelInput(forRegion: self.region)
logger.trace(
"Sending request to invokeModel",
metadata: [
Expand Down
4 changes: 2 additions & 2 deletions Sources/InvokeModel/InvokeModelRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,14 @@ struct InvokeModelRequest {
/// Creates an InvokeModelInput instance for making a request to Amazon Bedrock
/// - Returns: A configured InvokeModelInput containing the model ID, content type, and encoded request body
/// - Throws: BedrockLibraryError.encodingError if the request body cannot be encoded to JSON
public func getInvokeModelInput() throws -> InvokeModelInput {
public func getInvokeModelInput(forRegion region: Region) throws -> InvokeModelInput {
do {
let jsonData: Data = try JSONEncoder().encode(self.body)
return InvokeModelInput(
accept: self.accept.headerValue,
body: jsonData,
contentType: self.contentType.headerValue,
modelId: model.id
modelId: model.getModelIdWithCrossRegionInferencePrefix(region: region)
)
} catch {
throw BedrockLibraryError.encodingError(
Expand Down
2 changes: 1 addition & 1 deletion Sources/ListModels/ModelSummary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public struct ModelSummary: Encodable {
if sdkModelSummary.responseStreamingSupported != nil {
responseStreamingSupported = sdkModelSummary.responseStreamingSupported!
}
let bedrockModel = BedrockModel(rawValue: modelId) ?? BedrockModel(rawValue: "us.\(modelId)")
let bedrockModel = BedrockModel(rawValue: modelId)

return ModelSummary(
modelName: modelName,
Expand Down
24 changes: 24 additions & 0 deletions Sources/Modalities/CrossRegionInference.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Bedrock Library open source project
//
// Copyright (c) 2025 Amazon.com, Inc. or its affiliates
// and the Swift Bedrock Library project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift Bedrock Library project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

public protocol CrossRegionInferenceModality: Sendable {}
extension CrossRegionInferenceModality {
public func crossRegionPrefix(forRegion region: Region) -> String {
if region.isEURegion() { return "eu." }
if region.isUSRegion() { return "us." }
if region.isAPRegion() { return "ap." }
return ""
}
}
2 changes: 1 addition & 1 deletion Sources/Models/Amazon/Nova/Nova.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import Foundation

struct NovaText: TextModality, ConverseModality, ConverseStreamingModality {
struct NovaText: TextModality, ConverseModality, ConverseStreamingModality, CrossRegionInferenceModality {
func getName() -> String { "Nova Text Generation" }

let parameters: TextGenerationParameters
Expand Down
2 changes: 1 addition & 1 deletion Sources/Models/Anthropic/Anthropic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import Foundation

struct AnthropicText: TextModality, ConverseModality, ConverseStreamingModality {
struct AnthropicText: TextModality, ConverseModality, ConverseStreamingModality, CrossRegionInferenceModality {
let parameters: TextGenerationParameters
let converseParameters: ConverseParameters
let converseFeatures: [ConverseFeature]
Expand Down
14 changes: 7 additions & 7 deletions Sources/Models/Anthropic/AnthropicBedrockModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ extension BedrockModel {
)
)
public static let claudev3_opus: BedrockModel = BedrockModel(
id: "us.anthropic.claude-3-opus-20240229-v1:0",
id: "anthropic.claude-3-opus-20240229-v1:0",
name: "Claude V3 Opus",
modality: ClaudeV3Opus(
parameters: TextGenerationParameters(
Expand Down Expand Up @@ -123,7 +123,7 @@ extension BedrockModel {
)
)
public static let claudev3_5_haiku: BedrockModel = BedrockModel(
id: "us.anthropic.claude-3-5-haiku-20241022-v1:0",
id: "anthropic.claude-3-5-haiku-20241022-v1:0",
name: "Claude V3.5 Haiku",
modality: ClaudeV3_5Haiku(
parameters: TextGenerationParameters(
Expand All @@ -138,7 +138,7 @@ extension BedrockModel {
)
)
public static let claudev3_5_sonnet: BedrockModel = BedrockModel(
id: "us.anthropic.claude-3-5-sonnet-20240620-v1:0",
id: "anthropic.claude-3-5-sonnet-20240620-v1:0",
name: "Claude V3.5 Sonnet",
modality: ClaudeV3_5Sonnet(
parameters: TextGenerationParameters(
Expand All @@ -153,7 +153,7 @@ extension BedrockModel {
)
)
public static let claudev3_5_sonnet_v2: BedrockModel = BedrockModel(
id: "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
id: "anthropic.claude-3-5-sonnet-20241022-v2:0",
name: "Claude V3.5 Sonnet V2",
modality: ClaudeV3_5Sonnet(
parameters: TextGenerationParameters(
Expand All @@ -168,7 +168,7 @@ extension BedrockModel {
)
)
public static let claudev3_7_sonnet: BedrockModel = BedrockModel(
id: "us.anthropic.claude-3-7-sonnet-20250219-v1:0",
id: "anthropic.claude-3-7-sonnet-20250219-v1:0",
name: "Claude V3.7 Sonnet",
modality: ClaudeV3_7Sonnet(
parameters: TextGenerationParameters(
Expand All @@ -184,7 +184,7 @@ extension BedrockModel {
)
)
public static let claude_sonnet_v4: BedrockModel = BedrockModel(
id: "us.anthropic.claude-sonnet-4-20250514-v1:0",
id: "anthropic.claude-sonnet-4-20250514-v1:0",
name: "Claude Sonnet v4",
modality: Claude_Sonnet_v4(
parameters: TextGenerationParameters(
Expand All @@ -200,7 +200,7 @@ extension BedrockModel {
)
)
public static let claude_opus_v4: BedrockModel = BedrockModel(
id: "us.anthropic.claude-opus-4-20250514-v1:0",
id: "anthropic.claude-opus-4-20250514-v1:0",
name: "Claude Opus v4",
modality: Claude_Opus_v4(
parameters: TextGenerationParameters(
Expand Down
2 changes: 1 addition & 1 deletion Sources/Models/DeepSeek/DeepSeek.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Foundation
// filtered to remove the reasoning content blocks before it is sent to the model.
// The same goes for ConverseStreamingModality.

struct DeepSeekText: TextModality {
struct DeepSeekText: TextModality, CrossRegionInferenceModality {
let parameters: TextGenerationParameters
let converseFeatures: [ConverseFeature]
let converseParameters: ConverseParameters
Expand Down
2 changes: 1 addition & 1 deletion Sources/Models/DeepSeek/DeepSeekBedrockModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ typealias DeepSeekR1V1 = DeepSeekText

extension BedrockModel {
public static let deepseek_r1_v1: BedrockModel = BedrockModel(
id: "us.deepseek.r1-v1:0",
id: "deepseek.r1-v1:0",
name: "DeepSeek R1",
modality: DeepSeekR1V1(
parameters: TextGenerationParameters(
Expand Down
Loading