fix: keep notification summaries in plain text
- Force notification summaries to avoid markdown formatting - Normalize generated notification text before system display - Cover plain-text notification formatting with tests
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# Notifications Module Documentation
|
||||
|
||||
## Purpose
|
||||
This module provides notification message preparation utilities for the web server runtime, including text truncation and optional message summarization for system notifications.
|
||||
This module provides notification message preparation utilities for the web server runtime, including text truncation, plain-text normalization, and optional message summarization for system notifications.
|
||||
|
||||
## Entrypoints and structure
|
||||
- `packages/web/server/lib/notifications/index.js`: public entrypoint imported by `packages/web/server/index.js`.
|
||||
@@ -107,6 +107,7 @@ The `settings` parameter for `prepareNotificationLastMessage` supports:
|
||||
- Returns empty string for empty/null message.
|
||||
- Returns truncated original message if summarization disabled, message under threshold, or summarization fails.
|
||||
- Returns truncated summary if summarization succeeds and returns non-empty string.
|
||||
- Normalizes markdown-like formatting to plain text before truncation.
|
||||
- Always applies `maxLastMessageLength` truncation to final result.
|
||||
|
||||
## Notes for contributors
|
||||
|
||||
@@ -9,6 +9,26 @@ const resolvePositiveNumber = (value, fallback) => {
|
||||
return value;
|
||||
};
|
||||
|
||||
const normalizeNotificationPlainText = (text) => {
|
||||
if (typeof text !== 'string') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return text
|
||||
.replace(/```[\s\S]*?```/g, ' ')
|
||||
.replace(/`([^`]*)`/g, '$1')
|
||||
.replace(/^[\t ]*[-*+]\s+/gm, '')
|
||||
.replace(/^#{1,6}\s+/gm, '')
|
||||
.replace(/\*\*(.*?)\*\*/g, '$1')
|
||||
.replace(/__(.*?)__/g, '$1')
|
||||
.replace(/\*(.*?)\*/g, '$1')
|
||||
.replace(/_(.*?)_/g, '$1')
|
||||
.replace(/\[(.*?)\]\((.*?)\)/g, '$1')
|
||||
.replace(/\s*\n\s*/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
};
|
||||
|
||||
export const truncateNotificationText = (text, maxLength = DEFAULT_NOTIFICATION_MESSAGE_MAX_LENGTH) => {
|
||||
if (typeof text !== 'string') {
|
||||
return '';
|
||||
@@ -45,5 +65,6 @@ export const prepareNotificationLastMessage = async ({ message, settings, summar
|
||||
}
|
||||
}
|
||||
|
||||
return truncateNotificationText(messageForNotification, maxLastMessageLength);
|
||||
const plainTextMessage = normalizeNotificationPlainText(messageForNotification) || normalizeNotificationPlainText(originalMessage);
|
||||
return truncateNotificationText(plainTextMessage, maxLastMessageLength);
|
||||
};
|
||||
|
||||
@@ -56,4 +56,19 @@ describe('notification message helpers', () => {
|
||||
|
||||
expect(result).toBe('short summary');
|
||||
});
|
||||
|
||||
it('normalizes markdown summary to plain text', async () => {
|
||||
const result = await prepareNotificationLastMessage({
|
||||
message: '0123456789',
|
||||
summarize: async () => "**Committed.**\n\n- Commit: `85924b9d`\n- Message: `fix desktop notifications`",
|
||||
settings: {
|
||||
summarizeLastMessage: true,
|
||||
summaryThreshold: 5,
|
||||
summaryLength: 80,
|
||||
maxLastMessageLength: 200,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBe('Committed. Commit: 85924b9d Message: fix desktop notifications');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -134,7 +134,6 @@ export const createNotificationTriggerRuntime = (deps) => {
|
||||
}
|
||||
|
||||
const sessionId = extractSessionIdFromPayload(payload);
|
||||
|
||||
if (payload.type === 'message.updated') {
|
||||
const info = payload.properties?.info;
|
||||
if (info?.role === 'assistant' && info?.finish === 'stop' && sessionId) {
|
||||
|
||||
@@ -138,7 +138,7 @@ export const createNotificationTemplateRuntime = (deps) => {
|
||||
if (!text || typeof text !== 'string' || text.trim().length === 0) return text;
|
||||
|
||||
try {
|
||||
const prompt = `Summarize the following text in approximately ${targetLength} characters. Be concise and capture the key point. Output ONLY the summary text, nothing else.\n\nText:\n${text}`;
|
||||
const prompt = `Summarize the following text in approximately ${targetLength} characters. Be concise and capture the key point. Output plain text only. Do not use markdown, bullets, headings, code fences, backticks, or quotes. Output only the summary text.\n\nText:\n${text}`;
|
||||
|
||||
const completionTimeout = createTimeoutSignal(15000);
|
||||
let response;
|
||||
|
||||
Reference in New Issue
Block a user