Skip to content

Commit 8afe02d

Browse files
committed
Use new config components in all url builders
1 parent f84bf49 commit 8afe02d

File tree

8 files changed

+90
-63
lines changed

8 files changed

+90
-63
lines changed

Sources/OpenAI/OpenAI.swift

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -347,28 +347,6 @@ extension OpenAI {
347347
AssistantsURLBuilder(configuration: configuration, path: path, assistantId: assistantId)
348348
.buildURL()
349349
}
350-
351-
func buildURL(path: String) -> URL {
352-
var components = URLComponents()
353-
components.scheme = configuration.scheme
354-
components.host = configuration.host
355-
components.port = configuration.port
356-
357-
let pathComponents = [configuration.basePath, path]
358-
.filter { !$0.isEmpty }
359-
.map { $0.trimmingCharacters(in: ["/"]) }
360-
361-
components.path = "/" + pathComponents.joined(separator: "/")
362-
363-
if let url = components.url {
364-
return url
365-
} else {
366-
// We're expecting components.url to be not nil
367-
// But if it isn't, let's just use some URL api that returns non-nil url
368-
// Let all requests fail, but so that we don't crash on explicit unwrapping
369-
return URL(fileURLWithPath: "")
370-
}
371-
}
372350
}
373351

374352
typealias APIPath = String

Sources/OpenAI/Private/URLBuilder.swift

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,13 @@ struct DefaultURLBuilder: URLBuilder {
2626
}
2727

2828
func buildURL() -> URL {
29-
var components = URLComponents()
30-
components.scheme = "https"
31-
components.host = configuration.host
32-
components.path = path
29+
var components = URLComponents.components(perConfiguration: configuration, path: path)
30+
3331
if let after {
3432
components.queryItems = [URLQueryItem(name: "after", value: after)]
3533
}
36-
return components.url!
34+
35+
return components.urlSafe
3736
}
3837
}
3938

@@ -43,12 +42,9 @@ struct AssistantsURLBuilder: URLBuilder {
4342
let assistantId: String
4443

4544
func buildURL() -> URL {
46-
var components = URLComponents()
47-
components.scheme = "https"
48-
components.host = configuration.host
49-
components.path = path.stringValue.replacingOccurrences(of: "ASST_ID", with: assistantId)
50-
51-
return components.url!
45+
var components = URLComponents.components(perConfiguration: configuration, path: path.stringValue)
46+
components.path = components.path.replacingOccurrences(of: "ASST_ID", with: assistantId)
47+
return components.urlSafe
5248
}
5349
}
5450

@@ -59,14 +55,12 @@ struct RunsURLBuilder: URLBuilder {
5955
let before: String? = nil
6056

6157
func buildURL() -> URL {
62-
var components = URLComponents()
63-
components.scheme = "https"
64-
components.host = configuration.host
65-
components.path = path.stringValue.replacingOccurrences(of: "THREAD_ID", with: threadId)
58+
var components = URLComponents.components(perConfiguration: configuration, path: path.stringValue)
59+
components.path = components.path.replacingOccurrences(of: "THREAD_ID", with: threadId)
6660
if let before {
6761
components.queryItems = [URLQueryItem(name: "before", value: before)]
6862
}
69-
return components.url!
63+
return components.urlSafe
7064
}
7165
}
7266

@@ -86,14 +80,16 @@ struct RunRetrieveURLBuilder: URLBuilder {
8680
}
8781

