fix: remediate 10 review findings in communication spine
- Fix createSession race condition with in-flight promise map - Fix listener leak: always cleanup previous subscription per client - Fix REST timeout returning HTTP 200 — now rejects with 504 - Fix fire-and-forget Discord sends — await with error handling - Fix non-null assertion on client.user in Discord plugin - Fix TUI disconnect mid-stream deadlock (reset streaming state) - Add connect_error handler to TUI and Discord plugin - Add connected guard on TUI message submit - Add relayEvent guard for disconnected sockets - Sanitize error messages sent to WebSocket clients - Add error logging/context to AgentService create/prompt/destroy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,15 @@ export class DiscordPlugin {
|
||||
console.log('[discord] Connected to gateway');
|
||||
});
|
||||
|
||||
this.socket.on('disconnect', (reason: string) => {
|
||||
console.error(`[discord] Disconnected from gateway: ${reason}`);
|
||||
this.pendingResponses.clear();
|
||||
});
|
||||
|
||||
this.socket.on('connect_error', (err: Error) => {
|
||||
console.error(`[discord] Gateway connection error: ${err.message}`);
|
||||
});
|
||||
|
||||
// Handle streaming text from gateway
|
||||
this.socket.on('agent:text', (data: { conversationId: string; text: string }) => {
|
||||
const pending = this.pendingResponses.get(data.conversationId);
|
||||
@@ -51,8 +60,10 @@ export class DiscordPlugin {
|
||||
this.socket.on('agent:end', (data: { conversationId: string }) => {
|
||||
const text = this.pendingResponses.get(data.conversationId);
|
||||
if (text) {
|
||||
this.sendToDiscord(data.conversationId, text);
|
||||
this.pendingResponses.delete(data.conversationId);
|
||||
this.sendToDiscord(data.conversationId, text).catch((err) => {
|
||||
console.error(`[discord] Error sending response for ${data.conversationId}:`, err);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -79,18 +90,21 @@ export class DiscordPlugin {
|
||||
// Ignore bot messages
|
||||
if (message.author.bot) return;
|
||||
|
||||
// Not ready yet
|
||||
if (!this.client.user) return;
|
||||
|
||||
// Check guild binding
|
||||
if (this.config.guildId && message.guildId !== this.config.guildId) return;
|
||||
|
||||
// Respond to DMs always, or mentions in channels
|
||||
const isDM = !message.guildId;
|
||||
const isMention = message.mentions.has(this.client.user!);
|
||||
const isMention = message.mentions.has(this.client.user);
|
||||
|
||||
if (!isDM && !isMention) return;
|
||||
|
||||
// Strip bot mention from message content
|
||||
const content = message.content
|
||||
.replace(new RegExp(`<@!?${this.client.user!.id}>`, 'g'), '')
|
||||
.replace(new RegExp(`<@!?${this.client.user.id}>`, 'g'), '')
|
||||
.trim();
|
||||
|
||||
if (!content) return;
|
||||
@@ -104,27 +118,45 @@ export class DiscordPlugin {
|
||||
}
|
||||
|
||||
// Send to gateway
|
||||
this.socket?.emit('message', {
|
||||
if (!this.socket?.connected) {
|
||||
console.error(
|
||||
`[discord] Cannot forward message: not connected to gateway. channel=${channelId}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.socket.emit('message', {
|
||||
conversationId,
|
||||
content,
|
||||
});
|
||||
}
|
||||
|
||||
private sendToDiscord(conversationId: string, text: string): void {
|
||||
private async sendToDiscord(conversationId: string, text: string): Promise<void> {
|
||||
// Find the Discord channel for this conversation
|
||||
const channelId = Array.from(this.channelConversations.entries()).find(
|
||||
([, convId]) => convId === conversationId,
|
||||
)?.[0];
|
||||
|
||||
if (!channelId) return;
|
||||
if (!channelId) {
|
||||
console.error(`[discord] No channel found for conversation ${conversationId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const channel = this.client.channels.cache.get(channelId);
|
||||
if (!channel || !('send' in channel)) return;
|
||||
if (!channel || !('send' in channel)) {
|
||||
console.error(
|
||||
`[discord] Channel ${channelId} not sendable for conversation ${conversationId}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Chunk responses for Discord's 2000-char limit
|
||||
const chunks = this.chunkText(text, 1900);
|
||||
for (const chunk of chunks) {
|
||||
(channel as { send: (content: string) => Promise<unknown> }).send(chunk);
|
||||
try {
|
||||
await (channel as { send: (content: string) => Promise<unknown> }).send(chunk);
|
||||
} catch (err) {
|
||||
console.error(`[discord] Failed to send message to channel ${channelId}:`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user