mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-15 14:16:16 +00:00
test(hooks): add image analyzer regression coverage
This commit is contained in:
1 parent
0060c77c25
commit
50973752ba
2 files changed
+250
-19
No files matched your search
@@ -12,7 +12,7 @@
|
||||
* CCS_CURRENT_PROVIDER - Current CLIProxy provider (e.g., agy, gemini, codex)
|
||||
* CCS_IMAGE_ANALYSIS_TIMEOUT=60 - Timeout in seconds (default: 60)
|
||||
* CCS_PROFILE_TYPE - Profile type (account/default skip)
|
||||
* ANTHROPIC_MODEL - Fallback model if provider not in mapping
|
||||
* ANTHROPIC_MODEL - Chat model env (not used for image analysis fallback)
|
||||
* CCS_DEBUG=1 - Enable debug output
|
||||
*
|
||||
* Exit codes:
|
||||
@@ -147,6 +147,46 @@ function parseProviderModels(envValue) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract concatenated text content from CLIProxy response blocks.
|
||||
* Skips thinking and other non-text blocks.
|
||||
*/
|
||||
function extractTextContent(response) {
|
||||
if (!response || !Array.isArray(response.content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const textBlocks = response.content
|
||||
.filter((block) => block && block.type === 'text' && typeof block.text === 'string')
|
||||
.map((block) => block.text)
|
||||
.filter((text) => text.trim());
|
||||
|
||||
if (textBlocks.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return textBlocks.join('\n\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse raw CLIProxy response body and extract text content.
|
||||
*/
|
||||
function parseCliProxyResponse(data) {
|
||||
let response;
|
||||
try {
|
||||
response = JSON.parse(data);
|
||||
} catch (err) {
|
||||
throw new Error(`Failed to parse response: ${err.message}`);
|
||||
}
|
||||
|
||||
const text = extractTextContent(response);
|
||||
if (!text) {
|
||||
throw new Error('No text content in response');
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get model for current provider from provider_models mapping
|
||||
* Returns primary model only (for display/logging)
|
||||
@@ -160,13 +200,14 @@ function getModelForProvider() {
|
||||
/**
|
||||
* Get list of models to try in order:
|
||||
* 1. provider_models[current_provider] (if exists)
|
||||
* 2. DEFAULT_MODEL
|
||||
* 3. ANTHROPIC_MODEL from profile (if different and exists)
|
||||
* 2. DEFAULT_MODEL when no provider-specific vision model is configured
|
||||
*
|
||||
* ANTHROPIC_MODEL is intentionally ignored here because the chat model may
|
||||
* not be vision-capable on the current provider route.
|
||||
*/
|
||||
function getModelsToTry() {
|
||||
const currentProvider = process.env.CCS_CURRENT_PROVIDER || '';
|
||||
const providerModels = parseProviderModels(process.env.CCS_IMAGE_ANALYSIS_PROVIDER_MODELS);
|
||||
const anthropicModel = process.env.ANTHROPIC_MODEL;
|
||||
|
||||
const models = [];
|
||||
const seen = new Set();
|
||||
@@ -185,9 +226,6 @@ function getModelsToTry() {
|
||||
seen.add(DEFAULT_MODEL);
|
||||
}
|
||||
|
||||
// 3. ANTHROPIC_MODEL fallback — skip, the main chat model is not
|
||||
// necessarily vision-capable and adds unnecessary retry latency
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
@@ -381,20 +419,10 @@ function analyzeViaCliProxy(base64Data, mediaType, model, timeoutMs) {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = JSON.parse(data);
|
||||
// Find the first text block — skip thinking blocks which use
|
||||
// .thinking instead of .text (e.g. codex models with thinking enabled)
|
||||
const textBlock = response.content?.find(b => b.type === 'text' && b.text);
|
||||
const text = textBlock?.text;
|
||||
|
||||
if (!text) {
|
||||
reject(new Error('No text content in response'));
|
||||
return;
|
||||
}
|
||||
|
||||
const text = parseCliProxyResponse(data);
|
||||
resolve(text);
|
||||
} catch (err) {
|
||||
reject(new Error(`Failed to parse response: ${err.message}`));
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user