@mcpmesh/sdk 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=jobs.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/jobs.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,445 @@
1
+ /**
2
+ * Tests for `mesh.jobs.postEvent` + the napi-bound `recvEvent` /
3
+ * `sendEvent` plumbing (MeshJob event-injection — TS port of Python's
4
+ * PR #1041, issue #1032).
5
+ *
6
+ * Strategy:
7
+ * - Mock `@mcpmesh/core` so we can drive the napi-rs surface (`JobController`,
8
+ * `JobProxy`) without binding to a real registry. The mock mirrors the
9
+ * napi-rs generated TS surface (`recvEvent` / `sendEvent` etc.).
10
+ * - Exercise the wrappers' public contracts: type filter, timeout
11
+ * validation, typed-error re-classification, LRU cache eviction,
12
+ * registry-URL resolution.
13
+ * - LRU cap is overridden via `MCP_MESH_JOBPROXY_CACHE_MAX=2` in the
14
+ * cache test so eviction is reproducible at small scale.
15
+ */
16
+ import { describe, it, expect, vi, beforeEach } from "vitest";
17
+ // Mock napi-rs core so we don't need a real registry. The shapes match
18
+ // the generated `index.d.ts` `JobController` / `JobProxy` classes plus
19
+ // the new `recvEvent` / `sendEvent` methods added in this PR.
20
+ vi.mock("@mcpmesh/core", async () => {
21
+ const actual = await vi.importActual("@mcpmesh/core");
22
+ // Track constructed JobProxy instances per call so postEvent-cache
23
+ // tests can assert how many distinct proxies were built.
24
+ const proxyCalls = [];
25
+ const sendEventMock = vi.fn();
26
+ const listEventsMock = vi.fn();
27
+ class JobProxy {
28
+ jobId;
29
+ registryUrl;
30
+ sendEvent;
31
+ listEvents;
32
+ constructor(jobId, registryUrl) {
33
+ this.jobId = jobId;
34
+ this.registryUrl = registryUrl;
35
+ this.sendEvent = sendEventMock;
36
+ this.listEvents = listEventsMock;
37
+ proxyCalls.push({ jobId, registryUrl });
38
+ }
39
+ }
40
+ const recvEventMock = vi.fn();
41
+ class JobController {
42
+ jobId;
43
+ recvEvent;
44
+ constructor(jobId, _instanceId, _registryUrl) {
45
+ this.jobId = jobId;
46
+ this.recvEvent = recvEventMock;
47
+ }
48
+ }
49
+ return {
50
+ ...actual,
51
+ JobController,
52
+ JobProxy,
53
+ // Expose the per-test mocks + ctor recorder via the module namespace
54
+ // so the tests can reach for them.
55
+ __sendEventMock: sendEventMock,
56
+ __recvEventMock: recvEventMock,
57
+ __listEventsMock: listEventsMock,
58
+ __proxyCalls: proxyCalls,
59
+ };
60
+ });
61
+ import { postEvent, subscribeEvents, _getOrCreateProxy, _clearProxyCache, translateJobError, JobNotFoundError, JobTerminalError, } from "../jobs.js";
62
+ // Pull the mocks from the mocked module so test bodies can drive return
63
+ // values + read call counts.
64
+ const core = (await import("@mcpmesh/core"));
65
+ const sendEventMock = core.__sendEventMock;
66
+ const recvEventMock = core.__recvEventMock;
67
+ const listEventsMock = core.__listEventsMock;
68
+ const proxyCalls = core.__proxyCalls;
69
+ beforeEach(() => {
70
+ sendEventMock.mockReset();
71
+ recvEventMock.mockReset();
72
+ listEventsMock.mockReset();
73
+ proxyCalls.length = 0;
74
+ _clearProxyCache();
75
+ });
76
+ // ---------------------------------------------------------------------------
77
+ // translateJobError — substring → typed exception class
78
+ // ---------------------------------------------------------------------------
79
+ describe("translateJobError", () => {
80
+ it("re-classifies 'job is terminal' messages to JobTerminalError", () => {
81
+ const raw = new Error("job is terminal: completed at ts=...");
82
+ const out = translateJobError(raw);
83
+ expect(out).toBeInstanceOf(JobTerminalError);
84
+ expect(out.message).toContain("job is terminal");
85
+ });
86
+ it("re-classifies 'job not found' messages to JobNotFoundError", () => {
87
+ const raw = new Error("backend error: job not found: abc-123");
88
+ const out = translateJobError(raw);
89
+ expect(out).toBeInstanceOf(JobNotFoundError);
90
+ });
91
+ it("passes unrelated errors through unchanged", () => {
92
+ const raw = new Error("backend error: HTTP 500: boom");
93
+ expect(translateJobError(raw)).toBe(raw);
94
+ });
95
+ it("leaves typed exception subclasses alone", () => {
96
+ const already = new JobNotFoundError("nope");
97
+ expect(translateJobError(already)).toBe(already);
98
+ });
99
+ });
100
+ // ---------------------------------------------------------------------------
101
+ // JobController.recvEvent — invoked through the napi surface mock
102
+ // ---------------------------------------------------------------------------
103
+ describe("JobController.recvEvent (via napi mock)", () => {
104
+ it("returns the event object on backend success", async () => {
105
+ recvEventMock.mockResolvedValueOnce({
106
+ job_id: "j-1",
107
+ seq: 1,
108
+ type: "signal",
109
+ payload: { hello: "world" },
110
+ trace_context: null,
111
+ posted_by: "consumer-x",
112
+ created_at: 1_700_000_000,
113
+ });
114
+ const controller = new core.JobController("j-1", "inst-1", "http://r");
115
+ const ev = await controller.recvEvent(["signal"], 5);
116
+ expect(ev).toMatchObject({ type: "signal", seq: 1 });
117
+ expect(ev.payload.hello).toBe("world");
118
+ expect(recvEventMock).toHaveBeenCalledWith(["signal"], 5);
119
+ });
120
+ it("returns null on timeout", async () => {
121
+ recvEventMock.mockResolvedValueOnce(null);
122
+ const controller = new core.JobController("j-1", "inst-1", "http://r");
123
+ const ev = await controller.recvEvent(undefined, 0.1);
124
+ expect(ev).toBeNull();
125
+ });
126
+ it("forwards the types filter through unchanged", async () => {
127
+ recvEventMock.mockResolvedValueOnce(null);
128
+ const controller = new core.JobController("j-1", "inst-1", "http://r");
129
+ await controller.recvEvent(["target", "cancelled"], 1);
130
+ expect(recvEventMock).toHaveBeenCalledWith(["target", "cancelled"], 1);
131
+ });
132
+ // The actual NaN/Infinity/negative guard lives in the Rust binding
133
+ // (parse_timeout_secs in jobs_napi.rs), not in the TS wrapper — we
134
+ // simulate the boundary error here so callers can validate they get a
135
+ // catchable Error rather than a panic.
136
+ it("surfaces a guard error when timeoutSecs is invalid", async () => {
137
+ recvEventMock.mockRejectedValueOnce(new Error("timeoutSecs must be non-negative and finite, got NaN"));
138
+ const controller = new core.JobController("j-1", "inst-1", "http://r");
139
+ await expect(controller.recvEvent(undefined, NaN)).rejects.toThrow(/non-negative and finite/);
140
+ });
141
+ });
142
+ // ---------------------------------------------------------------------------
143
+ // postEvent — happy path + error mapping + cache behavior
144
+ // ---------------------------------------------------------------------------
145
+ describe("postEvent", () => {
146
+ beforeEach(() => {
147
+ // Explicit reset so each test starts from a known state — prevents
148
+ // pollution from the "unset" test below (which deletes the env var)
149
+ // bleeding into later additions or reordering.
150
+ delete process.env.MCP_MESH_REGISTRY_URL;
151
+ });
152
+ it("constructs a JobProxy from MCP_MESH_REGISTRY_URL + calls sendEvent", async () => {
153
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
154
+ sendEventMock.mockResolvedValueOnce({
155
+ job_id: "j-1",
156
+ seq: 1,
157
+ created_at: 1_700_000_000,
158
+ });
159
+ const receipt = await postEvent("j-1", "signal", { hello: "world" });
160
+ expect(receipt).toEqual({
161
+ job_id: "j-1",
162
+ seq: 1,
163
+ created_at: 1_700_000_000,
164
+ });
165
+ expect(proxyCalls).toHaveLength(1);
166
+ expect(proxyCalls[0]).toEqual({
167
+ jobId: "j-1",
168
+ registryUrl: "http://localhost:8000",
169
+ });
170
+ expect(sendEventMock).toHaveBeenCalledWith("signal", { hello: "world" });
171
+ });
172
+ it("normalises undefined/null payload to {}", async () => {
173
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
174
+ sendEventMock.mockResolvedValue({ job_id: "j", seq: 1, created_at: 1 });
175
+ await postEvent("j", "signal");
176
+ expect(sendEventMock).toHaveBeenLastCalledWith("signal", {});
177
+ await postEvent("j", "signal", null);
178
+ expect(sendEventMock).toHaveBeenLastCalledWith("signal", {});
179
+ });
180
+ it("re-classifies a 'job not found' napi error to JobNotFoundError", async () => {
181
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
182
+ sendEventMock.mockRejectedValueOnce(new Error("backend error: job not found: stale"));
183
+ await expect(postEvent("stale", "signal", {})).rejects.toBeInstanceOf(JobNotFoundError);
184
+ });
185
+ it("re-classifies a 'job is terminal' napi error to JobTerminalError", async () => {
186
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
187
+ sendEventMock.mockRejectedValueOnce(new Error("job is terminal: completed"));
188
+ await expect(postEvent("done", "signal", {})).rejects.toBeInstanceOf(JobTerminalError);
189
+ });
190
+ it("throws when MCP_MESH_REGISTRY_URL is unset", async () => {
191
+ delete process.env.MCP_MESH_REGISTRY_URL;
192
+ await expect(postEvent("j", "signal", {})).rejects.toThrow(/MCP_MESH_REGISTRY_URL is not set/);
193
+ });
194
+ it("caches the JobProxy per (registryUrl, jobId)", async () => {
195
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
196
+ sendEventMock.mockResolvedValue({ job_id: "j", seq: 1, created_at: 1 });
197
+ await postEvent("j-1", "signal", {});
198
+ await postEvent("j-1", "signal", {});
199
+ // Second call to same jobId must re-use the cached proxy.
200
+ expect(proxyCalls).toHaveLength(1);
201
+ // Different jobId constructs a fresh proxy.
202
+ await postEvent("j-2", "signal", {});
203
+ expect(proxyCalls).toHaveLength(2);
204
+ });
205
+ });
206
+ // ---------------------------------------------------------------------------
207
+ // LRU eviction — cap=2 via env override
208
+ // ---------------------------------------------------------------------------
209
+ describe("_getOrCreateProxy LRU eviction", () => {
210
+ it("evicts the least-recently-used entry when the cap is reached", () => {
211
+ process.env.MCP_MESH_JOBPROXY_CACHE_MAX = "2";
212
+ // Insert 3 distinct entries — after the third insert only the 2
213
+ // most recent ('b', 'c') should survive ('a' is evicted as LRU).
214
+ const p1 = _getOrCreateProxy("http://r", "a");
215
+ const p2 = _getOrCreateProxy("http://r", "b");
216
+ const p3 = _getOrCreateProxy("http://r", "c");
217
+ expect(proxyCalls).toHaveLength(3);
218
+ // Cache state at this point: { b, c }. 'c' is most-recent.
219
+ // 'b' and 'c' still cached — no new construction.
220
+ expect(_getOrCreateProxy("http://r", "b")).toBe(p2);
221
+ expect(_getOrCreateProxy("http://r", "c")).toBe(p3);
222
+ expect(proxyCalls).toHaveLength(3);
223
+ // Re-fetching 'a' constructs a NEW proxy (the original was evicted
224
+ // by the 'c' insert). proxyCalls grows; new ref differs from p1.
225
+ const p1b = _getOrCreateProxy("http://r", "a");
226
+ expect(proxyCalls).toHaveLength(4);
227
+ expect(p1b).not.toBe(p1);
228
+ delete process.env.MCP_MESH_JOBPROXY_CACHE_MAX;
229
+ });
230
+ it("bumps an entry to most-recent on hit (LRU semantics)", () => {
231
+ process.env.MCP_MESH_JOBPROXY_CACHE_MAX = "2";
232
+ const a1 = _getOrCreateProxy("http://r", "a");
233
+ const b1 = _getOrCreateProxy("http://r", "b");
234
+ // Touch 'a' so it becomes most-recent and 'b' becomes least-recent.
235
+ expect(_getOrCreateProxy("http://r", "a")).toBe(a1);
236
+ // Insert 'c' — should evict 'b' (the now-LRU), NOT 'a'.
237
+ _getOrCreateProxy("http://r", "c");
238
+ // 'a' is still cached.
239
+ expect(_getOrCreateProxy("http://r", "a")).toBe(a1);
240
+ // 'b' was evicted — re-fetching constructs a new instance.
241
+ const b2 = _getOrCreateProxy("http://r", "b");
242
+ expect(b2).not.toBe(b1);
243
+ delete process.env.MCP_MESH_JOBPROXY_CACHE_MAX;
244
+ });
245
+ });
246
+ // ---------------------------------------------------------------------------
247
+ // subscribeEvents — async iterator over listEvents
248
+ // ---------------------------------------------------------------------------
249
+ describe("subscribeEvents", () => {
250
+ beforeEach(() => {
251
+ delete process.env.MCP_MESH_REGISTRY_URL;
252
+ });
253
+ it("yields events from a non-empty page", async () => {
254
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
255
+ listEventsMock
256
+ .mockResolvedValueOnce({
257
+ events: [
258
+ {
259
+ job_id: "j-1",
260
+ seq: 1,
261
+ type: "work",
262
+ payload: { item: 1 },
263
+ trace_context: null,
264
+ posted_by: "consumer",
265
+ created_at: 1_700_000_000,
266
+ },
267
+ {
268
+ job_id: "j-1",
269
+ seq: 2,
270
+ type: "work",
271
+ payload: { item: 2 },
272
+ trace_context: null,
273
+ posted_by: "consumer",
274
+ created_at: 1_700_000_001,
275
+ },
276
+ ],
277
+ nextAfter: 2,
278
+ })
279
+ // Stop the iterator after the first batch — second call returns
280
+ // empty + same cursor so we can `break` after consuming the
281
+ // expected events.
282
+ .mockResolvedValue({ events: [], nextAfter: 2 });
283
+ const observed = [];
284
+ for await (const event of subscribeEvents("j-1", { types: ["work"] })) {
285
+ observed.push({ seq: event.seq, type: event.type });
286
+ if (observed.length >= 2)
287
+ break;
288
+ }
289
+ expect(observed).toEqual([
290
+ { seq: 1, type: "work" },
291
+ { seq: 2, type: "work" },
292
+ ]);
293
+ // First call: starts at cursor 0, with the supplied filter + default
294
+ // long-poll (30s). The binding-side `wait` is forwarded as a number.
295
+ expect(listEventsMock).toHaveBeenNthCalledWith(1, 0, ["work"], 30);
296
+ });
297
+ it("advances cursor from nextAfter on empty page (server-filtered range)", async () => {
298
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
299
+ listEventsMock
300
+ // Empty page (every event in the scanned range was filtered out)
301
+ // but registry returns a higher watermark — observer must resume
302
+ // from 42, not 0, on the next call.
303
+ .mockResolvedValueOnce({ events: [], nextAfter: 42 })
304
+ .mockResolvedValueOnce({
305
+ events: [
306
+ {
307
+ job_id: "j-1",
308
+ seq: 43,
309
+ type: "work",
310
+ payload: { item: 43 },
311
+ trace_context: null,
312
+ posted_by: null,
313
+ created_at: 1_700_000_000,
314
+ },
315
+ ],
316
+ nextAfter: 43,
317
+ })
318
+ .mockResolvedValue({ events: [], nextAfter: 43 });
319
+ const observed = [];
320
+ for await (const event of subscribeEvents("j-1", { types: ["work"] })) {
321
+ observed.push(event.seq);
322
+ break;
323
+ }
324
+ expect(observed).toEqual([43]);
325
+ // 2nd call must resume from cursor=42 (the watermark from the 1st
326
+ // empty-page response) — proof that empty-page cursor advance works.
327
+ expect(listEventsMock).toHaveBeenNthCalledWith(2, 42, ["work"], 30);
328
+ });
329
+ it("rejects an event whose seq is a boolean", async () => {
330
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
331
+ listEventsMock.mockResolvedValueOnce({
332
+ events: [
333
+ {
334
+ job_id: "j-1",
335
+ // Wire-level malformed — registry contract is integer seqs.
336
+ seq: true,
337
+ type: "work",
338
+ payload: {},
339
+ trace_context: null,
340
+ posted_by: null,
341
+ created_at: 1,
342
+ },
343
+ ],
344
+ nextAfter: 1,
345
+ });
346
+ const iter = subscribeEvents("j-1")[Symbol.asyncIterator]();
347
+ await expect(iter.next()).rejects.toThrow(/boolean 'seq'/);
348
+ });
349
+ it("rejects event without seq key", async () => {
350
+ // Mirror of Python's test_subscribe_events_raises_on_missing_seq:
351
+ // an event missing the integer `seq` key must surface as an Error
352
+ // BEFORE the event is yielded, with `'seq'` in the message so
353
+ // callers can identify the offending field.
354
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
355
+ listEventsMock.mockResolvedValueOnce({
356
+ events: [{ type: "work", payload: {} }],
357
+ nextAfter: 1n,
358
+ });
359
+ const iter = subscribeEvents("j-1")[Symbol.asyncIterator]();
360
+ await expect(iter.next()).rejects.toThrow(/'seq'/);
361
+ });
362
+ it("forwards longPollSecs=null to the binding verbatim", async () => {
363
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
364
+ listEventsMock.mockResolvedValueOnce({
365
+ events: [
366
+ {
367
+ job_id: "j-1",
368
+ seq: 1,
369
+ type: "work",
370
+ payload: {},
371
+ trace_context: null,
372
+ posted_by: null,
373
+ created_at: 1,
374
+ },
375
+ ],
376
+ nextAfter: 1,
377
+ });
378
+ const iter = subscribeEvents("j-1", { longPollSecs: null })[Symbol.asyncIterator]();
379
+ await iter.next();
380
+ // Mirror of Python's `long_poll_secs=None` forwarding test —
381
+ // `null` should reach the binding unchanged so a single-immediate
382
+ // -read call hits the right code path.
383
+ expect(listEventsMock).toHaveBeenCalledWith(0, undefined, null);
384
+ });
385
+ it("translates JobNotFoundError when the binding rejects with that message", async () => {
386
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
387
+ listEventsMock.mockRejectedValueOnce(new Error("backend error: job not found: stale-job"));
388
+ const iter = subscribeEvents("stale-job")[Symbol.asyncIterator]();
389
+ await expect(iter.next()).rejects.toBeInstanceOf(JobNotFoundError);
390
+ });
391
+ it("per-subscriber cursor: same proxy, both iters observe seq=1 independently", async () => {
392
+ process.env.MCP_MESH_REGISTRY_URL = "http://localhost:8000";
393
+ // Resolve with a single event then `.return()` the iterator so the
394
+ // generator's outer `while(true)` doesn't spin microtasks forever.
395
+ // (mockResolvedValue without an end-condition would loop the
396
+ // generator indefinitely and OOM the test runner.)
397
+ //
398
+ // The headline contract of subscribeEvents is that each call manages
399
+ // its own cursor: both iter1 and iter2 start at cursor=0, so both
400
+ // must observe the same seq=1 event even though they share the
401
+ // cached proxy. This asserts:
402
+ // 1. iter1 observes seq=1 (cursor starts at 0).
403
+ // 2. iter2 also observes seq=1 (its OWN cursor also starts at 0).
404
+ // 3. Only ONE proxy was constructed (LRU reuse).
405
+ listEventsMock.mockResolvedValue({
406
+ events: [
407
+ {
408
+ job_id: "j-shared",
409
+ seq: 1,
410
+ type: "x",
411
+ payload: {},
412
+ trace_context: null,
413
+ posted_by: null,
414
+ created_at: 1,
415
+ },
416
+ ],
417
+ nextAfter: 1,
418
+ });
419
+ const observed1 = [];
420
+ const iter1 = subscribeEvents("j-shared")[Symbol.asyncIterator]();
421
+ const r1 = await iter1.next();
422
+ if (!r1.done)
423
+ observed1.push(r1.value.seq);
424
+ await iter1.return?.(undefined);
425
+ // Subscribe again for the same job — must hit the same cached proxy
426
+ // AND start with its own fresh cursor=0 so it observes seq=1 too.
427
+ const observed2 = [];
428
+ const iter2 = subscribeEvents("j-shared")[Symbol.asyncIterator]();
429
+ const r2 = await iter2.next();
430
+ if (!r2.done)
431
+ observed2.push(r2.value.seq);
432
+ await iter2.return?.(undefined);
433
+ // Both iterators independently observed the seq=1 event — proves
434
+ // per-subscriber cursor isolation (the headline contract).
435
+ expect(observed1).toEqual([1]);
436
+ expect(observed2).toEqual([1]);
437
+ // Only ONE proxy was constructed — proves LRU caching.
438
+ expect(proxyCalls).toHaveLength(1);
439
+ expect(proxyCalls[0]).toEqual({
440
+ jobId: "j-shared",
441
+ registryUrl: "http://localhost:8000",
442
+ });
443
+ });
444
+ });
445
+ //# sourceMappingURL=jobs.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.spec.js","sourceRoot":"","sources":["../../src/__tests__/jobs.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Unit tests for the `modelParams` escape-hatch — issue #1019.
3
+ *
4
+ * The TS SDK exposes a typed option surface (`maxOutputTokens`, `temperature`,
5
+ * `topP`, `stop`) that maps to wire `model_params` keys. For vendor-specific
6
+ * kwargs that the typed surface doesn't expose (e.g., Gemini `thinking_config`,
7
+ * Anthropic `output_config`, OpenAI `reasoning_effort`) callers can pass an
8
+ * arbitrary dict via `options.modelParams`. The dict is merged into the wire
9
+ * `model_params` BEFORE typed fields, so typed options always win on collision
10
+ * (keeping the typed surface authoritative).
11
+ *
12
+ * Covers both the buffered (`complete()`) and the streaming (`streamComplete()`)
13
+ * paths since both build `model_params` independently.
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=llm-agent-model-params.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-agent-model-params.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/llm-agent-model-params.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}