/** * Every module's runtime answers `tools` for it (novox/hq ADR 0152, design 34 ยง3): the names, * descriptions and schemas from the code that answers them. Against a real bus, because the claim is * what a second connection gets back. * * docker run -d --rm --name t -p 14232:4222 nats:2.10-alpine -js * MESH_TEST_NATS=nats://127.0.0.1:14232 node --test --experimental-strip-types test/runtime-tools.test.ts */ import assert from "node:assert/strict"; import { test } from "node:test"; import { fileURLToPath } from "node:url"; import { resetTools } from "@novox/mesh-sdk/tools"; import { connectNats } from "../dist/broker-nats.js"; import { runTools } from "../dist/runtime.js"; const url = process.env.MESH_TEST_NATS; const fixture = (name: string) => fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)); test("a module registering two tools answers three names, the third being what it serves", async (t) => { if (!url) return t.skip("MESH_TEST_NATS unset"); resetTools(); const shop = await connectNats({ url, node: "one", module: "shop" }); const asker = await connectNats({ url, module: "person.ada" }); const stop = await runTools({ broker: shop, moduleEntrypoints: [fixture("shop-tools.mjs")] }); try { const answer = await asker.request, { module: string; tools: { name: string; input: unknown }[] }>( "shop.tools", {}, ); assert.equal(answer.module, "shop"); assert.deepEqual(answer.tools.map((x) => x.name), ["price", "refund"]); // The schema travels with the name: a name alone is not callable by something that has never // seen the mesh before. assert.deepEqual(answer.tools[0].input, { of: { type: "string", description: "the thing" } }); // And the tools themselves still answer beside it. const priced = await asker.request<{ of: string }, { cost: number }>("shop.price", { of: "a hat" }); assert.equal(priced.cost, 12); } finally { stop(); await asker.close(); await shop.close(); } }); test("a module naming a tool of its own `tools` is refused at load", async (t) => { if (!url) return t.skip("MESH_TEST_NATS unset"); resetTools(); const clash = await connectNats({ url, node: "one", module: "clash" }); try { await assert.rejects( () => runTools({ broker: clash, moduleEntrypoints: [fixture("clash-tools.mjs")] }), /names a tool "tools"/, ); } finally { resetTools(); await clash.close(); } });