mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat(coding-agent): format bash tool durations to support hours, minutes, seconds (#9742)
This commit is contained in:
parent
661619e872
commit
fe219d7f8d
3 changed files with 56 additions and 2 deletions
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
- Moved compaction, branch summarization, and retry spinners into the editor border alongside the working indicator. Custom editors use the same embedding opt-in for all status spinners.
|
||||
- Enabled strict-prefer JSON-schema sampling by default for built-in `read`, `bash`, `powershell`, `edit`, and `write` tools, without requiring `PI_EXPERIMENTAL`. Extensions can re-register tool definitions with `constrainedSampling: false`.
|
||||
- Formatted Bash and PowerShell tool durations of at least one minute as minutes and seconds, with hours when needed ([#9628](https://github.com/earendil-works/pi/issues/9628)).
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,15 @@ class BashResultRenderComponent extends Container {
|
|||
};
|
||||
}
|
||||
function formatDuration(ms: number): string {
|
||||
return `${(ms / 1000).toFixed(1)}s`;
|
||||
const seconds = ms / 1000;
|
||||
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
||||
|
||||
const totalSeconds = Math.floor(seconds);
|
||||
const minutes = Math.floor(totalSeconds / 60);
|
||||
const remainder = totalSeconds % 60;
|
||||
if (minutes < 60) return `${minutes}m ${remainder}s`;
|
||||
|
||||
return `${Math.floor(minutes / 60)}h ${minutes % 60}m ${remainder}s`;
|
||||
}
|
||||
function formatShellCall(args: { command?: string; timeout?: number } | undefined, prompt: string): string {
|
||||
const command = str(args?.command);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { join, resolve } from "node:path";
|
||||
import { Text, type TUI, type TuiMouseEvent } from "@earendil-works/pi-tui";
|
||||
import { Type } from "typebox";
|
||||
import { beforeAll, describe, expect, test } from "vitest";
|
||||
import { afterEach, beforeAll, describe, expect, test, vi } from "vitest";
|
||||
import { getReadmePath } from "../src/config.ts";
|
||||
import type { ToolDefinition } from "../src/core/extensions/types.ts";
|
||||
import { type BashOperations, createBashToolDefinition } from "../src/core/tools/bash.ts";
|
||||
|
|
@ -36,6 +36,10 @@ describe("ToolExecutionComponent parity", () => {
|
|||
initTheme("dark");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
test("stacks custom call and result renderers like the old implementation", () => {
|
||||
const toolDefinition: ToolDefinition = {
|
||||
...createBaseToolDefinition(),
|
||||
|
|
@ -192,6 +196,47 @@ describe("ToolExecutionComponent parity", () => {
|
|||
expect(rendered).not.toContain("[Showing lines 2001-4000 of 4000. Full output:");
|
||||
});
|
||||
|
||||
// Issue #9628: keep short durations precise and make long shell durations readable.
|
||||
test.each([
|
||||
{ ms: 0, formatted: "0.0s" },
|
||||
{ ms: 4_200, formatted: "4.2s" },
|
||||
{ ms: 59_900, formatted: "59.9s" },
|
||||
{ ms: 59_999, formatted: "60.0s" },
|
||||
{ ms: 60_000, formatted: "1m 0s" },
|
||||
{ ms: 90_900, formatted: "1m 30s" },
|
||||
{ ms: 1_592_200, formatted: "26m 32s" },
|
||||
{ ms: 3_599_999, formatted: "59m 59s" },
|
||||
{ ms: 3_600_000, formatted: "1h 0m 0s" },
|
||||
{ ms: 7_384_900, formatted: "2h 3m 4s" },
|
||||
])("bash renderer formats $ms ms as $formatted while running and after completion", ({ ms, formatted }) => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(0);
|
||||
const component = new ToolExecutionComponent(
|
||||
"bash",
|
||||
"tool-bash-duration",
|
||||
{ command: "long-running-command" },
|
||||
{},
|
||||
createBashToolDefinition(process.cwd(), { exposeSessionEnvironment: false }),
|
||||
createFakeTui(),
|
||||
process.cwd(),
|
||||
);
|
||||
component.markExecutionStarted();
|
||||
component.updateResult({ content: [], isError: false }, true);
|
||||
|
||||
vi.advanceTimersByTime(ms);
|
||||
component.invalidate();
|
||||
const running = stripAnsi(component.render(120).join("\n"));
|
||||
|
||||
component.updateResult({ content: [], isError: false }, false);
|
||||
const completed = stripAnsi(component.render(120).join("\n"));
|
||||
|
||||
vi.advanceTimersByTime(1_000);
|
||||
component.invalidate();
|
||||
expect(stripAnsi(component.render(120).join("\n"))).toBe(completed);
|
||||
expect(running).toContain(`Elapsed ${formatted}`);
|
||||
expect(completed).toContain(`Took ${formatted}`);
|
||||
});
|
||||
|
||||
test("does not duplicate built-in headers when passed the active built-in definition", () => {
|
||||
const component = new ToolExecutionComponent(
|
||||
"read",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue