Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 22 additions & 30 deletions docs/running_agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,25 +143,16 @@ from openai import AsyncOpenAI
client = AsyncOpenAI()

async def main():
agent = Agent(name="Assistant", instructions="Reply very concisely.")

# Create a server-managed conversation
conversation = await client.conversations.create()
conv_id = conversation.id
conv_id = conversation.id

agent = Agent(name="Assistant", instructions="Reply very concisely.")

# First turn
result1 = await Runner.run(agent, "What city is the Golden Gate Bridge in?", conversation_id=conv_id)
print(result1.final_output)
# San Francisco

# Second turn reuses the same conversation_id
result2 = await Runner.run(
agent,
"What state is it in?",
conversation_id=conv_id,
)
print(result2.final_output)
# California
while True:
user_input = input("You: ")
result = await Runner.run(agent, user_input, conversation_id=conv_id)
print(f"Assistant: {result.final_output}")
```

#### 2. Using `previous_response_id`
Expand All @@ -174,22 +165,23 @@ from agents import Agent, Runner
async def main():
agent = Agent(name="Assistant", instructions="Reply very concisely.")

# First turn
result1 = await Runner.run(agent, "What city is the Golden Gate Bridge in?")
print(result1.final_output)
# San Francisco

# Second turn, chained to the previous response
result2 = await Runner.run(
agent,
"What state is it in?",
previous_response_id=result1.last_response_id,
)
print(result2.final_output)
# California
previous_response_id = None

while True:
user_input = input("You: ")

# Setting auto_previous_response_id=True enables response chaining automatically
# for the first turn, even when there's no actual previous response ID yet.
result = await Runner.run(
agent,
user_input,
previous_response_id=previous_response_id,
auto_previous_response_id=True,
)
previous_response_id = result.last_response_id
print(f"Assistant: {result.final_output}")
```


## Long running agents & human-in-the-loop

