Files
kandev/apps/web/components/task/chat/messages/subagent-meta.test.ts
T

115 lines
4.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { subagentMetaChips } from "./subagent-meta";
import type { SubagentTaskPayload } from "@/components/task/chat/types";
describe("subagentMetaChips", () => {
it("returns empty list for undefined payload", () => {
expect(subagentMetaChips(undefined)).toEqual([]);
});
it("returns empty list when no metric fields are present", () => {
const payload: SubagentTaskPayload = { description: "do work", subagent_type: "general" };
expect(subagentMetaChips(payload)).toEqual([]);
});
it("formats a full Claude payload", () => {
const payload: SubagentTaskPayload = {
subagent_type: "general-purpose",
agent_id: "agent_0123456789abcdef",
duration_ms: 2200,
total_tokens: 9987,
tool_use_count: 0,
status: "complete",
};
expect(subagentMetaChips(payload)).toEqual([
{ label: "duration", value: "2.2s" },
{ label: "tokens", value: "9,987 tokens" },
{ label: "tools", value: "0 tools" },
]);
});
it("formats an OpenCode payload", () => {
const payload: SubagentTaskPayload = {
subagent_type: "task",
model: "opencode/big-pickle",
child_session_id: "sess_abcdef0123456789",
};
expect(subagentMetaChips(payload)).toEqual([
{ label: "model", value: "opencode/big-pickle" },
{ label: "session", value: "sess_abcdef0…" },
]);
});
it("formats a Cursor payload (duration only)", () => {
const payload: SubagentTaskPayload = { subagent_type: "task", duration_ms: 850 };
expect(subagentMetaChips(payload)).toEqual([{ label: "duration", value: "850ms" }]);
});
it("singularizes a single tool use", () => {
expect(subagentMetaChips({ tool_use_count: 1 })).toEqual([{ label: "tools", value: "1 tool" }]);
});
it("skips zero/negative duration and zero tokens but keeps zero tools", () => {
const payload: SubagentTaskPayload = { duration_ms: 0, total_tokens: 0, tool_use_count: 0 };
expect(subagentMetaChips(payload)).toEqual([{ label: "tools", value: "0 tools" }]);
});
it("does not truncate short session ids", () => {
expect(subagentMetaChips({ child_session_id: "short" })).toEqual([
{ label: "session", value: "short" },
]);
});
// Pins the fix for the "main agent finished, subagent backgrounded" race:
// claude-acp's Task tool with run_in_background=true returns
// is_async=true + status=async_launched. The card must surface a "background"
// chip so users see this isn't a normal completion.
it("adds a background chip when is_async is true", () => {
const payload: SubagentTaskPayload = {
subagent_type: "general-purpose",
is_async: true,
status: "async_launched",
output_file: "/tmp/tasks/abc.output",
};
expect(subagentMetaChips(payload)).toEqual([{ label: "background", value: "background" }]);
});
it("adds a background chip when status is async_launched even without is_async", () => {
const payload: SubagentTaskPayload = { status: "async_launched" };
expect(subagentMetaChips(payload)).toEqual([{ label: "background", value: "background" }]);
});
});
// The card header already reads "10 tool calls" from the rendered child count.
// A "10 tools" chip beside it states the same fact twice, in two registers.
describe("subagentMetaChips tool-count de-duplication", () => {
it("omits the tools chip when it repeats the rendered child count", () => {
const payload: SubagentTaskPayload = { tool_use_count: 10, duration_ms: 90278 };
const labels = subagentMetaChips(payload, 10).map((chip) => chip.label);
expect(labels).not.toContain("tools");
expect(labels).toContain("duration");
});
it("keeps the tools chip when the reported count differs from what streamed", () => {
expect(subagentMetaChips({ tool_use_count: 27 }, 20)).toEqual([
{ label: "tools", value: "27 tools" },
]);
});
it("keeps the tools chip when no children were rendered at all", () => {
expect(subagentMetaChips({ tool_use_count: 0 })).toEqual([
{ label: "tools", value: "0 tools" },
]);
});
// The card always passes a numeric childCount, so a zero-tool subagent hits
// 0 === 0 and would lose its "0 tools" chip — which is the one case the chip
// exists for. Passing undefined here (as the test above does) misses the
// production path entirely.
it("keeps the 0 tools chip when the card reports zero children", () => {
expect(subagentMetaChips({ tool_use_count: 0 }, 0)).toEqual([
{ label: "tools", value: "0 tools" },
]);
});
});