Merge pull request #4008 from jeremymcs/fix/latest-output-duplicate

fix(tui): clear pinned latest output on turn completion
This commit is contained in:
Jeremy McSpadden 2026-04-11 17:09:54 -05:00 committed by GitHub
commit 65c42ba6dc
2 changed files with 51 additions and 3 deletions

View file

@ -338,6 +338,54 @@ test("chat-controller clears pinned zone when a new assistant message starts", a
assert.equal(host.pinnedMessageContainer.children.length, 0, "pinned zone should clear on new assistant message");
});
test("chat-controller clears pinned zone when the agent turn ends", async () => {
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
fg: (_key: string, text: string) => text,
bg: (_key: string, text: string) => text,
bold: (text: string) => text,
italic: (text: string) => text,
truncate: (text: string) => text,
};
const host = createHost();
const toolCall = {
type: "toolCall",
id: "tool-clear-on-end-1",
name: "exec_command",
arguments: { cmd: "echo hi" },
};
await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) } as any);
host.getMarkdownThemeWithSettings = () => ({});
await handleAgentEvent(
host,
{
type: "message_update",
message: makeAssistant([{ type: "text", text: "Working on it." }, toolCall]),
assistantMessageEvent: {
type: "toolcall_end",
contentIndex: 1,
toolCall: {
...toolCall,
externalResult: {
content: [{ type: "text", text: "ok" }],
details: {},
isError: false,
},
},
partial: makeAssistant([{ type: "text", text: "Working on it." }, toolCall]),
},
} as any,
);
assert.ok(host.pinnedMessageContainer.children.length > 0, "pinned zone should be populated before agent_end");
await handleAgentEvent(host, { type: "agent_end" } as any);
assert.equal(host.pinnedMessageContainer.children.length, 0, "pinned zone should clear on agent_end");
});
test("chat-controller does not pin when there are no tool calls", async () => {
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
fg: (_key: string, text: string) => text,

View file

@ -432,12 +432,12 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
host.streamingMessage = undefined;
}
host.pendingTools.clear();
// Stop spinner on pinned border and switch label from "Working · Latest Output" to "Latest Output"
// Pinned output is only useful while work is actively streaming.
// Keep chat history as the single source after completion.
if (pinnedBorder) {
pinnedBorder.stopSpinner();
pinnedBorder.setLabel("Latest Output");
}
// Keep pinned message visible until the next assistant turn starts.
host.pinnedMessageContainer.clear();
lastPinnedText = "";
hasToolsInTurn = false;
pinnedBorder = undefined;