fix(v2): retry as plain text when adapter rejects markdown

A single message with markdown the adapter couldn't parse (e.g. Telegram
MarkdownV2 entity errors) would fail in deliverSessionMessages and be
retried forever, blocking every subsequent reply on that session.

Catch ValidationError from postMessage and retry once with the markdown
stripped to plain text via markdownToPlainText. Files re-attach in a
follow-up post since the plain-text retry drops the files payload shape.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Koshkoshinsk
2026-04-12 09:32:12 +00:00
parent 9dda75bb21
commit 4c477acca3
+26 -6
View File
@@ -14,10 +14,12 @@ import {
Button,
Modal,
TextInput,
markdownToPlainText,
type Adapter,
type ConcurrencyStrategy,
type Message as ChatMessage,
} from 'chat';
import { ValidationError } from '@chat-adapter/shared';
import { log } from '../log.js';
import { SqliteStateAdapter } from '../state-sqlite.js';
import type { ChannelAdapter, ChannelSetup, ConversationConfig, InboundMessage } from './adapter.js';
@@ -373,12 +375,30 @@ export function createChatSdkBridge(config: ChatSdkBridgeConfig): ChannelAdapter
data: f.data,
filename: f.filename,
}));
if (fileUploads && fileUploads.length > 0) {
const result = await adapter.postMessage(tid, { markdown: text, files: fileUploads });
return result?.id;
} else {
const result = await adapter.postMessage(tid, { markdown: text });
return result?.id;
try {
if (fileUploads && fileUploads.length > 0) {
const result = await adapter.postMessage(tid, { markdown: text, files: fileUploads });
return result?.id;
} else {
const result = await adapter.postMessage(tid, { markdown: text });
return result?.id;
}
} catch (err) {
// Permanent formatting failure (e.g. Telegram MarkdownV2 entity parse error):
// retry once as plain text so the queue isn't blocked forever.
if (err instanceof ValidationError) {
log.warn('Markdown rejected by adapter, retrying as plain text', {
adapter: adapter.name,
err: err.message,
});
const plain = markdownToPlainText(text);
const result = await adapter.postMessage(tid, plain);
if (fileUploads && fileUploads.length > 0) {
await adapter.postMessage(tid, { markdown: '', files: fileUploads });
}
return result?.id;
}
throw err;
}
} else if (message.files && message.files.length > 0) {
// Files only, no text