Skip to content

[Bug] openai-chat V2 spawn_agent emits empty arguments when message schema contains encrypted:true #1774

Description

@ZHJay

Client or integration

Codex App

Provider or upstream service

burnopenai (OpenAI-compatible Chat Completions upstream through the openai-chat adapter)

OpenCodex version

2.19.0 (also present by static inspection on current dev at c71c827)

Endpoint or capability

/v1/responses to openai-chat / Chat Completions translation; V2 collaboration spawn_agent tool calls

Current behaviour

With V2 collaboration enabled and a routed openai-chat parent, Codex supplies a complete spawn_agent schema whose required message property carries the Responses-only annotation encrypted: true.

OpenCodex preserves required: ["message"], but also forwards the non-standard annotation unchanged in tools[].function.parameters to the Chat Completions upstream. In the reproduced provider/model combination, the upstream then emits a spawn_agent call with zero argument bytes; OpenCodex normalizes that to {}, and Codex rejects it because message is missing. No child agent is created, and the parent retries.

One archived session produced 24 spawn_agent calls: 24/24 had arguments exactly {}, and all 24 corresponding tool results reported missing field message.

The generic openai-chat path still forwards the annotation on current dev; only the Zen-specific schema sanitizer currently drops it.

Expected behaviour

At the Responses to Chat Completions adapter boundary, OpenCodex should remove the Responses-only encrypted schema annotation before serializing Chat Completions tools, while preserving:

  • required: ["message"] and all other supported schema constraints;
  • legitimate tool property/definition names that are literally encrypted;
  • literal data under keywords such as const, default, enum, and examples.

Native OpenAI Responses passthrough should continue to preserve the annotation. The routed parent should emit a valid, non-empty message and create the child once.

Minimal redacted request or reproduction

# Environment
# OpenCodex 2.19.0, macOS, V2 collaboration
# Parent: burnopenai/gpt-5.6-sol, reasoning effort xhigh

# 1. Start a fresh Codex App task using the routed parent.
# 2. Ask it to delegate exactly one self-contained task with spawn_agent.
# 3. Observe repeated empty spawn_agent calls and no child creation.

# The incoming schema at the adapter boundary contains:
{
  "type": "object",
  "properties": {
    "message": { "type": "string", "encrypted": true }
  },
  "required": ["message"]
}

# On unmodified 2.19.0, createOpenAIChatAdapter(...).buildRequest(...)
# serializes the same message schema to tools[].function.parameters,
# including encrypted:true.

A controlled forced-tool A/B used the same upstream, model, prompt, and spawn_agent tool:

message schema contains encrypted:true  -> arguments are empty ("" / {})
only the encrypted annotation removed   -> {"message":"Reply exactly: READY"}

The result was the same for flat and namespace: collaboration tool shapes, which rules out namespace conversion as the differentiator.

Actual response or error

function_call name=spawn_agent namespace=collaboration arguments={}
function_call_output failed to parse function arguments: missing field message at line 1 column 2

# Redacted session totals:
spawn_agent calls: 24
arguments exactly {}: 24
missing-field-message errors: 24
children created: 0

Upstream documentation

No public provider or JSON Schema specification was found for the Codex encrypted annotation. It is identified in this repository as a Responses/ChatGPT-backend-only marker introduced by upstream OpenAI Codex, and the same compatibility class was confirmed and fixed for Google/Kiro in #85 and defensively handled by the Anthropic adapter.

The concrete client requirement is that Responses-private schema metadata must not change required Chat Completions tool-call arguments during protocol translation.

Suggested mapping or implementation notes

Sanitize tool parameter schemas once in the generic openai-chat adapter before provider-specific Chat Completions formatting. Strip encrypted only when it is a schema keyword, not when it is a property/definition name or literal JSON data. The existing Anthropic implementation already distinguishes schema-name maps and literal-value keywords and may be a useful precedent.

A focused regression should assert that nested annotations are removed, required: ["message"] survives, a property literally named encrypted survives, literal encrypted data survives, and the input schema is not mutated.

I am happy to prepare a focused PR with the adapter fix and behavior-contract regression test.

Additional context and attachments

Checks

  • I searched existing provider and compatibility issues.
  • The request and response were redacted.
  • The expected behaviour is based on an upstream specification or a concrete client requirement.

Metadata

Metadata

Assignees

No one assigned

    Labels

    providerProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reports

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions