fix(agent): drop assistant tool_calls turns with incomplete tool results
This commit is contained in:
parent
74b5af9e53
commit
ba1376ae6d
2 changed files with 94 additions and 1 deletions
|
|
@ -602,7 +602,52 @@ func sanitizeHistoryForProvider(history []providers.Message) []providers.Message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sanitized
|
final := make([]providers.Message, 0, len(sanitized))
|
||||||
|
for i := 0; i < len(sanitized); i++ {
|
||||||
|
msg := sanitized[i]
|
||||||
|
if msg.Role != "assistant" || len(msg.ToolCalls) == 0 {
|
||||||
|
final = append(final, msg)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := make(map[string]bool, len(msg.ToolCalls))
|
||||||
|
for _, tc := range msg.ToolCalls {
|
||||||
|
expected[tc.ID] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := i + 1; j < len(sanitized); j++ {
|
||||||
|
next := sanitized[j]
|
||||||
|
if next.Role != "tool" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, ok := expected[next.ToolCallID]; ok {
|
||||||
|
expected[next.ToolCallID] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allFound := true
|
||||||
|
for _, found := range expected {
|
||||||
|
if !found {
|
||||||
|
allFound = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !allFound {
|
||||||
|
logger.DebugCF(
|
||||||
|
"agent",
|
||||||
|
"Dropping assistant tool-call turn with incomplete tool results",
|
||||||
|
map[string]any{"tool_calls": len(expected)},
|
||||||
|
)
|
||||||
|
for i+1 < len(sanitized) && sanitized[i+1].Role == "tool" {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
final = append(final, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return final
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cb *ContextBuilder) AddToolResult(
|
func (cb *ContextBuilder) AddToolResult(
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,54 @@ func TestSanitizeHistoryForProvider_PlainConversation(t *testing.T) {
|
||||||
assertRoles(t, result, "user", "assistant", "user", "assistant")
|
assertRoles(t, result, "user", "assistant", "user", "assistant")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSanitizeHistoryForProvider_AssistantToolCallMissingAllResults(t *testing.T) {
|
||||||
|
history := []providers.Message{
|
||||||
|
msg("user", "run tool"),
|
||||||
|
assistantWithTools("A"),
|
||||||
|
msg("assistant", "fallback text"),
|
||||||
|
}
|
||||||
|
|
||||||
|
result := sanitizeHistoryForProvider(history)
|
||||||
|
if len(result) != 2 {
|
||||||
|
t.Fatalf("expected 2 messages, got %d: %+v", len(result), roles(result))
|
||||||
|
}
|
||||||
|
assertRoles(t, result, "user", "assistant")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSanitizeHistoryForProvider_AssistantToolCallIncompleteResults(t *testing.T) {
|
||||||
|
history := []providers.Message{
|
||||||
|
msg("user", "run two tools"),
|
||||||
|
assistantWithTools("A", "B"),
|
||||||
|
toolResult("A"),
|
||||||
|
msg("assistant", "next"),
|
||||||
|
}
|
||||||
|
|
||||||
|
result := sanitizeHistoryForProvider(history)
|
||||||
|
if len(result) != 2 {
|
||||||
|
t.Fatalf("expected 2 messages, got %d: %+v", len(result), roles(result))
|
||||||
|
}
|
||||||
|
assertRoles(t, result, "user", "assistant")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSanitizeHistoryForProvider_DropsBrokenRoundKeepsCompleteRound(t *testing.T) {
|
||||||
|
history := []providers.Message{
|
||||||
|
msg("user", "first"),
|
||||||
|
assistantWithTools("A", "B"),
|
||||||
|
toolResult("A"),
|
||||||
|
msg("assistant", "after broken round"),
|
||||||
|
msg("user", "second"),
|
||||||
|
assistantWithTools("C"),
|
||||||
|
toolResult("C"),
|
||||||
|
msg("assistant", "done"),
|
||||||
|
}
|
||||||
|
|
||||||
|
result := sanitizeHistoryForProvider(history)
|
||||||
|
if len(result) != 6 {
|
||||||
|
t.Fatalf("expected 6 messages, got %d: %+v", len(result), roles(result))
|
||||||
|
}
|
||||||
|
assertRoles(t, result, "user", "assistant", "user", "assistant", "tool", "assistant")
|
||||||
|
}
|
||||||
|
|
||||||
func roles(msgs []providers.Message) []string {
|
func roles(msgs []providers.Message) []string {
|
||||||
r := make([]string, len(msgs))
|
r := make([]string, len(msgs))
|
||||||
for i, m := range msgs {
|
for i, m := range msgs {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue