Add support for audio content in prompts and tool results (#73)
This commit is contained in:
parent
82f4fd29b3
commit
c748bc1549
4 changed files with 57 additions and 4 deletions
|
|
@ -64,6 +64,8 @@ public struct Prompt: Hashable, Codable, Sendable {
|
|||
case text(text: String)
|
||||
/// Image content
|
||||
case image(data: String, mimeType: String)
|
||||
/// Audio content
|
||||
case audio(data: String, mimeType: String)
|
||||
/// Embedded resource content
|
||||
case resource(uri: String, mimeType: String, text: String?, blob: String?)
|
||||
|
||||
|
|
@ -82,6 +84,10 @@ public struct Prompt: Hashable, Codable, Sendable {
|
|||
try container.encode("image", forKey: .type)
|
||||
try container.encode(data, forKey: .data)
|
||||
try container.encode(mimeType, forKey: .mimeType)
|
||||
case .audio(let data, let mimeType):
|
||||
try container.encode("audio", forKey: .type)
|
||||
try container.encode(data, forKey: .data)
|
||||
try container.encode(mimeType, forKey: .mimeType)
|
||||
case .resource(let uri, let mimeType, let text, let blob):
|
||||
try container.encode("resource", forKey: .type)
|
||||
try container.encode(uri, forKey: .uri)
|
||||
|
|
@ -103,6 +109,10 @@ public struct Prompt: Hashable, Codable, Sendable {
|
|||
let data = try container.decode(String.self, forKey: .data)
|
||||
let mimeType = try container.decode(String.self, forKey: .mimeType)
|
||||
self = .image(data: data, mimeType: mimeType)
|
||||
case "audio":
|
||||
let data = try container.decode(String.self, forKey: .data)
|
||||
let mimeType = try container.decode(String.self, forKey: .mimeType)
|
||||
self = .audio(data: data, mimeType: mimeType)
|
||||
case "resource":
|
||||
let uri = try container.decode(String.self, forKey: .uri)
|
||||
let mimeType = try container.decode(String.self, forKey: .mimeType)
|
||||
|
|
@ -155,7 +165,7 @@ public enum ListPrompts: Method {
|
|||
|
||||
public struct Parameters: NotRequired, Hashable, Codable, Sendable {
|
||||
public let cursor: String?
|
||||
|
||||
|
||||
public init() {
|
||||
self.cursor = nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ public struct Tool: Hashable, Codable, Sendable {
|
|||
case text(String)
|
||||
/// Image content
|
||||
case image(data: String, mimeType: String, metadata: [String: String]?)
|
||||
/// Audio content
|
||||
case audio(data: String, mimeType: String)
|
||||
/// Embedded resource content
|
||||
case resource(uri: String, mimeType: String, text: String?)
|
||||
|
||||
|
|
@ -36,6 +38,7 @@ public struct Tool: Hashable, Codable, Sendable {
|
|||
case text
|
||||
case image
|
||||
case resource
|
||||
case audio
|
||||
case uri
|
||||
case mimeType
|
||||
case data
|
||||
|
|
@ -56,6 +59,10 @@ public struct Tool: Hashable, Codable, Sendable {
|
|||
let metadata = try container.decodeIfPresent(
|
||||
[String: String].self, forKey: .metadata)
|
||||
self = .image(data: data, mimeType: mimeType, metadata: metadata)
|
||||
case "audio":
|
||||
let data = try container.decode(String.self, forKey: .data)
|
||||
let mimeType = try container.decode(String.self, forKey: .mimeType)
|
||||
self = .audio(data: data, mimeType: mimeType)
|
||||
case "resource":
|
||||
let uri = try container.decode(String.self, forKey: .uri)
|
||||
let mimeType = try container.decode(String.self, forKey: .mimeType)
|
||||
|
|
@ -79,6 +86,10 @@ public struct Tool: Hashable, Codable, Sendable {
|
|||
try container.encode(data, forKey: .data)
|
||||
try container.encode(mimeType, forKey: .mimeType)
|
||||
try container.encodeIfPresent(metadata, forKey: .metadata)
|
||||
case .audio(let data, let mimeType):
|
||||
try container.encode("audio", forKey: .type)
|
||||
try container.encode(data, forKey: .data)
|
||||
try container.encode(mimeType, forKey: .mimeType)
|
||||
case .resource(let uri, let mimeType, let text):
|
||||
try container.encode("resource", forKey: .type)
|
||||
try container.encode(uri, forKey: .uri)
|
||||
|
|
@ -120,7 +131,7 @@ public enum ListTools: Method {
|
|||
|
||||
public struct Parameters: NotRequired, Hashable, Codable, Sendable {
|
||||
public let cursor: String?
|
||||
|
||||
|
||||
public init() {
|
||||
self.cursor = nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,18 @@ struct PromptTests {
|
|||
#expect(Bool(false), "Expected text content")
|
||||
}
|
||||
|
||||
// Test audio content
|
||||
let audioContent = Prompt.Message.Content.audio(
|
||||
data: "base64audiodata", mimeType: "audio/wav")
|
||||
let audioData = try encoder.encode(audioContent)
|
||||
let decodedAudio = try decoder.decode(Prompt.Message.Content.self, from: audioData)
|
||||
if case .audio(let data, let mimeType) = decodedAudio {
|
||||
#expect(data == "base64audiodata")
|
||||
#expect(mimeType == "audio/wav")
|
||||
} else {
|
||||
#expect(Bool(false), "Expected audio content")
|
||||
}
|
||||
|
||||
// Test image content
|
||||
let imageContent = Prompt.Message.Content.image(data: "base64data", mimeType: "image/png")
|
||||
let imageData = try encoder.encode(imageContent)
|
||||
|
|
@ -142,7 +154,7 @@ struct PromptTests {
|
|||
let emptyParams = ListPrompts.Parameters()
|
||||
#expect(emptyParams.cursor == nil)
|
||||
}
|
||||
|
||||
|
||||
@Test("ListPrompts request decoding with omitted params")
|
||||
func testListPromptsRequestDecodingWithOmittedParams() throws {
|
||||
// Test decoding when params field is omitted
|
||||
|
|
@ -157,7 +169,7 @@ struct PromptTests {
|
|||
#expect(decoded.id == "test-id")
|
||||
#expect(decoded.method == ListPrompts.name)
|
||||
}
|
||||
|
||||
|
||||
@Test("ListPrompts request decoding with null params")
|
||||
func testListPromptsRequestDecodingWithNullParams() throws {
|
||||
// Test decoding when params field is null
|
||||
|
|
|
|||
|
|
@ -103,6 +103,26 @@ struct ToolTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Test("Audio content encoding and decoding")
|
||||
func testToolContentAudioEncoding() throws {
|
||||
let content = Tool.Content.audio(
|
||||
data: "base64audiodata",
|
||||
mimeType: "audio/wav"
|
||||
)
|
||||
let encoder = JSONEncoder()
|
||||
let decoder = JSONDecoder()
|
||||
|
||||
let data = try encoder.encode(content)
|
||||
let decoded = try decoder.decode(Tool.Content.self, from: data)
|
||||
|
||||
if case .audio(let data, let mimeType) = decoded {
|
||||
#expect(data == "base64audiodata")
|
||||
#expect(mimeType == "audio/wav")
|
||||
} else {
|
||||
#expect(Bool(false), "Expected audio content")
|
||||
}
|
||||
}
|
||||
|
||||
@Test("ListTools parameters validation")
|
||||
func testListToolsParameters() throws {
|
||||
let params = ListTools.Parameters(cursor: "next_page")
|
||||
|
|
|
|||
Loading…
Reference in a new issue