agent-ecosystem/src/features/agent-attachments/main/providers/claudeAttachmentAdapter.test.ts
2026-05-09 05:04:46 +03:00

111 lines
3.4 KiB
TypeScript

import {
buildClaudeAttachmentDeliveryParts,
redactClaudeBlocksForDiagnostics,
} from './claudeAttachmentAdapter';
import type { AttachmentPayload } from '@shared/types';
function attachment(overrides: Partial<AttachmentPayload> = {}): AttachmentPayload {
return {
id: 'att_1',
filename: 'red.png',
mimeType: 'image/png',
size: 3,
data: Buffer.from([1, 2, 3]).toString('base64'),
...overrides,
};
}
describe('Claude attachment adapter', () => {
it('keeps text-only messages on the legacy text path', () => {
expect(buildClaudeAttachmentDeliveryParts({ text: 'hello' })).toEqual({
kind: 'legacy_text',
blocks: [{ type: 'text', text: 'hello' }],
});
});
it('serializes png images as structured image blocks', () => {
const result = buildClaudeAttachmentDeliveryParts({
text: 'What color?',
attachments: [attachment()],
});
expect(result.kind).toBe('structured_blocks');
expect(result.blocks[0]).toEqual({ type: 'text', text: 'What color?' });
expect(result.blocks[1]).toMatchObject({
type: 'image',
source: { type: 'base64', media_type: 'image/png' },
});
});
it('serializes UTF-8 text files as text document blocks', () => {
const result = buildClaudeAttachmentDeliveryParts({
text: 'Read this',
attachments: [
attachment({
filename: 'note.txt',
mimeType: 'text/plain',
data: Buffer.from('hello', 'utf8').toString('base64'),
}),
],
});
expect(result.blocks[1]).toEqual({
type: 'document',
source: { type: 'text', media_type: 'text/plain', data: 'hello' },
title: 'note.txt',
});
});
it('serializes text subtypes as text document blocks', () => {
const result = buildClaudeAttachmentDeliveryParts({
text: 'Read this',
attachments: [
attachment({
filename: 'notes.md',
mimeType: 'text/markdown',
data: Buffer.from('# hello', 'utf8').toString('base64'),
}),
],
});
expect(result.blocks[1]).toEqual({
type: 'document',
source: { type: 'text', media_type: 'text/plain', data: '# hello' },
title: 'notes.md',
});
});
it('rejects unsupported non-image files before provider send', () => {
expect(() =>
buildClaudeAttachmentDeliveryParts({
text: 'read sheet',
attachments: [attachment({ filename: 'sheet.xlsx', mimeType: 'application/vnd.ms-excel' })],
})
).toThrow(/Claude attachment MIME unsupported/);
});
it('rejects unsupported image mime types before provider send', () => {
expect(() =>
buildClaudeAttachmentDeliveryParts({
text: 'see gif',
attachments: [attachment({ mimeType: 'image/gif' })],
})
).toThrow(/Claude attachment MIME unsupported/);
});
it('redacts image and document bytes in diagnostics', () => {
const result = buildClaudeAttachmentDeliveryParts({
text: 'What color?',
attachments: [
attachment(),
attachment({ id: 'att_2', filename: 'a.pdf', mimeType: 'application/pdf' }),
],
});
const redacted = redactClaudeBlocksForDiagnostics(result.blocks);
expect(JSON.stringify(redacted)).not.toContain(attachment().data);
expect(JSON.stringify(redacted)).toContain('[redacted image bytes: image/png]');
expect(JSON.stringify(redacted)).toContain('[redacted document bytes: application/pdf]');
});
});