diff --git a/apps/web/src/app/(authenticated)/usage/Messages.test.tsx b/apps/web/src/app/(authenticated)/usage/Messages.test.tsx new file mode 100644 index 0000000000..64eeb8569a --- /dev/null +++ b/apps/web/src/app/(authenticated)/usage/Messages.test.tsx @@ -0,0 +1,103 @@ +import { describe, it, expect } from 'vitest'; + +describe('Messages component integration', () => { + it('should parse newTask tool data correctly', () => { + const toolText = JSON.stringify({ + tool: 'newTask', + mode: 'Code', + content: 'Implement a new authentication system', + }); + + let toolData = null; + let isNewTask = false; + + try { + toolData = JSON.parse(toolText); + isNewTask = toolData?.tool === 'newTask'; + } catch { + // Invalid JSON, treat as regular tool message + } + + expect(isNewTask).toBe(true); + expect(toolData?.mode).toBe('Code'); + expect(toolData?.content).toBe('Implement a new authentication system'); + }); + + it('should handle invalid JSON gracefully', () => { + const toolText = 'invalid json'; + + let toolData = null; + let isNewTask = false; + + try { + toolData = JSON.parse(toolText); + isNewTask = toolData?.tool === 'newTask'; + } catch { + // Invalid JSON, treat as regular tool message + } + + expect(isNewTask).toBe(false); + expect(toolData).toBe(null); + }); + + it('should identify non-newTask tools correctly', () => { + const toolText = JSON.stringify({ + tool: 'readFile', + path: 'src/app.ts', + }); + + let toolData = null; + let isNewTask = false; + + try { + toolData = JSON.parse(toolText); + isNewTask = toolData?.tool === 'newTask'; + } catch { + // Invalid JSON, treat as regular tool message + } + + expect(isNewTask).toBe(false); + expect(toolData?.tool).toBe('readFile'); + }); + + it('should handle subtask_result messages correctly', () => { + // Test the isVisible function logic for subtask_result messages + const isVisible = (message: { + type: string; + ask?: string; + say?: string; + text?: string; + }) => { + if ( + message.type === 'ask' && + (message.ask === 'followup' || + message.ask === 'command' || + message.ask === 'tool') + ) { + return true; + } + + return ( + (message.ask === 'text' || + message.say === 'text' || + message.say === 'completion_result' || + message.say === 'subtask_result' || + message.say === 'user_feedback') && + typeof message.text === 'string' && + message.text.length > 0 + ); + }; + + const subtaskResultMessage = { + type: 'say', + say: 'subtask_result', + text: 'Subtask completed successfully with the following results...', + }; + + expect(isVisible(subtaskResultMessage)).toBe(true); + expect(subtaskResultMessage.say).toBe('subtask_result'); + expect(subtaskResultMessage.text).toBe( + 'Subtask completed successfully with the following results...', + ); + }); +}); diff --git a/apps/web/src/app/(authenticated)/usage/Messages.tsx b/apps/web/src/app/(authenticated)/usage/Messages.tsx index fcbd9f097e..27f93e1cc9 100644 --- a/apps/web/src/app/(authenticated)/usage/Messages.tsx +++ b/apps/web/src/app/(authenticated)/usage/Messages.tsx @@ -221,7 +221,103 @@ export const Messages = ({ const messageId = `message-${message.id}`; - // For tool messages, render only the tool usage badge in the space between bubbles + // Parse tool data to check for special cases + let toolData = null; + let isNewTask = false; + if (isTool && message.text) { + try { + toolData = JSON.parse(message.text); + isNewTask = toolData?.tool === 'newTask'; + } catch { + // Invalid JSON, treat as regular tool message + } + } + + // For newTask tool messages, render the full content + if (isNewTask && toolData) { + return ( +
+
+
+
+ + + + New task created in {toolData.mode} mode +
+
+
+
+ + {toolData.content} + +
+
+
+
+ ); + } + + // For subtask_result messages, render with special styling + if (message.say === 'subtask_result') { + return ( +
+
+
+
+ + + + Subtask results +
+
+
+
+ + {message.text} + +
+
+
+
+ ); + } + + // For other tool messages, render only the tool usage badge in the space between bubbles if (isTool) { return (
@@ -424,6 +520,7 @@ const isVisible = (message: Message) => { (message.ask === 'text' || message.say === 'text' || message.say === 'completion_result' || + message.say === 'subtask_result' || message.say === 'user_feedback') && typeof message.text === 'string' && message.text.length > 0