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<TodoItem>) 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>
This commit is contained in:
alliscode
2026-05-07 13:58:00 -07:00
Unverified
parent 2a9b68d1bd
commit 5791203d77
@@ -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<TodoItem>)
// 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(