
















@@ -12,6 +12,11 @@ import { startGatewayServer } from "../src/gateway/server.js";
12121313type Lane = "normal" | "code";
141415+type FetchJsonOptions = {
16+fetchImpl?: (url: string, init: RequestInit) => Promise<Response>;
17+timeoutMs?: number;
18+};
19+1520type LaneResult = {
1621lane: Lane;
1722status: string;
@@ -26,13 +31,26 @@ type LaneResult = {
2631};
27322833const FAKE_PLUGIN_ID = "tool-search-e2e-fixture";
34+const DEFAULT_FETCH_TIMEOUT_MS = readPositiveInt(
35+process.env.OPENCLAW_TOOL_SEARCH_GATEWAY_E2E_FETCH_TIMEOUT_MS,
36+180_000,
37+);
29383039function assert(condition: unknown, message: string): asserts condition {
3140if (!condition) {
3241throw new Error(message);
3342}
3443}
354445+function readPositiveInt(raw: string | undefined, fallback: number) {
46+const parsed = Number.parseInt(raw ?? "", 10);
47+return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
48+}
49+50+function timeoutError(message: string) {
51+return Object.assign(new Error(message), { code: "ETIMEDOUT" });
52+}
53+3654async function freePort(): Promise<number> {
3755return await new Promise((resolve, reject) => {
3856const server = net.createServer();
@@ -111,9 +129,39 @@ async function readSessionLogMentions(params: {
111129return mentions;
112130}
113131114-async function fetchJson(url: string, init?: RequestInit): Promise<unknown> {
115-const response = await fetch(url, init);
116-const text = await response.text();
132+export async function fetchJson(
133+url: string,
134+init: RequestInit = {},
135+options: FetchJsonOptions = {},
136+): Promise<unknown> {
137+const timeoutMs = Math.max(1, options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS);
138+const controller = new AbortController();
139+const error = timeoutError(`HTTP request to ${url} timed out after ${timeoutMs}ms`);
140+let timeout: NodeJS.Timeout | undefined;
141+const timeoutPromise = new Promise<never>((_, reject) => {
142+timeout = setTimeout(() => {
143+controller.abort(error);
144+reject(error);
145+}, timeoutMs);
146+timeout.unref?.();
147+});
148+149+let response: Response;
150+let text: string;
151+try {
152+response = await Promise.race([
153+(options.fetchImpl ?? fetch)(url, {
154+ ...init,
155+signal: controller.signal,
156+}),
157+timeoutPromise,
158+]);
159+text = await Promise.race([response.text(), timeoutPromise]);
160+} finally {
161+if (timeout) {
162+clearTimeout(timeout);
163+}
164+}
117165let parsed: unknown;
118166try {
119167parsed = text ? JSON.parse(text) : {};
@@ -213,6 +261,38 @@ async function writeConfig(params: {
213261controlUiEnabled: false,
214262providerMode: "mock-openai",
215263});
264+const defaults = cfg.agents?.defaults ?? {};
265+cfg = {
266+ ...cfg,
267+plugins: {
268+allow: [FAKE_PLUGIN_ID],
269+slots: {
270+ ...cfg.plugins?.slots,
271+memory: "none",
272+},
273+entries: {
274+[FAKE_PLUGIN_ID]: {
275+enabled: true,
276+},
277+},
278+},
279+agents: {
280+ ...cfg.agents,
281+defaults: {
282+ ...defaults,
283+memorySearch: {
284+ ...defaults.memorySearch,
285+enabled: false,
286+sync: {
287+ ...defaults.memorySearch?.sync,
288+onSearch: false,
289+onSessionStart: false,
290+watch: false,
291+},
292+},
293+},
294+},
295+};
216296cfg = {
217297 ...cfg,
218298tools: {
@@ -472,17 +552,18 @@ async function runLane(params: {
472552}
473553}
474554475-async function main() {
555+export async function main() {
476556const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-tool-search-"));
477-const provider = await startQaMockOpenAiServer();
478-const fakeTools = buildFakeTools();
479-const fakePluginDir = await writeFakePlugin({
480- rootDir,
481-repoRoot: process.cwd(),
482- fakeTools,
483-});
484-const targetTool = "fake_plugin_tool_17";
557+let provider: Awaited<ReturnType<typeof startQaMockOpenAiServer>> | undefined;
485558try {
559+provider = await startQaMockOpenAiServer();
560+const fakeTools = buildFakeTools();
561+const fakePluginDir = await writeFakePlugin({
562+ rootDir,
563+repoRoot: process.cwd(),
564+ fakeTools,
565+});
566+const targetTool = "fake_plugin_tool_17";
486567const normal = await runLane({
487568lane: "normal",
488569 rootDir,
@@ -541,8 +622,11 @@ async function main() {
541622};
542623process.stdout.write(`${JSON.stringify(summary, null, 2)}\n`);
543624} finally {
544-await provider.stop();
625+await provider?.stop();
626+await fs.rm(rootDir, { force: true, recursive: true });
545627}
546628}
547629548-await main();
630+if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
631+await main();
632+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。