disclaw/src/router.ts
Nick Tabeling 00132c6d22
Some checks failed
CI / build-and-test (ubuntu-latest) (pull_request) Has been cancelled
CI / build-and-test (windows-latest) (pull_request) Has been cancelled
CI / lint (pull_request) Has been cancelled
feat(DIS-105): codeblock-aware message splitting for Discord 2000-char limit
Add splitForDiscord() in src/discord/split.ts.
Fences are properly closed and reopened across chunk boundaries.
Router uses splitForDiscord instead of internal splitMessage().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 17:48:58 +02:00

90 lines
2.4 KiB
TypeScript

import { Message, TextChannel } from "discord.js";
import { DisclawDatabase } from "./db/database";
import { DisclawConfig } from "./config/loader";
import { runAgent } from "./agent/runner";
import { splitForDiscord } from "./discord/split";
/**
* Routes a Discord message to the correct agent based on channel_id.
* Returns true if the message was handled, false if the channel is not
* mapped to any agent.
*/
export async function routeMessage(
message: Message,
db: DisclawDatabase,
config: DisclawConfig,
managementChannelId: string | null
): Promise<boolean> {
const channelId = message.channelId;
// Ignore messages in the management channel (commands only)
if (channelId === managementChannelId) {
return false;
}
// Look up workspace for this channel
const workspace = db.getWorkspaceByChannelId(channelId);
if (!workspace) {
return false;
}
const channel = message.channel as TextChannel;
// Show typing indicator while the agent works
const typingInterval = setInterval(() => {
channel.sendTyping().catch(() => {});
}, 5000);
// Send immediately as well
await channel.sendTyping().catch(() => {});
try {
// Load recent conversation history for context
const history = db.getConversationHistory(workspace.id, 30);
// Run the agent
const response = await runAgent({
workspacePath: workspace.workspace_path,
channelName: channel.name,
userMessage: message.content,
conversationHistory: history,
});
// Store user message
db.addConversation(
workspace.id,
message.id,
"user",
message.content,
message.author.username
);
// Split and send response
const chunks = splitForDiscord(response);
let firstMsgId: string | null = null;
for (const chunk of chunks) {
const sent = await channel.send(chunk);
if (!firstMsgId) {
firstMsgId = sent.id;
}
}
// Store assistant response (use first message id for dedup)
if (firstMsgId) {
db.addConversation(
workspace.id,
firstMsgId,
"assistant",
response,
null
);
}
} catch (error) {
const msg = error instanceof Error ? error.message : "Unbekannter Fehler";
await channel.send(`Fehler bei der Verarbeitung: ${msg}`).catch(() => {});
} finally {
clearInterval(typingInterval);
}
return true;
}