Skip to content

Commit aaf570e

Browse files
committed
add cache for message content
1 parent f68beec commit aaf570e

File tree

7 files changed

+44
-22
lines changed

7 files changed

+44
-22
lines changed

Sources/AnthropicSwiftSDK/Entity/Content/Content.swift

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ public enum ContentType: String {
2828
/// Starting with Claude 3 models, you can also send `image` content blocks.
2929
public enum Content {
3030
/// a single string
31-
case text(String)
31+
case text(String, cacheControl: CacheControl? = nil)
3232
/// currently supported the `base64` source type for images, and the `image/jpeg`, `image/png`, `image/gif`, and `image/webp` media types.
33-
case image(ImageContent)
33+
case image(ImageContent, cacheControl: CacheControl? = nil)
3434
case toolUse(ToolUseContent)
3535
case toolResult(ToolResultContent)
36-
case document(DocumentContent)
36+
case document(DocumentContent, cacheControl: CacheControl? = nil)
3737

3838
/// The type of content block.
3939
public var contentType: ContentType {
@@ -54,9 +54,19 @@ public enum Content {
5454

5555
extension Content: Encodable {
5656
enum CodingKeys: String, CodingKey {
57+
case type
58+
}
59+
60+
enum TextCodingKeys: String, CodingKey {
61+
case type
5762
case text
63+
case cacheControl = "cache_control"
64+
}
65+
66+
enum BinaryCodingKeys: String, CodingKey {
5867
case type
5968
case source
69+
case cacheControl = "cache_control"
6070
}
6171

6272
enum ToolUseCodingKeys: String, CodingKey {
@@ -75,14 +85,20 @@ extension Content: Encodable {
7585

7686
public func encode(to encoder: Encoder) throws {
7787
switch self {
78-
case let .text(text):
79-
var container = encoder.container(keyedBy: CodingKeys.self)
88+
case let .text(text, cacheControl):
89+
var container = encoder.container(keyedBy: TextCodingKeys.self)
8090
try container.encode(self.contentType.rawValue, forKey: .type)
8191
try container.encode(text, forKey: .text)
82-
case let .image(image):
83-
var container = encoder.container(keyedBy: CodingKeys.self)
92+
if let cacheControl {
93+
try container.encode(cacheControl, forKey: .cacheControl)
94+
}
95+
case let .image(image, cacheControl):
96+
var container = encoder.container(keyedBy: BinaryCodingKeys.self)
8497
try container.encode(self.contentType.rawValue, forKey: .type)
8598
try container.encode(image, forKey: .source)
99+
if let cacheControl {
100+
try container.encode(cacheControl, forKey: .cacheControl)
101+
}
86102
case let .toolUse(toolUse):
87103
var container = encoder.container(keyedBy: ToolUseCodingKeys.self)
88104
try container.encode(self.contentType.rawValue, forKey: .type)
@@ -97,10 +113,13 @@ extension Content: Encodable {
97113
if toolResult.isError != nil {
98114
try container.encode(toolResult.isError, forKey: .isError)
99115
}
100-
case let .document(document):
101-
var container = encoder.container(keyedBy: CodingKeys.self)
116+
case let .document(document, cacheControl):
117+
var container = encoder.container(keyedBy: BinaryCodingKeys.self)
102118
try container.encode(self.contentType.rawValue, forKey: .type)
103119
try container.encode(document, forKey: .source)
120+
if let cacheControl {
121+
try container.encode(cacheControl, forKey: .cacheControl)
122+
}
104123
}
105124
}
106125
}
@@ -113,18 +132,21 @@ extension Content: Decodable {
113132

114133
switch type {
115134
case .text:
116-
let text = try container.decode(String.self, forKey: .text)
135+
let textContainer = try decoder.container(keyedBy: TextCodingKeys.self)
136+
let text = try textContainer.decode(String.self, forKey: .text)
117137
self = .text(text)
118138
case .image:
119-
let image = try container.decode(ImageContent.self, forKey: .source)
139+
let imageContainer = try decoder.container(keyedBy: BinaryCodingKeys.self)
140+
let image = try imageContainer.decode(ImageContent.self, forKey: .source)
120141
self = .image(image)
121142
case .toolUse:
122143
let content = try ToolUseContent(from: decoder)
123144
self = .toolUse(content)
124145
case .toolResult:
125146
fatalError("ContentType: `tool_result` is only used by user, not by assistant")
126147
case .document:
127-
let document = try container.decode(DocumentContent.self, forKey: .source)
148+
let documentContainer = try decoder.container(keyedBy: BinaryCodingKeys.self)
149+
let document = try documentContainer.decode(DocumentContent.self, forKey: .source)
128150
self = .document(document)
129151
case .none:
130152
throw ClientError.failedToParseContentType(contentTypeString)

Tests/AnthropicSwiftSDKTests/Entity/ContentTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ final class ContentTests: XCTestCase {
194194
from: TestCase.text.jsonString.data(using: .utf8)!
195195
)
196196

197-
guard case let .text(text) = expect else {
197+
guard case let .text(text, _) = expect else {
198198
XCTFail("Failed to decode text")
199199
return
200200
}
@@ -208,7 +208,7 @@ final class ContentTests: XCTestCase {
208208
from: TestCase.image.jsonString.data(using: .utf8)!
209209
)
210210

211-
guard case let .image(imageContent) = expect else {
211+
guard case let .image(imageContent, _) = expect else {
212212
XCTFail("Failed to decode image")
213213
return
214214
}

Tests/AnthropicSwiftSDKTests/MessagesTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ final class MessagesTests: XCTestCase {
8383
XCTAssertEqual(response.type, .message)
8484
XCTAssertEqual(response.role, .assistant)
8585
XCTAssertEqual(response.content.first?.contentType, .text)
86-
if case let .text(text) = response.content.first {
86+
if case let .text(text, _) = response.content.first {
8787
XCTAssertEqual(text, "Hello!")
8888
} else {
8989
XCTFail("Wrong type content is received.")

Tests/AnthropicSwiftSDKTests/Network/BatchResultResponseTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ final class BatchResultResponseTests: XCTestCase {
2525
XCTAssertEqual(batchResultResponse.result?.message?.id, "msg_123456")
2626
XCTAssertEqual(batchResultResponse.result?.message?.type, .message)
2727
XCTAssertEqual(batchResultResponse.result?.message?.role, .assistant)
28-
guard case let .text(text1) = batchResultResponse.result?.message?.content.first else {
28+
guard case let .text(text1, _) = batchResultResponse.result?.message?.content.first else {
2929
XCTFail("batchResultResponse.result?.message.content.first is not .text")
3030
return
3131
}

Tests/AnthropicSwiftSDKTests/Network/Request/MessageBatchesRequestTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ final class MessageBatchesRequestTests: XCTestCase {
4040
XCTAssertEqual(request.body?.requests[0].params.messages.count, 1)
4141
XCTAssertEqual(request.body?.requests[0].params.messages[0].role.rawValue, "user")
4242
let content1 = try XCTUnwrap(request.body?.requests[0].params.messages[0].content)
43-
guard case let .text(text1) = content1[0] else {
43+
guard case let .text(text1, _) = content1[0] else {
4444
XCTFail("content1[0] is not .text")
4545
return
4646
}
@@ -52,10 +52,10 @@ final class MessageBatchesRequestTests: XCTestCase {
5252
XCTAssertEqual(request.body?.requests[1].params.messages.count, 1)
5353
XCTAssertEqual(request.body?.requests[1].params.messages[0].role.rawValue, "user")
5454
let content2 = try XCTUnwrap(request.body?.requests[1].params.messages[0].content)
55-
guard case let .text(text2) = content2[0] else {
55+
guard case let .text(text2, _) = content2[0] else {
5656
XCTFail("content2[0] is not .text")
5757
return
5858
}
5959
XCTAssertEqual(text2, "お元気ですか?")
6060
}
61-
}
61+
}

Tests/AnthropicSwiftSDKTests/Network/Request/MessagesRequestTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ final class MessagesRequestTests: XCTestCase {
3838
XCTAssertEqual(request.body?.messages.count, 1)
3939
XCTAssertEqual(request.body?.messages[0].role.rawValue, "user")
4040
let content1 = try XCTUnwrap(request.body?.messages[0].content)
41-
guard case let .text(text1) = content1[0] else {
41+
guard case let .text(text1, _) = content1[0] else {
4242
XCTFail("content1[0] is not .text")
4343
return
4444
}
@@ -85,7 +85,7 @@ final class MessagesRequestTests: XCTestCase {
8585
XCTAssertEqual(request.body?.messages.count, 1)
8686
XCTAssertEqual(request.body?.messages[0].role.rawValue, "user")
8787
let content1 = try XCTUnwrap(request.body?.messages[0].content)
88-
guard case let .text(text1) = content1[0] else {
88+
guard case let .text(text1, _) = content1[0] else {
8989
XCTFail("content1[0] is not .text")
9090
return
9191
}

Tests/AnthropicSwiftSDKTests/Network/StreamingParser/StreamingDataLineParserTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ final class StreamingDataLineParserTests: XCTestCase {
5858

5959
XCTAssertEqual(result.type, .contentBlockStart)
6060
XCTAssertEqual(result.index, 0)
61-
if case .text(let text) = result.contentBlock {
61+
if case .text(let text, _) = result.contentBlock {
6262
XCTAssertEqual(text, "")
6363
} else {
6464
XCTFail()

0 commit comments

Comments
 (0)