mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 12:14:19 +00:00
fix(image-analysis): preview backend status safely
This commit is contained in:
1 parent
665668579d
commit
d394772f7c
10 files changed
+507
-26
No files matched your search
+44
-1
@@ -1013,12 +1013,55 @@ async function main(): Promise<void> {
|
||||
}
|
||||
|
||||
const webSearchEnv = getWebSearchHookEnv();
|
||||
const imageAnalysisEnv = getImageAnalysisHookEnv({
|
||||
let imageAnalysisEnv = getImageAnalysisHookEnv({
|
||||
profileName: profileInfo.name,
|
||||
profileType: profileInfo.type,
|
||||
settings,
|
||||
cliproxyBridge,
|
||||
});
|
||||
|
||||
const imageAnalysisProvider = imageAnalysisEnv['CCS_CURRENT_PROVIDER'];
|
||||
if (
|
||||
resolvedTarget === 'claude' &&
|
||||
imageAnalysisEnv['CCS_IMAGE_ANALYSIS_SKIP'] !== '1' &&
|
||||
imageAnalysisProvider
|
||||
) {
|
||||
const verboseProxyLaunch =
|
||||
remainingArgs.includes('--verbose') ||
|
||||
remainingArgs.includes('-v') ||
|
||||
targetRemainingArgs.includes('--verbose') ||
|
||||
targetRemainingArgs.includes('-v');
|
||||
|
||||
if (!isAuthenticated(imageAnalysisProvider as CLIProxyProvider)) {
|
||||
console.error(
|
||||
info(
|
||||
`Image analysis via ${imageAnalysisProvider} is configured, but CLIProxy auth is missing. This session will use native Read. Run "ccs ${imageAnalysisProvider} --auth" to enable it.`
|
||||
)
|
||||
);
|
||||
imageAnalysisEnv = {
|
||||
...imageAnalysisEnv,
|
||||
CCS_CURRENT_PROVIDER: '',
|
||||
CCS_IMAGE_ANALYSIS_SKIP: '1',
|
||||
};
|
||||
} else {
|
||||
const ensureServiceResult = await ensureCliproxyService(
|
||||
CLIPROXY_DEFAULT_PORT,
|
||||
verboseProxyLaunch
|
||||
);
|
||||
if (!ensureServiceResult.started) {
|
||||
console.error(
|
||||
warn(
|
||||
`Image analysis via ${imageAnalysisProvider} is unavailable because CCS could not start the local CLIProxy service. This session will use native Read.`
|
||||
)
|
||||
);
|
||||
imageAnalysisEnv = {
|
||||
...imageAnalysisEnv,
|
||||
CCS_CURRENT_PROVIDER: '',
|
||||
CCS_IMAGE_ANALYSIS_SKIP: '1',
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get global env vars (DISABLE_TELEMETRY, etc.) for third-party profiles
|
||||
const globalEnvConfig = getGlobalEnvConfig();
|
||||
const globalEnv = globalEnvConfig.enabled ? globalEnvConfig.env : {};
|
||||
|
||||
@@ -292,6 +292,17 @@ function resolveBackend(
|
||||
};
|
||||
}
|
||||
|
||||
const hasDirectAnthropicApiKey = Boolean(settings?.env?.ANTHROPIC_API_KEY?.trim());
|
||||
const hasBaseUrl = Boolean(settings?.env?.ANTHROPIC_BASE_URL?.trim());
|
||||
if (hasDirectAnthropicApiKey && !hasBaseUrl) {
|
||||
return {
|
||||
backendId: null,
|
||||
backendDisplayName: null,
|
||||
resolutionSource: 'unresolved',
|
||||
reason: 'Direct Anthropic settings profiles use native file access unless explicitly mapped.',
|
||||
};
|
||||
}
|
||||
|
||||
const fallbackBackend = normalizeImageAnalysisBackendId(
|
||||
config.fallback_backend,
|
||||
Object.keys(config.provider_models)
|
||||
@@ -323,7 +334,10 @@ export function resolveImageAnalysisStatus(
|
||||
? (config.provider_models[resolution.backendId] ?? null)
|
||||
: null;
|
||||
const shouldPersistHook =
|
||||
config.enabled && context.profileType !== 'default' && context.profileType !== 'account';
|
||||
config.enabled &&
|
||||
context.profileType !== 'default' &&
|
||||
context.profileType !== 'account' &&
|
||||
Boolean(resolution.backendId && model);
|
||||
|
||||
let status: ImageAnalysisStatusCode = 'active';
|
||||
let reason = resolution.reason;
|
||||
@@ -353,8 +367,16 @@ export function resolveImageAnalysisStatus(
|
||||
(!context.cliproxyBridge.usesCurrentTarget || !context.cliproxyBridge.usesCurrentAuthToken)
|
||||
) {
|
||||
status = 'attention';
|
||||
reason =
|
||||
'Active, but runtime uses the current CLIProxy target instead of the stale route saved in this profile.';
|
||||
if (!context.cliproxyBridge.usesCurrentTarget && !context.cliproxyBridge.usesCurrentAuthToken) {
|
||||
reason =
|
||||
'Runtime uses the current CLIProxy route and auth token instead of the saved values in this profile.';
|
||||
} else if (!context.cliproxyBridge.usesCurrentTarget) {
|
||||
reason =
|
||||
'Runtime uses the current CLIProxy route instead of the saved route in this profile.';
|
||||
} else {
|
||||
reason =
|
||||
'Runtime uses the current CLIProxy auth token instead of the saved token in this profile.';
|
||||
}
|
||||
} else if (resolution.resolutionSource === 'profile-backend') {
|
||||
status = 'mapped';
|
||||
}
|
||||
|
||||
@@ -303,6 +303,13 @@ function resolveImageAnalysisStatusForProfile(
|
||||
};
|
||||
}
|
||||
|
||||
function resolvePreviewImageAnalysisStatus(profileOrVariant: string, settings: Settings) {
|
||||
const normalizedSettings = canonicalizeProfileSettings(profileOrVariant, settings);
|
||||
const settingsPath = resolveSettingsPath(profileOrVariant);
|
||||
|
||||
return resolveImageAnalysisStatusForProfile(profileOrVariant, normalizedSettings, settingsPath);
|
||||
}
|
||||
|
||||
function writeSettingsAtomically(settingsPath: string, settings: Settings): void {
|
||||
const tempPath = `${settingsPath}.tmp.${process.pid}`;
|
||||
fs.writeFileSync(tempPath, JSON.stringify(settings, null, 2) + '\n');
|
||||
@@ -428,6 +435,29 @@ router.get('/:profile/raw', (req: Request, res: Response): void => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/settings/:profile/image-analysis-status - Preview image analysis status from editor JSON
|
||||
*/
|
||||
router.post('/:profile/image-analysis-status', (req: Request, res: Response): void => {
|
||||
if (!requireSensitiveLocalAccess(req, res)) return;
|
||||
|
||||
try {
|
||||
const { profile } = req.params;
|
||||
const { settings } = req.body;
|
||||
|
||||
if (!settings || typeof settings !== 'object') {
|
||||
res.status(400).json({ error: 'settings object is required in request body' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({
|
||||
imageAnalysisStatus: resolvePreviewImageAnalysisStatus(profile, settings as Settings),
|
||||
});
|
||||
} catch (error) {
|
||||
respondInternalError(res, error, 'Internal server error.');
|
||||
}
|
||||
});
|
||||
|
||||
/** Required env vars for CLIProxy providers to function */
|
||||
const REQUIRED_ENV_KEYS = ['ANTHROPIC_BASE_URL', 'ANTHROPIC_AUTH_TOKEN'] as const;
|
||||
|
||||
|
||||
Reference in new issue
Block a user