Skip to content

Fix incorrect formatting in OpenAI responses API for tool#125

Open
noorbhatia wants to merge 1 commit intomattt:mainfrom
noorbhatia:fix/openai-responses-api
Open

Fix incorrect formatting in OpenAI responses API for tool#125
noorbhatia wants to merge 1 commit intomattt:mainfrom
noorbhatia:fix/openai-responses-api

Conversation

@noorbhatia
Copy link
Contributor

Fix #124

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes incorrect OpenAI Responses API request-body formatting for tool-call round trips in OpenAILanguageModel (Fix #124), aligning it with Responses API conventions rather than Chat Completions conventions.

Changes:

  • Formats function_call_output.output as a direct value (plain string for .text, JSON array for .blocks) instead of JSON-stringifying “content blocks”.
  • Flattens image_url in tool output blocks to a string URL (Responses format).
  • Converts Chat Completions-style raw assistant tool_calls messages into Responses function_call input items.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1083 to +1092
case .string(let role) = dict["role"],
role == "assistant",
case .array(let toolCallsArr) = dict["tool_calls"]
{
for tc in toolCallsArr {
guard case .object(let tcDict) = tc,
case .string(let tcId) = tcDict["id"],
case .object(let fnDict) = tcDict["function"],
case .string(let fnName) = fnDict["name"],
case .string(let fnArgs) = fnDict["arguments"]
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern matches against dict["role"] / dict["tool_calls"] are missing optional unwrapping (?). Since dict[...] is optional (as used elsewhere in this file, e.g. case let .string(type)? = obj["type"]), this won’t compile. Update these to case .string(let role)? = ... / case .array(let toolCallsArr)? = ... (or unwrap with guard let).

Suggested change
case .string(let role) = dict["role"],
role == "assistant",
case .array(let toolCallsArr) = dict["tool_calls"]
{
for tc in toolCallsArr {
guard case .object(let tcDict) = tc,
case .string(let tcId) = tcDict["id"],
case .object(let fnDict) = tcDict["function"],
case .string(let fnName) = fnDict["name"],
case .string(let fnArgs) = fnDict["arguments"]
case .string(let role)? = dict["role"],
role == "assistant",
case .array(let toolCallsArr)? = dict["tool_calls"]
{
for tc in toolCallsArr {
guard case .object(let tcDict) = tc,
case .string(let tcId)? = tcDict["id"],
case .object(let fnDict)? = tcDict["function"],
case .string(let fnName)? = fnDict["name"],
case .string(let fnArgs)? = fnDict["arguments"]

Copilot uses AI. Check for mistakes.
Comment on lines +1089 to +1092
case .string(let tcId) = tcDict["id"],
case .object(let fnDict) = tcDict["function"],
case .string(let fnName) = fnDict["name"],
case .string(let fnArgs) = fnDict["arguments"]
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same optional-pattern issue inside the tool call loop: tcDict["id"], tcDict["function"], fnDict["name"], and fnDict["arguments"] are dictionary subscripts and need ? in the pattern match (or explicit unwrapping). As written, this block won’t compile.

Suggested change
case .string(let tcId) = tcDict["id"],
case .object(let fnDict) = tcDict["function"],
case .string(let fnName) = fnDict["name"],
case .string(let fnArgs) = fnDict["arguments"]
case .string(let tcId)? = tcDict["id"],
case .object(let fnDict)? = tcDict["function"],
case .string(let fnName)? = fnDict["name"],
case .string(let fnArgs)? = fnDict["arguments"]

Copilot uses AI. Check for mistakes.
Comment on lines 1080 to +1105
case .raw(rawContent: let rawContent):
outputs.append(rawContent)
// Convert Chat Completions assistant+tool_calls to Responses API function_call items
if case .object(let dict) = rawContent,
case .string(let role) = dict["role"],
role == "assistant",
case .array(let toolCallsArr) = dict["tool_calls"]
{
for tc in toolCallsArr {
guard case .object(let tcDict) = tc,
case .string(let tcId) = tcDict["id"],
case .object(let fnDict) = tcDict["function"],
case .string(let fnName) = fnDict["name"],
case .string(let fnArgs) = fnDict["arguments"]
else { continue }
outputs.append(
.object([
"type": .string("function_call"),
"call_id": .string(tcId),
"name": .string(fnName),
"arguments": .string(fnArgs),
])
)
}
} else {
outputs.append(rawContent)
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR changes request-body formatting for Responses tool-call round trips, but there’s no deterministic unit test asserting the generated input items (e.g., .raw assistant+tool_callsfunction_call items, and .toolfunction_call_output with a plain string output). Adding a unit test around Responses.createRequestBody would prevent regressions without requiring a live API key.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect formatting in OpenAI Responses API request body for tool calls

1 participant