-
Notifications
You must be signed in to change notification settings - Fork 235
api key dialog #31
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
Merged
Merged
api key dialog #31
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import { NextRequest, NextResponse } from 'next/server' | ||
| import { getUserApiKey } from '@/lib/api-keys/user-keys' | ||
|
|
||
| type Provider = 'openai' | 'gemini' | 'cursor' | 'anthropic' | 'aigateway' | ||
|
|
||
| // Map agents to their required providers | ||
| const AGENT_PROVIDER_MAP: Record<string, Provider> = { | ||
| claude: 'anthropic', | ||
| codex: 'aigateway', // Codex uses Vercel AI Gateway | ||
| cursor: 'cursor', | ||
| gemini: 'gemini', | ||
| opencode: 'openai', // OpenCode can use OpenAI or Anthropic, but primarily OpenAI | ||
| } | ||
|
|
||
| // Check if a model is an Anthropic model | ||
| function isAnthropicModel(model: string): boolean { | ||
| const anthropicPatterns = ['claude', 'sonnet', 'opus'] | ||
| const lowerModel = model.toLowerCase() | ||
| return anthropicPatterns.some((pattern) => lowerModel.includes(pattern)) | ||
| } | ||
|
|
||
| // Check if a model is an OpenAI model | ||
| function isOpenAIModel(model: string): boolean { | ||
| const openaiPatterns = ['gpt', 'openai'] | ||
| const lowerModel = model.toLowerCase() | ||
| return openaiPatterns.some((pattern) => lowerModel.includes(pattern)) | ||
| } | ||
|
|
||
| // Check if a model is a Gemini model | ||
| function isGeminiModel(model: string): boolean { | ||
| const geminiPatterns = ['gemini'] | ||
| const lowerModel = model.toLowerCase() | ||
| return geminiPatterns.some((pattern) => lowerModel.includes(pattern)) | ||
| } | ||
|
|
||
| export async function GET(req: NextRequest) { | ||
| try { | ||
| const { searchParams } = new URL(req.url) | ||
| const agent = searchParams.get('agent') | ||
| const model = searchParams.get('model') | ||
|
|
||
| if (!agent) { | ||
| return NextResponse.json({ error: 'Agent parameter is required' }, { status: 400 }) | ||
| } | ||
|
|
||
| let provider = AGENT_PROVIDER_MAP[agent] | ||
| if (!provider) { | ||
| return NextResponse.json({ error: 'Invalid agent' }, { status: 400 }) | ||
| } | ||
|
|
||
| // Override provider based on model for multi-provider agents | ||
| if (model && (agent === 'cursor' || agent === 'opencode')) { | ||
| if (isAnthropicModel(model)) { | ||
| provider = 'anthropic' | ||
| } else if (isGeminiModel(model)) { | ||
| provider = 'gemini' | ||
| } else if (isOpenAIModel(model)) { | ||
| // For OpenAI models, prefer AI Gateway if available, otherwise use OpenAI | ||
| provider = 'aigateway' | ||
| } | ||
| // For cursor with no recognizable pattern, keep the default 'cursor' provider | ||
| } | ||
|
|
||
| // Check if API key is available (either user's or system) | ||
| const apiKey = await getUserApiKey(provider) | ||
| const hasKey = !!apiKey | ||
|
|
||
| return NextResponse.json({ | ||
| success: true, | ||
| hasKey, | ||
| provider, | ||
| agentName: agent.charAt(0).toUpperCase() + agent.slice(1), | ||
| }) | ||
| } catch (error) { | ||
| console.error('Error checking API key:', error) | ||
| return NextResponse.json({ error: 'Failed to check API key' }, { status: 500 }) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing response status check before accessing API response data, causing error responses to show "undefined API key required" instead of proper error messages.
View Details
📝 Patch Details
Analysis
Missing response status check in API key validation causes misleading error messages
What fails:
components/task-form.tsxhandleSubmit() callsresponse.json()without checkingresponse.ok, causing error responses to be processed as valid dataHow to reproduce:
Result: When API returns
{ error: 'Invalid agent' }(status 400),data.hasKeyisundefined, so the code shows toast: "undefined API key required" with description "Please add your undefined API key to use the undefined agent with this model."Expected: Should check
response.okfirst (following Fetch API pattern used in 21 other locations in codebase including line 251 of same file), show proper error message from API response