121 lines · 4.3 KB · TypeScript
RawDownload
// ---------------------------------------------------------------------------// Tool-row projection coverage. The invoke and list hot paths select away the// heavy input_schema/output_schema JSON (TOOL_INVOCATION_COLUMNS) — a tool row// is ~KBs of schemas, but routing/policy needs only the names. These tests pin// the contract through a real dynamic integration://   - tools.list returns metadata without the schemas,//   - invoke works end-to-end off the projected row,//   - tools.schema (describe) still serves the full schemas.// --------------------------------------------------------------------------- import { describe, expect, it } from "@effect/vitest";import { Effect, Schema } from "effect";import { FetchHttpClient, HttpServerRequest } from "effect/unstable/http";import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi"; import {  createExecutor,  AuthTemplateSlug,  ConnectionName,  IntegrationSlug,  ToolAddress,} from "@executor-js/sdk";import { makeTestConfig, memoryCredentialsPlugin } from "@executor-js/sdk/testing";import { variable } from "@executor-js/sdk/http-auth"; import { openApiPlugin } from "./plugin";import { serveOpenApiHttpApiTestServer, unwrapInvocation } from "../testing"; const testPlugins = (httpClientLayer = FetchHttpClient.layer) =>  [openApiPlugin({ httpClientLayer }), memoryCredentialsPlugin()] as const; const EchoHeaders = Schema.Struct({  "x-api-key": Schema.optional(Schema.String),}); const EchoGroup = HttpApiGroup.make("items").add(  HttpApiEndpoint.get("echoHeaders", "/echo-headers", { success: EchoHeaders }),);const TestApi = HttpApi.make("testApi").add(EchoGroup); const EchoGroupLive = HttpApiBuilder.group(TestApi, "items", (handlers) =>  handlers.handle("echoHeaders", () =>    Effect.gen(function* () {      const req = yield* HttpServerRequest.HttpServerRequest;      return EchoHeaders.make({ "x-api-key": req.headers["x-api-key"] });    }),  ),); const apiKeyTemplate = {  slug: AuthTemplateSlug.make("apiKey"),  type: "apiKey" as const,  headers: { "x-api-key": [variable("token")] },}; const setup = Effect.gen(function* () {  const server = yield* serveOpenApiHttpApiTestServer({    api: TestApi,    handlersLayer: EchoGroupLive,  });  const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));  yield* executor.openapi.addSpec({    spec: { kind: "blob", value: server.specJson },    slug: "proj_api",    baseUrl: server.baseUrl,    authenticationTemplate: [apiKeyTemplate],  });  yield* executor.connections.create({    owner: "org",    name: ConnectionName.make("main"),    integration: IntegrationSlug.make("proj_api"),    template: AuthTemplateSlug.make("apiKey"),    value: "secret-key-123",  });  return executor;}); const TOOL_ADDRESS = ToolAddress.make("tools.proj_api.org.main.items.echoHeaders"); describe("tool-row projection on hot paths", () => {  it.effect("tools.list returns metadata without loading the schema columns", () =>    Effect.scoped(      Effect.gen(function* () {        const executor = yield* setup;        const tools = yield* executor.tools.list({          integration: IntegrationSlug.make("proj_api"),        });        const tool = tools.find((entry) => entry.address === TOOL_ADDRESS);        expect(tool).toBeDefined();        expect(tool!.description.length).toBeGreaterThan(0);        // The list surface is metadata-only: the projected query never loads        // input/output schema JSON, so the Tool carries none.        expect(tool!.inputSchema).toBeUndefined();        expect(tool!.outputSchema).toBeUndefined();      }),    ),  );   it.effect("invoke routes and executes off the projected row", () =>    Effect.scoped(      Effect.gen(function* () {        const executor = yield* setup;        const result = unwrapInvocation(yield* executor.execute(TOOL_ADDRESS, {})).data as {          "x-api-key"?: string;        };        expect(result["x-api-key"]).toBe("secret-key-123");      }),    ),  );   it.effect("tools.schema still serves the full schemas", () =>    Effect.scoped(      Effect.gen(function* () {        const executor = yield* setup;        const schema = yield* executor.tools.schema(TOOL_ADDRESS);        expect(schema).not.toBeNull();        expect(schema!.outputSchema).toBeDefined();      }),    ),  );});