@@ -21,6 +21,7 @@ const {
2121 createAdapterMethods,
2222 composeBodyTransforms,
2323} = require ( '../proxy-utils' ) ;
24+ const { sanitizeNullToolCallTypes } = require ( '../body-transform' ) ;
2425const { URL } = require ( 'url' ) ;
2526
2627// AWF injects this sentinel value into the agent environment for credential isolation.
@@ -173,51 +174,6 @@ function deriveGitHubApiBasePath(env = process.env) {
173174 }
174175}
175176
176- /**
177- * Normalize OpenAI-style tool calls that omit the required type field.
178- *
179- * Some Copilot/OpenAI-compatible responses can echo tool_calls entries with a
180- * null/undefined `type`, which later causes upstream validation failures when
181- * the same message history is sent back. This transform patches only
182- * function-style tool calls by setting `type: "function"`.
183- *
184- * @param {Buffer } body - Raw request body
185- * @returns {Buffer|null } Updated body or null when no changes are needed
186- */
187- function normalizeNullTypeToolCalls ( body ) {
188- let parsed ;
189- try {
190- parsed = JSON . parse ( body . toString ( 'utf8' ) ) ;
191- } catch {
192- return null ;
193- }
194-
195- if ( ! parsed || typeof parsed !== 'object' || Array . isArray ( parsed ) || ! Array . isArray ( parsed . messages ) ) {
196- return null ;
197- }
198-
199- let changed = false ;
200- for ( const message of parsed . messages ) {
201- if ( ! message || typeof message !== 'object' || Array . isArray ( message ) || ! Array . isArray ( message . tool_calls ) ) {
202- continue ;
203- }
204-
205- for ( const toolCall of message . tool_calls ) {
206- if ( ! toolCall || typeof toolCall !== 'object' || Array . isArray ( toolCall ) ) continue ;
207- const hasFunctionPayload =
208- toolCall . function &&
209- typeof toolCall . function === 'object' &&
210- ! Array . isArray ( toolCall . function ) ;
211- if ( toolCall . type == null && hasFunctionPayload ) {
212- toolCall . type = 'function' ;
213- changed = true ;
214- }
215- }
216- }
217-
218- return changed ? Buffer . from ( JSON . stringify ( parsed ) ) : null ;
219- }
220-
221177/**
222178 * Create the GitHub Copilot provider adapter.
223179 *
@@ -236,7 +192,7 @@ function createCopilotAdapter(env, deps = {}) {
236192
237193 const bodyTransform = composeBodyTransforms (
238194 deps . bodyTransform || null ,
239- normalizeNullTypeToolCalls
195+ ( body ) => { const result = sanitizeNullToolCallTypes ( body ) ; return result ? result . body : null ; }
240196 ) ;
241197
242198 // Pre-computed models path used by getModelsFetchConfig and getReflectionInfo.
@@ -410,7 +366,6 @@ module.exports = {
410366 deriveCopilotApiTarget,
411367 deriveGitHubApiTarget,
412368 deriveGitHubApiBasePath,
413- normalizeNullTypeToolCalls,
414369 COPILOT_PLACEHOLDER_TOKEN ,
415370 } ,
416371} ;
0 commit comments