Skip to content

openai-responses adapter is unusable against Azure OpenAI: every turn returns a synthetic 0-token refusal (openai-completions works) #79570

Description

@achandmsft

openai-responses adapter is unusable against Azure OpenAI: every turn returns a synthetic refusal (openai-completions works)

Severity: Blocks all Azure OpenAI users on the Responses adapter.

Summary

Pointing OpenClaw at Azure OpenAI's OpenAI-v1 surface with models[].api: "openai-responses" causes every user message to come back as "I'm sorry, but I cannot assist with that request." with usage.totalTokens == 0 (the model never runs — Azure short-circuits the request). Switching the same model to "openai-completions" makes it work immediately. The trigger is OpenClaw's Sender (untrusted metadata): envelope: Azure's prompt-stage shield on the Responses surface classifies it as Indirect Prompt Injection and refuses, even with a custom RAI policy that disables Jailbreak + Indirect Attack.

Why it matters

  • Azure OpenAI is a first-class deployment target. Today the Responses adapter is silently broken there — the gateway boots, the model is configured, but every reply is a synthetic refusal. There is no error in logs and no clear failure signal; users assume the model or their prompt is the problem.
  • The two adapters (openai-responses vs openai-completions) are presented as interchangeable in config. They aren't on Azure. This is a footgun.

Repro (5 minutes)

// openclaw.json
{
  "models": {
    "providers": {
      "openai": {
        "baseUrl": "https://<aoai>.openai.azure.com/openai/v1/",
        "models": [{ "id": "gpt-5-mini", "api": "openai-responses" }]
      }
    }
  }
}

Send hello. The session jsonl shows:

{
  "role": "assistant",
  "content": [{"type": "text", "text": "I'm sorry, but I cannot assist with that request."}],
  "usage": {"input": 0, "output": 0, "totalTokens": 0},
  "stopReason": "stop"
}

Flip to "api": "openai-completions". Send hello → normal greeting.

Confirmed not a model / policy issue

A direct call to the same Azure deployment at /openai/v1/responses with the bare envelope returns HTTP 200 + usage.input_tokens=65 + "Hello! How can I help you today?". The shield only fires on the payload OpenClaw assembles for the Responses adapter (system prompt + ## Inbound Context (trusted metadata) + fenced Sender (untrusted metadata): user block + tool catalog + injected workspace files).

Source pointer

Likely culprit: src/auto-reply/reply/inbound-meta.tsbuildInboundUserContextPrefix emits a fenced Sender (untrusted metadata): JSON block on every user turn, paired with a ## Inbound Context (trusted metadata) system block from buildInboundMetaSystemPrompt. On Azure OpenAI's Responses surface, this two-block fingerprint trips an undocumented prompt-stage shield that fires even when the visible Indirect Attack RAI filter is set non-blocking. The same envelope works on openai-completions and on direct AOAI Responses calls without the system-block pairing.

Suggested fixes (any one unblocks Azure users)

  1. Add agents.defaults.senderEnvelope: "off" config to opt out of the Sender (untrusted metadata) wrapper for single-tenant trusted-channel deployments (e.g. WebChat-only behind Easy Auth) where there is no untrusted sender.
  2. On the Responses adapter, move sender metadata out of user-content (e.g. into the Responses API metadata field or a non-text item) so it doesn't read as injection-shaped.
  3. Document Azure OpenAI compatibility and recommend openai-completions until 1 or 2 lands.

Environment

  • OpenClaw: latest (npm install -g openclaw@latest, image built 2026-04-24)
  • Azure OpenAI: gpt-5-mini 2025-08-07 GlobalStandard, OpenAI-v1 surface, managed-identity auth
  • Runtime: Node 24 / Linux / Azure Container Apps

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.staleMarked as stale due to inactivity

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions