Fix Story 12: Claude API key storage now working
- Fixed silent API key save failure by switching from keyring to Tauri store - Removed keyring dependency (didn't work in macOS dev mode for unsigned apps) - Implemented reliable cross-platform storage using tauri-plugin-store - Added pendingMessageRef to preserve user message during API key dialog flow - Refactored sendMessage to accept optional message parameter for retry - Removed all debug logging and test code - Removed unused entitlements.plist and macOS config - API key now persists correctly between sessions - Auto-retry after saving key works properly Story 12 complete and archived.
This commit is contained in:
117
.living_spec/stories/archive/12_be_able_to_use_claude.md
Normal file
117
.living_spec/stories/archive/12_be_able_to_use_claude.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Story 12: Be Able to Use Claude
|
||||
|
||||
## User Story
|
||||
As a user, I want to be able to select Claude (via Anthropic API) as my LLM provider so I can use Claude models instead of only local Ollama models.
|
||||
|
||||
## Acceptance Criteria
|
||||
- [x] Claude models appear in the unified model dropdown (same dropdown as Ollama models)
|
||||
- [x] Dropdown is organized with section headers: "Anthropic" and "Ollama" with models listed under each
|
||||
- [x] When user first selects a Claude model, a dialog prompts for Anthropic API key
|
||||
- [x] API key is stored securely (using Tauri store plugin for reliable cross-platform storage)
|
||||
- [x] Provider is auto-detected from model name (starts with `claude-` = Anthropic, otherwise = Ollama)
|
||||
- [x] Chat requests route to Anthropic API when Claude model is selected
|
||||
- [x] Streaming responses work with Claude (token-by-token display)
|
||||
- [x] Tool calling works with Claude (using Anthropic's tool format)
|
||||
- [x] Context window calculation accounts for Claude models (200k tokens)
|
||||
- [x] User's model selection persists between sessions
|
||||
- [x] Clear error messages if API key is missing or invalid
|
||||
|
||||
## Out of Scope
|
||||
- Support for other providers (OpenAI, Google, etc.) - can be added later
|
||||
- API key management UI (rotation, multiple keys, view/edit key after initial entry)
|
||||
- Cost tracking or usage monitoring
|
||||
- Model fine-tuning or custom models
|
||||
- Switching models mid-conversation (user can start new session)
|
||||
- Fetching available Claude models from API (hardcoded list is fine)
|
||||
|
||||
## Technical Notes
|
||||
- Anthropic API endpoint: `https://api.anthropic.com/v1/messages`
|
||||
- API key should be stored securely (environment variable or secure storage)
|
||||
- Claude models support tool use (function calling)
|
||||
- Context windows: claude-3-5-sonnet (200k), claude-3-5-haiku (200k)
|
||||
- Streaming uses Server-Sent Events (SSE)
|
||||
- Tool format differs from OpenAI/Ollama - needs conversion
|
||||
|
||||
## Design Considerations
|
||||
- Single unified model dropdown with section headers ("Anthropic", "Ollama")
|
||||
- Use `<optgroup>` in HTML select for visual grouping
|
||||
- API key dialog appears on-demand (first use of Claude model)
|
||||
- Store API key in OS keychain using `keyring` crate (cross-platform)
|
||||
- Backend auto-detects provider from model name pattern
|
||||
- Handle API key in backend only (don't expose to frontend logs)
|
||||
- Alphabetical sorting within each provider section
|
||||
|
||||
## Implementation Approach
|
||||
|
||||
### Backend (Rust)
|
||||
1. Add `anthropic` feature/module for Claude API client
|
||||
2. Create `AnthropicClient` with streaming support
|
||||
3. Convert tool definitions to Anthropic format
|
||||
4. Handle Anthropic streaming response format
|
||||
5. Add API key storage (encrypted or environment variable)
|
||||
|
||||
### Frontend (TypeScript)
|
||||
1. Add hardcoded list of Claude models (claude-3-5-sonnet-20241022, claude-3-5-haiku-20241022)
|
||||
2. Merge Ollama and Claude models into single dropdown with `<optgroup>` sections
|
||||
3. Create API key input dialog/modal component
|
||||
4. Trigger API key dialog when Claude model selected and no key stored
|
||||
5. Add Tauri command to check if API key exists in keychain
|
||||
6. Add Tauri command to set API key in keychain
|
||||
7. Update context window calculations for Claude models (200k tokens)
|
||||
|
||||
### API Differences
|
||||
- Anthropic uses `messages` array format (similar to OpenAI)
|
||||
- Tools are called `tools` with different schema
|
||||
- Streaming events have different structure
|
||||
- Need to map our tool format to Anthropic's format
|
||||
|
||||
## Security Considerations
|
||||
- API key stored in OS keychain (not in files or environment variables)
|
||||
- Use `keyring` crate for cross-platform secure storage
|
||||
- Never log API key in console or files
|
||||
- Backend validates API key format before making requests
|
||||
- Handle API errors gracefully (rate limits, invalid key, network errors)
|
||||
- API key only accessible to the app process
|
||||
|
||||
## UI Flow
|
||||
1. User opens model dropdown → sees "Anthropic" section with Claude models, "Ollama" section with local models
|
||||
2. User selects `claude-3-5-sonnet-20241022`
|
||||
3. Backend checks Tauri store for saved API key
|
||||
4. If not found → Frontend shows dialog: "Enter your Anthropic API key"
|
||||
5. User enters key → Backend stores in Tauri store (persistent JSON file)
|
||||
6. Chat proceeds with Anthropic API
|
||||
7. Future sessions: API key auto-loaded from store (no prompt)
|
||||
|
||||
## Implementation Notes (Completed)
|
||||
|
||||
### Storage Solution
|
||||
Initially attempted to use the `keyring` crate for OS keychain integration, but encountered issues in macOS development mode:
|
||||
- Unsigned Tauri apps in dev mode cannot reliably access the system keychain
|
||||
- The `keyring` crate reported successful saves but keys were not persisting
|
||||
- No macOS keychain permission dialogs appeared
|
||||
|
||||
**Solution:** Switched to Tauri's `store` plugin (`tauri-plugin-store`)
|
||||
- Provides reliable cross-platform persistent storage
|
||||
- Stores data in a JSON file managed by Tauri
|
||||
- Works consistently in both development and production builds
|
||||
- Simpler implementation without platform-specific entitlements
|
||||
|
||||
### Key Files Modified
|
||||
- `src-tauri/src/commands/chat.rs`: API key storage/retrieval using Tauri store
|
||||
- `src/components/Chat.tsx`: API key dialog and flow with pending message preservation
|
||||
- `src-tauri/Cargo.toml`: Removed `keyring` dependency, kept `tauri-plugin-store`
|
||||
- `src-tauri/src/llm/anthropic.rs`: Anthropic API client with streaming support
|
||||
|
||||
### Frontend Implementation
|
||||
- Added `pendingMessageRef` to preserve user's message when API key dialog is shown
|
||||
- Modified `sendMessage()` to accept optional message parameter for retry scenarios
|
||||
- API key dialog appears on first Claude model usage
|
||||
- After saving key, automatically retries sending the pending message
|
||||
|
||||
### Backend Implementation
|
||||
- `get_anthropic_api_key_exists()`: Checks if API key exists in store
|
||||
- `set_anthropic_api_key()`: Saves API key to store with verification
|
||||
- `get_anthropic_api_key()`: Retrieves API key for Anthropic API calls
|
||||
- Provider auto-detection based on `claude-` model name prefix
|
||||
- Tool format conversion from internal format to Anthropic's schema
|
||||
- SSE streaming implementation for real-time token display
|
||||
Reference in New Issue
Block a user