mirror of
https://github.com/block/buzz.git
synced 2026-10-29 21:41:33 +00:00
Render agent message sends as chat bubbles
Co-authored-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
Signed-off-by: Rizz <302abe414ca6e3134763d2539bfcf145aea2a63fe5f8455204ed602fd40cf381@buzz.block.builderlab.xyz>
(cherry picked from commit 62b9603bac)
Signed-off-by: ss-dev-00 <a02c4e0850e5e612b4ddf95dbe2f5c56467cf27c6552203bc833ff438fb31971@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -59,9 +59,10 @@ export function ToolItem({
|
||||
[],
|
||||
);
|
||||
|
||||
// On a work block's rail a posted message is a step the agent took, so it
|
||||
// takes the same muted, expandable row as every other step. Everywhere else
|
||||
// it keeps the bubble: see `useIsInsideWorkBlockRail`.
|
||||
// Message presentations keep their readable bubble whenever they are standalone.
|
||||
// The conversation grouping keeps message sends standalone rather than placing
|
||||
// them on a work block rail; this guard preserves the muted row if another
|
||||
// transcript composition explicitly embeds one in a rail.
|
||||
if (compactSummary.presentation === "message" && !insideWorkBlockRail) {
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -210,6 +210,34 @@ test("the plan stays a sibling and splits the work around it", () => {
|
||||
assert.deepEqual(blockItemIds(grouped[2]), ["tool:2"]);
|
||||
});
|
||||
|
||||
test("message sends stay outside the work block as chat bubbles", () => {
|
||||
const send = tool("tool:send", {
|
||||
args: { content: "Posted an update" },
|
||||
buzzToolName: "send_message",
|
||||
descriptor: {
|
||||
renderClass: "message",
|
||||
label: "Sent message",
|
||||
preview: "Posted an update",
|
||||
tone: "neutral",
|
||||
source: "buzz",
|
||||
},
|
||||
renderClass: "message",
|
||||
toolName: "send_message",
|
||||
});
|
||||
const grouped = groupConversationWorkBlocks(
|
||||
itemSegments(tool("tool:1"), send, tool("tool:2")),
|
||||
);
|
||||
|
||||
assert.deepEqual(kinds(grouped), ["work-block", "item", "work-block"]);
|
||||
assert.deepEqual(blockItemIds(grouped[0]), ["tool:1"]);
|
||||
assert.equal(
|
||||
grouped[1].item.id,
|
||||
"tool:send",
|
||||
"the existing message presenter can render the send as a readable bubble",
|
||||
);
|
||||
assert.deepEqual(blockItemIds(grouped[2]), ["tool:2"]);
|
||||
});
|
||||
|
||||
test("permission gates and errors stay loud, in position", () => {
|
||||
for (const renderClass of ["permission", "error", "status"]) {
|
||||
const grouped = groupConversationWorkBlocks(
|
||||
|
||||
@@ -2,6 +2,7 @@ import type {
|
||||
TranscriptTurnSegment,
|
||||
TranscriptDisplayBlock,
|
||||
} from "./agentSessionTranscriptGrouping";
|
||||
import { buildCompactToolSummary } from "./agentSessionToolSummary";
|
||||
import type { TranscriptItem } from "./agentSessionTypes";
|
||||
|
||||
/** Reasoning. */
|
||||
@@ -63,12 +64,14 @@ export type TranscriptConversationSegment =
|
||||
* Which items are *work* — the material the block absorbs.
|
||||
*
|
||||
* - **thoughts** — reasoning is a step on the rail, not a sibling disclosure.
|
||||
* - **tool steps**, including failed ones. A failure belongs to the work it
|
||||
* happened in; the folded line reports it (`N steps · 1 failed`) so it is
|
||||
* never hidden behind a neutral count.
|
||||
* - **tool steps**, including failed ones, except message sends. A failure
|
||||
* belongs to the work it happened in; the folded line reports it
|
||||
* (`N steps · 1 failed`) so it is never hidden behind a neutral count.
|
||||
* Message sends stay outside as chat bubbles: they are communication the
|
||||
* reader should be able to read and open, not generic work telemetry.
|
||||
* - **interim agent notes** — an assistant message that is not the turn's
|
||||
* answer. A relay post the agent makes mid-turn is a tool step and lands
|
||||
* here for the same reason: it reads as progress, not as the reply.
|
||||
* answer. Unlike a message-send tool, a note is narration within the turn,
|
||||
* so it stays on the rail as progress.
|
||||
*
|
||||
* Everything else stays outside and keeps its own row. Plans stay a sibling
|
||||
* (Buzz's checklist is a first-class surface, not a step), and lifecycle rows —
|
||||
@@ -84,7 +87,10 @@ function isWorkItem(
|
||||
item: TranscriptItem,
|
||||
finalAnswerId: string | null,
|
||||
): item is WorkBlockItem {
|
||||
if (item.type === "thought" || item.type === "tool") return true;
|
||||
if (item.type === "thought") return true;
|
||||
if (item.type === "tool") {
|
||||
return buildCompactToolSummary(item).presentation !== "message";
|
||||
}
|
||||
return (
|
||||
item.type === "message" &&
|
||||
item.role === "assistant" &&
|
||||
|
||||
Reference in New Issue
Block a user