@@ -142,6 +142,7 @@ private static LongJobProgressDetail tryParseAiDownloadFormat(Map<String, Object
142142 }
143143
144144 LongJobProgressDetail detail = new LongJobProgressDetail ();
145+ Map <String , Object > extra = new HashMap <>();
145146
146147 // state field
147148 Object stateVal = inner .get ("state" );
@@ -156,7 +157,7 @@ private static LongJobProgressDetail tryParseAiDownloadFormat(Map<String, Object
156157
157158 Number percent = toNumber (progress .get ("percent" ));
158159 if (percent != null ) {
159- detail .setPercent (( int ) Math .round (percent .doubleValue ()));
160+ detail .setPercent (Math . max ( 0 , Math . min ( 100 , ( int ) Math .round (percent .doubleValue ()) )));
160161 }
161162
162163 // AI agent uses snake_case field names
@@ -205,9 +206,7 @@ private static LongJobProgressDetail tryParseAiDownloadFormat(Map<String, Object
205206 extraProgress .remove ("downloaded_files" );
206207 extraProgress .remove ("total_files" );
207208 extraProgress .remove ("stage" );
208- if (!extraProgress .isEmpty ()) {
209- detail .setExtra (extraProgress );
210- }
209+ extra .putAll (extraProgress );
211210 }
212211
213212 // stateReason field — can be String or Map (structured reason with code/description)
@@ -218,6 +217,22 @@ private static LongJobProgressDetail tryParseAiDownloadFormat(Map<String, Object
218217 detail .setStateReason (JSONObjectUtil .toJsonString (stateReason ));
219218 }
220219
220+ // preserve unknown keys from inner top-level
221+ Map <String , Object > extraInner = new HashMap <>(inner );
222+ extraInner .remove ("state" );
223+ extraInner .remove ("progress" );
224+ extraInner .remove ("state_reason" );
225+ extra .putAll (extraInner );
226+
227+ // preserve unknown keys from raw outer-level
228+ Map <String , Object > extraRaw = new HashMap <>(raw );
229+ extraRaw .remove ("data" );
230+ extra .putAll (extraRaw );
231+
232+ if (!extra .isEmpty ()) {
233+ detail .setExtra (extra );
234+ }
235+
221236 return detail ;
222237 } catch (Exception e ) {
223238 logger .trace ("LongJobProgressDetailBuilder: failed to parse AI download format" , e );
0 commit comments