openai_compact_body_signal_test.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. //go:build unit
  2. package service
  3. import (
  4. "testing"
  5. "github.com/gin-gonic/gin"
  6. "github.com/stretchr/testify/require"
  7. "github.com/tidwall/gjson"
  8. )
  9. func TestIsOpenAINativeCompactionV2ReadsOnlyRequestMarker(t *testing.T) {
  10. c, _ := gin.CreateTestContext(nil)
  11. require.False(t, IsOpenAINativeCompactionV2(c))
  12. MarkOpenAINativeCompactionV2(c)
  13. require.True(t, IsOpenAINativeCompactionV2(c))
  14. require.False(t, IsOpenAINativeCompactionV2(nil))
  15. }
  16. func TestHasCompactionTriggerInInput_DetectsCompactSignal(t *testing.T) {
  17. body := []byte(`{
  18. "model":"gpt-5.5",
  19. "stream":true,
  20. "input":[
  21. {"type":"message","role":"user","content":"hello"},
  22. {"type":"compaction_trigger"}
  23. ]
  24. }`)
  25. require.True(t, HasCompactionTriggerInInput(body))
  26. }
  27. func TestHasCompactionTriggerInInput_NoTrigger(t *testing.T) {
  28. body := []byte(`{
  29. "model":"gpt-5.5",
  30. "input":[
  31. {"type":"message","role":"user","content":"hello"}
  32. ]
  33. }`)
  34. require.False(t, HasCompactionTriggerInInput(body))
  35. }
  36. func TestHasCompactionTriggerInInput_EmptyInput(t *testing.T) {
  37. body := []byte(`{"model":"gpt-5.5","input":[]}`)
  38. require.False(t, HasCompactionTriggerInInput(body))
  39. }
  40. func TestHasCompactionTriggerInInput_NoInputField(t *testing.T) {
  41. body := []byte(`{"model":"gpt-5.5"}`)
  42. require.False(t, HasCompactionTriggerInInput(body))
  43. }
  44. func TestHasCompactionTriggerInInput_EmptyBody(t *testing.T) {
  45. require.False(t, HasCompactionTriggerInInput(nil))
  46. require.False(t, HasCompactionTriggerInInput([]byte{}))
  47. }
  48. func TestHasCompactionTriggerInInput_StringInput(t *testing.T) {
  49. body := []byte(`{"model":"gpt-5.5","input":"compaction_trigger"}`)
  50. require.False(t, HasCompactionTriggerInInput(body))
  51. }
  52. func TestHasCompactionTriggerInInput_CompactTriggerOnly(t *testing.T) {
  53. body := []byte(`{"model":"gpt-5.5","input":[{"type":"compaction_trigger"}]}`)
  54. require.True(t, HasCompactionTriggerInInput(body))
  55. }
  56. func TestNormalizeCompactionTriggerInputOrder_MovesAndCollapsesTriggers(t *testing.T) {
  57. body := []byte(`{"model":"gpt-5.5","input":[{"type":"compaction_trigger"},{"type":"message","role":"user","content":"tail"},{"type":"compaction_trigger"}]}`)
  58. normalized, changed, err := NormalizeCompactionTriggerInputOrder(body)
  59. require.NoError(t, err)
  60. require.True(t, changed)
  61. items := gjson.GetBytes(normalized, "input").Array()
  62. require.Len(t, items, 2)
  63. require.Equal(t, "message", items[0].Get("type").String())
  64. require.Equal(t, "compaction_trigger", items[1].Get("type").String())
  65. }
  66. func TestNormalizeCompactionTriggerInputOrder_AlreadyFinalPreservesBytes(t *testing.T) {
  67. body := []byte(`{"input":[{"type":"message"},{"type":"compaction_trigger"}]}`)
  68. normalized, changed, err := NormalizeCompactionTriggerInputOrder(body)
  69. require.NoError(t, err)
  70. require.False(t, changed)
  71. require.Equal(t, string(body), string(normalized))
  72. }
  73. func TestNormalizeCompactionTriggerInputOrder_PreservesHistoryAndLargeNumbers(t *testing.T) {
  74. body := []byte(`{"input":[{"type":"compaction_trigger"},{"type":"message","id":"msg_1","content":"visible"},{"type":"function_call_output","call_id":"call_1","output":"result","sequence":9007199254740993}]}`)
  75. normalized, changed, err := NormalizeCompactionTriggerInputOrder(body)
  76. require.NoError(t, err)
  77. require.True(t, changed)
  78. require.Equal(t, "message", gjson.GetBytes(normalized, "input.0.type").String())
  79. require.Equal(t, "function_call_output", gjson.GetBytes(normalized, "input.1.type").String())
  80. require.Equal(t, "9007199254740993", gjson.GetBytes(normalized, "input.1.sequence").Raw)
  81. require.Equal(t, "compaction_trigger", gjson.GetBytes(normalized, "input.2.type").String())
  82. second, changedAgain, err := NormalizeCompactionTriggerInputOrder(normalized)
  83. require.NoError(t, err)
  84. require.False(t, changedAgain)
  85. require.Equal(t, normalized, second)
  86. }
  87. func TestWebSocketCompatibilityNormalizesTriggerAfterPairedOutputCleanup(t *testing.T) {
  88. body := []byte(`{"type":"response.create","model":"gpt-5.4","input":[{"type":"compaction_trigger"},{"type":"function_call","call_id":"call_1","name":"lookup","arguments":"{}"},{"type":"function_call_output","call_id":"call_1","output":"ok"},{"type":"message","role":"user","content":"visible"}]}`)
  89. account := &Account{Platform: PlatformOpenAI, Type: AccountTypeOAuth}
  90. normalized, changed, err := normalizeOpenAIResponsesWebSocketCompatibilityBody(body, account, false)
  91. require.NoError(t, err)
  92. require.True(t, changed)
  93. items := gjson.GetBytes(normalized, "input").Array()
  94. require.Len(t, items, 4)
  95. require.Equal(t, "function_call", items[0].Get("type").String())
  96. require.Equal(t, "function_call_output", items[1].Get("type").String())
  97. require.Equal(t, "message", items[2].Get("type").String())
  98. require.Equal(t, "compaction_trigger", items[3].Get("type").String())
  99. }