@neutrome/open-ai-router 0.3.0 → 0.3.2
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/package.json +3 -3
- package/src/router/execute.ts +48 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neutrome/open-ai-router",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/index.ts"
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
10
10
|
"hono": "^4.12.18",
|
|
11
|
-
"@neutrome/
|
|
12
|
-
"@neutrome/
|
|
11
|
+
"@neutrome/lilsdk-ts": "0.2.1",
|
|
12
|
+
"@neutrome/lil-engine": "0.2.0"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@types/node": "^25.9.3",
|
package/src/router/execute.ts
CHANGED
|
@@ -184,7 +184,6 @@ export async function handleChatCompletions(
|
|
|
184
184
|
const remoteMcp = prepareRemoteMcpExecution(options.runtime, resolved, options);
|
|
185
185
|
const execution = createRouterExecutionRuntime(options.runtime, options.ctx, remoteMcp.options);
|
|
186
186
|
|
|
187
|
-
const startTime = Date.now();
|
|
188
187
|
if (isStreaming(request)) {
|
|
189
188
|
try {
|
|
190
189
|
const chunks = execution.stream(request, { target: remoteMcp.target });
|
|
@@ -192,7 +191,6 @@ export async function handleChatCompletions(
|
|
|
192
191
|
"chat-completions",
|
|
193
192
|
chunks,
|
|
194
193
|
resolved,
|
|
195
|
-
startTime,
|
|
196
194
|
remoteMcp.close,
|
|
197
195
|
);
|
|
198
196
|
} catch (error) {
|
|
@@ -201,6 +199,7 @@ export async function handleChatCompletions(
|
|
|
201
199
|
}
|
|
202
200
|
}
|
|
203
201
|
|
|
202
|
+
const startTime = Date.now();
|
|
204
203
|
try {
|
|
205
204
|
const response = await execution.execute(request, {
|
|
206
205
|
target: remoteMcp.target,
|
|
@@ -262,7 +261,6 @@ async function handleProviderStyle(
|
|
|
262
261
|
const remoteMcp = prepareRemoteMcpExecution(options.runtime, resolved, options);
|
|
263
262
|
const execution = createRouterExecutionRuntime(options.runtime, options.ctx, remoteMcp.options);
|
|
264
263
|
|
|
265
|
-
const startTime = Date.now();
|
|
266
264
|
if (isStreaming(request)) {
|
|
267
265
|
try {
|
|
268
266
|
const chunks = execution.stream(request, { target: remoteMcp.target });
|
|
@@ -270,7 +268,6 @@ async function handleProviderStyle(
|
|
|
270
268
|
style,
|
|
271
269
|
chunks,
|
|
272
270
|
resolved,
|
|
273
|
-
startTime,
|
|
274
271
|
remoteMcp.close,
|
|
275
272
|
);
|
|
276
273
|
} catch (error) {
|
|
@@ -279,6 +276,7 @@ async function handleProviderStyle(
|
|
|
279
276
|
}
|
|
280
277
|
}
|
|
281
278
|
|
|
279
|
+
const startTime = Date.now();
|
|
282
280
|
try {
|
|
283
281
|
const response = await execution.execute(request, {
|
|
284
282
|
target: remoteMcp.target,
|
|
@@ -346,13 +344,16 @@ export function createFetchProviderInvoker(
|
|
|
346
344
|
provider: provider.name,
|
|
347
345
|
model: providerCtx.target.model,
|
|
348
346
|
});
|
|
349
|
-
|
|
347
|
+
let reqBody = emitProviderRequest(provider.style, resolvedRequest);
|
|
348
|
+
if (provider.style === "chat-completions" && isStreaming(resolvedRequest)) {
|
|
349
|
+
reqBody = injectStreamUsage(reqBody);
|
|
350
|
+
}
|
|
350
351
|
const reqBytes = reqBody.byteLength;
|
|
351
352
|
const upstream = await fetchProvider(
|
|
352
353
|
runtime,
|
|
353
354
|
ctx,
|
|
354
355
|
provider,
|
|
355
|
-
|
|
356
|
+
reqBody,
|
|
356
357
|
timed.signal,
|
|
357
358
|
);
|
|
358
359
|
if (!upstream.ok) {
|
|
@@ -392,13 +393,16 @@ export function createFetchProviderInvoker(
|
|
|
392
393
|
provider: provider.name,
|
|
393
394
|
model: providerCtx.target.model,
|
|
394
395
|
});
|
|
395
|
-
|
|
396
|
+
let reqBody = emitProviderRequest(provider.style, resolvedRequest);
|
|
397
|
+
if (provider.style === "chat-completions" && isStreaming(resolvedRequest)) {
|
|
398
|
+
reqBody = injectStreamUsage(reqBody);
|
|
399
|
+
}
|
|
396
400
|
const reqBytes = reqBody.byteLength;
|
|
397
401
|
const upstream = await fetchProvider(
|
|
398
402
|
runtime,
|
|
399
403
|
ctx,
|
|
400
404
|
provider,
|
|
401
|
-
|
|
405
|
+
reqBody,
|
|
402
406
|
timed.signal,
|
|
403
407
|
);
|
|
404
408
|
if (!upstream.ok) {
|
|
@@ -486,41 +490,52 @@ async function streamExecutionResponse(
|
|
|
486
490
|
responseStyle: ProviderStyle,
|
|
487
491
|
chunks: AsyncIterable<Program>,
|
|
488
492
|
resolved: ResolvedTarget,
|
|
489
|
-
startTime: number,
|
|
490
493
|
cleanup?: () => Promise<void>,
|
|
491
494
|
): Promise<Response> {
|
|
492
495
|
const iterator = chunks[Symbol.asyncIterator]();
|
|
493
496
|
|
|
494
497
|
const first = await iterator.next();
|
|
495
|
-
|
|
498
|
+
if (first.done) {
|
|
499
|
+
await cleanup?.();
|
|
500
|
+
const stream = new ReadableStream<Uint8Array>({
|
|
501
|
+
start(controller) {
|
|
502
|
+
if (responseStyle === "chat-completions") {
|
|
503
|
+
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
504
|
+
}
|
|
505
|
+
controller.close();
|
|
506
|
+
},
|
|
507
|
+
});
|
|
508
|
+
return new Response(stream, {
|
|
509
|
+
headers: {
|
|
510
|
+
"content-type": "text/event-stream; charset=utf-8",
|
|
511
|
+
...routingHeaders(resolved),
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
}
|
|
496
515
|
|
|
516
|
+
let done = false;
|
|
497
517
|
const stream = new ReadableStream<Uint8Array>({
|
|
498
|
-
|
|
518
|
+
start(controller) {
|
|
519
|
+
const bytes = emitProviderStreamChunk(responseStyle, first.value);
|
|
520
|
+
controller.enqueue(encoder.encode(`data: ${decoder.decode(bytes)}\n\n`));
|
|
521
|
+
},
|
|
522
|
+
async pull(controller) {
|
|
523
|
+
if (done) return;
|
|
499
524
|
try {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
if (!first.done) {
|
|
508
|
-
emitChunk(first.value);
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
while (true) {
|
|
512
|
-
const { done, value } = await iterator.next();
|
|
513
|
-
if (done) {
|
|
514
|
-
break;
|
|
525
|
+
const result = await iterator.next();
|
|
526
|
+
if (result.done) {
|
|
527
|
+
done = true;
|
|
528
|
+
if (responseStyle === "chat-completions") {
|
|
529
|
+
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
515
530
|
}
|
|
516
|
-
|
|
531
|
+
await cleanup?.();
|
|
532
|
+
controller.close();
|
|
533
|
+
return;
|
|
517
534
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
await cleanup?.();
|
|
522
|
-
controller.close();
|
|
535
|
+
const bytes = emitProviderStreamChunk(responseStyle, result.value);
|
|
536
|
+
controller.enqueue(encoder.encode(`data: ${decoder.decode(bytes)}\n\n`));
|
|
523
537
|
} catch (error) {
|
|
538
|
+
done = true;
|
|
524
539
|
await cleanup?.();
|
|
525
540
|
controller.enqueue(
|
|
526
541
|
encoder.encode(
|
|
@@ -540,7 +555,6 @@ async function streamExecutionResponse(
|
|
|
540
555
|
headers: {
|
|
541
556
|
"content-type": "text/event-stream; charset=utf-8",
|
|
542
557
|
...routingHeaders(resolved),
|
|
543
|
-
...timingHeaders(userTime),
|
|
544
558
|
},
|
|
545
559
|
});
|
|
546
560
|
}
|
|
@@ -628,7 +642,7 @@ async function fetchProvider(
|
|
|
628
642
|
runtime: RouterRuntime,
|
|
629
643
|
ctx: RequestContext,
|
|
630
644
|
provider: ProviderRuntime,
|
|
631
|
-
|
|
645
|
+
body: Uint8Array,
|
|
632
646
|
signal: AbortSignal,
|
|
633
647
|
): Promise<Response> {
|
|
634
648
|
const headers = cloneForwardHeaders(ctx.request.headers);
|
|
@@ -647,10 +661,6 @@ async function fetchProvider(
|
|
|
647
661
|
break;
|
|
648
662
|
}
|
|
649
663
|
|
|
650
|
-
let body = emitProviderRequest(provider.style, request);
|
|
651
|
-
if (provider.style === "chat-completions" && isStreaming(request)) {
|
|
652
|
-
body = injectStreamUsage(body);
|
|
653
|
-
}
|
|
654
664
|
return runtime.fetchImpl(`${provider.apiBaseUrl}${provider.endpointPath}`, {
|
|
655
665
|
method: "POST",
|
|
656
666
|
headers,
|