From ba3e3a774756b47ddcebe5a03ae91f91697bdc8a Mon Sep 17 00:00:00 2001 From: MVS-source <72023257+MVS-source@users.noreply.github.com> Date: Fri, 3 Jul 2026 17:21:30 +0200 Subject: [PATCH] feat(providers): add Eden AI as an OpenAI-compatible provider Eden AI (https://www.edenai.co/) is a European, OpenAI-compatible gateway to 100+ models behind a single key. The provider delegates to the OpenAI implementation (same pattern as opencode/openrouter), pointing at Eden's /v3 base URL. Supports chat completions (+ streaming), the Responses API (delegated), and list models. - core/providers/edenai: new provider package (+ unit and gated live tests) - register EdenAI in schemas (ModelProvider enum + StandardProviders) and the provider factory in core/bifrost.go - transports: add edenai to the config JSON schema - docs: supported-providers/edenai page, overview row, nav entry --- core/bifrost.go | 3 + core/providers/edenai/edenai.go | 389 ++++++++++++++++++ core/providers/edenai/edenai_live_test.go | 52 +++ core/providers/edenai/edenai_test.go | 43 ++ core/schemas/bifrost.go | 2 + docs/docs.json | 1 + docs/providers/supported-providers/edenai.mdx | 85 ++++ .../supported-providers/overview.mdx | 1 + transports/config.schema.json | 6 +- 9 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 core/providers/edenai/edenai.go create mode 100644 core/providers/edenai/edenai_live_test.go create mode 100644 core/providers/edenai/edenai_test.go create mode 100644 docs/providers/supported-providers/edenai.mdx diff --git a/core/bifrost.go b/core/bifrost.go index c733816c674..0138d1e2905 100644 --- a/core/bifrost.go +++ b/core/bifrost.go @@ -26,6 +26,7 @@ import ( "github.com/maximhq/bifrost/core/providers/bedrock" "github.com/maximhq/bifrost/core/providers/cerebras" "github.com/maximhq/bifrost/core/providers/cohere" + "github.com/maximhq/bifrost/core/providers/edenai" "github.com/maximhq/bifrost/core/providers/elevenlabs" "github.com/maximhq/bifrost/core/providers/fireworks" "github.com/maximhq/bifrost/core/providers/gemini" @@ -4056,6 +4057,8 @@ func (bifrost *Bifrost) createBaseProvider(providerKey schemas.ModelProvider, co return runware.NewRunwareProvider(config, bifrost.logger) case schemas.Fireworks: return fireworks.NewFireworksProvider(config, bifrost.logger) + case schemas.EdenAI: + return edenai.NewEdenAIProvider(config, bifrost.logger) default: return nil, fmt.Errorf("unsupported provider: %s", targetProviderKey) } diff --git a/core/providers/edenai/edenai.go b/core/providers/edenai/edenai.go new file mode 100644 index 00000000000..32b650d7723 --- /dev/null +++ b/core/providers/edenai/edenai.go @@ -0,0 +1,389 @@ +// Package edenai implements the Eden AI provider. +// Eden AI (https://www.edenai.co/) is a European, OpenAI-compatible gateway to +// 100+ models from many providers behind a single key. Bifrost delegates to the +// OpenAI implementation, differing only in the default base URL and provider key. +package edenai + +import ( + "context" + "strings" + "time" + + "github.com/maximhq/bifrost/core/providers/openai" + providerUtils "github.com/maximhq/bifrost/core/providers/utils" + schemas "github.com/maximhq/bifrost/core/schemas" + "github.com/valyala/fasthttp" +) + +// edenaiProvider implements the Provider interface for the Eden AI gateway. +type edenaiProvider struct { + logger schemas.Logger + client *fasthttp.Client + streamingClient *fasthttp.Client + networkConfig schemas.NetworkConfig + sendBackRawRequest bool + sendBackRawResponse bool +} + +// NewEdenAIProvider creates a new Eden AI provider instance. +// Eden exposes an OpenAI-compatible API at https://api.edenai.run/v3. +func NewEdenAIProvider(config *schemas.ProviderConfig, logger schemas.Logger) (*edenaiProvider, error) { + config.CheckAndSetDefaults() + + requestTimeout := time.Second * time.Duration(config.NetworkConfig.DefaultRequestTimeoutInSeconds) + client := &fasthttp.Client{ + ReadTimeout: requestTimeout, + WriteTimeout: requestTimeout, + MaxConnsPerHost: config.NetworkConfig.MaxConnsPerHost, + MaxIdleConnDuration: 30 * time.Second, + MaxConnWaitTimeout: requestTimeout, + MaxConnDuration: time.Second * time.Duration(schemas.DefaultMaxConnDurationInSeconds), + ConnPoolStrategy: fasthttp.FIFO, + } + + client = providerUtils.ConfigureProxy(client, config.ProxyConfig, logger) + client = providerUtils.ConfigureDialer(client, config.NetworkConfig.AllowPrivateNetwork) + client = providerUtils.ConfigureTLS(client, config.NetworkConfig, logger) + streamingClient := providerUtils.BuildStreamingClient(client) + + // Set default BaseURL if not provided + if config.NetworkConfig.BaseURL == "" { + config.NetworkConfig.BaseURL = "https://api.edenai.run/v3" + } + config.NetworkConfig.BaseURL = strings.TrimRight(config.NetworkConfig.BaseURL, "/") + + return &edenaiProvider{ + logger: logger, + client: client, + streamingClient: streamingClient, + networkConfig: config.NetworkConfig, + sendBackRawRequest: config.SendBackRawRequest, + sendBackRawResponse: config.SendBackRawResponse, + }, nil +} + +// GetProviderKey returns the provider identifier for Eden AI. +func (p *edenaiProvider) GetProviderKey() schemas.ModelProvider { + return schemas.EdenAI +} + +// ListModels performs a list models request to the Eden AI API. +func (p *edenaiProvider) ListModels(ctx *schemas.BifrostContext, keys []schemas.Key, request *schemas.BifrostListModelsRequest) (*schemas.BifrostListModelsResponse, *schemas.BifrostError) { + return openai.HandleOpenAIListModelsRequest( + ctx, + p.client, + request, + p.networkConfig.BaseURL+providerUtils.GetPathFromContext(ctx, "/models"), + keys, + p.networkConfig.ExtraHeaders, + p.GetProviderKey(), + providerUtils.ShouldSendBackRawRequest(ctx, p.sendBackRawRequest), + providerUtils.ShouldSendBackRawResponse(ctx, p.sendBackRawResponse), + ) +} + +// TextCompletion is not supported by Eden AI. +func (p *edenaiProvider) TextCompletion(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostTextCompletionRequest) (*schemas.BifrostTextCompletionResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.TextCompletionRequest, p.GetProviderKey()) +} + +// TextCompletionStream is not supported by Eden AI. +func (p *edenaiProvider) TextCompletionStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, postHookSpanFinalizer func(context.Context), key schemas.Key, request *schemas.BifrostTextCompletionRequest) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.TextCompletionStreamRequest, p.GetProviderKey()) +} + +// ChatCompletion performs a chat completion request to the Eden AI API. +func (p *edenaiProvider) ChatCompletion(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostChatRequest) (*schemas.BifrostChatResponse, *schemas.BifrostError) { + return openai.HandleOpenAIChatCompletionRequest( + ctx, + p.client, + p.networkConfig.BaseURL+providerUtils.GetPathFromContext(ctx, "/chat/completions"), + request, + key, + p.networkConfig.ExtraHeaders, + providerUtils.ShouldSendBackRawRequest(ctx, p.sendBackRawRequest), + providerUtils.ShouldSendBackRawResponse(ctx, p.sendBackRawResponse), + p.GetProviderKey(), + nil, + nil, + p.logger, + ) +} + +// ChatCompletionStream performs a streaming chat completion request to the Eden AI API. +func (p *edenaiProvider) ChatCompletionStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, postHookSpanFinalizer func(context.Context), key schemas.Key, request *schemas.BifrostChatRequest) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) { + var authHeader map[string]string + if v := key.Value.GetValue(); v != "" { + authHeader = map[string]string{"Authorization": "Bearer " + v} + } + return openai.HandleOpenAIChatCompletionStreaming( + ctx, + p.streamingClient, + p.networkConfig.BaseURL+providerUtils.GetPathFromContext(ctx, "/chat/completions"), + request, + authHeader, + p.networkConfig.ExtraHeaders, + p.networkConfig.StreamIdleTimeoutInSeconds, + providerUtils.ShouldSendBackRawRequest(ctx, p.sendBackRawRequest), + providerUtils.ShouldSendBackRawResponse(ctx, p.sendBackRawResponse), + p.GetProviderKey(), + postHookRunner, + nil, + nil, + nil, + nil, + nil, + p.logger, + postHookSpanFinalizer, + ) +} + +// Responses performs a responses request to the Eden AI API (delegated to chat completions). +func (p *edenaiProvider) Responses(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostResponsesRequest) (*schemas.BifrostResponsesResponse, *schemas.BifrostError) { + chatResponse, err := p.ChatCompletion(ctx, key, request.ToChatRequest()) + if err != nil { + return nil, err + } + return chatResponse.ToBifrostResponsesResponse(), nil +} + +// ResponsesStream performs a streaming responses request to the Eden AI API. +func (p *edenaiProvider) ResponsesStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, postHookSpanFinalizer func(context.Context), key schemas.Key, request *schemas.BifrostResponsesRequest) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) { + ctx.SetValue(schemas.BifrostContextKeyIsResponsesToChatCompletionFallback, true) + return p.ChatCompletionStream(ctx, postHookRunner, postHookSpanFinalizer, key, request.ToChatRequest()) +} + +// Embedding is not supported by the Eden AI provider (yet). +func (p *edenaiProvider) Embedding(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostEmbeddingRequest) (*schemas.BifrostEmbeddingResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.EmbeddingRequest, p.GetProviderKey()) +} + +// Rerank is not supported by Eden AI. +func (p *edenaiProvider) Rerank(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostRerankRequest) (*schemas.BifrostRerankResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.RerankRequest, p.GetProviderKey()) +} + +// OCR is not supported by Eden AI. +func (p *edenaiProvider) OCR(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostOCRRequest) (*schemas.BifrostOCRResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.OCRRequest, p.GetProviderKey()) +} + +// Speech is not supported by Eden AI. +func (p *edenaiProvider) Speech(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostSpeechRequest) (*schemas.BifrostSpeechResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.SpeechRequest, p.GetProviderKey()) +} + +// SpeechStream is not supported by Eden AI. +func (p *edenaiProvider) SpeechStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, postHookSpanFinalizer func(context.Context), key schemas.Key, request *schemas.BifrostSpeechRequest) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.SpeechStreamRequest, p.GetProviderKey()) +} + +// Transcription is not supported by Eden AI. +func (p *edenaiProvider) Transcription(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostTranscriptionRequest) (*schemas.BifrostTranscriptionResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.TranscriptionRequest, p.GetProviderKey()) +} + +// TranscriptionStream is not supported by Eden AI. +func (p *edenaiProvider) TranscriptionStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, postHookSpanFinalizer func(context.Context), key schemas.Key, request *schemas.BifrostTranscriptionRequest) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.TranscriptionStreamRequest, p.GetProviderKey()) +} + +// ImageGeneration is not supported by Eden AI. +func (p *edenaiProvider) ImageGeneration(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostImageGenerationRequest) (*schemas.BifrostImageGenerationResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ImageGenerationRequest, p.GetProviderKey()) +} + +// ImageGenerationStream is not supported by Eden AI. +func (p *edenaiProvider) ImageGenerationStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, postHookSpanFinalizer func(context.Context), key schemas.Key, request *schemas.BifrostImageGenerationRequest) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ImageGenerationStreamRequest, p.GetProviderKey()) +} + +// ImageEdit is not supported by Eden AI. +func (p *edenaiProvider) ImageEdit(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostImageEditRequest) (*schemas.BifrostImageGenerationResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ImageEditRequest, p.GetProviderKey()) +} + +// ImageEditStream is not supported by Eden AI. +func (p *edenaiProvider) ImageEditStream(ctx *schemas.BifrostContext, postHookRunner schemas.PostHookRunner, postHookSpanFinalizer func(context.Context), key schemas.Key, request *schemas.BifrostImageEditRequest) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ImageEditStreamRequest, p.GetProviderKey()) +} + +// ImageVariation is not supported by Eden AI. +func (p *edenaiProvider) ImageVariation(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostImageVariationRequest) (*schemas.BifrostImageGenerationResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ImageVariationRequest, p.GetProviderKey()) +} + +// VideoGeneration is not supported by Eden AI. +func (p *edenaiProvider) VideoGeneration(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostVideoGenerationRequest) (*schemas.BifrostVideoGenerationResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.VideoGenerationRequest, p.GetProviderKey()) +} + +// VideoRetrieve is not supported by Eden AI. +func (p *edenaiProvider) VideoRetrieve(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostVideoRetrieveRequest) (*schemas.BifrostVideoGenerationResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.VideoRetrieveRequest, p.GetProviderKey()) +} + +// VideoDownload is not supported by Eden AI. +func (p *edenaiProvider) VideoDownload(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostVideoDownloadRequest) (*schemas.BifrostVideoDownloadResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.VideoDownloadRequest, p.GetProviderKey()) +} + +// VideoDelete is not supported by Eden AI. +func (p *edenaiProvider) VideoDelete(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostVideoDeleteRequest) (*schemas.BifrostVideoDeleteResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.VideoDeleteRequest, p.GetProviderKey()) +} + +// VideoList is not supported by Eden AI. +func (p *edenaiProvider) VideoList(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostVideoListRequest) (*schemas.BifrostVideoListResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.VideoListRequest, p.GetProviderKey()) +} + +// VideoRemix is not supported by Eden AI. +func (p *edenaiProvider) VideoRemix(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostVideoRemixRequest) (*schemas.BifrostVideoGenerationResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.VideoRemixRequest, p.GetProviderKey()) +} + +// BatchCreate is not supported by Eden AI. +func (p *edenaiProvider) BatchCreate(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostBatchCreateRequest) (*schemas.BifrostBatchCreateResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.BatchCreateRequest, p.GetProviderKey()) +} + +// BatchList is not supported by Eden AI. +func (p *edenaiProvider) BatchList(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostBatchListRequest) (*schemas.BifrostBatchListResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.BatchListRequest, p.GetProviderKey()) +} + +// BatchRetrieve is not supported by Eden AI. +func (p *edenaiProvider) BatchRetrieve(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostBatchRetrieveRequest) (*schemas.BifrostBatchRetrieveResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.BatchRetrieveRequest, p.GetProviderKey()) +} + +// BatchCancel is not supported by Eden AI. +func (p *edenaiProvider) BatchCancel(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostBatchCancelRequest) (*schemas.BifrostBatchCancelResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.BatchCancelRequest, p.GetProviderKey()) +} + +// BatchDelete is not supported by Eden AI. +func (p *edenaiProvider) BatchDelete(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostBatchDeleteRequest) (*schemas.BifrostBatchDeleteResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.BatchDeleteRequest, p.GetProviderKey()) +} + +// BatchResults is not supported by Eden AI. +func (p *edenaiProvider) BatchResults(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostBatchResultsRequest) (*schemas.BifrostBatchResultsResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.BatchResultsRequest, p.GetProviderKey()) +} + +// FileUpload is not supported by Eden AI. +func (p *edenaiProvider) FileUpload(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostFileUploadRequest) (*schemas.BifrostFileUploadResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.FileUploadRequest, p.GetProviderKey()) +} + +// FileList is not supported by Eden AI. +func (p *edenaiProvider) FileList(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostFileListRequest) (*schemas.BifrostFileListResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.FileListRequest, p.GetProviderKey()) +} + +// FileRetrieve is not supported by Eden AI. +func (p *edenaiProvider) FileRetrieve(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostFileRetrieveRequest) (*schemas.BifrostFileRetrieveResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.FileRetrieveRequest, p.GetProviderKey()) +} + +// FileDelete is not supported by Eden AI. +func (p *edenaiProvider) FileDelete(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostFileDeleteRequest) (*schemas.BifrostFileDeleteResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.FileDeleteRequest, p.GetProviderKey()) +} + +// FileContent is not supported by Eden AI. +func (p *edenaiProvider) FileContent(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostFileContentRequest) (*schemas.BifrostFileContentResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.FileContentRequest, p.GetProviderKey()) +} + +// CountTokens is not supported by Eden AI. +func (p *edenaiProvider) CountTokens(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostResponsesRequest) (*schemas.BifrostCountTokensResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.CountTokensRequest, p.GetProviderKey()) +} + +// Compaction is not supported by Eden AI. +func (p *edenaiProvider) Compaction(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostCompactionRequest) (*schemas.BifrostCompactionResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.CompactionRequest, p.GetProviderKey()) +} + +// ContainerCreate is not supported by Eden AI. +func (p *edenaiProvider) ContainerCreate(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostContainerCreateRequest) (*schemas.BifrostContainerCreateResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ContainerCreateRequest, p.GetProviderKey()) +} + +// ContainerList is not supported by Eden AI. +func (p *edenaiProvider) ContainerList(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostContainerListRequest) (*schemas.BifrostContainerListResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ContainerListRequest, p.GetProviderKey()) +} + +// ContainerRetrieve is not supported by Eden AI. +func (p *edenaiProvider) ContainerRetrieve(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostContainerRetrieveRequest) (*schemas.BifrostContainerRetrieveResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ContainerRetrieveRequest, p.GetProviderKey()) +} + +// ContainerDelete is not supported by Eden AI. +func (p *edenaiProvider) ContainerDelete(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostContainerDeleteRequest) (*schemas.BifrostContainerDeleteResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ContainerDeleteRequest, p.GetProviderKey()) +} + +// ContainerFileCreate is not supported by Eden AI. +func (p *edenaiProvider) ContainerFileCreate(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostContainerFileCreateRequest) (*schemas.BifrostContainerFileCreateResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ContainerFileCreateRequest, p.GetProviderKey()) +} + +// ContainerFileList is not supported by Eden AI. +func (p *edenaiProvider) ContainerFileList(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostContainerFileListRequest) (*schemas.BifrostContainerFileListResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ContainerFileListRequest, p.GetProviderKey()) +} + +// ContainerFileRetrieve is not supported by Eden AI. +func (p *edenaiProvider) ContainerFileRetrieve(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostContainerFileRetrieveRequest) (*schemas.BifrostContainerFileRetrieveResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ContainerFileRetrieveRequest, p.GetProviderKey()) +} + +// ContainerFileContent is not supported by Eden AI. +func (p *edenaiProvider) ContainerFileContent(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostContainerFileContentRequest) (*schemas.BifrostContainerFileContentResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ContainerFileContentRequest, p.GetProviderKey()) +} + +// ContainerFileDelete is not supported by Eden AI. +func (p *edenaiProvider) ContainerFileDelete(_ *schemas.BifrostContext, _ []schemas.Key, _ *schemas.BifrostContainerFileDeleteRequest) (*schemas.BifrostContainerFileDeleteResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.ContainerFileDeleteRequest, p.GetProviderKey()) +} + +// CachedContentCreate is not supported by Eden AI. +func (p *edenaiProvider) CachedContentCreate(ctx *schemas.BifrostContext, key schemas.Key, request *schemas.BifrostCachedContentCreateRequest) (*schemas.BifrostCachedContentCreateResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.CachedContentCreateRequest, p.GetProviderKey()) +} + +// CachedContentList is not supported by Eden AI. +func (p *edenaiProvider) CachedContentList(ctx *schemas.BifrostContext, keys []schemas.Key, request *schemas.BifrostCachedContentListRequest) (*schemas.BifrostCachedContentListResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.CachedContentListRequest, p.GetProviderKey()) +} + +// CachedContentRetrieve is not supported by Eden AI. +func (p *edenaiProvider) CachedContentRetrieve(ctx *schemas.BifrostContext, keys []schemas.Key, request *schemas.BifrostCachedContentRetrieveRequest) (*schemas.BifrostCachedContentRetrieveResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.CachedContentRetrieveRequest, p.GetProviderKey()) +} + +// CachedContentUpdate is not supported by Eden AI. +func (p *edenaiProvider) CachedContentUpdate(ctx *schemas.BifrostContext, keys []schemas.Key, request *schemas.BifrostCachedContentUpdateRequest) (*schemas.BifrostCachedContentUpdateResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.CachedContentUpdateRequest, p.GetProviderKey()) +} + +// CachedContentDelete is not supported by Eden AI. +func (p *edenaiProvider) CachedContentDelete(ctx *schemas.BifrostContext, keys []schemas.Key, request *schemas.BifrostCachedContentDeleteRequest) (*schemas.BifrostCachedContentDeleteResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.CachedContentDeleteRequest, p.GetProviderKey()) +} + +// Passthrough is not supported by Eden AI. +func (p *edenaiProvider) Passthrough(_ *schemas.BifrostContext, _ schemas.Key, _ *schemas.BifrostPassthroughRequest) (*schemas.BifrostPassthroughResponse, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.PassthroughRequest, p.GetProviderKey()) +} + +// PassthroughStream is not supported by Eden AI. +func (p *edenaiProvider) PassthroughStream(_ *schemas.BifrostContext, _ schemas.PostHookRunner, _ func(context.Context), _ schemas.Key, _ *schemas.BifrostPassthroughRequest) (chan *schemas.BifrostStreamChunk, *schemas.BifrostError) { + return nil, providerUtils.NewUnsupportedOperationError(schemas.PassthroughStreamRequest, p.GetProviderKey()) +} diff --git a/core/providers/edenai/edenai_live_test.go b/core/providers/edenai/edenai_live_test.go new file mode 100644 index 00000000000..96a3df09f78 --- /dev/null +++ b/core/providers/edenai/edenai_live_test.go @@ -0,0 +1,52 @@ +package edenai_test + +import ( + "context" + "os" + "testing" + + bifrost "github.com/maximhq/bifrost/core" + "github.com/maximhq/bifrost/core/providers/edenai" + "github.com/maximhq/bifrost/core/schemas" +) + +// TestEdenAILiveChatCompletion performs a real chat completion against the Eden AI +// API through the Bifrost provider. It is skipped unless EDENAI_API_KEY is set, +// so CI stays hermetic. +func TestEdenAILiveChatCompletion(t *testing.T) { + apiKey := os.Getenv("EDENAI_API_KEY") + if apiKey == "" { + t.Skip("EDENAI_API_KEY not set; skipping live Eden AI test") + } + + config := &schemas.ProviderConfig{} + config.CheckAndSetDefaults() + provider, err := edenai.NewEdenAIProvider(config, bifrost.NewNoOpLogger()) + if err != nil { + t.Fatalf("NewEdenAIProvider failed: %v", err) + } + + ctx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline) + key := schemas.Key{Value: *schemas.NewSecretVar(apiKey), Models: schemas.WhiteList{"*"}} + content := "Reply with exactly: BIFROST-EDEN-OK" + request := &schemas.BifrostChatRequest{ + Provider: schemas.EdenAI, + Model: "openai/gpt-4o-mini", + Input: []schemas.ChatMessage{ + {Role: schemas.ChatMessageRoleUser, Content: &schemas.ChatMessageContent{ContentStr: &content}}, + }, + } + + resp, bifErr := provider.ChatCompletion(ctx, key, request) + if bifErr != nil { + msg := "" + if bifErr.Error != nil { + msg = bifErr.Error.Message + } + t.Fatalf("live ChatCompletion returned error: %s", msg) + } + if resp == nil || len(resp.Choices) == 0 { + t.Fatalf("expected at least one choice in the response, got %+v", resp) + } + t.Logf("Eden AI live chat completion succeeded via Bifrost provider (%d choice(s))", len(resp.Choices)) +} diff --git a/core/providers/edenai/edenai_test.go b/core/providers/edenai/edenai_test.go new file mode 100644 index 00000000000..230e727b08d --- /dev/null +++ b/core/providers/edenai/edenai_test.go @@ -0,0 +1,43 @@ +package edenai + +import ( + "testing" + + "github.com/maximhq/bifrost/core/schemas" +) + +// Compile-time check that edenaiProvider satisfies the full Provider interface. +var _ schemas.Provider = (*edenaiProvider)(nil) + +func TestEdenAIProviderConstructorDefaults(t *testing.T) { + t.Parallel() + + config := &schemas.ProviderConfig{} + config.CheckAndSetDefaults() + provider, err := NewEdenAIProvider(config, nil) + if err != nil { + t.Fatalf("NewEdenAIProvider failed: %v", err) + } + if provider.GetProviderKey() != schemas.EdenAI { + t.Errorf("expected provider key %s, got %s", schemas.EdenAI, provider.GetProviderKey()) + } + if provider.networkConfig.BaseURL != "https://api.edenai.run/v3" { + t.Errorf("expected base URL https://api.edenai.run/v3, got %s", provider.networkConfig.BaseURL) + } +} + +func TestEdenAIUnsupportedOperations(t *testing.T) { + t.Parallel() + + p := &edenaiProvider{} + + if _, err := p.TextCompletion(nil, schemas.Key{}, nil); err == nil { + t.Error("expected TextCompletion to be unsupported") + } + if _, err := p.Embedding(nil, schemas.Key{}, nil); err == nil { + t.Error("expected Embedding to be unsupported") + } + if _, err := p.Speech(nil, schemas.Key{}, nil); err == nil { + t.Error("expected Speech to be unsupported") + } +} diff --git a/core/schemas/bifrost.go b/core/schemas/bifrost.go index b1448456bfb..066dbf53d5c 100644 --- a/core/schemas/bifrost.go +++ b/core/schemas/bifrost.go @@ -67,6 +67,7 @@ const ( Runway ModelProvider = "runway" Runware ModelProvider = "runware" Fireworks ModelProvider = "fireworks" + EdenAI ModelProvider = "edenai" ) // SupportedBaseProviders is the list of base providers allowed for custom providers. @@ -108,6 +109,7 @@ var StandardProviders = []ModelProvider{ Runway, Runware, Fireworks, + EdenAI, } // RequestType represents the type of request being made to a provider. diff --git a/docs/docs.json b/docs/docs.json index e25bca88241..0de0df1acd3 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -136,6 +136,7 @@ "providers/supported-providers/cerebras", "providers/supported-providers/cohere", "providers/supported-providers/databricks", + "providers/supported-providers/edenai", "providers/supported-providers/elevenlabs", "providers/supported-providers/fireworks", "providers/supported-providers/gemini", diff --git a/docs/providers/supported-providers/edenai.mdx b/docs/providers/supported-providers/edenai.mdx new file mode 100644 index 00000000000..a18ee82d163 --- /dev/null +++ b/docs/providers/supported-providers/edenai.mdx @@ -0,0 +1,85 @@ +--- +title: "Eden AI" +description: "Eden AI integration guide - a European, OpenAI-compatible gateway to 100+ models with a single key." +icon: "globe" +--- + +## Overview + +[Eden AI](https://www.edenai.co/) is a **European, OpenAI-compatible** gateway that provides access to 100+ models from many providers (Mistral, OpenAI, Anthropic, Google, Cohere, DeepSeek, and more) through a single unified API and one key. Bifrost delegates to the OpenAI implementation, pointing at Eden's endpoint (`https://api.edenai.run/v3`). Key points: + +- **One key, many providers** — route to models from many vendors through a single `EDENAI_API_KEY`. +- **EU-based gateway** — requests are served through an Europe-based gateway with GDPR-aligned data handling, useful for data-residency requirements. +- **OpenAI-compatible** — chat completions, streaming (SSE), tool calling, and `reasoning_effort` are handled through the OpenAI-compatible surface. +- **Model naming** — models keep the underlying `provider/model` form, e.g. `mistral/mistral-small-latest`, `openai/gpt-4o-mini`, `anthropic/claude-sonnet-4-5`. + +### Supported Operations + +| Operation | Non-Streaming | Streaming | Endpoint | +|-----------|---------------|-----------|----------| +| Chat Completions | ✅ | ✅ | `/chat/completions` | +| Responses API | ✅ | ✅ | (delegated to Chat Completions) | +| List Models | ✅ | - | `/models` | +| Text Completions | ❌ | ❌ | - | +| Embeddings | ❌ | ❌ | - | +| Image Generation | ❌ | ❌ | - | +| Speech (TTS) | ❌ | ❌ | - | +| Transcriptions (STT) | ❌ | ❌ | - | + + +Eden AI exposes its API under the `/v3` base path (`https://api.edenai.run/v3`), so the chat completions endpoint is `https://api.edenai.run/v3/chat/completions`. Errors are returned in the standard OpenAI error envelope. + + +## Setup & Configuration + +Configure Eden AI as a provider. + + + + +1. Navigate to **Models** > **Model Providers**. If **Eden AI** is not listed under **Configured Providers**, click **Add New Provider** and select **Eden AI**. +2. Click **Add Key** or edit an existing key. +3. Set a name for your key. +4. Paste your API key directly or use an environment variable (for example, `env.EDENAI_API_KEY`). +5. Set **Allowed Models** to **All Models** (default) or a specific allowlist. +6. Save the provider configuration. + + + + +```json +{ + "providers": { + "edenai": { + "keys": [ + { + "name": "edenai-key-1", + "value": "env.EDENAI_API_KEY", + "models": [ + "*" + ], + "weight": 1.0 + } + ] + } + } +} +``` + +The default base URL is `https://api.edenai.run/v3`. You can override it via the provider's `network_config.base_url` if needed. + + + + +## Usage + +```bash +curl -X POST http://localhost:8080/v1/chat/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "edenai/mistral/mistral-small-latest", + "messages": [{"role": "user", "content": "Hello from a sovereign EU stack!"}] + }' +``` + +Get an API key from your [Eden AI account](https://www.edenai.co/) and see the [Eden AI documentation](https://docs.edenai.co/) for the full list of available models. diff --git a/docs/providers/supported-providers/overview.mdx b/docs/providers/supported-providers/overview.mdx index 6d8cd586c68..8f261fcabe0 100644 --- a/docs/providers/supported-providers/overview.mdx +++ b/docs/providers/supported-providers/overview.mdx @@ -31,6 +31,7 @@ The following table summarizes which operations are supported by each provider v | Ollama (`ollama/`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | OpenAI (`openai/`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | | OpenRouter (`openrouter/`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | +| Eden AI (`edenai/`) | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Parasail (`parasail/`) | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Perplexity (`perplexity/`) | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Replicate (`replicate/`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | diff --git a/transports/config.schema.json b/transports/config.schema.json index 8d455db97d5..a9e7d5d527e 100644 --- a/transports/config.schema.json +++ b/transports/config.schema.json @@ -335,6 +335,9 @@ "openrouter": { "$ref": "#/$defs/provider" }, + "edenai": { + "$ref": "#/$defs/provider" + }, "sgl": { "$ref": "#/$defs/provider_with_sgl_config" }, @@ -5459,7 +5462,8 @@ "vllm", "runway", "runware", - "fireworks" + "fireworks", + "edenai" ], "description": "Base provider type to extend" },