Skip to content
Changelog

OpenAIResponses recovers when the chained response is gone

October 1, 20261 min read

Agno's OpenAIResponses continues a reasoning model's conversation by sending the last stored response ID as previous_response_id with only the new messages. OpenAI answers a stale, expired or cross-account ID with a 400 that reads Previous response with id '...' not found., and earlier releases raised that as a ModelProviderError while Agno still held the whole conversation.

Now Agno catches that one error, logs a warning, strips the stored response IDs from copies of the messages and sends the request again with the full context. It retries once, on all four paths: sync, async and both streaming modes.

Real output from OpenAIResponses on gpt-5-mini, run against a mocked OpenAI endpoint that rejects an expired previous_response_id. Before, the request carrying previous_response_id resp_expired and one input item fails with ModelProviderError: Previous response with id 'resp_expired' not found. Now, the same request fails, Agno logs a warning that it is retrying with the full context replayed, sends a second request with no previous_response_id and four input items, and returns the answer: Your order number is 4417.

The retry stays narrow. Any other 400 propagates untouched, and a previous_response_id you pinned through request_params is yours, so Agno never replaces it.

The same change fixes two related chaining bugs. With background=True and store=False, Agno forces store=True on the wire, and message formatting and reasoning capture now read that forced value too, so a background request stops sending previous_response_id alongside the full history. And when a stored reasoning model replays a tool call without its reasoning item, Agno leaves out the call's fc_ item ID that OpenAI would reject and keeps the call_id, so tool outputs still pair with their calls.

See the cookbook for turning chaining off with use_previous_response_id=False, and learn more about OpenAI Responses in the documentation.

Frequently asked questions

Agno's OpenAIResponses chains reasoning-model turns through previous_response_id. If that stored response has expired, gone stale or belongs to another account, OpenAI rejects the request with a 400. Earlier releases raised it as a ModelProviderError; this release retries the turn with the full history.

Only a 400 whose message says the previous response was not found, and only once per request. Every other 400 reaches your code unchanged, and so does the error for a previous_response_id you set yourself through request_params.

No. Agno strips the stored response IDs from copies of the messages it sends, so the history saved in your database keeps its IDs.

Set use_previous_response_id=False on OpenAIResponses. Agno then replays the context it builds on every turn, and you can still keep store=True for response logs on OpenAI's side.

Shipped around the same time