fix(coding-agent): Coalesce adjacent assistant thinking blocks into one section
This commit is contained in:
@@ -34,11 +34,12 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed configured-provider catalog refresh to parse pi.dev's model-ID keyed responses, treat unimplemented routes as unavailable overlays, and show concise refresh status in `/model`.
|
||||
- Fixed configured-provider catalog refresh to parse pi.dev's model-ID keyed responses, throttle checks to once per four hours, send the versioned pi user agent, treat unimplemented routes as unavailable overlays, and show concise refresh status in `/model`.
|
||||
- Fixed inherited OpenRouter model context windows to use the top provider's actual context length ([#6481](https://github.com/earendil-works/pi-mono/pull/6481) by [@davidbrai](https://github.com/davidbrai)).
|
||||
- Fixed inherited OpenRouter OpenAI-compatible session IDs to use the `x-session-id` header instead of OpenAI-specific session-affinity fields ([#6366](https://github.com/earendil-works/pi/issues/6366)).
|
||||
- Fixed `Ctrl+V` to paste clipboard text when the pasteboard does not contain an image.
|
||||
- Fixed `/login amazon-bedrock` to prompt for and save a Bedrock API key instead of only displaying ambient AWS credential setup instructions.
|
||||
- Fixed adjacent assistant thinking blocks to render as one thinking section.
|
||||
|
||||
## [0.80.6] - 2026-07-09
|
||||
|
||||
|
||||
@@ -101,7 +101,24 @@ export class AssistantMessageComponent extends Container {
|
||||
// Assistant text messages with no background - trim the text
|
||||
// Set paddingY=0 to avoid extra spacing before tool executions
|
||||
this.contentContainer.addChild(new Markdown(content.text.trim(), this.outputPad, 0, this.markdownTheme));
|
||||
} else if (content.type === "thinking" && content.thinking.trim()) {
|
||||
} else if (content.type === "thinking") {
|
||||
const thinkingBlocks: string[] = [];
|
||||
for (; i < message.content.length; i++) {
|
||||
const thinkingContent = message.content[i];
|
||||
if (thinkingContent.type !== "thinking") {
|
||||
break;
|
||||
}
|
||||
const thinking = thinkingContent.thinking.trim();
|
||||
if (thinking) {
|
||||
thinkingBlocks.push(thinking);
|
||||
}
|
||||
}
|
||||
i--;
|
||||
|
||||
if (thinkingBlocks.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add spacing only when another visible assistant content block follows.
|
||||
// This avoids a superfluous blank line before separately-rendered tool execution blocks.
|
||||
const hasVisibleContentAfter = message.content
|
||||
@@ -109,24 +126,21 @@ export class AssistantMessageComponent extends Container {
|
||||
.some((c) => (c.type === "text" && c.text.trim()) || (c.type === "thinking" && c.thinking.trim()));
|
||||
|
||||
if (this.hideThinkingBlock) {
|
||||
// Show static thinking label when hidden
|
||||
// Show one static label for each run of thinking blocks when hidden.
|
||||
this.contentContainer.addChild(
|
||||
new Text(theme.italic(theme.fg("thinkingText", this.hiddenThinkingLabel)), this.outputPad, 0),
|
||||
);
|
||||
if (hasVisibleContentAfter) {
|
||||
this.contentContainer.addChild(new Spacer(1));
|
||||
}
|
||||
} else {
|
||||
// Thinking traces in thinkingText color, italic
|
||||
// Render each run of thinking blocks as one Markdown section.
|
||||
this.contentContainer.addChild(
|
||||
new Markdown(content.thinking.trim(), this.outputPad, 0, this.markdownTheme, {
|
||||
new Markdown(thinkingBlocks.join("\n\n"), this.outputPad, 0, this.markdownTheme, {
|
||||
color: (text: string) => theme.fg("thinkingText", text),
|
||||
italic: true,
|
||||
}),
|
||||
);
|
||||
if (hasVisibleContentAfter) {
|
||||
this.contentContainer.addChild(new Spacer(1));
|
||||
}
|
||||
}
|
||||
if (hasVisibleContentAfter) {
|
||||
this.contentContainer.addChild(new Spacer(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,24 @@ describe("AssistantMessageComponent", () => {
|
||||
expect(rendered).toContain("response may be incomplete");
|
||||
});
|
||||
|
||||
test("coalesces adjacent thinking blocks into one hidden thinking label", () => {
|
||||
initTheme("dark");
|
||||
|
||||
const component = new AssistantMessageComponent(
|
||||
createAssistantMessage([
|
||||
{ type: "thinking", thinking: "first thought" },
|
||||
{ type: "thinking", thinking: "" },
|
||||
{ type: "thinking", thinking: "second thought" },
|
||||
{ type: "text", text: "answer" },
|
||||
]),
|
||||
true,
|
||||
);
|
||||
const rendered = stripAnsi(component.render(80).join("\n"));
|
||||
|
||||
expect(rendered.match(/Thinking\.\.\./g)).toHaveLength(1);
|
||||
expect(rendered).toContain("answer");
|
||||
});
|
||||
|
||||
test("uses configured output padding for text and thinking", () => {
|
||||
initTheme("dark");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user