mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-09 03:20:56 +00:00
Skip text-free assistant turns in the Chat view
A text-free agent message marks the boundary between two batches of tool calls, so it stays in the turn stream to keep those batches as separate "N tool calls" chips. But it rendered an empty prose div, which still took a slot in the gap-4 column and doubled the vertical space between the chips on either side of it. Render nothing for those turns instead. The final assistant turn still renders when it carries a token/duration footer, even with no text, so the completed-stage metrics are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
73894c0f76
commit
6b9bf2be80
2 changed files with 62 additions and 2 deletions
|
|
@ -52,6 +52,58 @@ describe("StageChatView", () => {
|
|||
expect(html).toContain("1m 12s");
|
||||
});
|
||||
|
||||
test("renders no node for a text-free assistant turn between tool batches", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<StageChatView
|
||||
turns={[
|
||||
{
|
||||
kind: "tool",
|
||||
ts: "2026-04-09T12:00:01Z",
|
||||
toolName: "shell",
|
||||
input: "{}",
|
||||
result: "ok",
|
||||
isError: false,
|
||||
durationMs: 5,
|
||||
},
|
||||
{
|
||||
kind: "assistant",
|
||||
ts: "2026-04-09T12:00:02Z",
|
||||
content: " ",
|
||||
inputTokens: 0,
|
||||
outputTokens: 0,
|
||||
toolCallCount: 1,
|
||||
},
|
||||
{
|
||||
kind: "tool",
|
||||
ts: "2026-04-09T12:00:03Z",
|
||||
toolName: "shell",
|
||||
input: "{}",
|
||||
result: "ok",
|
||||
isError: false,
|
||||
durationMs: 5,
|
||||
},
|
||||
{
|
||||
kind: "assistant",
|
||||
ts: "2026-04-09T12:00:04Z",
|
||||
content: "Done",
|
||||
inputTokens: 10,
|
||||
outputTokens: 20,
|
||||
toolCallCount: null,
|
||||
},
|
||||
]}
|
||||
pendingTools={[]}
|
||||
stage={stage()}
|
||||
/>,
|
||||
);
|
||||
|
||||
// The boundary keeps the two batches as separate chips, but contributes
|
||||
// no element of its own between them.
|
||||
expect(html.match(/1 tool call/g)).toHaveLength(2);
|
||||
expect(html).not.toContain('class="prose prose-sm max-w-none"');
|
||||
expect(html.match(/class="prose /g)).toHaveLength(1);
|
||||
expect(html).toContain("Done");
|
||||
});
|
||||
|
||||
test("connects a long prompt's expand button to its controlled content", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<StageChatView
|
||||
|
|
|
|||
|
|
@ -1586,13 +1586,21 @@ export function StageChatView({
|
|||
</p>
|
||||
);
|
||||
case "assistant": {
|
||||
const hasText = turn.content.trim().length > 0;
|
||||
const metric = turnMetric(turn);
|
||||
const isFinal =
|
||||
turnIndex === lastAssistantTurnIndex && !stageActive;
|
||||
const showFooter = isFinal && Boolean(metric || duration);
|
||||
// A text-free assistant turn is the boundary between two batches
|
||||
// of tool calls, kept in the turn stream so those batches stay
|
||||
// separate chips. It has nothing to show, and an empty node would
|
||||
// still take a slot in this gap-4 column, doubling the space
|
||||
// between the chips on either side of it.
|
||||
if (!hasText && !showFooter) return null;
|
||||
return (
|
||||
<div key={`turn-${turnIndex}`} className="flex flex-col gap-1.5">
|
||||
<Markdown content={turn.content} />
|
||||
{isFinal && (metric || duration) && (
|
||||
{hasText && <Markdown content={turn.content} />}
|
||||
{showFooter && (
|
||||
<div className="flex gap-3 font-mono text-[11px] text-fg-muted tabular-nums">
|
||||
{metric && <span>{metric}</span>}
|
||||
{duration && <span>{duration}</span>}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue