diff --git a/transports/Dockerfile b/transports/Dockerfile index 96b0dccea6..a56d274d47 100644 --- a/transports/Dockerfile +++ b/transports/Dockerfile @@ -2,11 +2,11 @@ FROM golang:1.24-alpine AS builder WORKDIR /app -# Install dependencies in a single layer -RUN apk add --no-cache upx +# Install dependencies including gcc for CGO and sqlite +RUN apk add --no-cache upx gcc musl-dev sqlite-dev -# Set environment for static build -ENV CGO_ENABLED=0 GOOS=linux GOARCH=amd64 +# Set environment for CGO-enabled build (required for go-sqlite3) +ENV CGO_ENABLED=1 GOOS=linux # Define build-time variables ARG TRANSPORT_TYPE=http @@ -16,10 +16,11 @@ ARG TAG_VERSION=latest RUN go mod init bifrost-build && \ go get github.com/maximhq/bifrost/transports/bifrost-${TRANSPORT_TYPE}@${TAG_VERSION} -# Build the binary locally +# Build the binary with CGO enabled and static SQLite linking RUN go build \ -ldflags="-w -s -extldflags '-static'" \ -a -trimpath \ + -tags "sqlite_static" \ -o /app/main \ github.com/maximhq/bifrost/transports/bifrost-${TRANSPORT_TYPE} diff --git a/transports/bifrost-http/main.go b/transports/bifrost-http/main.go index d2703b55e6..73c2ba7bc2 100644 --- a/transports/bifrost-http/main.go +++ b/transports/bifrost-http/main.go @@ -373,7 +373,7 @@ func main() { // Apply CORS middleware to all routes corsHandler := corsMiddleware(r.Handler) - log.Printf("Starting server on port %s", port) + log.Printf("Successfully started bifrost. Serving UI on http://localhost:%s", port) if err := fasthttp.ListenAndServe(":"+port, corsHandler); err != nil { log.Fatalf("Error starting server: %v", err) } diff --git a/transports/bifrost-http/plugins/logging/main.go b/transports/bifrost-http/plugins/logging/main.go index 58cfc3fc70..1587a9e313 100644 --- a/transports/bifrost-http/plugins/logging/main.go +++ b/transports/bifrost-http/plugins/logging/main.go @@ -64,7 +64,6 @@ type UpdateLogData struct { OutputMessage *schemas.BifrostMessage ToolCalls *[]schemas.ToolCall ErrorDetails *schemas.BifrostError - ExtraFields map[string]interface{} Model string // May be different from request Object string // May be different from request } @@ -85,7 +84,6 @@ type LogEntry struct { TokenUsage *schemas.LLMUsage `json:"token_usage,omitempty"` Status string `json:"status"` // "processing", "success", or "error" ErrorDetails *schemas.BifrostError `json:"error_details,omitempty"` - ExtraFields map[string]interface{} `json:"extra_fields,omitempty"` CreatedAt time.Time `json:"created_at"` } @@ -233,7 +231,6 @@ func (p *LoggerPlugin) createTables() error { tool_calls TEXT, params TEXT, error_details TEXT, - extra_fields TEXT, -- For content search content_summary TEXT, @@ -499,17 +496,6 @@ func (p *LoggerPlugin) PostHook(ctx *context.Context, result *schemas.BifrostRes updateData.ToolCalls = result.Choices[0].Message.AssistantMessage.ToolCalls } } - - // Extra fields if available - if result.ExtraFields.Provider != "" || result.ExtraFields.Params.MaxTokens != nil { - updateData.ExtraFields = map[string]interface{}{ - "provider": result.ExtraFields.Provider, - "params": result.ExtraFields.Params, - "latency": result.ExtraFields.Latency, - "billed_usage": result.ExtraFields.BilledUsage, - "raw_response": result.ExtraFields.RawResponse, - } - } } logMsg.UpdateData = updateData diff --git a/transports/bifrost-http/plugins/logging/utils.go b/transports/bifrost-http/plugins/logging/utils.go index f90207a4a6..725063f976 100644 --- a/transports/bifrost-http/plugins/logging/utils.go +++ b/transports/bifrost-http/plugins/logging/utils.go @@ -110,13 +110,6 @@ func (p *LoggerPlugin) updateLogEntry(requestID string, timestamp time.Time, dat args = append(args, string(errorDetailsJSON)) } - // Update extra fields - if data.ExtraFields != nil { - extraFieldsJSON, _ := json.Marshal(data.ExtraFields) - setParts = append(setParts, "extra_fields = ?") - args = append(args, string(extraFieldsJSON)) - } - // Add the WHERE clause parameter args = append(args, requestID) @@ -161,13 +154,13 @@ func (p *LoggerPlugin) getLogEntry(requestID string) (*LogEntry, error) { SELECT id, timestamp, provider, model, object_type, status, latency, prompt_tokens, completion_tokens, total_tokens, input_history, output_message, tools, tool_calls, - params, error_details, extra_fields, created_at + params, error_details, created_at FROM logs WHERE id = ?` var entry LogEntry var timestampUnix, createdAtUnix int64 var inputHistoryJSON, outputMessageJSON, toolsJSON, toolCallsJSON sql.NullString - var paramsJSON, errorDetailsJSON, extraFieldsJSON sql.NullString + var paramsJSON, errorDetailsJSON sql.NullString var promptTokens, completionTokens, totalTokensRow sql.NullInt64 var latency sql.NullFloat64 @@ -176,7 +169,7 @@ func (p *LoggerPlugin) getLogEntry(requestID string) (*LogEntry, error) { &entry.Object, &entry.Status, &latency, &promptTokens, &completionTokens, &totalTokensRow, &inputHistoryJSON, &outputMessageJSON, &toolsJSON, &toolCallsJSON, - ¶msJSON, &errorDetailsJSON, &extraFieldsJSON, + ¶msJSON, &errorDetailsJSON, &createdAtUnix, ) if err != nil { @@ -226,9 +219,6 @@ func (p *LoggerPlugin) getLogEntry(requestID string) (*LogEntry, error) { if errorDetailsJSON.Valid { json.Unmarshal([]byte(errorDetailsJSON.String), &entry.ErrorDetails) } - if extraFieldsJSON.Valid { - json.Unmarshal([]byte(extraFieldsJSON.String), &entry.ExtraFields) - } return &entry, nil } @@ -335,9 +325,9 @@ func (p *LoggerPlugin) SearchLogs(filters *SearchFilters, pagination *Pagination for rows.Next() { var entry LogEntry - var timestampUnix int64 + var timestampUnix sql.NullInt64 var inputHistoryJSON, outputMessageJSON, toolsJSON, toolCallsJSON sql.NullString - var paramsJSON, errorDetailsJSON, extraFieldsJSON sql.NullString + var paramsJSON, errorDetailsJSON sql.NullString var promptTokens, completionTokens, totalTokensRow sql.NullInt64 var latency sql.NullFloat64 @@ -346,14 +336,18 @@ func (p *LoggerPlugin) SearchLogs(filters *SearchFilters, pagination *Pagination &entry.Object, &entry.Status, &latency, &promptTokens, &completionTokens, &totalTokensRow, &inputHistoryJSON, &outputMessageJSON, &toolsJSON, &toolCallsJSON, - ¶msJSON, &errorDetailsJSON, &extraFieldsJSON, + ¶msJSON, &errorDetailsJSON, ) if err != nil { return nil, fmt.Errorf("failed to scan row: %w", err) } - // Convert timestamp - entry.Timestamp = time.Unix(timestampUnix/1e9, timestampUnix%1e9) // Convert from nanoseconds + // Convert timestamp (handle NULL values) + if timestampUnix.Valid { + entry.Timestamp = time.Unix(timestampUnix.Int64/1e9, timestampUnix.Int64%1e9) // Convert from nanoseconds + } else { + entry.Timestamp = time.Time{} // Set to zero time if NULL + } // Handle latency if latency.Valid { @@ -394,9 +388,6 @@ func (p *LoggerPlugin) SearchLogs(filters *SearchFilters, pagination *Pagination if errorDetailsJSON.Valid { json.Unmarshal([]byte(errorDetailsJSON.String), &entry.ErrorDetails) } - if extraFieldsJSON.Valid { - json.Unmarshal([]byte(extraFieldsJSON.String), &entry.ExtraFields) - } logs = append(logs, entry) } @@ -433,7 +424,7 @@ func (p *LoggerPlugin) buildSearchQuery(filters *SearchFilters, pagination *Pagi SELECT id, timestamp, provider, model, object_type, status, latency, prompt_tokens, completion_tokens, total_tokens, input_history, output_message, tools, tool_calls, - params, error_details, extra_fields + params, error_details FROM logs` countQuery := "SELECT COUNT(*) FROM logs" diff --git a/transports/bifrost-http/ui/404.html b/transports/bifrost-http/ui/404.html index fb4e4626b4..1d921e5b46 100644 --- a/transports/bifrost-http/ui/404.html +++ b/transports/bifrost-http/ui/404.html @@ -1,4 +1,4 @@ -