Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/internal/testutil/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type TestScenarios struct {
FileRetrieve bool // File API retrieve functionality
FileDelete bool // File API delete functionality
FileContent bool // File API content download functionality
FileBatchInput bool // Whether batch create supports file-based input (InputFileID)
}

// ComprehensiveTestConfig extends TestConfig with additional scenarios
Expand Down
8 changes: 4 additions & 4 deletions core/internal/testutil/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,10 +627,10 @@ func RunFileUnsupportedTest(t *testing.T, client *bifrost.Bifrost, ctx context.C

// RunFileAndBatchIntegrationTest tests the integration between file upload and batch create
func RunFileAndBatchIntegrationTest(t *testing.T, client *bifrost.Bifrost, ctx context.Context, testConfig ComprehensiveTestConfig) {
// Skip if either file upload or batch create is not supported
if !testConfig.Scenarios.FileUpload || !testConfig.Scenarios.BatchCreate {
t.Logf("[SKIPPED] File and Batch Integration: FileUpload=%v, BatchCreate=%v for provider %s",
testConfig.Scenarios.FileUpload, testConfig.Scenarios.BatchCreate, testConfig.Provider)
// Skip if file-based batch input is not supported
if !testConfig.Scenarios.FileBatchInput {
t.Logf("[SKIPPED] File and Batch Integration: FileBatchInput=%v for provider %s",
testConfig.Scenarios.FileBatchInput, testConfig.Provider)
return
}

Expand Down
2 changes: 1 addition & 1 deletion core/internal/testutil/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func printTestSummary(t *testing.T, testConfig ComprehensiveTestConfig) {
{"FileDelete", testConfig.Scenarios.FileDelete},
{"FileContent", testConfig.Scenarios.FileContent},
{"FileUnsupported", !testConfig.Scenarios.FileUpload && !testConfig.Scenarios.FileList && !testConfig.Scenarios.FileRetrieve && !testConfig.Scenarios.FileDelete && !testConfig.Scenarios.FileContent},
{"FileAndBatchIntegration", testConfig.Scenarios.FileUpload && testConfig.Scenarios.BatchCreate},
{"FileAndBatchIntegration", testConfig.Scenarios.FileBatchInput},
}

supported := 0
Expand Down
3 changes: 2 additions & 1 deletion core/providers/anthropic/anthropic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ func TestAnthropic(t *testing.T) {
FileList: true,
FileRetrieve: true,
FileDelete: true,
FileContent: true,
FileContent: false,
FileBatchInput: false, // Anthropic batch API only supports inline requests, not file-based input
},
}

Expand Down
1 change: 1 addition & 0 deletions core/providers/bedrock/bedrock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func TestBedrock(t *testing.T) {
FileRetrieve: true,
FileDelete: true,
FileContent: true,
FileBatchInput: true,
},
}

Expand Down
67 changes: 44 additions & 23 deletions core/providers/gemini/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,34 +64,55 @@ func buildBatchRequestItems(requests []schemas.BatchRequestItem) []GeminiBatchRe
requestData = req.Params
}

// Extract messages from the request data
// Extract messages from the request data - handle multiple possible types
// Go type assertions don't work across slice types, so we handle each case
if requestData != nil {
if msgs, ok := requestData["messages"].([]interface{}); ok {
for _, msg := range msgs {
if msgMap, ok := msg.(map[string]interface{}); ok {
role := "user"
if r, ok := msgMap["role"].(string); ok {
if r == "assistant" {
role = "model"
} else if r == "system" {
// System messages are handled separately in Gemini
continue
} else {
role = r
}
}
var messages []map[string]interface{}

parts := []*Part{}
if c, ok := msgMap["content"].(string); ok {
parts = append(parts, &Part{Text: c})
}
// Try []interface{} first (generic JSON unmarshaling)
if msgsInterface, ok := requestData["messages"].([]interface{}); ok {
for _, m := range msgsInterface {
if msgMap, ok := m.(map[string]interface{}); ok {
messages = append(messages, msgMap)
}
}
} else if msgsTyped, ok := requestData["messages"].([]map[string]interface{}); ok {
// Try []map[string]interface{} (typed maps)
messages = msgsTyped
} else if msgsString, ok := requestData["messages"].([]map[string]string); ok {
// Try []map[string]string (test case format)
for _, m := range msgsString {
msgMap := make(map[string]interface{})
for k, v := range m {
msgMap[k] = v
}
messages = append(messages, msgMap)
}
}

contents = append(contents, Content{
Role: role,
Parts: parts,
})
// Process extracted messages
for _, msgMap := range messages {
role := "user"
if r, ok := msgMap["role"].(string); ok {
if r == "assistant" {
role = "model"
} else if r == "system" {
// System messages are handled separately in Gemini
continue
} else {
role = r
}
}

parts := []*Part{}
if c, ok := msgMap["content"].(string); ok {
parts = append(parts, &Part{Text: c})
}

contents = append(contents, Content{
Role: role,
Parts: parts,
})
}
}

Expand Down
3 changes: 2 additions & 1 deletion core/providers/gemini/gemini_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ func TestGemini(t *testing.T) {
FileList: true,
FileRetrieve: true,
FileDelete: true,
FileContent: true,
FileContent: false,
FileBatchInput: true,
},
}

Expand Down
1 change: 1 addition & 0 deletions core/providers/openai/openai_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func TestOpenAI(t *testing.T) {
FileRetrieve: true,
FileDelete: true,
FileContent: true,
FileBatchInput: true,
},
}

Expand Down