feat(llm): add Ollama provider support#9338
Conversation
Add Ollama as a new LLM provider using the OpenAI-compatible API with a custom base URL (default: http://localhost:11434). - New OllamaProvider class that dynamically fetches available models from the running Ollama instance via /api/tags - AddProviderModal updated with Ollama option, base URL field, and conditional API key requirement - Models displayed as 'Free' instead of showing pricing - Async model loading with 5s timeout for resilience - Route changed to asyncApiRoute for async model fetching
There was a problem hiding this comment.
Code Review
This pull request introduces support for Ollama as a self-hosted AI provider. Key changes include updating the provider configuration UI to handle optional API keys and custom base URLs, adding translations for free models, and implementing the OllamaProvider on the server to dynamically fetch models from local instances. Feedback focuses on simplifying redundant logic in model retrieval and optimizing performance by caching loaded models to avoid unnecessary network requests during chat and title generation.
eliandoran
left a comment
There was a problem hiding this comment.
Overall seems pretty fine.
However, I've tested it on NixOS which comes with Ollama 0.12.11, before the responses API was introduced (0.13.3), which results in the chat failing:
APICallError [AI_APICallError]: Not Found
at <anonymous> (/home/elian/Projects/TriliumNext/Notes/node_modules/@ai-sdk/provider-utils/src/response-handler.ts:70:16)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async postToApi (/home/elian/Projects/TriliumNext/Notes/node_modules/@ai-sdk/provider-utils/src/post-to-api.ts:118:28)
at async OpenAIResponsesLanguageModel.doStream (/home/elian/Projects/TriliumNext/Notes/node_modules/@ai-sdk/openai/src/responses/openai-responses-language-model.ts:1035:50)
at async fn (/home/elian/Projects/TriliumNext/Notes/node_modules/ai/src/generate-text/stream-text.ts:1686:27)
at async <anonymous> (/home/elian/Projects/TriliumNext/Notes/node_modules/ai/src/telemetry/record-span.ts:32:24)
at async _retryWithExponentialBackoff (/home/elian/Projects/TriliumNext/Notes/node_modules/ai/src/util/retry-with-exponential-backoff.ts:96:12)
at async streamStep (/home/elian/Projects/TriliumNext/Notes/node_modules/ai/src/generate-text/stream-text.ts:1638:17)
at async fn (/home/elian/Projects/TriliumNext/Notes/node_modules/ai/src/generate-text/stream-text.ts:2166:9)
at async <anonymous> (/home/elian/Projects/TriliumNext/Notes/node_modules/ai/src/telemetry/record-span.ts:32:24) {
cause: undefined,
url: 'http://localhost:11434/v1/responses',
This is not a good UX, we must guard against it.
Seems that we can fall back to chat mode via:
protected createModel(modelId: string) {
// Use .chat() to target /v1/chat/completions (Ollama doesn't support /v1/responses)
- return this.openai(modelId);
+ return this.openai.chat(modelId);
}Maybe we could do some version check of Ollama.
| costDescription: m.costMultiplier | ||
| ? `${m.costMultiplier}x` | ||
| : m.pricing.input === 0 && m.pricing.output === 0 | ||
| ? t("llm_chat.free") | ||
| : undefined |
There was a problem hiding this comment.
Too complicated. Extract to a function with simple ifs and returns.
Summary
Add Ollama as a new LLM provider, enabling local/self-hosted model support via Ollama's OpenAI-compatible API.
Changes
OllamaProviderclass using@ai-sdk/openaiwith custombaseURLGET /api/tagsendpointAddProviderModalwith base URL configurationgetModelsroute changed toasyncApiRouteto support async model fetchingFiles (9 files, +253/-26)
apps/server/src/services/llm/providers/ollama.ts- New: Ollama provider implementationapps/server/src/services/llm/index.ts- Provider registrationapps/server/src/services/llm/chat_title.ts- Ollama model handlingapps/server/src/routes/api/llm_chat.ts-asyncApiRoutefor getModelsapps/server/src/routes/routes.ts- Route type updateapps/client/src/widgets/type_widgets/options/llm/AddProviderModal.tsx- Ollama option in UIapps/client/src/widgets/type_widgets/llm_chat/ChatInputBar.tsx- Conditional cost displayapps/client/src/widgets/type_widgets/llm_chat/useLlmChat.ts- "Free" label logicapps/client/src/translations/en/translation.json- Translation keys