@@ -83,9 +83,11 @@ public static com.google.genai.types.Part toGenaiPart(io.a2a.spec.Part<?> a2aPar
8383 if (a2aPart instanceof TextPart textPart ) {
8484 com .google .genai .types .Part .Builder partBuilder =
8585 com .google .genai .types .Part .builder ().text (textPart .getText ());
86- if (textPart .getMetadata () != null
87- && Objects .equals (textPart .getMetadata ().get ("thought" ), Boolean .TRUE )) {
88- partBuilder .thought (true );
86+ if (textPart .getMetadata () != null ) {
87+ partBuilder .partMetadata (textPart .getMetadata ());
88+ if (Objects .equals (textPart .getMetadata ().get ("thought" ), true )) {
89+ partBuilder .thought (true );
90+ }
8991 }
9092 return partBuilder .build ();
9193 }
@@ -108,14 +110,19 @@ public static ImmutableList<com.google.genai.types.Part> toGenaiParts(
108110
109111 private static com .google .genai .types .Part convertFilePartToGenAiPart (FilePart filePart ) {
110112 FileContent fileContent = filePart .getFile ();
113+ Map <String , Object > metadata = filePart .getMetadata ();
111114 if (fileContent instanceof FileWithUri fileWithUri ) {
112- return com .google .genai .types .Part .builder ()
113- .fileData (
114- FileData .builder ()
115- .fileUri (fileWithUri .uri ())
116- .mimeType (fileWithUri .mimeType ())
117- .build ())
118- .build ();
115+ com .google .genai .types .Part .Builder builder =
116+ com .google .genai .types .Part .builder ()
117+ .fileData (
118+ FileData .builder ()
119+ .fileUri (fileWithUri .uri ())
120+ .mimeType (fileWithUri .mimeType ())
121+ .build ());
122+ if (metadata != null ) {
123+ builder .partMetadata (metadata );
124+ }
125+ return builder .build ();
119126 }
120127
121128 if (fileContent instanceof FileWithBytes fileWithBytes ) {
@@ -124,9 +131,13 @@ private static com.google.genai.types.Part convertFilePartToGenAiPart(FilePart f
124131 throw new GenAiFieldMissingException ("FileWithBytes missing byte content" );
125132 }
126133 byte [] decoded = Base64 .getDecoder ().decode (bytesString );
127- return com .google .genai .types .Part .builder ()
128- .inlineData (Blob .builder ().data (decoded ).mimeType (fileWithBytes .mimeType ()).build ())
129- .build ();
134+ com .google .genai .types .Part .Builder builder =
135+ com .google .genai .types .Part .builder ()
136+ .inlineData (Blob .builder ().data (decoded ).mimeType (fileWithBytes .mimeType ()).build ());
137+ if (metadata != null ) {
138+ builder .partMetadata (metadata );
139+ }
140+ return builder .build ();
130141 }
131142
132143 throw new IllegalArgumentException ("Unsupported FilePart content: " + fileContent .getClass ());
@@ -145,24 +156,33 @@ private static com.google.genai.types.Part convertDataPartToGenAiPart(DataPart d
145156 String functionName = String .valueOf (data .getOrDefault (NAME_KEY , "" ));
146157 String functionId = String .valueOf (data .getOrDefault (ID_KEY , "" ));
147158 Map <String , Object > args = coerceToMap (data .get (ARGS_KEY ));
148- return com .google .genai .types .Part .builder ()
149- .functionCall (FunctionCall .builder ().name (functionName ).id (functionId ).args (args ).build ())
150- .build ();
159+ com .google .genai .types .Part .Builder builder =
160+ com .google .genai .types .Part .builder ()
161+ .functionCall (
162+ FunctionCall .builder ().name (functionName ).id (functionId ).args (args ).build ());
163+ if (!metadata .isEmpty ()) {
164+ builder .partMetadata (metadata );
165+ }
166+ return builder .build ();
151167 }
152168
153169 if ((data .containsKey (NAME_KEY ) && data .containsKey (RESPONSE_KEY ))
154170 || metadataType .equals (A2ADataPartMetadataType .FUNCTION_RESPONSE .getType ())) {
155171 String functionName = String .valueOf (data .getOrDefault (NAME_KEY , "" ));
156172 String functionId = String .valueOf (data .getOrDefault (ID_KEY , "" ));
157173 Map <String , Object > response = coerceToMap (data .get (RESPONSE_KEY ));
158- return com .google .genai .types .Part .builder ()
159- .functionResponse (
160- FunctionResponse .builder ()
161- .name (functionName )
162- .id (functionId )
163- .response (response )
164- .build ())
165- .build ();
174+ com .google .genai .types .Part .Builder builder =
175+ com .google .genai .types .Part .builder ()
176+ .functionResponse (
177+ FunctionResponse .builder ()
178+ .name (functionName )
179+ .id (functionId )
180+ .response (response )
181+ .build ());
182+ if (!metadata .isEmpty ()) {
183+ builder .partMetadata (metadata );
184+ }
185+ return builder .build ();
166186 }
167187
168188 if ((data .containsKey (CODE_KEY ) && data .containsKey (LANGUAGE_KEY ))
@@ -171,26 +191,42 @@ private static com.google.genai.types.Part convertDataPartToGenAiPart(DataPart d
171191 String language =
172192 String .valueOf (
173193 data .getOrDefault (LANGUAGE_KEY , Language .Known .LANGUAGE_UNSPECIFIED .toString ()));
174- return com .google .genai .types .Part .builder ()
175- .executableCode (
176- ExecutableCode .builder ().code (code ).language (new Language (language )).build ())
177- .build ();
194+ com .google .genai .types .Part .Builder builder =
195+ com .google .genai .types .Part .builder ()
196+ .executableCode (
197+ ExecutableCode .builder ().code (code ).language (new Language (language )).build ());
198+ if (!metadata .isEmpty ()) {
199+ builder .partMetadata (metadata );
200+ }
201+ return builder .build ();
178202 }
179203
180204 if ((data .containsKey (OUTCOME_KEY ) && data .containsKey (OUTPUT_KEY ))
181205 || metadataType .equals (A2ADataPartMetadataType .CODE_EXECUTION_RESULT .getType ())) {
182206 String outcome =
183207 String .valueOf (data .getOrDefault (OUTCOME_KEY , Outcome .Known .OUTCOME_OK ).toString ());
184208 String output = String .valueOf (data .getOrDefault (OUTPUT_KEY , "" ));
185- return com .google .genai .types .Part .builder ()
186- .codeExecutionResult (
187- CodeExecutionResult .builder ().outcome (new Outcome (outcome )).output (output ).build ())
188- .build ();
209+ com .google .genai .types .Part .Builder builder =
210+ com .google .genai .types .Part .builder ()
211+ .codeExecutionResult (
212+ CodeExecutionResult .builder ()
213+ .outcome (new Outcome (outcome ))
214+ .output (output )
215+ .build ());
216+ if (!metadata .isEmpty ()) {
217+ builder .partMetadata (metadata );
218+ }
219+ return builder .build ();
189220 }
190221
191222 try {
192223 String json = objectMapper .writeValueAsString (data );
193- return com .google .genai .types .Part .builder ().text (json ).build ();
224+ com .google .genai .types .Part .Builder builder =
225+ com .google .genai .types .Part .builder ().text (json );
226+ if (!metadata .isEmpty ()) {
227+ builder .partMetadata (metadata );
228+ }
229+ return builder .build ();
194230 } catch (JsonProcessingException e ) {
195231 throw new IllegalArgumentException ("Failed to serialize DataPart payload" , e );
196232 }
@@ -309,10 +345,11 @@ public static io.a2a.spec.Part<?> fromGenaiPart(Part part, boolean isPartial) {
309345 if (isPartial ) {
310346 metadata .put (A2AMetadataKey .PARTIAL .getType (), true );
311347 }
348+ part .partMetadata ().ifPresent (metadata ::putAll );
312349
313350 if (part .text ().isPresent ()) {
314351 addValueIfPresent (metadata , "thought" , part .thought ());
315- return new TextPart (part .text ().get (), metadata .buildOrThrow ());
352+ return new TextPart (part .text ().get (), metadata .buildKeepingLast ());
316353 }
317354
318355 if (part .fileData ().isPresent () || part .inlineData ().isPresent ()) {
0 commit comments