Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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: "listing foundation models")
}
}

/// 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
Loading