8882
func buildURL() -> URL {
89-
var components = URLComponents()
90-
components.scheme = "https"
91-
components.host = configuration.host
92-
components.path = path.stringValue.replacingOccurrences(of: "THREAD_ID", with: threadId)
93-
.replacingOccurrences(of: "RUN_ID", with: runId)
83+
var components = URLComponents.components(perConfiguration: configuration, path: path.stringValue)
84+
components.path = components.path
85+
.replacingOccurrences(of: "THREAD_ID", with: threadId)
86+
.replacingOccurrences(of: "RUN_ID", with: runId)
87+
9488
if let before {
9589
components.queryItems = [URLQueryItem(name: "before", value: before)]
9690
}
97-
return components.url!
91+
return components.urlSafe
9892
}
9993
}
94+
95+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// URLComponents+.swift
3+
// OpenAI
4+
//
5+
// Created by Oleksii Nezhyborets on 24.01.2025.
6+
//
7+
8+
import Foundation
9+
#if canImport(FoundationNetworking)
10+
import FoundationNetworking
11+
#endif
12+
13+
extension URLComponents {
14+
static func components(perConfiguration configuration: OpenAI.Configuration, path: String) -> URLComponents {
15+
var components = URLComponents()
16+
components.scheme = configuration.scheme
17+
components.host = configuration.host
18+
components.port = configuration.port
19+
20+
let pathComponents = [configuration.basePath, path]
21+
.filter { !$0.isEmpty }
22+
.map { $0.trimmingCharacters(in: ["/"]) }
23+
24+
components.path = "/" + pathComponents.joined(separator: "/")
25+
return components
26+
}
27+
28+
var urlSafe: URL {
29+
if let url {
30+
return url
31+
} else {
32+
// We're expecting components.url to be not nil
33+
// But if it isn't, let's just use some URL api that returns non-nil url
34+
// Let all requests fail, but so that we don't crash on explicit unwrapping
35+
return URL(fileURLWithPath: "")
36+
}
37+
}
38+
}

