feat(discord): inbound + outbound media attachments#175
Conversation
Discord was fully text-only: inbound attachments were ignored and the agent couldn't send files. Wire the channel to the existing attachment infrastructure both directions. Inbound: message attachments (guild messages + DM gateway dispatch) are fetched from the Discord CDN and uploaded as session attachments (images become vision input); audio attachments are transcribed via the agent's STT and appended as text. Media-only messages now trigger the agent. Attachments over the 25 MiB cap are skipped. Outbound: the agent's attachment_send deliveries (SSE 'attachment' event) are sent back as Discord file uploads via AttachmentBuilder, with any caption as the message content. Discord is bundled into the CLI (private package), so this ships with the next openhermit release rather than a standalone publish. Bumps 0.2.0 -> 0.3.0 for changelog clarity. Adds the first unit tests for this package. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 2 minutes and 52 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR adds comprehensive media attachment support to the Discord channel adapter. It introduces attachment type contracts, extracts and maps attachments from Discord messages (both raw gateway events and discord.js objects), resolves them with size validation and audio transcription, and delivers agent-generated attachments back to Discord via file uploads. ChangesDiscord media attachment support
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/channels/discord/src/bridge.ts (1)
117-124: 💤 Low valueConsider adding a timeout for CDN fetch.
The
fetch(att.url)call has no timeout, so a stalled Discord CDN connection could block the message queue indefinitely. Adding anAbortSignal.timeout()would bound the wait time and improve resilience.💡 Suggested timeout
let bytes: Uint8Array; try { - const res = await fetch(att.url); + const res = await fetch(att.url, { signal: AbortSignal.timeout(30_000) }); if (!res.ok) throw new Error(`status ${res.status}`); bytes = new Uint8Array(await res.arrayBuffer()); } catch (err) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/channels/discord/src/bridge.ts` around lines 117 - 124, Add a bounded timeout to the CDN fetch call so a stalled request can't block processing: when calling fetch(att.url) (in the attachment fetch block that sets bytes from await res.arrayBuffer()), create an AbortSignal with AbortSignal.timeout(ms) (or a manual AbortController for older runtimes), pass that signal into fetch({ signal }), and handle the abort case in the existing catch (log a clear timeout/abort message via this.log and continue). Ensure the same error handling still covers non-OK status and other errors and that you clean up any controller if you use one.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/channels/discord/package.json`:
- Line 10: The package.json test script references "tsx" but this package lacks
tsx in its dependencies so running npm test fails; update
apps/channels/discord/package.json by adding "tsx" to devDependencies (e.g., add
a devDependency entry for "tsx" with an appropriate version) or adjust the
workspace/hoisting configuration so the package can resolve the existing tsx
installation; ensure the change targets the package.json that defines the
"test": "node --import tsx --test test/*.test.ts" script and run an install to
verify tests run.
- Line 4: Update apps/gateway's optionalDependencies entry for
`@openhermit/channel-discord` from "0.2.0" to "0.3.0" so the gateway picks up the
new attachment behavior; locate the optionalDependencies block in
apps/gateway/package.json and bump the version string for
`@openhermit/channel-discord`. Also, if this package is intended to be runnable
outside the monorepo, add "tsx" to the devDependencies of
apps/channels/discord/package.json (so the "test" script using node --import tsx
works when installed standalone).
---
Nitpick comments:
In `@apps/channels/discord/src/bridge.ts`:
- Around line 117-124: Add a bounded timeout to the CDN fetch call so a stalled
request can't block processing: when calling fetch(att.url) (in the attachment
fetch block that sets bytes from await res.arrayBuffer()), create an AbortSignal
with AbortSignal.timeout(ms) (or a manual AbortController for older runtimes),
pass that signal into fetch({ signal }), and handle the abort case in the
existing catch (log a clear timeout/abort message via this.log and continue).
Ensure the same error handling still covers non-OK status and other errors and
that you clean up any controller if you use one.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5dda98a6-6cd4-4f80-b4af-d2d5ae9a7122
📒 Files selected for processing (8)
apps/channels/discord/README.mdapps/channels/discord/package.jsonapps/channels/discord/src/bot.tsapps/channels/discord/src/bridge.tsapps/channels/discord/src/discord-api.tsapps/channels/discord/test/bot.test.tsdocs/channel-adapter.mddocs/manual/17-channels.md
| "scripts": { | ||
| "build": "tsc -b", | ||
| "typecheck": "tsc -p tsconfig.typecheck.json --pretty false", | ||
| "test": "node --import tsx --test test/*.test.ts", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if tsx is declared in this package or workspace root
cat apps/channels/discord/package.json | jq -r '.dependencies.tsx // .devDependencies.tsx // "not found"'
# Check workspace root if this is a monorepo
if [ -f package.json ]; then
echo "Workspace root tsx:"
cat package.json | jq -r '.dependencies.tsx // .devDependencies.tsx // "not found"'
fi
# Try running the test script to see if it fails
cd apps/channels/discord && npm test 2>&1 | head -20Repository: HCF-STUDIOS/openhermit
Length of output: 1115
Fix test script so tsx is available to this package.
apps/channels/discord/package.json has no tsx in dependencies/devDependencies, and running npm test from apps/channels/discord fails with ERR_MODULE_NOT_FOUND: Cannot find package 'tsx'. Add tsx to this package’s devDependencies (or fix workspace install/hoisting so this package can resolve it).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/channels/discord/package.json` at line 10, The package.json test script
references "tsx" but this package lacks tsx in its dependencies so running npm
test fails; update apps/channels/discord/package.json by adding "tsx" to
devDependencies (e.g., add a devDependency entry for "tsx" with an appropriate
version) or adjust the workspace/hoisting configuration so the package can
resolve the existing tsx installation; ensure the change targets the
package.json that defines the "test": "node --import tsx --test test/*.test.ts"
script and run an install to verify tests run.
The gateway optionalDependencies still pinned @openhermit/channel-discord at 0.2.0 while the workspace moved to 0.3.0, so a fresh install wouldn't link the updated adapter and the media changes wouldn't take effect in the bundled CLI. Bump the gateway pin and lockfile to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A stalled Discord CDN connection during inbound attachment download could block the per-channel message queue indefinitely. Add a 15s AbortSignal.timeout() to the fetch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Addressed the review:
On the |
Ship the bundled channel media support — Discord/Slack/Telegram attachments (#175, #176, #177) and their gateway pins (now all 0.3.0) — in the published CLI. Also syncs the stale lockfile cli entry (0.9.0 -> 0.9.2) left by the earlier 0.9.1 bump. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Second channel in the attachment-support rollout (after #174 WhatsApp).
Discord was fully text-only — inbound attachments ignored, agent couldn't send files. Wires the channel to the already-complete core attachment infrastructure both directions. No core/protocol/gateway changes.
Inbound (Discord → agent)
client.transcribeAudioand appended as[Transcribed voice message]text.Outbound (agent → Discord)
attachment_senddeliveries (SSEattachmentevent) are sent as Discord file uploads viaAttachmentBuilder, caption as message content.Notes
privatepackage bundled into theopenhermitCLI, so this ships with the next CLI release — no standalone npm publish. Version bumped 0.2.0 → 0.3.0 for changelog clarity.mapRawAttachments).🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Documentation
Tests