disclaw/src/discord/send-response.ts
Nick Tabeling 9e03fc5207
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-154): discord rich features — reactions, file responses, attachment inbox
- Status reactions on messages: 👀 on enqueue,  on success,  on any error
- Typing interval raised from 5s to 8s
- src/discord/send-response.ts: text >4000 chars sent as response.md attachment
- src/discord/attachment-inbox.ts: downloads Discord attachments into .disclaw-inbox/, cleanupInbox() removes files older than 24h
- src/router.ts: input limit guard at 4000 chars (⚠️ reaction + hint message), processAttachments hints injected into prompt
- Unit tests: send-response.test.ts, attachment-inbox.test.ts (107 tests, all green)

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

39 lines
1,023 B
TypeScript

import { TextChannel, Message, AttachmentBuilder } from "discord.js";
import { splitForDiscord } from "./split.js";
import { childLogger } from "../runtime/logger.js";
const log = childLogger("send-response");
const FILE_THRESHOLD = 4000;
/**
* Sends an agent response to a Discord channel.
* - Text > 4000 chars is sent as a Markdown file attachment.
* - Text <= 4000 chars is split with splitForDiscord and sent as plain messages.
*/
export async function sendResponse(
channel: TextChannel,
text: string,
_triggerMessage: Message
): Promise<void> {
if (text.length === 0) {
return;
}
if (text.length > FILE_THRESHOLD) {
log.debug({ length: text.length }, "Response exceeds threshold — sending as file");
await channel.send({
files: [
new AttachmentBuilder(Buffer.from(text, "utf-8"), {
name: "response.md",
}),
],
});
return;
}
const chunks = splitForDiscord(text);
for (const chunk of chunks) {
await channel.send(chunk);
}
}