diff --git a/chat/public/builder.js b/chat/public/builder.js index b7696f1..b0e6417 100644 --- a/chat/public/builder.js +++ b/chat/public/builder.js @@ -1896,6 +1896,17 @@ function hideLoadingIndicator() { window.hideLoadingIndicator = hideLoadingIndicator; function renderMessages(session) { + // Helper function to strip markdown formatting from user input + function stripMarkdownFormatting(text) { + if (!text || typeof text !== 'string') return text; + let cleaned = text; + cleaned = cleaned.replace(/\*\*([^*]+)\*\*/g, '$1'); + cleaned = cleaned.replace(/\*\*/g, ''); + cleaned = cleaned.replace(/^##\s+/gm, ''); + cleaned = cleaned.replace(/##/g, ''); + return cleaned; + } + // Don't clear the loading indicator if it exists const loadingIndicator = document.getElementById('loading-indicator'); // Store reference before clearing, and remove animation class to prevent bounce on re-render @@ -1960,7 +1971,8 @@ function renderMessages(session) { `; const userBody = document.createElement('div'); userBody.className = 'body'; - userBody.appendChild(renderContentWithTodos(msg.displayContent || msg.content || '')); + const contentToRender = isPlanMessage ? stripMarkdownFormatting(msg.displayContent || msg.content || '') : (msg.displayContent || msg.content || ''); + userBody.appendChild(renderContentWithTodos(contentToRender)); userCard.appendChild(userMeta); userCard.appendChild(userBody); // Attachments @@ -3190,7 +3202,18 @@ function streamMessage(sessionId, messageId) { const message = session?.messages.find(m => m.id === messageId); if (message && message.status === 'queued') { - // Server restart was signaled, poll for reconnection + // Check if this is a plan message (don't set error for plan messages, just log) + const isPlanMessage = message.phase === 'plan' || message.cli !== 'opencode'; + + if (isPlanMessage) { + // For plan messages, just log and don't modify the message + console.log('[SSE] Plan message encountered server restart, preserving original content', { messageId, sessionId }); + hideLoadingIndicator(); + setStatus('Service temporarily unavailable. Please try again in a moment.'); + return; + } + + // For OpenCode messages, poll for reconnection console.log('Server restart detected, attempting reconnection...', { messageId, sessionId }); let reconnectAttempts = 0; const maxReconnectAttempts = 30; // 30 seconds max diff --git a/chat/server.js b/chat/server.js index 6d72c8e..a90349a 100644 --- a/chat/server.js +++ b/chat/server.js @@ -9038,9 +9038,22 @@ async function handlePlanMessage(req, res, userId) { const session = getSession(sessionId, userId); if (!session) return sendJson(res, 404, { error: 'Session not found' }); + // Helper function to strip markdown formatting from display content + function stripMarkdownFromDisplay(text) { + if (!text || typeof text !== 'string') return text; + let cleaned = text; + cleaned = cleaned.replace(/\*\*([^*]+)\*\*/g, '$1'); + cleaned = cleaned.replace(/\*\*/g, ''); + cleaned = cleaned.replace(/^##\s+/gm, ''); + cleaned = cleaned.replace(/##/g, ''); + return cleaned; + } + // Sanitize user input to prevent prompt injection const content = sanitizePromptInput(body.content || ''); - const displayContent = typeof body.displayContent === 'string' && body.displayContent.trim() ? sanitizePromptInput(body.displayContent) : content; + const displayContent = typeof body.displayContent === 'string' && body.displayContent.trim() ? + stripMarkdownFromDisplay(sanitizePromptInput(body.displayContent)) : + stripMarkdownFromDisplay(content); if (!content) return sendJson(res, 400, { error: 'Message is required' }); const userPlan = resolveUserPlan(session.userId); const allowance = canConsumeTokens(session.userId, userPlan, estimateTokensFromText(content) + TOKEN_ESTIMATION_BUFFER); @@ -10293,7 +10306,7 @@ function shouldFallbackCliError(err, message) { // Rate limiting - these require fallback /error:.*rate limit exceeded/i, /error:.*too many requests/i, - /error:.*rate limited/i, + /error:.*rate limited/gi, // Size limits - clear model constraints /error:.*request too large/i, /error:.*token limit exceeded/i,