@@ -106,6 +106,7 @@ async def create_attachment(
106106 ) -> Attachment :
107107 # Simple in-memory attachment creation
108108 id = f"atc_{ len (self .files ) + 1 } "
109+ metadata = {"source" : "test" }
109110 if input .mime_type .startswith ("image/" ):
110111 attachment = ImageAttachment (
111112 id = id ,
@@ -117,6 +118,7 @@ async def create_attachment(
117118 method = "PUT" ,
118119 headers = {"X-My-Header" : "my-value" },
119120 ),
121+ metadata = metadata ,
120122 )
121123 else :
122124 attachment = FileAttachment (
@@ -128,6 +130,7 @@ async def create_attachment(
128130 method = "PUT" ,
129131 headers = {"X-My-Header" : "my-value" },
130132 ),
133+ metadata = metadata ,
131134 )
132135 self .files [attachment .id ] = attachment
133136 return attachment
@@ -1100,6 +1103,10 @@ async def test_create_file():
11001103 assert attachment .upload_descriptor .headers == {"X-My-Header" : "my-value" }
11011104 assert attachment .id in store .files
11021105
1106+ # The `metadata` field is excluded from serialization by default but still stored server-side
1107+ assert attachment .metadata is None
1108+ assert store .files [attachment .id ].metadata == {"source" : "test" }
1109+
11031110
11041111async def test_create_image_file ():
11051112 store = InMemoryFileStore ()
@@ -1135,6 +1142,43 @@ async def test_create_image_file():
11351142 assert attachment .id in store .files
11361143
11371144
1145+ async def test_user_message_attachment_metadata_not_serialized ():
1146+ attachment = FileAttachment (
1147+ id = "file_with_metadata" ,
1148+ type = "file" ,
1149+ mime_type = "text/plain" ,
1150+ name = "test.txt" ,
1151+ metadata = {"source" : "test" },
1152+ )
1153+
1154+ with make_server () as server :
1155+ await server .store .save_attachment (attachment , DEFAULT_CONTEXT )
1156+ events = await server .process_streaming (
1157+ ThreadsCreateReq (
1158+ params = ThreadCreateParams (
1159+ input = UserMessageInput (
1160+ content = [UserMessageTextContent (text = "Message with file" )],
1161+ attachments = [attachment .id ],
1162+ inference_options = InferenceOptions (),
1163+ )
1164+ )
1165+ )
1166+ )
1167+ thread = next (
1168+ event .thread for event in events if event .type == "thread.created"
1169+ )
1170+
1171+ list_result = await server .process_non_streaming (
1172+ ItemsListReq (params = ItemsListParams (thread_id = thread .id ))
1173+ )
1174+ items = TypeAdapter (Page [ThreadItem ]).validate_json (list_result .json )
1175+ user_items = [item for item in items .data if item .type == "user_message" ]
1176+ assert user_items
1177+ attachments = user_items [0 ].attachments
1178+ assert attachments
1179+ assert all (att .metadata is None for att in attachments )
1180+
1181+
11381182async def test_create_file_without_filestore ():
11391183 with pytest .raises (RuntimeError ):
11401184 with make_server () as server :
0 commit comments