Introduction & Lesson Overview

Welcome back! In the last lesson, you explored the details of the RunResult object and learned how to chain agents together using the OpenAI Agents SDK. You saw how to extract important information from an agent’s run and how to use the to_input_list() method to pass context between agents. This knowledge is essential for building more advanced workflows.

In this lesson, we will focus on a key feature of interactive agents: multi-turn conversations. Many real-world applications — such as chatbots, virtual assistants, and customer support agents — require the ability to remember and build upon previous exchanges. This is what makes interactions feel natural and coherent. By the end of this lesson, you will know how to manage and update conversation history using the to_input_list() method, enabling your agents to handle seamless, multi-turn interactions.

Recap of Agent Results and Conversation History

Let’s briefly review what you learned about the RunResult object. When you run an agent, the SDK returns a RunResult object that contains several useful properties: the original input, a list of new items (such as messages or tool calls), the final output, and the last agent executed. One of the most important features for multi-turn conversations is the to_input_list() method.

The to_input_list() method is designed to make managing conversation history easy. When you call this method on a RunResult object, it returns a list of message dictionaries. Each dictionary has a role (either "user" or "assistant") and a content field containing the text of the message. This format matches what the agent expects as input for the next turn. This method gives you the full conversation history in a format that the agent can understand for the next turn.

Preserving conversation history is crucial in multi-turn interactions. Without it, the agent would treat each message as a brand-new conversation, forgetting everything that happened before. By keeping track of both user and assistant messages, you ensure that the agent can respond in a way that makes sense, referencing earlier parts of the conversation as needed.

Let’s walk through a practical example that demonstrates how to manage a multi-turn conversation using the to_input_list() method.

Step 1: Set Up the Agent and Imports

To begin, import the necessary modules and create your agent. In this example, we’ll make a comedian agent that tells jokes on a given topic.

import asyncio
import json
from agents import Agent, Runner

# Create an agent
agent = Agent(
    name="Comedian",
    instructions="You are a comedian that tells jokes on a given topic",
    model="gpt-4.1"
)

async def main():
    # The main conversation logic will go here

if __name__ == "__main__":
    asyncio.run(main())
Step 2: Initialize Conversation History and Add the First User Message

Start the conversation by initializing an empty conversation history. Then, add the first user message to this history.

# Initialize conversation history as an empty list
conversation_history = []

# Define the first user message
first_message = "Tell me a joke about AI"

# Add the first message to the conversation history
conversation_history.append({"role": "user", "content": first_message})
Step 3: Run the Agent and Display the First Exchange

Pass the conversation history to the agent and print both the user’s message and the agent’s response.

# Run the agent with the current conversation history
result = await Runner.run(
    starting_agent=agent,
    input=conversation_history
)

# Print the user's message and the agent's reply
print(f"User: {first_message}\n")
print(f"Assistant: {result.final_output}\n")

When you run this code, you'll see the user's message and the assistant's reply printed out:

User: Tell me a joke about AI

Assistant: Why did the AI get kicked out of art class?

Because every time it tried to paint, it just kept drawing a blank!
Step 4: Update Conversation History Using to_input_list()

After the agent responds, update the conversation history using the to_input_list() method. This ensures the history now includes both the user’s message and the assistant’s reply.

# Update the conversation history with the agent's output
conversation_history = result.to_input_list()
Step 5: Add a Second User Message and Continue the Conversation

Now, add a second user message to the conversation history and repeat the process to keep the conversation going.

# Define a second user message
second_message = "Tell me another one on the same topic"

# Add the second message to the conversation history
conversation_history.append({"role": "user", "content": second_message})

# Run the agent again with the updated conversation history
result = await Runner.run(
    starting_agent=agent,
    input=conversation_history
)

# Print the user's message and the agent's reply
print(f"User: {second_message}\n")
print(f"Assistant: {result.final_output}\n")

If you try this next bit, you'll get the second user message and the assistant's new response—notice how the agent keeps up with the conversation and already knows the topic:

User: Tell me another one on the same topic

Assistant: Why did the AI break up with its laptop?

Because it found it too *space*-y and not enough *person*-ality!
Step 6: Update and Review the Full Conversation History

Update the conversation history again with the latest result, then print the entire conversation to see how it has evolved.

# Update the conversation history with the latest result
conversation_history = result.to_input_list()

# Print the full conversation history
print(f"Conversation history:\n{json.dumps(conversation_history, indent=2)}")

Once you update and print the conversation history, you'll see the full back-and-forth so far:

Conversation history:
[
  {
    "role": "user",
    "content": "Tell me a joke about AI"
  },
  {
    "id": "msg_6810f0426c9081929bd4d71fb79ca68b0e49e9a42c739291",
    "content": [
      {
        "annotations": [],
        "text": "Why did the AI get kicked out of art class?\n\nBecause every time it tried to paint, it just kept drawing a blank!",
        "type": "output_text"
      }
    ],
    "role": "assistant",
    "status": "completed",
    "type": "message"
  },
  {
    "role": "user",
    "content": "Tell me another one on the same topic"
  },
  {
    "id": "msg_6810f043d02c8192a1b74358be0b91100e49e9a42c739291",
    "content": [
      {
        "annotations": [],
        "text": "Why did the AI break up with its laptop?\n\nBecause it found it too *space*-y and not enough *person*-ality!",
        "type": "output_text"
      }
    ],
    "role": "assistant",
    "status": "completed",
    "type": "message"
  }
]

By following these steps, you can build a natural, back-and-forth conversation with your agent, where each turn builds on the previous ones and the context is preserved throughout.

Summary & Preparation for Practice Exercises

In this lesson, you learned how to manage and update conversation history using the to_input_list() method, enabling your agents to handle seamless multi-turn interactions. You saw how to initialize a conversation, update it with each new message, and pass the evolving history back to the agent. This approach is essential for building interactive applications where context matters.

By following best practices — such as managing token limits and keeping your conversation history well-structured — you can create agents that feel natural and engaging. You are now ready to practice these skills in the upcoming exercises. Keep up the great work, and get ready to build even more powerful and interactive agent experiences!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal