Skip to content

Commit 866f976

Browse files
committed
fix: drop trailing orphaned function responses
When the latest event is a function response whose IDs do not match any function-call event in session history (stale client retry, reconnect, session restart), drop only that trailing event and continue with the remaining valid history instead of hard-failing content construction. Fixes #760
1 parent a586408 commit 866f976

2 files changed

Lines changed: 20 additions & 7 deletions

File tree

internal/llminternal/contents_processor.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,10 @@ SearchLoop: // A label to allow breaking out of the nested loop
219219
}
220220

221221
if functionCallEventIdx == -1 {
222-
return nil, fmt.Errorf(
223-
"no function call event found for function responses ids: %v",
224-
responseIDs,
225-
)
222+
// Trailing function-response event has no matching call in history;
223+
// treat as stale (e.g. retry/reconnect) and drop it instead of failing
224+
// the whole turn. Earlier valid history is preserved.
225+
return events[:len(events)-1], nil
226226
}
227227

228228
// Collect all function response events *between* the call and the last response.

internal/llminternal/contents_processor_test.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -897,13 +897,26 @@ func TestContentsRequestProcessor_Rearrange(t *testing.T) {
897897
},
898898
},
899899
{
900-
name: "Error on function response without matching call",
900+
name: "Orphaned function response without matching call is dropped",
901901
events: []*session.Event{
902902
{Author: "user", LLMResponse: model.LLMResponse{Content: &genai.Content{Role: "user", Parts: []*genai.Part{{Text: "Regular message"}}}}},
903903
{Author: "user", LLMResponse: model.LLMResponse{Content: &genai.Content{Role: "user", Parts: []*genai.Part{{FunctionResponse: frOrphaned}}}}},
904904
},
905-
want: nil,
906-
wantErr: "no function call event found",
905+
want: []*genai.Content{
906+
genai.NewContentFromText("Regular message", "user"),
907+
},
908+
},
909+
{
910+
name: "Orphaned function response after text reply is dropped",
911+
events: []*session.Event{
912+
{Author: "user", LLMResponse: model.LLMResponse{Content: genai.NewContentFromText("Hello", "user")}},
913+
{Author: agentName, LLMResponse: model.LLMResponse{Content: genai.NewContentFromText("Hi there", "model")}},
914+
{Author: "user", LLMResponse: model.LLMResponse{Content: &genai.Content{Role: "user", Parts: []*genai.Part{{FunctionResponse: frOrphaned}}}}},
915+
},
916+
want: []*genai.Content{
917+
genai.NewContentFromText("Hello", "user"),
918+
genai.NewContentFromText("Hi there", "model"),
919+
},
907920
},
908921
}
909922

0 commit comments

Comments
 (0)