import { randomBytes } from "node:crypto";import { createServer } from "node:http"; import { expect } from "@effect/vitest";import { Effect } from "effect";import { composePluginApi } from "@executor-js/api/server";import { openApiHttpPlugin } from "@executor-js/plugin-openapi/api";import { AuthTemplateSlug, ConnectionName, IntegrationSlug } from "@executor-js/sdk/shared"; import { scenario } from "../src/scenario";import { Api, Target } from "../src/services"; const api = composePluginApi([openApiHttpPlugin()] as const); const serveRecordingUpstream = () => Effect.acquireRelease( Effect.callback<{ readonly url: string; readonly requests: () => readonly string[]; readonly close: () => void; }>((resume) => { const recorded: string[] = []; const server = createServer((request, response) => { recorded.push(request.url ?? ""); response.writeHead(200, { "content-type": "application/json" }); response.end(JSON.stringify({ id: "2", name: "Gadget" })); }); server.listen(0, "127.0.0.1", () => { const address = server.address(); const port = typeof address === "object" && address ? address.port : 0; resume( Effect.succeed({ url: `http://127.0.0.1:${port}`, requests: () => [...recorded], close: () => { server.close(); server.closeAllConnections(); }, }), ); }); }), (server) => Effect.sync(server.close), ); const itemsSpec = (baseUrl: string): string => JSON.stringify({ openapi: "3.0.3", info: { title: "Items API", version: "1.0.0" }, servers: [{ url: baseUrl }], paths: { "/items/{itemId}": { get: { operationId: "getItem", summary: "Fetch one item", parameters: [{ name: "itemId", in: "path", required: true, schema: { type: "string" } }], responses: { "200": { description: "the item" } }, }, }, }, }); const invokeByAddressCode = (address: string, args: unknown) => `const segments = ${JSON.stringify(address)}.split(".").slice(1);let node = tools;for (const segment of segments) node = node[segment];const result = await node(${JSON.stringify(args)});return JSON.stringify(result);`; type ToolEnvelope = { readonly ok: boolean; readonly error?: { readonly code?: string; readonly message?: string; };}; scenario( "OpenAPI: unknown tool arguments fail locally before any upstream request", {}, Effect.scoped( Effect.gen(function* () { const target = yield* Target; const { client: makeClient } = yield* Api; const identity = yield* target.newIdentity(); const client = yield* makeClient(api, identity); const upstream = yield* serveRecordingUpstream(); const slug = `openapi_unknown_args_${randomBytes(4).toString("hex")}`; yield* Effect.ensuring( Effect.gen(function* () { yield* client.openapi.addSpec({ payload: { spec: { kind: "blob", value: itemsSpec(upstream.url) }, slug, baseUrl: upstream.url, authenticationTemplate: [ { slug: "apiKey", type: "apiKey", headers: { authorization: ["Bearer ", { type: "variable", name: "token" }] }, }, ], }, }); yield* client.connections.create({ payload: { owner: "org", name: ConnectionName.make("main"), integration: IntegrationSlug.make(slug), template: AuthTemplateSlug.make("apiKey"), value: "tok_unknown_args", }, }); const tools = yield* client.tools.list({ query: {} }); const address = tools .filter((tool) => String(tool.integration) === slug) .map((tool) => String(tool.address)) .find((candidate) => candidate.endsWith("getItem")); expect(address, "the getItem operation is available").toBeDefined(); const executed = yield* client.executions.execute({ payload: { code: invokeByAddressCode(address!, { itemId: "2", doesNotExist: "nope" }), autoApprove: true, }, }); expect(executed.status, "the sandbox returns the tool failure as a value").toBe( "completed", ); const outcome = JSON.parse(executed.text) as ToolEnvelope; expect(outcome.ok, "the unknown argument fails the tool call").toBe(false); expect(outcome.error?.code, "the failure is classified as invalid arguments").toBe( "invalid_tool_arguments", ); expect( outcome.error?.message, "the failure names the argument the caller must remove", ).toContain("doesNotExist"); expect( upstream.requests(), "argument validation stops the call before upstream dispatch", ).toEqual([]); }), Effect.gen(function* () { yield* client.connections .remove({ params: { owner: "org", integration: IntegrationSlug.make(slug), name: ConnectionName.make("main"), }, }) .pipe(Effect.ignore); yield* client.openapi.removeSpec({ params: { slug } }).pipe(Effect.ignore); }), ); }), ),);
import { randomBytes } from "node:crypto";
import { createServer } from "node:http";
import { expect } from "@effect/vitest";
import { Effect } from "effect";
import { composePluginApi } from "@executor-js/api/server";
import { openApiHttpPlugin } from "@executor-js/plugin-openapi/api";
import { AuthTemplateSlug, ConnectionName, IntegrationSlug } from "@executor-js/sdk/shared";
import { scenario } from "../src/scenario";
import { Api, Target } from "../src/services";
const api = composePluginApi([openApiHttpPlugin()] as const);
const serveRecordingUpstream = () =>
Effect.acquireRelease(
Effect.callback<{
readonly url: string;
readonly requests: () => readonly string[];
readonly close: () => void;
}>((resume) => {
const recorded: string[] = [];
const server = createServer((request, response) => {
recorded.push(request.url ?? "");
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify({ id: "2", name: "Gadget" }));
});
server.listen(0, "127.0.0.1", () => {
const address = server.address();
const port = typeof address === "object" && address ? address.port : 0;
resume(
Effect.succeed({
url: `http://127.0.0.1:${port}`,
requests: () => [...recorded],
close: () => {
server.close();
server.closeAllConnections();
},
}),
);
});
}),
(server) => Effect.sync(server.close),
);
const itemsSpec = (baseUrl: string): string =>
JSON.stringify({
openapi: "3.0.3",
info: { title: "Items API", version: "1.0.0" },
servers: [{ url: baseUrl }],
paths: {
"/items/{itemId}": {
get: {
operationId: "getItem",
summary: "Fetch one item",
parameters: [{ name: "itemId", in: "path", required: true, schema: { type: "string" } }],
responses: { "200": { description: "the item" } },
},
},
},
});
const invokeByAddressCode = (address: string, args: unknown) => `
const segments = ${JSON.stringify(address)}.split(".").slice(1);
let node = tools;
for (const segment of segments) node = node[segment];
const result = await node(${JSON.stringify(args)});
return JSON.stringify(result);
`;
type ToolEnvelope = {
readonly ok: boolean;
readonly error?: {
readonly code?: string;
readonly message?: string;
};
};
scenario(
"OpenAPI: unknown tool arguments fail locally before any upstream request",
{},
Effect.scoped(
Effect.gen(function* () {
const target = yield* Target;
const { client: makeClient } = yield* Api;
const identity = yield* target.newIdentity();
const client = yield* makeClient(api, identity);
const upstream = yield* serveRecordingUpstream();
const slug = `openapi_unknown_args_${randomBytes(4).toString("hex")}`;
yield* Effect.ensuring(
Effect.gen(function* () {
yield* client.openapi.addSpec({
payload: {
spec: { kind: "blob", value: itemsSpec(upstream.url) },
slug,
baseUrl: upstream.url,
authenticationTemplate: [
{
slug: "apiKey",
type: "apiKey",
headers: { authorization: ["Bearer ", { type: "variable", name: "token" }] },
},
],
},
});
yield* client.connections.create({
payload: {
owner: "org",
name: ConnectionName.make("main"),
integration: IntegrationSlug.make(slug),
template: AuthTemplateSlug.make("apiKey"),
value: "tok_unknown_args",
},
});
const tools = yield* client.tools.list({ query: {} });
const address = tools
.filter((tool) => String(tool.integration) === slug)
.map((tool) => String(tool.address))
.find((candidate) => candidate.endsWith("getItem"));
expect(address, "the getItem operation is available").toBeDefined();
const executed = yield* client.executions.execute({
payload: {
code: invokeByAddressCode(address!, { itemId: "2", doesNotExist: "nope" }),
autoApprove: true,
},
});
expect(executed.status, "the sandbox returns the tool failure as a value").toBe(
"completed",
);
const outcome = JSON.parse(executed.text) as ToolEnvelope;
expect(outcome.ok, "the unknown argument fails the tool call").toBe(false);
expect(outcome.error?.code, "the failure is classified as invalid arguments").toBe(
"invalid_tool_arguments",
);
expect(
outcome.error?.message,
"the failure names the argument the caller must remove",
).toContain("doesNotExist");
expect(
upstream.requests(),
"argument validation stops the call before upstream dispatch",
).toEqual([]);
}),
Effect.gen(function* () {
yield* client.connections
.remove({
params: {
owner: "org",
integration: IntegrationSlug.make(slug),
name: ConnectionName.make("main"),
},
})
.pipe(Effect.ignore);
yield* client.openapi.removeSpec({ params: { slug } }).pipe(Effect.ignore);
}),
);
}),
),
);