Long messages silently dropped — missing chunker function in outbound config
Summary
Agent responses longer than ~15KB are silently dropped and never delivered to SimpleX. The agent completes the work (visible in gateway logs via journalctl) but the message never arrives on the user's phone. Short messages work fine.
Environment
- OpenClaw 2026.3.28 (build f9b1079)
@dangoldbj/openclaw-simplex 0.2.1
- SimpleX Chat CLI v6.4.10.0
- Node.js 22.22.0
- Platform: Intel NUC, Ubuntu (x86_64)
Root cause
SimpleX has a hard protocol limit of ~15,610 bytes per JSON message ([protocol spec](https://github.com/simplex-chat/simplex-chat/blob/stable/docs/protocol/simplex-chat.md)). LLM responses routinely exceed this.
Chunking was intended but is incomplete
The plugin already sets textChunkLimit: 4e3 in the outbound config (chunk-CYH4TCC4.js, line ~2612), which shows chunking was intended. However, the gateway requires two properties to actually split messages:
textChunkLimit — the max size per chunk ✅ (set to 4000 bytes)
chunker — a function that splits the text ❌ (never provided)
The gateway's reply-payload dispatcher (reply-payload-CJqP_sJ6.js, line ~104) checks for both:
const chunks = limit && params.chunker ? params.chunker(text, limit) : [text];
Because params.chunker is undefined, the ternary falls through to [text] — sending the entire response as one unsplit message. SimpleX silently rejects it. No error is thrown, no warning is logged. The message simply vanishes.
Other built-in OpenClaw channels (e.g. Twitch) provide both properties, so they chunk correctly:
chunker: chunkTextForOutbound,
chunkerMode: "markdown",
This failure is invisible
The combination of the gateway silently falling back to no splitting and SimpleX silently dropping oversized messages means there is no indication anywhere that something went wrong. The agent believes it responded successfully. The user sees nothing. The only way to diagnose this is to read the gateway logs and notice the response was generated but never delivered.
Note: It's also worth considering whether the gateway itself should provide a default chunker when a textChunkLimit is set without a chunker function. The current behaviour of silently falling back to [text] makes this class of bug invisible and hard to diagnose for any channel plugin. At minimum, a warning log when textChunkLimit is set but chunker is missing would help.
Fix
Add an inline chunker arrow function to the outbound config object, immediately after textChunkLimit: 4e3,.
Diff (against compiled dist/chunk-CYH4TCC4.js)
outbound: {
deliveryMode: "direct",
textChunkLimit: 4e3,
+ chunker: (text, limit) => {
+ if (!text || text.length <= limit) return [text];
+ const chunks = [];
+ let remaining = text;
+ while (remaining.length > 0) {
+ if (remaining.length <= limit) {
+ chunks.push(remaining);
+ break;
+ }
+ let splitAt = -1;
+ const range = remaining.substring(0, limit);
+ // Prefer splitting at paragraph breaks
+ const para = range.lastIndexOf("\n\n");
+ if (para > limit * 0.3) {
+ splitAt = para + 2;
+ } else {
+ // Fall back to line breaks
+ const line = range.lastIndexOf("\n");
+ if (line > limit * 0.3) {
+ splitAt = line + 1;
+ } else {
+ // Fall back to spaces
+ const space = range.lastIndexOf(" ");
+ if (space > limit * 0.3) {
+ splitAt = space + 1;
+ } else {
+ // Hard split as last resort
+ splitAt = limit;
+ }
+ }
+ }
+ chunks.push(remaining.substring(0, splitAt));
+ remaining = remaining.substring(splitAt);
+ }
+ return chunks;
+ },
sendPayload: async ({ cfg, to, payload, accountId }) => {
Where to apply in the TypeScript source
The equivalent change would go in the source file that defines the outbound object for the SimpleX channel (likely src/actions.ts or wherever the outbound transport hooks are defined). Add the chunker property to the object that already contains textChunkLimit: 4e3.
How to reproduce
- Install
@dangoldbj/openclaw-simplex 0.2.1
- Configure SimpleX as a channel and pair a phone
- Ask the agent a question that produces a long response (e.g. "Write a detailed 2000-word guide on setting up a Linux home server")
- Observe: the agent generates the response (visible in
journalctl --user -u openclaw-gateway -f) but nothing arrives on SimpleX
- Send "hi" — a short response arrives fine
Workaround (patch script)
Until this is fixed in the plugin, users can run this Node.js script to patch the compiled JS directly:
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const TARGET = path.join(
process.env.HOME,
'.openclaw/extensions/simplex/dist/chunk-CYH4TCC4.js'
);
if (!fs.existsSync(TARGET)) {
console.error('ERROR: Plugin file not found at', TARGET);
process.exit(1);
}
const backup = `${TARGET}.bak.${Date.now()}`;
fs.copyFileSync(TARGET, backup);
console.log('Backed up to:', backup);
let code = fs.readFileSync(TARGET, 'utf8');
if (code.includes('chunker:')) {
console.log('Already patched.');
process.exit(0);
}
const needle = 'textChunkLimit: 4e3,';
const idx = code.indexOf(needle);
if (idx === -1) {
console.error('ERROR: Could not find "textChunkLimit: 4e3,"');
process.exit(1);
}
const chunkerArrow = `
chunker: (text, limit) => {
if (!text || text.length <= limit) return [text];
const chunks = [];
let remaining = text;
while (remaining.length > 0) {
if (remaining.length <= limit) {
chunks.push(remaining);
break;
}
let splitAt = -1;
const range = remaining.substring(0, limit);
const para = range.lastIndexOf("\\n\\n");
if (para > limit * 0.3) {
splitAt = para + 2;
} else {
const line = range.lastIndexOf("\\n");
if (line > limit * 0.3) {
splitAt = line + 1;
} else {
const space = range.lastIndexOf(" ");
if (space > limit * 0.3) {
splitAt = space + 1;
} else {
splitAt = limit;
}
}
}
chunks.push(remaining.substring(0, splitAt));
remaining = remaining.substring(splitAt);
}
return chunks;
},`;
code = code.substring(0, idx + needle.length) + chunkerArrow + code.substring(idx + needle.length);
fs.writeFileSync(TARGET, code, 'utf8');
const verify = fs.readFileSync(TARGET, 'utf8');
if (verify.includes('chunker:') && verify.includes('remaining.substring')) {
console.log('SUCCESS: Patch applied. Restart the gateway:');
console.log(' systemctl --user restart openclaw-gateway');
} else {
console.error('ERROR: Verification failed. Restoring backup...');
fs.copyFileSync(backup, TARGET);
process.exit(1);
}
Save as patch-simplex-chunker.js, then run:
node patch-simplex-chunker.js
systemctl --user restart openclaw-gateway
Note: This patch is overwritten if the plugin is updated. Re-run the script after any openclaw plugins install @dangoldbj/openclaw-simplex.
Long messages silently dropped — missing
chunkerfunction in outbound configSummary
Agent responses longer than ~15KB are silently dropped and never delivered to SimpleX. The agent completes the work (visible in gateway logs via
journalctl) but the message never arrives on the user's phone. Short messages work fine.Environment
@dangoldbj/openclaw-simplex0.2.1Root cause
SimpleX has a hard protocol limit of ~15,610 bytes per JSON message ([protocol spec](https://github.com/simplex-chat/simplex-chat/blob/stable/docs/protocol/simplex-chat.md)). LLM responses routinely exceed this.
Chunking was intended but is incomplete
The plugin already sets
textChunkLimit: 4e3in the outbound config (chunk-CYH4TCC4.js, line ~2612), which shows chunking was intended. However, the gateway requires two properties to actually split messages:textChunkLimit— the max size per chunk ✅ (set to 4000 bytes)chunker— a function that splits the text ❌ (never provided)The gateway's reply-payload dispatcher (
reply-payload-CJqP_sJ6.js, line ~104) checks for both:Because
params.chunkerisundefined, the ternary falls through to[text]— sending the entire response as one unsplit message. SimpleX silently rejects it. No error is thrown, no warning is logged. The message simply vanishes.Other built-in OpenClaw channels (e.g. Twitch) provide both properties, so they chunk correctly:
This failure is invisible
The combination of the gateway silently falling back to no splitting and SimpleX silently dropping oversized messages means there is no indication anywhere that something went wrong. The agent believes it responded successfully. The user sees nothing. The only way to diagnose this is to read the gateway logs and notice the response was generated but never delivered.
Note: It's also worth considering whether the gateway itself should provide a default chunker when a
textChunkLimitis set without achunkerfunction. The current behaviour of silently falling back to[text]makes this class of bug invisible and hard to diagnose for any channel plugin. At minimum, a warning log whentextChunkLimitis set butchunkeris missing would help.Fix
Add an inline
chunkerarrow function to theoutboundconfig object, immediately aftertextChunkLimit: 4e3,.Diff (against compiled
dist/chunk-CYH4TCC4.js)outbound: { deliveryMode: "direct", textChunkLimit: 4e3, + chunker: (text, limit) => { + if (!text || text.length <= limit) return [text]; + const chunks = []; + let remaining = text; + while (remaining.length > 0) { + if (remaining.length <= limit) { + chunks.push(remaining); + break; + } + let splitAt = -1; + const range = remaining.substring(0, limit); + // Prefer splitting at paragraph breaks + const para = range.lastIndexOf("\n\n"); + if (para > limit * 0.3) { + splitAt = para + 2; + } else { + // Fall back to line breaks + const line = range.lastIndexOf("\n"); + if (line > limit * 0.3) { + splitAt = line + 1; + } else { + // Fall back to spaces + const space = range.lastIndexOf(" "); + if (space > limit * 0.3) { + splitAt = space + 1; + } else { + // Hard split as last resort + splitAt = limit; + } + } + } + chunks.push(remaining.substring(0, splitAt)); + remaining = remaining.substring(splitAt); + } + return chunks; + }, sendPayload: async ({ cfg, to, payload, accountId }) => {Where to apply in the TypeScript source
The equivalent change would go in the source file that defines the
outboundobject for the SimpleX channel (likelysrc/actions.tsor wherever the outbound transport hooks are defined). Add thechunkerproperty to the object that already containstextChunkLimit: 4e3.How to reproduce
@dangoldbj/openclaw-simplex0.2.1journalctl --user -u openclaw-gateway -f) but nothing arrives on SimpleXWorkaround (patch script)
Until this is fixed in the plugin, users can run this Node.js script to patch the compiled JS directly:
Save as
patch-simplex-chunker.js, then run:Note: This patch is overwritten if the plugin is updated. Re-run the script after any
openclaw plugins install @dangoldbj/openclaw-simplex.