diff --git a/Sources/AnyLanguageModel/Models/OpenAILanguageModel.swift b/Sources/AnyLanguageModel/Models/OpenAILanguageModel.swift index bd3d8c1..6299ce0 100644 --- a/Sources/AnyLanguageModel/Models/OpenAILanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/OpenAILanguageModel.swift @@ -514,9 +514,12 @@ public struct OpenAILanguageModel: LanguageModel { for invocation in invocations { let output = invocation.output entries.append(.toolOutput(output)) - let toolSegments: [Transcript.Segment] = output.segments - let blocks = convertSegmentsToOpenAIBlocks(toolSegments) - messages.append(OpenAIMessage(role: .tool(id: invocation.call.id), content: .blocks(blocks))) + messages.append( + OpenAIMessage( + role: .tool(id: invocation.call.id), + content: .text(convertSegmentsToToolContentString(output.segments)) + ) + ) } continue } @@ -579,9 +582,12 @@ public struct OpenAILanguageModel: LanguageModel { for invocation in invocations { let output = invocation.output entries.append(.toolOutput(output)) - let toolSegments: [Transcript.Segment] = output.segments - let blocks = convertSegmentsToOpenAIBlocks(toolSegments) - messages.append(OpenAIMessage(role: .tool(id: invocation.call.id), content: .blocks(blocks))) + messages.append( + OpenAIMessage( + role: .tool(id: invocation.call.id), + content: .text(convertSegmentsToToolContentString(output.segments)) + ) + ) } continue } @@ -1168,7 +1174,7 @@ extension Transcript { messages.append( .init( role: .tool(id: toolOutput.id), - content: .blocks(convertSegmentsToOpenAIBlocks(toolOutput.segments)) + content: .text(convertSegmentsToToolContentString(toolOutput.segments)) ) ) } @@ -1308,6 +1314,26 @@ private func convertSegmentsToOpenAIBlocks(_ segments: [Transcript.Segment]) -> return blocks } +/// Converts a list of transcript segments to a string representation suitable for tool message content. +private func convertSegmentsToToolContentString(_ segments: [Transcript.Segment]) -> String { + // Tool message content must be string (or text-only parts) per API spec. + // String is used for broad provider compatibility. + // Image segments are intentionally omitted because tool outputs only support text. + segments.compactMap { segment in + switch segment { + case .text(let textSegment): + return textSegment.content + case .structure(let structuredSegment): + switch structuredSegment.content.kind { + case .string(let text): return text + default: return structuredSegment.content.jsonString + } + case .image: + return nil + } + }.joined(separator: "\n") +} + private struct OpenAITool: Hashable, Codable, Sendable { let type: String let function: OpenAIFunction