mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Never hide a real agent reply behind narration heuristics
Turns visibly worked but never answered: two filters could swallow a genuinely sent reply. The chat timeline ran persisted agent messages through the transcript's internal-narration patterns, so replies like "Done! I've sent the summary…" were dropped outright; and the consecutive-run collapse preferred the last "human-facing" message, hiding a narration-styled FINAL reply behind an earlier one. Persisted messages now render on content alone (narration shaping stays in the activity transcript, dedup still applies), and the run collapse hides only interim narration — every substantive message stays, and the run's final message always stays regardless of phrasing. Regression spec: a narration-styled final reply must render alongside the earlier PR announcement. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
1f923a89ef
commit
3dcf6b0a62
@@ -159,14 +159,17 @@ function addIntermediateAgentTurnMessageIds({
|
||||
return;
|
||||
}
|
||||
|
||||
const keepMessage =
|
||||
[...agentRun]
|
||||
.reverse()
|
||||
.find((message) => isHumanFacingAssistantText(message.content)) ??
|
||||
agentRun[agentRun.length - 1];
|
||||
|
||||
// Hide only interim narration: substantive messages (PR announcements,
|
||||
// answers) all stay, and the run's FINAL message always stays even when
|
||||
// narration-styled — a real reply must never lose to a phrasing
|
||||
// heuristic, which is exactly how turns ended up visibly working but
|
||||
// never answering.
|
||||
const lastId = agentRun[agentRun.length - 1].id;
|
||||
for (const message of agentRun) {
|
||||
if (message.id !== keepMessage.id) {
|
||||
if (
|
||||
message.id !== lastId &&
|
||||
!isHumanFacingAssistantText(message.content)
|
||||
) {
|
||||
hiddenIds.add(message.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,22 +302,22 @@ export function ChatDetail({
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const isAgent =
|
||||
defaultAgent?.pubkey != null &&
|
||||
normalizePubkey(message.pubkey) ===
|
||||
normalizePubkey(defaultAgent.pubkey);
|
||||
// NOTE: no narration heuristics here. A persisted agent message was
|
||||
// deliberately SENT to the channel — filtering it through the
|
||||
// transcript's internal-narration patterns dropped real replies
|
||||
// ("Done! I've sent the summary…"), leaving turns that visibly
|
||||
// worked but never answered. Narration shaping belongs to the
|
||||
// activity transcript; persisted rows only dedup against it.
|
||||
return (
|
||||
(eventHasTag(message, "chat_context", "source") ||
|
||||
(isAgent
|
||||
? isHumanFacingAssistantText(message.content)
|
||||
: message.content.trim().length > 0)) &&
|
||||
message.content.trim().length > 0) &&
|
||||
!shouldHidePersistedAgentMessage({
|
||||
event: message,
|
||||
hiddenAgentMessageIds: chatActivity.hiddenAgentMessageIds,
|
||||
})
|
||||
);
|
||||
}),
|
||||
[chatActivity.hiddenAgentMessageIds, defaultAgent?.pubkey, messages],
|
||||
[chatActivity.hiddenAgentMessageIds, messages],
|
||||
);
|
||||
const hasTranscriptActivity = chatActivity.totalBlockCount > 0;
|
||||
|
||||
|
||||
@@ -118,6 +118,15 @@ test("first message in a new chat is sent and rendered", async ({ page }) => {
|
||||
createdAt: base + 2,
|
||||
pubkey: pubkey ?? undefined,
|
||||
});
|
||||
// A narration-styled FINAL reply must still render: persisted
|
||||
// messages are never filtered by the transcript's narration
|
||||
// heuristics (this exact phrasing used to be silently dropped).
|
||||
win.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
|
||||
channelName: "Hello Fizz, first message",
|
||||
content: "Done! I've sent the summary with details to the channel.",
|
||||
createdAt: base + 3,
|
||||
pubkey: pubkey ?? undefined,
|
||||
});
|
||||
// A human message with a mention tag: @bob must render as a chip
|
||||
// (alice's pubkey is a mock profile fixture; bob's resolves via the
|
||||
// message's p tag).
|
||||
@@ -135,6 +144,12 @@ test("first message in a new chat is sent and rendered", async ({ page }) => {
|
||||
{ pubkey: fizzPubkey },
|
||||
);
|
||||
|
||||
await expect(
|
||||
page
|
||||
.getByLabel("Chat messages")
|
||||
.getByText("Done! I've sent the summary with details to the channel."),
|
||||
).toBeVisible({ timeout: 10_000 });
|
||||
|
||||
// Mentions in chat messages render as chips, same as channels.
|
||||
await expect(
|
||||
page.getByLabel("Chat messages").locator("[data-mention]", {
|
||||
|
||||
Reference in New Issue
Block a user