Skip to content

Add Eden AI provider - #1187

Merged
njbrake merged 2 commits into
mozilla-ai:mainfrom
MVS-source:provider/edenai
Jul 17, 2026
Merged

njbrake merged 2 commits into
mozilla-ai:mainfrom
MVS-source:provider/edenai

Conversation

@MVS-source

@MVS-source MVS-source commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor

Description

This adds Eden AI as a provider.

Eden AI is an EU-based, OpenAI-compatible gateway. One API key reaches models from many providers (OpenAI, Anthropic, Google, Mistral, Cohere and more), with model ids like "openai/gpt-4o-mini", and it offers EU data residency, zero data retention, a DPA and SOC 2 / ISO 27001.

Implementation follows the OpenRouter provider pattern:

  • New provider package src/any_llm/providers/edenai/ with EdenaiProvider(BaseOpenAIProvider), a fixed API_BASE (https://api.edenai.run/v3), and a small models-list converter (Eden AI's /v3/models omits object/owned_by/created that the OpenAI Model schema requires; extras like model_name and context_length are preserved).
  • LLMProvider.EDENAI enum entry, the edenai extra in pyproject (empty, no new dependency), and conftest model maps.
  • Unit tests in tests/unit/providers/test_edenai_provider.py.

Reasoning and the Responses API are marked unsupported: Eden AI's OpenAI-compatible endpoint inlines reasoning in the message content rather than in a separate field, and does not expose the Responses API.

Verified live against the real Eden AI API: completion, streaming, embeddings, list_models, response_format and moderation all pass. ruff, ruff-format and mypy are clean and the new unit tests pass. (I ran the edenai-relevant unit and integration tests locally; the full suite runs in CI with all extras.)

PR Type

  • New Feature

Relevant issues

Fixes #1186

Checklist

  • I understand the code I am submitting.
  • I have added unit tests that prove my fix/feature works
  • I have run this code locally and verified it fixes the issue.
  • New and existing tests pass locally
  • Documentation was updated where necessary
  • I have read and followed the contribution guidelines
  • AI Usage:
    • No AI was used.
    • AI was used for drafting/refactoring.
    • This is fully AI-generated.

AI Usage Information

  • AI Model used: Claude Opus 4.8

  • AI Developer Tool used: Claude Code

  • Any other info you'd like to share: Implemented and verified live against the real Eden AI API by an Eden AI team member using Claude Code. We will maintain the provider.

  • I am an AI Agent filling out this form (check box if true)

Summary by CodeRabbit

  • New Features
    • Added Eden AI as a supported provider, including completions (with streaming), embeddings, moderation, and model listing.
    • Added an Eden AI provider extra to the project’s optional dependencies.
  • Tests
    • Added unit test coverage for Eden AI provider configuration, API key validation, parameter remapping, model conversion (including edge cases and round-trip serialisation), and model listing.

Add Eden AI (an EU-based, OpenAI-compatible gateway) as a provider by
subclassing BaseOpenAIProvider with a fixed base URL. Include a models
list converter (Eden AI's /v3/models omits fields the OpenAI Model
schema requires), the enum entry, the pyproject extra, conftest model
maps and a unit test. Verified live against the real API: completion,
streaming, embeddings, list_models, response_format and moderation.
@coderabbitai

coderabbitai Bot commented Jul 17, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Changes

Eden AI provider

Layer / File(s) Summary
Provider registration and packaging
pyproject.toml, src/any_llm/constants.py
Registers edenai as a provider and optional dependency extra.
Provider implementation and model conversion
src/any_llm/providers/edenai/*
Adds EdenaiProvider, capability configuration, public export, and Eden AI model-list conversion.
Provider and integration validation
tests/unit/providers/test_edenai_provider.py, tests/conftest.py, tests/integration/test_moderation.py
Tests configuration, parameter mapping, model conversion, serialisation, listing, and integration mappings.

Possibly related issues

  • mozilla-ai/any-llm#1186: Directly covers the Eden AI provider integration implemented by this PR.

Possibly related PRs

Suggested labels: 1.21.0

Suggested reviewers: tbille

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main change: adding an Eden AI provider.
Description check ✅ Passed The description follows the template with all required sections filled, including type, issue reference, checklist and AI usage details.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Note that Eden AI exposes /v3/responses but any-llm's OpenResponses shape is
unverified against it, so Responses stays unsupported for now. Correct the
models-list docstring: created is the field reliably absent, object/owned_by
may be present.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@njbrake
njbrake temporarily deployed to integration-tests July 17, 2026 19:21 — with GitHub Actions Inactive

@njbrake njbrake left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this review was drafted by Claude via back-and-forth with @njbrake. The reasoning and decisions are his; the prose is Claude's.

Approving. Eden AI is a genuine EU-based, OpenAI-compatible gateway; I verified the base URL (https://api.edenai.run/v3), the provider/model id format, and the /v3/chat/completions, /v3/models, /v3/embeddings and /v3/moderations endpoints against Eden AI's official docs rather than the PR description. The implementation follows the OpenRouter pattern closely, mypy and ruff are clean locally, and the unit tests pass. CodeRabbit found nothing actionable.

Two small clarifications were pushed on top:

  • SUPPORTS_RESPONSES stays False, now with a comment: Eden AI does expose /v3/responses, but any-llm's OpenResponses shape has not been verified against it, so it is left unsupported for now rather than claimed to work.
  • The models-conversion docstring was corrected: created is the field reliably absent; object/owned_by may be present. The converter already handled all cases defensively.

Thanks for the clean, well-tested contribution.

@codecov

codecov Bot commented Jul 17, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.23810% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/any_llm/providers/edenai/utils.py 88.23% 0 Missing and 2 partials ⚠️
Files with missing lines Coverage Δ
src/any_llm/constants.py 100.00% <100.00%> (ø)
src/any_llm/providers/edenai/__init__.py 100.00% <100.00%> (ø)
src/any_llm/providers/edenai/edenai.py 100.00% <100.00%> (ø)
src/any_llm/providers/edenai/utils.py 88.23% <88.23%> (ø)

... and 38 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/any_llm/providers/edenai/utils.py (1)

23-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use getattr for fallback and handle standard dictionaries.

Using getattr(response, "data", response) is a more idiomatic Python approach than using a conditional hasattr check. As per coding guidelines, getattr is the preferred approach for truly dynamic attributes (since response is typed as Any).

Additionally, if the supplied model happens to be a dictionary, calling vars(model) will raise a TypeError. It would be safer to explicitly handle dictionaries before falling back to vars().

♻️ Proposed refactor
-    raw_models = response.data if hasattr(response, "data") else response
+    raw_models = getattr(response, "data", response)
     result: list[Model] = []
     for model in raw_models:
-        data: dict[str, Any] = model.model_dump() if hasattr(model, "model_dump") else dict(vars(model))
+        data: dict[str, Any] = (
+            model.model_dump() if hasattr(model, "model_dump")
+            else dict(model) if isinstance(model, dict)
+            else dict(vars(model))
+        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/any_llm/providers/edenai/utils.py` around lines 23 - 26, Update the
response extraction in the surrounding model-conversion function to use
getattr(response, "data", response) instead of a hasattr conditional. In the
model loop, handle dictionary instances directly as the data mapping before
falling back to model_dump() or vars(model), preserving the existing Model
conversion behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/any_llm/providers/edenai/utils.py`:
- Around line 23-26: Update the response extraction in the surrounding
model-conversion function to use getattr(response, "data", response) instead of
a hasattr conditional. In the model loop, handle dictionary instances directly
as the data mapping before falling back to model_dump() or vars(model),
preserving the existing Model conversion behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0363beab-d3b5-4316-b8a4-77bba0f206fa

📥 Commits

Reviewing files that changed from the base of the PR and between 531b0c7 and 47f8f67.

📒 Files selected for processing (2)
  • src/any_llm/providers/edenai/edenai.py
  • src/any_llm/providers/edenai/utils.py

@njbrake
njbrake merged commit ae258fd into mozilla-ai:main Jul 17, 2026
14 checks passed
@github-actions github-actions Bot added the 1.22.0 Included in release 1.22.0 label Jul 22, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Jul 22, 2026
8 of 11 tasks

This branch was previously deployed

1 inactive deployment
integration-tests — 47f8f671 Deployed Jul 17, 2026 by njbrake via run-docs-tests #2184
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1.22.0 Included in release 1.22.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: add Eden AI as a provider

2 participants