# Plan: Add Mistral AI as Alternative Chat Provider ## Context bDS currently routes all AI chat through the OpenCode Zen gateway (`opencode.ai/zen/v1/...`) with two code paths: Anthropic Messages API and OpenAI-compatible. The user wants Mistral AI added as a direct alternative provider with frontier models that support chat completion, tool use, and vision. Mistral's API is OpenAI-compatible (`api.mistral.ai/v1/chat/completions`), making integration straightforward. ## Target Models - **Mistral Large 3** (`mistral-large-2512`) - frontier, vision, tools, 40k ctx - **Mistral Medium 3.1** (`mistral-medium-2508`) - frontier, vision, tools, 40k ctx - **Mistral Small 3.2** (`mistral-small-2506`) - vision, tools, 128k ctx ## Files to Modify ### 1. `src/main/engine/OpenCodeManager.ts` - Core provider logic **A. Add Mistral constants** (near lines 23-25) - `MISTRAL_API_URL = 'https://api.mistral.ai/v1/chat/completions'` - `MISTRAL_MODELS_URL = 'https://api.mistral.ai/v1/models'` **B. Add Mistral models to `MODEL_DISPLAY_NAMES`** (lines 28-69) ``` 'mistral-large-2512': 'Mistral Large 3' 'mistral-medium-2508': 'Mistral Medium 3.1' 'mistral-small-2506': 'Mistral Small 3.2' ``` **C. Update `detectProvider()`** (lines 1839-1845) - Add: `if (id.startsWith('mistral') || id.startsWith('ministral')) return 'mistral';` **D. Add Mistral API key storage** - New field: `private mistralApiKey: string = ''` - New methods: `setMistralApiKey()`, `getMistralApiKey()`, `validateMistralApiKey()` - Load on init from settings key `'mistral_api_key'` **E. Add Mistral request path in `sendMessage()`** - Route `provider === 'mistral'` to new `sendMistralRequest()` method - Similar to OpenAI path but: - URL: `MISTRAL_API_URL` (direct, not through OpenCode gateway) - Auth: `Authorization: Bearer ${this.mistralApiKey}` - No `tool_choice: "required"` — use `"any"` for Mistral's equivalent - Context budget: 35,000 tokens (vs 150k for OpenCode) for 40k-ctx models, 120k for Small 3.2 **F. Vision format for Mistral** - In `view_image` tool result handling: use `image_url` format with base64 data URI - Format: `{ type: 'image_url', image_url: { url: 'data:image/webp;base64,...' } }` - Same as OpenAI path (Mistral is compatible here) **G. Update `getAvailableModels()`** - When Mistral key is set, include Mistral models in returned list - Add `provider` field to model entries so UI can group them **H. Update `analyzeMediaImage()`** (lines 2066-2192) - Support Mistral models for image metadata analysis (title/alt/caption generation) - When a Mistral model is selected, use Mistral vision format (`image_url` with base64 data URI) - Route to `api.mistral.ai` with Mistral API key ### 2. `src/main/engine/ChatEngine.ts` - Settings persistence **A. Add Mistral key helpers** - `getMistralApiKey()` - read from settings table - `setMistralApiKey(key)` - persist to settings table - Settings key: `'mistral_api_key'` ### 3. `src/main/ipc/chatHandlers.ts` - IPC bridge **A. Add Mistral-specific handlers** - `chat:setMistralApiKey` - validate + persist Mistral key - `chat:getMistralApiKey` - return masked key - `chat:validateMistralApiKey` - test key against Mistral API **B. Update `chat:getAvailableModels`** - Include Mistral models when Mistral key is configured - Return provider info per model **C. Update `chat:checkReady`** - Report readiness for both providers independently ### 4. `src/main/shared/electronApi.ts` - Type definitions **A. Extend `ChatModel` interface** - Add `provider: 'opencode' | 'mistral'` field (already optional, ensure populated) **B. Add Mistral IPC methods to `ElectronAPI.chat`** - `setMistralApiKey(key: string)` - `getMistralApiKey()` - `validateMistralApiKey(key: string)` ### 5. `src/renderer/components/SettingsView.tsx` - UI settings **A. Add Mistral API key section** - Separate input field for Mistral API key (below OpenCode key) - Same pattern: masked display, change button, validation on save **B. Update model selector** - Group models by provider in dropdown (optgroup: "OpenCode Zen", "Mistral AI") - Show provider badge next to selected model ### 6. `src/renderer/components/ChatPanel/ChatPanel.tsx` - Chat UI **A. Update model selector in chat** - Group by provider in dropdown - Only show models for configured providers ### 7. Preload/IPC registration **A. `src/main/ipc/handlers.ts` or preload** - Register new Mistral IPC channels - Expose in preload bridge ### 8. MCP Server - `src/main/engine/MCPServer.ts` - No changes needed — MCP server exposes tools for external AI agents to call; no bDS-side AI runs during MCP requests ## Implementation Order 1. Tests first (per AGENTS.md) 2. Types (`electronApi.ts`) 3. Engine (`OpenCodeManager.ts` — constants, detection, key storage, request path) 4. Persistence (`ChatEngine.ts` — settings helpers) 5. IPC (`chatHandlers.ts` — new handlers) 6. UI (`SettingsView.tsx`, `ChatPanel.tsx` — key input, model grouping) 7. Build verification ## Key Differences to Handle | Aspect | OpenCode/OpenAI | Mistral | |--------|----------------|---------| | Base URL | `opencode.ai/zen/v1/...` | `api.mistral.ai/v1/...` | | Auth header | `Bearer ${openCodeKey}` | `Bearer ${mistralKey}` | | Tool choice forced | `"required"` | `"any"` | | Parallel tools | not set | `parallel_tool_calls: true` | | Context budget | 150k tokens | 35k (Large/Medium), 120k (Small) | | Vision format | `image_url` block | `image_url` block (same) | | Streaming | SSE deltas | SSE deltas (same) | ## Verification 1. Run `npm test` — all existing + new tests pass 2. Run `npm run build` — clean build 3. Manual: set Mistral API key in Settings, verify validation 4. Manual: select Mistral Large 3, send chat message, verify response streams 5. Manual: use `view_image` tool in chat with Mistral model, verify vision works 6. Manual: verify tool calling works (search_posts, list_posts, etc.) 7. Manual: verify OpenCode models still work unchanged ## Resolved Decisions 1. **`analyzeMediaImage()`** — Mistral models will be usable for image metadata analysis 2. **MCP server** — N/A; MCP server only exposes tools, no bDS-side AI runs during MCP requests 3. **Model dropdown grouping** — Use `` labels ("OpenCode Zen", "Mistral AI")