@mcpmesh/sdk 2.3.0 → 2.5.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.
Files changed (166) hide show
  1. package/dist/__tests__/agent-single-instance.spec.d.ts +2 -0
  2. package/dist/__tests__/agent-single-instance.spec.d.ts.map +1 -0
  3. package/dist/__tests__/agent-single-instance.spec.js +80 -0
  4. package/dist/__tests__/agent-single-instance.spec.js.map +1 -0
  5. package/dist/__tests__/event-loop-resilience.spec.d.ts +2 -0
  6. package/dist/__tests__/event-loop-resilience.spec.d.ts.map +1 -0
  7. package/dist/__tests__/event-loop-resilience.spec.js +321 -0
  8. package/dist/__tests__/event-loop-resilience.spec.js.map +1 -0
  9. package/dist/__tests__/llm-agent-model-params.test.js +83 -0
  10. package/dist/__tests__/llm-agent-model-params.test.js.map +1 -1
  11. package/dist/__tests__/llm-max-iterations.test.d.ts +20 -0
  12. package/dist/__tests__/llm-max-iterations.test.d.ts.map +1 -0
  13. package/dist/__tests__/llm-max-iterations.test.js +252 -0
  14. package/dist/__tests__/llm-max-iterations.test.js.map +1 -0
  15. package/dist/__tests__/llm-mesh-error-mapping.test.d.ts +16 -0
  16. package/dist/__tests__/llm-mesh-error-mapping.test.d.ts.map +1 -0
  17. package/dist/__tests__/llm-mesh-error-mapping.test.js +135 -0
  18. package/dist/__tests__/llm-mesh-error-mapping.test.js.map +1 -0
  19. package/dist/__tests__/llm-provider-multistep.test.d.ts +20 -0
  20. package/dist/__tests__/llm-provider-multistep.test.d.ts.map +1 -0
  21. package/dist/__tests__/llm-provider-multistep.test.js +138 -0
  22. package/dist/__tests__/llm-provider-multistep.test.js.map +1 -0
  23. package/dist/__tests__/llm-provider-output-mode.test.d.ts +21 -0
  24. package/dist/__tests__/llm-provider-output-mode.test.d.ts.map +1 -0
  25. package/dist/__tests__/llm-provider-output-mode.test.js +116 -0
  26. package/dist/__tests__/llm-provider-output-mode.test.js.map +1 -0
  27. package/dist/__tests__/llm-provider-stopwhen.test.d.ts +22 -0
  28. package/dist/__tests__/llm-provider-stopwhen.test.d.ts.map +1 -0
  29. package/dist/__tests__/llm-provider-stopwhen.test.js +127 -0
  30. package/dist/__tests__/llm-provider-stopwhen.test.js.map +1 -0
  31. package/dist/__tests__/llm-provider-system-synthesis.test.d.ts +20 -0
  32. package/dist/__tests__/llm-provider-system-synthesis.test.d.ts.map +1 -0
  33. package/dist/__tests__/llm-provider-system-synthesis.test.js +168 -0
  34. package/dist/__tests__/llm-provider-system-synthesis.test.js.map +1 -0
  35. package/dist/__tests__/llm-provider-vertex-settings.test.d.ts +18 -0
  36. package/dist/__tests__/llm-provider-vertex-settings.test.d.ts.map +1 -0
  37. package/dist/__tests__/llm-provider-vertex-settings.test.js +128 -0
  38. package/dist/__tests__/llm-provider-vertex-settings.test.js.map +1 -0
  39. package/dist/__tests__/llm-response-model.test.d.ts +10 -0
  40. package/dist/__tests__/llm-response-model.test.d.ts.map +1 -0
  41. package/dist/__tests__/llm-response-model.test.js +92 -0
  42. package/dist/__tests__/llm-response-model.test.js.map +1 -0
  43. package/dist/__tests__/port-conflict-fallback.spec.d.ts +2 -0
  44. package/dist/__tests__/port-conflict-fallback.spec.d.ts.map +1 -0
  45. package/dist/__tests__/port-conflict-fallback.spec.js +123 -0
  46. package/dist/__tests__/port-conflict-fallback.spec.js.map +1 -0
  47. package/dist/__tests__/port-probe-errors.spec.d.ts +2 -0
  48. package/dist/__tests__/port-probe-errors.spec.d.ts.map +1 -0
  49. package/dist/__tests__/port-probe-errors.spec.js +100 -0
  50. package/dist/__tests__/port-probe-errors.spec.js.map +1 -0
  51. package/dist/__tests__/provider-handler-registry.test.d.ts +0 -1
  52. package/dist/__tests__/provider-handler-registry.test.d.ts.map +1 -1
  53. package/dist/__tests__/provider-handler-registry.test.js +23 -1
  54. package/dist/__tests__/provider-handler-registry.test.js.map +1 -1
  55. package/dist/__tests__/proxy-sse-no-data.test.d.ts +13 -0
  56. package/dist/__tests__/proxy-sse-no-data.test.d.ts.map +1 -0
  57. package/dist/__tests__/proxy-sse-no-data.test.js +147 -0
  58. package/dist/__tests__/proxy-sse-no-data.test.js.map +1 -0
  59. package/dist/__tests__/proxy-stream.test.js +26 -0
  60. package/dist/__tests__/proxy-stream.test.js.map +1 -1
  61. package/dist/__tests__/proxy-timeout-guard.test.d.ts +12 -0
  62. package/dist/__tests__/proxy-timeout-guard.test.d.ts.map +1 -0
  63. package/dist/__tests__/proxy-timeout-guard.test.js +85 -0
  64. package/dist/__tests__/proxy-timeout-guard.test.js.map +1 -0
  65. package/dist/__tests__/proxy-timer-leak.test.d.ts +16 -0
  66. package/dist/__tests__/proxy-timer-leak.test.d.ts.map +1 -0
  67. package/dist/__tests__/proxy-timer-leak.test.js +97 -0
  68. package/dist/__tests__/proxy-timer-leak.test.js.map +1 -0
  69. package/dist/__tests__/proxy-tool-error.test.d.ts +13 -0
  70. package/dist/__tests__/proxy-tool-error.test.d.ts.map +1 -0
  71. package/dist/__tests__/proxy-tool-error.test.js +313 -0
  72. package/dist/__tests__/proxy-tool-error.test.js.map +1 -0
  73. package/dist/__tests__/registry-disconnect-retains-deps.spec.d.ts +2 -0
  74. package/dist/__tests__/registry-disconnect-retains-deps.spec.d.ts.map +1 -0
  75. package/dist/__tests__/registry-disconnect-retains-deps.spec.js +101 -0
  76. package/dist/__tests__/registry-disconnect-retains-deps.spec.js.map +1 -0
  77. package/dist/__tests__/response-parser.test.js +29 -0
  78. package/dist/__tests__/response-parser.test.js.map +1 -1
  79. package/dist/__tests__/route.test.js +21 -1
  80. package/dist/__tests__/route.test.js.map +1 -1
  81. package/dist/__tests__/settle-window.spec.d.ts +2 -0
  82. package/dist/__tests__/settle-window.spec.d.ts.map +1 -0
  83. package/dist/__tests__/settle-window.spec.js +324 -0
  84. package/dist/__tests__/settle-window.spec.js.map +1 -0
  85. package/dist/__tests__/sse.test.js +12 -0
  86. package/dist/__tests__/sse.test.js.map +1 -1
  87. package/dist/__tests__/stop-dispatchers.spec.d.ts +2 -0
  88. package/dist/__tests__/stop-dispatchers.spec.d.ts.map +1 -0
  89. package/dist/__tests__/stop-dispatchers.spec.js +227 -0
  90. package/dist/__tests__/stop-dispatchers.spec.js.map +1 -0
  91. package/dist/agent.d.ts +65 -5
  92. package/dist/agent.d.ts.map +1 -1
  93. package/dist/agent.js +317 -78
  94. package/dist/agent.js.map +1 -1
  95. package/dist/api-runtime.d.ts +33 -3
  96. package/dist/api-runtime.d.ts.map +1 -1
  97. package/dist/api-runtime.js +133 -33
  98. package/dist/api-runtime.js.map +1 -1
  99. package/dist/claim-dispatcher.d.ts +25 -0
  100. package/dist/claim-dispatcher.d.ts.map +1 -1
  101. package/dist/claim-dispatcher.js +59 -1
  102. package/dist/claim-dispatcher.js.map +1 -1
  103. package/dist/config.d.ts +73 -1
  104. package/dist/config.d.ts.map +1 -1
  105. package/dist/config.js +108 -2
  106. package/dist/config.js.map +1 -1
  107. package/dist/debug.d.ts +1 -1
  108. package/dist/debug.d.ts.map +1 -1
  109. package/dist/express.d.ts +33 -0
  110. package/dist/express.d.ts.map +1 -1
  111. package/dist/express.js +157 -32
  112. package/dist/express.js.map +1 -1
  113. package/dist/index.d.ts +1 -1
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +1 -1
  116. package/dist/index.js.map +1 -1
  117. package/dist/llm-agent.d.ts +34 -0
  118. package/dist/llm-agent.d.ts.map +1 -1
  119. package/dist/llm-agent.js +239 -434
  120. package/dist/llm-agent.js.map +1 -1
  121. package/dist/llm-provider.d.ts +51 -4
  122. package/dist/llm-provider.d.ts.map +1 -1
  123. package/dist/llm-provider.js +175 -36
  124. package/dist/llm-provider.js.map +1 -1
  125. package/dist/llm.d.ts +1 -1
  126. package/dist/llm.d.ts.map +1 -1
  127. package/dist/llm.js +8 -5
  128. package/dist/llm.js.map +1 -1
  129. package/dist/provider-handlers/gemini-handler.d.ts.map +1 -1
  130. package/dist/provider-handlers/gemini-handler.js +8 -14
  131. package/dist/provider-handlers/gemini-handler.js.map +1 -1
  132. package/dist/provider-handlers/openai-handler.d.ts.map +1 -1
  133. package/dist/provider-handlers/openai-handler.js +2 -15
  134. package/dist/provider-handlers/openai-handler.js.map +1 -1
  135. package/dist/provider-handlers/provider-handler-registry.d.ts +10 -1
  136. package/dist/provider-handlers/provider-handler-registry.d.ts.map +1 -1
  137. package/dist/provider-handlers/provider-handler-registry.js +4 -1
  138. package/dist/provider-handlers/provider-handler-registry.js.map +1 -1
  139. package/dist/provider-handlers/provider-handler.d.ts +12 -0
  140. package/dist/provider-handlers/provider-handler.d.ts.map +1 -1
  141. package/dist/provider-handlers/provider-handler.js +24 -0
  142. package/dist/provider-handlers/provider-handler.js.map +1 -1
  143. package/dist/proxy.d.ts.map +1 -1
  144. package/dist/proxy.js +360 -287
  145. package/dist/proxy.js.map +1 -1
  146. package/dist/response-parser.d.ts +10 -0
  147. package/dist/response-parser.d.ts.map +1 -1
  148. package/dist/response-parser.js +55 -0
  149. package/dist/response-parser.js.map +1 -1
  150. package/dist/route.d.ts.map +1 -1
  151. package/dist/route.js +38 -0
  152. package/dist/route.js.map +1 -1
  153. package/dist/settle.d.ts +129 -0
  154. package/dist/settle.d.ts.map +1 -0
  155. package/dist/settle.js +284 -0
  156. package/dist/settle.js.map +1 -0
  157. package/dist/sse.d.ts.map +1 -1
  158. package/dist/sse.js +5 -2
  159. package/dist/sse.js.map +1 -1
  160. package/dist/tracing.d.ts +13 -0
  161. package/dist/tracing.d.ts.map +1 -1
  162. package/dist/tracing.js +40 -0
  163. package/dist/tracing.js.map +1 -1
  164. package/dist/types.d.ts +10 -2
  165. package/dist/types.d.ts.map +1 -1
  166. package/package.json +2 -2
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Unit tests for the configurable provider-managed agentic-loop cap — issue #1116.
3
+ *
4
+ * Two surfaces are covered:
5
+ *
6
+ * 1. Provider resolution (`resolveMaxIterations`): precedence of the
7
+ * consumer-forwarded `model_params.max_iterations` over the
8
+ * `MESH_LLM_MAX_ITERATIONS` env, the default of 10 when neither is set,
9
+ * and the sanitization of invalid inputs.
10
+ *
11
+ * 2. Consumer forwarding (`MeshDelegatedProvider.complete()`): when the caller
12
+ * passes `options.maxIterations`, it surfaces on the wire request as
13
+ * `model_params.max_iterations`; when absent, no such key leaks.
14
+ *
15
+ * Parity note: the truncation marker stays the PLAIN content string
16
+ * "Maximum tool call iterations reached" (matching Python `mesh/helpers.py`);
17
+ * this PR does not introduce a structured marker.
18
+ */
19
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
20
+ vi.mock("@mcpmesh/core", () => ({
21
+ generateTraceId: () => "trace-mock",
22
+ generateSpanId: () => "span-mock",
23
+ injectTraceContext: (argsJson) => argsJson,
24
+ publishSpan: vi.fn(async () => false),
25
+ parseSseResponse: (s) => s,
26
+ parseSseResponseToObject: (s) => JSON.parse(s),
27
+ }));
28
+ vi.mock("../http-pool.js", () => ({
29
+ getDispatcher: () => undefined,
30
+ }));
31
+ import { resolveMaxIterations, envMaxIterations, sanitizeMaxIterations, } from "../llm-provider.js";
32
+ import { MeshDelegatedProvider } from "../llm-agent.js";
33
+ // ----------------------------------------------------------------------------
34
+ // resolveMaxIterations — provider-side precedence + sanitization
35
+ // ----------------------------------------------------------------------------
36
+ describe("resolveMaxIterations — provider loop cap resolution", () => {
37
+ const ORIGINAL_ENV = process.env.MESH_LLM_MAX_ITERATIONS;
38
+ afterEach(() => {
39
+ if (ORIGINAL_ENV === undefined) {
40
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
41
+ }
42
+ else {
43
+ process.env.MESH_LLM_MAX_ITERATIONS = ORIGINAL_ENV;
44
+ }
45
+ });
46
+ it("model_params override wins over env", () => {
47
+ process.env.MESH_LLM_MAX_ITERATIONS = "7";
48
+ expect(resolveMaxIterations(25)).toBe(25);
49
+ });
50
+ it("falls back to env when the param is absent", () => {
51
+ process.env.MESH_LLM_MAX_ITERATIONS = "15";
52
+ expect(resolveMaxIterations(undefined)).toBe(15);
53
+ });
54
+ it("defaults to 10 when neither param nor env is set", () => {
55
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
56
+ expect(resolveMaxIterations(undefined)).toBe(10);
57
+ });
58
+ it("accepts a numeric string from the env", () => {
59
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
60
+ process.env.MESH_LLM_MAX_ITERATIONS = "3";
61
+ expect(resolveMaxIterations(undefined)).toBe(3);
62
+ });
63
+ it("floors a fractional value to an integer", () => {
64
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
65
+ expect(resolveMaxIterations(4.9)).toBe(4);
66
+ });
67
+ // #1116 fractional hole: floor-BEFORE-validate. 0.5 floors to 0, which is
68
+ // not > 0, so it must fall back to the default — NOT return a zero cap that
69
+ // would disable the loop.
70
+ it("falls back to 10 for a fractional value that floors to zero (0.5)", () => {
71
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
72
+ expect(resolveMaxIterations(0.5)).toBe(10);
73
+ });
74
+ it("falls back to 10 for a fractional value that floors to zero (0.9)", () => {
75
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
76
+ expect(resolveMaxIterations(0.9)).toBe(10);
77
+ });
78
+ it.each([
79
+ ["zero", 0],
80
+ ["negative", -5],
81
+ ["NaN", NaN],
82
+ ["non-numeric string", "abc"],
83
+ ["null", null],
84
+ ["object", {}],
85
+ ])("falls back to 10 for an invalid value (%s)", (_label, value) => {
86
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
87
+ expect(resolveMaxIterations(value)).toBe(10);
88
+ });
89
+ it("an invalid env falls back to 10", () => {
90
+ process.env.MESH_LLM_MAX_ITERATIONS = "not-a-number";
91
+ expect(resolveMaxIterations(undefined)).toBe(10);
92
+ });
93
+ // Parity (#1116/#1160): the Gemini AI-SDK-managed loop wires
94
+ // `stopWhen: stepCountIs(resolvedMaxIterations)` — AI SDK v6 removed
95
+ // `maxSteps`, whose default-stepCountIs(1) replacement caused the empty
96
+ // assistant message regression (#1160). The actual generateText option
97
+ // wiring is asserted in llm-provider-stopwhen.test.ts, and the multi-step
98
+ // loop behavior (tool call → follow-up text) in
99
+ // llm-provider-multistep.test.ts. Here we only assert the resolution the
100
+ // Gemini path consumes.
101
+ it("Gemini stopWhen path consumes the forwarded resolved cap", () => {
102
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
103
+ expect(resolveMaxIterations(25)).toBe(25);
104
+ });
105
+ it("Gemini stopWhen path falls back to 10 when the cap is absent", () => {
106
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
107
+ expect(resolveMaxIterations(undefined)).toBe(10);
108
+ });
109
+ });
110
+ // ----------------------------------------------------------------------------
111
+ // envMaxIterations — single source of truth for env parsing
112
+ // ----------------------------------------------------------------------------
113
+ describe("envMaxIterations — env parse + validation", () => {
114
+ const ORIGINAL_ENV = process.env.MESH_LLM_MAX_ITERATIONS;
115
+ afterEach(() => {
116
+ if (ORIGINAL_ENV === undefined) {
117
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
118
+ }
119
+ else {
120
+ process.env.MESH_LLM_MAX_ITERATIONS = ORIGINAL_ENV;
121
+ }
122
+ });
123
+ it("returns undefined when the env is unset", () => {
124
+ delete process.env.MESH_LLM_MAX_ITERATIONS;
125
+ expect(envMaxIterations()).toBeUndefined();
126
+ });
127
+ it.each([
128
+ ["zero", "0", undefined],
129
+ ["empty string", "", undefined],
130
+ ["non-numeric", "abc", undefined],
131
+ ["fractional below one", "0.5", undefined],
132
+ ["positive integer", "15", 15],
133
+ ["fractional floors down", "4.9", 4],
134
+ ["scientific notation (Number semantics)", "1e2", 100],
135
+ ])("parses %s → %s", (_label, raw, expected) => {
136
+ process.env.MESH_LLM_MAX_ITERATIONS = raw;
137
+ expect(envMaxIterations()).toBe(expected);
138
+ });
139
+ });
140
+ // ----------------------------------------------------------------------------
141
+ // sanitizeMaxIterations — single source of truth for cap normalization
142
+ // ----------------------------------------------------------------------------
143
+ describe("sanitizeMaxIterations — value normalization", () => {
144
+ it.each([
145
+ ["positive integer", 5, 5],
146
+ ["fractional floors down", 4.9, 4],
147
+ ["numeric string", "15", 15],
148
+ ["scientific notation (Number semantics)", "1e2", 100],
149
+ ])("normalizes a valid value (%s) → %s", (_label, value, expected) => {
150
+ expect(sanitizeMaxIterations(value)).toBe(expected);
151
+ });
152
+ it.each([
153
+ ["undefined", undefined],
154
+ ["null", null],
155
+ ["zero", 0],
156
+ ["negative", -3],
157
+ ["fractional below one", 0.5],
158
+ ["NaN", NaN],
159
+ ["non-numeric string", "abc"],
160
+ ["empty string", ""],
161
+ ["object", {}],
162
+ ])("rejects an invalid value (%s) → undefined", (_label, value) => {
163
+ expect(sanitizeMaxIterations(value)).toBeUndefined();
164
+ });
165
+ });
166
+ // ----------------------------------------------------------------------------
167
+ // MeshDelegatedProvider.complete() — consumer forwards maxIterations
168
+ // ----------------------------------------------------------------------------
169
+ const ENDPOINT = "http://provider.local:9001";
170
+ const FN_BUFFERED = "process_chat";
171
+ describe("MeshDelegatedProvider.complete() — maxIterations forwarding", () => {
172
+ let originalFetch;
173
+ beforeEach(() => {
174
+ originalFetch = globalThis.fetch;
175
+ });
176
+ afterEach(() => {
177
+ globalThis.fetch = originalFetch;
178
+ vi.restoreAllMocks();
179
+ });
180
+ function mockJsonResponse(body) {
181
+ return {
182
+ ok: true,
183
+ status: 200,
184
+ statusText: "OK",
185
+ headers: {
186
+ get: (name) => name.toLowerCase() === "content-type" ? "application/json" : null,
187
+ },
188
+ text: async () => JSON.stringify(body),
189
+ json: async () => body,
190
+ };
191
+ }
192
+ function mcpToolResponse(payload) {
193
+ return {
194
+ jsonrpc: "2.0",
195
+ id: 1,
196
+ result: {
197
+ content: [{ type: "text", text: JSON.stringify(payload) }],
198
+ },
199
+ };
200
+ }
201
+ const STUB_COMPLETION = { role: "assistant", content: "ok" };
202
+ it("forwards options.maxIterations as model_params.max_iterations", async () => {
203
+ let capturedBody;
204
+ const fetchMock = vi.fn(async (_url, init) => {
205
+ capturedBody = init.body;
206
+ return mockJsonResponse(mcpToolResponse(STUB_COMPLETION));
207
+ });
208
+ globalThis.fetch = fetchMock;
209
+ const provider = new MeshDelegatedProvider(ENDPOINT, FN_BUFFERED, false);
210
+ const messages = [{ role: "user", content: "hi" }];
211
+ await provider.complete("anthropic/claude-sonnet-4-5", messages, undefined, {
212
+ maxIterations: 25,
213
+ });
214
+ const body = JSON.parse(capturedBody);
215
+ const modelParams = body.params.arguments.request.model_params;
216
+ expect(modelParams.max_iterations).toBe(25);
217
+ });
218
+ it("typed maxIterations wins over an escape-hatch modelParams.max_iterations", async () => {
219
+ let capturedBody;
220
+ const fetchMock = vi.fn(async (_url, init) => {
221
+ capturedBody = init.body;
222
+ return mockJsonResponse(mcpToolResponse(STUB_COMPLETION));
223
+ });
224
+ globalThis.fetch = fetchMock;
225
+ const provider = new MeshDelegatedProvider(ENDPOINT, FN_BUFFERED, false);
226
+ const messages = [{ role: "user", content: "hi" }];
227
+ await provider.complete("anthropic/claude-sonnet-4-5", messages, undefined, {
228
+ maxIterations: 25,
229
+ modelParams: { max_iterations: 3 },
230
+ });
231
+ const body = JSON.parse(capturedBody);
232
+ const modelParams = body.params.arguments.request.model_params;
233
+ expect(modelParams.max_iterations).toBe(25);
234
+ });
235
+ it("does not emit max_iterations when maxIterations is absent", async () => {
236
+ let capturedBody;
237
+ const fetchMock = vi.fn(async (_url, init) => {
238
+ capturedBody = init.body;
239
+ return mockJsonResponse(mcpToolResponse(STUB_COMPLETION));
240
+ });
241
+ globalThis.fetch = fetchMock;
242
+ const provider = new MeshDelegatedProvider(ENDPOINT, FN_BUFFERED, false);
243
+ const messages = [{ role: "user", content: "hi" }];
244
+ await provider.complete("anthropic/claude-sonnet-4-5", messages, undefined, {
245
+ maxOutputTokens: 256,
246
+ });
247
+ const body = JSON.parse(capturedBody);
248
+ const modelParams = body.params.arguments.request.model_params;
249
+ expect(modelParams.max_iterations).toBeUndefined();
250
+ });
251
+ });
252
+ //# sourceMappingURL=llm-max-iterations.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-max-iterations.test.js","sourceRoot":"","sources":["../../src/__tests__/llm-max-iterations.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Unit tests for #1116 item-2 regression fixes: routing TS LLM calls through
3
+ * the shared callMcpTool must preserve the behavior the hand-rolled paths had.
4
+ *
5
+ * Covered:
6
+ * - Fix 1: MeshDelegatedProvider.complete() maps a timeout to LLMAPIError(408).
7
+ * callMcpTool re-throws the AbortError as a plain Error ("MCP call
8
+ * timed out after <N>ms"), so complete() now matches on the message.
9
+ * - Fix 2: callMcpTool surfaces a tool-level isError result by throwing, so
10
+ * complete() re-wraps it into LLMAPIError and createLlmToolProxy into
11
+ * ToolExecutionError instead of returning the error text as success.
12
+ * - Fix 3: createLlmToolProxy returns null (not "") when the tool returns no
13
+ * content.
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=llm-mesh-error-mapping.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-mesh-error-mapping.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/llm-mesh-error-mapping.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Unit tests for #1116 item-2 regression fixes: routing TS LLM calls through
3
+ * the shared callMcpTool must preserve the behavior the hand-rolled paths had.
4
+ *
5
+ * Covered:
6
+ * - Fix 1: MeshDelegatedProvider.complete() maps a timeout to LLMAPIError(408).
7
+ * callMcpTool re-throws the AbortError as a plain Error ("MCP call
8
+ * timed out after <N>ms"), so complete() now matches on the message.
9
+ * - Fix 2: callMcpTool surfaces a tool-level isError result by throwing, so
10
+ * complete() re-wraps it into LLMAPIError and createLlmToolProxy into
11
+ * ToolExecutionError instead of returning the error text as success.
12
+ * - Fix 3: createLlmToolProxy returns null (not "") when the tool returns no
13
+ * content.
14
+ */
15
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
16
+ import { MeshDelegatedProvider, createLlmToolProxy } from "../llm-agent.js";
17
+ import { LLMAPIError, ToolExecutionError } from "../errors.js";
18
+ vi.mock("@mcpmesh/core", () => ({
19
+ generateTraceId: () => "trace-mock",
20
+ generateSpanId: () => "span-mock",
21
+ injectTraceContext: (argsJson) => argsJson,
22
+ publishSpan: vi.fn(async () => false),
23
+ parseSseResponse: (s) => s,
24
+ parseSseResponseToObject: (s) => JSON.parse(s),
25
+ awaitJobCancel: vi.fn(() => new Promise(() => { })),
26
+ matchesPropagateHeader: () => false,
27
+ }));
28
+ vi.mock("../http-pool.js", () => ({
29
+ getDispatcher: () => undefined,
30
+ }));
31
+ const ENDPOINT = "http://provider.local:9000";
32
+ const FUNCTION = "mesh_complete";
33
+ function jsonResponse(result) {
34
+ const body = JSON.stringify({ jsonrpc: "2.0", id: "x", result });
35
+ return {
36
+ ok: true,
37
+ status: 200,
38
+ statusText: "OK",
39
+ text: async () => body,
40
+ headers: {
41
+ get: (name) => name.toLowerCase() === "content-type" ? "application/json" : null,
42
+ },
43
+ };
44
+ }
45
+ describe("MeshDelegatedProvider.complete() error mapping (#1116 item-2)", () => {
46
+ let originalFetch;
47
+ beforeEach(() => {
48
+ originalFetch = globalThis.fetch;
49
+ });
50
+ afterEach(() => {
51
+ globalThis.fetch = originalFetch;
52
+ vi.restoreAllMocks();
53
+ delete process.env.MESH_PROVIDER_TIMEOUT_MS;
54
+ });
55
+ it("Fix 1: maps a timeout to LLMAPIError with status 408", async () => {
56
+ process.env.MESH_PROVIDER_TIMEOUT_MS = "10";
57
+ // fetch hangs until aborted; reject with AbortError when the signal fires.
58
+ const fetchMock = vi.fn((_url, init) => {
59
+ const signal = init.signal;
60
+ return new Promise((_resolve, reject) => {
61
+ signal.addEventListener("abort", () => {
62
+ const err = new Error("aborted");
63
+ err.name = "AbortError";
64
+ reject(err);
65
+ });
66
+ });
67
+ });
68
+ globalThis.fetch = fetchMock;
69
+ const provider = new MeshDelegatedProvider(ENDPOINT, FUNCTION);
70
+ const err = await provider
71
+ .complete("mesh-delegated", [{ role: "user", content: "hi" }])
72
+ .then(() => null)
73
+ .catch((e) => e);
74
+ expect(err).toBeInstanceOf(LLMAPIError);
75
+ expect(err.statusCode).toBe(408);
76
+ expect(err.message).toMatch(/timed out/i);
77
+ });
78
+ it("Fix 2: maps a tool-level isError result to LLMAPIError(0)", async () => {
79
+ const fetchMock = vi.fn(async () => jsonResponse({
80
+ isError: true,
81
+ content: [{ type: "text", text: "provider blew up" }],
82
+ }));
83
+ globalThis.fetch = fetchMock;
84
+ const provider = new MeshDelegatedProvider(ENDPOINT, FUNCTION);
85
+ const err = await provider
86
+ .complete("mesh-delegated", [{ role: "user", content: "hi" }])
87
+ .then(() => null)
88
+ .catch((e) => e);
89
+ expect(err).toBeInstanceOf(LLMAPIError);
90
+ expect(err.statusCode).toBe(0);
91
+ expect(err.message).toContain("provider blew up");
92
+ });
93
+ });
94
+ describe("createLlmToolProxy error/empty mapping (#1116 item-2)", () => {
95
+ let originalFetch;
96
+ const toolInfo = {
97
+ functionName: "do_thing",
98
+ capability: "doer",
99
+ endpoint: ENDPOINT,
100
+ agentId: "agent-1",
101
+ };
102
+ beforeEach(() => {
103
+ originalFetch = globalThis.fetch;
104
+ });
105
+ afterEach(() => {
106
+ globalThis.fetch = originalFetch;
107
+ vi.restoreAllMocks();
108
+ });
109
+ it("Fix 2: maps a tool-level isError result to ToolExecutionError", async () => {
110
+ const fetchMock = vi.fn(async () => jsonResponse({
111
+ isError: true,
112
+ content: [{ type: "text", text: "tool failed" }],
113
+ }));
114
+ globalThis.fetch = fetchMock;
115
+ const proxy = createLlmToolProxy(toolInfo);
116
+ const err = await proxy({}).then(() => null).catch((e) => e);
117
+ expect(err).toBeInstanceOf(ToolExecutionError);
118
+ expect(err.message).toContain("tool failed");
119
+ });
120
+ it("Fix 3: returns null when the tool returns no content", async () => {
121
+ const fetchMock = vi.fn(async () => jsonResponse({ content: [] }));
122
+ globalThis.fetch = fetchMock;
123
+ const proxy = createLlmToolProxy(toolInfo);
124
+ const result = await proxy({});
125
+ expect(result).toBeNull();
126
+ });
127
+ it("returns parsed JSON for non-empty content", async () => {
128
+ const fetchMock = vi.fn(async () => jsonResponse({ content: [{ type: "text", text: '{"ok":true}' }] }));
129
+ globalThis.fetch = fetchMock;
130
+ const proxy = createLlmToolProxy(toolInfo);
131
+ const result = await proxy({});
132
+ expect(result).toEqual({ ok: true });
133
+ });
134
+ });
135
+ //# sourceMappingURL=llm-mesh-error-mapping.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-mesh-error-mapping.test.js","sourceRoot":"","sources":["../../src/__tests__/llm-mesh-error-mapping.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Gemini SDK-managed multi-step loop — end-to-end regression test for #1160.
3
+ *
4
+ * Uses the REAL `ai` module (generateText + stopWhen + tool execution) with a
5
+ * `MockLanguageModelV3` (from `ai/test`) injected via a mocked
6
+ * `@ai-sdk/google` provider. The model emits a tool call on step 1 and text
7
+ * on step 2.
8
+ *
9
+ * With the broken `maxSteps` wiring (removed in AI SDK v6), generateText
10
+ * defaulted to `stopWhen: stepCountIs(1)`: the loop stopped right after the
11
+ * tool-call step, `result.text` was empty, and since the tools carried
12
+ * `_mesh_endpoint` the provider also stripped tool_calls — consumers received
13
+ * an empty assistant message. With `stopWhen: stepCountIs(n)` the loop does
14
+ * the follow-up generation and the final text is non-empty.
15
+ *
16
+ * Tool execution goes through the provider's execute functions →
17
+ * `callMcpTool`, which is mocked here to return a canned tool result.
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=llm-provider-multistep.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-provider-multistep.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/llm-provider-multistep.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Gemini SDK-managed multi-step loop — end-to-end regression test for #1160.
3
+ *
4
+ * Uses the REAL `ai` module (generateText + stopWhen + tool execution) with a
5
+ * `MockLanguageModelV3` (from `ai/test`) injected via a mocked
6
+ * `@ai-sdk/google` provider. The model emits a tool call on step 1 and text
7
+ * on step 2.
8
+ *
9
+ * With the broken `maxSteps` wiring (removed in AI SDK v6), generateText
10
+ * defaulted to `stopWhen: stepCountIs(1)`: the loop stopped right after the
11
+ * tool-call step, `result.text` was empty, and since the tools carried
12
+ * `_mesh_endpoint` the provider also stripped tool_calls — consumers received
13
+ * an empty assistant message. With `stopWhen: stepCountIs(n)` the loop does
14
+ * the follow-up generation and the final text is non-empty.
15
+ *
16
+ * Tool execution goes through the provider's execute functions →
17
+ * `callMcpTool`, which is mocked here to return a canned tool result.
18
+ */
19
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
20
+ // Per-step model results, controllable per test. vi.hoisted so the
21
+ // vi.mock("@ai-sdk/google") factory can reference it.
22
+ const modelHarness = vi.hoisted(() => ({
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
+ results: [],
25
+ calls: 0,
26
+ }));
27
+ const callMcpToolMock = vi.hoisted(() => vi.fn());
28
+ vi.mock("@ai-sdk/google", async () => {
29
+ const { MockLanguageModelV3 } = await import("ai/test");
30
+ return {
31
+ google: (modelId) => new MockLanguageModelV3({
32
+ modelId,
33
+ // Function form (not the array form: MockLanguageModelV3 indexes the
34
+ // array AFTER pushing the call, skipping element 0).
35
+ doGenerate: async () => {
36
+ const result = modelHarness.results[modelHarness.calls];
37
+ modelHarness.calls++;
38
+ if (!result) {
39
+ throw new Error(`MockLanguageModelV3: no scripted result for step ${modelHarness.calls}`);
40
+ }
41
+ return result;
42
+ },
43
+ }),
44
+ };
45
+ });
46
+ // Replace only callMcpTool — keep runWithTraceContext etc. real.
47
+ vi.mock("../proxy.js", async (importOriginal) => {
48
+ const actual = await importOriginal();
49
+ return { ...actual, callMcpTool: callMcpToolMock };
50
+ });
51
+ // Keep tracing inert (publishTraceSpan is best-effort fire-and-forget).
52
+ vi.mock("../tracing.js", async (importOriginal) => {
53
+ const actual = await importOriginal();
54
+ return { ...actual, publishTraceSpan: vi.fn(async () => false) };
55
+ });
56
+ import { llmProvider } from "../llm-provider.js";
57
+ const TOOL_CALL_STEP = {
58
+ content: [
59
+ {
60
+ type: "tool-call",
61
+ toolCallId: "call-1",
62
+ toolName: "get_weather",
63
+ input: JSON.stringify({ city: "Paris" }),
64
+ },
65
+ ],
66
+ finishReason: "tool-calls",
67
+ usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },
68
+ warnings: [],
69
+ };
70
+ const TEXT_STEP = {
71
+ content: [{ type: "text", text: "It is sunny in Paris." }],
72
+ finishReason: "stop",
73
+ usage: { inputTokens: 20, outputTokens: 8, totalTokens: 28 },
74
+ warnings: [],
75
+ };
76
+ function meshToolRequest(modelParams) {
77
+ return {
78
+ request: {
79
+ messages: [{ role: "user", content: "What's the weather in Paris?" }],
80
+ tools: [
81
+ {
82
+ type: "function",
83
+ function: {
84
+ name: "get_weather",
85
+ description: "Get the current weather for a city",
86
+ parameters: {
87
+ type: "object",
88
+ properties: { city: { type: "string" } },
89
+ required: ["city"],
90
+ },
91
+ _mesh_endpoint: "http://weather-agent.local:9100",
92
+ },
93
+ },
94
+ ],
95
+ model_params: { ...modelParams },
96
+ },
97
+ };
98
+ }
99
+ describe("Gemini multi-step loop with real generateText (#1160)", () => {
100
+ beforeEach(() => {
101
+ modelHarness.results = [TOOL_CALL_STEP, TEXT_STEP];
102
+ modelHarness.calls = 0;
103
+ callMcpToolMock.mockReset();
104
+ callMcpToolMock.mockResolvedValue(JSON.stringify({ temperature_c: 21, condition: "sunny" }));
105
+ });
106
+ afterEach(() => {
107
+ vi.restoreAllMocks();
108
+ });
109
+ it("executes the tool on step 1 and returns the follow-up text from step 2", async () => {
110
+ const tool = llmProvider({ model: "gemini/gemini-2.5-flash", capability: "llm" });
111
+ const raw = await tool.execute(meshToolRequest({ max_iterations: 3 }));
112
+ const response = JSON.parse(raw);
113
+ // The model was called twice: tool-call step + follow-up generation.
114
+ expect(modelHarness.calls).toBe(2);
115
+ // The tool was executed provider-side via its _mesh_endpoint.
116
+ expect(callMcpToolMock).toHaveBeenCalledTimes(1);
117
+ const [endpoint, toolName, toolArgs] = callMcpToolMock.mock.calls[0];
118
+ expect(endpoint).toBe("http://weather-agent.local:9100");
119
+ expect(toolName).toBe("get_weather");
120
+ expect(toolArgs).toEqual({ city: "Paris" });
121
+ // #1160: the assistant message must carry the step-2 text, not be empty.
122
+ expect(response.content).toBe("It is sunny in Paris.");
123
+ // Tools were executed provider-side — no tool_calls leak to the consumer.
124
+ expect(response.tool_calls).toBeUndefined();
125
+ });
126
+ it("honors the forwarded cap: max_iterations=1 stops after the tool-call step", async () => {
127
+ const tool = llmProvider({ model: "gemini/gemini-2.5-flash", capability: "llm" });
128
+ const raw = await tool.execute(meshToolRequest({ max_iterations: 1 }));
129
+ const response = JSON.parse(raw);
130
+ // stopWhen=stepCountIs(1): the tool still executes within step 1, but no
131
+ // follow-up generation happens — proving the cap actually drives the loop.
132
+ expect(modelHarness.calls).toBe(1);
133
+ expect(callMcpToolMock).toHaveBeenCalledTimes(1);
134
+ expect(response.content).toBe("");
135
+ expect(response.tool_calls).toBeUndefined();
136
+ });
137
+ });
138
+ //# sourceMappingURL=llm-provider-multistep.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-provider-multistep.test.js","sourceRoot":"","sources":["../../src/__tests__/llm-provider-multistep.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Provider-side honoring of the consumer-supplied output_mode override — #1112.
3
+ *
4
+ * The provider's effective output mode is:
5
+ * effective = (model_params.output_mode is one of strict/hint/text)
6
+ * ? that override
7
+ * : handler.determineOutputMode(outputSchema) // today's auto
8
+ *
9
+ * Observability seam: the strict path drives `generateObject()` while
10
+ * hint/text drive `generateText()` (useStructuredOutput === outputMode ===
11
+ * "strict"). For an OpenAI provider WITH a schema and NO tools, auto-selection
12
+ * is "strict" → generateObject. A "hint"/"text" override flips it to
13
+ * generateText. An absent/invalid override leaves auto (strict) intact.
14
+ *
15
+ * Also asserts output_mode is stripped from the params before they reach the
16
+ * vendor SDK call (generateObject/generateText options).
17
+ *
18
+ * The Vercel `ai` module is mocked — no real LLM is invoked.
19
+ */
20
+ export {};
21
+ //# sourceMappingURL=llm-provider-output-mode.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-provider-output-mode.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/llm-provider-output-mode.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}