@@ -728,20 +728,37 @@ func dedupeInputItemsByID(rawArray string) (string, error) {
728728 return "" , errUnmarshal
729729 }
730730
731+ // Parse each item's type, id and call_id once; gjson is a scan-based
732+ // parser, so reusing this metadata avoids rescanning every item in each of
733+ // the loops below as the conversation history grows.
734+ type itemMetadata struct {
735+ itemType string
736+ id string
737+ callID string
738+ }
739+ meta := make ([]itemMetadata , len (items ))
740+ for i , item := range items {
741+ if len (item ) == 0 {
742+ continue
743+ }
744+ res := gjson .GetManyBytes (item , "type" , "id" , "call_id" )
745+ meta [i ] = itemMetadata {
746+ itemType : strings .TrimSpace (res [0 ].String ()),
747+ id : strings .TrimSpace (res [1 ].String ()),
748+ callID : strings .TrimSpace (res [2 ].String ()),
749+ }
750+ }
751+
731752 // Collect the call_ids that are still referenced by tool-call output
732753 // items. When several input items share the same id, the one we keep must
733754 // preserve any call_id that has a matching output; otherwise the upstream
734755 // rejects the request with "No tool call found for function call output".
735756 referencedCallIDs := make (map [string ]struct {}, len (items ))
736- for _ , item := range items {
737- if len (item ) == 0 {
738- continue
739- }
740- switch strings .TrimSpace (gjson .GetBytes (item , "type" ).String ()) {
757+ for i := range items {
758+ switch meta [i ].itemType {
741759 case "function_call_output" , "custom_tool_call_output" :
742- callID := strings .TrimSpace (gjson .GetBytes (item , "call_id" ).String ())
743- if callID != "" {
744- referencedCallIDs [callID ] = struct {}{}
760+ if meta [i ].callID != "" {
761+ referencedCallIDs [meta [i ].callID ] = struct {}{}
745762 }
746763 }
747764 }
@@ -753,17 +770,13 @@ func dedupeInputItemsByID(rawArray string) (string, error) {
753770 // paired with their outputs.
754771 keepIndexByID := make (map [string ]int , len (items ))
755772 keepReferencedByID := make (map [string ]bool , len (items ))
756- for i , item := range items {
757- if len (item ) == 0 {
758- continue
759- }
760- itemID := strings .TrimSpace (gjson .GetBytes (item , "id" ).String ())
773+ for i := range items {
774+ itemID := meta [i ].id
761775 if itemID == "" {
762776 continue
763777 }
764- callID := strings .TrimSpace (gjson .GetBytes (item , "call_id" ).String ())
765- _ , referenced := referencedCallIDs [callID ]
766- referenced = referenced && callID != ""
778+ _ , referenced := referencedCallIDs [meta [i ].callID ]
779+ referenced = referenced && meta [i ].callID != ""
767780 if _ , seen := keepIndexByID [itemID ]; ! seen {
768781 keepIndexByID [itemID ] = i
769782 keepReferencedByID [itemID ] = referenced
@@ -780,7 +793,7 @@ func dedupeInputItemsByID(rawArray string) (string, error) {
780793 if len (item ) == 0 {
781794 continue
782795 }
783- itemID := strings . TrimSpace ( gjson . GetBytes ( item , "id" ). String ())
796+ itemID := meta [ i ]. id
784797 if itemID != "" {
785798 if keepIndexByID [itemID ] != i {
786799 continue
0 commit comments