[Platform] Add support for Eden AI gateway - #2417
Conversation
18398f3 to
d329111
Compare
d329111 to
1ab4bb1
Compare
wachterjohannes
left a comment
There was a problem hiding this comment.
Structurally this holds up: scaffolding, deptrac, splitsh and the bundle wiring all match the sibling bridges, and the two things that looked like omissions (no base_url in the bundle config, two catalogs) are what the siblings do. Details inline.
- Record and replay is the direction we want to take bridges, so that a converter is pinned against the provider's real shapes rather than hand-written fixtures. This bridge is the strongest case for it so far, eight converters at once, and you already ran every example against the live API, so
examples/runner --record edenaiwould come almost for free.ExamplesReplayTestiterates over the cassettes, so without one the bridge stays silently uncovered.
On scope I am deliberately not deciding: a gateway with eight expert-feature families and its own result types is a maintenance call, so I would like @chr-hertel to weigh in before this moves.
Verified locally, all green.
1a8d8a8 to
0e34b28
Compare
0e34b28 to
c03dd4c
Compare
|
@welcoMattic i rebased this and adopted the async job capabilities from #2408 - somehow still not all example run on my side? can you please give it a final test before we bring it in? |
c03dd4c to
c39816a
Compare
Eden AI is an AI gateway exposing hundreds of models from many providers behind a
single API, using `provider/model` identifiers.
The bridge covers both halves of the v3 API:
* the OpenAI-compatible endpoints, `/v3/chat/completions` and `/v3/embeddings`,
reusing the Generic bridge for chat (including streaming and tool calling) and
embeddings;
* the expert models of the `/v3/universal-ai` endpoints: OCR, document parsing
(invoices, resumes, identity documents), text-to-speech, speech-to-text, image
analysis (object detection, explicit content, logo detection, face detection,
AI detection, deepfake detection) and image generation.
Expert models take their input either as a direct file URL, as a file ID, or as
`Audio`, `Document` and `Image` content, which is transparently uploaded through
`/v3/upload` first. Options that are not root-level request fields are forwarded
inside the `input` object.
Speech-to-text runs on `/v3/universal-ai/async`, which answers either with the
transcription already in the body or with a job still running. The second case
yields a `JobResult` whose handle is resolved through `EdenAiJobClient`, the
bridge's `Job\JobClientInterface` implementation, so nothing blocks inside
`invoke()`: how long to wait for a job - through `JobRunner`, from a worker that
picked the handle up from storage, or not at all when a `webhook_receiver` is
given - is the caller's decision. `GET /v3/universal-ai/async/{job_id}` is the
only documented way to reach a finished job, and `success`, `fail` and
`processing` the only documented states, both per
https://api.edenai.run/v3/docs/openapi.json.
Two catalogs are provided. `ModelCatalog` curates a static subset and accepts extra
entries through `$additionalModels`. `ModelApiCatalog` discovers everything the
gateway currently serves - 1083 models against the 65 curated ones - from the public
`/v3/models`, `/v3/embeddings/models` and `/v3/info` endpoints; expert subfeatures
the bridge has no converter for stay hidden, so an unsupported model fails at lookup
instead of at conversion time. Capabilities are derived from the metadata
`/v3/models` exposes per entry: `supports_response_schema` maps to
`OUTPUT_STRUCTURED`, `supports_function_calling` to `TOOL_CALLING`, and the
`input_modalities` to the matching `INPUT_*` cases.
Errors get a dedicated `ErrorHandlingTrait` because Eden AI is a FastAPI application
and reports failures through `detail`, in shapes the shared
`Result\HttpStatusErrorHandlingTrait` cannot read - so an unmapped status used to
surface as a misleading "Response does not contain ..." message. All the shapes below
were captured from the live API, including a 422 body that differs from what the
published OpenAPI schema documents, and a 403 that nothing mapped at all:
403 {"detail": "Not authenticated"}
401 {"detail": "Invalid token"}
404 {"detail": {"error": "Provider not found", "message": "..."}}
400 {"detail": {"error": "Invalid provider format", "message": "..."}}
422 {"detail": "Validation error", "errors": [{"field": "language", ...}]}
A missing required option now reports `Validation error: language: Field required`
rather than `Response does not contain audio_resource_url.`.
Image generation returns every generated image instead of only the first: since
`num_images` accepts up to 10 and each one is billed, several are exposed as a
`MultiPartResult`, mirroring the OpenAI image bridge. The gateway `cost` and
`provider` - which vary per request once `fallbacks` is used - are exposed as result
metadata on the binary and text results too, not only on the object ones. The
text-to-speech download, the asynchronous job decoding and the file upload all map
their own failures onto platform exceptions rather than leaking HttpClient ones, and
an unusable binary input is rejected before it can be uploaded empty and billed.
The synthesized audio is reported with its real format: the CDN serving it answers
`binary/octet-stream` whatever `audio_format` was requested, so the extension Eden AI
puts in the resource URL decides, which was verified against the audio magic bytes for
mp3 and wav.
Endpoints, payload keys, the upload contract and every output shape were checked
against the live API and against the published OpenAPI schema, and the thirteen
examples were all run against it. Note that
the `output_schema` that `GET /v3/info` advertises for `image/generation` describes
a single item without the enclosing `items` list the endpoint really returns, which
is documented in the converter so the discrepancy does not read as a bug.
The bridge documentation lives in `docs/components/platform/edenai.rst`, and the thirteen
examples are recorded as replay cassettes under `examples/tests/fixtures/edenai/`, so every
converter stays covered offline through `ExamplesReplayTest`, without any credentials.
c39816a to
fa6db02
Compare
|
@chr-hertel I've fixed the branch and re-run examples scripts against the real Eden AI API. |
|
Thank you @welcoMattic. |
Eden AI is an AI gateway exposing hundreds of models from many
providers behind a single API, using
provider/modelidentifiers. This adds asymfony/ai-eden-ai-platformbridge covering both halves of its v3 API.OpenAI-compatible endpoints
Chat completions (
/v3/chat/completions, including streaming and tool calling) andembeddings (
/v3/embeddings) reuse the Generic bridge:Expert models
The
/v3/universal-aiendpoints expose non-LLM features, addressed asfeature/subfeature/provider[/model]: OCR, document parsing (invoices, resumes, identitydocuments), text-to-speech, speech-to-text, image analysis (object detection, explicit
content) and image generation.
Expert models accept their input as a direct file URL, as a file ID, or as
Audio,DocumentandImagecontent, which is transparently uploaded through/v3/uploadbeforehand. Speech-to-text runs on
/v3/universal-ai/async, whose job is polled until itreaches a terminal state. Options that are not root-level request fields (
fallbacks,provider_params,show_original_response,webhook_receiver,user_webhook_parameters) are forwarded inside theinputobject, so per-featureparameters like
language,document_typeorvoiceare passed as invocation options.Notes
The catalog ships a curated subset of the available models; any other one can be
registered through the
$additionalModelsconstructor argument. Capabilities are derivedfrom the metadata
/v3/modelsexposes per entry:supports_response_schemamaps toOUTPUT_STRUCTURED,supports_function_callingtoTOOL_CALLING, and theinput_modalitiesto the matchingINPUT_*cases.Gateways like Eden AI answer authentication failures with
{"detail": "..."}rather thanan OpenAI-style error payload. The Generic completions converter already threw an
AuthenticationExceptionon those, it just could not find the reason in that shape andfell back to its generic
Authentication failed.message. It now reads both shapes, sothe gateway's own wording reaches the exception.
Endpoints, payload keys, the upload contract and every output shape were checked against
the live API, and the thirteen examples under
examples/edenai/were all run against itand recorded as replay cassettes under
examples/tests/fixtures/edenai/, so every converteris covered offline by
ExamplesReplayTest.One discrepancy is worth flagging for future readers: the
output_schemaadvertised byGET /v3/infoforimage/generationdescribes a single item without the enclosingitemslist the endpoint really returns, which the converter documents.Bridge documentation is in
docs/components/platform/edenai.rst, and 115 tests cover the modelcatalog, the contract normalizers, both model clients and every result converter.
cc @Guikingone