fix(combo): strip omniModel tags from outbound streaming responses (#585)
The <omniModel> tag was leaking into user-visible content when context_cache_protection was enabled on a combo. The tag is an internal marker for model pinning across conversation turns. Fix: Add a second TransformStream pass (sanitize) that strips the tag from SSE chunk content before delivery to the client. The tag is still injected for round-trip context pinning but cleaned from visible output. Also adds X-OmniRoute-Model response header as a cleaner metadata channel. Closes #585
This commit is contained in:
@@ -522,10 +522,33 @@ export async function handleComboChat({
|
||||
},
|
||||
});
|
||||
|
||||
const transformedStream = res.body.pipeThrough(transform);
|
||||
// FIX #585: Sanitize outbound stream — strip <omniModel> tags from
|
||||
// visible content so they don't leak to the user. The tag is still
|
||||
// present in the full response for round-trip context pinning, but
|
||||
// we clean it from each SSE chunk's content field before delivery.
|
||||
const sanitize = new TransformStream({
|
||||
transform(chunk, controller) {
|
||||
const text = decoder.decode(chunk, { stream: true });
|
||||
// Only run replacement if the chunk actually contains the tag
|
||||
if (text.includes("<omniModel>")) {
|
||||
const cleaned = text.replace(
|
||||
/(?:\\\\n|\\n)?<omniModel>[^<]+<\/omniModel>(?:\\\\n|\\n)?/g,
|
||||
""
|
||||
);
|
||||
controller.enqueue(encoder.encode(cleaned));
|
||||
} else {
|
||||
controller.enqueue(chunk);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const transformedStream = res.body.pipeThrough(transform).pipeThrough(sanitize);
|
||||
// Add model info as response header for clients that support it
|
||||
const headers = new Headers(res.headers);
|
||||
headers.set("X-OmniRoute-Model", modelStr);
|
||||
return new Response(transformedStream, {
|
||||
status: res.status,
|
||||
headers: res.headers,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
: handleSingleModel;
|
||||
|
||||
Reference in New Issue
Block a user