-
Notifications
You must be signed in to change notification settings - Fork 51
Pass API keys for docker build #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,7 @@ import { LLMBaseProvider } from './LLMProvider.js'; | |||||||||||||||||||||||||||||||||||||
| import { LLMRetryManager } from './LLMErrorHandler.js'; | ||||||||||||||||||||||||||||||||||||||
| import { LLMResponseParser } from './LLMResponseParser.js'; | ||||||||||||||||||||||||||||||||||||||
| import { createLogger } from '../core/Logger.js'; | ||||||||||||||||||||||||||||||||||||||
| import { getEnvironmentConfig } from '../core/EnvironmentConfig.js'; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const logger = createLogger('GroqProvider'); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
@@ -38,10 +39,29 @@ export class GroqProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| readonly name: LLMProvider = 'groq'; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| private readonly envConfig = getEnvironmentConfig(); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| constructor(private readonly apiKey: string) { | ||||||||||||||||||||||||||||||||||||||
| super(); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||
| * Get the API key with fallback hierarchy: | ||||||||||||||||||||||||||||||||||||||
| * 1. Constructor parameter (for backward compatibility) | ||||||||||||||||||||||||||||||||||||||
| * 2. localStorage (user-configured) | ||||||||||||||||||||||||||||||||||||||
| * 3. Build-time environment config | ||||||||||||||||||||||||||||||||||||||
| * 4. Empty string | ||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||
| private getApiKey(): string { | ||||||||||||||||||||||||||||||||||||||
| // Constructor parameter (highest priority for backward compatibility) | ||||||||||||||||||||||||||||||||||||||
| if (this.getApiKey() && this.getApiKey().trim() !== '') { | ||||||||||||||||||||||||||||||||||||||
| return this.getApiKey().trim(); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // Use environment config which handles localStorage -> build-time -> empty fallback | ||||||||||||||||||||||||||||||||||||||
| return this.envConfig.getApiKey('groq'); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix infinite recursion in getApiKey().
private getApiKey(): string {
// Constructor parameter (highest priority for backward compatibility)
- if (this.getApiKey() && this.getApiKey().trim() !== '') {
- return this.getApiKey().trim();
+ if (this.apiKey && this.apiKey.trim() !== '') {
+ return this.apiKey.trim();
}
// Use environment config which handles localStorage -> build-time -> empty fallback
- return this.envConfig.getApiKey('groq');
+ return this.envConfig.getApiKey('groq')?.trim() ?? '';
}📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 60-60: Trailing spaces not allowed. (@stylistic/no-trailing-spaces) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||
| * Get the chat completions endpoint URL | ||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -92,7 +112,7 @@ export class GroqProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||||
| method: 'POST', | ||||||||||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||||||||||
| 'Content-Type': 'application/json', | ||||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.apiKey}`, | ||||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.getApiKey()}`, | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
114
to
116
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Unquote Authorization header and guard against empty key.
- 'Authorization': `Bearer ${this.getApiKey()}`,
+ Authorization: (() => {
+ const k = this.getApiKey();
+ if (!k) throw new Error('Groq API key is missing. Configure it in Settings.');
+ return `Bearer ${k}`;
+ })(),- 'Authorization': `Bearer ${this.getApiKey()}`,
+ Authorization: (() => {
+ const k = this.getApiKey();
+ if (!k) throw new Error('Groq API key is missing. Configure it in Settings.');
+ return `Bearer ${k}`;
+ })(),Also applies to: 281-283 🧰 Tools🪛 ESLint[error] 115-115: Unnecessarily quoted property 'Authorization' found. (@stylistic/quote-props) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| body: JSON.stringify(payloadBody), | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -259,7 +279,7 @@ export class GroqProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||||
| const response = await fetch(this.getModelsEndpoint(), { | ||||||||||||||||||||||||||||||||||||||
| method: 'GET', | ||||||||||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.apiKey}`, | ||||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.getApiKey()}`, | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
@@ -432,29 +452,15 @@ export class GroqProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||||
| * Validate that required credentials are available for Groq | ||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||
| validateCredentials(): {isValid: boolean, message: string, missingItems?: string[]} { | ||||||||||||||||||||||||||||||||||||||
| const storageKeys = this.getCredentialStorageKeys(); | ||||||||||||||||||||||||||||||||||||||
| const apiKey = localStorage.getItem(storageKeys.apiKey!); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if (!apiKey) { | ||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||
| isValid: false, | ||||||||||||||||||||||||||||||||||||||
| message: 'Groq API key is required. Please add your API key in Settings.', | ||||||||||||||||||||||||||||||||||||||
| missingItems: ['API Key'] | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||
| isValid: true, | ||||||||||||||||||||||||||||||||||||||
| message: 'Groq credentials are configured correctly.' | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
| return this.envConfig.validateCredentials('groq'); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||
| * Get the storage keys this provider uses for credentials | ||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||
| getCredentialStorageKeys(): {apiKey: string} { | ||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||
| apiKey: 'ai_chat_groq_api_key' | ||||||||||||||||||||||||||||||||||||||
| apiKey: this.envConfig.getStorageKey('groq') | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,7 @@ import { LLMBaseProvider } from './LLMProvider.js'; | |||||||||||||||||||
| import { LLMRetryManager } from './LLMErrorHandler.js'; | ||||||||||||||||||||
| import { LLMResponseParser } from './LLMResponseParser.js'; | ||||||||||||||||||||
| import { createLogger } from '../core/Logger.js'; | ||||||||||||||||||||
| import { getEnvironmentConfig } from '../core/EnvironmentConfig.js'; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const logger = createLogger('OpenAIProvider'); | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
@@ -42,10 +43,29 @@ export class OpenAIProvider extends LLMBaseProvider { | |||||||||||||||||||
|
|
||||||||||||||||||||
| readonly name: LLMProvider = 'openai'; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| private readonly envConfig = getEnvironmentConfig(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| constructor(private readonly apiKey: string) { | ||||||||||||||||||||
| super(); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** | ||||||||||||||||||||
| * Get the API key with fallback hierarchy: | ||||||||||||||||||||
| * 1. Constructor parameter (for backward compatibility) | ||||||||||||||||||||
| * 2. localStorage (user-configured) | ||||||||||||||||||||
| * 3. Build-time environment config | ||||||||||||||||||||
| * 4. Empty string | ||||||||||||||||||||
| */ | ||||||||||||||||||||
| private getApiKey(): string { | ||||||||||||||||||||
| // Constructor parameter (highest priority for backward compatibility) | ||||||||||||||||||||
| if (this.apiKey && this.apiKey.trim() !== '') { | ||||||||||||||||||||
| return this.apiKey.trim(); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Use environment config which handles localStorage -> build-time -> empty fallback | ||||||||||||||||||||
| return this.envConfig.getApiKey('openai'); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** | ||||||||||||||||||||
| * Determines the model family based on the model name | ||||||||||||||||||||
| */ | ||||||||||||||||||||
|
|
@@ -280,7 +300,7 @@ export class OpenAIProvider extends LLMBaseProvider { | |||||||||||||||||||
| metadata: { | ||||||||||||||||||||
| provider: 'openai', | ||||||||||||||||||||
| errorType: 'api_error', | ||||||||||||||||||||
| hasApiKey: !!this.apiKey | ||||||||||||||||||||
| hasApiKey: !!this.getApiKey() | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }, context.traceId); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
@@ -299,7 +319,7 @@ export class OpenAIProvider extends LLMBaseProvider { | |||||||||||||||||||
| method: 'POST', | ||||||||||||||||||||
| headers: { | ||||||||||||||||||||
| 'Content-Type': 'application/json', | ||||||||||||||||||||
| Authorization: `Bearer ${this.apiKey}`, | ||||||||||||||||||||
| Authorization: `Bearer ${this.getApiKey()}`, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
|
Comment on lines
321
to
323
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid sending empty Authorization header. If no key is present, fail fast with a clear error instead of - Authorization: `Bearer ${this.getApiKey()}`,
+ ...(this.getApiKey()
+ ? { Authorization: `Bearer ${this.getApiKey()}` }
+ : (() => { throw new Error('OpenAI API key is missing. Configure it in Settings.'); })()),📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
| body: JSON.stringify(payloadBody), | ||||||||||||||||||||
| }); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,7 @@ import { LLMBaseProvider } from './LLMProvider.js'; | |||||||||||||||||||||||||||||||||||
| import { LLMRetryManager } from './LLMErrorHandler.js'; | ||||||||||||||||||||||||||||||||||||
| import { LLMResponseParser } from './LLMResponseParser.js'; | ||||||||||||||||||||||||||||||||||||
| import { createLogger } from '../core/Logger.js'; | ||||||||||||||||||||||||||||||||||||
| import { getEnvironmentConfig } from '../core/EnvironmentConfig.js'; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const logger = createLogger('OpenRouterProvider'); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
@@ -59,10 +60,29 @@ export class OpenRouterProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||
| private visionModelsCacheExpiry: number = 0; | ||||||||||||||||||||||||||||||||||||
| private static readonly CACHE_DURATION_MS = 30 * 60 * 1000; // 30 minutes | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| private readonly envConfig = getEnvironmentConfig(); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| constructor(private readonly apiKey: string) { | ||||||||||||||||||||||||||||||||||||
| super(); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * Get the API key with fallback hierarchy: | ||||||||||||||||||||||||||||||||||||
| * 1. Constructor parameter (for backward compatibility) | ||||||||||||||||||||||||||||||||||||
| * 2. localStorage (user-configured) | ||||||||||||||||||||||||||||||||||||
| * 3. Build-time environment config | ||||||||||||||||||||||||||||||||||||
| * 4. Empty string | ||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||
| private getApiKey(): string { | ||||||||||||||||||||||||||||||||||||
| // Constructor parameter (highest priority for backward compatibility) | ||||||||||||||||||||||||||||||||||||
| if (this.apiKey && this.apiKey.trim() !== '') { | ||||||||||||||||||||||||||||||||||||
| return this.apiKey.trim(); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Use environment config which handles localStorage -> build-time -> empty fallback | ||||||||||||||||||||||||||||||||||||
| return this.envConfig.getApiKey('openrouter'); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * Check if a model doesn't support temperature parameter | ||||||||||||||||||||||||||||||||||||
| * OpenAI's GPT-5, O3, and O4 models accessed through OpenRouter don't support temperature | ||||||||||||||||||||||||||||||||||||
|
|
@@ -144,7 +164,7 @@ export class OpenRouterProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||
| method: 'POST', | ||||||||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||||||||
| 'Content-Type': 'application/json', | ||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.apiKey}`, | ||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.getApiKey()}`, | ||||||||||||||||||||||||||||||||||||
| 'HTTP-Referer': 'https://browseroperator.io', // Site URL for rankings on openrouter.ai | ||||||||||||||||||||||||||||||||||||
| 'X-Title': 'Browser Operator', // Site title for rankings on openrouter.ai | ||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
166
to
170
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid empty Bearer token; unquote Authorization header. - headers: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${this.getApiKey()}`,
- 'HTTP-Referer': 'https://browseroperator.io', // Site URL for rankings on openrouter.ai
- 'X-Title': 'Browser Operator', // Site title for rankings on openrouter.ai
- },
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: (() => {
+ const k = this.getApiKey()?.trim();
+ if (!k) throw new Error('OpenRouter API key is missing. Configure it in Settings.');
+ return `Bearer ${k}`;
+ })(),
+ 'HTTP-Referer': 'https://browseroperator.io',
+ 'X-Title': 'Browser Operator',
+ },📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 167-167: Unnecessarily quoted property 'Authorization' found. (@stylistic/quote-props) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
|
|
@@ -324,7 +344,7 @@ export class OpenRouterProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||
| const response = await fetch(this.getToolSupportingModelsEndpoint(), { | ||||||||||||||||||||||||||||||||||||
| method: 'GET', | ||||||||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.apiKey}`, | ||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.getApiKey()}`, | ||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
344
to
349
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Same Authorization fix for fetchModels(). - headers: {
- 'Authorization': `Bearer ${this.getApiKey()}`,
- },
+ headers: {
+ Authorization: (() => {
+ const k = this.getApiKey()?.trim();
+ if (!k) throw new Error('OpenRouter API key is missing. Configure it in Settings.');
+ return `Bearer ${k}`;
+ })(),
+ },📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 347-347: Unnecessarily quoted property 'Authorization' found. (@stylistic/quote-props) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
@@ -358,7 +378,7 @@ export class OpenRouterProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||
| const response = await fetch(this.getVisionModelsEndpoint(), { | ||||||||||||||||||||||||||||||||||||
| method: 'GET', | ||||||||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.apiKey}`, | ||||||||||||||||||||||||||||||||||||
| 'Authorization': `Bearer ${this.getApiKey()}`, | ||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
@@ -621,15 +641,21 @@ export class OpenRouterProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||
| logger.debug('=== VALIDATING OPENROUTER CREDENTIALS ==='); | ||||||||||||||||||||||||||||||||||||
| logger.debug('Timestamp:', new Date().toISOString()); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const storageKeys = this.getCredentialStorageKeys(); | ||||||||||||||||||||||||||||||||||||
| logger.debug('Storage keys:', storageKeys); | ||||||||||||||||||||||||||||||||||||
| // Use the new environment config for validation | ||||||||||||||||||||||||||||||||||||
| const validationResult = this.envConfig.validateCredentials('openrouter'); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Enhanced logging for debugging | ||||||||||||||||||||||||||||||||||||
| const apiKey = this.getApiKey(); | ||||||||||||||||||||||||||||||||||||
| const source = this.envConfig.getApiKeySource('openrouter'); | ||||||||||||||||||||||||||||||||||||
| const buildInfo = this.envConfig.getBuildInfo(); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const apiKey = localStorage.getItem(storageKeys.apiKey!); | ||||||||||||||||||||||||||||||||||||
| logger.debug('API key check:'); | ||||||||||||||||||||||||||||||||||||
| logger.debug('- Storage key used:', storageKeys.apiKey); | ||||||||||||||||||||||||||||||||||||
| logger.debug('- API key exists:', !!apiKey); | ||||||||||||||||||||||||||||||||||||
| logger.debug('- API key length:', apiKey?.length || 0); | ||||||||||||||||||||||||||||||||||||
| logger.debug('- API key prefix:', apiKey?.substring(0, 8) + '...' || 'none'); | ||||||||||||||||||||||||||||||||||||
| logger.debug('- API key source:', source); | ||||||||||||||||||||||||||||||||||||
| logger.debug('- Build config available:', buildInfo.hasBuildConfig); | ||||||||||||||||||||||||||||||||||||
| logger.debug('- Build time:', buildInfo.buildTime); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||
| // Also check OAuth-related storage for debugging | ||||||||||||||||||||||||||||||||||||
| const authMethod = localStorage.getItem('openrouter_auth_method'); | ||||||||||||||||||||||||||||||||||||
|
|
@@ -638,37 +664,22 @@ export class OpenRouterProvider extends LLMBaseProvider { | |||||||||||||||||||||||||||||||||||
| logger.debug('- Auth method:', authMethod); | ||||||||||||||||||||||||||||||||||||
| logger.debug('- OAuth token exists:', !!oauthToken); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Check all OpenRouter-related localStorage keys | ||||||||||||||||||||||||||||||||||||
| const allKeys = Object.keys(localStorage); | ||||||||||||||||||||||||||||||||||||
| const openRouterKeys = allKeys.filter(key => key.includes('openrouter') || key.includes('ai_chat')); | ||||||||||||||||||||||||||||||||||||
| logger.debug('All OpenRouter-related storage keys:'); | ||||||||||||||||||||||||||||||||||||
| openRouterKeys.forEach(key => { | ||||||||||||||||||||||||||||||||||||
| const value = localStorage.getItem(key); | ||||||||||||||||||||||||||||||||||||
| logger.debug(`- ${key}:`, value?.substring(0, 50) + (value && value.length > 50 ? '...' : '') || 'null'); | ||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (!apiKey) { | ||||||||||||||||||||||||||||||||||||
| if (validationResult.isValid) { | ||||||||||||||||||||||||||||||||||||
| logger.info('✅ OpenRouter credentials validation passed'); | ||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||
| logger.warn('❌ OpenRouter API key missing'); | ||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||
| isValid: false, | ||||||||||||||||||||||||||||||||||||
| message: 'OpenRouter API key is required. Please add your API key in Settings.', | ||||||||||||||||||||||||||||||||||||
| missingItems: ['API Key'] | ||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| logger.info('✅ OpenRouter credentials validation passed'); | ||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||
| isValid: true, | ||||||||||||||||||||||||||||||||||||
| message: 'OpenRouter credentials are configured correctly.' | ||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||
| return validationResult; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * Get the storage keys this provider uses for credentials | ||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||
| getCredentialStorageKeys(): {apiKey: string} { | ||||||||||||||||||||||||||||||||||||
| const storageKey = this.envConfig.getStorageKey('openrouter'); | ||||||||||||||||||||||||||||||||||||
| const keys = { | ||||||||||||||||||||||||||||||||||||
| apiKey: 'ai_chat_openrouter_api_key' | ||||||||||||||||||||||||||||||||||||
| apiKey: storageKey | ||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||
| logger.debug('OpenRouter credential storage keys:', keys); | ||||||||||||||||||||||||||||||||||||
| return keys; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.