Skip to content

feat: add first-class oMLX provider via Esperanto profile - #1164

Merged
lfnovo merged 2 commits into
lfnovo:mainfrom
Gautam-Diwan:feature/omlx-provider
Jul 19, 2026
Merged

feat: add first-class oMLX provider via Esperanto profile#1164
lfnovo merged 2 commits into
lfnovo:mainfrom
Gautam-Diwan:feature/omlx-provider

Conversation

@Gautam-Diwan

@Gautam-Diwan Gautam-Diwan commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Description

Adds first-class oMLX provider support in Settings, following the direction settled on #1048 after Esperanto upstream landed (lfnovo/esperanto#228 / PR #239).

Open Notebook exposes the native Esperanto provider name omlx (built-in OpenAICompatibleProfile). There is no remapping to openai-compatible and no OPENAI_COMPATIBLE_* env mirroring (the approach rejected in closed #1049).

  • Settings entry via provider_registry (frontend consumes GET /api/providers)
  • Default base URL http://localhost:11435/v1 (avoids SurrealDB on 8000)
  • Optional API key; language + embedding modalities
  • Connection test + /v1/models discovery with existing prepare_pinned_http_target SSRF helpers (fix: pin DNS for outbound provider HTTP requests #1063)
  • Docs: docs/5-CONFIGURATION/omlx.md + cross-links

Issue status: #1048 is open, labels enhancement / area: providers / upstream / esperanto, unassigned. This PR implements the thin Open Notebook exposure now that upstream is done.

Esperanto dependency: oMLX is merged to Esperanto main but not yet on PyPI (latest release still 2.24.0). This PR pins Esperanto to merge commit cf319506 of #239 until a release ships; happy to switch to esperanto>=2.25.0 (or whatever tag) as soon as it is published.

Related Issue

Fixes #1048

Supersedes closed #1049 (wrong approach: Open Notebook remapping).

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Performance improvement
  • Test coverage improvement

How Has This Been Tested?

  • Tested locally with Docker
  • Tested locally with development setup
  • Added new unit tests
  • Existing tests pass (uv run pytest)
  • Manual testing performed (describe below)

Test Details:

$ uv run python -m pytest tests/test_credential_provider_validation.py tests/test_credentials_api.py tests/test_model_discovery.py -q --tb=short
........................................................................ [100%]
72 passed, 2 warnings in 8.25s

$ uv run ruff check open_notebook/ai/provider_registry.py open_notebook/ai/key_provider.py open_notebook/ai/model_discovery.py api/models.py api/credentials_service.py api/routers/models.py tests/test_credential_provider_validation.py tests/test_credentials_api.py tests/test_model_discovery.py
All checks passed!

$ uv run python -c "from esperanto import AIFactory; ..."
# create_language('omlx', ...) → base http://localhost:11435/v1, api_key 'not-required'
# create_embedding('omlx', ...) → OpenAICompatibleEmbeddingModel

Design Alignment

Which design principles does this PR support? (See VISION.md)

  • Privacy First
  • Simplicity Over Features
  • API-First Architecture
  • Multi-Provider Flexibility
  • Extensibility Through Standards
  • Async-First for Performance

Explanation:

Local Apple Silicon inference stays on-device (privacy). Identity lives in Esperanto’s profile mechanism (extensibility through standards) rather than Open Notebook-only aliases, matching DeepSeek/xAI/DashScope.
Where it differs from traditional HTTP server based inference tools like Ollama is that oMLX cannot be run directly under a Docker environment.

Checklist

Code Quality

  • My code follows PEP 8 style guidelines (Python)
  • My code follows TypeScript best practices (Frontend)
  • I have added type hints to my code (Python)
  • I have added JSDoc comments where appropriate (TypeScript)
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings or errors

Testing

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I ran linting: make ruff or ruff check . --fix
  • I ran type checking: make lint or uv run python -m mypy .

Documentation

  • I have updated the relevant documentation in /docs (if applicable)
  • I have added/updated docstrings for new/modified functions
  • I have updated the API documentation (if API changes were made)
  • I have added comments to complex logic

Database Changes

  • I have created migration scripts for any database schema changes (in /migrations)
  • Migration includes both up and down scripts
  • Migration has been tested locally

Breaking Changes

  • This PR includes breaking changes
  • I have documented the migration path for users
  • I have updated MIGRATION.md (if applicable)

Screenshots (if applicable)

N/A (provider wiring + docs; Settings entry comes from registry / GET /api/providers)

Additional Context

Key wiring (no remapping):

  • open_notebook/ai/provider_registry.pyomlx ProviderSpec
  • api/models.pySupportedProvider Literal
  • open_notebook/ai/key_provider.pyOMLX_API_KEY + OMLX_API_BASE via simple provision (not OPENAI_COMPATIBLE_*)
  • api/credentials_service.py — connection test + discover_with_config
  • open_notebook/ai/model_discovery.pydiscover_omlx_models
  • Runtime: ModelManager already passes provider omlx through to AIFactory after underscore→hyphen normalize (no-op for omlx)

Pre-Submission Verification

  • I have read CONTRIBUTING.md
  • I have read VISION.md
  • This PR addresses an approved issue assigned to me, or it's a small obvious fix (typo, docs, tiny bug) that doesn't need one — for anything bigger without an issue, mark this PR as draft and open the issue (triage takes 1–2 days)
  • I have not included unrelated changes in this PR
  • My PR title follows conventional commits format (e.g., "feat: add user authentication")

Review in cubic

@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 and verified against the latest diff

Confidence score: 5/5

  • In docs/4-AI-PROVIDERS/index.md, the Setup Guide link pattern is inconsistent with other providers, so users may be sent to a less comparable destination and miss the expected anchor-based context—update this link to the same ai-providers.md anchor style before merging.
  • In .env.example, presenting OLLAMA_API_BASE without a deprecation cue can nudge users toward the legacy env-var setup, creating avoidable configuration confusion—add a short deprecation note (or remove the example entry) to align with the Settings UI guidance before merging.
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="docs/4-AI-PROVIDERS/index.md">

<violation number="1" location="docs/4-AI-PROVIDERS/index.md:95">
P3: This entry's 'Setup Guide' link breaks the pattern used by all other providers in this comparison table, which point to an anchor within ai-providers.md rather than the standalone provider doc. Consider linking to `../5-CONFIGURATION/ai-providers.md#omlx-apple-silicon` for consistency, or updating the pattern intentionally across the file.</violation>
</file>

<file name=".env.example">

<violation number="1" location=".env.example:51">
P3: OLLAMA_API_BASE is documented as deprecated in favor of the Settings UI, but this example line presents it without any deprecation note, which could steer users toward the legacy env-var flow.</violation>
</file>

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

Re-trigger cubic

- Best for: macOS Apple Silicon, private local inference
- Privacy: 100% local; default URL `http://localhost:11435/v1` (avoids SurrealDB on 8000)

→ [Setup Guide](../5-CONFIGURATION/omlx.md)

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: This entry's 'Setup Guide' link breaks the pattern used by all other providers in this comparison table, which point to an anchor within ai-providers.md rather than the standalone provider doc. Consider linking to ../5-CONFIGURATION/ai-providers.md#omlx-apple-silicon for consistency, or updating the pattern intentionally across the file.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/4-AI-PROVIDERS/index.md, line 96:

<comment>This entry's 'Setup Guide' link breaks the pattern used by all other providers in this comparison table, which point to an anchor within ai-providers.md rather than the standalone provider doc. Consider linking to `../5-CONFIGURATION/ai-providers.md#omlx-apple-silicon` for consistency, or updating the pattern intentionally across the file.</comment>

<file context>
@@ -84,6 +84,17 @@ Open Notebook supports 17+ AI providers. This guide helps you **choose the right
+- Privacy: 100% local
+- Note: Default port 8000 conflicts with SurrealDB — use `11435`
+
+→ [Setup Guide](../5-CONFIGURATION/omlx.md)
+
 **LM Studio (Alternative)**
</file context>
Suggested change
[Setup Guide](../5-CONFIGURATION/omlx.md)
[Setup Guide](../5-CONFIGURATION/ai-providers.md#omlx-apple-silicon)

Comment thread .env.example
@@ -50,6 +50,10 @@ SURREAL_DATABASE=open_notebook
# Ollama endpoint (if running locally)
# OLLAMA_API_BASE=http://localhost:11434

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: OLLAMA_API_BASE is documented as deprecated in favor of the Settings UI, but this example line presents it without any deprecation note, which could steer users toward the legacy env-var flow.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .env.example, line 51:

<comment>OLLAMA_API_BASE is documented as deprecated in favor of the Settings UI, but this example line presents it without any deprecation note, which could steer users toward the legacy env-var flow.</comment>

<file context>
@@ -48,7 +48,11 @@ SURREAL_DATABASE=open_notebook
 
 # Ollama endpoint (if running locally)
-# OLLAMA_BASE_URL=http://ollama:11434
+# OLLAMA_API_BASE=http://localhost:11434
+
+# oMLX endpoint (Apple Silicon MLX server; avoid port 8000 — SurrealDB)
</file context>

@Gautam-Diwan

Copy link
Copy Markdown
Contributor Author

CI failure fix

Failing job: build-regular (uv sync --frozen --no-dev in Docker backend-builder)

Cause: Esperanto is git-pinned (cf319506, oMLX profile not on PyPI yet). The slim builder image had build-essential but no git, so:

× Failed to download and build `esperanto @ git+https://github.com/lfnovo/esperanto.git@cf319506…`
╰─▶ Git executable not found. Ensure that Git is installed and available.

Backend Lint / Tests / Typecheck and Frontend checks were already green — only the Docker build failed.

Fix: Install git in the Dockerfile backend-builder apt step (with a note to drop it when switching back to a PyPI bound).

Local evidence (same failing step)

$ docker build --target backend-builder --progress=plain -t open-notebook-backend-builder-test .
# … Setting up git …
# … Updating https://github.com/lfnovo/esperanto.git (cf319506…)
# … Updated https://github.com/lfnovo/esperanto.git …
# … RUN uv sync --frozen --no-dev → DONE
# naming to docker.io/library/open-notebook-backend-builder-test:latest done

$ docker run --rm open-notebook-backend-builder-test \
    .venv/bin/python -c "from importlib.metadata import version; from esperanto.providers.llm.profiles import get_profile; p=get_profile('omlx'); print(version('esperanto'), p.name, p.base_url, p.requires_api_key)"
2.24.0 omlx http://localhost:11435/v1 False

$ uv run ruff check .
All checks passed!

$ uv run python -m pytest tests/test_credential_provider_validation.py tests/test_credentials_api.py tests/test_model_discovery.py -q --tb=line
72 passed, 2 warnings in 12.04s

Rebuild of backend-builder after the fix also completed with no Git executable not found error.

Expose Esperanto's built-in omlx OpenAICompatibleProfile in Settings with
Ollama-style UX (default http://localhost:11435/v1, optional API key,
language+embedding discovery). No openai-compatible remapping or
OPENAI_COMPATIBLE_* env mirroring.

Fixes lfnovo#1048
@lfnovo
lfnovo force-pushed the feature/omlx-provider branch from 17b39c0 to 2234ef0 Compare July 19, 2026 17:13
@lfnovo

lfnovo commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Heads-up: I rebased this branch onto main now that esperanto 2.25.1 is on PyPI. This let me drop the temporary git-commit pin and the Dockerfile git install — the pin is now the released esperanto>=2.25.1. Your oMLX feature code is unchanged and tests pass. Thanks for the contribution!

@lfnovo
lfnovo merged commit ef9bc43 into lfnovo:main Jul 19, 2026
13 checks passed
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.

Add first-class oMLX provider support

2 participants