Duplicate Code Opportunity
Summary
- Pattern: Near-identical function for normalizing null
type fields in OpenAI-style tool_calls arrays
- Locations:
containers/api-proxy/providers/copilot.js:187–221 and containers/api-proxy/body-transform.js:12–65
- Impact: ~35 lines of near-duplicate request-body transformation logic; a bug fixed in one function won't automatically be caught in the other
Evidence
copilot.js lines 187–221 — normalizeNullTypeToolCalls:
function normalizeNullTypeToolCalls(body) {
let parsed;
try { parsed = JSON.parse(body.toString('utf8')); } catch { return null; }
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed) || !Array.isArray(parsed.messages))
return null;
let changed = false;
for (const message of parsed.messages) {
if (!message || typeof message !== 'object' || Array.isArray(message) || !Array.isArray(message.tool_calls))
continue;
for (const toolCall of message.tool_calls) {
if (!toolCall || typeof toolCall !== 'object' || Array.isArray(toolCall)) continue;
const hasFunctionPayload = toolCall.function && typeof toolCall.function === 'object' && !Array.isArray(toolCall.function);
if (toolCall.type == null && hasFunctionPayload) {
toolCall.type = 'function';
changed = true;
}
}
}
return changed ? Buffer.from(JSON.stringify(parsed)) : null;
}
body-transform.js lines 12–65 — sanitizeNullToolCallTypes (already an exported shared utility):
function sanitizeNullToolCallTypes(body) {
let parsed;
try { parsed = JSON.parse(body.toString('utf8')); } catch { return null; }
if (!parsed || typeof parsed !== 'object' || !Array.isArray(parsed.messages))
return null;
let changed = false;
let normalizedCount = 0;
let droppedCount = 0;
for (const message of parsed.messages) {
if (!message || typeof message !== 'object' || !Array.isArray(message.tool_calls)) continue;
const nextToolCalls = [];
for (const toolCall of message.tool_calls) {
if (toolCall && typeof toolCall === 'object' && Object.hasOwn(toolCall, 'type') && toolCall.type === null) {
if (toolCall.function && typeof toolCall.function === 'object') {
nextToolCalls.push({ ...toolCall, type: 'function' });
normalizedCount += 1;
} else {
droppedCount += 1;
}
changed = true;
continue;
}
nextToolCalls.push(toolCall);
}
message.tool_calls = nextToolCalls;
}
if (!changed) return null;
return { body: Buffer.from(JSON.stringify(parsed)), normalizedCount, droppedCount };
}
The two functions diverge slightly:
body-transform.js also drops malformed entries (no function payload) and returns { body, normalizedCount, droppedCount }.
copilot.js skips malformed entries silently and returns Buffer|null.
Suggested Refactoring
body-transform.js is already the shared utilities module (module.exports exposes sanitizeNullToolCallTypes). The copilot.js version should be removed and the adapter should delegate to the shared function:
// In copilot.js — remove normalizeNullTypeToolCalls entirely and instead:
const { sanitizeNullToolCallTypes } = require('../body-transform');
// In createCopilotAdapter's bodyTransforms array, replace the local function reference:
(body) => {
const result = sanitizeNullToolCallTypes(body);
return result ? result.body : null;
}
The return-type difference (counted result vs plain Buffer) can be bridged with a one-line wrapper as shown above.
Affected Files
containers/api-proxy/providers/copilot.js — lines 187–221 (function definition), 239 (usage), 413 (export)
containers/api-proxy/body-transform.js — lines 12–65
Effort Estimate
Low
Detected by Duplicate Code Detector workflow. Run date: 2026-05-16
Generated by Duplicate Code Detector · ● 9.9M · ◷
Duplicate Code Opportunity
Summary
typefields in OpenAI-styletool_callsarrayscontainers/api-proxy/providers/copilot.js:187–221andcontainers/api-proxy/body-transform.js:12–65Evidence
copilot.jslines 187–221 —normalizeNullTypeToolCalls:body-transform.jslines 12–65 —sanitizeNullToolCallTypes(already an exported shared utility):The two functions diverge slightly:
body-transform.jsalso drops malformed entries (no function payload) and returns{ body, normalizedCount, droppedCount }.copilot.jsskips malformed entries silently and returnsBuffer|null.Suggested Refactoring
body-transform.jsis already the shared utilities module (module.exportsexposessanitizeNullToolCallTypes). Thecopilot.jsversion should be removed and the adapter should delegate to the shared function:The return-type difference (counted result vs plain Buffer) can be bridged with a one-line wrapper as shown above.
Affected Files
containers/api-proxy/providers/copilot.js— lines 187–221 (function definition), 239 (usage), 413 (export)containers/api-proxy/body-transform.js— lines 12–65Effort Estimate
Low
Detected by Duplicate Code Detector workflow. Run date: 2026-05-16