@@ -65,7 +65,8 @@ export function mapAnthropicContentBlock(block: any): object {
6565
6666 // -------------------------------------------------------------------------
6767 // Document — sources: base64 | text | url | file
68- // Note: document blocks have no OTel modality (modality is image/video/audio only)
68+ // OTel modality accepts any string (anyOf: [Modality enum, string]), so
69+ // "document" is a valid value for BlobPart/UriPart/FilePart modality.
6970 // -------------------------------------------------------------------------
7071 case "document" : {
7172 const src = block . source ;
@@ -75,6 +76,7 @@ export function mapAnthropicContentBlock(block: any): object {
7576 // (can be "application/pdf" or "text/plain")
7677 return {
7778 type : "blob" ,
79+ modality : "document" ,
7880 mime_type : src . media_type ,
7981 content : src . data ,
8082 } ;
@@ -83,10 +85,15 @@ export function mapAnthropicContentBlock(block: any): object {
8385 return { type : "text" , content : src . data } ;
8486 case "url" :
8587 // URL-referenced PDF
86- return { type : "uri" , mime_type : "application/pdf" , uri : src . url } ;
88+ return {
89+ type : "uri" ,
90+ modality : "document" ,
91+ mime_type : "application/pdf" ,
92+ uri : src . url ,
93+ } ;
8794 case "file" :
8895 // Files API reference — file_id is on source.file_id
89- return { type : "file" , file_id : src . file_id } ;
96+ return { type : "file" , modality : "document" , file_id : src . file_id } ;
9097 default :
9198 return { type : block . type , ...block } ;
9299 }
@@ -158,8 +165,8 @@ export function mapAnthropicContentBlock(block: any): object {
158165// image_url (regular URL) → UriPart { modality: "image" }
159166// image_url (data: URI) → BlobPart { modality: "image", mime_type parsed from URI }
160167// input_audio → BlobPart { modality: "audio", mime_type: "audio/{format}" }
161- // file (file_id) → FilePart { file_id }
162- // file (file_data) → BlobPart { no modality — documents }
168+ // file (file_id) → FilePart { modality: "document", file_id }
169+ // file (file_data) → BlobPart { modality: "document", mime_type }
163170// refusal → GenericPart { type: "refusal", content }
164171// <unknown> → GenericPart
165172
@@ -212,14 +219,14 @@ export function mapOpenAIContentBlock(block: any): object {
212219
213220 // -------------------------------------------------------------------------
214221 // File — can be file_id reference or inline file_data
215- // OTel FilePart and BlobPart require `modality` (image/video/audio),
216- // but OpenAI files don't specify modality. Use GenericPart to preserve
217- // all info without violating the schema.
222+ // OpenAI file content parts are used for documents (PDFs etc.), not images
223+ // (images use image_url). modality accepts any string, so "document" is valid.
218224 // -------------------------------------------------------------------------
219225 case "file" : {
220226 if ( block . file ?. file_id ) {
221227 return {
222228 type : "file" ,
229+ modality : "document" ,
223230 file_id : block . file . file_id ,
224231 ...( block . file . filename && { filename : block . file . filename } ) ,
225232 } ;
@@ -228,6 +235,7 @@ export function mapOpenAIContentBlock(block: any): object {
228235 // Inline file data → BlobPart. OTel FilePart is a reference type (file_id only).
229236 return {
230237 type : "blob" ,
238+ modality : "document" ,
231239 mime_type : block . file . mime_type || "application/octet-stream" ,
232240 content : block . file . file_data ,
233241 } ;
0 commit comments