mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 10:17:39 +00:00
chore: Fix types in tests 5/N.
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import type { GatewayMessageChannel } from "../utils/message-channel.js";
|
|
||||||
import type { SandboxFsBridge } from "./sandbox/fs-bridge.js";
|
|
||||||
import type { AnyAgentTool } from "./tools/common.js";
|
|
||||||
import { resolvePluginTools } from "../plugins/tools.js";
|
import { resolvePluginTools } from "../plugins/tools.js";
|
||||||
|
import type { GatewayMessageChannel } from "../utils/message-channel.js";
|
||||||
import { resolveSessionAgentId } from "./agent-scope.js";
|
import { resolveSessionAgentId } from "./agent-scope.js";
|
||||||
|
import type { SandboxFsBridge } from "./sandbox/fs-bridge.js";
|
||||||
import { createAgentsListTool } from "./tools/agents-list-tool.js";
|
import { createAgentsListTool } from "./tools/agents-list-tool.js";
|
||||||
import { createBrowserTool } from "./tools/browser-tool.js";
|
import { createBrowserTool } from "./tools/browser-tool.js";
|
||||||
import { createCanvasTool } from "./tools/canvas-tool.js";
|
import { createCanvasTool } from "./tools/canvas-tool.js";
|
||||||
|
import type { AnyAgentTool } from "./tools/common.js";
|
||||||
import { createCronTool } from "./tools/cron-tool.js";
|
import { createCronTool } from "./tools/cron-tool.js";
|
||||||
import { createGatewayTool } from "./tools/gateway-tool.js";
|
import { createGatewayTool } from "./tools/gateway-tool.js";
|
||||||
import { createImageTool } from "./tools/image-tool.js";
|
import { createImageTool } from "./tools/image-tool.js";
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ describe("sanitizeToolUseResultPairing", () => {
|
|||||||
content: [{ type: "text", text: "ok" }],
|
content: [{ type: "text", text: "ok" }],
|
||||||
isError: false,
|
isError: false,
|
||||||
},
|
},
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolUseResultPairing(input);
|
const out = sanitizeToolUseResultPairing(input);
|
||||||
expect(out[0]?.role).toBe("assistant");
|
expect(out[0]?.role).toBe("assistant");
|
||||||
@@ -56,7 +56,7 @@ describe("sanitizeToolUseResultPairing", () => {
|
|||||||
isError: false,
|
isError: false,
|
||||||
},
|
},
|
||||||
{ role: "user", content: "ok" },
|
{ role: "user", content: "ok" },
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolUseResultPairing(input);
|
const out = sanitizeToolUseResultPairing(input);
|
||||||
expect(out.filter((m) => m.role === "toolResult")).toHaveLength(1);
|
expect(out.filter((m) => m.role === "toolResult")).toHaveLength(1);
|
||||||
@@ -83,7 +83,7 @@ describe("sanitizeToolUseResultPairing", () => {
|
|||||||
content: [{ type: "text", text: "second (duplicate)" }],
|
content: [{ type: "text", text: "second (duplicate)" }],
|
||||||
isError: false,
|
isError: false,
|
||||||
},
|
},
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolUseResultPairing(input);
|
const out = sanitizeToolUseResultPairing(input);
|
||||||
const results = out.filter((m) => m.role === "toolResult") as Array<{
|
const results = out.filter((m) => m.role === "toolResult") as Array<{
|
||||||
@@ -107,7 +107,7 @@ describe("sanitizeToolUseResultPairing", () => {
|
|||||||
role: "assistant",
|
role: "assistant",
|
||||||
content: [{ type: "text", text: "ok" }],
|
content: [{ type: "text", text: "ok" }],
|
||||||
},
|
},
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolUseResultPairing(input);
|
const out = sanitizeToolUseResultPairing(input);
|
||||||
expect(out.some((m) => m.role === "toolResult")).toBe(false);
|
expect(out.some((m) => m.role === "toolResult")).toBe(false);
|
||||||
@@ -125,7 +125,7 @@ describe("sanitizeToolUseResultPairing", () => {
|
|||||||
stopReason: "error",
|
stopReason: "error",
|
||||||
},
|
},
|
||||||
{ role: "user", content: "something went wrong" },
|
{ role: "user", content: "something went wrong" },
|
||||||
] as AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const result = repairToolUseResultPairing(input);
|
const result = repairToolUseResultPairing(input);
|
||||||
|
|
||||||
@@ -147,7 +147,7 @@ describe("sanitizeToolUseResultPairing", () => {
|
|||||||
stopReason: "aborted",
|
stopReason: "aborted",
|
||||||
},
|
},
|
||||||
{ role: "user", content: "retrying after abort" },
|
{ role: "user", content: "retrying after abort" },
|
||||||
] as AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const result = repairToolUseResultPairing(input);
|
const result = repairToolUseResultPairing(input);
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ describe("sanitizeToolUseResultPairing", () => {
|
|||||||
stopReason: "toolUse",
|
stopReason: "toolUse",
|
||||||
},
|
},
|
||||||
{ role: "user", content: "user message" },
|
{ role: "user", content: "user message" },
|
||||||
] as AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const result = repairToolUseResultPairing(input);
|
const result = repairToolUseResultPairing(input);
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ describe("sanitizeToolUseResultPairing", () => {
|
|||||||
isError: false,
|
isError: false,
|
||||||
},
|
},
|
||||||
{ role: "user", content: "retrying" },
|
{ role: "user", content: "retrying" },
|
||||||
] as AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const result = repairToolUseResultPairing(input);
|
const result = repairToolUseResultPairing(input);
|
||||||
|
|
||||||
@@ -211,20 +211,20 @@ describe("sanitizeToolUseResultPairing", () => {
|
|||||||
|
|
||||||
describe("sanitizeToolCallInputs", () => {
|
describe("sanitizeToolCallInputs", () => {
|
||||||
it("drops tool calls missing input or arguments", () => {
|
it("drops tool calls missing input or arguments", () => {
|
||||||
const input: AgentMessage[] = [
|
const input = [
|
||||||
{
|
{
|
||||||
role: "assistant",
|
role: "assistant",
|
||||||
content: [{ type: "toolCall", id: "call_1", name: "read" }],
|
content: [{ type: "toolCall", id: "call_1", name: "read" }],
|
||||||
},
|
},
|
||||||
{ role: "user", content: "hello" },
|
{ role: "user", content: "hello" },
|
||||||
];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolCallInputs(input);
|
const out = sanitizeToolCallInputs(input);
|
||||||
expect(out.map((m) => m.role)).toEqual(["user"]);
|
expect(out.map((m) => m.role)).toEqual(["user"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("drops tool calls with missing or blank name/id", () => {
|
it("drops tool calls with missing or blank name/id", () => {
|
||||||
const input: AgentMessage[] = [
|
const input = [
|
||||||
{
|
{
|
||||||
role: "assistant",
|
role: "assistant",
|
||||||
content: [
|
content: [
|
||||||
@@ -234,7 +234,7 @@ describe("sanitizeToolCallInputs", () => {
|
|||||||
{ type: "functionCall", id: "", name: "exec", arguments: {} },
|
{ type: "functionCall", id: "", name: "exec", arguments: {} },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolCallInputs(input);
|
const out = sanitizeToolCallInputs(input);
|
||||||
const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
|
const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
|
||||||
@@ -250,7 +250,7 @@ describe("sanitizeToolCallInputs", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("keeps valid tool calls and preserves text blocks", () => {
|
it("keeps valid tool calls and preserves text blocks", () => {
|
||||||
const input: AgentMessage[] = [
|
const input = [
|
||||||
{
|
{
|
||||||
role: "assistant",
|
role: "assistant",
|
||||||
content: [
|
content: [
|
||||||
@@ -259,7 +259,7 @@ describe("sanitizeToolCallInputs", () => {
|
|||||||
{ type: "toolCall", id: "call_drop", name: "read" },
|
{ type: "toolCall", id: "call_drop", name: "read" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolCallInputs(input);
|
const out = sanitizeToolCallInputs(input);
|
||||||
const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
|
const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
|
import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
|
||||||
|
|
||||||
const agentSpy = vi.fn(async () => ({ runId: "run-main", status: "ok" }));
|
type AgentCallRequest = { method?: string; params?: Record<string, unknown> };
|
||||||
const sessionsDeleteSpy = vi.fn();
|
type RequesterResolution = {
|
||||||
const readLatestAssistantReplyMock = vi.fn(async () => "raw subagent reply");
|
requesterSessionKey: string;
|
||||||
|
requesterOrigin?: Record<string, unknown>;
|
||||||
|
} | null;
|
||||||
|
|
||||||
|
const agentSpy = vi.fn(async (_req: AgentCallRequest) => ({ runId: "run-main", status: "ok" }));
|
||||||
|
const sessionsDeleteSpy = vi.fn((_req: AgentCallRequest) => undefined);
|
||||||
|
const readLatestAssistantReplyMock = vi.fn(
|
||||||
|
async (_sessionKey?: string): Promise<string | undefined> => "raw subagent reply",
|
||||||
|
);
|
||||||
const embeddedRunMock = {
|
const embeddedRunMock = {
|
||||||
isEmbeddedPiRunActive: vi.fn(() => false),
|
isEmbeddedPiRunActive: vi.fn(() => false),
|
||||||
isEmbeddedPiRunStreaming: vi.fn(() => false),
|
isEmbeddedPiRunStreaming: vi.fn(() => false),
|
||||||
@@ -12,8 +20,8 @@ const embeddedRunMock = {
|
|||||||
};
|
};
|
||||||
const subagentRegistryMock = {
|
const subagentRegistryMock = {
|
||||||
isSubagentSessionRunActive: vi.fn(() => true),
|
isSubagentSessionRunActive: vi.fn(() => true),
|
||||||
countActiveDescendantRuns: vi.fn(() => 0),
|
countActiveDescendantRuns: vi.fn((_sessionKey: string) => 0),
|
||||||
resolveRequesterForChildSession: vi.fn(() => null),
|
resolveRequesterForChildSession: vi.fn((_sessionKey: string): RequesterResolution => null),
|
||||||
};
|
};
|
||||||
let sessionStore: Record<string, Record<string, unknown>> = {};
|
let sessionStore: Record<string, Record<string, unknown>> = {};
|
||||||
let configOverride: ReturnType<(typeof import("../config/config.js"))["loadConfig"]> = {
|
let configOverride: ReturnType<(typeof import("../config/config.js"))["loadConfig"]> = {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const buildDuplicateIdCollisionInput = () =>
|
|||||||
toolName: "read",
|
toolName: "read",
|
||||||
content: [{ type: "text", text: "two" }],
|
content: [{ type: "text", text: "two" }],
|
||||||
},
|
},
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
function expectCollisionIdsRemainDistinct(
|
function expectCollisionIdsRemainDistinct(
|
||||||
out: AgentMessage[],
|
out: AgentMessage[],
|
||||||
@@ -62,7 +62,7 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => {
|
|||||||
toolName: "read",
|
toolName: "read",
|
||||||
content: [{ type: "text", text: "ok" }],
|
content: [{ type: "text", text: "ok" }],
|
||||||
},
|
},
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolCallIdsForCloudCodeAssist(input);
|
const out = sanitizeToolCallIdsForCloudCodeAssist(input);
|
||||||
expect(out).toBe(input);
|
expect(out).toBe(input);
|
||||||
@@ -80,7 +80,7 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => {
|
|||||||
toolName: "read",
|
toolName: "read",
|
||||||
content: [{ type: "text", text: "ok" }],
|
content: [{ type: "text", text: "ok" }],
|
||||||
},
|
},
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolCallIdsForCloudCodeAssist(input);
|
const out = sanitizeToolCallIdsForCloudCodeAssist(input);
|
||||||
expect(out).not.toBe(input);
|
expect(out).not.toBe(input);
|
||||||
@@ -126,7 +126,7 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => {
|
|||||||
toolName: "read",
|
toolName: "read",
|
||||||
content: [{ type: "text", text: "two" }],
|
content: [{ type: "text", text: "two" }],
|
||||||
},
|
},
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolCallIdsForCloudCodeAssist(input);
|
const out = sanitizeToolCallIdsForCloudCodeAssist(input);
|
||||||
const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
|
const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
|
||||||
@@ -168,7 +168,7 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => {
|
|||||||
toolName: "login",
|
toolName: "login",
|
||||||
content: [{ type: "text", text: "ok" }],
|
content: [{ type: "text", text: "ok" }],
|
||||||
},
|
},
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolCallIdsForCloudCodeAssist(input, "strict");
|
const out = sanitizeToolCallIdsForCloudCodeAssist(input, "strict");
|
||||||
expect(out).not.toBe(input);
|
expect(out).not.toBe(input);
|
||||||
@@ -217,7 +217,7 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => {
|
|||||||
toolName: "read",
|
toolName: "read",
|
||||||
content: [{ type: "text", text: "two" }],
|
content: [{ type: "text", text: "two" }],
|
||||||
},
|
},
|
||||||
] satisfies AgentMessage[];
|
] as unknown as AgentMessage[];
|
||||||
|
|
||||||
const out = sanitizeToolCallIdsForCloudCodeAssist(input, "strict9");
|
const out = sanitizeToolCallIdsForCloudCodeAssist(input, "strict9");
|
||||||
expect(out).not.toBe(input);
|
expect(out).not.toBe(input);
|
||||||
|
|||||||
@@ -1,27 +1,31 @@
|
|||||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
const browserClientMocks = vi.hoisted(() => ({
|
const browserClientMocks = vi.hoisted(() => ({
|
||||||
browserCloseTab: vi.fn(async () => ({})),
|
browserCloseTab: vi.fn(async (..._args: unknown[]) => ({})),
|
||||||
browserFocusTab: vi.fn(async () => ({})),
|
browserFocusTab: vi.fn(async (..._args: unknown[]) => ({})),
|
||||||
browserOpenTab: vi.fn(async () => ({})),
|
browserOpenTab: vi.fn(async (..._args: unknown[]) => ({})),
|
||||||
browserProfiles: vi.fn(async () => []),
|
browserProfiles: vi.fn(
|
||||||
browserSnapshot: vi.fn(async () => ({
|
async (..._args: unknown[]): Promise<Array<Record<string, unknown>>> => [],
|
||||||
ok: true,
|
),
|
||||||
format: "ai",
|
browserSnapshot: vi.fn(
|
||||||
targetId: "t1",
|
async (..._args: unknown[]): Promise<Record<string, unknown>> => ({
|
||||||
url: "https://example.com",
|
ok: true,
|
||||||
snapshot: "ok",
|
format: "ai",
|
||||||
})),
|
targetId: "t1",
|
||||||
browserStart: vi.fn(async () => ({})),
|
url: "https://example.com",
|
||||||
browserStatus: vi.fn(async () => ({
|
snapshot: "ok",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
browserStart: vi.fn(async (..._args: unknown[]) => ({})),
|
||||||
|
browserStatus: vi.fn(async (..._args: unknown[]) => ({
|
||||||
ok: true,
|
ok: true,
|
||||||
running: true,
|
running: true,
|
||||||
pid: 1,
|
pid: 1,
|
||||||
cdpPort: 18792,
|
cdpPort: 18792,
|
||||||
cdpUrl: "http://127.0.0.1:18792",
|
cdpUrl: "http://127.0.0.1:18792",
|
||||||
})),
|
})),
|
||||||
browserStop: vi.fn(async () => ({})),
|
browserStop: vi.fn(async (..._args: unknown[]) => ({})),
|
||||||
browserTabs: vi.fn(async () => []),
|
browserTabs: vi.fn(async (..._args: unknown[]): Promise<Array<Record<string, unknown>>> => []),
|
||||||
}));
|
}));
|
||||||
vi.mock("../../browser/client.js", () => browserClientMocks);
|
vi.mock("../../browser/client.js", () => browserClientMocks);
|
||||||
|
|
||||||
@@ -55,7 +59,7 @@ const browserConfigMocks = vi.hoisted(() => ({
|
|||||||
vi.mock("../../browser/config.js", () => browserConfigMocks);
|
vi.mock("../../browser/config.js", () => browserConfigMocks);
|
||||||
|
|
||||||
const nodesUtilsMocks = vi.hoisted(() => ({
|
const nodesUtilsMocks = vi.hoisted(() => ({
|
||||||
listNodes: vi.fn(async () => []),
|
listNodes: vi.fn(async (..._args: unknown[]): Promise<Array<Record<string, unknown>>> => []),
|
||||||
}));
|
}));
|
||||||
vi.mock("./nodes-utils.js", async () => {
|
vi.mock("./nodes-utils.js", async () => {
|
||||||
const actual = await vi.importActual<typeof import("./nodes-utils.js")>("./nodes-utils.js");
|
const actual = await vi.importActual<typeof import("./nodes-utils.js")>("./nodes-utils.js");
|
||||||
@@ -101,7 +105,7 @@ describe("browser tool snapshot maxChars", () => {
|
|||||||
|
|
||||||
it("applies the default ai snapshot limit", async () => {
|
it("applies the default ai snapshot limit", async () => {
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
await tool.execute?.(null, { action: "snapshot", snapshotFormat: "ai" });
|
await tool.execute?.("call-1", { action: "snapshot", snapshotFormat: "ai" });
|
||||||
|
|
||||||
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
|
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
|
||||||
undefined,
|
undefined,
|
||||||
@@ -115,7 +119,7 @@ describe("browser tool snapshot maxChars", () => {
|
|||||||
it("respects an explicit maxChars override", async () => {
|
it("respects an explicit maxChars override", async () => {
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
const override = 2_000;
|
const override = 2_000;
|
||||||
await tool.execute?.(null, {
|
await tool.execute?.("call-1", {
|
||||||
action: "snapshot",
|
action: "snapshot",
|
||||||
snapshotFormat: "ai",
|
snapshotFormat: "ai",
|
||||||
maxChars: override,
|
maxChars: override,
|
||||||
@@ -131,27 +135,29 @@ describe("browser tool snapshot maxChars", () => {
|
|||||||
|
|
||||||
it("skips the default when maxChars is explicitly zero", async () => {
|
it("skips the default when maxChars is explicitly zero", async () => {
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
await tool.execute?.(null, {
|
await tool.execute?.("call-1", {
|
||||||
action: "snapshot",
|
action: "snapshot",
|
||||||
snapshotFormat: "ai",
|
snapshotFormat: "ai",
|
||||||
maxChars: 0,
|
maxChars: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(browserClientMocks.browserSnapshot).toHaveBeenCalled();
|
expect(browserClientMocks.browserSnapshot).toHaveBeenCalled();
|
||||||
const [, opts] = browserClientMocks.browserSnapshot.mock.calls.at(-1) ?? [];
|
const opts = browserClientMocks.browserSnapshot.mock.calls.at(-1)?.[1] as
|
||||||
|
| { maxChars?: number }
|
||||||
|
| undefined;
|
||||||
expect(Object.hasOwn(opts ?? {}, "maxChars")).toBe(false);
|
expect(Object.hasOwn(opts ?? {}, "maxChars")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("lists profiles", async () => {
|
it("lists profiles", async () => {
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
await tool.execute?.(null, { action: "profiles" });
|
await tool.execute?.("call-1", { action: "profiles" });
|
||||||
|
|
||||||
expect(browserClientMocks.browserProfiles).toHaveBeenCalledWith(undefined);
|
expect(browserClientMocks.browserProfiles).toHaveBeenCalledWith(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("passes refs mode through to browser snapshot", async () => {
|
it("passes refs mode through to browser snapshot", async () => {
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
await tool.execute?.(null, { action: "snapshot", snapshotFormat: "ai", refs: "aria" });
|
await tool.execute?.("call-1", { action: "snapshot", snapshotFormat: "ai", refs: "aria" });
|
||||||
|
|
||||||
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
|
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
|
||||||
undefined,
|
undefined,
|
||||||
@@ -167,7 +173,7 @@ describe("browser tool snapshot maxChars", () => {
|
|||||||
browser: { snapshotDefaults: { mode: "efficient" } },
|
browser: { snapshotDefaults: { mode: "efficient" } },
|
||||||
});
|
});
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
await tool.execute?.(null, { action: "snapshot", snapshotFormat: "ai" });
|
await tool.execute?.("call-1", { action: "snapshot", snapshotFormat: "ai" });
|
||||||
|
|
||||||
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
|
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
|
||||||
undefined,
|
undefined,
|
||||||
@@ -182,16 +188,18 @@ describe("browser tool snapshot maxChars", () => {
|
|||||||
browser: { snapshotDefaults: { mode: "efficient" } },
|
browser: { snapshotDefaults: { mode: "efficient" } },
|
||||||
});
|
});
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
await tool.execute?.(null, { action: "snapshot", snapshotFormat: "aria" });
|
await tool.execute?.("call-1", { action: "snapshot", snapshotFormat: "aria" });
|
||||||
|
|
||||||
expect(browserClientMocks.browserSnapshot).toHaveBeenCalled();
|
expect(browserClientMocks.browserSnapshot).toHaveBeenCalled();
|
||||||
const [, opts] = browserClientMocks.browserSnapshot.mock.calls.at(-1) ?? [];
|
const opts = browserClientMocks.browserSnapshot.mock.calls.at(-1)?.[1] as
|
||||||
|
| { mode?: string }
|
||||||
|
| undefined;
|
||||||
expect(opts?.mode).toBeUndefined();
|
expect(opts?.mode).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("defaults to host when using profile=chrome (even in sandboxed sessions)", async () => {
|
it("defaults to host when using profile=chrome (even in sandboxed sessions)", async () => {
|
||||||
const tool = createBrowserTool({ sandboxBridgeUrl: "http://127.0.0.1:9999" });
|
const tool = createBrowserTool({ sandboxBridgeUrl: "http://127.0.0.1:9999" });
|
||||||
await tool.execute?.(null, { action: "snapshot", profile: "chrome", snapshotFormat: "ai" });
|
await tool.execute?.("call-1", { action: "snapshot", profile: "chrome", snapshotFormat: "ai" });
|
||||||
|
|
||||||
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
|
expect(browserClientMocks.browserSnapshot).toHaveBeenCalledWith(
|
||||||
undefined,
|
undefined,
|
||||||
@@ -212,7 +220,7 @@ describe("browser tool snapshot maxChars", () => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
await tool.execute?.(null, { action: "status", target: "node" });
|
await tool.execute?.("call-1", { action: "status", target: "node" });
|
||||||
|
|
||||||
expect(gatewayMocks.callGatewayTool).toHaveBeenCalledWith(
|
expect(gatewayMocks.callGatewayTool).toHaveBeenCalledWith(
|
||||||
"node.invoke",
|
"node.invoke",
|
||||||
@@ -236,7 +244,7 @@ describe("browser tool snapshot maxChars", () => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const tool = createBrowserTool({ sandboxBridgeUrl: "http://127.0.0.1:9999" });
|
const tool = createBrowserTool({ sandboxBridgeUrl: "http://127.0.0.1:9999" });
|
||||||
await tool.execute?.(null, { action: "status" });
|
await tool.execute?.("call-1", { action: "status" });
|
||||||
|
|
||||||
expect(browserClientMocks.browserStatus).toHaveBeenCalledWith(
|
expect(browserClientMocks.browserStatus).toHaveBeenCalledWith(
|
||||||
"http://127.0.0.1:9999",
|
"http://127.0.0.1:9999",
|
||||||
@@ -256,7 +264,7 @@ describe("browser tool snapshot maxChars", () => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
await tool.execute?.(null, { action: "status", profile: "chrome" });
|
await tool.execute?.("call-1", { action: "status", profile: "chrome" });
|
||||||
|
|
||||||
expect(browserClientMocks.browserStatus).toHaveBeenCalledWith(
|
expect(browserClientMocks.browserStatus).toHaveBeenCalledWith(
|
||||||
undefined,
|
undefined,
|
||||||
@@ -292,7 +300,7 @@ describe("browser tool snapshot labels", () => {
|
|||||||
imagePath: "/tmp/snap.png",
|
imagePath: "/tmp/snap.png",
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await tool.execute?.(null, {
|
const result = await tool.execute?.("call-1", {
|
||||||
action: "snapshot",
|
action: "snapshot",
|
||||||
snapshotFormat: "ai",
|
snapshotFormat: "ai",
|
||||||
labels: true,
|
labels: true,
|
||||||
@@ -335,7 +343,7 @@ describe("browser tool external content wrapping", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
const result = await tool.execute?.(null, { action: "snapshot", snapshotFormat: "aria" });
|
const result = await tool.execute?.("call-1", { action: "snapshot", snapshotFormat: "aria" });
|
||||||
expect(result?.content?.[0]).toMatchObject({
|
expect(result?.content?.[0]).toMatchObject({
|
||||||
type: "text",
|
type: "text",
|
||||||
text: expect.stringContaining("<<<EXTERNAL_UNTRUSTED_CONTENT>>>"),
|
text: expect.stringContaining("<<<EXTERNAL_UNTRUSTED_CONTENT>>>"),
|
||||||
@@ -369,7 +377,7 @@ describe("browser tool external content wrapping", () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
const result = await tool.execute?.(null, { action: "tabs" });
|
const result = await tool.execute?.("call-1", { action: "tabs" });
|
||||||
expect(result?.content?.[0]).toMatchObject({
|
expect(result?.content?.[0]).toMatchObject({
|
||||||
type: "text",
|
type: "text",
|
||||||
text: expect.stringContaining("<<<EXTERNAL_UNTRUSTED_CONTENT>>>"),
|
text: expect.stringContaining("<<<EXTERNAL_UNTRUSTED_CONTENT>>>"),
|
||||||
@@ -402,7 +410,7 @@ describe("browser tool external content wrapping", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const tool = createBrowserTool();
|
const tool = createBrowserTool();
|
||||||
const result = await tool.execute?.(null, { action: "console" });
|
const result = await tool.execute?.("call-1", { action: "console" });
|
||||||
expect(result?.content?.[0]).toMatchObject({
|
expect(result?.content?.[0]).toMatchObject({
|
||||||
type: "text",
|
type: "text",
|
||||||
text: expect.stringContaining("<<<EXTERNAL_UNTRUSTED_CONTENT>>>"),
|
text: expect.stringContaining("<<<EXTERNAL_UNTRUSTED_CONTENT>>>"),
|
||||||
|
|||||||
@@ -43,35 +43,35 @@ const kickMemberDiscord = vi.fn(async () => ({}));
|
|||||||
const banMemberDiscord = vi.fn(async () => ({}));
|
const banMemberDiscord = vi.fn(async () => ({}));
|
||||||
|
|
||||||
vi.mock("../../discord/send.js", () => ({
|
vi.mock("../../discord/send.js", () => ({
|
||||||
banMemberDiscord: (...args: unknown[]) => banMemberDiscord(...args),
|
banMemberDiscord,
|
||||||
createChannelDiscord: (...args: unknown[]) => createChannelDiscord(...args),
|
createChannelDiscord,
|
||||||
createThreadDiscord: (...args: unknown[]) => createThreadDiscord(...args),
|
createThreadDiscord,
|
||||||
deleteChannelDiscord: (...args: unknown[]) => deleteChannelDiscord(...args),
|
deleteChannelDiscord,
|
||||||
deleteMessageDiscord: (...args: unknown[]) => deleteMessageDiscord(...args),
|
deleteMessageDiscord,
|
||||||
editChannelDiscord: (...args: unknown[]) => editChannelDiscord(...args),
|
editChannelDiscord,
|
||||||
editMessageDiscord: (...args: unknown[]) => editMessageDiscord(...args),
|
editMessageDiscord,
|
||||||
fetchMessageDiscord: (...args: unknown[]) => fetchMessageDiscord(...args),
|
fetchMessageDiscord,
|
||||||
fetchChannelPermissionsDiscord: (...args: unknown[]) => fetchChannelPermissionsDiscord(...args),
|
fetchChannelPermissionsDiscord,
|
||||||
fetchReactionsDiscord: (...args: unknown[]) => fetchReactionsDiscord(...args),
|
fetchReactionsDiscord,
|
||||||
kickMemberDiscord: (...args: unknown[]) => kickMemberDiscord(...args),
|
kickMemberDiscord,
|
||||||
listGuildChannelsDiscord: (...args: unknown[]) => listGuildChannelsDiscord(...args),
|
listGuildChannelsDiscord,
|
||||||
listPinsDiscord: (...args: unknown[]) => listPinsDiscord(...args),
|
listPinsDiscord,
|
||||||
listThreadsDiscord: (...args: unknown[]) => listThreadsDiscord(...args),
|
listThreadsDiscord,
|
||||||
moveChannelDiscord: (...args: unknown[]) => moveChannelDiscord(...args),
|
moveChannelDiscord,
|
||||||
pinMessageDiscord: (...args: unknown[]) => pinMessageDiscord(...args),
|
pinMessageDiscord,
|
||||||
reactMessageDiscord: (...args: unknown[]) => reactMessageDiscord(...args),
|
reactMessageDiscord,
|
||||||
readMessagesDiscord: (...args: unknown[]) => readMessagesDiscord(...args),
|
readMessagesDiscord,
|
||||||
removeChannelPermissionDiscord: (...args: unknown[]) => removeChannelPermissionDiscord(...args),
|
removeChannelPermissionDiscord,
|
||||||
removeOwnReactionsDiscord: (...args: unknown[]) => removeOwnReactionsDiscord(...args),
|
removeOwnReactionsDiscord,
|
||||||
removeReactionDiscord: (...args: unknown[]) => removeReactionDiscord(...args),
|
removeReactionDiscord,
|
||||||
searchMessagesDiscord: (...args: unknown[]) => searchMessagesDiscord(...args),
|
searchMessagesDiscord,
|
||||||
sendMessageDiscord: (...args: unknown[]) => sendMessageDiscord(...args),
|
sendMessageDiscord,
|
||||||
sendVoiceMessageDiscord: (...args: unknown[]) => sendVoiceMessageDiscord(...args),
|
sendVoiceMessageDiscord,
|
||||||
sendPollDiscord: (...args: unknown[]) => sendPollDiscord(...args),
|
sendPollDiscord,
|
||||||
sendStickerDiscord: (...args: unknown[]) => sendStickerDiscord(...args),
|
sendStickerDiscord,
|
||||||
setChannelPermissionDiscord: (...args: unknown[]) => setChannelPermissionDiscord(...args),
|
setChannelPermissionDiscord,
|
||||||
timeoutMemberDiscord: (...args: unknown[]) => timeoutMemberDiscord(...args),
|
timeoutMemberDiscord,
|
||||||
unpinMessageDiscord: (...args: unknown[]) => unpinMessageDiscord(...args),
|
unpinMessageDiscord,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const enableAllActions = () => true;
|
const enableAllActions = () => true;
|
||||||
@@ -165,7 +165,9 @@ describe("handleDiscordMessagingAction", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("adds normalized timestamps to readMessages payloads", async () => {
|
it("adds normalized timestamps to readMessages payloads", async () => {
|
||||||
readMessagesDiscord.mockResolvedValueOnce([{ id: "1", timestamp: "2026-01-15T10:00:00.000Z" }]);
|
readMessagesDiscord.mockResolvedValueOnce([
|
||||||
|
{ id: "1", timestamp: "2026-01-15T10:00:00.000Z" },
|
||||||
|
] as never);
|
||||||
|
|
||||||
const result = await handleDiscordMessagingAction(
|
const result = await handleDiscordMessagingAction(
|
||||||
"readMessages",
|
"readMessages",
|
||||||
|
|||||||
@@ -2,34 +2,34 @@ import { describe, expect, it, vi } from "vitest";
|
|||||||
import type { OpenClawConfig } from "../../config/config.js";
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
import { handleSlackAction } from "./slack-actions.js";
|
import { handleSlackAction } from "./slack-actions.js";
|
||||||
|
|
||||||
const deleteSlackMessage = vi.fn(async () => ({}));
|
const deleteSlackMessage = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const editSlackMessage = vi.fn(async () => ({}));
|
const editSlackMessage = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const getSlackMemberInfo = vi.fn(async () => ({}));
|
const getSlackMemberInfo = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const listSlackEmojis = vi.fn(async () => ({}));
|
const listSlackEmojis = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const listSlackPins = vi.fn(async () => ({}));
|
const listSlackPins = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const listSlackReactions = vi.fn(async () => ({}));
|
const listSlackReactions = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const pinSlackMessage = vi.fn(async () => ({}));
|
const pinSlackMessage = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const reactSlackMessage = vi.fn(async () => ({}));
|
const reactSlackMessage = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const readSlackMessages = vi.fn(async () => ({}));
|
const readSlackMessages = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const removeOwnSlackReactions = vi.fn(async () => ["thumbsup"]);
|
const removeOwnSlackReactions = vi.fn(async (..._args: unknown[]) => ["thumbsup"]);
|
||||||
const removeSlackReaction = vi.fn(async () => ({}));
|
const removeSlackReaction = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const sendSlackMessage = vi.fn(async () => ({}));
|
const sendSlackMessage = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
const unpinSlackMessage = vi.fn(async () => ({}));
|
const unpinSlackMessage = vi.fn(async (..._args: unknown[]) => ({}));
|
||||||
|
|
||||||
vi.mock("../../slack/actions.js", () => ({
|
vi.mock("../../slack/actions.js", () => ({
|
||||||
deleteSlackMessage: (...args: unknown[]) => deleteSlackMessage(...args),
|
deleteSlackMessage,
|
||||||
editSlackMessage: (...args: unknown[]) => editSlackMessage(...args),
|
editSlackMessage,
|
||||||
getSlackMemberInfo: (...args: unknown[]) => getSlackMemberInfo(...args),
|
getSlackMemberInfo,
|
||||||
listSlackEmojis: (...args: unknown[]) => listSlackEmojis(...args),
|
listSlackEmojis,
|
||||||
listSlackPins: (...args: unknown[]) => listSlackPins(...args),
|
listSlackPins,
|
||||||
listSlackReactions: (...args: unknown[]) => listSlackReactions(...args),
|
listSlackReactions,
|
||||||
pinSlackMessage: (...args: unknown[]) => pinSlackMessage(...args),
|
pinSlackMessage,
|
||||||
reactSlackMessage: (...args: unknown[]) => reactSlackMessage(...args),
|
reactSlackMessage,
|
||||||
readSlackMessages: (...args: unknown[]) => readSlackMessages(...args),
|
readSlackMessages,
|
||||||
removeOwnSlackReactions: (...args: unknown[]) => removeOwnSlackReactions(...args),
|
removeOwnSlackReactions,
|
||||||
removeSlackReaction: (...args: unknown[]) => removeSlackReaction(...args),
|
removeSlackReaction,
|
||||||
sendSlackMessage: (...args: unknown[]) => sendSlackMessage(...args),
|
sendSlackMessage,
|
||||||
unpinSlackMessage: (...args: unknown[]) => unpinSlackMessage(...args),
|
unpinSlackMessage,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe("handleSlackAction", () => {
|
describe("handleSlackAction", () => {
|
||||||
@@ -521,7 +521,7 @@ describe("handleSlackAction", () => {
|
|||||||
cfg,
|
cfg,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [, opts] = readSlackMessages.mock.calls[0] ?? [];
|
const opts = readSlackMessages.mock.calls[0]?.[1] as { threadId?: string } | undefined;
|
||||||
expect(opts?.threadId).toBe("12345.6789");
|
expect(opts?.threadId).toBe("12345.6789");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -551,7 +551,7 @@ describe("handleSlackAction", () => {
|
|||||||
readSlackMessages.mockClear();
|
readSlackMessages.mockClear();
|
||||||
readSlackMessages.mockResolvedValueOnce({ messages: [], hasMore: false });
|
readSlackMessages.mockResolvedValueOnce({ messages: [], hasMore: false });
|
||||||
await handleSlackAction({ action: "readMessages", channelId: "C1" }, cfg);
|
await handleSlackAction({ action: "readMessages", channelId: "C1" }, cfg);
|
||||||
const [, opts] = readSlackMessages.mock.calls[0] ?? [];
|
const opts = readSlackMessages.mock.calls[0]?.[1] as { token?: string } | undefined;
|
||||||
expect(opts?.token).toBe("xoxp-1");
|
expect(opts?.token).toBe("xoxp-1");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -562,7 +562,7 @@ describe("handleSlackAction", () => {
|
|||||||
readSlackMessages.mockClear();
|
readSlackMessages.mockClear();
|
||||||
readSlackMessages.mockResolvedValueOnce({ messages: [], hasMore: false });
|
readSlackMessages.mockResolvedValueOnce({ messages: [], hasMore: false });
|
||||||
await handleSlackAction({ action: "readMessages", channelId: "C1" }, cfg);
|
await handleSlackAction({ action: "readMessages", channelId: "C1" }, cfg);
|
||||||
const [, opts] = readSlackMessages.mock.calls[0] ?? [];
|
const opts = readSlackMessages.mock.calls[0]?.[1] as { token?: string } | undefined;
|
||||||
expect(opts?.token).toBeUndefined();
|
expect(opts?.token).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -572,7 +572,7 @@ describe("handleSlackAction", () => {
|
|||||||
} as OpenClawConfig;
|
} as OpenClawConfig;
|
||||||
sendSlackMessage.mockClear();
|
sendSlackMessage.mockClear();
|
||||||
await handleSlackAction({ action: "sendMessage", to: "channel:C1", content: "Hello" }, cfg);
|
await handleSlackAction({ action: "sendMessage", to: "channel:C1", content: "Hello" }, cfg);
|
||||||
const [, , opts] = sendSlackMessage.mock.calls[0] ?? [];
|
const opts = sendSlackMessage.mock.calls[0]?.[2] as { token?: string } | undefined;
|
||||||
expect(opts?.token).toBeUndefined();
|
expect(opts?.token).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -584,7 +584,7 @@ describe("handleSlackAction", () => {
|
|||||||
} as OpenClawConfig;
|
} as OpenClawConfig;
|
||||||
sendSlackMessage.mockClear();
|
sendSlackMessage.mockClear();
|
||||||
await handleSlackAction({ action: "sendMessage", to: "channel:C1", content: "Hello" }, cfg);
|
await handleSlackAction({ action: "sendMessage", to: "channel:C1", content: "Hello" }, cfg);
|
||||||
const [, , opts] = sendSlackMessage.mock.calls[0] ?? [];
|
const opts = sendSlackMessage.mock.calls[0]?.[2] as { token?: string } | undefined;
|
||||||
expect(opts?.token).toBe("xoxp-1");
|
expect(opts?.token).toBe("xoxp-1");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|||||||
import { createWebFetchTool, createWebSearchTool } from "./web-tools.js";
|
import { createWebFetchTool, createWebSearchTool } from "./web-tools.js";
|
||||||
|
|
||||||
function installMockFetch(payload: unknown) {
|
function installMockFetch(payload: unknown) {
|
||||||
const mockFetch = vi.fn(() =>
|
const mockFetch = vi.fn((_input?: unknown, _init?: unknown) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: () => Promise.resolve(payload),
|
json: () => Promise.resolve(payload),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
// @ts-expect-error mock fetch
|
|
||||||
global.fetch = mockFetch;
|
global.fetch = mockFetch;
|
||||||
return mockFetch;
|
return mockFetch;
|
||||||
}
|
}
|
||||||
@@ -55,7 +54,7 @@ async function executePerplexitySearch(
|
|||||||
const mockFetch = installPerplexitySuccessFetch();
|
const mockFetch = installPerplexitySuccessFetch();
|
||||||
const tool = createPerplexitySearchTool(options?.perplexityConfig);
|
const tool = createPerplexitySearchTool(options?.perplexityConfig);
|
||||||
await tool?.execute?.(
|
await tool?.execute?.(
|
||||||
1,
|
"call-1",
|
||||||
options?.freshness ? { query, freshness: options.freshness } : { query },
|
options?.freshness ? { query, freshness: options.freshness } : { query },
|
||||||
);
|
);
|
||||||
return mockFetch;
|
return mockFetch;
|
||||||
@@ -90,7 +89,6 @@ describe("web_search country and language parameters", () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.unstubAllEnvs();
|
vi.unstubAllEnvs();
|
||||||
// @ts-expect-error global fetch cleanup
|
|
||||||
global.fetch = priorFetch;
|
global.fetch = priorFetch;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -105,7 +103,7 @@ describe("web_search country and language parameters", () => {
|
|||||||
const mockFetch = installMockFetch({ web: { results: [] } });
|
const mockFetch = installMockFetch({ web: { results: [] } });
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
expect(tool).not.toBeNull();
|
expect(tool).not.toBeNull();
|
||||||
await tool?.execute?.(1, { query: "test", ...params });
|
await tool?.execute?.("call-1", { query: "test", ...params });
|
||||||
expect(mockFetch).toHaveBeenCalled();
|
expect(mockFetch).toHaveBeenCalled();
|
||||||
return new URL(mockFetch.mock.calls[0][0] as string);
|
return new URL(mockFetch.mock.calls[0][0] as string);
|
||||||
}
|
}
|
||||||
@@ -123,7 +121,7 @@ describe("web_search country and language parameters", () => {
|
|||||||
it("rejects invalid freshness values", async () => {
|
it("rejects invalid freshness values", async () => {
|
||||||
const mockFetch = installMockFetch({ web: { results: [] } });
|
const mockFetch = installMockFetch({ web: { results: [] } });
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
const result = await tool?.execute?.(1, { query: "test", freshness: "yesterday" });
|
const result = await tool?.execute?.("call-1", { query: "test", freshness: "yesterday" });
|
||||||
|
|
||||||
expect(mockFetch).not.toHaveBeenCalled();
|
expect(mockFetch).not.toHaveBeenCalled();
|
||||||
expect(result?.details).toMatchObject({ error: "invalid_freshness" });
|
expect(result?.details).toMatchObject({ error: "invalid_freshness" });
|
||||||
@@ -135,7 +133,6 @@ describe("web_search perplexity baseUrl defaults", () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.unstubAllEnvs();
|
vi.unstubAllEnvs();
|
||||||
// @ts-expect-error global fetch cleanup
|
|
||||||
global.fetch = priorFetch;
|
global.fetch = priorFetch;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -213,7 +210,6 @@ describe("web_search external content wrapping", () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.unstubAllEnvs();
|
vi.unstubAllEnvs();
|
||||||
// @ts-expect-error global fetch cleanup
|
|
||||||
global.fetch = priorFetch;
|
global.fetch = priorFetch;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -236,11 +232,10 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
// @ts-expect-error mock fetch
|
|
||||||
global.fetch = mockFetch;
|
global.fetch = mockFetch;
|
||||||
|
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
const result = await tool?.execute?.(1, { query: "test" });
|
const result = await tool?.execute?.("call-1", { query: "test" });
|
||||||
const details = result?.details as {
|
const details = result?.details as {
|
||||||
externalContent?: { untrusted?: boolean; source?: string; wrapped?: boolean };
|
externalContent?: { untrusted?: boolean; source?: string; wrapped?: boolean };
|
||||||
results?: Array<{ description?: string }>;
|
results?: Array<{ description?: string }>;
|
||||||
@@ -275,11 +270,10 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
// @ts-expect-error mock fetch
|
|
||||||
global.fetch = mockFetch;
|
global.fetch = mockFetch;
|
||||||
|
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
const result = await tool?.execute?.(1, { query: "unique-test-url-not-wrapped" });
|
const result = await tool?.execute?.("call-1", { query: "unique-test-url-not-wrapped" });
|
||||||
const details = result?.details as { results?: Array<{ url?: string }> };
|
const details = result?.details as { results?: Array<{ url?: string }> };
|
||||||
|
|
||||||
// URL should NOT be wrapped - kept raw for tool chaining (e.g., web_fetch)
|
// URL should NOT be wrapped - kept raw for tool chaining (e.g., web_fetch)
|
||||||
@@ -306,11 +300,10 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
// @ts-expect-error mock fetch
|
|
||||||
global.fetch = mockFetch;
|
global.fetch = mockFetch;
|
||||||
|
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
const result = await tool?.execute?.(1, { query: "unique-test-site-name-wrapping" });
|
const result = await tool?.execute?.("call-1", { query: "unique-test-site-name-wrapping" });
|
||||||
const details = result?.details as { results?: Array<{ siteName?: string }> };
|
const details = result?.details as { results?: Array<{ siteName?: string }> };
|
||||||
|
|
||||||
expect(details.results?.[0]?.siteName).toBe("example.com");
|
expect(details.results?.[0]?.siteName).toBe("example.com");
|
||||||
@@ -337,11 +330,12 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
// @ts-expect-error mock fetch
|
|
||||||
global.fetch = mockFetch;
|
global.fetch = mockFetch;
|
||||||
|
|
||||||
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
const tool = createWebSearchTool({ config: undefined, sandboxed: true });
|
||||||
const result = await tool?.execute?.(1, { query: "unique-test-brave-published-wrapping" });
|
const result = await tool?.execute?.("call-1", {
|
||||||
|
query: "unique-test-brave-published-wrapping",
|
||||||
|
});
|
||||||
const details = result?.details as { results?: Array<{ published?: string }> };
|
const details = result?.details as { results?: Array<{ published?: string }> };
|
||||||
|
|
||||||
expect(details.results?.[0]?.published).toBe("2 days ago");
|
expect(details.results?.[0]?.published).toBe("2 days ago");
|
||||||
@@ -360,14 +354,13 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
// @ts-expect-error mock fetch
|
|
||||||
global.fetch = mockFetch;
|
global.fetch = mockFetch;
|
||||||
|
|
||||||
const tool = createWebSearchTool({
|
const tool = createWebSearchTool({
|
||||||
config: { tools: { web: { search: { provider: "perplexity" } } } },
|
config: { tools: { web: { search: { provider: "perplexity" } } } },
|
||||||
sandboxed: true,
|
sandboxed: true,
|
||||||
});
|
});
|
||||||
const result = await tool?.execute?.(1, { query: "test" });
|
const result = await tool?.execute?.("call-1", { query: "test" });
|
||||||
const details = result?.details as { content?: string };
|
const details = result?.details as { content?: string };
|
||||||
|
|
||||||
expect(details.content).toContain("<<<EXTERNAL_UNTRUSTED_CONTENT>>>");
|
expect(details.content).toContain("<<<EXTERNAL_UNTRUSTED_CONTENT>>>");
|
||||||
@@ -377,7 +370,7 @@ describe("web_search external content wrapping", () => {
|
|||||||
it("does not wrap Perplexity citations (raw for tool chaining)", async () => {
|
it("does not wrap Perplexity citations (raw for tool chaining)", async () => {
|
||||||
vi.stubEnv("PERPLEXITY_API_KEY", "pplx-test");
|
vi.stubEnv("PERPLEXITY_API_KEY", "pplx-test");
|
||||||
const citation = "https://example.com/some-article";
|
const citation = "https://example.com/some-article";
|
||||||
const mockFetch = vi.fn(() =>
|
const mockFetch = vi.fn((_input?: unknown, _init?: unknown) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
ok: true,
|
ok: true,
|
||||||
json: () =>
|
json: () =>
|
||||||
@@ -387,14 +380,15 @@ describe("web_search external content wrapping", () => {
|
|||||||
}),
|
}),
|
||||||
} as Response),
|
} as Response),
|
||||||
);
|
);
|
||||||
// @ts-expect-error mock fetch
|
|
||||||
global.fetch = mockFetch;
|
global.fetch = mockFetch;
|
||||||
|
|
||||||
const tool = createWebSearchTool({
|
const tool = createWebSearchTool({
|
||||||
config: { tools: { web: { search: { provider: "perplexity" } } } },
|
config: { tools: { web: { search: { provider: "perplexity" } } } },
|
||||||
sandboxed: true,
|
sandboxed: true,
|
||||||
});
|
});
|
||||||
const result = await tool?.execute?.(1, { query: "unique-test-perplexity-citations-raw" });
|
const result = await tool?.execute?.("call-1", {
|
||||||
|
query: "unique-test-perplexity-citations-raw",
|
||||||
|
});
|
||||||
const details = result?.details as { citations?: string[] };
|
const details = result?.details as { citations?: string[] };
|
||||||
|
|
||||||
// Citations are URLs - should NOT be wrapped for tool chaining
|
// Citations are URLs - should NOT be wrapped for tool chaining
|
||||||
|
|||||||
Reference in New Issue
Block a user