mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
fix(responses): sanitize empty string placeholders from tool-call optional arguments in stream delta accumulation (#1674)
This commit is contained in:
@@ -15,6 +15,9 @@
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **fix(responses):** sanitize empty string placeholders from tool-call optional arguments in stream delta accumulation to avoid breaking strict clients (#1674)
|
||||
- **fix(codex):** prevent unexpected protocol leakage and fabricated instructions on bare chat completion requests without tools (#1686)
|
||||
- **fix(executors):** truncate tools array to 128 items max in GitHub Copilot and OpenCode executors to mitigate 400 Bad Request errors from upstream (#1687)
|
||||
- **fix(chatgpt-web):** bound tls-client native deadlocks so requests never hang forever (#1664)
|
||||
- **fix(codex):** default gpt-5.5 to HTTP transport instead of WebSocket (#1660)
|
||||
- **fix(codex):** [urgent] fix gpt-5.5 websocket transport and model labels (#1656)
|
||||
|
||||
@@ -221,7 +221,27 @@ export function createResponsesApiTransformStream(logger = null) {
|
||||
const closeToolCall = (controller, idx) => {
|
||||
const callId = state.funcCallIds[idx];
|
||||
if (callId && !state.funcItemDone[idx]) {
|
||||
const args = state.funcArgsBuf[idx] || "{}";
|
||||
let args = state.funcArgsBuf[idx] || "{}";
|
||||
|
||||
// Fix #1674: Final cleanup of empty string placeholders that might have been split across delta chunks
|
||||
try {
|
||||
const parsed = JSON.parse(args);
|
||||
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
||||
let modified = false;
|
||||
for (const [k, v] of Object.entries(parsed)) {
|
||||
if (v === "") {
|
||||
delete parsed[k];
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
args = JSON.stringify(parsed);
|
||||
state.funcArgsBuf[idx] = args;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignore malformed JSON
|
||||
}
|
||||
|
||||
emit(controller, "response.function_call_arguments.done", {
|
||||
type: "response.function_call_arguments.done",
|
||||
@@ -484,15 +504,25 @@ export function createResponsesApiTransformStream(logger = null) {
|
||||
|
||||
if (tc.function?.arguments) {
|
||||
const refCallId = state.funcCallIds[tcIdx] || newCallId;
|
||||
let deltaStr = tc.function.arguments;
|
||||
|
||||
// Fix #1674: cx/gpt-5.5 injects empty strings for optional parameters.
|
||||
// We strip these directly from the streaming deltas to avoid breaking strict clients like Claude Code.
|
||||
if (deltaStr.includes('""')) {
|
||||
deltaStr = deltaStr
|
||||
.replace(/,"[a-zA-Z0-9_]+":""/g, "")
|
||||
.replace(/"[a-zA-Z0-9_]+":"",/g, "");
|
||||
}
|
||||
|
||||
if (refCallId) {
|
||||
emit(controller, "response.function_call_arguments.delta", {
|
||||
type: "response.function_call_arguments.delta",
|
||||
item_id: `fc_${refCallId}`,
|
||||
output_index: tcIdx,
|
||||
delta: tc.function.arguments,
|
||||
delta: deltaStr,
|
||||
});
|
||||
}
|
||||
state.funcArgsBuf[tcIdx] += tc.function.arguments;
|
||||
state.funcArgsBuf[tcIdx] += deltaStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,7 @@ test("CodexExecutor.transformRequest injects default instructions, clamps reason
|
||||
const body = {
|
||||
model: "gpt-5-mini",
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
tools: [{ type: "function", function: { name: "test_tool" } }],
|
||||
prompt: "legacy",
|
||||
stream_options: { include_usage: true },
|
||||
instructions: "",
|
||||
|
||||
Reference in New Issue
Block a user