@mcpmesh/sdk 2.2.4 → 2.4.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.
- package/dist/__tests__/jobs.spec.js +231 -1
- package/dist/__tests__/jobs.spec.js.map +1 -1
- package/dist/__tests__/llm-agent-model-params.test.js +83 -0
- package/dist/__tests__/llm-agent-model-params.test.js.map +1 -1
- package/dist/__tests__/llm-max-iterations.test.d.ts +20 -0
- package/dist/__tests__/llm-max-iterations.test.d.ts.map +1 -0
- package/dist/__tests__/llm-max-iterations.test.js +250 -0
- package/dist/__tests__/llm-max-iterations.test.js.map +1 -0
- package/dist/__tests__/llm-mesh-error-mapping.test.d.ts +16 -0
- package/dist/__tests__/llm-mesh-error-mapping.test.d.ts.map +1 -0
- package/dist/__tests__/llm-mesh-error-mapping.test.js +135 -0
- package/dist/__tests__/llm-mesh-error-mapping.test.js.map +1 -0
- package/dist/__tests__/llm-provider-output-mode.test.d.ts +21 -0
- package/dist/__tests__/llm-provider-output-mode.test.d.ts.map +1 -0
- package/dist/__tests__/llm-provider-output-mode.test.js +115 -0
- package/dist/__tests__/llm-provider-output-mode.test.js.map +1 -0
- package/dist/__tests__/llm-provider-system-synthesis.test.d.ts +20 -0
- package/dist/__tests__/llm-provider-system-synthesis.test.d.ts.map +1 -0
- package/dist/__tests__/llm-provider-system-synthesis.test.js +167 -0
- package/dist/__tests__/llm-provider-system-synthesis.test.js.map +1 -0
- package/dist/__tests__/llm-response-model.test.d.ts +10 -0
- package/dist/__tests__/llm-response-model.test.d.ts.map +1 -0
- package/dist/__tests__/llm-response-model.test.js +92 -0
- package/dist/__tests__/llm-response-model.test.js.map +1 -0
- package/dist/__tests__/proxy-timeout-guard.test.d.ts +12 -0
- package/dist/__tests__/proxy-timeout-guard.test.d.ts.map +1 -0
- package/dist/__tests__/proxy-timeout-guard.test.js +85 -0
- package/dist/__tests__/proxy-timeout-guard.test.js.map +1 -0
- package/dist/__tests__/registry-disconnect-retains-deps.spec.d.ts +2 -0
- package/dist/__tests__/registry-disconnect-retains-deps.spec.d.ts.map +1 -0
- package/dist/__tests__/registry-disconnect-retains-deps.spec.js +101 -0
- package/dist/__tests__/registry-disconnect-retains-deps.spec.js.map +1 -0
- package/dist/__tests__/response-parser.test.js +29 -0
- package/dist/__tests__/response-parser.test.js.map +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +4 -0
- package/dist/agent.js.map +1 -1
- package/dist/api-runtime.d.ts.map +1 -1
- package/dist/api-runtime.js +8 -1
- package/dist/api-runtime.js.map +1 -1
- package/dist/express.d.ts.map +1 -1
- package/dist/express.js +8 -1
- package/dist/express.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/jobs.d.ts +191 -0
- package/dist/jobs.d.ts.map +1 -1
- package/dist/jobs.js +198 -1
- package/dist/jobs.js.map +1 -1
- package/dist/llm-agent.d.ts +34 -0
- package/dist/llm-agent.d.ts.map +1 -1
- package/dist/llm-agent.js +239 -434
- package/dist/llm-agent.js.map +1 -1
- package/dist/llm-provider.d.ts +33 -4
- package/dist/llm-provider.d.ts.map +1 -1
- package/dist/llm-provider.js +91 -4
- package/dist/llm-provider.js.map +1 -1
- package/dist/llm.d.ts +1 -1
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +8 -5
- package/dist/llm.js.map +1 -1
- package/dist/provider-handlers/gemini-handler.d.ts.map +1 -1
- package/dist/provider-handlers/gemini-handler.js +2 -14
- package/dist/provider-handlers/gemini-handler.js.map +1 -1
- package/dist/provider-handlers/openai-handler.d.ts.map +1 -1
- package/dist/provider-handlers/openai-handler.js +2 -15
- package/dist/provider-handlers/openai-handler.js.map +1 -1
- package/dist/provider-handlers/provider-handler.d.ts +12 -0
- package/dist/provider-handlers/provider-handler.d.ts.map +1 -1
- package/dist/provider-handlers/provider-handler.js +24 -0
- package/dist/provider-handlers/provider-handler.js.map +1 -1
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +189 -254
- package/dist/proxy.js.map +1 -1
- package/dist/response-parser.d.ts +10 -0
- package/dist/response-parser.d.ts.map +1 -1
- package/dist/response-parser.js +55 -0
- package/dist/response-parser.js.map +1 -1
- package/dist/tracing.d.ts +12 -0
- package/dist/tracing.d.ts.map +1 -1
- package/dist/tracing.js +37 -0
- package/dist/tracing.js.map +1 -1
- package/dist/types.d.ts +10 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,250 @@
|
|
|
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): the Gemini AI-SDK-managed loop sets
|
|
94
|
+
// `requestOptions.maxSteps = resolvedMaxIterations`, the SAME value the
|
|
95
|
+
// manual provider-managed loop uses as its cap. We assert the resolution
|
|
96
|
+
// the Gemini path consumes here rather than the wired `maxSteps`, since
|
|
97
|
+
// observing the latter would require a full `vi.mock("ai")` generateText
|
|
98
|
+
// harness that this file deliberately does not build.
|
|
99
|
+
it("Gemini maxSteps path consumes the forwarded resolved cap", () => {
|
|
100
|
+
delete process.env.MESH_LLM_MAX_ITERATIONS;
|
|
101
|
+
expect(resolveMaxIterations(25)).toBe(25);
|
|
102
|
+
});
|
|
103
|
+
it("Gemini maxSteps path falls back to 10 when the cap is absent", () => {
|
|
104
|
+
delete process.env.MESH_LLM_MAX_ITERATIONS;
|
|
105
|
+
expect(resolveMaxIterations(undefined)).toBe(10);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
// ----------------------------------------------------------------------------
|
|
109
|
+
// envMaxIterations — single source of truth for env parsing
|
|
110
|
+
// ----------------------------------------------------------------------------
|
|
111
|
+
describe("envMaxIterations — env parse + validation", () => {
|
|
112
|
+
const ORIGINAL_ENV = process.env.MESH_LLM_MAX_ITERATIONS;
|
|
113
|
+
afterEach(() => {
|
|
114
|
+
if (ORIGINAL_ENV === undefined) {
|
|
115
|
+
delete process.env.MESH_LLM_MAX_ITERATIONS;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
process.env.MESH_LLM_MAX_ITERATIONS = ORIGINAL_ENV;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
it("returns undefined when the env is unset", () => {
|
|
122
|
+
delete process.env.MESH_LLM_MAX_ITERATIONS;
|
|
123
|
+
expect(envMaxIterations()).toBeUndefined();
|
|
124
|
+
});
|
|
125
|
+
it.each([
|
|
126
|
+
["zero", "0", undefined],
|
|
127
|
+
["empty string", "", undefined],
|
|
128
|
+
["non-numeric", "abc", undefined],
|
|
129
|
+
["fractional below one", "0.5", undefined],
|
|
130
|
+
["positive integer", "15", 15],
|
|
131
|
+
["fractional floors down", "4.9", 4],
|
|
132
|
+
["scientific notation (Number semantics)", "1e2", 100],
|
|
133
|
+
])("parses %s → %s", (_label, raw, expected) => {
|
|
134
|
+
process.env.MESH_LLM_MAX_ITERATIONS = raw;
|
|
135
|
+
expect(envMaxIterations()).toBe(expected);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
// ----------------------------------------------------------------------------
|
|
139
|
+
// sanitizeMaxIterations — single source of truth for cap normalization
|
|
140
|
+
// ----------------------------------------------------------------------------
|
|
141
|
+
describe("sanitizeMaxIterations — value normalization", () => {
|
|
142
|
+
it.each([
|
|
143
|
+
["positive integer", 5, 5],
|
|
144
|
+
["fractional floors down", 4.9, 4],
|
|
145
|
+
["numeric string", "15", 15],
|
|
146
|
+
["scientific notation (Number semantics)", "1e2", 100],
|
|
147
|
+
])("normalizes a valid value (%s) → %s", (_label, value, expected) => {
|
|
148
|
+
expect(sanitizeMaxIterations(value)).toBe(expected);
|
|
149
|
+
});
|
|
150
|
+
it.each([
|
|
151
|
+
["undefined", undefined],
|
|
152
|
+
["null", null],
|
|
153
|
+
["zero", 0],
|
|
154
|
+
["negative", -3],
|
|
155
|
+
["fractional below one", 0.5],
|
|
156
|
+
["NaN", NaN],
|
|
157
|
+
["non-numeric string", "abc"],
|
|
158
|
+
["empty string", ""],
|
|
159
|
+
["object", {}],
|
|
160
|
+
])("rejects an invalid value (%s) → undefined", (_label, value) => {
|
|
161
|
+
expect(sanitizeMaxIterations(value)).toBeUndefined();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
// ----------------------------------------------------------------------------
|
|
165
|
+
// MeshDelegatedProvider.complete() — consumer forwards maxIterations
|
|
166
|
+
// ----------------------------------------------------------------------------
|
|
167
|
+
const ENDPOINT = "http://provider.local:9001";
|
|
168
|
+
const FN_BUFFERED = "process_chat";
|
|
169
|
+
describe("MeshDelegatedProvider.complete() — maxIterations forwarding", () => {
|
|
170
|
+
let originalFetch;
|
|
171
|
+
beforeEach(() => {
|
|
172
|
+
originalFetch = globalThis.fetch;
|
|
173
|
+
});
|
|
174
|
+
afterEach(() => {
|
|
175
|
+
globalThis.fetch = originalFetch;
|
|
176
|
+
vi.restoreAllMocks();
|
|
177
|
+
});
|
|
178
|
+
function mockJsonResponse(body) {
|
|
179
|
+
return {
|
|
180
|
+
ok: true,
|
|
181
|
+
status: 200,
|
|
182
|
+
statusText: "OK",
|
|
183
|
+
headers: {
|
|
184
|
+
get: (name) => name.toLowerCase() === "content-type" ? "application/json" : null,
|
|
185
|
+
},
|
|
186
|
+
text: async () => JSON.stringify(body),
|
|
187
|
+
json: async () => body,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function mcpToolResponse(payload) {
|
|
191
|
+
return {
|
|
192
|
+
jsonrpc: "2.0",
|
|
193
|
+
id: 1,
|
|
194
|
+
result: {
|
|
195
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const STUB_COMPLETION = { role: "assistant", content: "ok" };
|
|
200
|
+
it("forwards options.maxIterations as model_params.max_iterations", async () => {
|
|
201
|
+
let capturedBody;
|
|
202
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
203
|
+
capturedBody = init.body;
|
|
204
|
+
return mockJsonResponse(mcpToolResponse(STUB_COMPLETION));
|
|
205
|
+
});
|
|
206
|
+
globalThis.fetch = fetchMock;
|
|
207
|
+
const provider = new MeshDelegatedProvider(ENDPOINT, FN_BUFFERED, false);
|
|
208
|
+
const messages = [{ role: "user", content: "hi" }];
|
|
209
|
+
await provider.complete("anthropic/claude-sonnet-4-5", messages, undefined, {
|
|
210
|
+
maxIterations: 25,
|
|
211
|
+
});
|
|
212
|
+
const body = JSON.parse(capturedBody);
|
|
213
|
+
const modelParams = body.params.arguments.request.model_params;
|
|
214
|
+
expect(modelParams.max_iterations).toBe(25);
|
|
215
|
+
});
|
|
216
|
+
it("typed maxIterations wins over an escape-hatch modelParams.max_iterations", async () => {
|
|
217
|
+
let capturedBody;
|
|
218
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
219
|
+
capturedBody = init.body;
|
|
220
|
+
return mockJsonResponse(mcpToolResponse(STUB_COMPLETION));
|
|
221
|
+
});
|
|
222
|
+
globalThis.fetch = fetchMock;
|
|
223
|
+
const provider = new MeshDelegatedProvider(ENDPOINT, FN_BUFFERED, false);
|
|
224
|
+
const messages = [{ role: "user", content: "hi" }];
|
|
225
|
+
await provider.complete("anthropic/claude-sonnet-4-5", messages, undefined, {
|
|
226
|
+
maxIterations: 25,
|
|
227
|
+
modelParams: { max_iterations: 3 },
|
|
228
|
+
});
|
|
229
|
+
const body = JSON.parse(capturedBody);
|
|
230
|
+
const modelParams = body.params.arguments.request.model_params;
|
|
231
|
+
expect(modelParams.max_iterations).toBe(25);
|
|
232
|
+
});
|
|
233
|
+
it("does not emit max_iterations when maxIterations is absent", async () => {
|
|
234
|
+
let capturedBody;
|
|
235
|
+
const fetchMock = vi.fn(async (_url, init) => {
|
|
236
|
+
capturedBody = init.body;
|
|
237
|
+
return mockJsonResponse(mcpToolResponse(STUB_COMPLETION));
|
|
238
|
+
});
|
|
239
|
+
globalThis.fetch = fetchMock;
|
|
240
|
+
const provider = new MeshDelegatedProvider(ENDPOINT, FN_BUFFERED, false);
|
|
241
|
+
const messages = [{ role: "user", content: "hi" }];
|
|
242
|
+
await provider.complete("anthropic/claude-sonnet-4-5", messages, undefined, {
|
|
243
|
+
maxOutputTokens: 256,
|
|
244
|
+
});
|
|
245
|
+
const body = JSON.parse(capturedBody);
|
|
246
|
+
const modelParams = body.params.arguments.request.model_params;
|
|
247
|
+
expect(modelParams.max_iterations).toBeUndefined();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
//# 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,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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
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
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
21
|
+
const generateObjectMock = vi.fn();
|
|
22
|
+
const generateTextMock = vi.fn();
|
|
23
|
+
vi.mock("ai", () => ({
|
|
24
|
+
generateText: (opts) => generateTextMock(opts),
|
|
25
|
+
generateObject: (opts) => generateObjectMock(opts),
|
|
26
|
+
jsonSchema: (schema) => schema,
|
|
27
|
+
tool: (config) => config,
|
|
28
|
+
}));
|
|
29
|
+
// Keep tracing inert/deterministic (publishTraceSpan is best-effort anyway).
|
|
30
|
+
vi.mock("../tracing.js", () => ({
|
|
31
|
+
generateTraceId: () => "trace-mock",
|
|
32
|
+
generateSpanId: () => "span-mock",
|
|
33
|
+
publishTraceSpan: vi.fn(async () => { }),
|
|
34
|
+
matchesPropagateHeader: () => false,
|
|
35
|
+
}));
|
|
36
|
+
import { llmProvider } from "../llm-provider.js";
|
|
37
|
+
const SCHEMA = {
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: { answer: { type: "string" } },
|
|
40
|
+
required: ["answer"],
|
|
41
|
+
};
|
|
42
|
+
function makeProvider() {
|
|
43
|
+
// OpenAI vendor: auto-selects "strict" when a schema is present.
|
|
44
|
+
return llmProvider({ model: "openai/gpt-4o", capability: "llm" });
|
|
45
|
+
}
|
|
46
|
+
function baseRequest(modelParams) {
|
|
47
|
+
return {
|
|
48
|
+
request: {
|
|
49
|
+
messages: [
|
|
50
|
+
{ role: "system", content: "You are helpful." },
|
|
51
|
+
{ role: "user", content: "hi" },
|
|
52
|
+
],
|
|
53
|
+
model_params: {
|
|
54
|
+
output_schema: SCHEMA,
|
|
55
|
+
output_type_name: "Answer",
|
|
56
|
+
...modelParams,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
describe("provider output_mode override (#1112)", () => {
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
generateObjectMock.mockReset();
|
|
64
|
+
generateTextMock.mockReset();
|
|
65
|
+
generateObjectMock.mockResolvedValue({
|
|
66
|
+
object: { answer: "ok" },
|
|
67
|
+
usage: { inputTokens: 1, outputTokens: 1 },
|
|
68
|
+
finishReason: "stop",
|
|
69
|
+
});
|
|
70
|
+
generateTextMock.mockResolvedValue({
|
|
71
|
+
text: "ok",
|
|
72
|
+
toolCalls: [],
|
|
73
|
+
usage: { inputTokens: 1, outputTokens: 1 },
|
|
74
|
+
finishReason: "stop",
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
afterEach(() => {
|
|
78
|
+
vi.restoreAllMocks();
|
|
79
|
+
});
|
|
80
|
+
it("auto-selects strict (generateObject) when no override is present — byte-identical to today", async () => {
|
|
81
|
+
const tool = makeProvider();
|
|
82
|
+
await tool.execute(baseRequest({}));
|
|
83
|
+
expect(generateObjectMock).toHaveBeenCalledTimes(1);
|
|
84
|
+
expect(generateTextMock).not.toHaveBeenCalled();
|
|
85
|
+
});
|
|
86
|
+
it("honors a 'hint' override where it would auto-select strict (uses generateText)", async () => {
|
|
87
|
+
const tool = makeProvider();
|
|
88
|
+
await tool.execute(baseRequest({ output_mode: "hint" }));
|
|
89
|
+
expect(generateTextMock).toHaveBeenCalledTimes(1);
|
|
90
|
+
expect(generateObjectMock).not.toHaveBeenCalled();
|
|
91
|
+
});
|
|
92
|
+
it("honors a 'text' override (uses generateText)", async () => {
|
|
93
|
+
const tool = makeProvider();
|
|
94
|
+
await tool.execute(baseRequest({ output_mode: "text" }));
|
|
95
|
+
expect(generateTextMock).toHaveBeenCalledTimes(1);
|
|
96
|
+
expect(generateObjectMock).not.toHaveBeenCalled();
|
|
97
|
+
});
|
|
98
|
+
it("ignores an invalid override and falls back to auto (strict → generateObject)", async () => {
|
|
99
|
+
const tool = makeProvider();
|
|
100
|
+
await tool.execute(baseRequest({ output_mode: "bogus" }));
|
|
101
|
+
expect(generateObjectMock).toHaveBeenCalledTimes(1);
|
|
102
|
+
expect(generateTextMock).not.toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
it("strips output_mode from the params reaching the vendor SDK call", async () => {
|
|
105
|
+
const tool = makeProvider();
|
|
106
|
+
await tool.execute(baseRequest({ output_mode: "hint" }));
|
|
107
|
+
// hint → generateText; assert the options object carries no output_mode.
|
|
108
|
+
expect(generateTextMock).toHaveBeenCalledTimes(1);
|
|
109
|
+
const opts = generateTextMock.mock.calls[0][0];
|
|
110
|
+
expect("output_mode" in opts).toBe(false);
|
|
111
|
+
// Nested guard: output_mode must not leak via providerOptions either.
|
|
112
|
+
expect(JSON.stringify(opts)).not.toContain("output_mode");
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
//# sourceMappingURL=llm-provider-output-mode.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-provider-output-mode.test.js","sourceRoot":"","sources":["../../src/__tests__/llm-provider-output-mode.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider synthesizes a system message when the consumer supplies none but
|
|
3
|
+
* structured-output (hint mode) instructions still need to reach the model —
|
|
4
|
+
* #1112 finding 6.
|
|
5
|
+
*
|
|
6
|
+
* Root cause: the request.messages transform only augmented an EXISTING system
|
|
7
|
+
* message with the schema/JSON hint instructions. A mesh-delegated consumer
|
|
8
|
+
* with a typed schema and NO systemPrompt produced no system message, so the
|
|
9
|
+
* hint instructions were silently dropped. In hint mode there is no native
|
|
10
|
+
* response_format backstop (strict-only), so the model returned prose and the
|
|
11
|
+
* consumer's ResponseParser threw "Could not extract JSON from response."
|
|
12
|
+
*
|
|
13
|
+
* Fix: when NO system message exists AND mode !== "text" AND a schema is
|
|
14
|
+
* present, synthesize a system message via formatSystemPrompt("", ...) and
|
|
15
|
+
* prepend it.
|
|
16
|
+
*
|
|
17
|
+
* The Vercel `ai` module is mocked — no real LLM is invoked.
|
|
18
|
+
*/
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=llm-provider-system-synthesis.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-provider-system-synthesis.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/llm-provider-system-synthesis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
|