# How AI Providers Integrate with the Esperanto Library in Open-Notebook

> Discover how OpenAI Anthropic Google Mistral and Ollama integrate with Open Notebook's Esperanto library Learn about the three layer architecture for AI provider integration.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-07-04

---

**Open-Notebook integrates multiple AI providers (OpenAI, Anthropic, Google, Mistral, Ollama) with the Esperanto library through a three-layer architecture involving encrypted credential storage, environment variable provisioning, and factory-based model instantiation.**

The Open-Notebook project provides a unified interface for large language models (LLMs), embeddings, and speech services by leveraging the Esperanto library. This integration supports providers ranging from cloud APIs like OpenAI and Anthropic to local deployments via Ollama. The architecture decrypts credentials at runtime, provisions environment variables, and uses factory methods to instantiate provider-specific clients without exposing implementation details to the rest of the application.


## Credential Storage and Configuration

The foundation of provider integration rests in the `Credential` domain model, which handles encrypted storage and configuration mapping.

### The Credential Domain Model

In [`open_notebook/domain/credential.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/credential.py), the `Credential` class stores secret keys and optional endpoint configurations. The model automatically decrypts encrypted API keys when read and exposes a helper method `to_esperanto_config()` that returns a plain dictionary suitable for Esperanto initialization. This dictionary contains keys like `api_key`, `base_url`, `endpoint`, and `num_ctx`, allowing the library to connect to the provider's infrastructure.

### Building Esperanto-Compatible Configs

When the system needs to instantiate a model, it retrieves the associated credential and calls `to_esperanto_config()`. This method extracts the decrypted secret and formats provider-specific parameters into a unified structure. By centralizing this logic in the domain model, Open-Notebook ensures that sensitive data never appears in logs or error traces while remaining accessible to the factory layer.


## Runtime Key Provisioning

Before any Esperanto API call executes, Open-Notebook ensures the necessary environment variables exist through an explicit provisioning step.

### Environment Variable Injection

The `provision_provider_keys()` function in [`open_notebook/ai/key_provider.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/key_provider.py) looks up the first `Credential` record for the requested provider. It then injects the API key and any URL overrides into the appropriate environment variables—such as `OPENAI_API_KEY` or `OLLAMA_API_BASE`—using `os.environ`.

If no credential exists in the database, the function falls back to user-defined environment variables, preserving backward compatibility with standard deployment practices. This approach allows the application to switch between database-managed credentials and infrastructure-level secrets without code changes.


## Factory-Based Model Instantiation

The core abstraction layer translates database records into live Esperanto objects through the `ModelManager` class.

### The ModelManager Class

Located in [`open_notebook/ai/models.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/models.py), `ModelManager` orchestrates the conversion of database `Model` records into functional AI clients. The process follows these steps:

1. Load the linked `Credential` (if any) and build the provider-specific config dict via `credential.to_esperanto_config()`
2. Normalize provider names from underscore format (`openai_compatible`) to Esperanto's hyphenated form (`openai-compatible`)
3. Call the appropriate factory method based on model type

Depending on the model type—`language`, `embedding`, `speech_to_text`, or `text_to_speech`—`ModelManager` invokes the corresponding method:

```python
AIFactory.create_language(model_name=model.name, provider=provider, config=config)
AIFactory.create_embedding(...)
AIFactory.create_speech_to_text(...)
AIFactory.create_text_to_speech(...)

```

Esperanto caches the actual model instance internally, making subsequent calls cheap and suitable for high-throughput workflows.

### Provider Name Normalization

Open-Notebook stores provider names with underscores (e.g., `openai_compatible`), but Esperanto expects hyphenated identifiers (`openai-compatible`). The `ModelManager` handles this translation automatically during the factory call, ensuring compatibility between the database schema and the library's naming conventions.


## Discovery and Registration

Open-Notebook automatically discovers available models from each provider and classifies them into the appropriate Esperanto categories.

### Automatic Model Discovery

The `sync_provider_models()` function in [`open_notebook/ai/model_discovery.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/model_discovery.py) queries provider APIs to retrieve available model catalogs. It then populates the local `model` table with entries for each discovered model, storing metadata like provider name, model identifier, and capabilities.

### Pattern-Based Classification

The `classify_model_type()` helper uses provider-specific pattern tables (such as `OPENAI_MODEL_TYPES` and `OLLAMA_MODEL_TYPES`) to inspect model names and assign them to one of the four Esperanto model types. This classification enables the system to automatically register newly discovered models with the correct factory method, eliminating manual configuration for standard provider offerings.


