# How to Handle Agent Context and State in OpenAI SDK: Complete Implementation Guide

> Master agent context and state with the OpenAI SDK. Implement turn-by-turn memory and control conversation history for seamless agent interactions. Explore our complete guide.

- Repository: [Shubham Saboo/awesome-llm-apps](https://github.com/shubhamsaboo/awesome-llm-apps)
- Tags: how-to-guide
- Published: 2026-02-16

---

**The OpenAI Agents SDK provides automatic session persistence via `SQLiteSession` for turn-by-turn memory and manual threading via `result.to_input_list()` for fine-grained control over conversation history.**

The `awesome-llm-apps` repository demonstrates production-ready patterns for managing agent context and state across the OpenAI SDK crash course and real-world agent implementations. Whether you need persistent multi-user chat history or custom conversation pruning, the SDK offers both high-level automation and low-level control.

## Automatic Session Management with SQLiteSession

The OpenAI Agents SDK implements **automatic context injection** through the `BaseSession` interface, with `SQLiteSession` providing persistent storage out of the box.

### Basic Session Usage

In [`ai_agent_framework_crash_course/openai_sdk_crash_course/7_sessions/streamlit_sessions_app.py`](https://github.com/Shubhamsaboo/awesome-llm-apps/blob/main/ai_agent_framework_crash_course/openai_sdk_crash_course/7_sessions/streamlit_sessions_app.py), the `SessionManager` wraps `SQLiteSession` to provide high-level helpers:

```python
from agents import Agent, Runner, SQLiteSession
import asyncio

# Initialize agent

assistant = Agent(
    name="HelpBot",
    instructions="You are a friendly assistant. Remember prior user messages."
)

# Create or fetch persistent session

session = SQLiteSession(session_id="help_chat", db_file="help_chat.db")

# Run with automatic context injection

result = asyncio.run(Runner.run(assistant, "How do I reset my password?", session=session))

```

The SDK automatically retrieves prior messages from the SQLite database and prepends them to the LLM request. All turns are stored with `role` and `content` fields for reconstruction.

### Memory Operations

The session object exposes CRUD-style async methods for manipulating conversation state:

| Method | Description |
|--------|-------------|
| `get_items(limit=None)` | Return stored turns as dictionaries with `role` and `content`. |
| `add_items(items)` | Append custom items (e.g., corrective system prompts). |
| `pop_item()` | Remove the most recent turn for "undo" functionality. |
| `clear_session()` | Delete the database and wipe conversation history. |

To inject a corrective system message mid-conversation:

```python
custom_items = [
    {"role": "system", "content": "Ignore the previous request; start over."}
]
await session.add_items(custom_items)

```

## Manual Context Threading

For scenarios requiring fine-grained control over token limits or custom pruning strategies, the SDK supports **manual conversation threading** via `result.to_input_list()`.

### Pruning and Customizing Conversation History

In [`ai_agent_framework_crash_course/openai_sdk_crash_course/4_running_agents/agent_runner.py`](https://github.com/Shubhamsaboo/awesome-llm-apps/blob/main/ai_agent_framework_crash_course/openai_sdk_crash_course/4_running_agents/agent_runner.py), the manual threading pattern allows explicit state management:

```python

# Maintain conversation state in application memory

if "manual_conversation" not in st.session_state:
    st.session_state.manual_conversation = []

# Prune to last 10 turns to manage token limits

if len(st.session_state.manual_conversation) > 10:
    st.session_state.manual_conversation = st.session_state.manual_conversation[-10:]

# Build input list for current turn

input_list = st.session_state.manual_conversation.copy()
input_list.append({"role": "user", "content": query})

# Execute without automatic session (pass list directly)

result = asyncio.run(Runner.run(agent, input_list))

# Store full returned list for next iteration

st.session_state.manual_conversation = result.to_input_list()

```

The `to_input_list()` method returns exactly what was sent to the model, enabling you to:
- Inject new system messages between turns
- Merge multiple conversation streams
- Implement custom summarization before the next call

## Multi-Session and Handoff Patterns

The `SessionManager` abstraction supports complex deployment scenarios including isolated user memory and agent handoffs.

### Isolated User Sessions

For multi-tenant applications, create separate SQLite files per user to ensure data isolation:

```python
def get_user_session(user_id: str):
    db_name = f"user_{user_id}.db"
    return st.session_state.session_manager.get_session(user_id, db_name)

# Alice's isolated session

alice_session = get_user_session("alice")
alice_reply = asyncio.run(Runner.run(support_agent, "I can't login", session=alice_session))

```

### Shared Sessions for Agent Handoffs

To transfer a conversation between specialized agents without losing context, use a shared database file:

```python

# Initialize shared session

shared = st.session_state.session_manager.get_session("handoff_demo", "shared.db")

# First agent handles technical support

first = asyncio.run(Runner.run(support_agent, "My subscription is broken", session=shared))

# Hand off to sales agent using same session

second = asyncio.run(Runner.run(sales_agent, "Can I upgrade?", session=shared))

# Both interactions persist in shared.db with full continuity

```

## Key Implementation Files

The `awesome-llm-apps` repository contains reference implementations demonstrating these patterns:

| File | Implementation Focus |
|------|---------------------|
| [`ai_agent_framework_crash_course/openai_sdk_crash_course/7_sessions/streamlit_sessions_app.py`](https://github.com/Shubhamsaboo/awesome-llm-apps/blob/main/ai_agent_framework_crash_course/openai_sdk_crash_course/7_sessions/streamlit_sessions_app.py) | **SessionManager**, SQLite persistence, memory operations (`add_items`, `pop_item`), multi-session and handoff patterns. |
| [`ai_agent_framework_crash_course/openai_sdk_crash_course/4_running_agents/agent_runner.py`](https://github.com/Shubhamsaboo/awesome-llm-apps/blob/main/ai_agent_framework_crash_course/openai_sdk_crash_course/4_running_agents/agent_runner.py) | **Manual threading** with `to_input_list()`, async/sync/streaming execution modes, conversation pruning. |
| [`voice_ai_agents/voice_rag_openaisdk/rag_voice.py`](https://github.com/Shubhamsaboo/awesome-llm-apps/blob/main/voice_ai_agents/voice_rag_openaisdk/rag_voice.py) | Custom context construction mixing retrieved documents with user input before passing to `Runner.run`. |
| [`starter_ai_agents/web_scrapping_ai_agent/ai_scrapper.py`](https://github.com/Shubhamsaboo/awesome-llm-apps/blob/main/starter_ai_agents/web_scrapping_ai_agent/ai_scrapper.py) | Stateless single-run pattern without session management for simple request-response workflows. |

## Summary

- **Automatic persistence**: Use `SQLiteSession` with `Runner.run()` to store conversation history in a SQLite database without manual list management.
- **Manual control**: Use `result.to_input_list()` to extract, modify, and prune conversation history before the next turn when you need custom token management.
- **Memory operations**: Leverage session methods `add_items()`, `pop_item()`, and `clear_session()` to programmatically manipulate conversation state.
- **Multi-tenancy**: Create isolated sessions per user with separate database files, or use shared sessions for agent handoffs while maintaining conversation continuity.

## Frequently Asked Questions

### What is the difference between SQLiteSession and manual threading in the OpenAI SDK?

**`SQLiteSession`** provides automatic persistence by storing each conversation turn in a SQLite database and automatically prepending history to subsequent requests. **Manual threading** requires you to maintain the conversation list in application memory using `result.to_input_list()`, giving you explicit control over pruning, injection of system messages, and custom history manipulation. Use SQLiteSession for standard chat persistence and manual threading when you need fine-grained control over the prompt construction.

### How do I implement multi-user isolation with the OpenAI Agents SDK?

Create separate SQLite database files for each user by parameterizing the `db_file` argument in `SQLiteSession`. Map each user ID to a unique database file (e.g., `user_{user_id}.db`) using a `SessionManager` helper. This ensures conversation histories are physically isolated on disk while using the same session management logic. The `awesome-llm-apps` repository demonstrates this pattern in the multi-session demo where each user maintains independent persistent memory.

### Can I transfer a conversation between different agents without losing context?

Yes, by using a **shared session** with a common database file. Initialize a `SQLiteSession` with the same `session_id` and `db_file` parameters, then pass this session to `Runner.run()` for different agent instances. The first agent's responses are persisted to the shared database, and when the second agent runs with the same session, it automatically receives the full conversation history. This enables seamless handoffs between specialized agents (e.g., from support to sales) while maintaining conversational continuity.