diff --git a/README.md b/README.md index 4447b524a3..27a5e76b46 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,7 @@ curl -X POST http://localhost:8080/providers \ curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "Hello from Bifrost! 🌈"} ] diff --git a/docs/mcp.md b/docs/mcp.md index a285f68856..33262f1625 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -33,8 +33,7 @@ Bifrost's Model Context Protocol integration enables AI models to seamlessly dis curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "List the files in the /tmp directory"} ] diff --git a/docs/quickstart/http-transport.md b/docs/quickstart/http-transport.md index 6c296af59e..a1a51c5acc 100644 --- a/docs/quickstart/http-transport.md +++ b/docs/quickstart/http-transport.md @@ -132,8 +132,7 @@ docker run -p 8080:8080 maximhq/bifrost curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello, Bifrost!"}] }' ``` @@ -242,12 +241,12 @@ export ANTHROPIC_API_KEY="your-anthropic-key" # Use OpenAI curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ - -d '{"provider": "openai", "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello from OpenAI!"}]}' + -d '{"model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello from OpenAI!"}]}' # Use Anthropic curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ - -d '{"provider": "anthropic", "model": "claude-3-sonnet-20240229", "messages": [{"role": "user", "content": "Hello from Anthropic!"}]}' + -d '{"model": "anthropic/claude-3-sonnet-20240229", "messages": [{"role": "user", "content": "Hello from Anthropic!"}]}' ``` ### **🔄 Add Automatic Fallbacks** @@ -257,10 +256,9 @@ curl -X POST http://localhost:8080/v1/chat/completions \ curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello!"}], - "fallbacks": [{"provider": "anthropic", "model": "claude-3-sonnet-20240229"}] + "fallbacks": ["anthropic/claude-3-sonnet-20240229"] }' ``` @@ -276,8 +274,7 @@ import requests response = requests.post( "http://localhost:8080/v1/chat/completions", json={ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello from Python!"}] } ) @@ -291,8 +288,7 @@ const response = await fetch("http://localhost:8080/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - provider: "openai", - model: "gpt-4o-mini", + model: "openai/gpt-4o-mini", messages: [{ role: "user", content: "Hello from Node.js!" }], }), }); @@ -306,8 +302,7 @@ response, err := http.Post( "http://localhost:8080/v1/chat/completions", "application/json", strings.NewReader(`{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello from Go!"}] }`) ) diff --git a/docs/usage/errors.md b/docs/usage/errors.md index f4d025228f..efe3d4be93 100644 --- a/docs/usage/errors.md +++ b/docs/usage/errors.md @@ -221,8 +221,7 @@ client = BifrostClient("http://localhost:8080") try: response = client.chat_completion({ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello!"}] }) print("Success:", response) diff --git a/docs/usage/http-transport/README.md b/docs/usage/http-transport/README.md index ce10f8a9dc..72b1e4fbba 100644 --- a/docs/usage/http-transport/README.md +++ b/docs/usage/http-transport/README.md @@ -28,7 +28,7 @@ open http://localhost:8080 # Make requests to any provider curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ - -d '{"provider": "openai", "model": "gpt-4o-mini", "messages": [...]}' + -d '{"model": "openai/gpt-4o-mini", "messages": [...]}' ``` --- @@ -171,10 +171,9 @@ const response = await openai.chat.completions.create({ curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello!"}], - "fallbacks": [{"provider": "anthropic", "model": "claude-3-sonnet-20240229"}] + "fallbacks": ["anthropic/claude-3-sonnet-20240229"] }' # OpenAI-compatible endpoint diff --git a/docs/usage/http-transport/configuration/mcp.md b/docs/usage/http-transport/configuration/mcp.md index dda606ca5e..b289e6fa4e 100644 --- a/docs/usage/http-transport/configuration/mcp.md +++ b/docs/usage/http-transport/configuration/mcp.md @@ -209,8 +209,7 @@ Tools are automatically available in chat completions: curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "List the files in the current directory"} ] @@ -269,8 +268,7 @@ When MCP is configured, Bifrost automatically adds available tools to requests. curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "Can you list the files in the /tmp directory?"} ] @@ -337,8 +335,7 @@ curl -X POST http://localhost:8080/v1/mcp/tool/execute \ curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "Can you list the files in the /tmp directory?"}, { @@ -394,8 +391,7 @@ Control which MCP tools are available per request using context: curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "List files and search web"} ], @@ -407,8 +403,7 @@ curl -X POST http://localhost:8080/v1/chat/completions \ curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "Help me with file operations"} ], @@ -479,8 +474,7 @@ bifrost-http -config config.json -port 8080 -plugins maxim curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "What files are in this directory?"} ] @@ -563,8 +557,7 @@ docker logs bifrost-container | grep MCP curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ { "role": "user", diff --git a/docs/usage/http-transport/configuration/providers.md b/docs/usage/http-transport/configuration/providers.md index c75fa79891..129125ce0a 100644 --- a/docs/usage/http-transport/configuration/providers.md +++ b/docs/usage/http-transport/configuration/providers.md @@ -497,8 +497,7 @@ docker run -p 8080:8080 \ curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Test message"}] }' @@ -506,11 +505,10 @@ curl -X POST http://localhost:8080/v1/chat/completions \ curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Test message"}], "fallbacks": [ - {"provider": "anthropic", "model": "claude-3-sonnet-20240229"} + "anthropic/claude-3-sonnet-20240229" ] }' ``` diff --git a/docs/usage/http-transport/endpoints.md b/docs/usage/http-transport/endpoints.md index b776425a1c..2d1ae5c3f3 100644 --- a/docs/usage/http-transport/endpoints.md +++ b/docs/usage/http-transport/endpoints.md @@ -31,8 +31,7 @@ Chat conversation endpoint supporting all providers. ```json { - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ { "role": "user", @@ -43,12 +42,7 @@ Chat conversation endpoint supporting all providers. "temperature": 0.7, "max_tokens": 1000 }, - "fallbacks": [ - { - "provider": "anthropic", - "model": "claude-3-sonnet-20240229" - } - ] + "fallbacks": ["anthropic/claude-3-sonnet-20240229"] } ``` @@ -83,8 +77,7 @@ Chat conversation endpoint supporting all providers. curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "What is the capital of France?"} ] @@ -99,8 +92,7 @@ Text completion endpoint for simple text generation. ```json { - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "text": "The future of AI is", "params": { "temperature": 0.8, @@ -254,12 +246,11 @@ bifrost_provider_errors_total{provider="openai",error_type="rate_limit"} 23 ### **Common Parameters** -| Parameter | Type | Description | Example | -| ----------- | ------ | ----------------------- | ----------------------------- | -| `provider` | string | AI provider to use | `"openai"` | -| `model` | string | Model name | `"gpt-4o-mini"` | -| `params` | object | Model parameters | `{"temperature": 0.7}` | -| `fallbacks` | array | Fallback configurations | `[{"provider": "anthropic"}]` | +| Parameter | Type | Description | Example | +| ----------- | ------ | ----------------------- | ---------------------------------------- | +| `model` | string | Provider and model name | `"openai/gpt-4o-mini"` | +| `params` | object | Model parameters | `{"temperature": 0.7}` | +| `fallbacks` | array | Fallback model names | `["anthropic/claude-3-sonnet-20240229"]` | ### **Model Parameters** @@ -315,8 +306,7 @@ MCP tools are automatically available in chat completions: curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "List files in the current directory"} ] @@ -354,8 +344,7 @@ curl -X POST http://localhost:8080/v1/chat/completions \ # Initial request curl -X POST http://localhost:8080/v1/chat/completions \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [ {"role": "user", "content": "Read the README.md file"}, { diff --git a/docs/usage/http-transport/openapi.json b/docs/usage/http-transport/openapi.json index 82b848d31a..d1979c10b5 100644 --- a/docs/usage/http-transport/openapi.json +++ b/docs/usage/http-transport/openapi.json @@ -37,8 +37,7 @@ "simple_chat": { "summary": "Simple chat message", "value": { - "provider": "openai", - "model": "gpt-4o", + "model": "openai/gpt-4o", "messages": [ { "role": "user", @@ -50,8 +49,7 @@ "tool_calling": { "summary": "Chat with tool calling", "value": { - "provider": "openai", - "model": "gpt-4o", + "model": "openai/gpt-4o", "messages": [ { "role": "user", @@ -90,8 +88,7 @@ "with_fallbacks": { "summary": "Chat with fallback providers", "value": { - "provider": "openai", - "model": "gpt-4o", + "model": "openai/gpt-4o", "messages": [ { "role": "user", @@ -113,8 +110,7 @@ "structured_content": { "summary": "Chat with structured content (text and image)", "value": { - "provider": "openai", - "model": "gpt-4o", + "model": "openai/gpt-4o", "messages": [ { "role": "user", @@ -258,8 +254,7 @@ "simple_text": { "summary": "Simple text completion", "value": { - "provider": "openai", - "model": "gpt-3.5-turbo-instruct", + "model": "openai/gpt-3.5-turbo-instruct", "text": "The future of artificial intelligence is", "params": { "max_tokens": 100, @@ -452,15 +447,12 @@ "schemas": { "ChatCompletionRequest": { "type": "object", - "required": ["provider", "model", "messages"], + "required": ["model", "messages"], "properties": { - "provider": { - "$ref": "#/components/schemas/ModelProvider" - }, "model": { "type": "string", - "description": "Model identifier (provider-specific)", - "example": "gpt-4o" + "description": "Model identifier in 'provider/model' format (e.g., 'openai/gpt-4o-mini', 'anthropic/claude-3-sonnet-20240229')", + "example": "openai/gpt-4o-mini" }, "messages": { "type": "array", @@ -476,23 +468,21 @@ "fallbacks": { "type": "array", "items": { - "$ref": "#/components/schemas/Fallback" + "type": "string" }, - "description": "Fallback providers and models" + "description": "Fallback model names in 'provider/model' format", + "example": ["anthropic/claude-3-sonnet-20240229", "openai/gpt-4o"] } } }, "TextCompletionRequest": { "type": "object", - "required": ["provider", "model", "text"], + "required": ["model", "text"], "properties": { - "provider": { - "$ref": "#/components/schemas/ModelProvider" - }, "model": { "type": "string", - "description": "Model identifier (provider-specific)", - "example": "gpt-3.5-turbo-instruct" + "description": "Model identifier in 'provider/model' format (e.g., 'openai/gpt-3.5-turbo-instruct', 'anthropic/claude-3-haiku-20240307')", + "example": "openai/gpt-3.5-turbo-instruct" }, "text": { "type": "string", @@ -505,9 +495,13 @@ "fallbacks": { "type": "array", "items": { - "$ref": "#/components/schemas/Fallback" + "type": "string" }, - "description": "Fallback providers and models" + "description": "Fallback model names in 'provider/model' format", + "example": [ + "anthropic/claude-3-haiku-20240307", + "openai/gpt-4o-mini" + ] } } }, diff --git a/docs/usage/providers.md b/docs/usage/providers.md index 5716d3be3c..55559315bf 100644 --- a/docs/usage/providers.md +++ b/docs/usage/providers.md @@ -134,8 +134,7 @@ export OPENAI_API_KEY=your_openai_api_key curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello from OpenAI!"}] }' ``` @@ -280,8 +279,7 @@ func useWithFallback(bf *bifrost.Bifrost) { response=$(curl -s -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello!"}] }') diff --git a/transports/README.md b/transports/README.md index c4660607d8..dbc4c560b6 100644 --- a/transports/README.md +++ b/transports/README.md @@ -70,8 +70,7 @@ docker run -p 8080:8080 -v $(pwd)/data:/app/data maximhq/bifrost curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello!"}] }' ``` @@ -99,8 +98,7 @@ response = client.chat.completions.create( curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ - "provider": "openai", - "model": "gpt-4o-mini", + "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello!"}], "fallbacks": [ {"provider": "anthropic", "model": "claude-3-5-sonnet-20241022"}, @@ -210,7 +208,7 @@ Enable AI models to use external tools like filesystem operations, web search, a ```bash # AI automatically uses configured tools curl -X POST http://localhost:8080/v1/chat/completions \ - -d '{"provider": "openai", "model": "gpt-4o-mini", + -d '{"model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "List files in /tmp"}]}' ``` diff --git a/transports/bifrost-http/handlers/completions.go b/transports/bifrost-http/handlers/completions.go index bd6fa7c514..532a04fc85 100644 --- a/transports/bifrost-http/handlers/completions.go +++ b/transports/bifrost-http/handlers/completions.go @@ -5,6 +5,7 @@ package handlers import ( "encoding/json" "fmt" + "strings" "github.com/fasthttp/router" bifrost "github.com/maximhq/bifrost/core" @@ -29,12 +30,11 @@ func NewCompletionHandler(client *bifrost.Bifrost, logger schemas.Logger) *Compl // CompletionRequest represents a request for either text or chat completion type CompletionRequest struct { - Provider schemas.ModelProvider `json:"provider"` // The AI model provider to use + Model string `json:"model"` // Model to use in "provider/model" format Messages []schemas.BifrostMessage `json:"messages"` // Chat messages (for chat completion) Text string `json:"text"` // Text input (for text completion) - Model string `json:"model"` // Model to use Params *schemas.ModelParameters `json:"params"` // Additional model parameters - Fallbacks []schemas.Fallback `json:"fallbacks"` // Fallback providers and models + Fallbacks []string `json:"fallbacks"` // Fallback providers and models in "provider/model" format } type CompletionType string @@ -70,23 +70,39 @@ func (h *CompletionHandler) handleCompletion(ctx *fasthttp.RequestCtx, completio return } - // Validate required fields - if req.Provider == "" { - SendError(ctx, fasthttp.StatusBadRequest, "Provider is required", h.logger) + if req.Model == "" { + SendError(ctx, fasthttp.StatusBadRequest, "Model is required", h.logger) return } - if req.Model == "" { - SendError(ctx, fasthttp.StatusBadRequest, "Model is required", h.logger) + model := strings.Split(req.Model, "/") + if len(model) != 2 { + SendError(ctx, fasthttp.StatusBadRequest, "Model must be in the format of 'provider/model'", h.logger) return } + provider := model[0] + modelName := model[1] + + fallbacks := make([]schemas.Fallback, len(req.Fallbacks)) + for i, fallback := range req.Fallbacks { + fallbackModel := strings.Split(fallback, "/") + if len(fallbackModel) != 2 { + SendError(ctx, fasthttp.StatusBadRequest, "Fallback must be in the format of 'provider/model'", h.logger) + return + } + fallbacks[i] = schemas.Fallback{ + Provider: schemas.ModelProvider(fallbackModel[0]), + Model: fallbackModel[1], + } + } + // Create BifrostRequest bifrostReq := &schemas.BifrostRequest{ - Provider: req.Provider, - Model: req.Model, + Model: modelName, + Provider: schemas.ModelProvider(provider), Params: req.Params, - Fallbacks: req.Fallbacks, + Fallbacks: fallbacks, } // Validate and set input based on completion type diff --git a/transports/bifrost-http/plugins/logging/utils.go b/transports/bifrost-http/plugins/logging/utils.go index 2e7db2805d..f91ba778da 100644 --- a/transports/bifrost-http/plugins/logging/utils.go +++ b/transports/bifrost-http/plugins/logging/utils.go @@ -329,6 +329,7 @@ func (p *LoggerPlugin) searchByTimeRange(txn *badger.Txn, startTime, endTime *ti return nil }); err != nil { // Log error but continue processing + p.logger.Debug(fmt.Sprintf("error getting log entry by ID: %v", err)) } } } @@ -492,7 +493,8 @@ func (p *LoggerPlugin) searchByLatencyRange(txn *badger.Txn, minLatency, maxLate idMap[string(val)] = true return nil }); err != nil { - // Log error but continue + // Log error but continue processing + p.logger.Debug(fmt.Sprintf("error getting log entry by ID: %v", err)) } } } @@ -542,7 +544,8 @@ func (p *LoggerPlugin) searchByTokenRange(txn *badger.Txn, minTokens, maxTokens idMap[string(val)] = true return nil }); err != nil { - // Log error but continue + // Log error but continue processing + p.logger.Debug(fmt.Sprintf("error getting log entry by ID: %v", err)) } } } diff --git a/transports/go.sum b/transports/go.sum index 3c39a74e4e..d1b1ec871d 100644 --- a/transports/go.sum +++ b/transports/go.sum @@ -87,6 +87,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mark3labs/mcp-go v0.32.0 h1:fgwmbfL2gbd67obg57OfV2Dnrhs1HtSdlY/i5fn7MU8= github.com/mark3labs/mcp-go v0.32.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= +github.com/maximhq/bifrost/core v1.1.6 h1:rZrfPVcAfNggfBaOTdu/w+xNwDhW79bfexXsw8LRoMQ= +github.com/maximhq/bifrost/core v1.1.6/go.mod h1:yMRCncTgKYBIrECSRVxMbY3BL8CjLbipJlc644jryxc= github.com/maximhq/bifrost/plugins/maxim v1.0.6 h1:m1tWjbmxW9Lz4mDhXclQhZdFt/TrRPbZwFcoWY9ZAEk= github.com/maximhq/bifrost/plugins/maxim v1.0.6/go.mod h1:+D/E498VB4JNTEzG4fYyFJf9WQaq/9FgYrmzl49mLNc= github.com/maximhq/maxim-go v0.1.3 h1:nVzdz3hEjZVxmWHARWIM+Yrn1Jp50qrsK4BA/sz2jj8=