Skip to content

Commit 8ae0380

Browse files
committed
fix(share): tool blocks collapse fixes
1 parent e2afd84 commit 8ae0380

2 files changed

Lines changed: 38 additions & 1 deletion

File tree

src-rust/crates/core/src/share_export/template.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ nav {
183183
#messages.hide-tools details.thinking {
184184
display: none;
185185
}
186+
/* Messages whose entire content was tool calls / tool results / thinking
187+
would otherwise render as an empty role-only stub when the toggle hides
188+
their body — collapse the whole row instead. */
189+
#messages.hide-tools .msg.tool-only {
190+
display: none;
191+
}
186192

187193
/* Messages container */
188194
#messages { padding: 0; }

src-rust/crates/core/src/share_export/template.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@
120120

121121
function renderMessage(m) {
122122
var div = document.createElement('div');
123-
div.className = 'msg ' + (m.role || '');
123+
var classes = ['msg', m.role || ''];
124+
if (isToolOnlyMessage(m)) classes.push('tool-only');
125+
div.className = classes.join(' ').trim();
124126
var role = document.createElement('div');
125127
role.className = 'role ' + (m.role || '');
126128
role.textContent = m.role || 'message';
@@ -132,6 +134,35 @@
132134
return div;
133135
}
134136

137+
// A message is "tool-only" when every block in its content is a tool call,
138+
// tool result, or thinking block — i.e. there is no prose, image, or other
139+
// user-visible content. When the toggle hides those blocks we also hide the
140+
// whole row so we don't leave behind a blank user/assistant stub.
141+
function isToolOnlyMessage(m) {
142+
var content = m && m.content;
143+
if (typeof content === 'string') return false;
144+
if (!Array.isArray(content) || content.length === 0) return false;
145+
return content.every(isHiddenByToolToggle);
146+
}
147+
148+
function isHiddenByToolToggle(block) {
149+
if (!block || typeof block !== 'object') return false;
150+
switch (block.type) {
151+
case 'tool_use':
152+
case 'tool_result':
153+
case 'thinking':
154+
case 'redacted_thinking':
155+
return true;
156+
case 'text':
157+
// Empty/whitespace-only text blocks contribute nothing visible, so
158+
// treat them as "no content" too — otherwise a turn that's just a
159+
// tool call + an empty trailing text frame would still render blank.
160+
return !(block.text && block.text.trim().length > 0);
161+
default:
162+
return false;
163+
}
164+
}
165+
135166
function renderContent(parent, content) {
136167
if (typeof content === 'string') {
137168
parent.insertAdjacentHTML('beforeend', renderMarkdown(content));

0 commit comments

Comments
 (0)