Sanitize null tool_calls[].type in proxied chat history for GPT-5.4#3101
Conversation
tool_calls[].type in proxied chat history for GPT-5.4
Smoke Test Results
Total: 2/3 PASS
|
Smoke Test: CodexPRs reviewed: #3080 Remove dead Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "registry.npmjs.org"See Network Configuration for more information.
|
Smoke Test: Copilot BYOK (Offline) Mode
Running in BYOK offline mode ( Overall status: FAIL — pre-step template variables were not substituted; tests 1–3 could not be verified.
|
🧪 Smoke Test Results — Copilot Engine
Overall: FAIL — MCP tool returned 401 on PR list query. PR triggered by
|
There was a problem hiding this comment.
Pull request overview
Fixes a proxying bug where Copilot CLI chat history could include messages[].tool_calls[].type = null, causing upstream OpenAI-compatible endpoints (e.g., GPT-5.4) to reject requests with HTTP 400 and making retries ineffective.
Changes:
- Added request-body sanitization in the API proxy to normalize
tool_calls[].type: nullto"function"when a function payload exists, otherwise dropping malformed tool calls. - Added regression tests ensuring the proxied outbound body is sanitized before upstream forwarding.
Show a summary per file
| File | Description |
|---|---|
| containers/api-proxy/proxy-request.js | Adds outbound JSON-body sanitization for null tool_calls[].type and logs normalization/drop counts. |
| containers/api-proxy/server.proxy.test.js | Extends proxy request tests to assert normalization and malformed-entry dropping behavior. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 1
| if (req.method === 'POST' || req.method === 'PUT' || req.method === 'PATCH') { | ||
| const sanitized = sanitizeNullToolCallTypes(body); | ||
| if (sanitized) { | ||
| body = sanitized.body; | ||
| logRequest('info', 'request_sanitized', { | ||
| request_id: requestId, | ||
| provider, | ||
| normalized_tool_calls: sanitized.normalizedCount, | ||
| dropped_tool_calls: sanitized.droppedCount, | ||
| }); | ||
| } | ||
| } |
Smoke Test Results\n\n- GitHub MCP Testing: ❌ (mcpscripts command not found)\n- GitHub.com Connectivity: ❌ (SSL error 35)\n- File Writing Testing: ✅\n- Bash Tool Testing: ✅\n\nOverall status: FAILWarning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "localhost"See Network Configuration for more information.
|
🏗️ Build Test Suite Results
Overall: 8/8 ecosystems passed — ✅ PASS
|
Smoke Test Results
Overall: FAIL —
|
Chroot Smoke Test Results
Overall: FAILED — Python and Node.js versions differ between host and chroot environment.
|
Bug Fix
What was the bug?
GPT-5.4 requests coming from Copilot CLI could include prior messages with
tool_calls[].type = null(notably after edit-tool turns), which OpenAI rejects with HTTP 400 (expected 'function'|'alltools'|'custom'). Retry logic could not recover because the same poisoned history was resent.How did you fix it?
containers/api-proxy/proxy-request.jsthat runs on outbound JSON bodies for POST/PUT/PATCH.messages[*].tool_calls[*]:type: null+ validfunctionpayload → normalize totype: "function".type: nullwithout usable function payload → drop malformed entry.messages.containers/api-proxy/server.proxy.test.jswith focused cases for:Testing
Added regression tests asserting forwarded request bodies are sanitized before upstream dispatch for both:
null -> "function"normalization