| package semanticcache |
|
|
| import ( |
| "strconv" |
| "testing" |
|
|
| bifrost "github.com/maximhq/bifrost/core" |
| "github.com/maximhq/bifrost/core/schemas" |
| ) |
|
|
| |
| func TestConversationHistoryThresholdBasic(t *testing.T) { |
| |
| setup := CreateTestSetupWithConversationThreshold(t, 2) |
| defer setup.Cleanup() |
|
|
| ctx := CreateContextWithCacheKey("test-conversation-threshold-basic") |
|
|
| |
| conversation1 := BuildConversationHistory("", |
| []string{"Hello", "Hi there!"}, |
| ) |
| request1 := CreateConversationRequest(conversation1, 0.7, 50) |
|
|
| t.Log("Testing conversation with exactly 2 messages (at threshold)...") |
| response1, err1 := setup.Client.ChatCompletionRequest(ctx, request1) |
| if err1 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1}) |
|
|
| WaitForCache(setup.Plugin) |
|
|
| |
| response2, err2 := setup.Client.ChatCompletionRequest(ctx, request1) |
| if err2 != nil { |
| if err2.Error != nil { |
| t.Fatalf("Second request failed: %v", err2.Error.Message) |
| } else { |
| t.Fatalf("Second request failed: %v", err2) |
| } |
| } |
| AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}, "direct") |
|
|
| |
| conversation2 := BuildConversationHistory("", |
| []string{"Hello", "Hi there!"}, |
| []string{"How are you?", "I'm doing well!"}, |
| ) |
| messages2 := AddUserMessage(conversation2, "What's the weather?") |
| request2 := CreateConversationRequest(messages2, 0.7, 50) |
|
|
| t.Log("Testing conversation with 5 messages (exceeds threshold)...") |
| response3, err3 := setup.Client.ChatCompletionRequest(ctx, request2) |
| if err3 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response3}) |
|
|
| WaitForCache(setup.Plugin) |
|
|
| |
| t.Log("Verifying conversation exceeding threshold was not cached...") |
| response4, err4 := setup.Client.ChatCompletionRequest(ctx, request2) |
| if err4 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response4}) |
|
|
| t.Log("✅ Conversation history threshold works correctly") |
| } |
|
|
| |
| func TestConversationHistoryThresholdWithSystemPrompt(t *testing.T) { |
| |
| setup := CreateTestSetupWithConversationThreshold(t, 3) |
| defer setup.Cleanup() |
|
|
| ctx := CreateContextWithCacheKey("test-threshold-system-prompt") |
|
|
| |
| conversation := BuildConversationHistory( |
| "You are a helpful assistant", |
| []string{"Hello", "Hi there!"}, |
| []string{"How are you?", "I'm doing well!"}, |
| ) |
| request := CreateConversationRequest(conversation, 0.7, 50) |
|
|
| t.Log("Testing conversation with system prompt (5 total messages > 3 threshold)...") |
| response1, err1 := setup.Client.ChatCompletionRequest(ctx, request) |
| if err1 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1}) |
|
|
| WaitForCache(setup.Plugin) |
|
|
| |
| response2, err2 := setup.Client.ChatCompletionRequest(ctx, request) |
| if err2 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}) |
|
|
| t.Log("✅ Conversation threshold correctly counts system messages") |
| } |
|
|
| |
| func TestConversationHistoryThresholdWithExcludeSystemPrompt(t *testing.T) { |
| |
| setup := CreateTestSetupWithThresholdAndExcludeSystem(t, 3, true) |
| defer setup.Cleanup() |
|
|
| ctx := CreateContextWithCacheKey("test-threshold-exclude-system") |
|
|
| |
| |
| |
| conversation := BuildConversationHistory( |
| "You are helpful", |
| []string{"Hello", "Hi"}, |
| []string{"Thanks", ""}, |
| ) |
| |
| request := CreateConversationRequest(conversation, 0.7, 50) |
|
|
| t.Log("Testing threshold with ExcludeSystemPrompt=true (3 non-system messages = at threshold)...") |
|
|
| |
| |
| |
| |
|
|
| response1, err1 := setup.Client.ChatCompletionRequest(ctx, request) |
| if err1 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1}) |
|
|
| WaitForCache(setup.Plugin) |
|
|
| |
| response2, err2 := setup.Client.ChatCompletionRequest(ctx, request) |
| if err2 != nil { |
| if err2.Error != nil { |
| t.Fatalf("Second request failed: %v", err2.Error.Message) |
| } else { |
| t.Fatalf("Second request failed: %v", err2) |
| } |
| } |
| AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}, "direct") |
|
|
| t.Log("✅ Conversation threshold respects ExcludeSystemPrompt setting") |
| } |
|
|
| |
| func TestConversationHistoryThresholdDifferentValues(t *testing.T) { |
| testCases := []struct { |
| name string |
| threshold int |
| messages int |
| shouldCache bool |
| }{ |
| {"Threshold 1, 1 message", 1, 1, true}, |
| {"Threshold 1, 2 messages", 1, 2, false}, |
| {"Threshold 5, 4 messages", 5, 4, true}, |
| {"Threshold 5, 6 messages", 5, 6, false}, |
| } |
|
|
| for _, tc := range testCases { |
| t.Run(tc.name, func(t *testing.T) { |
| setup := CreateTestSetupWithConversationThreshold(t, tc.threshold) |
| defer setup.Cleanup() |
|
|
| ctx := CreateContextWithCacheKey("test-threshold-" + tc.name) |
|
|
| |
| var conversation []schemas.ChatMessage |
| for i := 0; i < tc.messages; i++ { |
| role := schemas.ChatMessageRoleUser |
| if i%2 == 1 { |
| role = schemas.ChatMessageRoleAssistant |
| } |
| message := schemas.ChatMessage{ |
| Role: role, |
| Content: &schemas.ChatMessageContent{ |
| ContentStr: bifrost.Ptr("Message " + strconv.Itoa(i+1)), |
| }, |
| } |
| conversation = append(conversation, message) |
| } |
|
|
| request := CreateConversationRequest(conversation, 0.7, 50) |
|
|
| response1, err1 := setup.Client.ChatCompletionRequest(ctx, request) |
| if err1 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1}) |
|
|
| WaitForCache(setup.Plugin) |
|
|
| response2, err2 := setup.Client.ChatCompletionRequest(ctx, request) |
| if err2 != nil { |
| return |
| } |
|
|
| if tc.shouldCache { |
| AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}, "direct") |
| } else { |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}) |
| } |
| }) |
| } |
|
|
| t.Log("✅ Different conversation threshold values work correctly") |
| } |
|
|
| |
| func TestExcludeSystemPromptBasic(t *testing.T) { |
| |
| setup := CreateTestSetupWithExcludeSystemPrompt(t, true) |
| defer setup.Cleanup() |
|
|
| ctx := CreateContextWithCacheKey("test-exclude-system-basic") |
|
|
| |
| conversation1 := BuildConversationHistory( |
| "You are a helpful assistant", |
| []string{"What is AI?", "AI is artificial intelligence."}, |
| ) |
|
|
| conversation2 := BuildConversationHistory( |
| "You are a technical expert", |
| []string{"What is AI?", "AI is artificial intelligence."}, |
| ) |
|
|
| request1 := CreateConversationRequest(conversation1, 0.7, 50) |
| request2 := CreateConversationRequest(conversation2, 0.7, 50) |
|
|
| t.Log("Caching conversation with system prompt 1...") |
| response1, err1 := setup.Client.ChatCompletionRequest(ctx, request1) |
| if err1 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1}) |
|
|
| WaitForCache(setup.Plugin) |
|
|
| t.Log("Testing conversation with different system prompt (should hit cache due to ExcludeSystemPrompt=true)...") |
| response2, err2 := setup.Client.ChatCompletionRequest(ctx, request2) |
| if err2 != nil { |
| if err2.Error != nil { |
| t.Fatalf("Second request failed: %v", err2.Error.Message) |
| } else { |
| t.Fatalf("Second request failed: %v", err2) |
| } |
| } |
| |
| AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}, "direct") |
|
|
| t.Log("✅ ExcludeSystemPrompt=true correctly ignores system prompts in cache keys") |
| } |
|
|
| |
| func TestExcludeSystemPromptComparison(t *testing.T) { |
| |
| setup1 := CreateTestSetupWithExcludeSystemPrompt(t, false) |
| defer setup1.Cleanup() |
|
|
| ctx1 := CreateContextWithCacheKey("test-exclude-system-false") |
|
|
| conversation1 := BuildConversationHistory( |
| "You are helpful", |
| []string{"Hello", "Hi there!"}, |
| ) |
|
|
| conversation2 := BuildConversationHistory( |
| "You are an expert", |
| []string{"Hello", "Hi there!"}, |
| ) |
|
|
| request1 := CreateConversationRequest(conversation1, 0.7, 50) |
| request2 := CreateConversationRequest(conversation2, 0.7, 50) |
|
|
| t.Log("Testing ExcludeSystemPrompt=false...") |
| response1, err1 := setup1.Client.ChatCompletionRequest(ctx1, request1) |
| if err1 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1}) |
|
|
| WaitForCache(setup1.Plugin) |
|
|
| response2, err2 := setup1.Client.ChatCompletionRequest(ctx1, request2) |
| if err2 != nil { |
| if err2.Error != nil { |
| t.Fatalf("Second request failed: %v", err2.Error.Message) |
| } else { |
| t.Fatalf("Second request failed: %v", err2) |
| } |
| } |
| |
| if response2.ExtraFields.CacheDebug != nil && response2.ExtraFields.CacheDebug.CacheHit { |
| if response2.ExtraFields.CacheDebug.HitType != nil && *response2.ExtraFields.CacheDebug.HitType == "semantic" { |
| t.Log("✅ Found semantic cache match (expected with similar content)") |
| } else { |
| t.Error("❌ Unexpected direct cache hit with different system prompts") |
| } |
| } else { |
| t.Log("✅ No cache hit (system prompts create different cache keys)") |
| } |
|
|
| |
| setup2 := CreateTestSetupWithExcludeSystemPrompt(t, true) |
| defer setup2.Cleanup() |
|
|
| ctx2 := CreateContextWithCacheKey("test-exclude-system-true") |
|
|
| t.Log("Testing ExcludeSystemPrompt=true...") |
| response3, err3 := setup2.Client.ChatCompletionRequest(ctx2, request1) |
| if err3 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response3}) |
|
|
| WaitForCache(setup2.Plugin) |
|
|
| response4, err4 := setup2.Client.ChatCompletionRequest(ctx2, request2) |
| if err4 != nil { |
| t.Fatalf("Fourth request failed: %v", err4) |
| } |
| |
| AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response4}, "direct") |
|
|
| t.Log("✅ ExcludeSystemPrompt true vs false comparison works correctly") |
| } |
|
|
| |
| func TestExcludeSystemPromptWithMultipleSystemMessages(t *testing.T) { |
| setup := CreateTestSetupWithExcludeSystemPrompt(t, true) |
| defer setup.Cleanup() |
|
|
| ctx := CreateContextWithCacheKey("test-multiple-system-messages") |
|
|
| |
| conversation1 := []schemas.ChatMessage{ |
| { |
| Role: schemas.ChatMessageRoleSystem, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("You are helpful")}, |
| }, |
| { |
| Role: schemas.ChatMessageRoleSystem, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("Be concise")}, |
| }, |
| { |
| Role: schemas.ChatMessageRoleUser, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("Hello")}, |
| }, |
| { |
| Role: schemas.ChatMessageRoleAssistant, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("Hi!")}, |
| }, |
| } |
|
|
| conversation2 := []schemas.ChatMessage{ |
| { |
| Role: schemas.ChatMessageRoleSystem, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("You are an expert")}, |
| }, |
| { |
| Role: schemas.ChatMessageRoleSystem, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("Be detailed")}, |
| }, |
| { |
| Role: schemas.ChatMessageRoleUser, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("Hello")}, |
| }, |
| { |
| Role: schemas.ChatMessageRoleAssistant, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("Hi!")}, |
| }, |
| } |
|
|
| request1 := CreateConversationRequest(conversation1, 0.7, 50) |
| request2 := CreateConversationRequest(conversation2, 0.7, 50) |
|
|
| t.Log("Caching conversation with multiple system messages...") |
| response1, err1 := setup.Client.ChatCompletionRequest(ctx, request1) |
| if err1 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1}) |
|
|
| WaitForCache(setup.Plugin) |
|
|
| t.Log("Testing conversation with different multiple system messages...") |
| response2, err2 := setup.Client.ChatCompletionRequest(ctx, request2) |
| if err2 != nil { |
| if err2.Error != nil { |
| t.Fatalf("Second request failed: %v", err2.Error.Message) |
| } else { |
| t.Fatalf("Second request failed: %v", err2) |
| } |
| } |
| |
| AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}, "direct") |
|
|
| t.Log("✅ ExcludeSystemPrompt works with multiple system messages") |
| } |
|
|
| |
| func TestExcludeSystemPromptWithNoSystemMessages(t *testing.T) { |
| setup := CreateTestSetupWithExcludeSystemPrompt(t, true) |
| defer setup.Cleanup() |
|
|
| ctx := CreateContextWithCacheKey("test-no-system-messages") |
|
|
| |
| conversation := []schemas.ChatMessage{ |
| { |
| Role: schemas.ChatMessageRoleUser, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("Hello")}, |
| }, |
| { |
| Role: schemas.ChatMessageRoleAssistant, |
| Content: &schemas.ChatMessageContent{ContentStr: bifrost.Ptr("Hi there!")}, |
| }, |
| } |
|
|
| request := CreateConversationRequest(conversation, 0.7, 50) |
|
|
| t.Log("Testing conversation with no system messages...") |
| response1, err1 := setup.Client.ChatCompletionRequest(ctx, request) |
| if err1 != nil { |
| return |
| } |
| AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1}) |
|
|
| WaitForCache(setup.Plugin) |
|
|
| |
| response2, err2 := setup.Client.ChatCompletionRequest(ctx, request) |
| if err2 != nil { |
| if err2.Error != nil { |
| t.Fatalf("Second request failed: %v", err2.Error.Message) |
| } else { |
| t.Fatalf("Second request failed: %v", err2) |
| } |
| } |
| AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}, "direct") |
|
|
| t.Log("✅ ExcludeSystemPrompt works correctly when no system messages present") |
| } |
|
|