@velum-labs/routekit-gateway 0.9.0 → 0.9.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.
|
@@ -1022,25 +1022,42 @@ export class CodexResponsesBackend extends HttpProviderBackend {
|
|
|
1022
1022
|
...decoder.feed(await response.text()),
|
|
1023
1023
|
...decoder.flush()
|
|
1024
1024
|
];
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
let completed;
|
|
1025
|
+
const completedOutput = [];
|
|
1026
|
+
let completedResponse;
|
|
1027
|
+
for (const event of events) {
|
|
1028
|
+
let payload;
|
|
1030
1029
|
try {
|
|
1031
|
-
|
|
1030
|
+
payload = JSON.parse(event.data);
|
|
1032
1031
|
}
|
|
1033
1032
|
catch {
|
|
1033
|
+
if (event.event !== "response.output_item.done" &&
|
|
1034
|
+
event.event !== "response.completed") {
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1034
1037
|
throw new SseParseError("provider SSE event contained malformed JSON", event.data.slice(0, 200));
|
|
1035
1038
|
}
|
|
1036
|
-
if (typeof
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1039
|
+
if (typeof payload !== "object" || payload === null)
|
|
1040
|
+
continue;
|
|
1041
|
+
const record = payload;
|
|
1042
|
+
const eventType = event.event ?? record.type;
|
|
1043
|
+
if (eventType === "response.output_item.done" &&
|
|
1044
|
+
typeof record.item === "object" &&
|
|
1045
|
+
record.item !== null) {
|
|
1046
|
+
completedOutput.push(record.item);
|
|
1043
1047
|
}
|
|
1048
|
+
if (eventType === "response.completed" &&
|
|
1049
|
+
typeof record.response === "object" &&
|
|
1050
|
+
record.response !== null) {
|
|
1051
|
+
completedResponse = record.response;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
if (completedResponse !== undefined) {
|
|
1055
|
+
const terminalOutput = completedResponse.output;
|
|
1056
|
+
const payload = (!Array.isArray(terminalOutput) || terminalOutput.length === 0) &&
|
|
1057
|
+
completedOutput.length > 0
|
|
1058
|
+
? { ...completedResponse, output: completedOutput }
|
|
1059
|
+
: completedResponse;
|
|
1060
|
+
return jsonResponse(chatCompletion(model, responsesOutput(payload), normalizedOpenAiUsage(payload.usage)));
|
|
1044
1061
|
}
|
|
1045
1062
|
throw new SseParseError("provider SSE stream ended without response.completed");
|
|
1046
1063
|
}
|
|
@@ -393,6 +393,50 @@ test("Codex subscription egress forces SSE and omits unsupported sampling", asyn
|
|
|
393
393
|
globalThis.fetch = original;
|
|
394
394
|
}
|
|
395
395
|
});
|
|
396
|
+
test("Codex subscription egress recovers output from completed stream items", async () => {
|
|
397
|
+
const original = globalThis.fetch;
|
|
398
|
+
globalThis.fetch = async () => sse([
|
|
399
|
+
{
|
|
400
|
+
data: {
|
|
401
|
+
type: "response.output_item.done",
|
|
402
|
+
item: {
|
|
403
|
+
type: "message",
|
|
404
|
+
role: "assistant",
|
|
405
|
+
content: [{ type: "output_text", text: "ok" }]
|
|
406
|
+
},
|
|
407
|
+
output_index: 0
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
data: {
|
|
412
|
+
type: "response.completed",
|
|
413
|
+
response: {
|
|
414
|
+
output: [],
|
|
415
|
+
usage: { input_tokens: 8, output_tokens: 5, total_tokens: 13 }
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
]);
|
|
420
|
+
try {
|
|
421
|
+
const backend = new CodexResponsesBackend({
|
|
422
|
+
baseUrl: "https://chatgpt.test/backend-api/codex",
|
|
423
|
+
apiKey: "oauth",
|
|
424
|
+
defaultModel: "gpt-5.4-mini",
|
|
425
|
+
forceStream: true,
|
|
426
|
+
omitSampling: true
|
|
427
|
+
});
|
|
428
|
+
const response = await backend.chat({
|
|
429
|
+
stream: false,
|
|
430
|
+
messages: [{ role: "user", content: "Say ok" }]
|
|
431
|
+
});
|
|
432
|
+
const body = (await response.json());
|
|
433
|
+
assert.equal(body.choices[0]?.message.content, "ok");
|
|
434
|
+
assert.equal(body.usage.completion_tokens, 5);
|
|
435
|
+
}
|
|
436
|
+
finally {
|
|
437
|
+
globalThis.fetch = original;
|
|
438
|
+
}
|
|
439
|
+
});
|
|
396
440
|
test("Anthropic streaming egress preserves tool calls and terminal usage", async () => {
|
|
397
441
|
const original = globalThis.fetch;
|
|
398
442
|
globalThis.fetch = async () => sse([
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velum-labs/routekit-gateway",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.2",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/velum-labs/handoffkit.git",
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"zod": "4.4.3",
|
|
30
|
-
"@velum-labs/routekit-
|
|
31
|
-
"@velum-labs/routekit-
|
|
32
|
-
"@velum-labs/routekit-
|
|
33
|
-
"@velum-labs/routekit-
|
|
30
|
+
"@velum-labs/routekit-registry": "0.9.2",
|
|
31
|
+
"@velum-labs/routekit-contracts": "0.9.2",
|
|
32
|
+
"@velum-labs/routekit-tracing": "0.9.2",
|
|
33
|
+
"@velum-labs/routekit-runtime": "0.9.2"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
36
36
|
"routekit",
|