summaryrefslogtreecommitdiffhomepage
path: root/packages/cli/src/render.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli/src/render.test.ts')
-rw-r--r--packages/cli/src/render.test.ts105
1 files changed, 103 insertions, 2 deletions
diff --git a/packages/cli/src/render.test.ts b/packages/cli/src/render.test.ts
index c638584..849d33a 100644
--- a/packages/cli/src/render.test.ts
+++ b/packages/cli/src/render.test.ts
@@ -1,7 +1,12 @@
-import type { AgentEvent } from "@dispatch/transport-contract";
+import type { AgentEvent, ConversationMeta } from "@dispatch/transport-contract";
import type { StepId } from "@dispatch/wire";
import { describe, expect, it } from "vitest";
-import { renderEvent } from "./render.js";
+import {
+ extractLastText,
+ formatConversationList,
+ formatRelativeTime,
+ renderEvent,
+} from "./render.js";
describe("renderEvent", () => {
const opts = { showReasoning: false };
@@ -149,3 +154,99 @@ describe("renderEvent", () => {
expect(renderEvent(e, opts)).toBeUndefined();
});
});
+
+describe("extractLastText", () => {
+ it("accumulates text deltas", () => {
+ const events: AgentEvent[] = [
+ { type: "text-delta", conversationId: "c", turnId: "t", delta: "Hello" },
+ { type: "text-delta", conversationId: "c", turnId: "t", delta: ", " },
+ { type: "text-delta", conversationId: "c", turnId: "t", delta: "world" },
+ { type: "done", conversationId: "c", turnId: "t", reason: "completed" },
+ ];
+ expect(extractLastText(events)).toBe("Hello, world");
+ });
+
+ it("returns empty string when no text-delta events", () => {
+ const events: AgentEvent[] = [
+ { type: "turn-start", conversationId: "c", turnId: "t" },
+ { type: "done", conversationId: "c", turnId: "t", reason: "completed" },
+ ];
+ expect(extractLastText(events)).toBe("");
+ });
+
+ it("ignores non-text-delta events but keeps deltas interleaved among them", () => {
+ const events: AgentEvent[] = [
+ { type: "text-delta", conversationId: "c", turnId: "t", delta: "a" },
+ {
+ type: "tool-call",
+ conversationId: "c",
+ turnId: "t",
+ stepId: "t1#0" as StepId,
+ toolCallId: "tc1",
+ toolName: "read_file",
+ input: {},
+ },
+ { type: "text-delta", conversationId: "c", turnId: "t", delta: "b" },
+ ];
+ expect(extractLastText(events)).toBe("ab");
+ });
+
+ it("returns empty string for an empty event list", () => {
+ expect(extractLastText([])).toBe("");
+ });
+});
+
+describe("formatRelativeTime", () => {
+ const now = 1_000_000_000_000; // fixed clock
+
+ it("returns 'just now' for under a minute", () => {
+ expect(formatRelativeTime(now - 30_000, now)).toBe("just now");
+ });
+
+ it("returns minutes ago", () => {
+ expect(formatRelativeTime(now - 5 * 60_000, now)).toBe("5m ago");
+ });
+
+ it("returns hours ago", () => {
+ expect(formatRelativeTime(now - 3 * 3_600_000, now)).toBe("3h ago");
+ });
+
+ it("returns days ago", () => {
+ expect(formatRelativeTime(now - 2 * 86_400_000, now)).toBe("2d ago");
+ });
+
+ it("returns a date past a week", () => {
+ // 2001-09-09T01:46:40.000Z
+ expect(formatRelativeTime(now - 8 * 86_400_000, now)).toBe("2001-09-01");
+ });
+});
+
+describe("formatConversationList", () => {
+ const now = 1_000_000_000_000;
+
+ const conv = (id: string, title: string, ageMs: number): ConversationMeta => ({
+ id,
+ title,
+ createdAt: now - ageMs - 1000,
+ lastActivityAt: now - ageMs,
+ });
+
+ it("returns empty string for an empty list", () => {
+ expect(formatConversationList([], now)).toBe("");
+ });
+
+ it("formats one row with short id, title, relative time", () => {
+ const list = [conv("abcdef1234567890", "hello world", 5 * 60_000)];
+ expect(formatConversationList(list, now)).toBe("abcdef12 | hello world | 5m ago");
+ });
+
+ it("formats multiple rows one per line", () => {
+ const list = [
+ conv("abcdef1234567890", "first", 5 * 60_000),
+ conv("0123456789abcdef", "second", 3 * 3_600_000),
+ ];
+ expect(formatConversationList(list, now)).toBe(
+ "abcdef12 | first | 5m ago\n01234567 | second | 3h ago",
+ );
+ });
+});