132 lines
4 KiB
TypeScript
132 lines
4 KiB
TypeScript
import type {
|
|
AgentAttachmentCapability,
|
|
AgentAttachmentCapabilityTarget,
|
|
ProviderImageMimeType,
|
|
} from './types';
|
|
|
|
const DEFAULT_IMAGE_BYTES_PER_PROVIDER = 4 * 1024 * 1024;
|
|
const DEFAULT_IMAGE_BYTES_TOTAL = 8 * 1024 * 1024;
|
|
const DEFAULT_FILE_BYTES_PER_PROVIDER = 4 * 1024 * 1024;
|
|
|
|
export const NATIVE_IMAGE_MIME_TYPES = ['image/png', 'image/jpeg', 'image/webp'] as const;
|
|
export const CLAUDE_IMAGE_MIME_TYPES = [
|
|
'image/png',
|
|
'image/jpeg',
|
|
'image/gif',
|
|
'image/webp',
|
|
] as const;
|
|
|
|
function supportedImagesOnly(
|
|
displayText: string,
|
|
supportedImageMimeTypes: readonly ProviderImageMimeType[] = NATIVE_IMAGE_MIME_TYPES
|
|
): AgentAttachmentCapability {
|
|
return {
|
|
supportsImages: true,
|
|
supportsFiles: false,
|
|
supportedImageMimeTypes: [...supportedImageMimeTypes],
|
|
supportedFileMimeTypes: [],
|
|
maxImages: 5,
|
|
maxFiles: 0,
|
|
maxBytesPerImage: DEFAULT_IMAGE_BYTES_PER_PROVIDER,
|
|
maxBytesPerFile: 0,
|
|
maxBytesTotal: DEFAULT_IMAGE_BYTES_TOTAL,
|
|
reason: 'known_provider_support',
|
|
displayText,
|
|
filesDisplayText:
|
|
'This provider path currently supports image attachments only. Non-image files are blocked before provider delivery.',
|
|
};
|
|
}
|
|
|
|
function supportedClaude(displayText: string): AgentAttachmentCapability {
|
|
return {
|
|
...supportedImagesOnly(displayText, CLAUDE_IMAGE_MIME_TYPES),
|
|
supportsFiles: true,
|
|
supportedFileMimeTypes: ['application/pdf', 'text/*'],
|
|
maxFiles: 5,
|
|
maxBytesPerFile: DEFAULT_FILE_BYTES_PER_PROVIDER,
|
|
filesDisplayText: 'Claude can receive text files and PDFs through structured document blocks.',
|
|
};
|
|
}
|
|
|
|
function unsupported(
|
|
reason: AgentAttachmentCapability['reason'],
|
|
displayText: string
|
|
): AgentAttachmentCapability {
|
|
return {
|
|
supportsImages: false,
|
|
supportsFiles: false,
|
|
supportedImageMimeTypes: [],
|
|
supportedFileMimeTypes: [],
|
|
maxImages: 0,
|
|
maxFiles: 0,
|
|
maxBytesPerImage: 0,
|
|
maxBytesPerFile: 0,
|
|
maxBytesTotal: 0,
|
|
reason,
|
|
displayText,
|
|
filesDisplayText:
|
|
'Selected provider does not support non-image file attachments through this delivery path.',
|
|
};
|
|
}
|
|
|
|
export function canonicalizeOpenCodeModel(input: { providerId: string; model?: string | null }): {
|
|
providerId: string;
|
|
model: string;
|
|
} {
|
|
const providerId = input.providerId.trim().toLowerCase();
|
|
const model = (input.model ?? '')
|
|
.trim()
|
|
.toLowerCase()
|
|
.replace(/^openrouter\//, '')
|
|
.replace(/^openai\//, '');
|
|
return { providerId, model };
|
|
}
|
|
|
|
export function resolveAgentAttachmentCapability(
|
|
target: AgentAttachmentCapabilityTarget
|
|
): AgentAttachmentCapability {
|
|
const providerId = target.providerId.trim().toLowerCase();
|
|
|
|
if (providerId === 'anthropic') {
|
|
return supportedClaude('Claude can receive image attachments through structured image blocks.');
|
|
}
|
|
|
|
if (providerId === 'codex') {
|
|
return supportedImagesOnly(
|
|
'Codex can receive image attachments through the native image channel.'
|
|
);
|
|
}
|
|
|
|
if (providerId === 'opencode') {
|
|
const { model } = canonicalizeOpenCodeModel(target);
|
|
if (model === 'gpt-5.4-mini') {
|
|
return {
|
|
...supportedImagesOnly(
|
|
'OpenCode model openai/gpt-5.4-mini is verified for image attachments.'
|
|
),
|
|
reason: 'known_vision_model',
|
|
};
|
|
}
|
|
if (model === 'moonshotai/kimi-k2.6' || model === 'z-ai/glm-4.5v') {
|
|
return {
|
|
...supportedImagesOnly(`OpenCode model ${model} is verified for image attachments.`),
|
|
reason: 'known_vision_model',
|
|
};
|
|
}
|
|
if (model === 'z-ai/glm-5.1') {
|
|
return unsupported(
|
|
'known_non_vision_model',
|
|
'This OpenCode model is not verified for image attachments. Choose a vision-capable model or remove the image.'
|
|
);
|
|
}
|
|
return unsupported(
|
|
'unknown_model',
|
|
'This OpenCode model has unknown image support. Image delivery is blocked for reliability.'
|
|
);
|
|
}
|
|
|
|
return unsupported(
|
|
'unsupported_provider',
|
|
'Selected provider does not support image attachments through this delivery path.'
|
|
);
|
|
}
|