1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
import { describe, expect, it } from "vitest";
import { createReadTabTool, type ReadTabCallbacks } from "../../src/tools/read-tab.js";
import type { TabResolution } from "../../src/tools/send-to-tab.js";
function makeCallbacks(overrides: Partial<ReadTabCallbacks> = {}): ReadTabCallbacks {
return {
resolveShortId: (): TabResolution => ({
status: "ok",
tab: { id: "target-id", title: "Target", handle: "targ" },
}),
getLastResponse: () => ({ text: "the answer is 42", status: "idle" }),
listOpenHandles: () => [{ handle: "targ", title: "Target" }],
...overrides,
};
}
describe("createReadTabTool — schema & description", () => {
it("is a non-blocking snapshot read", () => {
const tool = createReadTabTool(makeCallbacks());
expect(tool.name).toBe("read_tab");
expect(tool.description).toContain("SNAPSHOT");
expect(tool.description.toLowerCase()).toContain("does not block");
});
});
describe("createReadTabTool — execute()", () => {
it("returns the last assistant response wrapped in a tab_response tag", async () => {
const tool = createReadTabTool(makeCallbacks());
const out = await tool.execute({ tab_id: "targ" });
expect(out).toContain("<tab_response");
expect(out).toContain('tab="targ"');
expect(out).toContain('status="idle"');
expect(out).toContain("the answer is 42");
expect(out).toContain("</tab_response>");
});
it("notes that a running tab's response is its previous completed turn", async () => {
const tool = createReadTabTool(
makeCallbacks({
getLastResponse: () => ({ text: "older turn", status: "running" }),
}),
);
const out = await tool.execute({ tab_id: "targ" });
expect(out).toContain("still running");
expect(out).toContain("older turn");
});
it("explains when a tab has no completed response yet (idle)", async () => {
const tool = createReadTabTool(
makeCallbacks({
getLastResponse: () => ({ text: null, status: "idle" }),
}),
);
const out = await tool.execute({ tab_id: "targ" });
expect(out).toContain("no completed response");
expect(out).toContain("no assistant responses yet");
});
it("explains when a tab is still on its first turn (running, no prior text)", async () => {
const tool = createReadTabTool(
makeCallbacks({
getLastResponse: () => ({ text: null, status: "running" }),
}),
);
const out = await tool.execute({ tab_id: "targ" });
expect(out).toContain("no completed response");
expect(out).toContain("still working on its first turn");
});
it("rejects an empty tab_id and lists open handles", async () => {
const tool = createReadTabTool(makeCallbacks());
const out = await tool.execute({ tab_id: "" });
expect(out).toContain("Error");
expect(out).toContain("targ");
});
it("returns a helpful error when the id is unknown", async () => {
const tool = createReadTabTool(makeCallbacks({ resolveShortId: () => ({ status: "none" }) }));
const out = await tool.execute({ tab_id: "zzzz" });
expect(out).toContain("no open tab matches");
expect(out).toContain("Currently open tabs:");
});
it("asks for more characters when the id is ambiguous", async () => {
const tool = createReadTabTool(
makeCallbacks({
resolveShortId: () => ({
status: "ambiguous",
matches: [
{ id: "a1", title: "One", handle: "abcd1" },
{ id: "a2", title: "Two", handle: "abcd2" },
],
}),
}),
);
const out = await tool.execute({ tab_id: "abcd" });
expect(out).toContain("ambiguous");
expect(out).toContain("abcd1");
expect(out).toContain("abcd2");
});
});
|