fix(profiles): support API profiles in auth check and model resolution (#608)
* fix(profiles): support API profiles in auth check and model resolution - useClaudeTokenCheck() now checks for active API profile in addition to OAuth token, preventing unnecessary OAuth prompts when using custom Anthropic-compatible endpoints - agent-queue.ts now passes model shorthand (opus/sonnet/haiku) to backend instead of resolved full model ID, allowing backend to use API profile's custom model mappings via env vars Fixes issue where Ideation/Roadmap would prompt for OAuth even when a valid API profile was configured and active. * Refactor token check with useCallback in EnvConfigModal Wrapped the checkToken function in useCallback and updated useEffect dependencies to use checkToken instead of activeProfileId. * Improve error handling in Claude token check hook Adds logic to set an error message if the OAuth token check fails and there is no API profile fallback. * Refactor API profile check in useClaudeTokenCheck Simplifies the logic for determining if an API profile exists by computing hasAPIProfile once using the closure-captured activeProfileId. --------- Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
5005e56e46
commit
78aceaed1e
@@ -7,7 +7,6 @@ import { AgentEvents } from './agent-events';
|
||||
import { AgentProcessManager } from './agent-process';
|
||||
import { RoadmapConfig } from './types';
|
||||
import type { IdeationConfig, Idea } from '../../shared/types';
|
||||
import { MODEL_ID_MAP } from '../../shared/constants';
|
||||
import { detectRateLimit, createSDKRateLimitInfo, getProfileEnv } from '../rate-limit-detector';
|
||||
import { getAPIProfileEnv } from '../services/profile';
|
||||
import { getOAuthModeClearVars } from './env-utils';
|
||||
@@ -96,9 +95,9 @@ export class AgentQueueManager {
|
||||
}
|
||||
|
||||
// Add model and thinking level from config
|
||||
// Pass shorthand (opus/sonnet/haiku) - backend resolves using API profile env vars
|
||||
if (config?.model) {
|
||||
const modelId = MODEL_ID_MAP[config.model] || MODEL_ID_MAP['opus'];
|
||||
args.push('--model', modelId);
|
||||
args.push('--model', config.model);
|
||||
}
|
||||
if (config?.thinkingLevel) {
|
||||
args.push('--thinking-level', config.thinkingLevel);
|
||||
@@ -172,9 +171,9 @@ export class AgentQueueManager {
|
||||
}
|
||||
|
||||
// Add model and thinking level from config
|
||||
// Pass shorthand (opus/sonnet/haiku) - backend resolves using API profile env vars
|
||||
if (config.model) {
|
||||
const modelId = MODEL_ID_MAP[config.model] || MODEL_ID_MAP['opus'];
|
||||
args.push('--model', modelId);
|
||||
args.push('--model', config.model);
|
||||
}
|
||||
if (config.thinkingLevel) {
|
||||
args.push('--thinking-level', config.thinkingLevel);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import {
|
||||
AlertCircle,
|
||||
Key,
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
ChevronDown,
|
||||
ChevronRight
|
||||
} from 'lucide-react';
|
||||
import { useSettingsStore } from '../stores/settings-store';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -592,35 +593,51 @@ export function EnvConfigModal({
|
||||
/**
|
||||
* Hook to check if the Claude token is configured
|
||||
* Returns { hasToken, isLoading, checkToken }
|
||||
*
|
||||
* This combines two sources of authentication:
|
||||
* 1. OAuth token from source .env (checked via checkSourceToken)
|
||||
* 2. Active API profile (custom Anthropic-compatible endpoint)
|
||||
*/
|
||||
export function useClaudeTokenCheck() {
|
||||
const [hasToken, setHasToken] = useState<boolean | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const checkToken = async () => {
|
||||
// Get active API profile from settings store
|
||||
const activeProfileId = useSettingsStore((state) => state.activeProfileId);
|
||||
|
||||
const checkToken = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
// Compute once - activeProfileId is captured from closure
|
||||
const hasAPIProfile = !!activeProfileId;
|
||||
|
||||
try {
|
||||
const result = await window.electronAPI.checkSourceToken();
|
||||
if (result.success && result.data) {
|
||||
setHasToken(result.data.hasToken);
|
||||
} else {
|
||||
setHasToken(false);
|
||||
const hasSourceOAuthToken = result.success && result.data?.hasToken;
|
||||
|
||||
// Auth is valid if either OAuth token OR API profile exists
|
||||
setHasToken(hasSourceOAuthToken || hasAPIProfile);
|
||||
|
||||
// Set error if OAuth check failed and no API profile fallback
|
||||
if (!result.success && !hasAPIProfile) {
|
||||
setError(result.error || 'Failed to check token');
|
||||
}
|
||||
} catch (err) {
|
||||
setHasToken(false);
|
||||
setError(err instanceof Error ? err.message : 'Unknown error');
|
||||
// Even if OAuth check fails, API profile is still valid auth
|
||||
setHasToken(hasAPIProfile);
|
||||
if (!hasAPIProfile) {
|
||||
setError(err instanceof Error ? err.message : 'Unknown error');
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
}, [activeProfileId]);
|
||||
|
||||
useEffect(() => {
|
||||
checkToken();
|
||||
}, []);
|
||||
}, [checkToken]); // Re-check when checkToken changes (i.e., when activeProfileId changes)
|
||||
|
||||
return { hasToken, isLoading, error, checkToken };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user