Skip to content

Commit cbb5e47

Browse files
authored
Add Global Cross-Region Inference and Claude Opus 4.5 Support (#63)
* add invoke model example * add opus 4.5 and support froo global Cross region inference
1 parent 1ddfa78 commit cbb5e47

File tree

8 files changed

+238
-9
lines changed

8 files changed

+238
-9
lines changed

Examples/invoke-model/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// swift-tools-version: 6.0
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "InvokeModel",
8+
platforms: [.macOS(.v15), .iOS(.v18), .tvOS(.v18)],
9+
products: [
10+
.executable(name: "InvokeModel", targets: ["InvokeModel"])
11+
],
12+
dependencies: [
13+
// for production use, uncomment the following line
14+
// .package(url: "https://github.com/build-on-aws/swift-bedrock-library.git", branch: "main"),
15+
16+
// for local development, use the following line
17+
.package(name: "swift-bedrock-library", path: "../.."),
18+
19+
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.0"),
20+
],
21+
targets: [
22+
.executableTarget(
23+
name: "InvokeModel",
24+
dependencies: [
25+
.product(name: "BedrockService", package: "swift-bedrock-library"),
26+
.product(name: "Logging", package: "swift-log"),
27+
]
28+
)
29+
]
30+
)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Bedrock Library open source project
4+
//
5+
// Copyright (c) 2025 Amazon.com, Inc. or its affiliates
6+
// and the Swift Bedrock Library project authors
7+
// Licensed under Apache License v2.0
8+
//
9+
// See LICENSE.txt for license information
10+
// See CONTRIBUTORS.txt for the list of Swift Bedrock Library project authors
11+
//
12+
// SPDX-License-Identifier: Apache-2.0
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
import BedrockService
17+
import Logging
18+
19+
@main
20+
struct InvokeModel {
21+
static func main() async throws {
22+
do {
23+
try await InvokeModel.run()
24+
} catch {
25+
print("Error:\n\(error)")
26+
}
27+
}
28+
static func run() async throws {
29+
var logger = Logger(label: "InvokeModel")
30+
logger.logLevel = .debug
31+
32+
let bedrock = try await BedrockService(
33+
region: .useast1,
34+
logger: logger
35+
// uncomment if you use SSO with AWS Identity Center
36+
// authentication: .sso
37+
)
38+
39+
let model: BedrockModel = .claude_opus_v4_5
40+
41+
let response = try await bedrock.completeText("who are you?", with: model)
42+
43+
print(response.completion)
44+
}
45+
}

Sources/BedrockService/BedrockRuntimeClient/Modalities/CrossRegionInference.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
//
1414
//===----------------------------------------------------------------------===//
1515

