@@ -273,9 +273,102 @@ func (r *InternalLLMRequest) Validate() error {
273273 return errors .New ("messages are required" )
274274 }
275275
276+ if isChatRequest {
277+ r .fillMissingToolCallIDsFromToolMessages ()
278+ // r.fillMissingToolCallIDs()
279+ }
280+
276281 return nil
277282}
278283
284+ func (r * InternalLLMRequest ) fillMissingToolCallIDs () {
285+ usedIDs := make (map [string ]struct {})
286+ for _ , msg := range r .Messages {
287+ for _ , tc := range msg .ToolCalls {
288+ if tc .ID == "" {
289+ continue
290+ }
291+ usedIDs [tc .ID ] = struct {}{}
292+ }
293+ }
294+
295+ sequence := 0
296+ for messageIndex := range r .Messages {
297+ for toolCallIndex := range r .Messages [messageIndex ].ToolCalls {
298+ toolCall := & r .Messages [messageIndex ].ToolCalls [toolCallIndex ]
299+ if toolCall .ID != "" {
300+ continue
301+ }
302+
303+ candidate := fmt .Sprintf ("call_octopus_%d_%d" , messageIndex , toolCallIndex )
304+ if _ , exists := usedIDs [candidate ]; exists {
305+ for {
306+ candidate = fmt .Sprintf ("call_octopus_%d" , sequence )
307+ sequence ++
308+ if _ , conflict := usedIDs [candidate ]; ! conflict {
309+ break
310+ }
311+ }
312+ }
313+
314+ toolCall .ID = candidate
315+ usedIDs [candidate ] = struct {}{}
316+ }
317+ }
318+ }
319+
320+
321+ func (r * InternalLLMRequest ) fillMissingToolCallIDsFromToolMessages () {
322+ for msgIndex := 0 ; msgIndex < len (r .Messages ); msgIndex ++ {
323+ msg := & r .Messages [msgIndex ]
324+ if msg .Role != "assistant" || len (msg .ToolCalls ) == 0 {
325+ continue
326+ }
327+
328+ candidates := make ([]string , 0 , len (msg .ToolCalls ))
329+ for nextIndex := msgIndex + 1 ; nextIndex < len (r .Messages ); nextIndex ++ {
330+ nextMsg := r .Messages [nextIndex ]
331+ if nextMsg .Role != "tool" {
332+ break
333+ }
334+ if nextMsg .ToolCallID == nil || * nextMsg .ToolCallID == "" {
335+ continue
336+ }
337+ candidates = append (candidates , * nextMsg .ToolCallID )
338+ }
339+
340+ if len (candidates ) == 0 {
341+ continue
342+ }
343+
344+ used := make (map [string ]struct {})
345+ for _ , toolCall := range msg .ToolCalls {
346+ if toolCall .ID == "" {
347+ continue
348+ }
349+ used [toolCall .ID ] = struct {}{}
350+ }
351+
352+ candidateIndex := 0
353+ for toolCallIndex := range msg .ToolCalls {
354+ if msg .ToolCalls [toolCallIndex ].ID != "" {
355+ continue
356+ }
357+
358+ for candidateIndex < len (candidates ) {
359+ candidate := candidates [candidateIndex ]
360+ candidateIndex ++
361+ if _ , exists := used [candidate ]; exists {
362+ continue
363+ }
364+ msg .ToolCalls [toolCallIndex ].ID = candidate
365+ used [candidate ] = struct {}{}
366+ break
367+ }
368+ }
369+ }
370+ }
371+
279372// IsEmbeddingRequest returns true if this is an embedding request.
280373func (r * InternalLLMRequest ) IsEmbeddingRequest () bool {
281374 return r .EmbeddingInput != nil
0 commit comments