Skip to content

feat(core): add Eden AI as a built-in model provider - #1386

Open
MVS-source wants to merge 1 commit into
VoltAgent:mainfrom
MVS-source:feat/edenai-provider
Open

feat(core): add Eden AI as a built-in model provider#1386
MVS-source wants to merge 1 commit into
VoltAgent:mainfrom
MVS-source:feat/edenai-provider

Conversation

@MVS-source

@MVS-source MVS-source commented Jul 21, 2026

Copy link
Copy Markdown

What

Adds Eden AI as a built-in model provider.

Eden AI is an EU-based, OpenAI-compatible LLM gateway (single API key, one endpoint, many upstream vendors). Because it speaks the OpenAI-compatible protocol, it slots into the existing EXTRA_PROVIDER_REGISTRY and is wired through the shared @ai-sdk/openai-compatible adapter, exactly like the MiniMax entries. No new adapter code is required.

Usage

const agent = new Agent({
  name: "Eden AI Assistant",
  instructions: "You are a helpful assistant powered by Eden AI.",
  model: "edenai/openai/gpt-4o-mini",
});

Eden AI model ids are vendor-prefixed, so the full router id is edenai/<vendor>/<model>, for example:

  • edenai/openai/gpt-4o-mini
  • edenai/anthropic/claude-haiku-4-5
  • edenai/mistral/mistral-small-latest

The provider reads EDENAI_API_KEY and defaults to https://api.edenai.run/v3. Set EDENAI_BASE_URL=https://api.eu.edenai.run/v3 for EU data residency. The registry splits on the first slash, so the edenai segment is the provider and the remaining <vendor>/<model> is passed straight through to Eden AI.