16+
// https://docs.aws.amazon.com/bedrock/latest/userguide/cross-region-inference.html
17+
1618
public protocol CrossRegionInferenceModality: Sendable {}
1719
extension CrossRegionInferenceModality {
1820
public func crossRegionPrefix(forRegion region: Region) -> String {
@@ -22,3 +24,8 @@ extension CrossRegionInferenceModality {
2224
return ""
2325
}
2426
}
27+
28+
public protocol GlobalCrossRegionInferenceModality: Sendable {}
29+
extension GlobalCrossRegionInferenceModality {
30+
public func crossRegionPrefix() -> String { "global." }
31+
}

Sources/BedrockService/Models/Anthropic/Anthropic.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ struct AnthropicText: TextModality, ConverseModality, ConverseStreamingModality,
6767
return AnthropicRequestBody(
6868
prompt: prompt,
6969
maxTokens: maxTokens,
70-
temperature: temperature ?? parameters.temperature.defaultValue,
71-
topP: topP ?? parameters.topP.defaultValue,
70+
temperature: temperature,
71+
topP: topP,
7272
topK: topK ?? parameters.topK.defaultValue,
7373
stopSequences: stopSequences ?? parameters.stopSequences.defaultValue
7474
)

Sources/BedrockService/Models/Anthropic/AnthropicBedrockModels.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ typealias ClaudeV3_5Sonnet = AnthropicText
3030
typealias ClaudeV3_7Sonnet = AnthropicText
3131
typealias Claude_Sonnet_v4 = AnthropicText
3232
typealias Claude_Opus_v4 = AnthropicText
33-
typealias Claude_Sonnet_v4_5 = AnthropicText
3433

3534
// text
3635
// https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html
@@ -236,4 +235,20 @@ extension BedrockModel {
236235
maxReasoningTokens: Parameter(.maxReasoningTokens, minValue: 1_024, maxValue: 8_191, defaultValue: 4_096)
237236
)
238237
)
238+
public static let claude_opus_v4_5: BedrockModel = BedrockModel(
239+
id: "anthropic.claude-opus-4-5-20251101-v1:0",
240+
name: "Claude Opus v4.5",
241+
modality: Claude_Opus_v4_5(
242+
parameters: TextGenerationParameters(
243+
temperature: Parameter(.temperature, minValue: 0, maxValue: 1, defaultValue: 1),
244+
maxTokens: Parameter(.maxTokens, minValue: 1, maxValue: 32_000, defaultValue: 8_192),
245+
topP: Parameter(.topP, minValue: 0, maxValue: 1, defaultValue: 0.999),
246+
topK: Parameter(.topK, minValue: 0, maxValue: 500, defaultValue: 0),
247+
stopSequences: StopSequenceParams(maxSequences: 8191, defaultValue: []),
248+
maxPromptSize: 200_000
249+
),
250+
features: [.textGeneration, .systemPrompts, .document, .vision, .toolUse, .reasoning],
251+
maxReasoningTokens: Parameter(.maxReasoningTokens, minValue: 1_024, maxValue: 8_191, defaultValue: 4_096)
252+
)
253+
)
239254
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Bedrock Library open source project
4+
//
5+
// Copyright (c) 2025 Amazon.com, Inc. or its affiliates
6+
// and the Swift Bedrock Library project authors
7+
// Licensed under Apache License v2.0
8+
//
9+
// See LICENSE.txt for license information
10+
// See CONTRIBUTORS.txt for the list of Swift Bedrock Library project authors
11+
//
12+
// SPDX-License-Identifier: Apache-2.0
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#if canImport(FoundationEssentials)
17+
import FoundationEssentials
18+
#else
19+
import Foundation
20+
#endif
21+
22+
// Wrapper structs for v4.5 models to support GlobalCrossRegionInferenceModality
23+
struct Claude_Sonnet_v4_5: TextModality, ConverseModality, ConverseStreamingModality, GlobalCrossRegionInferenceModality
24+
{
25+
private let anthropicText: AnthropicText
26+
27+
let converseParameters: ConverseParameters
28+
let converseFeatures: [ConverseFeature]
29+
30+
init(parameters: TextGenerationParameters, features: [ConverseFeature], maxReasoningTokens: Parameter<Int>) {
31+
self.anthropicText = AnthropicText(
32+
parameters: parameters,
33+
features: features,
34+
maxReasoningTokens: maxReasoningTokens
35+
)
36+
self.converseParameters = anthropicText.converseParameters
37+
self.converseFeatures = anthropicText.converseFeatures
38+
}
39+
40+
func getName() -> String { anthropicText.getName() }
41+
func getParameters() -> TextGenerationParameters { anthropicText.getParameters() }
42+
func getConverseParameters() -> ConverseParameters { anthropicText.getConverseParameters() }
43+
func getConverseFeatures() -> [ConverseFeature] { anthropicText.getConverseFeatures() }
44+
45+
func getTextRequestBody(
46+
prompt: String,
47+
maxTokens: Int?,
48+
temperature: Double?,
49+
topP: Double?,
50+
topK: Int?,
51+
stopSequences: [String]?,
52+
serviceTier: ServiceTier
53+
) throws -> BedrockBodyCodable {
54+
try anthropicText.getTextRequestBody(
55+
prompt: prompt,
56+
maxTokens: maxTokens,
57+
temperature: temperature,
58+
topP: topP,
59+
topK: topK,
60+
stopSequences: stopSequences,
61+
serviceTier: serviceTier
62+
)
63+
}
64+
65+
func getTextResponseBody(from data: Data) throws -> ContainsTextCompletion {
66+
try anthropicText.getTextResponseBody(from: data)
67+
}
68+
}
69+
70+
struct Claude_Opus_v4_5: TextModality, ConverseModality, ConverseStreamingModality, GlobalCrossRegionInferenceModality {
71+
private let anthropicText: AnthropicText
72+
73+
let converseParameters: ConverseParameters
74+
let converseFeatures: [ConverseFeature]
75+
76+
init(parameters: TextGenerationParameters, features: [ConverseFeature], maxReasoningTokens: Parameter<Int>) {
77+
self.anthropicText = AnthropicText(
78+
parameters: parameters,
79+
features: features,
80+
maxReasoningTokens: maxReasoningTokens
81+
)
82+
self.converseParameters = anthropicText.converseParameters
83+
self.converseFeatures = anthropicText.converseFeatures
84+
}
85+
86+
func getName() -> String { anthropicText.getName() }
87+
func getParameters() -> TextGenerationParameters { anthropicText.getParameters() }
88+
func getConverseParameters() -> ConverseParameters { anthropicText.getConverseParameters() }
89+
func getConverseFeatures() -> [ConverseFeature] { anthropicText.getConverseFeatures() }
90+
91+
func getTextRequestBody(
92+
prompt: String,
93+
maxTokens: Int?,
94+
temperature: Double?,
95+
topP: Double?,
96+
topK: Int?,
97+
stopSequences: [String]?,
98+
serviceTier: ServiceTier
99+
) throws -> BedrockBodyCodable {
100+
try anthropicText.getTextRequestBody(
101+
prompt: prompt,
102+
maxTokens: maxTokens,
103+
temperature: temperature,
104+
topP: topP,
105+
topK: topK,
106+
stopSequences: stopSequences,
107+
serviceTier: serviceTier
108+
)
109+
}
110+
111+
func getTextResponseBody(from data: Data) throws -> ContainsTextCompletion {
112+
try anthropicText.getTextResponseBody(from: data)
113+
}
114+
}

