@neutrome/open-ai-router 0.4.2 → 0.5.1
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/.dev.vars.example +2 -0
- package/README.md +5 -1
- package/package.json +5 -4
- package/src/admission/access.ts +0 -1
- package/src/admission/types.ts +0 -1
- package/src/app/factory.test.ts +40 -34
- package/src/app/factory.ts +120 -173
- package/src/app/google-genai-route.ts +48 -0
- package/src/app/http-utils.ts +14 -0
- package/src/app/model-listing.ts +29 -0
- package/src/app/response-lifecycle.ts +66 -0
- package/src/app/types.ts +38 -0
- package/src/index.ts +11 -43
- package/src/otlp.ts +155 -0
- package/src/router/audit.ts +5 -12
- package/src/router/config.ts +4 -4
- package/src/router/error-codec.ts +170 -0
- package/src/router/errors.ts +38 -1
- package/src/router/execute.test.ts +177 -107
- package/src/router/execute.ts +68 -924
- package/src/router/execution-events.ts +39 -0
- package/src/router/execution-invocation.ts +144 -0
- package/src/router/execution-observation.ts +161 -0
- package/src/router/execution-resolution.ts +120 -0
- package/src/router/execution-runtime.test.ts +156 -83
- package/src/router/execution-runtime.ts +144 -542
- package/src/router/execution-transforms.ts +82 -0
- package/src/router/execution-types.ts +8 -19
- package/src/router/index.ts +6 -5
- package/src/router/mcp.ts +12 -6
- package/src/router/provider-invoker.ts +134 -0
- package/src/router/provider-stream.ts +192 -0
- package/src/router/provider-telemetry.ts +59 -0
- package/src/router/remote-mcp-execution.ts +61 -0
- package/src/router/request-program.ts +16 -0
- package/src/router/request-target.ts +56 -0
- package/src/router/resolve.test.ts +43 -10
- package/src/router/resolve.ts +50 -28
- package/src/router/response-delivery.ts +141 -0
- package/src/router/runtime.test.ts +56 -0
- package/src/router/runtime.ts +79 -9
- package/src/router/targets.ts +3 -1
- package/src/router/upstream-client.ts +137 -0
- package/src/telemetry.test.ts +78 -0
- package/src/telemetry.ts +316 -0
- package/src/trace-labels.ts +29 -0
- package/src/upstream-auth/env.ts +15 -3
- package/src/upstream-auth/proxy.ts +6 -1
- package/src/upstream-auth/registry.ts +3 -1
- package/src/util/glob.ts +1 -1
- package/src/util/model-syntax.ts +3 -3
- package/src/worker.ts +12 -6
- package/worker-configuration.d.ts +195 -164
- package/pnpm-workspace.yaml +0 -4
- package/src/admission/jwt.test.ts +0 -96
- package/src/admission/jwt.ts +0 -221
- package/src/app/handlers.ts +0 -198
- package/src/example.test.ts +0 -377
- package/src/example.ts +0 -73
- package/src/observer.test.ts +0 -54
- package/src/observer.ts +0 -315
- package/src/timing.ts +0 -36
|
@@ -18,7 +18,7 @@ describe("router execution", () => {
|
|
|
18
18
|
config: {
|
|
19
19
|
providers: {
|
|
20
20
|
openrouter: {
|
|
21
|
-
|
|
21
|
+
apiBaseUrl: "https://openrouter.ai/api/v1",
|
|
22
22
|
style: "chat-completions",
|
|
23
23
|
exports: ["*"],
|
|
24
24
|
},
|
|
@@ -35,7 +35,9 @@ describe("router execution", () => {
|
|
|
35
35
|
fetchImpl: vi.fn(async (input, init) => {
|
|
36
36
|
capturedUrl = String(input);
|
|
37
37
|
capturedAuth = new Headers(init?.headers).get("authorization") ?? "";
|
|
38
|
-
capturedBody = JSON.parse(
|
|
38
|
+
capturedBody = JSON.parse(
|
|
39
|
+
decoder.decode(new Uint8Array(init?.body as ArrayBuffer)),
|
|
40
|
+
);
|
|
39
41
|
return new Response(
|
|
40
42
|
JSON.stringify({
|
|
41
43
|
id: "resp_1",
|
|
@@ -78,7 +80,9 @@ describe("router execution", () => {
|
|
|
78
80
|
model: "gpt-4o",
|
|
79
81
|
messages: [{ role: "user", content: "hi" }],
|
|
80
82
|
});
|
|
81
|
-
expect(response.headers.get("x-openairouter-provider-id")).toBe(
|
|
83
|
+
expect(response.headers.get("x-openairouter-provider-id")).toBe(
|
|
84
|
+
"openrouter",
|
|
85
|
+
);
|
|
82
86
|
expect(response.headers.get("x-openairouter-model-id")).toBe("gpt-4o");
|
|
83
87
|
expect(await response.json()).toEqual({
|
|
84
88
|
object: "chat.completion",
|
|
@@ -98,11 +102,13 @@ describe("router execution", () => {
|
|
|
98
102
|
const capturedBodies: Record<string, unknown>[] = [];
|
|
99
103
|
const events: Array<{ kind: string; data?: Record<string, unknown> }> = [];
|
|
100
104
|
const close = vi.fn(async () => {});
|
|
101
|
-
const callTool = vi.fn(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
const callTool = vi.fn(
|
|
106
|
+
async (name: string, args: Record<string, unknown>) => {
|
|
107
|
+
expect(name).toBe("lookup");
|
|
108
|
+
expect(args).toEqual({ id: "42" });
|
|
109
|
+
return { content: [{ type: "text", text: "customer is active" }] };
|
|
110
|
+
},
|
|
111
|
+
);
|
|
106
112
|
const remoteMcpClientFactory: RemoteMcpClientFactory = vi.fn(async () => ({
|
|
107
113
|
callTool,
|
|
108
114
|
close,
|
|
@@ -112,7 +118,7 @@ describe("router execution", () => {
|
|
|
112
118
|
config: {
|
|
113
119
|
providers: {
|
|
114
120
|
openrouter: {
|
|
115
|
-
|
|
121
|
+
apiBaseUrl: "https://openrouter.ai/api/v1",
|
|
116
122
|
style: "chat-completions",
|
|
117
123
|
exports: ["*"],
|
|
118
124
|
},
|
|
@@ -122,15 +128,17 @@ describe("router execution", () => {
|
|
|
122
128
|
type: "mcp_streamable_http",
|
|
123
129
|
url: "https://mcp.example.test/mcp",
|
|
124
130
|
headers: { authorization: "Bearer static" },
|
|
125
|
-
tools: [
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
tools: [
|
|
132
|
+
{
|
|
133
|
+
name: "lookup",
|
|
134
|
+
description: "Look up a customer",
|
|
135
|
+
inputSchema: {
|
|
136
|
+
type: "object",
|
|
137
|
+
properties: { id: { type: "string" } },
|
|
138
|
+
required: ["id"],
|
|
139
|
+
},
|
|
132
140
|
},
|
|
133
|
-
|
|
141
|
+
],
|
|
134
142
|
},
|
|
135
143
|
},
|
|
136
144
|
modelNamespaces: {
|
|
@@ -147,37 +155,48 @@ describe("router execution", () => {
|
|
|
147
155
|
},
|
|
148
156
|
},
|
|
149
157
|
fetchImpl: vi.fn(async (_input, init) => {
|
|
150
|
-
const body = JSON.parse(
|
|
158
|
+
const body = JSON.parse(
|
|
159
|
+
decoder.decode(new Uint8Array(init?.body as ArrayBuffer)),
|
|
160
|
+
);
|
|
151
161
|
capturedBodies.push(body);
|
|
152
162
|
if (capturedBodies.length === 1) {
|
|
153
|
-
expect(body.tools).toEqual([
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
163
|
+
expect(body.tools).toEqual([
|
|
164
|
+
{
|
|
165
|
+
type: "function",
|
|
166
|
+
function: {
|
|
167
|
+
name: "crm__lookup",
|
|
168
|
+
description: "Look up a customer",
|
|
169
|
+
parameters: {
|
|
170
|
+
type: "object",
|
|
171
|
+
properties: { id: { type: "string" } },
|
|
172
|
+
required: ["id"],
|
|
173
|
+
},
|
|
162
174
|
},
|
|
163
175
|
},
|
|
164
|
-
|
|
176
|
+
]);
|
|
165
177
|
return new Response(
|
|
166
178
|
JSON.stringify({
|
|
167
179
|
id: "resp_1",
|
|
168
180
|
model: "gpt-4o",
|
|
169
|
-
choices: [
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
181
|
+
choices: [
|
|
182
|
+
{
|
|
183
|
+
index: 0,
|
|
184
|
+
message: {
|
|
185
|
+
role: "assistant",
|
|
186
|
+
tool_calls: [
|
|
187
|
+
{
|
|
188
|
+
id: "call_1",
|
|
189
|
+
type: "function",
|
|
190
|
+
function: {
|
|
191
|
+
name: "crm__lookup",
|
|
192
|
+
arguments: '{"id":"42"}',
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
finish_reason: "tool_calls",
|
|
178
198
|
},
|
|
179
|
-
|
|
180
|
-
}],
|
|
199
|
+
],
|
|
181
200
|
}),
|
|
182
201
|
{ headers: { "content-type": "application/json; charset=utf-8" } },
|
|
183
202
|
);
|
|
@@ -191,11 +210,13 @@ describe("router execution", () => {
|
|
|
191
210
|
JSON.stringify({
|
|
192
211
|
id: "resp_2",
|
|
193
212
|
model: "gpt-4o",
|
|
194
|
-
choices: [
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
213
|
+
choices: [
|
|
214
|
+
{
|
|
215
|
+
index: 0,
|
|
216
|
+
message: { role: "assistant", content: "done" },
|
|
217
|
+
finish_reason: "stop",
|
|
218
|
+
},
|
|
219
|
+
],
|
|
199
220
|
}),
|
|
200
221
|
{ headers: { "content-type": "application/json; charset=utf-8" } },
|
|
201
222
|
);
|
|
@@ -229,9 +250,17 @@ describe("router execution", () => {
|
|
|
229
250
|
expect(callTool).toHaveBeenCalledOnce();
|
|
230
251
|
expect(close).toHaveBeenCalledOnce();
|
|
231
252
|
expect(capturedBodies).toHaveLength(2);
|
|
232
|
-
expect(
|
|
233
|
-
|
|
234
|
-
|
|
253
|
+
expect(
|
|
254
|
+
events.find((event) => event.kind === "remote_mcp.connect")?.data
|
|
255
|
+
?.durationMs,
|
|
256
|
+
).toEqual(expect.any(Number));
|
|
257
|
+
expect(
|
|
258
|
+
events.find((event) => event.kind === "remote_mcp.tool_call")?.data
|
|
259
|
+
?.durationMs,
|
|
260
|
+
).toEqual(expect.any(Number));
|
|
261
|
+
expect(
|
|
262
|
+
events.find((event) => event.kind === "tool.executed")?.data?.durationMs,
|
|
263
|
+
).toEqual(expect.any(Number));
|
|
235
264
|
expect(await response.json()).toMatchObject({
|
|
236
265
|
choices: [{ message: { content: "done" } }],
|
|
237
266
|
});
|
|
@@ -245,7 +274,7 @@ describe("router execution", () => {
|
|
|
245
274
|
config: {
|
|
246
275
|
providers: {
|
|
247
276
|
openai: {
|
|
248
|
-
|
|
277
|
+
apiBaseUrl: "https://api.openai.com/v1",
|
|
249
278
|
style: "responses",
|
|
250
279
|
exports: ["*"],
|
|
251
280
|
},
|
|
@@ -261,17 +290,21 @@ describe("router execution", () => {
|
|
|
261
290
|
},
|
|
262
291
|
fetchImpl: vi.fn(async (input, init) => {
|
|
263
292
|
capturedUrl = String(input);
|
|
264
|
-
capturedBody = JSON.parse(
|
|
293
|
+
capturedBody = JSON.parse(
|
|
294
|
+
decoder.decode(new Uint8Array(init?.body as ArrayBuffer)),
|
|
295
|
+
);
|
|
265
296
|
return new Response(
|
|
266
297
|
JSON.stringify({
|
|
267
298
|
id: "resp_1",
|
|
268
299
|
model: "gpt-5",
|
|
269
|
-
output: [
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
300
|
+
output: [
|
|
301
|
+
{
|
|
302
|
+
type: "message",
|
|
303
|
+
role: "assistant",
|
|
304
|
+
status: "completed",
|
|
305
|
+
content: [{ type: "output_text", text: "hello" }],
|
|
306
|
+
},
|
|
307
|
+
],
|
|
275
308
|
}),
|
|
276
309
|
{ headers: { "content-type": "application/json; charset=utf-8" } },
|
|
277
310
|
);
|
|
@@ -302,11 +335,13 @@ describe("router execution", () => {
|
|
|
302
335
|
object: "chat.completion",
|
|
303
336
|
id: "resp_1",
|
|
304
337
|
model: "gpt-5",
|
|
305
|
-
choices: [
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
338
|
+
choices: [
|
|
339
|
+
{
|
|
340
|
+
index: 0,
|
|
341
|
+
message: { role: "assistant", content: "hello" },
|
|
342
|
+
finish_reason: "stop",
|
|
343
|
+
},
|
|
344
|
+
],
|
|
310
345
|
});
|
|
311
346
|
});
|
|
312
347
|
|
|
@@ -318,7 +353,7 @@ describe("router execution", () => {
|
|
|
318
353
|
config: {
|
|
319
354
|
providers: {
|
|
320
355
|
anthropic: {
|
|
321
|
-
|
|
356
|
+
apiBaseUrl: "https://api.anthropic.com",
|
|
322
357
|
style: "anthropic-messages",
|
|
323
358
|
exports: ["*"],
|
|
324
359
|
},
|
|
@@ -327,14 +362,19 @@ describe("router execution", () => {
|
|
|
327
362
|
default: {
|
|
328
363
|
exports: ["*"],
|
|
329
364
|
models: {
|
|
330
|
-
"claude-sonnet-4": {
|
|
365
|
+
"claude-sonnet-4": {
|
|
366
|
+
provider: "anthropic",
|
|
367
|
+
model: "claude-sonnet-4",
|
|
368
|
+
},
|
|
331
369
|
},
|
|
332
370
|
},
|
|
333
371
|
},
|
|
334
372
|
},
|
|
335
373
|
fetchImpl: vi.fn(async (input, init) => {
|
|
336
374
|
capturedUrl = String(input);
|
|
337
|
-
capturedBody = JSON.parse(
|
|
375
|
+
capturedBody = JSON.parse(
|
|
376
|
+
decoder.decode(new Uint8Array(init?.body as ArrayBuffer)),
|
|
377
|
+
);
|
|
338
378
|
return new Response(
|
|
339
379
|
JSON.stringify({
|
|
340
380
|
id: "msg_1",
|
|
@@ -377,11 +417,13 @@ describe("router execution", () => {
|
|
|
377
417
|
completion_tokens: 5,
|
|
378
418
|
total_tokens: 15,
|
|
379
419
|
},
|
|
380
|
-
choices: [
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
420
|
+
choices: [
|
|
421
|
+
{
|
|
422
|
+
index: 0,
|
|
423
|
+
message: { role: "assistant", content: "hello" },
|
|
424
|
+
finish_reason: "stop",
|
|
425
|
+
},
|
|
426
|
+
],
|
|
385
427
|
});
|
|
386
428
|
});
|
|
387
429
|
|
|
@@ -393,7 +435,8 @@ describe("router execution", () => {
|
|
|
393
435
|
config: {
|
|
394
436
|
providers: {
|
|
395
437
|
google: {
|
|
396
|
-
|
|
438
|
+
apiBaseUrl:
|
|
439
|
+
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent",
|
|
397
440
|
style: "google-genai",
|
|
398
441
|
exports: ["*"],
|
|
399
442
|
},
|
|
@@ -402,21 +445,28 @@ describe("router execution", () => {
|
|
|
402
445
|
default: {
|
|
403
446
|
exports: ["*"],
|
|
404
447
|
models: {
|
|
405
|
-
"gemini-2.5-flash": {
|
|
448
|
+
"gemini-2.5-flash": {
|
|
449
|
+
provider: "google",
|
|
450
|
+
model: "gemini-2.5-flash",
|
|
451
|
+
},
|
|
406
452
|
},
|
|
407
453
|
},
|
|
408
454
|
},
|
|
409
455
|
},
|
|
410
456
|
fetchImpl: vi.fn(async (input, init) => {
|
|
411
457
|
capturedUrl = String(input);
|
|
412
|
-
capturedBody = JSON.parse(
|
|
458
|
+
capturedBody = JSON.parse(
|
|
459
|
+
decoder.decode(new Uint8Array(init?.body as ArrayBuffer)),
|
|
460
|
+
);
|
|
413
461
|
return new Response(
|
|
414
462
|
JSON.stringify({
|
|
415
463
|
modelVersion: "gemini-2.5-flash",
|
|
416
|
-
candidates: [
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
464
|
+
candidates: [
|
|
465
|
+
{
|
|
466
|
+
content: { parts: [{ text: "hello" }] },
|
|
467
|
+
finishReason: "STOP",
|
|
468
|
+
},
|
|
469
|
+
],
|
|
420
470
|
}),
|
|
421
471
|
{ headers: { "content-type": "application/json; charset=utf-8" } },
|
|
422
472
|
);
|
|
@@ -438,7 +488,9 @@ describe("router execution", () => {
|
|
|
438
488
|
|
|
439
489
|
const response = await handleChatCompletions({ runtime, ctx });
|
|
440
490
|
expect(response.status).toBe(200);
|
|
441
|
-
expect(capturedUrl).toBe(
|
|
491
|
+
expect(capturedUrl).toBe(
|
|
492
|
+
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent",
|
|
493
|
+
);
|
|
442
494
|
expect(capturedBody).toEqual({
|
|
443
495
|
model: "gemini-2.5-flash",
|
|
444
496
|
contents: [{ role: "user", parts: [{ text: "hi" }] }],
|
|
@@ -446,11 +498,13 @@ describe("router execution", () => {
|
|
|
446
498
|
expect(await response.json()).toEqual({
|
|
447
499
|
object: "chat.completion",
|
|
448
500
|
model: "gemini-2.5-flash",
|
|
449
|
-
choices: [
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
501
|
+
choices: [
|
|
502
|
+
{
|
|
503
|
+
index: 0,
|
|
504
|
+
message: { role: "assistant", content: "hello" },
|
|
505
|
+
finish_reason: "stop",
|
|
506
|
+
},
|
|
507
|
+
],
|
|
454
508
|
});
|
|
455
509
|
});
|
|
456
510
|
|
|
@@ -521,7 +575,7 @@ describe("router execution", () => {
|
|
|
521
575
|
config: {
|
|
522
576
|
providers: {
|
|
523
577
|
openrouter: {
|
|
524
|
-
|
|
578
|
+
apiBaseUrl: "https://openrouter.ai/api/v1",
|
|
525
579
|
style: "chat-completions",
|
|
526
580
|
exports: ["*"],
|
|
527
581
|
},
|
|
@@ -543,7 +597,9 @@ describe("router execution", () => {
|
|
|
543
597
|
`data: ${JSON.stringify({
|
|
544
598
|
id: "chunk_1",
|
|
545
599
|
model: "gpt-4o",
|
|
546
|
-
choices: [
|
|
600
|
+
choices: [
|
|
601
|
+
{ index: 0, delta: { role: "assistant", content: "Hi" } },
|
|
602
|
+
],
|
|
547
603
|
})}\n\n`,
|
|
548
604
|
),
|
|
549
605
|
);
|
|
@@ -584,9 +640,11 @@ describe("router execution", () => {
|
|
|
584
640
|
const response = await handleChatCompletions({ runtime, ctx });
|
|
585
641
|
const text = await response.text();
|
|
586
642
|
|
|
587
|
-
expect(response.headers.get("content-type")).toBe(
|
|
588
|
-
|
|
589
|
-
|
|
643
|
+
expect(response.headers.get("content-type")).toBe(
|
|
644
|
+
"text/event-stream; charset=utf-8",
|
|
645
|
+
);
|
|
646
|
+
expect(text).toContain('"content":"Hi"');
|
|
647
|
+
expect(text).toContain('"finish_reason":"stop"');
|
|
590
648
|
expect(text).toContain("data: [DONE]");
|
|
591
649
|
});
|
|
592
650
|
|
|
@@ -595,7 +653,7 @@ describe("router execution", () => {
|
|
|
595
653
|
config: {
|
|
596
654
|
providers: {
|
|
597
655
|
openrouter: {
|
|
598
|
-
|
|
656
|
+
apiBaseUrl: "https://openrouter.ai/api/v1",
|
|
599
657
|
style: "chat-completions",
|
|
600
658
|
exports: ["*"],
|
|
601
659
|
},
|
|
@@ -656,7 +714,7 @@ describe("router execution", () => {
|
|
|
656
714
|
config: {
|
|
657
715
|
providers: {
|
|
658
716
|
anthropic: {
|
|
659
|
-
|
|
717
|
+
apiBaseUrl: "https://api.anthropic.com",
|
|
660
718
|
style: "anthropic-messages",
|
|
661
719
|
exports: ["*"],
|
|
662
720
|
},
|
|
@@ -665,23 +723,30 @@ describe("router execution", () => {
|
|
|
665
723
|
default: {
|
|
666
724
|
exports: ["*"],
|
|
667
725
|
models: {
|
|
668
|
-
"claude-sonnet-4": {
|
|
726
|
+
"claude-sonnet-4": {
|
|
727
|
+
provider: "anthropic",
|
|
728
|
+
model: "claude-sonnet-4",
|
|
729
|
+
},
|
|
669
730
|
},
|
|
670
731
|
},
|
|
671
732
|
},
|
|
672
733
|
},
|
|
673
|
-
fetchImpl: vi.fn(
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
734
|
+
fetchImpl: vi.fn(
|
|
735
|
+
async () =>
|
|
736
|
+
new Response(
|
|
737
|
+
JSON.stringify({
|
|
738
|
+
type: "error",
|
|
739
|
+
error: {
|
|
740
|
+
type: "overloaded_error",
|
|
741
|
+
message: "Provider is overloaded",
|
|
742
|
+
},
|
|
743
|
+
request_id: "req_upstream",
|
|
744
|
+
}),
|
|
745
|
+
{
|
|
746
|
+
status: 529,
|
|
747
|
+
headers: { "content-type": "application/json; charset=utf-8" },
|
|
748
|
+
},
|
|
749
|
+
),
|
|
685
750
|
),
|
|
686
751
|
});
|
|
687
752
|
|
|
@@ -715,12 +780,17 @@ describe("router execution", () => {
|
|
|
715
780
|
code: null,
|
|
716
781
|
},
|
|
717
782
|
});
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
783
|
+
expect(events).toContainEqual(
|
|
784
|
+
expect.objectContaining({
|
|
785
|
+
kind: "provider.fetch_headers",
|
|
786
|
+
data: expect.objectContaining({ status: 529 }),
|
|
787
|
+
}),
|
|
788
|
+
);
|
|
789
|
+
expect(events).toContainEqual(
|
|
790
|
+
expect.objectContaining({
|
|
791
|
+
kind: "execution.failed",
|
|
792
|
+
data: expect.objectContaining({ message: "Provider is overloaded" }),
|
|
793
|
+
}),
|
|
722
794
|
);
|
|
723
|
-
expect(observedError?.data?.lilText).toContain('ERR_MESSAGE "Provider is overloaded"');
|
|
724
|
-
expect(observedError?.data?.lilText).toContain('ERR_DATA "request_id"="req_upstream"');
|
|
725
795
|
});
|
|
726
796
|
});
|