first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:52:23 +03:00
commit 880f412e2c
2662 changed files with 866266 additions and 0 deletions

View File

@@ -0,0 +1,198 @@
package azure_test
import (
"strings"
"testing"
"github.com/maximhq/bifrost/core/providers/openai"
"github.com/maximhq/bifrost/core/schemas"
)
// TestAzure_OpenAIModel_CachingDeterminism verifies that Azure's delegation to
// openai.ToOpenAIChatRequest() produces deterministic JSON for prompt caching.
// Two schemas with the same properties but different structural key order within
// property definitions must produce byte-identical JSON after normalization.
func TestAzure_OpenAIModel_CachingDeterminism(t *testing.T) {
makeReq := func(props *schemas.OrderedMap) *schemas.BifrostChatRequest {
return &schemas.BifrostChatRequest{
Provider: schemas.Azure,
Model: "gpt-4o",
Input: []schemas.ChatMessage{{Role: schemas.ChatMessageRoleUser}},
Params: &schemas.ChatParameters{
Tools: []schemas.ChatTool{{
Type: schemas.ChatToolTypeFunction,
Function: &schemas.ChatToolFunction{
Name: "test",
Parameters: &schemas.ToolFunctionParameters{
Type: "object",
Properties: props,
},
},
}},
},
}
}
// Version A: type before description
propsA := schemas.NewOrderedMapFromPairs(
schemas.KV("reasoning", schemas.NewOrderedMapFromPairs(
schemas.KV("type", "string"),
schemas.KV("description", "Step by step"),
)),
schemas.KV("answer", schemas.NewOrderedMapFromPairs(
schemas.KV("type", "string"),
schemas.KV("description", "Final answer"),
)),
)
// Version B: description before type (different structural order)
propsB := schemas.NewOrderedMapFromPairs(
schemas.KV("reasoning", schemas.NewOrderedMapFromPairs(
schemas.KV("description", "Step by step"),
schemas.KV("type", "string"),
)),
schemas.KV("answer", schemas.NewOrderedMapFromPairs(
schemas.KV("description", "Final answer"),
schemas.KV("type", "string"),
)),
)
// Azure delegates OpenAI models to openai.ToOpenAIChatRequest()
ctx, cancel := schemas.NewBifrostContextWithCancel(nil)
defer cancel()
resultA := openai.ToOpenAIChatRequest(ctx, makeReq(propsA))
resultB := openai.ToOpenAIChatRequest(ctx, makeReq(propsB))
jsonA, err := schemas.Marshal(resultA.ChatParameters.Tools[0].Function.Parameters)
if err != nil {
t.Fatalf("failed to marshal params A: %v", err)
}
jsonB, err := schemas.Marshal(resultB.ChatParameters.Tools[0].Function.Parameters)
if err != nil {
t.Fatalf("failed to marshal params B: %v", err)
}
// Caching: byte-identical JSON
if string(jsonA) != string(jsonB) {
t.Errorf("caching broken via Azure→OpenAI path: same schema produced different JSON\nA: %s\nB: %s", jsonA, jsonB)
}
// CoT: property order preserved
keys := resultA.ChatParameters.Tools[0].Function.Parameters.Properties.Keys()
if len(keys) != 2 || keys[0] != "reasoning" || keys[1] != "answer" {
t.Errorf("expected property order [reasoning, answer], got %v", keys)
}
}
// TestAzure_OpenAIModel_PreservesPropertyOrder verifies that the Azure→OpenAI
// delegation path preserves user-defined property ordering.
func TestAzure_OpenAIModel_PreservesPropertyOrder(t *testing.T) {
bifrostReq := &schemas.BifrostChatRequest{
Provider: schemas.Azure,
Model: "gpt-4o",
Input: []schemas.ChatMessage{{Role: schemas.ChatMessageRoleUser}},
Params: &schemas.ChatParameters{
Tools: []schemas.ChatTool{{
Type: schemas.ChatToolTypeFunction,
Function: &schemas.ChatToolFunction{
Name: "AnswerResponseModel",
Parameters: &schemas.ToolFunctionParameters{
Type: "object",
Properties: schemas.NewOrderedMapFromPairs(
schemas.KV("chain_of_thought", schemas.NewOrderedMapFromPairs(schemas.KV("type", "string"))),
schemas.KV("answer", schemas.NewOrderedMapFromPairs(schemas.KV("type", "string"))),
schemas.KV("citations", schemas.NewOrderedMapFromPairs(schemas.KV("type", "array"))),
),
},
},
}},
},
}
ctx, cancel := schemas.NewBifrostContextWithCancel(nil)
defer cancel()
result := openai.ToOpenAIChatRequest(ctx, bifrostReq)
keys := result.ChatParameters.Tools[0].Function.Parameters.Properties.Keys()
if len(keys) != 3 || keys[0] != "chain_of_thought" || keys[1] != "answer" || keys[2] != "citations" {
t.Errorf("expected property order [chain_of_thought, answer, citations], got %v", keys)
}
}
// TestAzure_ToolInputKeyOrderPreservation verifies that tool call arguments
// preserve their original key ordering through the Azure→OpenAI delegation path.
// TestAzure_ToolInputKeyOrderPreservation verifies that Azure→OpenAI delegation
// preserves the original key ordering of tool call arguments for prompt caching.
// Tests multiple parallel tool calls with different key orderings per block.
func TestAzure_ToolInputKeyOrderPreservation(t *testing.T) {
bifrostReq := &schemas.BifrostChatRequest{
Provider: schemas.Azure,
Model: "gpt-4o",
Input: []schemas.ChatMessage{
{
Role: schemas.ChatMessageRoleUser,
Content: &schemas.ChatMessageContent{ContentStr: schemas.Ptr("test")},
},
{
Role: schemas.ChatMessageRoleAssistant,
ChatAssistantMessage: &schemas.ChatAssistantMessage{
ToolCalls: []schemas.ChatAssistantMessageToolCall{
{
Index: 0,
Type: schemas.Ptr("function"),
ID: schemas.Ptr("toolu_001"),
Function: schemas.ChatAssistantMessageToolCallFunction{
Name: schemas.Ptr("bash"),
Arguments: `{"description":"Find references quickly","timeout":30000,"command":"grep -r auth_injector ."}`,
},
},
{
Index: 1,
Type: schemas.Ptr("function"),
ID: schemas.Ptr("toolu_002"),
Function: schemas.ChatAssistantMessageToolCallFunction{
Name: schemas.Ptr("bash"),
Arguments: `{"command":"git diff main...HEAD --stat","description":"Show diff"}`,
},
},
},
},
},
},
}
ctx, cancel := schemas.NewBifrostContextWithCancel(nil)
defer cancel()
result := openai.ToOpenAIChatRequest(ctx, bifrostReq)
if result == nil {
t.Fatal("expected non-nil result")
}
// Collect tool call arguments from assistant message
var argsList []string
for _, msg := range result.Messages {
if msg.OpenAIChatAssistantMessage != nil {
for _, tc := range msg.OpenAIChatAssistantMessage.ToolCalls {
argsList = append(argsList, tc.Function.Arguments)
}
}
}
if len(argsList) != 2 {
t.Fatalf("expected 2 tool call arguments, got %d", len(argsList))
}
// OpenAI path passes Arguments through as strings — verify key order is preserved
// Block 0: keys should be description, timeout, command
s0 := argsList[0]
if !(strings.Index(s0, "description") < strings.Index(s0, "timeout") &&
strings.Index(s0, "timeout") < strings.Index(s0, "command")) {
t.Errorf("block 0: key order not preserved, expected description < timeout < command in: %s", s0)
}
// Block 1: keys should be command, description
s1 := argsList[1]
if !(strings.Index(s1, "command") < strings.Index(s1, "description")) {
t.Errorf("block 1: key order not preserved, expected command < description in: %s", s1)
}
}