feat(coding-agent): add configurable assistant output padding

Closes #6168
This commit is contained in:
Alexey Zaytsev
2026-06-30 04:44:34 -05:00
committed by GitHub
parent 2117b61c6b
commit 6564d94717
9 changed files with 111 additions and 3 deletions
@@ -2,6 +2,7 @@ import type { AssistantMessage } from "@earendil-works/pi-ai";
import { describe, expect, test } from "vitest";
import { AssistantMessageComponent } from "../src/modes/interactive/components/assistant-message.ts";
import { initTheme } from "../src/modes/interactive/theme/theme.ts";
import { stripAnsi } from "../src/utils/ansi.ts";
const OSC133_ZONE_START = "\x1b]133;A\x07";
const OSC133_ZONE_END = "\x1b]133;B\x07";
@@ -71,4 +72,28 @@ describe("AssistantMessageComponent", () => {
expect(rendered).toContain("maximum output token limit");
expect(rendered).toContain("response may be incomplete");
});
test("uses configured output padding for text and thinking", () => {
initTheme("dark");
const component = new AssistantMessageComponent(
createAssistantMessage([
{ type: "text", text: "hello" },
{ type: "thinking", thinking: "reasoning" },
]),
false,
undefined,
"Thinking...",
1,
);
const lines = component.render(80).map((line) => stripAnsi(line));
expect(lines.some((line) => line.includes(" hello"))).toBe(true);
expect(lines.some((line) => line.includes(" reasoning"))).toBe(true);
component.setOutputPad(0);
const updatedLines = component.render(80).map((line) => stripAnsi(line));
expect(updatedLines.some((line) => line.startsWith("hello"))).toBe(true);
expect(updatedLines.some((line) => line.startsWith("reasoning"))).toBe(true);
});
});
@@ -397,6 +397,29 @@ describe("SettingsManager", () => {
});
});
describe("outputPad", () => {
it("should default to 1 and persist binary values", async () => {
const manager = SettingsManager.create(projectDir, agentDir);
expect(manager.getOutputPad()).toBe(1);
manager.setOutputPad(0);
await manager.flush();
expect(manager.getOutputPad()).toBe(0);
const savedSettings = JSON.parse(readFileSync(join(agentDir, "settings.json"), "utf-8"));
expect(savedSettings.outputPad).toBe(0);
});
it("should treat unsupported outputPad values as default padding", () => {
writeFileSync(join(agentDir, "settings.json"), JSON.stringify({ outputPad: 2 }));
const manager = SettingsManager.create(projectDir, agentDir);
expect(manager.getOutputPad()).toBe(1);
});
});
describe("shellCommandPrefix", () => {
it("should load shellCommandPrefix from settings", () => {
const settingsPath = join(agentDir, "settings.json");
@@ -97,6 +97,7 @@ type ReloadCommandContext = {
settingsManager: {
getHttpIdleTimeoutMs: () => number;
getHideThinkingBlock: () => boolean;
getOutputPad: () => 0 | 1;
getEditorPaddingX: () => number;
getAutocompleteMaxVisible: () => number;
getShowHardwareCursor: () => boolean;
@@ -168,6 +169,7 @@ function createReloadCommandContext(overrides: ReloadCommandContextOverrides = {
settingsManager: {
getHttpIdleTimeoutMs: () => 0,
getHideThinkingBlock: () => false,
getOutputPad: () => 1,
getEditorPaddingX: () => 1,
getAutocompleteMaxVisible: () => 10,
getShowHardwareCursor: () => false,