# How to Add Support for a New AI Provider to Meetily: A Step-by-Step Guide

> Learn how to add a new AI provider to Meetily with this step-by-step guide. Extend the LLMProvider enum, update the parser, implement request building, and expose it in the React frontend.

- Repository: [Zackriya Solutions/meetily](https://github.com/Zackriya-Solutions/meetily)
- Tags: how-to-guide
- Published: 2026-08-02

---

**Adding a new AI provider to Meetily requires extending the `LLMProvider` enum in [`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs), updating the string-to-enum parser, implementing a request-building branch in `generate_summary`, and exposing the option in the React frontend.**

Meetily, the open-source meeting assistant from Zackriya-Solutions, abstracts LLM interactions through a clean Rust layer that supports Ollama, Claude, Groq, OpenRouter, and built-in local models. When you need to add support for a new AI provider to Meetily—whether it's a niche API or a custom OpenAI-compatible endpoint—the architecture lets you integrate without touching the audio pipeline or recording subsystems. This guide details the exact file paths and code modifications required to extend the provider list.

## Understanding the Provider Architecture

Meetily's LLM integration relies on a three-part abstraction in the Tauri backend. The `LLMProvider` enum defines available providers, the `from_str` method handles configuration parsing, and the `generate_summary` function dispatches HTTP requests with provider-specific headers and endpoints. This design isolates provider logic to [`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs), ensuring that new integrations only require localized changes.

## Step 1: Extend the LLMProvider Enum

Locate the provider definition in [`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs). Add your new provider as a variant to the existing enum:

```rust
pub enum LLMProvider {
    OpenAI,
    Claude,
    Groq,
    Ollama,
    OpenRouter,
    BuiltInAI,
    CustomOpenAI,
    MyProvider,  // ← Add your new provider here
}

```

This enum drives type safety throughout the application, ensuring that the compiler catches unhandled providers at build time.

## Step 2: Update the String-to-Enum Parser

In the same file, extend the `from_str` implementation to recognize your provider's identifier from configuration files and UI selections:

```rust
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),
        "myprovider" => Ok(Self::MyProvider),  // ← Add this arm
        _ => Err(format!("Unsupported LLM provider: {}", s)),
    }
}

```

This parser enables the frontend to pass provider names as strings while the backend operates on type-safe enum variants.

## Step 3: Implement Request Building Logic

Inside the `generate_summary` function, add a match arm that returns the correct API endpoint and headers for your provider:

```rust
let (api_url, mut headers) = match provider {
    LLMProvider::OpenAI => ("https://api.openai.com/v1/chat/completions".into(), HeaderMap::new()),
    LLMProvider::Groq => ("https://api.groq.com/openai/v1/chat/completions".into(), HeaderMap::new()),
    LLMProvider::OpenRouter => ("https://openrouter.ai/api/v1/chat/completions".into(), HeaderMap::new()),
    LLMProvider::MyProvider => {
        let mut h = HeaderMap::new();
        h.insert("authorization", format!("Bearer {}", api_key).parse().unwrap());
        ("https://api.myprovider.com/v1/chat/completions".to_string(), h)
    },
    LLMProvider::Ollama => { /* existing Ollama logic */ },
    LLMProvider::BuiltInAI => unreachable!(),
};

```

This branch ensures Meetily constructs the correct HTTP request format for your provider's chat completions endpoint.

## Step 4: Create Provider-Specific Helpers (Optional)

For providers that expose model listing endpoints, create a dedicated module following the OpenRouter pattern. Reference [`frontend/src-tauri/src/openrouter/openrouter.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/openrouter/openrouter.rs) as a template:

```rust
// frontend/src-tauri/src/myprovider/myprovider.rs
#[command]
pub fn get_myprovider_models() -> Result<Vec<ModelInfo>, String> {
    let client = Client::new();
    let resp = client
        .get("https://api.myprovider.com/v1/models")
        .bearer_auth(std::env::var("MYPROVIDER_API_KEY").unwrap())
        .send()
        .map_err(|e| e.to_string())?;
    resp.json::<Vec<ModelInfo>>().map_err(|e| e.to_string())
}

```

