Skip to content

Commit f82fac8

Browse files
declan-scaleclaude
andcommitted
fix(openai): retain multi-turn history in 140_harness_openai tutorial [greptile]
The activity created a fresh agent each turn and passed only the latest user message to Runner.run_streamed, so the model had no memory of prior turns. Thread the running conversation through the workflow instance (self._messages): pass the prior input_list into the activity, build [*history, user_message] for the run, and return result.to_input_list() so the next turn continues the conversation. The activity now returns RunHarnessAgentResult (final_text + input_list); the workflow deserializes it via result_type. Note: the separate 06-22 "usage always empty in the auto_send path" comment is resolved by the foundation — UnifiedEmitter.auto_send_turn now reads turn.usage() AFTER auto_send drains the stream (no eager capture). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 84f99f4 commit f82fac8

2 files changed

Lines changed: 38 additions & 7 deletions

File tree

examples/tutorials/10_async/10_temporal/140_harness_openai/project/activities.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
from __future__ import annotations
1414

15+
from typing import Any
16+
1517
from agents import Runner
1618
from pydantic import BaseModel
1719
from temporalio import activity
@@ -31,25 +33,43 @@ class RunHarnessAgentParams(BaseModel):
3133

3234
task_id: str
3335
user_message: str
36+
# Prior conversation as OpenAI Agents SDK input items, so the agent sees the
37+
# full history (not just the latest message) on every turn.
38+
input_list: list[Any] = []
3439
trace_id: str | None = None
3540
parent_span_id: str | None = None
3641

3742

43+
class RunHarnessAgentResult(BaseModel):
44+
"""Result of one harness turn."""
45+
46+
final_text: str
47+
# Updated conversation (prior history + this turn) to carry into the next turn.
48+
input_list: list[Any]
49+
50+
3851
class HarnessActivities:
3952
"""Hosts the harness-backed OpenAI agent activity."""
4053

4154
@activity.defn(name=RUN_HARNESS_AGENT_ACTIVITY)
42-
async def run_harness_openai_agent(self, params: RunHarnessAgentParams) -> str:
43-
"""Run the agent for one turn and auto-send its output; return final text."""
55+
async def run_harness_openai_agent(self, params: RunHarnessAgentParams) -> RunHarnessAgentResult:
56+
"""Run the agent for one turn and auto-send its output.
57+
58+
Threads the running conversation through ``input_list`` so multi-turn
59+
chats retain memory: prior history + the new user message go in, and the
60+
updated conversation comes back out via ``result.to_input_list()``.
61+
"""
4462
logger.info(f"Running harness OpenAI agent for task {params.task_id}")
4563

4664
agent = create_agent()
47-
result = Runner.run_streamed(starting_agent=agent, input=params.user_message)
65+
input_list: list[Any] = [*params.input_list, {"role": "user", "content": params.user_message}]
66+
result = Runner.run_streamed(starting_agent=agent, input=input_list)
4867
turn = OpenAITurn(result=result, model=MODEL_NAME)
4968
emitter = UnifiedEmitter(
5069
task_id=params.task_id,
5170
trace_id=params.trace_id,
5271
parent_span_id=params.parent_span_id,
5372
)
5473
turn_result = await emitter.auto_send_turn(turn)
55-
return turn_result.final_text
74+
# to_input_list() is valid now: auto_send_turn has exhausted the stream.
75+
return RunHarnessAgentResult(final_text=turn_result.final_text, input_list=result.to_input_list())

examples/tutorials/10_async/10_temporal/140_harness_openai/project/workflow.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
from temporalio.common import RetryPolicy
1818

1919
from agentex.lib import adk
20-
from project.activities import RUN_HARNESS_AGENT_ACTIVITY, RunHarnessAgentParams
20+
from project.activities import (
21+
RUN_HARNESS_AGENT_ACTIVITY,
22+
RunHarnessAgentParams,
23+
RunHarnessAgentResult,
24+
)
2125
from agentex.lib.types.acp import SendEventParams, CreateTaskParams
2226
from agentex.lib.types.tracing import SGPTracingProcessorConfig
2327
from agentex.lib.utils.logging import make_logger
@@ -53,6 +57,9 @@ def __init__(self):
5357
super().__init__(display_name=environment_variables.AGENT_NAME)
5458
self._complete_task = False
5559
self._turn_number = 0
60+
# Running conversation (OpenAI Agents SDK input items) so each turn sees
61+
# the full history, not just the latest user message.
62+
self._messages: list = []
5663

5764
@workflow.signal(name=SignalName.RECEIVE_EVENT)
5865
async def on_task_event_send(self, params: SendEventParams) -> None:
@@ -69,19 +76,23 @@ async def on_task_event_send(self, params: SendEventParams) -> None:
6976
name=f"Turn {self._turn_number}",
7077
input={"message": params.event.content.content},
7178
) as span:
72-
final_text = await workflow.execute_activity(
79+
turn_result = await workflow.execute_activity(
7380
RUN_HARNESS_AGENT_ACTIVITY,
7481
RunHarnessAgentParams(
7582
task_id=params.task.id,
7683
user_message=params.event.content.content,
84+
input_list=self._messages,
7785
trace_id=params.task.id,
7886
parent_span_id=span.id if span else None,
7987
),
8088
start_to_close_timeout=timedelta(minutes=5),
8189
retry_policy=RetryPolicy(maximum_attempts=3),
90+
result_type=RunHarnessAgentResult,
8291
)
92+
# Carry the updated conversation into the next turn.
93+
self._messages = turn_result.input_list
8394
if span:
84-
span.output = {"final_output": final_text}
95+
span.output = {"final_output": turn_result.final_text}
8596

8697
@workflow.run
8798
async def on_task_create(self, params: CreateTaskParams) -> str:

0 commit comments

Comments
 (0)