Sources/BedrockService/Models/BedrockModel.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ public struct BedrockModel: Hashable, Sendable, Equatable, RawRepresentable {
8181
self = BedrockModel.claude_opus_v4
8282
case BedrockModel.claude_sonnet_v4_5.id:
8383
self = BedrockModel.claude_sonnet_v4_5
84+
case BedrockModel.claude_opus_v4_5.id:
85+
self = BedrockModel.claude_opus_v4_5
8486
// titan
8587
case BedrockModel.titan_text_g1_premier.id:
8688
self = BedrockModel.titan_text_g1_premier
@@ -132,13 +134,21 @@ public struct BedrockModel: Hashable, Sendable, Equatable, RawRepresentable {
132134

133135
// MARK: Cross region inference
134136
public func getModelIdWithCrossRegionInferencePrefix(region: Region) -> String {
135-
// If the model does not support cross region inference, return the model ID as is
136-
guard let crossRegionInferenceModality = modality as? CrossRegionInferenceModality else {
137-
return id
137+
138+
// If the model support global cross region inference, return the global ID first
139+
if let globalCrossRegionInferenceModality = modality as? GlobalCrossRegionInferenceModality {
140+
let prefix = globalCrossRegionInferenceModality.crossRegionPrefix()
141+
return "\(prefix)\(id)"
142+
}
143+
144+
// If the model support cross region inference, return the regional ID
145+
if let crossRegionInferenceModality = modality as? CrossRegionInferenceModality {
146+
let prefix = crossRegionInferenceModality.crossRegionPrefix(forRegion: region)
147+
return "\(prefix)\(id)"
138148
}
139-
// If the model supports cross region inference, return the model ID with the appropriate prefix
140-
let prefix = crossRegionInferenceModality.crossRegionPrefix(forRegion: region)
141-
return "\(prefix)\(id)"
149+
150+
// otherwise, returns the Id
151+
return id
142152
}
143153

144154
// MARK: Modality checks

0 commit comments

Comments
 (0)