Skip to content

Commit bc5a47f

Browse files
sebstoCopilot
andauthored
add support for OpenAI models (#35)
* add support for OpenAI models * [CI] add openai example to CI tests * optimize regex Co-authored-by: Copilot <[email protected]> * revert incorrect copilot suggestion --------- Co-authored-by: Copilot <[email protected]>
1 parent 6c9f6b6 commit bc5a47f

16 files changed

+415
-8
lines changed

.github/workflows/pull_request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
# We pass the list of examples here, but we can't pass an array as argument
3636
# Instead, we pass a String with a valid JSON array.
3737
# The workaround is mentioned here https://github.com/orgs/community/discussions/11692
38-
examples: "[ 'api-key', 'converse', 'converse-stream', 'text_chat' ]"
38+
examples: "[ 'api-key', 'converse', 'converse-stream', 'openai', 'text_chat' ]"
3939

4040
swift-6-language-mode:
4141
name: Swift 6 Language Mode

Examples/openai/.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

Examples/openai/Package.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// swift-tools-version: 6.1
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: "OpenAI",
8+
platforms: [.macOS(.v15), .iOS(.v18), .tvOS(.v18)],
9+
dependencies: [
10+
// for production use, uncomment the following line
11+
// .package(url: "https://github.com/build-on-aws/swift-bedrock-library.git", branch: "main"),
12+
13+
// for local development, use the following line
14+
.package(name: "swift-bedrock-library", path: "../.."),
15+
16+
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.0"),
17+
],
18+
targets: [
19+
.executableTarget(
20+
name: "OpenAIInvoke",
21+
dependencies: [
22+
.product(name: "BedrockService", package: "swift-bedrock-library"),
23+
.product(name: "Logging", package: "swift-log"),
24+
],
25+
path: "Sources/Invoke"
26+
),
27+
.executableTarget(
28+
name: "OpenAIConverse",
29+
dependencies: [
30+
.product(name: "BedrockService", package: "swift-bedrock-library"),
31+
.product(name: "Logging", package: "swift-log"),
32+
],
33+
path: "Sources/Converse"
34+
),
35+
]
36+
)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
var logger = Logger(label: "OpenAIConverse")
20+
logger.logLevel = .debug
21+
22+
let bedrock = try await BedrockService(
23+
region: .uswest2,
24+
logger: logger,
25+
)
26+
27+
var builder = try ConverseRequestBuilder(with: .openai_gpt_oss_20b)
28+
.withPrompt("Who are you?")
29+
30+
var reply = try await bedrock.converse(with: builder)
31+
32+
print("Assistant: \(reply)")
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
var logger = Logger(label: "OpenAIInvoke")
20+
logger.logLevel = .debug
21+
22+
let bedrock = try await BedrockService(
23+
region: .uswest2,
24+
logger: logger
25+
)
26+
27+
let textCompletion = try await bedrock.completeText(
28+
"Who are you?",
29+
with: .openai_gpt_oss_20b
30+
)
31+
32+
if let reasoning = textCompletion.reasoning {
33+
print("------- Reasoning ----------\n\(reasoning)\n----------------------------\n")
34+
}
35+
print(textCompletion.completion)

Sources/BedrockModel.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ public struct BedrockModel: Hashable, Sendable, Equatable, RawRepresentable {
101101
//cohere
102102
case BedrockModel.cohere_command_R_plus.id: self = BedrockModel.cohere_command_R_plus
103103
case BedrockModel.cohere_command_R.id: self = BedrockModel.cohere_command_R
104+
// OpenAI
105+
case BedrockModel.openai_gpt_oss_20b.id: self = BedrockModel.openai_gpt_oss_20b
106+
case BedrockModel.openai_gpt_oss_120b.id: self = BedrockModel.openai_gpt_oss_120b
104107
default:
105108
return nil
106109
}

Sources/Converse/ConverseReply.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//
1414
//===----------------------------------------------------------------------===//
1515

16-
public struct ConverseReply: Codable, CustomStringConvertible {
16+
public struct ConverseReply: Codable, Sendable, CustomStringConvertible {
1717
let history: History
1818
let textReply: String?
1919
let toolUse: ToolUseBlock?

Sources/InvokeModel/BedrockService+InvokeModelImage.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ extension BedrockService {
182182
}
183183
let invokemodelResponse: InvokeModelResponse = try InvokeModelResponse.createImageResponse(
184184
body: responseBody,
185-
model: model
185+
model: model,
186+
logger: self.logger
186187
)
187188
return try invokemodelResponse.getGeneratedImage()
188189
}

Sources/InvokeModel/BedrockService+InvokeModelText.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ extension BedrockService {
119119

120120
let invokemodelResponse: InvokeModelResponse = try InvokeModelResponse.createTextResponse(
121121
body: responseBody,
122-
model: model
122+
model: model,
123+
logger: self.logger
123124
)
124125
logger.trace(
125126
"Generated text completion",

Sources/InvokeModel/InvokeModelResponse.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
@preconcurrency import AWSBedrockRuntime
1717
import Foundation
18+
import Logging
1819

1920
public struct InvokeModelResponse {
2021
let model: BedrockModel
@@ -50,9 +51,10 @@ public struct InvokeModelResponse {
5051
/// - model: The Bedrock model that generated the response
5152
/// - Throws: BedrockLibraryError.invalidModel if the model is not supported
5253
/// BedrockLibraryError.invalidResponseBody if the response cannot be decoded
53-
static func createTextResponse(body data: Data, model: BedrockModel) throws -> Self {
54+
static func createTextResponse(body data: Data, model: BedrockModel, logger: Logger) throws -> Self {
5455
do {
5556
let textModality = try model.getTextModality()
57+
logger.trace("Raw response data:\n\(String(data: data, encoding: .utf8) ?? "")\n")
5658
return self.init(model: model, textCompletionBody: try textModality.getTextResponseBody(from: data))
5759
} catch {
5860
throw BedrockLibraryError.invalidSDKResponseBody(data)
@@ -65,9 +67,10 @@ public struct InvokeModelResponse {
6567
/// - model: The Bedrock model that generated the response
6668
/// - Throws: BedrockLibraryError.invalidModel if the model is not supported
6769
/// BedrockLibraryError.invalidResponseBody if the response cannot be decoded
68-
static func createImageResponse(body data: Data, model: BedrockModel) throws -> Self {
70+
static func createImageResponse(body data: Data, model: BedrockModel, logger: Logger) throws -> Self {
6971
do {
7072
let imageModality = try model.getImageModality()
73+
logger.trace("Raw response", metadata: ["Data": "\(String(data: data, encoding: .utf8) ?? "")"])
7174
return self.init(model: model, imageGenerationBody: try imageModality.getImageResponseBody(from: data))
7275
} catch {
7376
throw BedrockLibraryError.invalidSDKResponseBody(data)

0 commit comments

Comments
 (0)