.env.example, development-setup.md, and examples/README.md referenced
APP_PASSWORD and BASIC_AUTH_USERNAME/BASIC_AUTH_PASSWORD, none of which
exist in code. api/auth.py's PasswordAuthMiddleware only reads
OPEN_NOTEBOOK_PASSWORD; the old names silently did nothing.
Co-authored-by: Luis Novo <lfnovo@gmail.com>
* fix(proxy): keep internal SurrealDB websocket out of HTTP proxy (#1160)
websockets 15.0 auto-detects HTTP_PROXY/HTTPS_PROXY and tunnels even
ws:// connections through the proxy. The SurrealDB SDK connects over a
websocket, so with a proxy set the internal DB connection was routed
through the external proxy, which rejected the internal host with HTTP
403 and killed the worker/API on startup.
- Add ensure_internal_no_proxy() helper that merges host.docker.internal,
surrealdb, localhost, 127.0.0.1 into no_proxy/NO_PROXY (never clobbering
a user value) and call it at API, worker and DB-module startup.
- Add host.docker.internal and surrealdb to the .env.example and docs
NO_PROXY examples.
- Add unit tests for the injection helper.
* fix(proxy): preserve NO_PROXY wildcard and include custom SurrealDB host (#1160)
Address review findings on the no_proxy injection:
- NO_PROXY=* (bypass all hosts) is now treated as terminal: leave the
user's config untouched instead of narrowing the wildcard to a finite
list by appending the internal hosts.
- Parse the SurrealDB host from SURREAL_URL (falling back to
SURREAL_ADDRESS) and add it to the bypass list, so deployments with a
custom DB host/IP no longer route DB traffic through the proxy. Unset
or malformed values fall back to the four defaults gracefully.
- Drop the inaccurate getproxies() caching remark in the test.
Register anthropic_compatible in the provider registry so its env config,
modalities, test model, and /api/providers entry are derived from PROVIDERS
(#1075's single source of truth); the only manual copy is the SupportedProvider
Literal. Maps to esperanto's anthropic provider with a custom base_url, and
re-injects that base_url via ChatAnthropic since esperanto's to_langchain drops
it. Connection-test and model discovery mirror the openai_compatible siblings,
including DNS-rebinding pinning (prepare_pinned_http_target). A single shared
validator enforces the base_url + api_key requirement on both the create and
update paths.
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Luis Novo <lfnovo@gmail.com>
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#1048
Co-authored-by: Luis Novo <lfnovo@gmail.com>
Wire four esperanto 2.25.1 providers into the provider matrix:
- Cohere (COHERE_API_KEY): language + embedding via the native v2 API,
with a bespoke discoverer (AIFactory.get_provider_models) since Cohere
is not OpenAI-compatible. Reranking is out of scope (#1087).
- Deepgram: extend modalities to add speech_to_text (Nova/Whisper)
alongside the existing Aura text_to_speech voices.
- PayPerQ / PPQ (PPQ_API_KEY): multi-modality OpenAI-compatible gateway
(https://api.ppq.ai/v1), auto-discovered via the /models endpoint.
- Novita (NOVITA_API_KEY): OpenAI-compatible LLM gateway
(https://api.novita.ai/openai), auto-discovered via /models.
Registry-derived surfaces (env config, modalities, test models, discovery
table, GET /api/providers) update automatically; the SupportedProvider
Literal, key_provider config, availability env map, docs and tests were
updated to match. Closes#1170
esperanto 2.25.0 added OpenRouter for TTS and STT (previously LLM/embedding
only). Expose those modalities in Open Notebook.
- provider_registry: openrouter modalities -> all four (adds speech_to_text,
text_to_speech)
- model_discovery: bespoke discover_openrouter_models combines the live
OpenAI-compatible /models listing with a static seed of the audio model ids
esperanto ships as defaults (microsoft/mai-voice-2 for TTS, openai/whisper-1
and openai/whisper-large-v3 for STT), since OpenRouter's listing does not
reliably tag audio models. Seed only when live discovery returns models, so a
failed discovery never registers unusable audio models.
- credentials_service: credential-based discovery seeds the same audio ids for
openrouter (only after a successful /models response)
- connection_tester: exclude openrouter from DEFAULT_TEST_VOICES so TTS tests
use esperanto's model-specific available_voices (voices are model-specific;
the default model uses Microsoft neural voice names, not alloy/nova)
- tests, docs (provider matrix, AI provider guides) and CHANGELOG
Closes#987
The quick-start guide and the Ollama compose examples set OLLAMA_BASE_URL,
but no code path reads that variable. The authoritative env var is
OLLAMA_API_BASE (see open_notebook/ai/provider_registry.py). Following the
examples verbatim left Ollama permanently unavailable with no error.
Renames OLLAMA_BASE_URL to OLLAMA_API_BASE in the three remaining shipped
files, keeping the value unchanged.
The worker processes all queued tasks up to a fixed concurrency of 5, which
overloads single-GPU / local-LLM setups and triggers rate limits (#893). The
surreal-commands worker already accepts --max-tasks; wire it to a new
OPEN_NOTEBOOK_WORKER_MAX_TASKS env var (default 5, set 1 for sequential) at
every launch point.
- Makefile (worker-start, start-all): --max-tasks "$${VAR:-5}" (Make-escaped)
- dev-init.sh: POSIX ${VAR:-5} default expansion
- supervisord.conf: wrap in sh -c so the shell expands the var (command= does
not run through a shell)
- docker-compose.yml: commented environment example
- .env.example + environment-reference.md: document it, incl. the launch-time
sourcing behavior
Also fixes a phantom doc entry: SURREAL_COMMANDS_MAX_TASKS was documented but
is not read anywhere (the worker's --max-tasks Typer option has no envvar);
replaced with the real OPEN_NOTEBOOK_WORKER_MAX_TASKS.
Closes#893
Create .pre-commit-config.yaml with ruff (lint + format), mypy and basic
hygiene hooks so local commits fail for the same reasons PRs would.
- Ruff lint (--fix for local convenience, no drift vs CI's ruff check .)
- Ruff format check (not yet gated in CI but zero drift — same tool)
- Mypy via language:system/uv to match CI's uv run python -m mypy .
- Hygiene: large files, merge conflicts, YAML/TOML syntax, trailing
whitespace, EOF newlines
- Updated development-setup.md with install/run/skip/update docs
Closes#940
Co-authored-by: dyzur <dyzur@users.noreply.github.com>
Co-authored-by: Luis Novo <lfnovo@gmail.com>
Docling and local Crawl4AI are now opt-in, installed on first container startup
via OPEN_NOTEBOOK_ENABLE_DOCLING / OPEN_NOTEBOOK_ENABLE_CRAWL4AI, keeping the
default image lean (Crawl4AI un-bundled). Downloads cache on the /app/data
volume; installs are blocking with loud logs and degrade-don't-die on failure.
A GET /api/capabilities probe reports actual availability and the Settings UI
gates the Docling/Crawl4AI engines and OCR toggle (with env-var hints) until the
runtime is present. Docs folded from #1121 and rewritten to opt-in; ADR-007 added.
Closes#1122. Closes#1105.
Migration 22 best-effort maps profiles whose outline_llm/transcript_llm/
voice_model references are still empty to existing model records
(provider + name + type, no auto-create), clears the legacy values and
drops the 6 columns. The startup data migration that retried this
mapping on every boot (open_notebook/podcasts/migration.py) is deleted
along with its api/main.py lifespan hook; the legacy fields are removed
from the Pydantic models, API schemas and frontend types/panels.
Accepted trade-off: profiles whose mapping never converged lose the
legacy strings and stay unresolved - they were already non-functional
and the UI already flags them; the user re-picks models once.
The settings frontend now fetches the provider list from the backend
registry endpoint (session-cached react-query hook useProviders())
instead of keeping its own hardcoded copies of provider names, display
names, modalities and docs URLs in lib/providers.tsx.
- New api module (lib/api/providers.ts) + hook (lib/hooks/use-providers.ts)
with staleTime: Infinity — the list only changes on deploy.
- lib/providers.tsx reduced to modality presentation (icon/color/label)
behind fallback-safe helpers, so an unknown modality from a future
provider still renders instead of breaking.
- The backend registry declaration order is the display order (verified
identical to the old curated ALL_PROVIDERS order; endpoint test now
pins order, not just set-equality).
- api-keys page gains loading/error states for the provider fetch; new
i18n keys added to all 14 locales.
- Deleted the regex-based frontend/backend sync test; the
SupportedProvider Literal test remains the backend guarantee.
- Renamed the dead useProviders() in use-models.ts (availability
endpoint) to useProviderAvailability() to avoid a name collision.
- Updated stale docs/comments (AGENTS.md, credentials.md, cubic.yaml,
provider_registry.py, api/models.py) that still described the frontend
table as a manual sync point.
Closes#1082
Documents the policy decided while reviewing PR #1085: one migration per PR
that needs one, numbers allocated in merge order, never consolidate after a
migration lands on main (v1-dev images apply migrations the moment they hit
main, so post-hoc squashing would desync _sbl_migrations for dev users).
Cross-referenced from the Database Migration playbook; also adds the missing
ADR-005 row to the decisions index.
Compose interpolates ${SURREAL_PASSWORD} into the scalar command string
before splitting it into arguments, so a password containing spaces became
multiple argv entries and SurrealDB failed to start. The list (exec) form
keeps each interpolated value in exactly one argument slot.
Also resyncs the mirrored compose snippets in
docs/1-INSTALLATION/docker-compose.md and README.md with the shipped file
(both had drifted: no credential interpolation, SurrealDB port published on
all interfaces) and documents the optional .env credential override for
readers who create the file manually.
Closes#1093
Container runtimes inject HOSTNAME=<container/pod hostname> at runtime; under
Podman pods it resolves to 127.0.1.1, so Next.js standalone bound to the wrong
address and the UI became unreachable. Setting HOSTNAME explicitly in the
supervisord command (with a FRONTEND_BIND_HOST override knob) beats any
injected value. Drops the now-dead ENV HOSTNAME from the Dockerfile and
updates the environment reference and reverse-proxy docs.
Closes#994
* docs: stop teaching 0.0.0.0 SurrealDB port exposure in setup snippets
Bind port 8000 to 127.0.0.1 in every compose and docker run snippet
(README, quick starts, installation, configuration and development docs,
and the examples/docker-compose-*.yml files), matching the shipped
docker-compose.yml from #1025. Drop the redundant --bind 0.0.0.0:8000
from containerized surreal start commands (it is the in-container
default) and add !override to docker-compose.override.yml.example so the
opt-in re-publish actually replaces the base port binding instead of
colliding with it. Docs that discuss reaching the database from another
machine now point at the override example plus a firewall/SSH-tunnel
note.
Closes#1034
* docs: parameterize creds in manual compose example, note Compose version for !override
Consolidate the three copies of context assembly into
open_notebook/utils/context_builder.py:
- POST /api/chat/context now delegates to build_notebook_context()
(same request/response shapes, same string-matching config semantics)
- The source-chat graph now calls build_source_context() instead of the
495-line generalized ContextBuilder class, which had exactly one
caller and whose notebook/notes/priority-config flexibility was dead
- POST /api/notebooks/{notebook_id}/context removed: it duplicated
/api/chat/context with a slightly different envelope and had zero
callers (frontend, docs, tests)
Behavior is pinned by new characterization tests written before the
refactor (tests/test_context_endpoint_characterization.py) plus unit
tests for build_source_context.
* refactor(ai): single provider registry as the backend source of truth
Provider metadata (env vars, modalities, connection-test models,
OpenAI-compatible discovery URLs, display names, docs links) is now
defined once in open_notebook/ai/provider_registry.py. The existing
surfaces are derived from it, keeping every import and call-site shape
unchanged:
- api/credentials_service.py: PROVIDER_ENV_CONFIG, PROVIDER_MODALITIES
and the discovery url_map are built from the registry
- open_notebook/ai/connection_tester.py: TEST_MODELS derived
- open_notebook/ai/model_discovery.py: OPENAI_COMPAT_PROVIDERS built
from registry entries with a discovery URL (quirk hooks stay local)
The SupportedProvider Literal (typing, can't be built at runtime) and
the frontend provider tables remain manual copies; the cross-check
tests now assert registry keys == Literal == frontend list, plus
registry internal consistency and discovery-table coverage.
New GET /api/providers endpoint exposes the registry (name, display
name, modalities, docs_url, env-configured status) so clients can stop
hardcoding provider lists (frontend adoption is a follow-up).
Docs updated: open_notebook/AGENTS.md and docs/7-DEVELOPMENT/credentials.md
now describe the registry instead of the four-place sync rule.
* refactor(ai): address review findings on the provider registry
- Build PROVIDERS via _build_registry(), which raises on a duplicate
provider name at import time instead of silently dropping the earlier
spec (dict-comprehension behavior); regression test added
- Pin the exact OpenAI-compatible provider -> discovery URL mapping in
a test so a registry edit can't silently drop or misassign a URL
- Give TEST_MODELS a real type annotation
(Dict[str, Tuple[Optional[str], str]]) instead of bare dict
Delete api/client.py (synchronous httpx client calling the app's own
FastAPI server, a leftover from the removed Streamlit UI) and the 13
api/*_service.py wrappers around it. None of these files had any
importer in routers, commands or tests, verified by grepping the whole
repo for each module name.
Also remove commands/example_commands.py (process_text/analyze_data
demo commands from the surreal-commands README) and its export from
commands/__init__.py, and update remaining docstring examples to
reference the real generate_podcast command.
The real services (command_service, credentials_service,
podcast_service) are untouched.
Captures the process designed and executed for v1.11.0 so every future
release reproduces it:
- .github/RELEASE_PROCESS.md v2: changelog audit, risk-based test
matrix (buckets A/B/C), the Docker image gate, fix-loop re-test
policy, CI-based publishing path, communication structure with a
mandatory credits section, retro, and the gotchas that cost
iterations this cycle
- ADR-005: why releases now pass a risk-based confidence process gated
on the real image, with the v1.11.0 evidence (bugs the unit suite
could not catch: SEARCH-index ORDER BY 500, credential clear no-op)
- scripts/release-test/: the harness built during v1.11.0 —
fresh-install + upgrade gate (release-image-test.sh) and the
browsable RC stack with optional dev-data copy (rc-stack.sh), plus
compose/nginx encoding the API_URL, host.docker.internal and
SurrealDB import learnings
- make release-test / release-stack / release-stack-down targets
* fix: update Google model version in connection tester and tests
* fix: updated the gemini model lists that references deprecated models
* fix: update also documentation. This is more prone to not follow the maintainer's directives, so PTADL
* fix: forgot two references to gemini deprecated versions
* fix: use valid, longer-lived gemini model IDs
Several IDs the PR introduced don't exist or are near shutdown, verified
against Google's official model/deprecation pages (2026-07):
- connection test model gemini-2.5-flash -> gemini-3.5-flash (2.5-flash
retires 2026-10-16; 3.5-flash is the current stable GA and Google's
named replacement, so the #970 fix doesn't re-break in ~3 months)
- gemini-3.5-pro (does not exist) -> gemini-2.5-pro in docs
- plain gemini-3.1-flash (not a GA Gemini-API id) dropped from the Vertex
discovery list / preferences / docs; use gemini-3.5-flash or -flash-lite
- dead gemini-pro dropped from preferences and docs
Ported #996's #970 regression test, pinned to gemini-3.5-flash.
---------
Co-authored-by: Luis Novo <lfnovo@gmail.com>
check_api_password() (an unused HTTPBearer-based dependency, superseded
by PasswordAuthMiddleware) and its now-unused imports are dead code -
nothing calls it. Removed.
Docs across api/CLAUDE.md, docs/3-USER-GUIDE/api-configuration.md,
docs/5-CONFIGURATION/security.md, docs/7-DEVELOPMENT/security.md, and
docs/SECURITY_REVIEW.md still described a hardcoded default password
("open-notebook-change-me") that PasswordAuthMiddleware doesn't actually
have - if OPEN_NOTEBOOK_PASSWORD is unset, auth is fully disabled
instead. Updated to match actual behavior.
* docs: restructure documentation around AGENTS.md, VISION.md and decision records
- Consolidate 17 CLAUDE.md files into 3 AGENTS.md (root, backend, frontend);
CLAUDE.md files become @AGENTS.md pointers
- Add VISION.md: product identity + current posture with horizon clusters
- Add docs/7-DEVELOPMENT/decisions/ with 4 retroactive ADRs and 2 PDRs
- Add 5 new engineering docs pages (credentials, content-processing,
podcasts, prompts, frontend) absorbing knowledge from removed CLAUDE.md
- Dismember TRIAGE.md: label taxonomy into maintainer-guide.md, product
jurisprudence into VISION.md, operator heuristics stay local (gitignored)
- Add AI-assisted/agent-generated PR guidelines to contributing.md
- Convert README.dev.md into a pointer after migrating its unique content
(make workflow matrix, Docker publishing, add-a-language playbook)
- Fix stale docs: migration path/format, provider count, locale list;
fix broken links (docs/index.md, PR template, CONFIGURATION.md)
* docs: fix README doc links and add markdown link check to CI
- Repoint 9 README links to pages that actually exist in docs/
- Replace literal (link) placeholder in maintainer-guide templates
- Add scripts/check_md_links.py validating relative links in tracked
markdown (skips URLs, anchors and code spans)
- Add docs-links workflow running the check on PRs that touch markdown
* docs: add documentation restructure to changelog
* feat: add cubic.yaml with project-aware AI review agents
Three custom review agents (vision & principles alignment backed by
VISION.md, known mechanical caveats, security & testability), PR-contract
review instructions, and automatic ultrareviews for auth, credential,
encryption and migration changes.
* docs: graduate issue-first policy by change size
Small obvious fixes (typos, docs, tiny bugs, i18n completions) no longer
require an issue; features and architecture changes still do. Sizeable
PRs opened without an issue convert to draft while the issue goes
through triage (1-2 days). Applied consistently across contributing
guide, root CONTRIBUTING pointer, PR template, maintainer guide red
flags and cubic review instructions.
* docs: align PR template Related Issue section with graduated issue-first policy
* docs: address review — generalize ADR-002/004, unwrap hard-wrapped lines
- ADR-002 now records the general delegation rule (platform/media support
that needs heavy coding lives in focused external libraries) covering
Esperanto, Content Core and podcast-creator
- ADR-004 now records the durable decision (long-running work runs on
background workers — heavy content, varied machine sizes, never lock
usage) with the queue technology as a swappable implementation detail
pending #381
- Remove mid-paragraph hard line wrapping from authored docs to match
repo convention (one line per paragraph)
* fix: address cubic review — stale doc facts, make dev/full targets, link checker query strings
- credentials.md: only PROVIDER_CONFIG exists as a map; Vertex/Azure/
OpenAI-compatible provisioning is inline in _provision_*() functions
- content-processing.md: correct ContextConfig priority weights
(source 100 > insight 75 > note 50)
- development-setup.md + Makefile: make dev/full pointed at root compose
files that don't exist; targets now use examples/docker-compose-dev.yml
and examples/docker-compose-full-local.yml with --project-directory .
- check_md_links.py: strip query strings before file-existence checks
Two small fixes to the podcast episode-listing path, plus a doc note:
- audio_file is only ever set server-side today from a UUID-named
directory under PODCASTS_FOLDER, so this can't currently be tripped -
but the stream/retry/delete endpoints didn't verify the resolved path
actually stayed within PODCASTS_FOLDER before following it. Add
_is_audio_path_contained() as defense in depth against a future code
path (e.g. importing external audio) setting audio_file to something
else.
- Listing episodes called get_job_detail() -> get_command_status() once
per episode, each its own round trip (no connection pooling). Add
PodcastEpisode.get_job_details_for_commands() to batch-fetch status
for every episode's command in one query instead.
Also documents (docs/7-DEVELOPMENT/security.md) that podcast_creator's
configure("templates", {...}) compiles strings as Jinja2 template
source - the same shape as the SSTI vulnerability fixed in
transformation.py (GHSA-f35w-wx37-26q7). Confirmed dormant: no code path
in this repo calls it today. commands/podcast_commands.py gets a
matching code comment warning against wiring user text into it if a
"custom podcast template" feature is ever added.
* fix: reject oversized request bodies before auth/routing
No limit existed on request body size, so a single upload could exhaust
memory/disk before any validation ran. MaxBodySizeMiddleware
(api/middleware.py) rejects requests over OPEN_NOTEBOOK_MAX_UPLOAD_SIZE_MB
(default 100MB) via both a Content-Length pre-check and by counting bytes
as the body streams in, so it also catches chunked requests with no
Content-Length header.
Registered after PasswordAuthMiddleware (wrapping it) so oversized
requests are rejected before spending any work on credential checks, and
inside CORSMiddleware so a rejected upload still gets CORS headers.
* fix: clamp non-positive size limits and log rejected requests
OPEN_NOTEBOOK_MAX_UPLOAD_SIZE_MB=0 (or negative) made every request with a
body 413; fall back to the default instead, with a warning. Also log each
413 rejection so operators can diagnose failed uploads.
---------
Co-authored-by: Luis Novo <lfnovo@gmail.com>
* fix: don't combine wildcard CORS origins with allow_credentials
Combining allow_origins=["*"] with allow_credentials=True makes
Starlette's CORSMiddleware reflect the request's Origin header verbatim
instead of returning a literal "*" (browsers reject a literal wildcard
alongside credentials) - defeating the origin allowlist for any
credentialed request.
allow_credentials is now tied to whether CORS_ORIGINS was explicitly
scoped: False for the default wildcard, True once an operator opts into
specific origins. _cors_headers() (the manual CORS builder for error
responses raised before CORSMiddleware runs) is updated to match, so it
can't grant credentials the real middleware wouldn't.
Not independently exploitable today (the frontend never sends
credentialed requests, and auth is a Bearer header, not a cookie), but
there's no reason to allow it for the default wildcard case.
* fix: key allow_credentials on the parsed origins list, not the env var
An operator who explicitly sets CORS_ORIGINS=* got allow_credentials=True
with a wildcard origin list - the exact reflect-any-Origin behavior this
change exists to prevent. Introduce CORS_ALLOW_CREDENTIALS keyed on the
parsed list containing '*' and use it at both the middleware registration
and the manual error-response headers; replace the tautological formula
tests with ones exercising the real parser.
---------
Co-authored-by: Luis Novo <lfnovo@gmail.com>
Rewrite the Windows native Quick Start to start the four services manually via uv run, and add an optional sample launcher users can save themselves, instead of pointing at a start-open-notebook.bat that the repo never shipped.
Fixes#846
Documents the EasyPanel template (examples/easypanel/) in the cloud-platform deploy list, covering the one-click gallery flow and the manual playground flow. Notes it provisions the app + a dedicated SurrealDB with generated secrets.
Refs #189
quick-start-local.md (#781):
- add the required OLLAMA_BASE_URL=http://ollama:11434 env var to the
open_notebook service (already present in examples/docker-compose-ollama.yml)
- correct the provider/model setup navigation from "Settings → API Keys" to
the actual "Manage → Models" location
from-source.md (#779):
- add a "Start Worker" step between API and Frontend; without the
surreal-commands worker, sources stay stuck at CommandStatus.NEW
- fix the same outdated "Settings → API Keys" navigation reference
* docs: add Code of Conduct (Contributor Covenant v2.1)
The contributing guide references a Code of Conduct that contributors
are expected to uphold, but the file was missing. This adds the
standard Contributor Covenant v2.1 and links to it from the
contributing guide.
* docs: point Code of Conduct enforcement contact to project channels
Replace the placeholder conduct@opennotebook.dev address (not a project
domain) with the open-notebook.ai contact form and the project Discord.
---------
Co-authored-by: zichen0116 <zichen0116@users.noreply.github.com>
Co-authored-by: Luis Novo <lfnovo@gmail.com>
* feat(i18n): add Turkish (tr-TR) translation
* fix(i18n): derive LanguageCode from resources to avoid sync drift
* fix(i18n): make Turkish selectable and fix tr-TR syntax errors
- Fix unescaped quotes in tr-TR search strings that broke the build
- Add Turkish entry to LanguageToggle so it is selectable in the UI
- Register Turkish date-fns locale for date formatting
- Add turkish language name key across all locales for consistency
---------
Co-authored-by: Luis Novo <lfnovo@gmail.com>
Upgrade esperanto 2.20.0 -> 2.22.0. The constraint (>=2.20.0,<3) already
allowed it; this relocks and picks up upstream fixes (OpenRouter json body,
clearer null-embedding errors, streaming ToolCall objects, base_url
trailing-slash normalization, Ollama thinking-model content).
Esperanto 2.21.0 lowered the Ollama num_ctx default from 128000 to 8192 to
avoid OOM on consumer GPUs. We keep that safe default and add an optional
per-credential num_ctx override for self-hosters whose hardware can handle a
larger context window:
- Credential gains a num_ctx field, surfaced via to_esperanto_config() so it
flows into AIFactory automatically (no ModelManager change needed).
- Credential create/update API schemas + router pass num_ctx through.
- Frontend: optional numeric field on the Ollama credential form, with i18n
labels translated across all 13 locales.
- Docs: document the new default and the override under AI providers.
Closes#825
* docs: add windows native installation guide
Added a comprehensive installation guide for Open Notebook on Windows, covering prerequisites, setup steps, critical fixes, and troubleshooting.
* docs: move windows native guide into 1-INSTALLATION and link from index
---------
Co-authored-by: Luis Novo <lfnovo@gmail.com>
Header-based splitters (notably HTMLHeaderTextSplitter on complex pages
like Wikipedia or Project Gutenberg) can emit single-character or
punctuation-only chunks. Some embedding providers — including
llama.cpp's OpenAI-compatible endpoint — return null vector elements
for such inputs, which then crash response parsing in Esperanto with
'TypeError: float() argument must be a string or a real number, not
NoneType'.
chunk_text() now filters chunks below OPEN_NOTEBOOK_MIN_CHUNK_SIZE
tokens (default 5) after splitting. The filter is bypassed when it
would empty the result list, so legitimately short documents are
preserved.
* docs: add external Ollama setup guide
Add guide for users who have Ollama installed separately and don't
want Docker to run the Ollama service. Includes connection instructions
for host.docker.internal routing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: remove obsolete test for Ollama embeddings API
* chore: remove ARCHITECTURE_DIAGRAMS.md file
---------
Co-authored-by: jjay <jjay@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Replace hardcoded `allow_origins=["*"]` with a parsed `CORS_ORIGINS`
environment variable (comma-separated). Default remains `*` for
backward compatibility — no existing deployment breaks — but the API
now logs a startup warning prompting users to set it explicitly for
production.
Exception handlers now route their CORS headers through a shared
`_cors_headers()` helper that mirrors Starlette's CORSMiddleware
behavior: reflects the request Origin when allowed (handling the
browser-rejected `*` + credentials combination correctly), and omits
`Access-Control-Allow-Origin` for disallowed origins so error bodies
don't leak cross-origin when `CORS_ORIGINS` is configured.
Closes#585, #730.
Based on the original work by Greg Grace in #597; rewritten on top of
current main to address prior review feedback (load_dotenv kept at
top, `import os` grouped with stdlib, `_cors_headers` defined before
its exception-handler callers, origins parsed once at module load)
and to choose a non-breaking default paired with a startup warning
instead of a stricter-by-default origin.
Co-authored-by: Greg Grace <ggrace@519lab.com>
* fix: map base_url to endpoint for Azure credentials
The Azure credential form only exposes a base_url field, but the
connection tester, key provisioner, and Esperanto config all expect
an endpoint field. This maps base_url to endpoint for Azure providers
so credentials work without requiring a dedicated endpoint form field.
Closes#727
* docs: update Azure credential docs to reflect base_url mapping
- Bump version from 1.8.1 to 1.8.2
- Add changelog entry for DashScope and MiniMax provider support
- Update provider counts across README and docs (16+ → 18+, 15+ → 17+)
- Add DashScope and MiniMax to README provider support matrix
- Bump esperanto dependency to >=2.20.0 for new provider profiles
- Register both providers in credentials, key provider, connection tester, model discovery, and models router
- Add frontend provider entries (display names, modalities, docs links)
- Add documentation sections for both providers in ai-providers.md, environment-reference.md, and provider comparison
The v1-latest image requires a separate surrealdb service unlike the
deprecated single-container image. Add comments pointing to the full
base docker-compose.yml in all partial code examples.