You can use the Agents SDK [Temporal](https://temporal.io/) integration to run durable, long-running workflows, including human-in-the-loop tasks. View a demo of Temporal and the Agents SDK working in action to complete long-running tasks [in this video](https://www.youtube.com/watch?v=fFBZqzT4DD8), and [view docs here](https://github.com/temporalio/sdk-python/tree/main/temporalio/contrib/openai_agents).
Expand Down
51 changes: 44 additions & 7 deletions src/agents/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,21 +129,26 @@ class CallModelData(Generic[TContext]):
@dataclass
class _ServerConversationTracker:
"""Tracks server-side conversation state for either conversation_id or
previous_response_id modes."""
previous_response_id modes.

Note: When auto_previous_response_id=True is used, response chaining is enabled
automatically for the first turn, even when there's no actual previous response ID yet.
"""

conversation_id: str | None = None
previous_response_id: str | None = None
auto_previous_response_id: bool = False
sent_items: set[int] = field(default_factory=set)
server_items: set[int] = field(default_factory=set)

def track_server_items(self, model_response: ModelResponse) -> None:
for output_item in model_response.output:
self.server_items.add(id(output_item))

# Update previous_response_id only when using previous_response_id
# Update previous_response_id when using previous_response_id mode or auto mode
if (
self.conversation_id is None
and self.previous_response_id is not None
and (self.previous_response_id is not None or self.auto_previous_response_id)
and model_response.response_id is not None
):
self.previous_response_id = model_response.response_id
Expand Down Expand Up @@ -284,6 +289,9 @@ class RunOptions(TypedDict, Generic[TContext]):
previous_response_id: NotRequired[str | None]
"""The ID of the previous response, if any."""

auto_previous_response_id: NotRequired[bool]
"""Enable automatic response chaining for the first turn."""

conversation_id: NotRequired[str | None]
"""The ID of the stored conversation, if any."""

Expand All @@ -303,6 +311,7 @@ async def run(
hooks: RunHooks[TContext] | None = None,
run_config: RunConfig | None = None,
previous_response_id: str | None = None,
auto_previous_response_id: bool = False,
conversation_id: str | None = None,
session: Session | None = None,
) -> RunResult:
Expand Down Expand Up @@ -363,6 +372,7 @@ async def run(
hooks=hooks,
run_config=run_config,
previous_response_id=previous_response_id,
auto_previous_response_id=auto_previous_response_id,
conversation_id=conversation_id,
session=session,
)
Expand All @@ -378,6 +388,7 @@ def run_sync(
hooks: RunHooks[TContext] | None = None,
run_config: RunConfig | None = None,
previous_response_id: str | None = None,
auto_previous_response_id: bool = False,
conversation_id: str | None = None,
session: Session | None = None,
) -> RunResult:
Expand Down Expand Up @@ -438,6 +449,7 @@ def run_sync(
previous_response_id=previous_response_id,
conversation_id=conversation_id,
session=session,
auto_previous_response_id=auto_previous_response_id,
)

@classmethod
Expand All @@ -450,6 +462,7 @@ def run_streamed(
hooks: RunHooks[TContext] | None = None,
run_config: RunConfig | None = None,
previous_response_id: str | None = None,
auto_previous_response_id: bool = False,
conversation_id: str | None = None,
session: Session | None = None,
) -> RunResultStreaming:
Expand Down Expand Up @@ -505,6 +518,7 @@ def run_streamed(
hooks=hooks,
run_config=run_config,
previous_response_id=previous_response_id,
auto_previous_response_id=auto_previous_response_id,
conversation_id=conversation_id,
session=session,
)
Expand All @@ -527,14 +541,23 @@ async def run(
hooks = cast(RunHooks[TContext], self._validate_run_hooks(kwargs.get("hooks")))
run_config = kwargs.get("run_config")
previous_response_id = kwargs.get("previous_response_id")
auto_previous_response_id = kwargs.get("auto_previous_response_id", False)
conversation_id = kwargs.get("conversation_id")
session = kwargs.get("session")

if run_config is None:
run_config = RunConfig()

if conversation_id is not None or previous_response_id is not None:
# Check whether to enable OpenAI server-managed conversation
if (
conversation_id is not None
or previous_response_id is not None
or auto_previous_response_id
):
server_conversation_tracker = _ServerConversationTracker(
conversation_id=conversation_id, previous_response_id=previous_response_id
conversation_id=conversation_id,
previous_response_id=previous_response_id,
auto_previous_response_id=auto_previous_response_id,
)
else:
server_conversation_tracker = None
Expand Down Expand Up @@ -773,6 +796,7 @@ def run_sync(
hooks = kwargs.get("hooks")
run_config = kwargs.get("run_config")
previous_response_id = kwargs.get("previous_response_id")
auto_previous_response_id = kwargs.get("auto_previous_response_id", False)
conversation_id = kwargs.get("conversation_id")
session = kwargs.get("session")

Expand Down Expand Up @@ -819,6 +843,7 @@ def run_sync(
hooks=hooks,
run_config=run_config,
previous_response_id=previous_response_id,
auto_previous_response_id=auto_previous_response_id,
conversation_id=conversation_id,
)
)
Expand Down Expand Up @@ -852,6 +877,7 @@ def run_streamed(
hooks = cast(RunHooks[TContext], self._validate_run_hooks(kwargs.get("hooks")))
run_config = kwargs.get("run_config")
previous_response_id = kwargs.get("previous_response_id")
auto_previous_response_id = kwargs.get("auto_previous_response_id", False)
conversation_id = kwargs.get("conversation_id")
session = kwargs.get("session")

Expand Down Expand Up @@ -907,6 +933,7 @@ def run_streamed(
context_wrapper=context_wrapper,
run_config=run_config,
previous_response_id=previous_response_id,
auto_previous_response_id=auto_previous_response_id,
conversation_id=conversation_id,
session=session,
)
Expand Down Expand Up @@ -1035,6 +1062,7 @@ async def _start_streaming(
context_wrapper: RunContextWrapper[TContext],
run_config: RunConfig,
previous_response_id: str | None,
auto_previous_response_id: bool,
conversation_id: str | None,
session: Session | None,
):
Expand All @@ -1047,9 +1075,16 @@ async def _start_streaming(
should_run_agent_start_hooks = True
tool_use_tracker = AgentToolUseTracker()

if conversation_id is not None or previous_response_id is not None:
# Check whether to enable OpenAI server-managed conversation
if (
conversation_id is not None
or previous_response_id is not None
or auto_previous_response_id
):
server_conversation_tracker = _ServerConversationTracker(
conversation_id=conversation_id, previous_response_id=previous_response_id
conversation_id=conversation_id,
previous_response_id=previous_response_id,
auto_previous_response_id=auto_previous_response_id,
)
else:
server_conversation_tracker = None
Expand Down Expand Up @@ -1376,6 +1411,7 @@ async def _run_single_turn_streamed(
previous_response_id = (
server_conversation_tracker.previous_response_id
if server_conversation_tracker
and server_conversation_tracker.previous_response_id is not None
else None
)
conversation_id = (
Expand Down Expand Up @@ -1814,6 +1850,7 @@ async def _get_new_response(
previous_response_id = (
server_conversation_tracker.previous_response_id
if server_conversation_tracker
and server_conversation_tracker.previous_response_id is not None
else None
)
conversation_id = (
Expand Down
Loading