open-notebook/api/routers
Luis Novo 3b7243d216
Some checks are pending
Development Build / extract-version (push) Waiting to run
Development Build / changes (push) Waiting to run
Tests / Frontend Lint (push) Waiting to run
Tests / Backend Tests (push) Waiting to run
Tests / Backend Lint (push) Waiting to run
Tests / Backend Typecheck (push) Waiting to run
Development Build / build-regular (push) Blocked by required conditions
Development Build / build-single (push) Blocked by required conditions
Development Build / summary (push) Blocked by required conditions
Tests / Frontend Tests (push) Waiting to run
Tests / Frontend Build (push) Waiting to run
fix(sources): fall back to auto when a selected engine's runtime is absent (#1194)
* fix(sources): fall back to auto when a selected engine's runtime is absent

The content-processing engine choice is persisted in the database; the
runtime that serves it (Docling, local Crawl4AI) is installed on demand
from environment flags evaluated at boot. The two therefore drift: a
redeploy that drops OPEN_NOTEBOOK_ENABLE_CRAWL4AI/_DOCLING, a volume
moved to a new deployment, or a failed on-demand install all leave a
stored selection pointing at a runtime that is not there.

The source graph passed that selection straight to content-core, so
every affected extraction failed with "Could not extract any text
content from this source" - no mention of the engine, the runtime, or
the flag that would fix it. For a URL engine set to crawl4ai this breaks
URL ingestion entirely.

The graph now checks runtime availability before honoring the stored
engine and degrades to content-core's "auto" chain, logging a WARNING
that names the engine and the env var that would enable it. Engines with
no opt-in runtime (auto/simple/firecrawl/jina) are passed through
untouched.

The availability probes moved from api/routers/capabilities.py to
open_notebook/utils/runtime_capabilities.py so the graph can use them
without importing from the API layer; the capabilities endpoint keeps
identical behavior and its tests follow the probes to their new home.

Found by the smoke-e2e agent during v1.14.0 release testing, on a dev
environment that was in exactly this state. Pre-existing since v1.13.0
(#1122 made the runtimes opt-in, #432 made the stored selection take
effect), not a v1.14.0 regression.

* docs(changelog): record the unavailable-engine fallback fix
2026-07-20 18:09:00 -03:00
..
__init__.py Api podcast migration (#93) 2025-07-17 08:36:11 -03:00
_chat_shared.py refactor(api): extract shared session and message helpers for chat routers (#1072) 2026-07-11 19:01:47 -03:00
auth.py feat: credential-based API key management (#477) (#540) 2026-02-10 08:30:22 -03:00
capabilities.py fix(sources): fall back to auto when a selected engine's runtime is absent (#1194) 2026-07-20 18:09:00 -03:00
chat.py refactor(api): single context-building implementation (#1079) 2026-07-11 19:55:46 -03:00
commands.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
config.py chore(lint): re-enable F401/F841/E722 and fix fallout (#1062) 2026-07-11 18:36:04 -03:00
credentials.py feat: add anthropic_compatible credential provider (#1043) 2026-07-19 15:14:17 -03:00
embedding.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
embedding_rebuild.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
episode_profiles.py chore(podcasts): drop legacy provider/model string fields from podcast profiles (#1107) (#1112) 2026-07-12 14:35:04 -03:00
insights.py fix(insights): stamp created/updated on source_insight and stop serializing "None" (#1085) 2026-07-12 11:05:51 -03:00
languages.py feat(podcasts): model registry integration, credential passthrough & new features (#632) 2026-02-27 11:06:47 -03:00
models.py fix(models): stop auto-assign from re-filling cleared optional defaults (#1186) 2026-07-19 18:06:17 -03:00
notebooks.py fix(notebook): cascade-delete chat sessions on notebook deletion (#1175) 2026-07-19 12:45:15 -03:00
notes.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
podcasts.py fix(podcasts): render EpisodeCard model details from resolved model references (#1115) 2026-07-12 14:57:54 -03:00
providers.py refactor(ai): single provider registry as the backend source of truth (#1075) 2026-07-11 19:21:36 -03:00
search.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
settings.py feat(settings): expose Docling formula & vision enrichment toggles (#1187) 2026-07-19 18:15:40 -03:00
source_chat.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00
sources.py fix(sources): cap error text surfaced to clients (#1140) 2026-07-14 12:22:19 -03:00
speaker_profiles.py chore(podcasts): drop legacy provider/model string fields from podcast profiles (#1107) (#1112) 2026-07-12 14:35:04 -03:00
transformations.py fix(api): let typed domain exceptions reach the global handlers (#1078) 2026-07-11 19:42:10 -03:00