Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## What's new in 4.0.31

### Improvements

- **RovoDev**: Collapsed completed tool call results in the thinking drawer for a more compact chat view. Users can still expand the drawer to see details.

### Bug Fixes

- **RovoDev**: Hid stack traces, stderr, and log details from external users while preserving them for Atlassian users.
Expand Down
15 changes: 15 additions & 0 deletions src/rovo-dev/ui/RovoDev.css
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,21 @@ body {
word-break: break-all;
}

.tool-return-collapsed {
border: none;
padding: 2px 6px;
margin-bottom: 2px;
gap: 6px;
}

.tool-return-collapsed-text {
font-size: 12px;
color: var(--vscode-input-placeholderForeground);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.tool-return-bash-command {
pre {
margin: 0;
Expand Down
11 changes: 10 additions & 1 deletion src/rovo-dev/ui/common/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ export const renderChatHistory = (
retryAfterError: () => void,
onError: (error: Error, errorMessage: string) => void,
isAtlassianUser?: boolean,
collapsedToolReturns?: boolean,
) => {
switch (msg.event_kind) {
case 'tool-return':
Expand All @@ -223,7 +224,15 @@ export const renderChatHistory = (
if (message.todoData) {
return <ToDoList key={index} todos={message.todoData} />;
}
return <ToolReturnParsedItem key={index} msg={message} openFile={openFile} onLinkClick={onLinkClick} />;
return (
<ToolReturnParsedItem
key={index}
msg={message}
openFile={openFile}
onLinkClick={onLinkClick}
collapsed={collapsedToolReturns}
/>
);
});
case '_RovoDevDialog':
let customButton: { text: string; onClick: () => void } | undefined = undefined;
Expand Down
1 change: 1 addition & 0 deletions src/rovo-dev/ui/messaging/MessageDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const MessageDrawer: React.FC<MessageDrawerProps> = ({
retryPromptAfterError,
onError,
isAtlassianUser,
true, // collapse tool returns for compact display
),
)}
</div>
Expand Down
61 changes: 61 additions & 0 deletions src/rovo-dev/ui/tools/ToolReturnItem.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,65 @@ describe('ToolReturnParsedItem', () => {
render(<ToolReturnParsedItem msg={msg} openFile={mockOpenFile} onLinkClick={mockOnLinkClick} />);
}).not.toThrow();
});

test('renders collapsed view with content and title', () => {
const msg: ToolReturnParseResult = {
content: 'Replaced code',
title: 'myFile.ts',
type: 'modify',
filePath: '/path/to/myFile.ts',
};

const { getByText, container } = render(
<ToolReturnParsedItem msg={msg} openFile={mockOpenFile} onLinkClick={mockOnLinkClick} collapsed={true} />,
);

expect(container.querySelector('.tool-return-collapsed')).toBeTruthy();
expect(getByText('Replaced code — myFile.ts')).toBeTruthy();
});

test('renders collapsed view with content only (no title)', () => {
const msg: ToolReturnParseResult = {
content: 'Searched files',
type: 'open',
};

const { getByText, container } = render(
<ToolReturnParsedItem msg={msg} openFile={mockOpenFile} onLinkClick={mockOnLinkClick} collapsed={true} />,
);

expect(container.querySelector('.tool-return-collapsed')).toBeTruthy();
expect(getByText('Searched files')).toBeTruthy();
});

test('collapsed view calls openFile when clicked with filePath', () => {
const filePath = '/path/to/file.ts';
const msg: ToolReturnParseResult = {
content: 'Opened file',
type: 'open',
filePath,
};

const { getByText } = render(
<ToolReturnParsedItem msg={msg} openFile={mockOpenFile} onLinkClick={mockOnLinkClick} collapsed={true} />,
);

fireEvent.click(getByText('Opened file'));
expect(mockOpenFile).toHaveBeenCalledWith(filePath);
});

test('renders expanded view by default (collapsed=false)', () => {
const msg: ToolReturnParseResult = {
content: 'Replaced code',
title: 'myFile.ts',
type: 'modify',
filePath: '/path/to/myFile.ts',
};

const { container } = render(
<ToolReturnParsedItem msg={msg} openFile={mockOpenFile} onLinkClick={mockOnLinkClick} />,
);

expect(container.querySelector('.tool-return-collapsed')).toBeNull();
});
});
18 changes: 17 additions & 1 deletion src/rovo-dev/ui/tools/ToolReturnItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export const ToolReturnParsedItem: React.FC<{
msg: ToolReturnParseResult;
openFile: OpenFileFunc;
onLinkClick: (href: string) => void;
}> = ({ msg, openFile, onLinkClick }) => {
collapsed?: boolean;
}> = ({ msg, openFile, onLinkClick, collapsed = false }) => {
const toolIcon = React.useMemo(() => (msg.type ? iconMap[msg.type] : undefined), [msg.type]);

const filePathClass = msg.filePath && msg.type !== 'delete' ? 'tool-return-file-path' : '';
Expand All @@ -28,6 +29,21 @@ export const ToolReturnParsedItem: React.FC<{
[msg.filePath, msg.type, openFile],
);

if (collapsed) {
return (
<a
className={`tool-return-item-base tool-return-item tool-return-collapsed ${filePathClass}`}
onClick={handleOpenFile}
>
{toolIcon}
<span className="tool-return-collapsed-text">
{msg.content ?? ''}
{msg.title ? ` — ${msg.title}` : ''}
</span>
</a>
);
}

return (
<a className={`tool-return-item-base tool-return-item ${filePathClass}`} onClick={handleOpenFile}>
{toolIcon}
Expand Down
Loading