From 5791203d7745ed13fd5e92725c98e43df227241c Mon Sep 17 00:00:00 2001 From: alliscode Date: Thu, 7 May 2026 13:58:00 -0700 Subject: [PATCH] Fix function_call_output.output to be a JSON string on the wire OutputConverter was passing the JSON serialization of complex tool results (e.g. List) directly into OutputItemFunctionToolCallOutput via BinaryData.FromString. The Responses SDK treats that BinaryData as the *raw JSON value* for the field, so non-string results landed on the wire as an unquoted JSON array (e.g. `"output":[{...}]`) instead of a JSON string. The OpenAI Responses spec requires `function_call_output.output` to be a JSON string. The strict-parsing OpenAI .NET client (FunctionCallOutputResponseItem) consequently failed when threading a follow-up turn that replayed such an item, with: `The JSON value could not be converted... requires an element of type 'String', but the target element has type 'Array'`. Always wrap the payload as a JSON string literal: - string s -> JSON-encode s (quoted, with escapes) - object o -> JSON-serialize o, then JSON-encode the resulting text Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../OutputConverter.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dotnet/src/Microsoft.Agents.AI.Foundry.Hosting/OutputConverter.cs b/dotnet/src/Microsoft.Agents.AI.Foundry.Hosting/OutputConverter.cs index 5d2524fda3..43a8bd5f10 100644 --- a/dotnet/src/Microsoft.Agents.AI.Foundry.Hosting/OutputConverter.cs +++ b/dotnet/src/Microsoft.Agents.AI.Foundry.Hosting/OutputConverter.cs @@ -279,12 +279,24 @@ internal static class OutputConverter accumulatedText = null; previousMessageId = null; - var outputText = functionResult.Result switch + // The OpenAI Responses spec requires `function_call_output.output` to + // be a JSON string. The Responses SDK's OutputItemFunctionToolCallOutput + // accepts a BinaryData containing the *raw JSON value* for the field, so + // we must always wrap the payload as a JSON string literal: + // - string s → JSON-encode s (quoted, with escapes) + // - object o → JSON-serialize o, then JSON-encode the resulting text + // Without this wrapping, complex tool results (e.g. List) + // would land on the wire as an unquoted JSON array, which the strict- + // parsing OpenAI .NET client (FunctionCallOutputResponseItem) rejects + // with "requires an element of type 'String', but the target element + // has type 'Array'". + string innerText = functionResult.Result switch { null => string.Empty, string s => s, _ => JsonSerializer.Serialize(functionResult.Result), }; + string outputText = JsonSerializer.Serialize(innerText); var itemId = GenerateItemId("fc"); var outputItem = new OutputItemFunctionToolCallOutput(