Skip to content

fix(discord): chunk replies over 2000 chars instead of truncating#2812

Open
axnjxn415 wants to merge 2 commits into
nanocoai:channelsfrom
axnjxn415:fix/discord-chunk-long-replies
Open

fix(discord): chunk replies over 2000 chars instead of truncating#2812
axnjxn415 wants to merge 2 commits into
nanocoai:channelsfrom
axnjxn415:fix/discord-chunk-long-replies

Conversation

@axnjxn415

Copy link
Copy Markdown

What

The Chat SDK bridge ships a splitForLimit chunker (src/channels/chat-sdk-bridge.ts) that splits a reply longer than maxTextLength across multiple platform messages. It only runs when the adapter passes maxTextLength into createChatSdkBridge. The Discord adapter never set it, so any reply over Discord's 2000-char hard cap was silently truncated with an ellipsis by @chat-adapter/discord instead of being chunked.

This sets maxTextLength: 2000 on the Discord adapter so long replies chunk across multiple messages.

Why

Whenever an agent emits a single reply over 2000 chars, the message is cut off mid-sentence with and the remainder is lost — no error, no log. It shows up more often with more verbose models that tend to write longer single messages. Observed in production.

Note — same omission in other adapters

Several other adapters call createChatSdkBridge without maxTextLength and have the same latent truncation: gchat, github, imessage, linear, matrix, resend, slack, teams, webex, whatsapp-cloud. Only discord (after this PR) and telegram set it.

I scoped this PR to Discord — the confirmed, production-verified case — rather than guess each platform's character limit. Flagging it here in case you'd like to extend the fix across the fleet.

Testing

Verified across three production installs: with maxTextLength set, splitForLimit engages and replies over the cap arrive as multiple messages instead of one truncated message. No behavior change for replies under the cap.

The Chat SDK bridge ships a splitForLimit chunker that splits long
replies across multiple messages, but it only runs when the adapter
sets maxTextLength. The Discord adapter never set it, so any reply
over Discord's 2000-char hard cap was silently truncated with an
ellipsis by @chat-adapter/discord instead of being chunked.

Set maxTextLength: 2000 so long Discord replies chunk across multiple
messages. Surfaces most often with verbose models that emit long
single messages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mksocial19-code

Copy link
Copy Markdown

Maintainer pass looks good overall — the Discord fix is scoped and the bridge already has the right chunking path.

I verified locally in a disposable checkout:

npx vitest run src/channels/chat-sdk-bridge.test.ts src/channels/discord-registration.test.ts

Result with the added regression below: 2 test files passed, 9 tests passed.

Before merge, please add this small regression test so the maxTextLength delivery path is covered directly:

diff --git a/src/channels/chat-sdk-bridge.test.ts b/src/channels/chat-sdk-bridge.test.ts
index 7e3c4ff..164a3f2 100644
--- a/src/channels/chat-sdk-bridge.test.ts
+++ b/src/channels/chat-sdk-bridge.test.ts
@@ -77,4 +77,27 @@ describe('createChatSdkBridge', () => {
     });
     expect(typeof bridge.subscribe).toBe('function');
   });
+
+  it('splits outbound text when maxTextLength is set', async () => {
+    const posted: string[] = [];
+    const bridge = createChatSdkBridge({
+      adapter: stubAdapter({
+        postMessage: async (_threadId: string, message: { markdown?: string }) => {
+          posted.push(message.markdown ?? '');
+          return { id: `msg-${posted.length}` };
+        },
+      }),
+      supportsThreads: true,
+      maxTextLength: 10,
+    });
+
+    const id = await bridge.deliver('stub:channel', null, {
+      content: { text: 'alpha bravo charlie delta' },
+    });
+
+    expect(id).toBe('msg-1');
+    expect(posted.length).toBeGreaterThan(1);
+    expect(posted.every((chunk) => chunk.length <= 10)).toBe(true);
+    expect(posted.join(' ')).toBe('alpha bravo charlie delta');
+  });
 });

I tried pushing this directly because maintainerCanModify is true, but GitHub rejected push to the fork branch for my token. So leaving the exact patch here instead.

@mksocial19-code

Copy link
Copy Markdown

Reviewed this and opened a replacement with regression coverage: #2816

Delta: same Discord maxTextLength=2000 fix, plus a registration test proving the Discord adapter passes the limit to createChatSdkBridge.

axnjxn415 pushed a commit to axnjxn415/nanoclaw that referenced this pull request Jun 19, 2026
…egress

Adds src/channels/discord.test.ts — stubs the factory's collaborators and
asserts the Discord adapter passes maxTextLength: 2000 into createChatSdkBridge.
Verified it fails if the line is removed. Addresses review feedback on nanocoai#2812.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…egress

Adds src/channels/discord.test.ts — stubs the factory's collaborators and
asserts the Discord adapter passes maxTextLength: 2000 into createChatSdkBridge.
Verified it fails if the line is removed. Addresses review feedback on nanocoai#2812.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@axnjxn415 axnjxn415 force-pushed the fix/discord-chunk-long-replies branch from 9709d52 to ebee085 Compare June 19, 2026 11:13
@axnjxn415

Copy link
Copy Markdown
Author

Thanks for the review. Added a regression test (src/channels/discord.test.ts) that asserts the Discord adapter passes maxTextLength: 2000 into createChatSdkBridge — it fails if the line is removed (verified), is prettier-clean, and passes locally.

I kept it as a focused adapter test next to the existing discord-registration.test.ts, since the regression we care about is the Discord adapter wiring the limit — happy to fold it into chat-sdk-bridge.test.ts instead if you'd prefer.

This PR is the original fix for the truncation bug; #2816 duplicates the same one-line change, so this one can land standalone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants