test: cover browser snapshot labels and efficient mode

This commit is contained in:
Peter Steinberger
2026-01-15 04:04:23 +00:00
parent 6320f739d4
commit 429f973280
5 changed files with 94 additions and 12 deletions

View File

@@ -10,6 +10,7 @@
- Security: add detect-secrets CI scan and baseline guidance. (#227) — thanks @Hyaxia.
### Fixes
- Browser: add tests for snapshot labels/efficient query params and labeled image responses.
- Doctor: avoid re-adding WhatsApp config when only legacy ack reactions are set. (#927, fixes #900) — thanks @grp06.
- Agents: scrub tuple `items` schemas for Gemini tool calls. (#926, fixes #746) — thanks @grp06.
- Embedded runner: suppress raw API error payloads from replies. (#924) — thanks @grp06.

View File

@@ -80,14 +80,9 @@ function resolveProviderToolPolicy(params: {
const normalizedProvider = normalizeProviderKey(provider);
const rawModelId = params.modelId?.trim().toLowerCase();
const fullModelId =
rawModelId && !rawModelId.includes("/")
? `${normalizedProvider}/${rawModelId}`
: rawModelId;
rawModelId && !rawModelId.includes("/") ? `${normalizedProvider}/${rawModelId}` : rawModelId;
const candidates = [
...(fullModelId ? [fullModelId] : []),
normalizedProvider,
];
const candidates = [...(fullModelId ? [fullModelId] : []), normalizedProvider];
for (const key of candidates) {
const match = lookup.get(key);

View File

@@ -125,8 +125,7 @@ export function createClawdbotCodingTools(options?: {
});
const profilePolicy = resolveToolProfilePolicy(profile);
const providerProfilePolicy = resolveToolProfilePolicy(providerProfile);
const scopeKey =
options?.exec?.scopeKey ?? (agentId ? `agent:${agentId}` : undefined);
const scopeKey = options?.exec?.scopeKey ?? (agentId ? `agent:${agentId}` : undefined);
const subagentPolicy =
isSubagentSessionKey(options?.sessionKey) && options?.sessionKey
? resolveSubagentToolPolicy(options.config)
@@ -240,9 +239,7 @@ export function createClawdbotCodingTools(options?: {
hasRepliedRef: options?.hasRepliedRef,
}),
];
const toolsFiltered = profilePolicy
? filterToolsByPolicy(tools, profilePolicy)
: tools;
const toolsFiltered = profilePolicy ? filterToolsByPolicy(tools, profilePolicy) : tools;
const providerProfileFiltered = providerProfilePolicy
? filterToolsByPolicy(toolsFiltered, providerProfilePolicy)
: toolsFiltered;

View File

@@ -52,6 +52,17 @@ vi.mock("../../config/config.js", () => ({
loadConfig: vi.fn(() => ({ browser: {} })),
}));
const toolCommonMocks = vi.hoisted(() => ({
imageResultFromFile: vi.fn(),
}));
vi.mock("./common.js", async () => {
const actual = await vi.importActual<typeof import("./common.js")>("./common.js");
return {
...actual,
imageResultFromFile: toolCommonMocks.imageResultFromFile,
};
});
import { DEFAULT_AI_SNAPSHOT_MAX_CHARS } from "../../browser/constants.js";
import { createBrowserTool } from "./browser-tool.js";
@@ -103,3 +114,47 @@ describe("browser tool snapshot maxChars", () => {
expect(Object.hasOwn(opts ?? {}, "maxChars")).toBe(false);
});
});
describe("browser tool snapshot labels", () => {
afterEach(() => {
vi.clearAllMocks();
});
it("returns image + text when labels are requested", async () => {
const tool = createBrowserTool();
const imageResult = {
content: [
{ type: "text", text: "label text" },
{ type: "image", data: "base64", mimeType: "image/png" },
],
details: { path: "/tmp/snap.png" },
};
toolCommonMocks.imageResultFromFile.mockResolvedValueOnce(imageResult);
browserClientMocks.browserSnapshot.mockResolvedValueOnce({
ok: true,
format: "ai",
targetId: "t1",
url: "https://example.com",
snapshot: "label text",
imagePath: "/tmp/snap.png",
});
const result = await tool.execute?.(null, {
action: "snapshot",
format: "ai",
labels: true,
});
expect(toolCommonMocks.imageResultFromFile).toHaveBeenCalledWith(
expect.objectContaining({
path: "/tmp/snap.png",
extraText: "label text",
}),
);
expect(result).toEqual(imageResult);
expect(result?.content).toHaveLength(2);
expect(result?.content?.[0]).toMatchObject({ type: "text", text: "label text" });
expect(result?.content?.[1]).toMatchObject({ type: "image" });
});
});

View File

@@ -49,6 +49,40 @@ describe("browser client", () => {
).rejects.toThrow(/409: conflict/i);
});
it("adds labels + efficient mode query params to snapshots", async () => {
const calls: string[] = [];
vi.stubGlobal(
"fetch",
vi.fn(async (url: string) => {
calls.push(url);
return {
ok: true,
json: async () => ({
ok: true,
format: "ai",
targetId: "t1",
url: "https://x",
snapshot: "ok",
}),
} as unknown as Response;
}),
);
await expect(
browserSnapshot("http://127.0.0.1:18791", {
format: "ai",
labels: true,
mode: "efficient",
}),
).resolves.toMatchObject({ ok: true, format: "ai" });
const snapshotCall = calls.find((url) => url.includes("/snapshot?"));
expect(snapshotCall).toBeTruthy();
const parsed = new URL(snapshotCall as string);
expect(parsed.searchParams.get("labels")).toBe("1");
expect(parsed.searchParams.get("mode")).toBe("efficient");
});
it("uses the expected endpoints + methods for common calls", async () => {
const calls: Array<{ url: string; init?: RequestInit }> = [];