diff --git a/backend/internal/service/openai_responses_item_id.go b/backend/internal/service/openai_responses_item_id.go index cb1522e4fb..5fc8bb77d5 100644 --- a/backend/internal/service/openai_responses_item_id.go +++ b/backend/internal/service/openai_responses_item_id.go @@ -50,7 +50,7 @@ func shouldStripOpenAIResponsesInputItemID(itemType, id string) bool { if !constrained { return false } - return id == "" || !strings.HasPrefix(id, prefix) + return id == "" || len(id) > 64 || !strings.HasPrefix(id, prefix) } func shouldStripOpenAIResponsesNonPairCallID(itemType string) bool { diff --git a/backend/internal/service/openai_responses_item_id_test.go b/backend/internal/service/openai_responses_item_id_test.go index b300b22a2e..10fd5dd6e0 100644 --- a/backend/internal/service/openai_responses_item_id_test.go +++ b/backend/internal/service/openai_responses_item_id_test.go @@ -2,6 +2,7 @@ package service import ( "strconv" + "strings" "testing" "github.com/stretchr/testify/require" @@ -29,6 +30,9 @@ func TestOpenAIResponsesInputItemIDPrefixUsesObservedOutputContracts(t *testing. {itemType: "tool_search_call", id: "fc_123", strip: true}, {itemType: "web_search_call", id: "ws_123", strip: false}, {itemType: "web_search_call", id: "item_123", strip: true}, + {itemType: "web_search_call", id: "ws_" + strings.Repeat("x", 60), strip: false}, + {itemType: "web_search_call", id: "ws_" + strings.Repeat("x", 61), strip: false}, + {itemType: "web_search_call", id: "ws_" + strings.Repeat("x", 62), strip: true}, {itemType: "custom_tool_call_output", id: "fc_123", strip: false}, {itemType: "custom_tool_call_output", id: "ctco_123", strip: true}, // Do not impose an inferred contract on output types for which there is @@ -132,6 +136,19 @@ func TestSanitizeOpenAIResponsesInputItemIDsStripsEmptyKnownIDsOnly(t *testing.T require.True(t, gjson.GetBytes(sanitized, "input.1.id").Exists()) } +func TestSanitizeOpenAIResponsesInputItemIDsStripsOversizedWebSearchID(t *testing.T) { + validID := "ws_" + strings.Repeat("x", 61) + oversizedID := "ws_" + strings.Repeat("x", 62) + body := []byte(`{"input":[{"type":"web_search_call","id":"` + validID + `"},{"type":"web_search_call","id":"` + oversizedID + `"}]}`) + + sanitized, changed, err := sanitizeOpenAIResponsesInputItemIDs(body) + + require.NoError(t, err) + require.True(t, changed) + require.Equal(t, validID, gjson.GetBytes(sanitized, "input.0.id").String()) + require.False(t, gjson.GetBytes(sanitized, "input.1.id").Exists()) +} + func TestSanitizeOpenAIResponsesInputItemIDsStripsOnlyNonPairCallIDs(t *testing.T) { body := []byte(`{"input":[ {"type":"message","call_id":"remove_message","content":"hi"},