feat: add MEDIA outbound attachment directive

This commit is contained in:
ejclaw
2026-05-26 17:26:20 +09:00
parent 89b3dd382e
commit df6ec5f2b2
11 changed files with 373 additions and 29 deletions

View File

@@ -9,7 +9,13 @@ export interface PreparedDiscordOutbound {
text: string;
cleanText: string;
attachments: OutboundAttachment[];
attachmentSource: 'structured' | 'md-link' | 'image-tag' | 'mixed' | 'none';
attachmentSource:
| 'structured'
| 'media-tag'
| 'md-link'
| 'image-tag'
| 'mixed'
| 'none';
silent: boolean;
}
@@ -51,9 +57,11 @@ export function prepareDiscordOutbound(
? 'structured'
: normalized.attachmentSource === 'legacy-ejclaw-json'
? 'structured'
: normalized.attachmentSource === 'markdown-image'
? 'md-link'
: (normalized.attachmentSource ?? 'none');
: normalized.attachmentSource === 'media-tag'
? 'media-tag'
: normalized.attachmentSource === 'markdown-image'
? 'md-link'
: (normalized.attachmentSource ?? 'none');
return {
text: outboundText,

View File

@@ -102,6 +102,10 @@ const ONE_PIXEL_PNG = Buffer.from(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII=',
'base64',
);
const MINIMAL_MP4 = Buffer.from([
0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f, 0x6d, 0x00,
0x00, 0x02, 0x00, 0x69, 0x73, 0x6f, 0x6d, 0x69, 0x73, 0x6f, 0x32,
]);
const tempFiles: string[] = [];
@@ -258,6 +262,39 @@ ${JSON.stringify({
});
});
it('normalizes MEDIA directives and sends them as files', async () => {
const channel = new DiscordChannel('test-token', createTestOpts());
await channel.connect();
const filePath = path.join(
os.tmpdir(),
`adventurer-active-sfx-preview-${Date.now()}.mp4`,
);
fs.writeFileSync(filePath, MINIMAL_MP4);
tempFiles.push(filePath);
const mockChannel = {
send: vi.fn().mockResolvedValue({ id: 'discord-message-media' }),
sendTyping: vi.fn(),
};
clientRef.current.channels.fetch.mockResolvedValue(mockChannel);
await channel.sendMessage(
'dc:1234567890123456',
`사운드 프리뷰입니다.\nMEDIA:${filePath}`,
);
expect(mockChannel.send).toHaveBeenCalledWith({
content: '사운드 프리뷰입니다.',
files: [
{
attachment: fs.realpathSync(filePath),
name: path.basename(filePath),
},
],
flags: 1 << 2,
});
expect(JSON.stringify(mockChannel.send.mock.calls)).not.toContain('MEDIA:');
});
it('keeps non-image local markdown links readable without uploading files', async () => {
const channel = new DiscordChannel('test-token', createTestOpts());
await channel.connect();