Official
claude
Claude Code agent provider: runs the Claude Code CLI headless for each account.
The app opens the listing; nothing installs until an agent in your Plugins workspace has read the files and you enable the plugin. In a terminal: cvg install convergence/claude@0.2.0
Permissions in 0.2.0
Files
map.test.ts26.6 KB
// Ported from the Rust plugin's map.rs tests.
import * as wire from "./wire.ts";
import type * as z from "zod";
import assert from "node:assert/strict";
import { eventAs, contentAs, required, test } from "./testing.ts";
import type { Emission } from "./types.ts";
import { Mapper, failureMessage, usage } from "./map.ts";
const stream = (event: wire.StreamEvent) => ({ type: "stream_event", parent_tool_use_id: null, event });
const kinds = (events: Emission[]) => events.map((event) => event.kind);
const texts = (events: Emission[]) =>
events
.map((event) => event.kind)
.filter((kind) => kind.event === "text_delta")
.map((kind) => [kind.itemId, kind.text]);
const tasks = (events: Emission[]) => events.map((event) => event.kind).filter((kind) => kind.event === "task");
function agentCall(id: string, parent: string | null, input: wire.Input) {
return {
type: "assistant",
parent_tool_use_id: parent,
message: { id: `msg_${id}`, content: [{ type: "tool_use", id, name: "Agent", input }] },
};
}
test("text deltas accumulate under one item id", () => {
const mapper = new Mapper();
mapper.handle(stream({ type: "message_start", message: { id: "msg_1" } }));
assert.deepEqual(
mapper.handle(stream({ type: "content_block_start", index: 0, content_block: { type: "text", text: "" } })),
[],
);
const events = [];
for (const chunk of ["Hello", " ", "world"]) {
events.push(
...mapper.handle(stream({ type: "content_block_delta", index: 0, delta: { type: "text_delta", text: chunk } })),
);
}
assert.deepEqual(texts(events), [
["msg_1:0", "Hello"],
["msg_1:0", " "],
["msg_1:0", "world"],
]);
// The complete message must not repeat what the stream delivered.
const repeat = mapper.handle({
type: "assistant",
parent_tool_use_id: null,
message: { id: "msg_1", content: [{ type: "text", text: "Hello world" }] },
});
assert.deepEqual(repeat, []);
});
test("reasoning streams as its own item", () => {
const mapper = new Mapper();
mapper.handle(stream({ type: "message_start", message: { id: "msg_2" } }));
mapper.handle(stream({ type: "content_block_start", index: 0, content_block: { type: "thinking", thinking: "" } }));
const events = mapper.handle(
stream({ type: "content_block_delta", index: 0, delta: { type: "thinking_delta", thinking: " step\n" } }),
);
assert.deepEqual(kinds(events), [{ event: "reasoning_delta", itemId: "msg_2:0", text: " step\n", mode: "append" }]);
});
/// A subagent has no stream: each of its blocks arrives as a message of
/// its own, with the same id and the block at position 0.
test("a subagent message split into blocks keeps every block", () => {
const mapper = new Mapper();
mapper.handle({
type: "assistant",
parent_tool_use_id: null,
message: {
id: "msg_p",
content: [
{
type: "tool_use",
id: "toolu_agent",
name: "Agent",
input: { description: "Count lines", prompt: "Count the lines of a.txt", subagent_type: "general-purpose" },
},
],
},
});
const child = (content: z.infer<typeof wire.block>) => ({
type: "assistant",
parent_tool_use_id: "toolu_agent",
message: { id: "msg_c", model: "claude-haiku-4-5", content: [content] },
});
const events = [
...mapper.handle(child({ type: "thinking", thinking: "" })),
...mapper.handle(child({ type: "tool_use", id: "toolu_wc", name: "Bash", input: { command: "wc -l a.txt" } })),
...mapper.handle(child({ type: "text", text: "2" })),
];
const tagged = events.filter((event) => event.task === "toolu_agent").map((event) => event.kind);
assert.ok(tagged.some((kind) => kind.event === "tool_call_started" && kind.id === "toolu_wc"));
assert.ok(tagged.some((kind) => kind.event === "text_delta" && kind.text === "2"));
// The same message again (an older CLI repeats it whole) adds nothing.
const again = mapper.handle({
type: "assistant",
parent_tool_use_id: "toolu_agent",
message: {
id: "msg_c",
content: [
{ type: "thinking", thinking: "" },
{ type: "tool_use", id: "toolu_wc", name: "Bash", input: {} },
{ type: "text", text: "2" },
],
},
});
assert.ok(!again.some((event) => ["tool_call_started", "text_delta"].includes(event.kind.event)));
});
test("the assistant message fills in blocks the stream missed", () => {
const mapper = new Mapper();
const events = mapper.handle({
type: "assistant",
parent_tool_use_id: null,
message: { id: "msg_3", model: "claude-opus-5", content: [{ type: "text", text: "PONG" }] },
});
assert.deepEqual(kinds(events), [{ event: "text_delta", itemId: "msg_3:0", text: "PONG", mode: "replace" }]);
// The message named the model, which picks the context window.
const result = mapper.handle({
type: "result",
usage: { input_tokens: 1 },
modelUsage: { "claude-haiku-4-5": { contextWindow: 200000 }, "claude-opus-5": { contextWindow: 1000000 } },
});
assert.equal(eventAs(result[0].kind, "usage").contextWindow, 1000000);
});
test("a command tool call reports output and exit code", () => {
const mapper = new Mapper();
mapper.handle(stream({ type: "message_start", message: { id: "msg_4" } }));
mapper.handle(
stream({
type: "content_block_start",
index: 0,
content_block: { type: "tool_use", id: "toolu_1", name: "Bash", input: {} },
}),
);
for (const chunk of ['{"command":', '"ls -l"}']) {
mapper.handle(
stream({ type: "content_block_delta", index: 0, delta: { type: "input_json_delta", partial_json: chunk } }),
);
}
const [started] = mapper.handle(stream({ type: "content_block_stop", index: 0 }));
assert.equal(started.kind.event, "tool_call_started");
assert.equal(started.kind.id, "toolu_1");
assert.equal(started.kind.kind, "execute");
assert.equal(started.kind.title, "ls -l");
assert.equal(started.kind.status, "running");
// The command is on show from the start.
assert.deepEqual(started.kind.content, [{ type: "terminal", command: "ls -l", output: "" }]);
const [finished] = mapper.handle({
type: "user",
tool_use_result: { exitCode: 0 },
message: { content: [{ type: "tool_result", tool_use_id: "toolu_1", content: "total 0\n" }] },
});
assert.equal(eventAs(finished.kind, "tool_call_updated").status, "completed");
assert.deepEqual(
eventAs(finished.kind, "tool_call_updated").output,
{ exitCode: 0 },
"the structured result reaches the renderer",
);
assert.deepEqual(eventAs(finished.kind, "tool_call_updated").content, [
{ type: "terminal", command: "ls -l", output: "total 0\n", exitCode: 0 },
]);
});
test("a file edit carries a diff on start and on completion", () => {
const mapper = new Mapper();
const [started] = mapper.handle({
type: "assistant",
parent_tool_use_id: null,
message: {
id: "msg_5",
content: [
{
type: "tool_use",
id: "toolu_2",
name: "Edit",
input: { file_path: "/w/a.rs", old_string: "let a = 1;\n", new_string: "let a = 2;\n" },
},
],
},
});
assert.equal(eventAs(started.kind, "tool_call_started").kind, "edit");
assert.deepEqual(eventAs(started.kind, "tool_call_started").locations, [{ path: "/w/a.rs" }]);
assert.match(
required(contentAs(required(eventAs(started.kind, "tool_call_started").content)[0], "diff").diff),
/\+let a = 2;/,
);
const [finished] = mapper.handle({
type: "user",
message: { content: [{ type: "tool_result", tool_use_id: "toolu_2", content: "ok" }] },
});
assert.equal(eventAs(finished.kind, "tool_call_updated").status, "completed");
assert.equal(required(eventAs(finished.kind, "tool_call_updated").content)[0].type, "diff");
});
test("a failed tool result marks the call failed", () => {
const mapper = new Mapper();
mapper.rememberTool("toolu_3", "Read", { file_path: "/w/missing" });
const [event] = mapper.handle({
type: "user",
message: {
content: [
{
type: "tool_result",
tool_use_id: "toolu_3",
is_error: true,
content: [{ type: "text", text: "no such file" }],
},
],
},
});
assert.equal(eventAs(event.kind, "tool_call_updated").status, "failed");
assert.deepEqual(eventAs(event.kind, "tool_call_updated").content, [{ type: "text", text: "no such file" }]);
});
test("TodoWrite also emits a plan", () => {
const mapper = new Mapper();
const events = mapper.handle({
type: "assistant",
parent_tool_use_id: null,
message: {
id: "msg_6",
content: [
{
type: "tool_use",
id: "toolu_4",
name: "TodoWrite",
input: {
todos: [
{ content: "one", status: "in_progress" },
{ content: "two", status: "pending" },
],
},
},
],
},
});
assert.equal(events[1].kind.event, "plan");
assert.equal(required(eventAs(required(events[1]).kind, "plan").entries).length, 2);
assert.equal(required(eventAs(required(events[1]).kind, "plan").entries)[0].status, "in_progress");
});
/// The exact frame claude 2.1.280 sends for an ordinary foreground Bash
/// call. Read as a subagent, it hid the command row behind a task row.
test("a foreground command is not a subagent", () => {
const mapper = new Mapper();
const [started] = mapper.handle({
type: "assistant",
parent_tool_use_id: null,
message: {
id: "msg_b",
content: [
{ type: "tool_use", id: "toolu_bash", name: "Bash", input: { command: "ls -la", description: "List files" } },
],
},
});
assert.equal(eventAs(started.kind, "tool_call_started").kind, "execute");
assert.deepEqual(
mapper.handle({
type: "system",
subtype: "task_started",
task_id: "b38o239g0",
task_type: "local_bash",
tool_use_id: "toolu_bash",
description: "ls -la",
is_backgrounded: false,
}),
[],
);
const finished = mapper.handle({
type: "user",
parent_tool_use_id: null,
tool_use_result: { stdout: "a\n", exitCode: 0 },
message: { content: [{ type: "tool_result", tool_use_id: "toolu_bash", content: "a\n" }] },
});
assert.equal(finished.length, 1);
assert.equal(finished[0].task, null);
assert.equal(eventAs(finished[0].kind, "tool_call_updated").id, "toolu_bash");
assert.deepEqual(
mapper.handle({
type: "system",
subtype: "task_notification",
task_id: "b38o239g0",
tool_use_id: "toolu_bash",
status: "completed",
summary: "ls -la",
}),
[],
);
assert.equal(mapper.taskOfAgent("b38o239g0", "toolu_bash"), null);
assert.equal(mapper.cliTaskId("toolu_bash"), null);
});
test("a subagent becomes a task that owns its messages", () => {
const mapper = new Mapper();
mapper.handle(stream({ type: "message_start", message: { id: "msg_1", model: "claude-opus-5" } }));
const [call] = mapper.handle(
agentCall("toolu_a", null, {
description: "Search the tests",
prompt: "Find every test.\nThen stop.",
subagent_type: "Explore",
}),
);
assert.equal(eventAs(call.kind, "tool_call_started").kind, "task");
const started = mapper.handle({
type: "system",
subtype: "task_started",
task_id: "a1b2",
tool_use_id: "toolu_a",
description: "Search the tests",
subagent_type: "Explore",
task_type: "local_agent",
is_backgrounded: false,
spawn_depth: 1,
prompt: "Find every test.\nThen stop.",
});
let info = tasks(started)[0];
assert.equal(started[0].task, null, "the declaration belongs to the conversation");
assert.equal(info.id, "toolu_a", "published under the spawning call, which every child message names");
assert.equal(info.toolCallId, "toolu_a");
assert.equal(info.title, "Search the tests");
assert.equal(info.name, "Explore");
assert.equal(info.prompt, "Find every test.\nThen stop.");
assert.equal(info.status, "running");
assert.ok(info.startedAt);
assert.equal(info.parentTaskId, undefined);
assert.equal(mapper.cliTaskId("toolu_a"), "a1b2");
// The child's messages are tagged with the task, and its model is learnt
// from the first one without becoming the session's model.
const child = mapper.handle({
type: "assistant",
parent_tool_use_id: "toolu_a",
message: {
id: "msg_c1",
model: "claude-haiku-4-5",
content: [
{ type: "text", text: "looking" },
{ type: "tool_use", id: "toolu_grep", name: "Grep", input: { pattern: "fn test" } },
],
},
});
assert.equal(tasks(child)[0].model, "claude-haiku-4-5");
const tagged = child.filter((event) => event.kind.event !== "task");
assert.equal(tagged.length, 2);
assert.ok(tagged.every((event) => event.task === "toolu_a"));
const result = mapper.handle({
type: "user",
parent_tool_use_id: "toolu_a",
message: { content: [{ type: "tool_result", tool_use_id: "toolu_grep", content: "a.rs" }] },
});
assert.equal(result[0].task, "toolu_a");
const usageEvents = mapper.handle({
type: "result",
usage: { input_tokens: 1 },
modelUsage: { "claude-haiku-4-5": { contextWindow: 200000 }, "claude-opus-5": { contextWindow: 1000000 } },
});
assert.equal(eventAs(usageEvents[0].kind, "usage").contextWindow, 1000000);
// Progress moves the activity line and the counters, never the title.
const progress = mapper.handle({
type: "system",
subtype: "task_progress",
task_id: "a1b2",
tool_use_id: "toolu_a",
description: "Running Grep",
last_tool_name: "Grep",
summary: "reading map.rs",
usage: { total_tokens: 1200, tool_uses: 3, duration_ms: 400 },
});
assert.equal(progress.length, 1);
info = tasks(progress)[0];
assert.equal(info.title, "Search the tests");
assert.equal(info.activity, "Grep");
assert.equal(info.summary, "reading map.rs");
assert.equal(required(info.usage).usedTokens, 1200);
assert.equal(info.toolUses, 3);
const paused = mapper.handle({
type: "system",
subtype: "task_updated",
task_id: "a1b2",
patch: { status: "paused", description: "Other" },
});
assert.equal(tasks(paused)[0].status, "waiting");
assert.equal(tasks(paused)[0].title, "Search the tests");
mapper.handle({ type: "system", subtype: "task_updated", task_id: "a1b2", patch: { status: "running" } });
mapper.handle({
type: "assistant",
parent_tool_use_id: "toolu_a",
message: { id: "msg_c2", content: [{ type: "text", text: "Found 3 tests." }] },
});
const done = mapper.handle({
type: "system",
subtype: "task_notification",
task_id: "a1b2",
tool_use_id: "toolu_a",
status: "completed",
summary: 'Agent "Search the tests" completed',
usage: { total_tokens: 1500, tool_uses: 4, duration_ms: 900 },
});
info = tasks(done)[0];
assert.equal(info.status, "completed");
assert.equal(info.activity, undefined);
assert.ok(info.endedAt);
assert.equal(info.summary, "Found 3 tests.");
assert.equal(required(info.usage).usedTokens, 1500);
// The spawning call's result is the whole answer, and it stays.
const answer = mapper.handle({
type: "user",
parent_tool_use_id: null,
tool_use_result: {
status: "completed",
agentId: "a1b2",
content: [{ type: "text", text: "Three tests: a, b, c." }],
totalTokens: 1600,
totalToolUseCount: 4,
},
message: {
content: [
{
type: "tool_result",
tool_use_id: "toolu_a",
content: [
{ type: "text", text: "Three tests: a, b, c." },
{ type: "text", text: "agentId: a1b2" },
],
},
],
},
});
assert.equal(answer[0].kind.event, "tool_call_updated");
assert.equal(answer[0].kind.id, "toolu_a");
assert.equal(answer[0].task, null);
info = tasks(answer)[0];
assert.equal(info.summary, "Three tests: a, b, c.");
assert.equal(required(info.usage).usedTokens, 1600);
const later = mapper.handle({
type: "system",
subtype: "task_updated",
task_id: "a1b2",
patch: { status: "completed" },
});
assert.ok(tasks(later).every((info) => info.summary === "Three tests: a, b, c."));
// A message after the end still lands in the task.
const late = mapper.handle({
type: "assistant",
parent_tool_use_id: "toolu_a",
message: { id: "msg_late", content: [{ type: "text", text: "leftover" }] },
});
assert.equal(late.length, 1);
assert.equal(late[0].task, "toolu_a");
});
test("a nested subagent lives inside its parent", () => {
const mapper = new Mapper();
mapper.handle(agentCall("toolu_outer", null, { description: "Outer", prompt: "go" }));
mapper.handle({
type: "system",
subtype: "task_started",
task_id: "outer1",
tool_use_id: "toolu_outer",
description: "Outer",
task_type: "local_agent",
spawn_depth: 1,
});
// The inner call is made by the outer agent.
const call = mapper.handle(agentCall("toolu_inner", "toolu_outer", { prompt: "\nInspect the parser\nand report" }));
assert.equal(call[0].task, "toolu_outer");
const started = mapper.handle({
type: "system",
subtype: "task_started",
task_id: "inner1",
tool_use_id: "toolu_inner",
task_type: "local_agent",
subagent_type: "general-purpose",
spawn_depth: 2,
});
const info = tasks(started)[0];
assert.equal(info.id, "toolu_inner");
assert.equal(info.parentTaskId, "toolu_outer");
assert.equal(info.title, "Inspect the parser", "the prompt's first line when there is no description");
const text = mapper.handle({
type: "assistant",
parent_tool_use_id: "toolu_inner",
message: { id: "msg_i", content: [{ type: "text", text: "deep" }] },
});
assert.equal(text[0].task, "toolu_inner");
assert.equal(mapper.taskOfAgent("inner1", null), "toolu_inner");
});
/// A child can speak before `task_started`; it declares its task from the
/// call rather than landing in the main conversation.
test("a subagent that speaks first still gets a task", () => {
const mapper = new Mapper();
mapper.handle({
type: "assistant",
parent_tool_use_id: null,
message: {
id: "msg_1",
content: [
{
type: "tool_use",
id: "toolu_p",
name: "Task",
input: { description: "Search the tests", prompt: "find them", run_in_background: true },
},
],
},
});
const early = mapper.handle({
type: "assistant",
parent_tool_use_id: "toolu_p",
message: { id: "msg_c", content: [{ type: "text", text: "looking" }] },
});
assert.equal(early[0].kind.event, "task");
assert.equal(early[0].kind.id, "toolu_p");
assert.equal(early[0].kind.title, "Search the tests");
assert.equal(early[0].kind.background, true);
assert.equal(early[0].task, null);
assert.ok(early.slice(1).every((event) => event.task === "toolu_p"));
const started = mapper.handle({
type: "system",
subtype: "task_started",
task_id: "task_9",
tool_use_id: "toolu_p",
description: "Search the tests",
subagent_type: "Explore",
task_type: "local_agent",
is_backgrounded: true,
});
assert.equal(eventAs(started[0].kind, "task").id, "toolu_p");
assert.equal(eventAs(started[0].kind, "task").name, "Explore");
// A background agent's result is what it said last; the frame's own
// summary is a status line.
mapper.handle({
type: "assistant",
parent_tool_use_id: "toolu_p",
message: { id: "msg_d", content: [{ type: "text", text: "All found." }] },
});
const done = tasks(
mapper.handle({
type: "system",
subtype: "task_notification",
task_id: "task_9",
status: "completed",
summary: "Agent finished",
}),
)[0];
assert.equal(done.status, "completed");
assert.equal(done.summary, "All found.");
});
test("a stopped or killed task is cancelled", () => {
for (const frame of [
{ type: "system", subtype: "task_updated", task_id: "t", patch: { status: "killed" } },
{ type: "system", subtype: "task_notification", task_id: "t", status: "stopped" },
]) {
const mapper = new Mapper();
mapper.handle({
type: "system",
subtype: "task_started",
task_id: "t",
tool_use_id: "tu",
description: "d",
task_type: "local_agent",
});
const info = tasks(mapper.handle(frame))[0];
assert.equal(info.status, "cancelled");
assert.equal(info.title, "d");
// The Agent call then ends in an error; the subagent was still
// stopped, not failed.
const after = mapper.handle({
type: "user",
parent_tool_use_id: null,
message: { content: [{ type: "tool_result", tool_use_id: "tu", is_error: true, content: "interrupted" }] },
});
for (const info of tasks(after)) assert.equal(info.status, "cancelled");
}
});
test("housekeeping tasks are not announced", () => {
const mapper = new Mapper();
assert.deepEqual(
mapper.handle({
type: "system",
subtype: "task_started",
task_id: "t",
description: "watch",
skip_transcript: true,
task_type: "local_agent",
}),
[],
);
});
test("a subagent request is attributed to its task", () => {
const mapper = new Mapper();
mapper.handle(agentCall("toolu_a", null, { description: "Edit" }));
mapper.handle({
type: "system",
subtype: "task_started",
task_id: "agent7",
tool_use_id: "toolu_a",
task_type: "local_agent",
});
mapper.handle({
type: "assistant",
parent_tool_use_id: "toolu_a",
message: { id: "m", content: [{ type: "tool_use", id: "toolu_w", name: "Write", input: { file_path: "/w/a" } }] },
});
assert.equal(mapper.taskOfAgent("agent7", "toolu_x"), "toolu_a");
assert.equal(mapper.taskOfAgent(null, "toolu_w"), "toolu_a");
assert.equal(mapper.taskOfAgent(null, "toolu_main"), null);
assert.equal(tasks(mapper.ask("toolu_a"))[0].status, "waiting");
assert.equal(tasks(mapper.answered("toolu_a"))[0].status, "running");
const denied = mapper.handle({
type: "system",
subtype: "permission_denied",
tool_name: "Write",
agent_id: "agent7",
tool_use_id: "toolu_w",
});
assert.equal(denied[0].task, "toolu_a");
assert.deepEqual(denied[0].kind, { event: "notice", level: "warning", message: "Permission denied for Write." });
});
test("a status line for a tool becomes that tool's output", () => {
const mapper = new Mapper();
const events = mapper.handle({
type: "system",
subtype: "informational",
level: "info",
content: "Running 3 of 40 tests",
tool_use_id: "toolu_9",
});
assert.deepEqual(events[0].kind, {
event: "tool_call_updated",
id: "toolu_9",
outputDelta: "Running 3 of 40 tests\n",
});
// A repeated line would fill the panel with the same sentence.
assert.deepEqual(
mapper.handle({
type: "system",
subtype: "informational",
content: "Running 3 of 40 tests",
tool_use_id: "toolu_9",
}),
[],
);
// A line with no tool is a notice, its text under `content`.
const notice = mapper.handle({
type: "system",
subtype: "informational",
level: "warning",
content: "A hook blocked the prompt",
});
assert.deepEqual(kinds(notice), [{ event: "notice", level: "warning", message: "A hook blocked the prompt" }]);
});
test("compaction reports the summary the CLI wrote", () => {
const mapper = new Mapper();
assert.deepEqual(
mapper.handle({
type: "user",
isCompactSummary: true,
message: { role: "user", content: [{ type: "text", text: "We fixed the parser." }] },
}),
[],
);
const events = mapper.handle({
type: "system",
subtype: "compact_boundary",
compact_metadata: { trigger: "manual", pre_tokens: 180000, post_tokens: 20000 },
});
assert.deepEqual(kinds(events), [{ event: "compacted", summary: "We fixed the parser." }]);
const failed = mapper.handle({
type: "system",
subtype: "status",
status: "idle",
compact_result: "failed",
compact_error: "too large",
});
assert.deepEqual(kinds(failed), [{ event: "notice", level: "error", message: "Compaction failed: too large" }]);
});
test("a rate limit event becomes usage limits", () => {
const mapper = new Mapper();
const [event] = mapper.handle({
type: "rate_limit_event",
rate_limit_info: { status: "allowed", rateLimitType: "five_hour", utilization: 0.5, resetsAt: 1789000000 },
});
assert.equal(event.kind.event, "usage_limits");
assert.equal(required(event.kind.windows)[0].id, "five_hour");
assert.ok(Math.abs(required(event.kind.windows)[0].usedPercent - 50) < 1e-9);
});
test("the result reports the context of the last request", () => {
// Numbers from a CLI 2.1 turn with two tool calls.
const mapper = new Mapper();
for (const [read, created] of [
[13673, 9014],
[22687, 2609],
[25296, 142],
]) {
mapper.handle({
type: "assistant",
parent_tool_use_id: null,
message: {
id: `msg_${read}`,
model: "claude-haiku-4-5",
content: [],
usage: {
input_tokens: 8,
cache_read_input_tokens: read,
cache_creation_input_tokens: created,
output_tokens: 1,
},
},
});
}
// A subagent's request is its own context, not the chat's.
mapper.handle({
type: "assistant",
parent_tool_use_id: "toolu_agent",
message: {
id: "msg_child",
model: "claude-haiku-4-5",
content: [],
usage: { input_tokens: 90000, output_tokens: 1 },
},
});
const [event] = mapper.handle({
type: "result",
subtype: "success",
usage: { input_tokens: 26, cache_read_input_tokens: 61656, cache_creation_input_tokens: 11765, output_tokens: 431 },
modelUsage: { "claude-haiku-4-5": { contextWindow: 200000 } },
});
assert.equal(eventAs(event.kind, "usage").usedTokens, 8 + 25296 + 142 + 1);
assert.equal(eventAs(event.kind, "usage").contextWindow, 200000);
});
test("the result reports usage and outcome", () => {
const success = {
type: "result",
subtype: "success",
is_error: false,
total_cost_usd: 0.25,
usage: {
input_tokens: 2,
output_tokens: 5,
cache_read_input_tokens: 11,
cache_creation_input_tokens: 12,
output_tokens_details: { thinking_tokens: 3 },
},
modelUsage: { "claude-opus-5": { contextWindow: 1000000 }, "claude-haiku-4-5": { contextWindow: 200000 } },
};
// The session's own model decides the window.
assert.deepEqual(usage(success, "claude-haiku-4-5", null), {
usedTokens: 30,
contextWindow: 200000,
costUsd: 0.25,
inputTokens: 2,
cachedInputTokens: 23,
outputTokens: 5,
reasoningTokens: 3,
});
assert.equal(failureMessage(success), null);
assert.equal(
failureMessage({ type: "result", subtype: "error_during_execution", is_error: true, errors: ["boom"] }),
"error_during_execution: boom",
);
assert.equal(
failureMessage({ type: "result", subtype: "success", is_error: true, result: "credit balance too low" }),
"success: credit balance too low",
);
});Versions
| Version | Published | Plugin API | Size | Permissions | Status |
|---|---|---|---|---|---|
| 0.2.0latest | Oct 5, 2026 | >=2 <3 | 128.7 KB | 4 permissions | Listed |
No comments yet.