Sources/OpenAI/Public/Models/AssistantResult.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public struct AssistantResult: Codable, Equatable {
1313
public let description: String?
1414
public let instructions: String?
1515
public let tools: [Tool]?
16-
public let toolResources: ToolResources
16+
public let toolResources: ToolResources?
1717

1818
enum CodingKeys: String, CodingKey {
1919
case id
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// File.swift
3+
// OpenAI
4+
//
5+
// Created by Oleksii Nezhyborets on 24.01.2025.
6+
//
7+
8+
import Foundation
9+
@testable import OpenAI
10+
11+
extension AssistantResult {
12+
static func makeMock() -> AssistantResult {
13+
AssistantResult(id: "asst_9876", name: "My New Assistant", description: "Assistant Description", instructions: "You are a helpful assistant.", tools: nil, toolResources: nil)
14+
}
15+
}

Tests/OpenAITests/OpenAITests.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ class OpenAITests: XCTestCase {
432432
// 1106
433433
func testAssistantCreateQuery() async throws {
434434
let query = assistantsQuery()
435-
let expectedResult = AssistantResult(id: "asst_9876", name: "My New Assistant", description: "Assistant Description", instructions: "You are a helpful assistant.", tools: nil, fileIds: nil)
435+
let expectedResult = AssistantResult.makeMock()
436436
try self.stub(result: expectedResult)
437437

438438
let result = try await openAI.assistantCreate(query: query)
@@ -450,7 +450,7 @@ class OpenAITests: XCTestCase {
450450
}
451451

452452
func testListAssistantQuery() async throws {
453-
let expectedAssistant = AssistantResult(id: "asst_9876", name: "My New Assistant", description: "Assistant Description", instructions: "You are a helpful assistant.", tools: nil, fileIds: nil)
453+
let expectedAssistant = AssistantResult.makeMock()
454454
let expectedResult = AssistantsResult(data: [expectedAssistant], firstId: expectedAssistant.id, lastId: expectedAssistant.id, hasMore: false)
455455
try self.stub(result: expectedResult)
456456

@@ -468,7 +468,7 @@ class OpenAITests: XCTestCase {
468468

469469
func testAssistantModifyQuery() async throws {
470470
let query = assistantsQuery()
471-
let expectedResult = AssistantResult(id: "asst_9876", name: "My New Assistant", description: "Assistant Description", instructions: "You are a helpful assistant.", tools: nil, fileIds: nil)
471+
let expectedResult = AssistantResult.makeMock()
472472
try self.stub(result: expectedResult)
473473

474474
let result = try await openAI.assistantModify(query: query, assistantId: "asst_9876")
@@ -556,7 +556,7 @@ class OpenAITests: XCTestCase {
556556
}
557557

558558
func testRunRetrieveStepsQuery() async throws {
559-
let expectedResult = RunRetrieveStepsResult(data: [.init(id: "step_1234", stepDetails: .init(toolCalls: [.init(id: "tool_456", type: .retrieval, codeInterpreter: nil, function: nil)]))])
559+
let expectedResult = RunRetrieveStepsResult(data: [.init(id: "step_1234", stepDetails: .init(toolCalls: [.init(id: "tool_456", type: .fileSearch, codeInterpreter: nil, function: nil)]))])
560560
try self.stub(result: expectedResult)
561561

562562
let result = try await openAI.runRetrieveSteps(threadId: "thread_1234", runId: "run_1234")
@@ -646,22 +646,22 @@ class OpenAITests: XCTestCase {
646646
func testCustomRunsURLBuilt() {
647647
let configuration = OpenAI.Configuration(token: "foo", organizationIdentifier: "bar", host: "my.host.com", timeoutInterval: 14)
648648
let openAI = OpenAI(configuration: configuration, session: self.urlSession)
649-
let completionsURL = openAI.buildRunsURL(path: .runs, threadId: "thread_4321")
650-
XCTAssertEqual(completionsURL, URL(string: "https://my.host.com/v1/threads/thread_4321/runs"))
649+
let completionsURL = openAI.buildRunsURL(path: APIPath.Assistants.runs.stringValue, threadId: "thread_4321")
650+
XCTAssertEqual(completionsURL, URL(string: "https://my.host.com:443/v1/threads/thread_4321/runs"))
651651
}
652652

653653
func testCustomRunsRetrieveURLBuilt() {
654654
let configuration = OpenAI.Configuration(token: "foo", organizationIdentifier: "bar", host: "my.host.com", timeoutInterval: 14)
655655
let openAI = OpenAI(configuration: configuration, session: self.urlSession)
656-
let completionsURL = openAI.buildRunRetrieveURL(path: .runRetrieve, threadId: "thread_4321", runId: "run_1234")
657-
XCTAssertEqual(completionsURL, URL(string: "https://my.host.com/v1/threads/thread_4321/runs/run_1234"))
656+
let completionsURL = openAI.buildRunRetrieveURL(path: APIPath.Assistants.runRetrieve.stringValue, threadId: "thread_4321", runId: "run_1234")
657+
XCTAssertEqual(completionsURL, URL(string: "https://my.host.com:443/v1/threads/thread_4321/runs/run_1234"))
658658
}
659659

660660
func testCustomRunRetrieveStepsURLBuilt() {
661661
let configuration = OpenAI.Configuration(token: "foo", organizationIdentifier: "bar", host: "my.host.com", timeoutInterval: 14)
662662
let openAI = OpenAI(configuration: configuration, session: self.urlSession)
663-
let completionsURL = openAI.buildRunRetrieveURL(path: .runRetrieveSteps, threadId: "thread_4321", runId: "run_1234")
664-
XCTAssertEqual(completionsURL, URL(string: "https://my.host.com/v1/threads/thread_4321/runs/run_1234/steps"))
663+
let completionsURL = openAI.buildRunRetrieveURL(path: APIPath.Assistants.runRetrieveSteps.stringValue, threadId: "thread_4321", runId: "run_1234")
664+
XCTAssertEqual(completionsURL, URL(string: "https://my.host.com:443/v1/threads/thread_4321/runs/run_1234/steps"))
665665
}
666666
// 1106 end
667667

Tests/OpenAITests/OpenAITestsCombine.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ final class OpenAITestsCombine: XCTestCase {
105105

106106
// 1106
107107
func testAssistantsQuery() throws {
108-
let expectedAssistant = AssistantResult(id: "asst_9876", name: "My New Assistant", description: "Assistant Description", instructions: "You are a helpful assistant.", tools: nil, fileIds: nil)
108+
let expectedAssistant = AssistantResult.makeMock()
109109
let expectedResult = AssistantsResult(data: [expectedAssistant], firstId: expectedAssistant.id, lastId: expectedAssistant.id, hasMore: false)
110110
try self.stub(result: expectedResult)
111111

@@ -115,7 +115,7 @@ final class OpenAITestsCombine: XCTestCase {
115115

116116
func testAssistantCreateQuery() throws {
117117
let query = AssistantsQuery.makeMock()
118-
let expectedResult = AssistantResult(id: "asst_9876", name: "My New Assistant", description: "Assistant Description", instructions: "You are a helpful assistant.", tools: nil, fileIds: nil)
118+
let expectedResult = AssistantResult.makeMock()
119119
try self.stub(result: expectedResult)
120120

121121
let result = try awaitPublisher(openAI.assistantCreate(query: query))
@@ -124,7 +124,7 @@ final class OpenAITestsCombine: XCTestCase {
124124

125125
func testAssistantModifyQuery() throws {
126126
let query = AssistantsQuery.makeMock()
127-
let expectedResult = AssistantResult(id: "asst_9876", name: "My New Assistant", description: "Assistant Description", instructions: "You are a helpful assistant.", tools: nil, fileIds: nil)
127+
let expectedResult = AssistantResult.makeMock()
128128
try self.stub(result: expectedResult)
129129

130130
let result = try awaitPublisher(openAI.assistantModify(query: query, assistantId: "asst_9876"))
@@ -170,7 +170,7 @@ final class OpenAITestsCombine: XCTestCase {
170170
}
171171

172172
func testRunRetrieveStepsQuery() throws {
173-
let expectedResult = RunRetrieveStepsResult(data: [.init(id: "step_1234", stepDetails: .init(toolCalls: [.init(id: "tool_456", type: .retrieval, codeInterpreter: nil, function: nil)]))])
173+
let expectedResult = RunRetrieveStepsResult(data: [.init(id: "step_1234", stepDetails: .init(toolCalls: [.init(id: "tool_456", type: .fileSearch, codeInterpreter: nil, function: nil)]))])
174174
try self.stub(result: expectedResult)
175175

176176
let result = try awaitPublisher(openAI.runRetrieveSteps(threadId: "thread_1234", runId: "run_1234"))

Tests/OpenAITests/OpenAITestsDecoder.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ class OpenAITestsDecoder: XCTestCase {
444444
}
445445
"""
446446

447-
let expectedValue = AssistantResult(id: "asst_abc123", name: "Math Tutor", description: nil, instructions: "You are a personal math tutor. When asked a question, write and run Python code to answer the question.", tools: [.codeInterpreter], fileIds: [])
447+
let expectedValue = AssistantResult(id: "asst_abc123", name: "Math Tutor", description: nil, instructions: "You are a personal math tutor. When asked a question, write and run Python code to answer the question.", tools: [.codeInterpreter], toolResources: nil)
448448
try decode(data, expectedValue)
449449
}
450450

@@ -455,7 +455,7 @@ class OpenAITestsDecoder: XCTestCase {
455455
description: nil,
456456
instructions: "You are a personal math tutor. When asked a question, write and run Python code to answer the question.",
457457
tools: [.codeInterpreter],
458-
fileIds: nil
458+
toolResources: nil
459459
)
460460

461461
let expectedValue = """
@@ -510,8 +510,8 @@ class OpenAITestsDecoder: XCTestCase {
510510

511511
let expectedValue = AssistantsResult(
512512
data: [
513-
.init(id: "asst_abc123", name: "Coding Tutor", description: nil, instructions: "You are a helpful assistant designed to make me better at coding!", tools: [], fileIds: []),
514-
.init(id: "asst_abc456", name: "My Assistant", description: nil, instructions: "You are a helpful assistant designed to teach me about AI!", tools: [], fileIds: []),
513+
.init(id: "asst_abc123", name: "Coding Tutor", description: nil, instructions: "You are a helpful assistant designed to make me better at coding!", tools: [], toolResources: nil),
514+
.init(id: "asst_abc456", name: "My Assistant", description: nil, instructions: "You are a helpful assistant designed to teach me about AI!", tools: [], toolResources: nil),
515515
],
516516
firstId: "asst_abc123",
517517
lastId: "asst_abc789",

0 commit comments

Comments
 (0)