Export this module in [`src-tauri/src/myprovider/mod.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/src-tauri/src/myprovider/mod.rs) and register the Tauri command in your main application builder to make model discovery available to the UI.

## Step 5: Update the React Frontend

Modify the provider selector component to include your new option. When the user initiates recording, the frontend invokes the Rust backend with the selected provider name:

```typescript
// In your provider selection component
<select
  value={provider}
  onChange={e => setProvider(e.target.value)}
>
  <option value="openai">OpenAI</option>
  <option value="claude">Claude</option>
  <option value="groq">Groq</option>
  <option value="openrouter">OpenRouter</option>
  <option value="ollama">Ollama</option>
  <option value="myprovider">MyProvider</option>  // ← Add this option
</select>

// Later, when calling the backend
await invoke('generate_summary', {
  provider: 'myprovider',
  apiKey: apiKey,
  // ... other params
});

```

The string value must match exactly the case you implemented in the Rust `from_str` parser.

## Step 6: Add Unit Tests

Extend the existing test suite in [`llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/llm_client.rs) to cover your new provider. Verify that `from_str` correctly parses your identifier and that `generate_summary` constructs the expected request structure:

```rust
#[test]
fn test_myprovider_from_str() {
    assert_eq!(LLMProvider::from_str("myprovider").unwrap(), LLMProvider::MyProvider);
    assert_eq!(LLMProvider::from_str("MyProvider").unwrap(), LLMProvider::MyProvider);
}

```

Testing ensures that refactors to the summary engine do not break your integration.

## Key Files Reference

| Path | Purpose |
|------|---------|
| [`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs) | Core abstraction containing `LLMProvider`, `from_str`, and `generate_summary` |
| [`frontend/src-tauri/src/openrouter/openrouter.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/openrouter/openrouter.rs) | Template for provider-specific Tauri commands (model fetching) |
| `frontend/src-tauri/src/<provider>/mod.rs` | Module exports for new provider commands |
| [`frontend/src/components/Sidebar/SidebarProvider.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src/components/Sidebar/SidebarProvider.tsx) | React component managing provider selection state |

## Summary

- **Modify the enum**: Add a variant to `LLMProvider` in [`llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/llm_client.rs) to define the new provider type.
- **Update parsing**: Extend `from_str` to handle the provider's string identifier from configuration.
- **Implement requests**: Add a match arm in `generate_summary` specifying the endpoint URL and authentication headers.
- **Add helpers**: Create optional Tauri commands for provider-specific features like model listing.
- **Expose in UI**: Update the React frontend to include the new provider in selection dropdowns.
- **Test thoroughly**: Verify enum parsing and request construction with unit tests to maintain CI integrity.

## Frequently Asked Questions

### What file contains the main LLM provider logic?

The primary logic resides in [`frontend/src-tauri/src/summary/llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/summary/llm_client.rs). This file contains the `LLMProvider` enum, the `from_str` parser, and the `generate_summary` function that dispatches requests to various providers.

### Do I need to modify the audio recording system to add a new AI provider?

No. Meetily's architecture cleanly separates the audio pipeline from the LLM integration layer. Adding a provider only requires changes to the summary module ([`llm_client.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/llm_client.rs)) and the frontend provider selector, leaving the recording and transcription systems untouched.

### Can I integrate a provider that doesn't use OpenAI's API format?

Yes. While Meetily's existing providers largely follow the OpenAI chat completions format, you can customize the request body construction within the `generate_summary` match arm. Transform the payload structure, headers, and endpoint URL to match your target provider's requirements before the HTTP client sends the request.

### How does the frontend communicate the selected provider to the backend?

The React frontend uses Tauri's `invoke` function to call Rust commands, passing the provider name as a string parameter. The backend then uses `LLMProvider::from_str` to convert this string into the typed enum variant used by `generate_summary` to route the request correctly.