How to Add Support for a New LLM Provider in Meetily: Ollama, Claude, Groq, and OpenRouter
To add a new LLM provider in Meetily, extend the LLMProvider enum in frontend/src-tauri/src/summary/llm_client.rs, implement the from_str parser, add the endpoint and headers in the generate_summary match statement, and expose the new option in the settings UI.
Meetily abstracts LLM communication behind a unified Rust backend that handles multiple providers through a single interface. To add support for services like Ollama, Claude, Groq, or OpenRouter, you modify the provider enumeration and request-building logic in the Tauri backend. This guide walks through the exact implementation steps using the actual source code from the Zackriya-Solutions/meetily repository.
Extend the LLMProvider Enum
First, add your new provider to the enumeration that defines supported services. In frontend/src-tauri/src/summary/llm_client.rs, locate the LLMProvider enum around lines 66-74 and add a new variant:
// frontend/src-tauri/src/summary/llm_client.rs
pub enum LLMProvider {
OpenAI,
Claude,
Groq,
Ollama,
OpenRouter,
BuiltInAI,
CustomOpenAI,
MyNewProvider, // ← Add your new provider here
}
This enum acts as the source of truth for all supported LLM integrations throughout the application.
Implement String Parsing with from_str
Meetily converts user-selected strings from the UI into enum variants using the from_str method. Update the implementation around lines 78-90 to handle your new provider:
impl LLMProvider {
pub fn from_str(s: &str) -> Result<Self, String> {
match s.to_lowercase().as_str() {
"openai" => Ok(Self::OpenAI),
"claude" => Ok(Self::Claude),
"groq" => Ok(Self::Groq),
"ollama" => Ok(Self::Ollama),
"openrouter" => Ok(Self::OpenRouter),
"mynewprovider" => Ok(Self::MyNewProvider), // ↔ new mapping
_ => Err(format!("Unsupported LLM provider: {}", s)),
}
}
}
The string literal you match here (e.g., "mynewprovider") must match the value stored in the settings database and passed from the UI.
Configure API Endpoints in generate_summary
The generate_summary function uses a match statement to select the correct API endpoint and construct the request payload. Around lines 51-73, add a new arm for your provider:
match provider {
LLMProvider::OpenAI => {
let endpoint = "https://api.openai.com/v1/chat/completions".to_string();
(endpoint, header::HeaderMap::new())
}
LLMProvider::MyNewProvider => {
// Example: OpenAI-compatible endpoint
let endpoint = "https://api.mynewprovider.com/v1/chat/completions".to_string();
(endpoint, header::HeaderMap::new())
}
// ... other providers
}
If your provider uses a custom request schema (like Claude's distinct message format), create a provider-specific struct similar to ClaudeRequest and build the payload in the conditional block that handles non-OpenAI formats.
Handle Provider-Specific Headers
For services requiring unique authentication headers, insert the header logic within the same match section. For example, Claude uses x-api-key instead of the standard Authorization header around lines 81-90:
let mut header_map = header::HeaderMap::new();
header_map.insert("x-api-key", api_key.parse()?);
Apply this pattern to your provider if it requires custom headers like X-API-Key, api-key, or specialized content-type specifications.
Update the provider_name Helper for Logging
Meetily uses a helper function to generate human-readable names for debug output and logging. Around lines 35-45, add a match arm for your new variant:
match provider {
LLMProvider::OpenAI => "OpenAI",
LLMProvider::Claude => "Claude",
LLMProvider::Groq => "Groq",
LLMProvider::Ollama => "Ollama",
LLMProvider::OpenRouter => "OpenRouter",
LLMProvider::MyNewProvider => "MyNewProvider",
_ => "Unknown",
}
This ensures that logs and error messages clearly identify which provider is handling the request.
Expose the Provider in the Settings UI
The frontend settings screen must allow users to select your new provider. In the React/TypeScript components (typically frontend/src/app/Settings.tsx or similar), add your provider string to the dropdown or selection list:
const providers = [
{ value: "openai", label: "OpenAI" },
{ value: "claude", label: "Claude" },
{ value: "mynewprovider", label: "MyNewProvider" },
// ... other providers
];
Ensure the value matches exactly the string handled by LLMProvider::from_str in the Rust backend.
Persist the Selection in the Database
User preferences are stored via the settings repository in frontend/src-tauri/src/database/repositories/setting.rs (lines 1-20). The system stores key-value pairs as strings, so no schema migration is required. When the user selects your new provider, the string value is saved automatically and retrieved by the summary service (frontend/src-tauri/src/summary/service.rs) when generating summaries.
Test the Integration End-to-End
Verify your implementation by running the Tauri development server and executing a full workflow:
- Start the dev server:
pnpm run tauri:dev - Select the provider: Navigate to Settings → LLM Provider and choose your new option
- Trigger a summary: Start a recording, let Meetily transcribe the audio, and click Generate Summary
- Verify the request: Run with debug logging (
RUST_LOG=debug) and confirm the request URL matches your configured endpoint and that the response parses correctly
If your provider uses a custom response format, add a deserialization struct similar to ClaudeChatResponse and adjust the final parsing block around lines 300-330 to extract the generated text.
Summary
- Extend the enum: Add your provider to
LLMProviderinfrontend/src-tauri/src/summary/llm_client.rs - Parse the string: Update
from_strto recognize the new provider identifier - Configure the endpoint: Add the API URL and headers in the
generate_summarymatch statement - Handle custom headers: Insert special authentication headers if the provider requires them
- Update logging: Add the display name to the
provider_namehelper - Wire the UI: Add the provider to the settings dropdown in the frontend React components
- Persist settings: The database automatically stores the selection via
setting.rs - Test: Run the full transcription-to-summary workflow with debug logging enabled
Frequently Asked Questions
Which file contains the main LLM provider logic in Meetily?
The core integration logic resides in frontend/src-tauri/src/summary/llm_client.rs. This file contains the LLMProvider enum definition, the from_str parser, the generate_summary function that handles HTTP requests, and the provider_name helper for logging.
Do I need to modify the database schema to add a new LLM provider?
No, the settings repository in frontend/src-tauri/src/database/repositories/setting.rs stores the provider as a generic key-value string pair. As long as your new provider name is handled by LLMProvider::from_str, the system will persist and retrieve it without any schema changes.
How does Meetily handle different API request formats between providers?
The generate_summary function uses a Rust match statement to select endpoints and construct appropriate payloads. For OpenAI-compatible providers, it uses standard chat completion formats. For unique schemas like Claude, it constructs provider-specific request structs (e.g., ClaudeRequest) and handles response parsing with dedicated deserialization structs such as ClaudeChatResponse around lines 300-330.
Can I add a provider that requires a custom authentication header?
Yes, you can insert custom headers within the provider's match arm in generate_summary. For example, Claude uses x-api-key instead of Authorization, which is implemented by creating a new HeaderMap and inserting the required key before returning the endpoint tuple.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →