diff --git a/scripts/e2e/lib/openai-web-search-minimal/client.mjs b/scripts/e2e/lib/openai-web-search-minimal/client.mjs index 5455e1ce0b3..63907204540 100644 --- a/scripts/e2e/lib/openai-web-search-minimal/client.mjs +++ b/scripts/e2e/lib/openai-web-search-minimal/client.mjs @@ -14,22 +14,22 @@ async function loadCallGateway() { throw new Error(`unable to find callGateway export in /app/dist (${candidates.join(", ")})`); } -const callGateway = await loadCallGateway(); +const DEFAULT_RAW_SCHEMA_ERROR = + "400 The following tools cannot be used with reasoning.effort 'minimal': web_search."; -const port = process.env.PORT; -const token = process.env.OPENCLAW_GATEWAY_TOKEN; -const mode = process.argv[2]; -const sessionKey = `agent:main:openai-web-search-minimal:${mode}`; -const message = - mode === "reject" ? "FORCE_SCHEMA_REJECT" : "Return exactly OPENCLAW_SCHEMA_E2E_OK."; -const id = mode === "reject" ? "schema-reject" : "schema-success"; - -if (!port || !token) { - throw new Error("missing PORT/OPENCLAW_GATEWAY_TOKEN"); +function readExpectedRawSchemaError() { + return process.env.RAW_SCHEMA_ERROR?.trim() || DEFAULT_RAW_SCHEMA_ERROR; } async function gatewayAgent(params) { + const port = process.env.PORT; + const token = process.env.OPENCLAW_GATEWAY_TOKEN; + if (!port || !token) { + throw new Error("missing PORT/OPENCLAW_GATEWAY_TOKEN"); + } + try { + const callGateway = await loadCallGateway(); return { ok: true, value: await callGateway({ @@ -51,24 +51,51 @@ async function gatewayAgent(params) { } } -const result = await gatewayAgent({ - sessionKey, - message, - thinking: "minimal", - deliver: false, - timeout: 180, - idempotencyKey: id, -}); +function stringifyError(value) { + return value instanceof Error ? value.message || String(value) : String(value); +} -if (mode === "reject") { - console.error(result.ok ? JSON.stringify(result.value) : String(result.error)); - process.exit(0); +function validateRejectResult(result, expectedRawSchemaError = readExpectedRawSchemaError()) { + if (result.ok) { + throw new Error(`reject mode unexpectedly completed: ${JSON.stringify(result.value)}`); + } + const errorText = stringifyError(result.error); + if (!errorText.includes(expectedRawSchemaError)) { + throw new Error( + `reject mode failed for an unexpected reason; expected ${JSON.stringify( + expectedRawSchemaError, + )} in ${JSON.stringify(errorText)}`, + ); + } + return errorText; } -if (!result.ok) { - throw toLintErrorObject(result.error, "Non-Error thrown"); -} -if (result.value?.status !== "ok") { - throw new Error(`agent run did not complete successfully: ${JSON.stringify(result.value)}`); + +async function main() { + const mode = process.argv[2]; + const sessionKey = `agent:main:openai-web-search-minimal:${mode}`; + const message = + mode === "reject" ? "FORCE_SCHEMA_REJECT" : "Return exactly OPENCLAW_SCHEMA_E2E_OK."; + const id = mode === "reject" ? "schema-reject" : "schema-success"; + + const result = await gatewayAgent({ + sessionKey, + message, + thinking: "minimal", + deliver: false, + timeout: 180, + idempotencyKey: id, + }); + + if (mode === "reject") { + console.error(validateRejectResult(result)); + return; + } + if (!result.ok) { + throw toLintErrorObject(result.error, "Non-Error thrown"); + } + if (result.value?.status !== "ok") { + throw new Error(`agent run did not complete successfully: ${JSON.stringify(result.value)}`); + } } function toLintErrorObject(value, fallbackMessage) { @@ -84,3 +111,17 @@ function toLintErrorObject(value, fallbackMessage) { } return error; } + +if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) { + try { + await main(); + } catch (error) { + console.error(error instanceof Error ? error.stack || error.message : String(error)); + process.exit(1); + } +} + +export const testing = { + DEFAULT_RAW_SCHEMA_ERROR, + validateRejectResult, +}; diff --git a/test/scripts/openai-web-search-minimal-client.test.ts b/test/scripts/openai-web-search-minimal-client.test.ts new file mode 100644 index 00000000000..9b974e2b8a5 --- /dev/null +++ b/test/scripts/openai-web-search-minimal-client.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from "vitest"; +import { testing } from "../../scripts/e2e/lib/openai-web-search-minimal/client.mjs"; + +describe("scripts/e2e/lib/openai-web-search-minimal/client.mjs", () => { + it("accepts only the expected raw schema rejection in reject mode", () => { + expect( + testing.validateRejectResult({ + ok: false, + error: new Error(`gateway failed: ${testing.DEFAULT_RAW_SCHEMA_ERROR}`), + }), + ).toContain(testing.DEFAULT_RAW_SCHEMA_ERROR); + }); + + it("fails reject mode when the agent run unexpectedly succeeds", () => { + expect(() => + testing.validateRejectResult({ + ok: true, + value: { status: "ok" }, + }), + ).toThrow(/reject mode unexpectedly completed/u); + }); + + it("fails reject mode on unrelated transport errors", () => { + expect(() => + testing.validateRejectResult({ + ok: false, + error: new Error("connect ECONNREFUSED 127.0.0.1:9"), + }), + ).toThrow(/reject mode failed for an unexpected reason/u); + }); +});