diff --git a/agent/compaction/equality.go b/agent/compaction/equality.go index f62a21c1..d56996f9 100644 --- a/agent/compaction/equality.go +++ b/agent/compaction/equality.go @@ -70,7 +70,29 @@ func contentEqual(left, right message.Content) bool { case *message.HostedFileContent: rightContent := right.(*message.HostedFileContent) return leftContent.FileID == rightContent.FileID && leftContent.MediaType == rightContent.MediaType && leftContent.Name == rightContent.Name + case *message.MCPServerToolCallContent: + rightContent := right.(*message.MCPServerToolCallContent) + return leftContent.CallID == rightContent.CallID && leftContent.Name == rightContent.Name && + leftContent.ServerName == rightContent.ServerName && leftContent.Arguments == rightContent.Arguments + case *message.MCPServerToolResultContent: + rightContent := right.(*message.MCPServerToolResultContent) + return leftContent.CallID == rightContent.CallID && leftContent.Name == rightContent.Name && + leftContent.ServerName == rightContent.ServerName && leftContent.Error == rightContent.Error && + contentsEqual(leftContent.Outputs, rightContent.Outputs) + case *message.CodeInterpreterToolCallContent: + rightContent := right.(*message.CodeInterpreterToolCallContent) + return leftContent.CallID == rightContent.CallID && contentsEqual(leftContent.Inputs, rightContent.Inputs) + case *message.CodeInterpreterToolResultContent: + rightContent := right.(*message.CodeInterpreterToolResultContent) + return leftContent.CallID == rightContent.CallID && contentsEqual(leftContent.Outputs, rightContent.Outputs) + case *message.UsageContent: + rightContent := right.(*message.UsageContent) + return reflect.DeepEqual(leftContent.Details, rightContent.Details) default: + // An unhandled content type is treated as equal so a genuinely new, + // forward-compatible content type does not force an index rebuild. The + // hosted content types the framework produces are handled explicitly + // above so real changes in them are detected. return true } } diff --git a/agent/compaction/equality_test.go b/agent/compaction/equality_test.go index 346edaf5..95f7797f 100644 --- a/agent/compaction/equality_test.go +++ b/agent/compaction/equality_test.go @@ -68,6 +68,12 @@ func TestMessageIndexUpdate_MatchesKnownContentTypes(t *testing.T) { {name: "function result", original: &message.FunctionResultContent{CallID: "c1", Result: "sunny"}, replacement: &message.FunctionResultContent{CallID: "c1", Result: "rainy"}, matches: false}, {name: "function result error", original: &message.FunctionResultContent{CallID: "c1", Result: "sunny"}, replacement: &message.FunctionResultContent{CallID: "c1", Result: "sunny", Error: errors.New("boom")}, matches: false}, {name: "hosted file", original: &message.HostedFileContent{FileID: "file-1", MediaType: "text/csv", Name: "a.csv"}, replacement: &message.HostedFileContent{FileID: "file-1", MediaType: "text/csv", Name: "a.csv"}, matches: true}, + {name: "mcp call same", original: &message.MCPServerToolCallContent{CallID: "c1", Name: "fn", Arguments: `{"x":1}`}, replacement: &message.MCPServerToolCallContent{CallID: "c1", Name: "fn", Arguments: `{"x":1}`}, matches: true}, + {name: "mcp call args differ", original: &message.MCPServerToolCallContent{CallID: "c1", Name: "fn", Arguments: `{"x":1}`}, replacement: &message.MCPServerToolCallContent{CallID: "c1", Name: "fn", Arguments: `{"x":2}`}, matches: false}, + {name: "mcp result outputs differ", original: &message.MCPServerToolResultContent{CallID: "c1", Outputs: message.Contents{&message.TextContent{Text: "a"}}}, replacement: &message.MCPServerToolResultContent{CallID: "c1", Outputs: message.Contents{&message.TextContent{Text: "b"}}}, matches: false}, + {name: "code interpreter call inputs differ", original: &message.CodeInterpreterToolCallContent{CallID: "c1", Inputs: message.Contents{&message.TextContent{Text: "x=1"}}}, replacement: &message.CodeInterpreterToolCallContent{CallID: "c1", Inputs: message.Contents{&message.TextContent{Text: "x=2"}}}, matches: false}, + {name: "code interpreter result outputs differ", original: &message.CodeInterpreterToolResultContent{CallID: "c1", Outputs: message.Contents{&message.TextContent{Text: "1"}}}, replacement: &message.CodeInterpreterToolResultContent{CallID: "c1", Outputs: message.Contents{&message.TextContent{Text: "2"}}}, matches: false}, + {name: "usage differs", original: &message.UsageContent{Details: message.UsageDetails{InputTokenCount: 10}}, replacement: &message.UsageContent{Details: message.UsageDetails{InputTokenCount: 20}}, matches: false}, } for _, tt := range tests {