External Publication
Visit Post

`responses` corrupts previous conversations `assistant` item

OpenAI Developer Community May 2, 2026
Source

The role=system messages are red herrings. I could switch them all to role=developer and it wouldn’t make a difference. It could omit them and it still wouldn’t make a difference. I also tried switching the hard coded assistant messages from EasyInputMessage to a ResponseOutputMessage, that didn’t make a difference either.

It seems like all hard coded assistant messages synthetically inserted into a Conversation using the conversations/conversation_id/items POST endpoint, prior to a responses call that produces an AI generated message will be wiped as soon as the response from that call is returned.

The only way to synthetically insert an assistant message into a Conversation is to create it by making a deterministic call to responses where the message is presented to the AI with a request to simply reply with the exact message. It feels a little hacky in my opinion, but it seems to be the only thing that works. Something like this:

{
  "model": "gpt-5.4-mini",
  "conversation": "conv_...",
  "temperature": 0,
  "input": [
    {
      "role": "developer",
      "content": "Reply EXACTLY with the following text, no deviation:\n\n[HARD CODED ASSISTANT MESSAGE]"
    },
    {
      "role": "user",
      "content": "Start"
    }
  ]
}

To wrap up, here’s an extended bash script that inserts three hard coded assistant messages with different phases, followed by a user message, and then a Responses call, and all the assistant messages get wiped.

#!/usr/bin/env bash
set -eu

: "${OPENAI_API_KEY:?Set OPENAI_API_KEY first}"

BASE="https://api.openai.com/v1"
MODEL="gpt-5.4-mini"

AUTH=(
  -H "Authorization: Bearer $OPENAI_API_KEY"
  -H "Content-Type: application/json"
)

SYSTEM_TEXT="System message containing instructions."
USER_TEXT="Initial user message"
SECOND_USER_TEXT="Second user message before Responses call"
DEVELOPER_TEXT="Has the user provided answers to the outstanding fields? "

list_items() {
  curl -sS --globoff \
    "$BASE/conversations/$CONV_ID/items?order=asc&limit=100" \
    "${AUTH[@]}"
}

retrieve_item() {
  ITEM_ID="$1"
  curl -sS --globoff \
    "$BASE/conversations/$CONV_ID/items/$ITEM_ID" \
    "${AUTH[@]}"
}

echo "1) Create conversation with system message"
CREATE_CONV_RESPONSE=$(
  curl -sS "$BASE/conversations" \
    "${AUTH[@]}" \
    -d "$(jq -n --arg text "$SYSTEM_TEXT" '{
      items: [
        {
          role: "system",
          content: $text,
          type: "message"
        }
      ]
    }')"
)

echo "$CREATE_CONV_RESPONSE" | jq .
CONV_ID=$(echo "$CREATE_CONV_RESPONSE" | jq -r '.id')
echo "CONV_ID=$CONV_ID"

echo
echo "2) Add first user message"
curl -sS "$BASE/conversations/$CONV_ID/items" \
  "${AUTH[@]}" \
  -d "$(jq -n --arg text "$USER_TEXT" '{
    items: [
      {
        type: "message",
        role: "user",
        content: [
          {
            type: "input_text",
            text: $text
          }
        ]
      }
    ]
  }')" | jq .

echo
echo "3) Add assistant messages with different phase variants"

ASSISTANT_IDS=()

for PHASE in "final_answer" "commentary" ""; do
  LABEL="${PHASE:-none}"
  TEXT="Assistant (${LABEL}) message"

  echo "Adding assistant message with phase: ${LABEL}"

  ADD_ASSISTANT_RESPONSE=$(
    curl -sS "$BASE/conversations/$CONV_ID/items" \
      "${AUTH[@]}" \
      -d "$(jq -n \
        --arg text "$TEXT" \
        --arg phase "$PHASE" \
        '{
          items: [
            (
              {
                type: "message",
                role: "assistant",
                content: [
                  {
                    type: "output_text",
                    text: $text
                  }
                ]
              }
              + (if $phase != "" then {phase: $phase} else {} end)
            )
          ]
        }')"
  )

  echo "$ADD_ASSISTANT_RESPONSE" | jq .

  ID=$(echo "$ADD_ASSISTANT_RESPONSE" | jq -r '.data[0].id')
  ASSISTANT_IDS+=("$ID")
done

echo
echo "4) Add SECOND user message"
curl -sS "$BASE/conversations/$CONV_ID/items" \
  "${AUTH[@]}" \
  -d "$(jq -n --arg text "$SECOND_USER_TEXT" '{
    items: [
      {
        type: "message",
        role: "user",
        content: [
          {
            type: "input_text",
            text: $text
          }
        ]
      }
    ]
  }')" | jq .

echo
echo "5) List all items BEFORE Responses call"
LIST_BEFORE=$(list_items)
echo "$LIST_BEFORE" | jq .

echo
echo "6) Verify assistant items exist BEFORE Responses"
for ID in "${ASSISTANT_IDS[@]}"; do
  if echo "$LIST_BEFORE" | jq -e --arg id "$ID" '.data[] | select(.id == $id)' >/dev/null; then
    echo "OK: $ID present"
  else
    echo "ERROR: $ID missing before Responses"
  fi
done

echo
echo "7) Create response using SAME conversation"
CREATE_RESPONSE_RESPONSE=$(
  curl -sS "$BASE/responses" \
    "${AUTH[@]}" \
    -d "$(jq -n \
      --arg model "$MODEL" \
      --arg conv "$CONV_ID" \
      --arg text "$DEVELOPER_TEXT" \
      '{
        model: $model,
        conversation: $conv,
        store: true,
        input: [
          {
            role: "developer",
            type: "message",
            content: $text
          }
        ]
      }')"
)

echo "$CREATE_RESPONSE_RESPONSE" | jq .

echo
echo "8) List all items AFTER Responses call"
LIST_AFTER=$(list_items)
echo "$LIST_AFTER" | jq .

echo
echo "9) Check assistant messages after Responses"

for ID in "${ASSISTANT_IDS[@]}"; do
  echo
  echo "Checking $ID"

  if echo "$LIST_AFTER" | jq -e --arg id "$ID" '.data[] | select(.id == $id)' >/dev/null; then
    echo "❌ Still present in list"
  else
    echo "✅ Missing from list (DISAPPEARED)"
  fi

  RETRIEVE=$(retrieve_item "$ID")
  echo "$RETRIEVE" | jq .

  if echo "$RETRIEVE" | jq -e '
    .role == "unknown"
    and (.content[0].text == "<unknown message>")
  ' >/dev/null; then
    echo "✅ Corrupted to <unknown message>"
  else
    echo "❌ Still valid"
  fi
done

echo
echo "Done."
echo "CONV_ID=$CONV_ID"
echo "ASSISTANT_IDS=${ASSISTANT_IDS[*]}"

I am sure they have a very good reason for why they don’t allow synthetic assistant messages in a conversation, but it is a little frustrating either way. Thank you all for your help figuring this one out!

Discussion in the ATmosphere

Loading comments...