Skip to content

Commit 5c8a50b

Browse files
committed
Merge reasoning content leak fix
2 parents 71be63d + ab587b7 commit 5c8a50b

5 files changed

Lines changed: 63 additions & 15 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rerouted",
3-
"version": "0.4.9",
3+
"version": "0.4.10",
44
"description": "A macOS menu-bar router for accounts, models, and automatic fallback.",
55
"author": "gitcommit90",
66
"license": "MIT",

src/lib/providers/chatgpt.js

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -483,19 +483,15 @@ async function pipeResponsesSse(
483483
}
484484

485485
let delta = "";
486-
if (type === "response.output_text.delta" && typeof data.delta === "string") delta = data.delta;
487-
else if (type === "response.output_text.delta" && data.delta?.text) delta = data.delta.text;
488-
else if (type === "response.output_text.delta" && typeof data.text === "string")
489-
delta = data.text;
490-
else if (data.delta?.content) {
491-
for (const c of data.delta.content) {
492-
if (c.type === "output_text" || c.type === "text") delta += c.text || "";
486+
if (type === "response.output_text.delta") {
487+
if (typeof data.delta === "string") delta = data.delta;
488+
else if (data.delta?.text) delta = data.delta.text;
489+
else if (typeof data.text === "string") delta = data.text;
490+
else if (Array.isArray(data.delta?.content)) {
491+
for (const c of data.delta.content) {
492+
if (c.type === "output_text" || c.type === "text") delta += c.text || "";
493+
}
493494
}
494-
} else if (
495-
type !== "response.function_call_arguments.delta" &&
496-
typeof data.delta === "string"
497-
) {
498-
delta = data.delta;
499495
}
500496

501497
if (delta) {

tests/chatgpt-tools.test.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,56 @@ describe("ChatGPT Responses tool translation", () => {
311311
assert.equal(next.input[1].encrypted_content, "encrypted-json-reasoning");
312312
});
313313

314+
it("keeps structured reasoning out of visible JSON and streaming content", async () => {
315+
const json = chatgpt.fromResponsesJson(
316+
{
317+
output: [
318+
{
319+
id: "rs_hidden",
320+
type: "reasoning",
321+
summary: [{ type: "summary_text", text: "Private planning" }],
322+
},
323+
{
324+
type: "message",
325+
role: "assistant",
326+
content: [{ type: "output_text", text: "Visible answer" }],
327+
},
328+
],
329+
},
330+
"gpt-5.6-sol"
331+
);
332+
assert.equal(json.choices[0].message.content, "Visible answer");
333+
334+
const events = [
335+
{
336+
type: "response.reasoning_summary_text.delta",
337+
delta: "Private streamed planning",
338+
},
339+
{ type: "response.output_text.delta", delta: "Visible streamed answer" },
340+
{ type: "response.completed" },
341+
].map((event) => `data: ${JSON.stringify(event)}\n\n`);
342+
343+
const collected = await chatgpt.pipeResponsesSse(
344+
Readable.from(events),
345+
null,
346+
"gpt-5.6-sol",
347+
{ collect: true }
348+
);
349+
assert.equal(collected.choices[0].message.content, "Visible streamed answer");
350+
351+
const writes = [];
352+
await chatgpt.pipeResponsesSse(
353+
Readable.from(events),
354+
{ write(chunk) { writes.push(chunk); } },
355+
"gpt-5.6-sol"
356+
);
357+
const visibleContent = parseSseWrites(writes)
358+
.map((chunk) => chunk.choices[0].delta.content || "")
359+
.join("");
360+
assert.equal(visibleContent, "Visible streamed answer");
361+
assert.doesNotMatch(writes.join(""), /Private streamed planning/);
362+
});
363+
314364
it("replays multiple reasoning phases once in their original call order", () => {
315365
const first = chatgpt.fromResponsesJson(
316366
{

tests/xai.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ describe("xAI OAuth Responses transport", () => {
197197
it("collects non-stream output and relays streaming output and errors", async () => {
198198
const events = [
199199
'event: response.created\ndata: {"type":"response.created"}\n\n',
200+
'event: response.reasoning_summary_text.delta\ndata: {"type":"response.reasoning_summary_text.delta","delta":"Private planning"}\n\n',
200201
'event: response.output_text.delta\ndata: {"type":"response.output_text.delta","delta":"Hel"}\n\n',
201202
'event: response.output_text.delta\ndata: {"type":"response.output_text.delta","delta":"lo"}\n\n',
202203
'event: response.completed\ndata: {"type":"response.completed"}\n\n',
@@ -216,6 +217,7 @@ describe("xAI OAuth Responses transport", () => {
216217
const output = chunks.join("");
217218
assert.match(output, /chat\.completion\.chunk/);
218219
assert.match(output, /\[DONE\]/);
220+
assert.doesNotMatch(output, /Private planning/);
219221

220222
await assert.rejects(
221223
xai.pipeResponsesSse(

0 commit comments

Comments
 (0)