Stabilize paired-room orchestration and Codex app-server flow
This commit is contained in:
@@ -313,11 +313,55 @@ describe('DiscordChannel', () => {
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
content: 'I am a bot',
|
||||
is_from_me: false,
|
||||
is_bot_message: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('ignores self-authored bot messages', async () => {
|
||||
const opts = createTestOpts();
|
||||
const channel = new DiscordChannel('test-token', opts);
|
||||
await channel.connect();
|
||||
|
||||
const msg = createMessage({
|
||||
authorId: '999888777',
|
||||
isBot: true,
|
||||
content: 'I am this bot',
|
||||
});
|
||||
await triggerMessage(msg);
|
||||
|
||||
expect(opts.onMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('identifies stored messages authored by the current bot', async () => {
|
||||
const opts = createTestOpts();
|
||||
const channel = new DiscordChannel('test-token', opts);
|
||||
await channel.connect();
|
||||
|
||||
expect(
|
||||
channel.isOwnMessage?.({
|
||||
id: 'msg_bot',
|
||||
chat_jid: 'dc:1234567890123456',
|
||||
sender: '999888777',
|
||||
sender_name: 'Andy',
|
||||
content: 'bot message',
|
||||
timestamp: '2024-01-01T00:00:00.000Z',
|
||||
is_bot_message: true,
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
channel.isOwnMessage?.({
|
||||
id: 'msg_user',
|
||||
chat_jid: 'dc:1234567890123456',
|
||||
sender: '55512345',
|
||||
sender_name: 'Alice',
|
||||
content: 'user message',
|
||||
timestamp: '2024-01-01T00:00:00.000Z',
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('uses member displayName when available (server nickname)', async () => {
|
||||
const opts = createTestOpts();
|
||||
const channel = new DiscordChannel('test-token', opts);
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
} from '../config.js';
|
||||
import { readEnvFile } from '../env.js';
|
||||
import { logger } from '../logger.js';
|
||||
import { formatOutbound } from '../router.js';
|
||||
|
||||
const ATTACHMENTS_DIR = path.join(DATA_DIR, 'attachments');
|
||||
const TRANSCRIPTION_CACHE_DIR = path.join(CACHE_DIR, 'transcriptions');
|
||||
@@ -158,6 +159,7 @@ import {
|
||||
AgentType,
|
||||
Channel,
|
||||
ChannelMeta,
|
||||
NewMessage,
|
||||
OnChatMetadata,
|
||||
OnInboundMessage,
|
||||
RegisteredGroup,
|
||||
@@ -446,6 +448,7 @@ export class DiscordChannel implements Channel {
|
||||
for (const [name, id] of Object.entries(mentionMap)) {
|
||||
cleaned = cleaned.replace(new RegExp(`@${name}`, 'g'), `<@${id}>`);
|
||||
}
|
||||
cleaned = formatOutbound(cleaned);
|
||||
|
||||
// Discord has a 2000 character limit per message — split if needed
|
||||
const MAX_LENGTH = 2000;
|
||||
@@ -454,6 +457,11 @@ export class DiscordChannel implements Channel {
|
||||
name: path.basename(f),
|
||||
}));
|
||||
|
||||
if (!cleaned && files.length === 0) {
|
||||
logger.debug({ jid }, 'Skipping empty Discord outbound message');
|
||||
return;
|
||||
}
|
||||
|
||||
if (cleaned.length <= MAX_LENGTH) {
|
||||
await textChannel.send({
|
||||
content: cleaned || undefined,
|
||||
@@ -490,6 +498,10 @@ export class DiscordChannel implements Channel {
|
||||
return groupType === this.agentTypeFilter;
|
||||
}
|
||||
|
||||
isOwnMessage(msg: NewMessage): boolean {
|
||||
return !!this.client?.user?.id && msg.sender === this.client.user.id;
|
||||
}
|
||||
|
||||
async disconnect(): Promise<void> {
|
||||
if (this.client) {
|
||||
this.client.destroy();
|
||||
|
||||
Reference in New Issue
Block a user