Skip to content

Commit b4b49d0

Browse files
committed
feat(shared): add MarkdownV2 utilities and sanitization
1 parent 3a05593 commit b4b49d0

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

packages/shared/src/index.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,87 @@ export async function markdownToHtml(s: string): Promise<string> {
191191
return (parsed as string).replace(/\n{3,}/g, '\n\n').trim();
192192
}
193193

194+
export function sanitizeMarkdownV2(text: string): string {
195+
return text.replace(/([_*[\]()~`>#+\-=|{}.!])/g, '\\$1');
196+
}
197+
198+
export async function markdownToMarkdownV2(s: string): Promise<string> {
199+
const renderer = new marked.Renderer();
200+
201+
const escape = (text: string) => sanitizeMarkdownV2(text);
202+
203+
renderer.heading = ({ tokens }) => {
204+
const text = renderer.parser.parseInline(tokens);
205+
return `*${text}*\n\n`;
206+
};
207+
208+
renderer.paragraph = ({ tokens }) => {
209+
const text = renderer.parser.parseInline(tokens);
210+
return `${text}\n\n`;
211+
};
212+
213+
renderer.br = () => '\n';
214+
215+
renderer.list = ({ items, ordered, start }) => {
216+
let result = '';
217+
for (let i = 0; i < items.length; i++) {
218+
const item = items[i];
219+
const prefix = ordered
220+
? `${start !== '' && start !== undefined ? Number(start) + i : i + 1}\\. `
221+
: '• ';
222+
result += `${prefix}${renderer.listitem(item)}\n`;
223+
}
224+
return result;
225+
};
226+
227+
renderer.listitem = (item) => {
228+
return renderer.parser.parse(item.tokens).trim();
229+
};
230+
231+
renderer.strong = ({ tokens }) => `*${renderer.parser.parseInline(tokens)}*`;
232+
renderer.em = ({ tokens }) => `_${renderer.parser.parseInline(tokens)}_`;
233+
renderer.codespan = ({ text }) => `\`${text.replace(/[`\\]/g, '\\$&')}\``;
234+
renderer.code = ({ text, lang }) => {
235+
const escapedText = text.replace(/[`\\]/g, '\\$&');
236+
if (lang) {
237+
return `\`\`\`${lang}\n${escapedText}\n\`\`\`\n`;
238+
}
239+
return `\`\`\`\n${escapedText}\n\`\`\`\n`;
240+
};
241+
renderer.del = ({ tokens }) => `~${renderer.parser.parseInline(tokens)}~`;
242+
243+
renderer.link = ({ href, tokens }) =>
244+
`[${renderer.parser.parseInline(tokens)}](${escape(href)})`;
245+
renderer.image = ({ href, text }) => `[${escape(text)}](${escape(href)})`;
246+
247+
renderer.blockquote = ({ tokens }) => {
248+
const text = renderer.parser.parse(tokens).trim();
249+
return text
250+
.split('\n')
251+
.map((line) => `>${line}`)
252+
.join('\n');
253+
};
254+
255+
renderer.hr = () => `────────\n\n`;
256+
257+
renderer.text = (token) => {
258+
if ('tokens' in token && token.tokens) {
259+
return renderer.parser.parseInline(token.tokens);
260+
}
261+
return escape(token.text);
262+
};
263+
264+
marked.setOptions({
265+
gfm: true,
266+
breaks: true
267+
});
268+
269+
const parsed = await marked.parse(s, { renderer });
270+
271+
// Trim multiple newlines
272+
return (parsed as string).replace(/\n{3,}/g, '\n\n').trim();
273+
}
274+
194275
export const SYSTEM_PROMPTS = {
195276
TUX_ROBOT:
196277
'You are a friendly assistant named TuxRobot. You have access to an HTTP fetch tool, a web search tool, and document tools. If a user asks you to get data from an API, look up a profile, or visit a website, you MUST execute the fetch tool yourself to get the data. You can perform web searches using the `tavily_search` tool. If the user asks about an uploaded document, a file, a PDF, or a markdown file, you MUST use the `search_telegram_file` tool to search its contents; do NOT use `tavily_search` or write code. If a user asks a follow-up question about a document they previously uploaded, use the tool again if needed. When calling tools, use the EXACT name provided (e.g., `search_telegram_file`); do NOT add any prefixes like "functions.". If the user replies with only a single word, sticker, or emoji, respond with no more than one short paragraph. Always keep replies below 4096 characters. Only use formatting that will be supported on Telegram. DO NOT use LaTeX formatting or math equations (like \\( ... \\) or \\[ ... \\]); always use standard plain text or simple markdown formatting as LaTeX does not render on Telegram.',

0 commit comments

Comments
 (0)