Changes

  • packages/core/src/registries/model-provider-registry.ts: one EXTRA_PROVIDER_REGISTRY entry (id: "edenai", @ai-sdk/openai-compatible, api: https://api.edenai.run/v3, env: ["EDENAI_API_KEY"]).
  • packages/core/src/registries/model-provider-registry-edenai.spec.ts: unit tests mirroring the MiniMax spec (provider is registered, resolves through @ai-sdk/openai-compatible with the right base URL and API key, keeps the vendor-prefixed model id after the provider segment, honors EDENAI_BASE_URL, throws when the key is missing).
  • examples/with-edenai/: runnable example mirroring examples/with-openrouter.
  • .changeset/edenai-provider.md: patch changeset for @voltagent/core.

Testing

  • Unit: the new spec and the existing MiniMax spec both pass (vitest run on the registry specs, 13 tests).
  • Live: verified end to end against the real Eden AI API with a real key, reproducing the registry adapter path (createOpenAICompatible({ name: "edenai", baseURL: "https://api.edenai.run/v3", apiKey })) and generateText from ai@6. Three upstream vendors returned completions: openai/gpt-4o-mini, anthropic/claude-haiku-4-5, mistral/mistral-small-latest.
  • Lint/format: biome check clean; example typechecks with tsc --noEmit.

Summary by cubic

Add Eden AI as a built-in model provider via the @ai-sdk/openai-compatible adapter, enabling models addressed as edenai/<vendor>/<model> with EU endpoint support. Includes a runnable example and unit tests; no new adapter code.

  • New Features
    • Register edenai in EXTRA_PROVIDER_REGISTRY with API https://api.edenai.run/v3; reads EDENAI_API_KEY and supports EDENAI_BASE_URL.
    • Preserve vendor-prefixed ids after edenai/ (e.g. edenai/openai/gpt-4o-mini).
    • Add examples/with-edenai and a spec verifying registration, base URL override, and missing-key errors.

Written for commit 18aae4d. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added built-in Eden AI model provider support.
    • Use vendor-prefixed model IDs such as edenai/openai/gpt-4o-mini.
    • Configure access with EDENAI_API_KEY; optional EU routing is supported through EDENAI_BASE_URL.
    • Added a complete Eden AI example application with memory, logging, and server integration.
  • Documentation

    • Added setup instructions, configuration guidance, and usage details for Eden AI.

Eden AI is an EU-based, OpenAI-compatible LLM gateway. It is registered
as an EXTRA_PROVIDER_REGISTRY entry wired through the existing
@ai-sdk/openai-compatible adapter, exactly like MiniMax, and reached with
edenai/<vendor>/<model> ids (e.g. edenai/openai/gpt-4o-mini). The provider
reads EDENAI_API_KEY and defaults to https://api.edenai.run/v3, with
EDENAI_BASE_URL supported for the EU endpoint.

Adds a registry spec mirroring the MiniMax test and a with-edenai example.
@changeset-bot

changeset-bot Bot commented Jul 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18aae4d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Eden AI as a built-in OpenAI-compatible model provider and introduces a complete with-edenai example with environment configuration, memory, logging, Hono serving, tests, documentation, and a core patch changeset.

Changes

Eden AI provider integration

Layer / File(s) Summary
Provider registration and resolver coverage
packages/core/src/registries/model-provider-registry.ts, packages/core/src/registries/model-provider-registry-edenai.spec.ts
Registers edenai with the shared OpenAI-compatible adapter and tests vendor-prefixed model IDs, API-key validation, default configuration, and base URL overrides.
Eden AI example runtime
examples/with-edenai/src/index.ts, examples/with-edenai/package.json, examples/with-edenai/tsconfig.json, examples/with-edenai/.env.example, examples/with-edenai/.gitignore
Adds an Eden AI agent using LibSQL memory, Pino logging, Hono serving, startup API-key validation, and a text-generation demo.
Example documentation and release metadata
examples/with-edenai/README.md, .changeset/edenai-provider.md
Documents setup, model naming, endpoint configuration, and records a patch release for @voltagent/core.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant ModelProviderRegistry
  participant EdenAIAPI
  Agent->>ModelProviderRegistry: Resolve edenai/openai/gpt-4o-mini
  ModelProviderRegistry->>EdenAIAPI: Configure OpenAI-compatible provider
  Agent->>EdenAIAPI: Generate text
  EdenAIAPI-->>Agent: Return text and usage
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding Eden AI as a built-in model provider.
Description check ✅ Passed The description is detailed and covers what changed, usage, files, and testing, though some template sections are missing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
examples/with-edenai/package.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

examples/with-edenai/tsconfig.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


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.

Warning

⚠️ This pull request shows signs of AI-generated slop (trivial_assertion). It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
examples/with-edenai/.gitignore (1)

4-5: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Add .env to .gitignore to prevent credential leaks.

The README.md instructs users to create a .env file containing their EDENAI_API_KEY. When users scaffold a new app from this example template using the CLI, they will inherit this .gitignore. Omitting .env from this file creates a critical security risk where users can inadvertently commit and leak their sensitive API keys to source control.

🔒️ Proposed fix
 .DS_Store
 .voltagent/
+.env
🤖 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 `@examples/with-edenai/.gitignore` around lines 4 - 5, Add .env to the ignore
entries in the example’s .gitignore, alongside .voltagent/, so scaffolded
applications exclude environment files containing EDENAI_API_KEY from version
control.
🧹 Nitpick comments (1)
examples/with-edenai/src/index.ts (1)

37-44: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Handle potential promise rejections.

The anonymous async execution block does not handle errors. If agent.generateText fails (e.g., due to a network timeout or invalid API key), it will cause an unhandled promise rejection and abruptly crash the process. While this is an example, demonstrating robust error handling is highly recommended.

🛡️ Proposed refactor for graceful error handling
 (async () => {
-  const result = await agent.generateText("Explain how observability helps with AI cost control.");
-
-  logger.info("Eden AI example request completed", {
-    text: result.text,
-    usage: result.usage,
-  });
+  try {
+    const result = await agent.generateText("Explain how observability helps with AI cost control.");
+
+    logger.info("Eden AI example request completed", {
+      text: result.text,
+      usage: result.usage,
+    });
+  } catch (error) {
+    logger.error("Eden AI example request failed", { error });
+    process.exit(1);
+  }
 })();
🤖 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 `@examples/with-edenai/src/index.ts` around lines 37 - 44, Update the anonymous
async execution block around agent.generateText to catch promise rejections and
log the failure through logger.info or the appropriate error-level logger,
including useful error details. Preserve the existing success logging for
completed requests while ensuring failures are handled without an unhandled
promise rejection.
🤖 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.

Inline comments:
In `@examples/with-edenai/package.json`:
- Line 34: Update the package.json start script to invoke Node with
--env-file=.env before dist/index.js, matching the existing dev script’s
environment loading behavior while preserving the compiled-output startup
command.

In `@packages/core/src/registries/model-provider-registry-edenai.spec.ts`:
- Around line 7-9: Update the safeStringify mock in the test setup to remove
JSON.stringify, using String or an explicit stubbed string representation while
preserving the mock’s string-returning behavior.

---

Outside diff comments:
In `@examples/with-edenai/.gitignore`:
- Around line 4-5: Add .env to the ignore entries in the example’s .gitignore,
alongside .voltagent/, so scaffolded applications exclude environment files
containing EDENAI_API_KEY from version control.

---

Nitpick comments:
In `@examples/with-edenai/src/index.ts`:
- Around line 37-44: Update the anonymous async execution block around
agent.generateText to catch promise rejections and log the failure through
logger.info or the appropriate error-level logger, including useful error
details. Preserve the existing success logging for completed requests while
ensuring failures are handled without an unhandled promise rejection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 645bdcd7-72f3-42ce-8f5f-c29beb33f061

📥 Commits

Reviewing files that changed from the base of the PR and between 3377f6d and 18aae4d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • .changeset/edenai-provider.md
  • examples/with-edenai/.env.example
  • examples/with-edenai/.gitignore
  • examples/with-edenai/README.md
  • examples/with-edenai/package.json
  • examples/with-edenai/src/index.ts
  • examples/with-edenai/tsconfig.json
  • packages/core/src/registries/model-provider-registry-edenai.spec.ts
  • packages/core/src/registries/model-provider-registry.ts

"scripts": {
"build": "tsc",
"dev": "tsx watch --env-file=.env ./src",
"start": "node dist/index.js",

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add --env-file=.env to the start script.

To ensure the example works consistently when users follow the README instruction to test the compiled output (pnpm build && pnpm start), the start script needs to load the .env file, just like the dev script does.

🐛 Proposed fix
-    "start": "node dist/index.js",
+    "start": "node --env-file=.env dist/index.js",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"start": "node dist/index.js",
"start": "node --env-file=.env dist/index.js",
🤖 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 `@examples/with-edenai/package.json` at line 34, Update the package.json start
script to invoke Node with --env-file=.env before dist/index.js, matching the
existing dev script’s environment loading behavior while preserving the
compiled-output startup command.

Comment on lines +7 to +9
vi.mock("@voltagent/internal", () => ({
safeStringify: (value: unknown) => JSON.stringify(value),
}));

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove JSON.stringify to comply with coding guidelines.

As per coding guidelines, JSON.stringify should never be used. Even within a test mock, this strict rule must be adhered to. You can use a simpler primitive like String or explicitly return a stubbed string representation instead of relying on JSON.stringify.

♻️ Proposed alternative
 // Mock `@voltagent/internal` to avoid build dependency
 vi.mock("`@voltagent/internal`", () => ({
-  safeStringify: (value: unknown) => JSON.stringify(value),
+  safeStringify: (value: unknown) => String(value),
 }));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
vi.mock("@voltagent/internal", () => ({
safeStringify: (value: unknown) => JSON.stringify(value),
}));
vi.mock("`@voltagent/internal`", () => ({
safeStringify: (value: unknown) => String(value),
}));
🤖 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 `@packages/core/src/registries/model-provider-registry-edenai.spec.ts` around
lines 7 - 9, Update the safeStringify mock in the test setup to remove
JSON.stringify, using String or an explicit stubbed string representation while
preserving the mock’s string-returning behavior.

Source: Coding guidelines

@cubic-dev-ai cubic-dev-ai Bot 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.

2 issues found across 10 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/core/src/registries/model-provider-registry-edenai.spec.ts">

<violation number="1" location="packages/core/src/registries/model-provider-registry-edenai.spec.ts:8">
P3: The `safeStringify` mock uses `JSON.stringify` directly. If the project's coding guidelines discourage `JSON.stringify` usage (preferring `safeStringify` from `@voltagent/internal` for safety), even test mocks should avoid it to stay consistent. Since no test here actually depends on the serialization output, a simpler stub like `String(value)` or a fixed string return would satisfy the mock contract without importing the discouraged primitive.</violation>
</file>

<file name="examples/with-edenai/package.json">

<violation number="1" location="examples/with-edenai/package.json:34">
P2: The `start` script doesn't load environment variables from `.env`, unlike the `dev` script which uses `--env-file=.env`. Since `src/index.ts` throws immediately if `EDENAI_API_KEY` is missing, running `pnpm build && pnpm start` (as the README suggests) will fail unless the user manually exports the variable. Adding `--env-file=.env` keeps behavior consistent with the dev script and the documented workflow.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

"scripts": {
"build": "tsc",
"dev": "tsx watch --env-file=.env ./src",
"start": "node dist/index.js",

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.

P2: The start script doesn't load environment variables from .env, unlike the dev script which uses --env-file=.env. Since src/index.ts throws immediately if EDENAI_API_KEY is missing, running pnpm build && pnpm start (as the README suggests) will fail unless the user manually exports the variable. Adding --env-file=.env keeps behavior consistent with the dev script and the documented workflow.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At examples/with-edenai/package.json, line 34:

<comment>The `start` script doesn't load environment variables from `.env`, unlike the `dev` script which uses `--env-file=.env`. Since `src/index.ts` throws immediately if `EDENAI_API_KEY` is missing, running `pnpm build && pnpm start` (as the README suggests) will fail unless the user manually exports the variable. Adding `--env-file=.env` keeps behavior consistent with the dev script and the documented workflow.</comment>

<file context>
@@ -0,0 +1,38 @@
+  "scripts": {
+    "build": "tsc",
+    "dev": "tsx watch --env-file=.env ./src",
+    "start": "node dist/index.js",
+    "volt": "volt"
+  },
</file context>


// Mock @voltagent/internal to avoid build dependency
vi.mock("@voltagent/internal", () => ({
safeStringify: (value: unknown) => JSON.stringify(value),

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.

P3: The safeStringify mock uses JSON.stringify directly. If the project's coding guidelines discourage JSON.stringify usage (preferring safeStringify from @voltagent/internal for safety), even test mocks should avoid it to stay consistent. Since no test here actually depends on the serialization output, a simpler stub like String(value) or a fixed string return would satisfy the mock contract without importing the discouraged primitive.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/registries/model-provider-registry-edenai.spec.ts, line 8:

<comment>The `safeStringify` mock uses `JSON.stringify` directly. If the project's coding guidelines discourage `JSON.stringify` usage (preferring `safeStringify` from `@voltagent/internal` for safety), even test mocks should avoid it to stay consistent. Since no test here actually depends on the serialization output, a simpler stub like `String(value)` or a fixed string return would satisfy the mock contract without importing the discouraged primitive.</comment>

<file context>
@@ -0,0 +1,117 @@
+
+// Mock @voltagent/internal to avoid build dependency
+vi.mock("@voltagent/internal", () => ({
+  safeStringify: (value: unknown) => JSON.stringify(value),
+}));
+
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant