fix(discord): escape prose markdown without clobbering structured output
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import { normalizeAgentOutput } from '../agent-protocol.js';
|
import { normalizeAgentOutput } from '../agent-protocol.js';
|
||||||
|
import { neutralizeStrayMarkdown, sanitizeForOutbound } from '../router.js';
|
||||||
import type { OutboundAttachment } from '../types.js';
|
import type { OutboundAttachment } from '../types.js';
|
||||||
|
|
||||||
const LOCAL_MARKDOWN_LINK_RE = /\[[^\]\n]*\]\((\/[^)\n]+)\)/g;
|
const LOCAL_MARKDOWN_LINK_RE = /\[[^\]\n]*\]\((\/[^)\n]+)\)/g;
|
||||||
@@ -46,7 +47,17 @@ export function prepareDiscordOutbound(
|
|||||||
const structuredOutput =
|
const structuredOutput =
|
||||||
normalized.output?.visibility === 'public' ? normalized.output : null;
|
normalized.output?.visibility === 'public' ? normalized.output : null;
|
||||||
const outboundText = structuredOutput?.text ?? normalized.result ?? text;
|
const outboundText = structuredOutput?.text ?? normalized.result ?? text;
|
||||||
const cleanText = sanitizeLocalMarkdownLinks(outboundText);
|
// Redact/strip before escaping so secret patterns (which contain `_`) still
|
||||||
|
// match, then escape stray Discord markdown in free-form agent prose so
|
||||||
|
// emphasis markers (**bold**, ~~strike~~, …) render literally. Author-
|
||||||
|
// controlled structured envelopes are intentional, so their text is left
|
||||||
|
// untouched. Escaping runs before sanitizeLocalMarkdownLinks so the inline
|
||||||
|
// code it deliberately produces is preserved.
|
||||||
|
const safeText = sanitizeForOutbound(outboundText);
|
||||||
|
const renderedText = structuredOutput
|
||||||
|
? safeText
|
||||||
|
: neutralizeStrayMarkdown(safeText);
|
||||||
|
const cleanText = sanitizeLocalMarkdownLinks(renderedText);
|
||||||
const attachments =
|
const attachments =
|
||||||
optionAttachments && optionAttachments.length > 0
|
optionAttachments && optionAttachments.length > 0
|
||||||
? optionAttachments
|
? optionAttachments
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { CACHE_DIR } from '../config.js';
|
|||||||
import { getEnv } from '../env.js';
|
import { getEnv } from '../env.js';
|
||||||
import { logger } from '../logger.js';
|
import { logger } from '../logger.js';
|
||||||
import { validateOutboundAttachments } from '../outbound-attachments.js';
|
import { validateOutboundAttachments } from '../outbound-attachments.js';
|
||||||
import { formatOutbound } from '../router.js';
|
import { sanitizeForOutbound } from '../router.js';
|
||||||
import { hasReviewerLease } from '../service-routing.js';
|
import { hasReviewerLease } from '../service-routing.js';
|
||||||
import type {
|
import type {
|
||||||
DeleteRecentMessagesByContentOptions,
|
DeleteRecentMessagesByContentOptions,
|
||||||
@@ -528,7 +528,9 @@ export class DiscordChannel implements Channel {
|
|||||||
for (const [name, id] of Object.entries(mentionMap)) {
|
for (const [name, id] of Object.entries(mentionMap)) {
|
||||||
cleaned = cleaned.replace(new RegExp(`@${name}`, 'g'), `<@${id}>`);
|
cleaned = cleaned.replace(new RegExp(`@${name}`, 'g'), `<@${id}>`);
|
||||||
}
|
}
|
||||||
cleaned = formatOutbound(cleaned);
|
// Markdown escaping already happened in prepareDiscordOutbound (before
|
||||||
|
// the deliberate link→inline-code step). Here we only strip/redact.
|
||||||
|
cleaned = sanitizeForOutbound(cleaned);
|
||||||
|
|
||||||
// Discord has a 2000 character limit per message and 10 attachments per message
|
// Discord has a 2000 character limit per message and 10 attachments per message
|
||||||
const MAX_LENGTH = 2000;
|
const MAX_LENGTH = 2000;
|
||||||
|
|||||||
Reference in New Issue
Block a user