ResponseInputText cannot be used in EasyInputMessage with role "assistant"

Environment

  • Surface: API + SDK
  • Endpoint or feature: Responses
  • Model: gpt-5-nano
  • SDK and version, if applicable: Python SDK 2.9.0

Bug

According to the API Reference for EasyInput, EasyInput.content can accept a list of ResponseInputText.

However, sending such input returns a 400: “Invalid value: ‘input_text’. Supported values are: ‘output_text’ and ‘refusal’.”

Reproduction

import asyncio

from openai import AsyncOpenAI
from openai.types.responses import EasyInputMessageParam, ResponseInputTextParam


async def main():
    async with AsyncOpenAI() as client:
        response = await client.responses.create(
            model="gpt-5-nano",
            input=[
                EasyInputMessageParam(
                    role="user",
                    content=[
                        ResponseInputTextParam(
                            type="input_text",
                            text="who are you?",
                        )
                    ],
                ),
                EasyInputMessageParam(
                    role="assistant",
                    content=[
                        ResponseInputTextParam(
                            type="input_text",
                            text="i am a bot",
                        )
                    ],
                ),
                EasyInputMessageParam(
                    role="assistant",
                    content=[
                        ResponseInputTextParam(
                            type="input_text",
                            text="is there a Rust OpenAI SDK? how mature is it?",
                        )
                    ],
                ),
            ],
        )

        print(response)


if __name__ == "__main__":
    asyncio.run(main())

Note that this snippet is valid according to a type checker (pyright).

Output:

openai.BadRequestError: Error code: 400 - {'error': {'message': "Invalid value: 'input_text'. Supported values are: 'output_text' and 'refusal'.", 'type': 'invalid_request_error', 'param': 'input[1].content[0]', 'code': 'invalid_value'}}

Expected output

The call produces a valid response.

I don’t know that anyone is encouraging using the internal typing to create requests…

I immediately spot something without going to the API reference or its underlying specification:

On Responses, assistant message by role can only be returned as the received output_text content.type of a response, even when placed back in messages that would seem to logically be an input.

Then, you are asking a follow-up question but as “assistant”, again with input_text that collides with that role.

Your corrected “repro” shape.

import asyncio

from openai import AsyncOpenAI
from openai.types.responses import EasyInputMessageParam, ResponseInputTextParam


async def main():
    async with AsyncOpenAI() as client:
        response = await client.responses.create(
            model="gpt-5-nano",
            input=[
                EasyInputMessageParam(
                    role="user",
                    content=[
                        ResponseInputTextParam(
                            type="input_text",
                            text="who are you?",
                        )
                    ],
                ),
                EasyInputMessageParam(
                    role="assistant",
                    content=[
                        ResponseInputTextParam(
                            type="output_text",
                            text="I am a AI language model.",
                        )
                    ],
                ),
                EasyInputMessageParam(
                    role="user",
                    content=[
                        ResponseInputTextParam(
                            type="input_text",
                            text="Do you have a name?",
                        )
                    ],
                ),
            ],
        )

        print(response.output_text)


if __name__ == "__main__":
    asyncio.run(main())

Yes. I’m ChatGPT, a language model created by OpenAI. You can also give me a nickname if you’d like—would you like to name me something special?

Placing the received output back as input, verbatim, will preserve the context, especially when you replay “phase” and the encrypted reasoning output items.

PS: I had to install openai in Python - how little I use the SDK library module.

To add the typing side of this: EasyInputMessageParam.content is typed as str | ResponseInputMessageContentListParam for every role, so pyright can’t see the rule that assistant content has to be output_text. That part is a gap in the generated types, not your code.

If you want something that is both type-clean and accepted by the API, two options in 2.9.0:

from openai.types.responses import (
    EasyInputMessageParam, ResponseOutputMessageParam, ResponseOutputTextParam,
)

# 1. plain string content for the assistant turn
EasyInputMessageParam(role="assistant", content="i am a bot")

# 2. the output message type, which only allows output_text / refusal
ResponseOutputMessageParam(
    type="message",
    role="assistant",
    id="msg_prev_1",
    status="completed",
    content=[ResponseOutputTextParam(type="output_text", text="i am a bot", annotations=[])],
)

ResponseOutputMessageParam is part of the ResponseInputItemParam union, so pyright accepts it inside input=[...]. I ran your repro next to both of these: yours gets the same 400 on input[1].content[0], and both of these get past request validation. Writing ResponseInputTextParam(type="output_text", ...) also works at runtime, but pyright will flag it because that TypedDict’s type is Literal["input_text"].

Separately, your third message is a question sent as assistant. You probably want that one as role="user", otherwise the model sees itself asking the question.