## API Exposure and Usage

The integration surfaces through FastAPI endpoints that expose provider availability and credential-backed testing.

### FastAPI Endpoints

The router in [`api/routers/models.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/models.py) calls `AIFactory.get_available_providers()` to list usable providers and provides endpoints for model discovery and credential validation. This lets the UI display only providers with valid credentials and auto-assign default models for chat, transformation, and podcast workflows.

### Practical Usage Examples

The following patterns demonstrate how to interact with the integration layer:

```python

# 1️⃣ Create a credential for an OpenAI key (via the API or UI)

await Credential(
    name="My OpenAI",
    provider="openai",
    api_key=SecretStr("sk-..."),
).save()

```

```python

# 2️⃣ Provision env vars for the provider (run automatically by ModelManager,

#    but can be called manually if you need the vars early)

from open_notebook.ai.key_provider import provision_provider_keys
await provision_provider_keys("openai")   # sets OPENAI_API_KEY in os.environ

```

```python

# 3️⃣ Retrieve a language model by its database ID

from open_notebook.ai.models import model_manager
lang_model = await model_manager.get_model("model:1234")

# `lang_model` is an Esperanto LanguageModel ready for LangChain or direct calls

response = await lang_model.chat(messages=[{"role": "user", "content": "Hello"}])

```

```python

# 4️⃣ Get the default chat model (falls back to env vars if no DB entry)

default_chat = await model_manager.get_default_model("chat")
print(default_chat)  # <LanguageModel provider='openai' name='gpt-4o' ...>

```

```python

# 5️⃣ Discover and register all models from Ollama

from open_notebook.ai.model_discovery import sync_provider_models
await sync_provider_models("ollama")   # populates the `model` table automatically

```

Users can add a new provider simply by creating a `Credential` record. The system automatically provisions environment variables, discovers the provider's model catalog, and creates ready-to-use Esperanto objects for workflow graphs.


## Summary

- **Encrypted credential storage**: The `Credential` model in [`open_notebook/domain/credential.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/credential.py) decrypts API keys and generates Esperanto-compatible configuration via `to_esperanto_config()`
- **Environment provisioning**: `provision_provider_keys()` in [`open_notebook/ai/key_provider.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/key_provider.py) injects credentials into environment variables before API calls
- **Factory instantiation**: `ModelManager` in [`open_notebook/ai/models.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/models.py) normalizes provider names and uses `AIFactory` methods to create cached model instances
- **Automatic discovery**: `sync_provider_models()` in [`open_notebook/ai/model_discovery.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/model_discovery.py) classifies and registers provider models using pattern matching
- **API exposure**: FastAPI routers expose provider availability and enable credential-backed testing through `AIFactory.get_available_providers()`


## Frequently Asked Questions

### How does Open-Notebook secure API keys when integrating with Esperanto?

API keys are stored encrypted in the `Credential` domain model within [`open_notebook/domain/credential.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/credential.py). The model decrypts keys only when reading and exposes them through `to_esperanto_config()`, which returns a configuration dictionary suitable for Esperanto. This ensures plaintext secrets never persist in memory longer than necessary and remain encrypted at rest in the database.

### What happens if no credential exists for a provider in the database?

If no `Credential` record exists, `provision_provider_keys()` falls back to standard environment variables (such as `OPENAI_API_KEY` or `OLLAMA_API_BASE`). This backward-compatible approach allows the application to function with infrastructure-level secrets even when database credentials are unavailable, maintaining seamless integration with container orchestration and secret management systems.

### How does Open-Notebook handle provider name differences between its database and Esperanto?

Open-Notebook stores provider names with underscores (e.g., `openai_compatible`), while Esperanto expects hyphenated formats (`openai-compatible`). The `ModelManager` class in [`open_notebook/ai/models.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/models.py) automatically normalizes these names during the factory instantiation process, ensuring the database schema and library conventions remain compatible without manual intervention.

### Can I manually trigger model discovery for a new provider?

Yes, you can call `sync_provider_models()` from [`open_notebook/ai/model_discovery.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/model_discovery.py) with the provider name as an argument. This function queries the provider's API, classifies discovered models using `classify_model_type()`, and populates the `model` table automatically. This enables immediate availability of new models in the UI and API without requiring application restarts or manual database inserts.