runtime: RPC replies ride mesh.rpc; an invoke subcommand (ADR 0052)

Replies go through the RPC exchange keyed by the caller's reply-queue name, not
the default exchange — so a serving module's scoped account answers with write
on mesh.rpc alone, never the default exchange (which would let it publish into
any queue). 'mesh-tools invoke <module> <tool> [args]' is the caller's side, the
sibling of emit. Verified against a real broker: a scoped account serves its
tool and is refused another module's serve queue.
This commit is contained in:
2026-09-04 21:56:04 +02:00
parent bf5339cec2
commit 4558248f16
3 changed files with 37 additions and 10 deletions
+4 -9
View File
@@ -1,7 +1,7 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { registerModuleTools, resetTools } from "@novox/mesh-sdk/tools";
import { registerModuleTools, resetTools, invokeTool } from "@novox/mesh-sdk/tools";
import { connectAmqp } from "../dist/broker-amqp.js";
import { runTools } from "../dist/runtime.js";
@@ -27,17 +27,12 @@ test("a module's tool serves and is invoked over a real AMQP broker", { skip: !u
const serverBroker = await connectAmqp(url!);
const stop = await runTools({ broker: serverBroker, moduleEntrypoints: [] });
// A separate connection — a caller, like mesh-control's command API — invokes over the broker.
// A separate connection — a caller, like mesh-control's command API — invokes over the broker,
// by module and tool (novox/hq ADR 0052: served on serve.demo.greet, invoked as demo.greet).
const caller = await connectAmqp(url!);
const result = await caller.request<{ tool: string; args: Record<string, unknown> }, { hello: string }>(
"tools.invoke",
{ tool: "greet", args: { who: "mesh" } },
);
const result = (await invokeTool(caller, "demo", "greet", { who: "mesh" })) as { hello: string };
assert.equal(result.hello, "mesh");
// An unknown tool is refused over the wire, not silently dropped.
await assert.rejects(caller.request("tools.invoke", { tool: "nope", args: {} }), /no such tool/);
stop();
await caller.close();
await serverBroker.close();