Something went wrong. Try again.
fork of prime agent with changes i want but are not upstreamable probqbly (and some fixes)
Something went wrong. Try again.
5.9 kB · 151 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152import { setKeybindings, type TUI, visibleWidth } from "@earendil-works/pi-tui";import stripAnsi from "strip-ansi";import { beforeAll, describe, expect, test } from "vitest";import { KeybindingsManager } from "../src/core/keybindings.js";import { convertToLlm, createRefinementOutcomeMessage, isRefinementOutcomeMessage } from "../src/core/messages.js";import type { HarnessEntry, RefinementResult } from "../src/core/refinement/refinement.js";import { buildConversationComponents } from "../src/modes/interactive/components/conversation-components.js";import { RefinementOutcomeMessageComponent } from "../src/modes/interactive/components/refinement-outcome-message.js";import { initTheme } from "../src/modes/interactive/theme/theme.js";
function entry(overrides: Partial<HarnessEntry> = {}): HarnessEntry { return { id: "rhyme-response-guidance", kind: "prompt", title: "Rhyme response guidance", content: "Make conversational responses rhyme.", path: "prompts/rhyme-response-guidance.md", scope: "local", reference: {}, arguments: {}, metadata: {}, source: "refinement", created_at: "2026-08-18T00:00:00.000Z", updated_at: "2026-08-18T00:00:00.000Z", version: 1, ...overrides, };}
function result(): RefinementResult { const after = entry(); return { id: "refine-rhyme", summary: "Added local guidance to make conversational responses rhyme.", rationale: "The user requested rhyming guidance.", expectedOutcome: "Conversational responses rhyme.", appliedEdits: [ { action: "create", kind: "prompt", id: after.id, title: after.title, content: after.content, path: after.path, after, applied: true, }, ], harnessStatePath: "/tmp/harness/state.json", scope: "local", };}
function rendered(component: RefinementOutcomeMessageComponent): string { return stripAnsi(component.render(120).join("\n"));}
describe("RefinementOutcomeMessageComponent", () => { beforeAll(() => { initTheme("dark"); setKeybindings(new KeybindingsManager()); });
test("collapses to a labeled one-liner and expands through the shared tool toggle", () => { const message = createRefinementOutcomeMessage(result()); const component = new RefinementOutcomeMessageComponent(message);
const collapsed = rendered(component); expect(collapsed).toContain("[refinement]"); expect(collapsed).toContain("Added local guidance to make conversational responses rhyme."); expect(collapsed).toContain("1 edit applied"); expect(collapsed).toContain("Ctrl+O to expand"); expect(collapsed).not.toContain("Created local prompt"); expect(collapsed).not.toContain('Make conversational responses rhyme."');
component.setExpanded(true); const expanded = rendered(component); expect(expanded).toContain("Created local prompt `rhyme-response-guidance`"); expect(expanded).toContain('"content": "Make conversational responses rhyme."'); expect(expanded).toContain('"path": "prompts/rhyme-response-guidance.md"'); });
test("truncates the collapsed summary so the line never wraps", () => { const long = result(); long.summary = "Created local memory entries for the verifiers project context and running subagent tracking, plus a reusable subagent spec for parallel codebase exploration."; const component = new RefinementOutcomeMessageComponent(createRefinementOutcomeMessage(long));
const lines = component.render(80).map((line) => stripAnsi(line)); const content = lines.filter((line) => line.trim().length > 0); expect(content).toHaveLength(2); expect(content[1]).toContain("…"); expect(content[1]).toContain("1 edit applied"); expect(content[1]).toContain("Ctrl+O to expand"); for (const line of lines) { expect(visibleWidth(line)).toBeLessThanOrEqual(80); }
for (const width of [40, 24, 12]) { for (const line of component.render(width)) { expect(visibleWidth(stripAnsi(line))).toBeLessThanOrEqual(width); } } });
test("renders exact before and after payloads for updates and deletes", () => { const base = result(); const before = entry({ id: "tone-guidance", content: "Respond plainly." }); const after = entry({ id: "tone-guidance", content: "Respond in rhyme.", version: 2 }); const deleted = entry({ id: "obsolete-guidance", content: "Use prose." }); const message = createRefinementOutcomeMessage({ ...base, appliedEdits: [ { action: "update", kind: "prompt", id: before.id, before, after, applied: true }, { action: "delete", kind: "prompt", id: deleted.id, before: deleted, applied: true }, ], }); const component = new RefinementOutcomeMessageComponent(message); component.setExpanded(true); const output = rendered(component);
expect(output).toContain("Updated local prompt `tone-guidance`"); expect(output).toContain("Deleted local prompt `obsolete-guidance`"); expect(output).toContain('"content": "Respond plainly."'); expect(output).toContain('"content": "Respond in rhyme."'); expect(output).toContain('"content": "Use prose."'); });
test("replays the durable outcome with the saved tool expansion state", () => { const message = createRefinementOutcomeMessage(result()); const [component] = buildConversationComponents([message], { ui: {} as TUI, cwd: "/tmp", toolOptions: {}, getToolDefinition: () => undefined, toolsExpanded: true, });
expect(component).toBeInstanceOf(RefinementOutcomeMessageComponent); expect(stripAnsi(component!.render(120).join("\n"))).toContain( '"content": "Make conversational responses rhyme."', ); });
test("uses a typed, presentation-only custom message", () => { const message = createRefinementOutcomeMessage(result()); expect(isRefinementOutcomeMessage(message)).toBe(true); expect(convertToLlm([message])).toEqual([]); expect(isRefinementOutcomeMessage({ ...message, details: { ...message.details, edits: [{}] } })).toBe(false); });});