This commit is contained in:
seb
2026-10-11 12:58:15 +02:00
parent 8262e35e53
commit 1149ffddcb
24 changed files with 575 additions and 261 deletions

View File

@@ -7,6 +7,12 @@ import env from '../config/env.js';
import { getImageByHash } from '../db/pic.js';
import { prepareVfs, extractFullHash } from './vfs.js';
import { resolveOpenRouterKey, resolveDefaultModel } from './llm-key.js';
import {
TOOL_DESCRIPTIONS,
TOOL_PARAMETER_DESCRIPTIONS,
ANALYZE_IMAGE_VISION_COMPARE_PROMPT,
ANALYZE_IMAGE_VISION_DESCRIBE_PROMPT,
} from './prompts.js';
/**
* analyze_image — lets a vision model actually LOOK at images held in the VFS.
@@ -275,9 +281,7 @@ async function fetchDatabaseImage(hash, googleAuthId) {
export function createAnalyzeImageTool({ googleAuthId, model }) {
return defineTool({
name: 'analyze_image',
description:
'Inspect 1-9 images via vision model. Multiple paths render as a labelled comparison grid. ' +
'Paths: VFS-relative ("images/foo.avif") or DB ("image/<hash>"). Returns model evaluation.',
description: TOOL_DESCRIPTIONS.analyze_image,
strict: false,
parameters: {
type: 'object',
@@ -286,23 +290,23 @@ export function createAnalyzeImageTool({ googleAuthId, model }) {
properties: {
note: {
type: ['string', 'null'],
description: 'A note explaining what this image inspection is doing (or null). This note will be displayed to the user while the images are being analyzed.',
description: TOOL_PARAMETER_DESCRIPTIONS.analyze_image.note,
},
paths: {
type: 'array',
description: '1–9 VFS paths or DB paths ("image/<hash>").',
description: TOOL_PARAMETER_DESCRIPTIONS.analyze_image.paths,
items: { type: 'string' },
minItems: 1,
maxItems: MAX_IMAGES,
},
prompt: {
type: ['string', 'null'],
description: 'Inspection criteria or question, or null.',
description: TOOL_PARAMETER_DESCRIPTIONS.analyze_image.prompt,
},
grid: {
type: ['string', 'null'],
enum: [...Object.keys(GRID_CONFIGS), null],
description: 'Grid layout or null for auto.',
description: TOOL_PARAMETER_DESCRIPTIONS.analyze_image.grid,
},
},
},
@@ -378,14 +382,14 @@ export function createAnalyzeImageTool({ googleAuthId, model }) {
// ── Ask the vision model ──────────────────────────────────────
const question = typeof prompt === 'string' && prompt.trim() ? prompt.trim() : null;
const text = items.length > 1
? `${question || 'Compare these images, judge visual quality, flag watermarks, text overlays or defects, and say which one is best and why.'}\n\n` +
? `${question || ANALYZE_IMAGE_VISION_COMPARE_PROMPT}\n\n` +
`The grid is ${shape.name}. Each image has its file name printed beneath it:\n` +
items.map((it, idx) => {
const row = Math.floor(idx / GRID_CONFIGS[shape.name].cols) + 1;
const col = (idx % GRID_CONFIGS[shape.name].cols) + 1;
return `- Row ${row}, Col ${col}: "${it.name}"`;
}).join('\n')
: question || 'Describe this image, judge its visual quality, flag any watermark, text overlay or defect, and say whether it is usable as a product or category image.';
: question || ANALYZE_IMAGE_VISION_DESCRIBE_PROMPT;
const apiKey = await resolveOpenRouterKey(googleAuthId);
const visionModel = (await resolveDefaultModel(googleAuthId)) || model;