repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/ultra/__tests__/call.test.ts
Rawimport { stripVTControlCharacters } from "node:util";
import {
initTheme,
type Theme,
ToolExecutionComponent,
} from "@earendil-works/pi-coding-agent";
import { type TUI, visibleWidth } from "@earendil-works/pi-tui";
import { beforeAll, describe, expect, it, vi } from "vitest";
import { renderUltraCall } from "../call.ts";
import { initialReducerState, reduceProgress } from "../progress.ts";
import { renderUltraResult } from "../ui.ts";
beforeAll(() => initTheme());
const theme = {
fg: (_color: string, text: string) => text,
bold: (text: string) => text,
} as Theme;
const drafting = {
expanded: false,
argsComplete: false,
executionStarted: false,
isPartial: true,
isError: false,
};
const request = {
spec: {
name: "auth-review",
description: "Review authentication boundaries.",
phases: [
{
id: "inspect",
kind: "fanout",
over: ["tokens", "sessions", "permissions"],
step: {
summary: "Inspect authentication boundaries",
prompt:
"FIRST-PROMPT\nCheck {item}.\nReport evidence-backed findings.",
model: "small",
tools: ["read", "grep", "ls"],
},
},
{
id: "synthesize",
kind: "single",
step: {
summary: "Consolidate verified findings",
prompt: "Combine independent findings. Preserve evidence.",
model: "large",
thinkingLevel: "high",
tools: ["read", "grep"],
},
},
],
return: "{synthesize.results}",
},
};
function lines(args: unknown, options = drafting, width = 80) {
return renderUltraCall(args, theme, options)
.render(width)
.map(stripVTControlCharacters);
}
function host(args: unknown = {}) {
return new ToolExecutionComponent(
"run_workflow",
"call-1",
args,
{},
{ renderCall: renderUltraCall, renderResult: renderUltraResult },
{ requestRender: vi.fn() } as unknown as TUI,
process.cwd(),
);
}
function screen(component: ToolExecutionComponent) {
return component.render(100).map(stripVTControlCharacters).join("\n");
}
describe("streaming workflow call", () => {
it("renders each partial argument update, without validation or pretending to run agents", () => {
const row = host();
expect(screen(row)).toContain("Receiving workflow arguments…");
row.updateArgs({ spec: { name: "auth-" } });
expect(screen(row)).toContain("run_workflow auth-");
expect(screen(row)).toContain("0 phases received");
row.updateArgs({
spec: { name: "auth-review", phases: [{ id: "inspect" }] },
});
expect(screen(row)).toContain("1 phase received");
expect(screen(row)).toContain("kind not received");
expect(screen(row)).toContain("Summary not received");
row.updateArgs(request);
const text = screen(row);
expect(text).toContain("2 phases received · no agents running");
expect(text).toContain("inspect · fanout · 3 items received · small");
expect(text).toContain("Consolidate verified findings");
expect(text).not.toContain("Prompt tail · synthesize");
expect(text).not.toContain(
"Combine independent findings. Preserve evidence.",
);
expect(text).not.toContain("0/0 done");
expect(text).not.toContain("FIRST-PROMPT");
});
it("keeps arriving prompt chunks expansion-only and never schedules animation", () => {
const interval = vi.spyOn(globalThis, "setInterval");
const timeout = vi.spyOn(globalThis, "setTimeout");
try {
const args = { spec: { phases: [{ step: { prompt: "Inspect" } }] } };
expect(lines(args).join("\n")).not.toContain("Inspect");
expect(lines(args, { ...drafting, expanded: true }).join("\n")).toContain(
"Inspect",
);
args.spec.phases[0].step.prompt += " authentication";
const component = renderUltraCall(args, theme, {
...drafting,
expanded: true,
});
expect(component.render(80).join("\n")).toContain(
"Inspect authentication",
);
component.invalidate();
expect(component.render(80)).toEqual(component.render(80));
expect(interval).not.toHaveBeenCalled();
expect(timeout).not.toHaveBeenCalled();
} finally {
interval.mockRestore();
timeout.mockRestore();
}
});
it("distinguishes complete arguments from validated or running work", () => {
const row = host(request);
row.setArgsComplete();
const text = screen(row);
expect(text).toContain("Arguments received · 2 phases received");
expect(text).toContain("Awaiting validation and execution.");
expect(text).not.toContain("▎");
expect(text).not.toContain("Drafting");
});
it("hands off to the real result board and keeps received prompts available on expansion", () => {
const row = host(request);
row.setArgsComplete();
row.markExecutionStarted();
expect(screen(row)).not.toContain("Prompt tail");
expect(screen(row)).not.toContain("Consolidate verified findings");
const details = reduceProgress(
initialReducerState({ workflowName: "auth-review" }),
{
kind: "start",
phase: "inspect",
agentId: "inspect#0",
},
);
row.updateResult({ content: [], details, isError: false }, true);
expect(screen(row)).toContain("1 active");
expect(screen(row)).not.toContain("Drafting workflow");
row.setExpanded(true);
const expanded = screen(row);
expect(expanded).toContain("Received workflow");
expect(expanded).toContain("FIRST-PROMPT");
expect(expanded).toContain("Check {item}.");
expect(expanded).toContain("tools: read, grep, ls");
expect(expanded).toContain("thinking: high");
expect(expanded).toContain("return: {synthesize.results}");
row.updateResult({ content: [], details, isError: false });
expect(screen(row)).toContain("FIRST-PROMPT");
row.setExpanded(false);
expect(screen(row)).not.toContain("FIRST-PROMPT");
expect(screen(row)).not.toContain("Combine independent findings");
});
it.each([true, false])(
"clears drafting on failure, including pre-execution validation (started: %s)",
(started) => {
const row = host(request);
if (started) row.markExecutionStarted();
row.updateResult({
content: [
{ type: "text", text: "Invalid workflow spec: missing summary" },
],
isError: true,
});
const text = screen(row);
expect(text).toContain(
"ultra · failed: Invalid workflow spec: missing summary",
);
expect(text).not.toContain("Drafting workflow");
expect(text).not.toContain("Prompt tail");
expect(text).not.toContain("0/0 done");
row.setExpanded(true);
expect(screen(row)).toContain("FIRST-PROMPT");
expect(screen(row)).toContain("Invalid workflow spec: missing summary");
},
);
it("restores a completed call without reviving the drafting preview", () => {
const row = host(request);
row.updateResult({
content: [],
details: initialReducerState(),
isError: false,
});
expect(screen(row)).not.toContain("Drafting workflow");
expect(screen(row)).not.toContain("Prompt tail");
row.setExpanded(true);
expect(screen(row)).toContain("Received workflow");
expect(screen(row)).toContain("FIRST-PROMPT");
});
it("bounds collapsed phases and keeps prompt bodies expansion-only", () => {
const phases = Array.from({ length: 20 }, (_, index) => ({
id: `phase_${index}`,
kind: "single",
step: {
summary: `Summary ${index}`,
prompt: `OLD-PROMPT-${index}\n${"x".repeat(100_000)}\nLATEST-TAIL`,
},
}));
const output = lines({ spec: { name: "large", phases } }, drafting, 240);
expect(output.length).toBeLessThanOrEqual(13);
const text = output.join("\n");
expect(text).toContain("20 phases received");
expect(text).toContain("17 earlier phases");
expect(text).not.toContain("Summary 16");
expect(text).toContain("Summary 17");
expect(text).toContain("Summary 19");
expect(text).not.toContain("LATEST-TAIL");
expect(text).not.toContain("OLD-PROMPT");
expect(text).toContain("to expand");
const expanded = lines(
{ spec: { phases } },
{ ...drafting, expanded: true },
240,
).join("\n");
expect(expanded).toContain("Summary 0");
expect(expanded).toContain("OLD-PROMPT-0");
expect(expanded).toContain("OLD-PROMPT-19");
expect(expanded).toContain("LATEST-TAIL");
});
it("labels dynamic and conditional fanouts without evaluating selectors", () => {
const args = {
spec: {
phases: [
{
id: "verify",
kind: "fanout",
over: "{inspect.results}",
when: "{inspect.results}",
step: { summary: "Verify {item}" },
},
],
},
};
const text = lines(args).join("\n");
expect(text).toContain("dynamic items · conditional");
expect(text).toContain("Verify {item}");
expect(text).not.toContain("0 items");
const expanded = lines(args, { ...drafting, expanded: true }).join("\n");
expect(expanded).toContain("over: {inspect.results}");
expect(expanded).toContain("when: {inspect.results}");
});
it("renders saved names and input counts without loading a workflow or exposing input bodies", () => {
const text = lines({
name: "does-not-exist",
args: { question: "PRIVATE-INPUT", source: "repo" },
}).join("\n");
expect(text).toContain("run_workflow does-not-exist");
expect(text).toContain("Saved workflow · 2 inputs received");
expect(text).not.toContain("PRIVATE-INPUT");
expect(text).not.toContain("unknown workflow");
expect(lines({ name: "ignored", ...request }).join("\n")).not.toContain(
"ignored",
);
});
it.each([
undefined,
null,
[],
"broken",
42,
{},
{ spec: null },
{ spec: [] },
{ spec: { name: {}, phases: "not-an-array" } },
{
spec: {
phases: [
null,
1,
"partial",
[],
{},
{ id: [], kind: {}, step: null },
{ step: { summary: {}, prompt: [], tools: [null, {}] } },
],
},
},
])(
"tolerates incomplete and malformed args without renderer fallback: %j",
(args) => {
for (const expanded of [true, false]) {
expect(() => lines(args, { ...drafting, expanded })).not.toThrow();
expect(lines(args, { ...drafting, expanded })[0]).toContain(
"run_workflow",
);
}
},
);
it("stays within narrow terminal widths and sanitizes control bytes from all fields", () => {
const args = {
spec: {
name: "name\n\x1b[31mred\x1b[0m",
phases: [
{
id: "phase\nnext",
kind: "single",
step: {
summary: "wide 界界 and emoji 🔍🔍\nsummary",
model: "small\r\x00",
tools: ["read\x07"],
prompt: "line\twith\x1b[2Jcontrols\nUnicode 界界🔍🔍\x07",
},
},
],
},
};
for (const width of [1, 2, 8, 24, 80]) {
for (const expanded of [true, false]) {
const output = lines(args, { ...drafting, expanded }, width);
expect(output.every((text) => visibleWidth(text) <= width)).toBe(true);
expect(output.join("\n")).not.toMatch(/[\x00\x07\r\t]/);
}
}
expect(lines(args)[0]).toBe("run_workflow name red");
});
});