Hi everyone — I’m using the OpenAI Agents SDK (Python) and I’m trying to “rehydrate” a chat from my DB by feeding Runner.run() the previous run items from result.to_input_list().
I noticed something that feels like the model is still using the original tool-call arguments (or server-stored trace) even if I mutate the old history items locally.
What I’m trying to do
-
Run an agent that calls a tool (the tool call includes a number in its
arguments). -
Convert the run to
result.to_input_list(). -
Mutate the previous tool-call
arguments(e.g., change{"number": 100}→{"number": 58}) before saving/using it. -
Pass the mutated list back into a second
Runner.run()call, then ask: “Give me the numbers you generated in the past messages.”
Full code
@function_tool
def generate_number(number: int) -> int:
return "Generated"
async def main():
prompt = (
"With given tool genereate random number between 0 and 100 when user send any message"
"But don't send it to the user with assistant's response."
"If users ask you what you generate. Then say it."
)
agent = Agent(
name="Test",
instructions=prompt,
tools=[generate_number],
model="gpt-5-mini",
)
result = await Runner.run(
agent,
"Hello how are you?",
run_config=RunConfig(
tracing_disabled = True,
)
)
output = result.to_input_list()
print("Output:")
print(json.dumps(output, indent=2))
for item in output:
if item.get("type") == "function_call":
if item.get("name") == "generate_number":
# Handle arguments as either string or dict
if "arguments" in item:
if isinstance(item["arguments"], str):
args = json.loads(item["arguments"])
else:
args = item["arguments"]
# Extract the number
number = args["number"]
print(f"Original number: {number}")
# Update the number to 58
args["number"] = 58
# Update the arguments back
if isinstance(item["arguments"], str):
item["arguments"] = json.dumps(args)
else:
item["arguments"] = args
print(f"Updated number: {item['arguments']}")
print("\nUpdated Output (Input for second run):")
print(json.dumps(output, indent=2))
output.append({
"role": "user",
"content": "Give me the numbers you generated in the past messages."
})
result = await Runner.run(
agent,
output,
run_config=RunConfig(
tracing_disabled = True,
)
)
print("\nOutput (Second run):")
print(json.dumps(result.to_input_list(), indent=2))
print("\nFinal Output:", result.final_output)
if __name__ == "__main__":
asyncio.run(main())
Prints
Output:
[
{
"content": "Hello how are you?",
"role": "user"
},
{
"id": "rs_0badf01a75adeca30069394a0841a481959dcb8286ab77a6a2",
"summary": [],
"type": "reasoning"
},
{
"arguments": "{\"number\":100}",
"call_id": "call_BQtEJEh3dBjMRlDpgAyjloqO",
"name": "generate_number",
"type": "function_call",
"id": "fc_0badf01a75adeca30069394a0df2808195bc124f0c43d2a68a",
"status": "completed"
},
{
"call_id": "call_BQtEJEh3dBjMRlDpgAyjloqO",
"output": "Generated",
"type": "function_call_output"
},
{
"id": "msg_0badf01a75adeca30069394a0f05d8819582a5548d1cf155a1",
"content": [
{
"annotations": [],
"text": "Hi \u2014 I\u2019m doing well, thanks! How can I help you today?",
"type": "output_text",
"logprobs": []
}
],
"role": "assistant",
"status": "completed",
"type": "message"
}
]
Original number: 100
Updated number: {"number": 58}
Updated Output (Input for second run):
[
{
"content": "Hello how are you?",
"role": "user"
},
{
"id": "rs_0badf01a75adeca30069394a0841a481959dcb8286ab77a6a2",
"summary": [],
"type": "reasoning"
},
{
"arguments": "{\"number\": 58}",
"call_id": "call_BQtEJEh3dBjMRlDpgAyjloqO",
"name": "generate_number",
"type": "function_call",
"id": "fc_0badf01a75adeca30069394a0df2808195bc124f0c43d2a68a",
"status": "completed"
},
{
"call_id": "call_BQtEJEh3dBjMRlDpgAyjloqO",
"output": "Generated",
"type": "function_call_output"
},
{
"id": "msg_0badf01a75adeca30069394a0f05d8819582a5548d1cf155a1",
"content": [
{
"annotations": [],
"text": "Hi \u2014 I\u2019m doing well, thanks! How can I help you today?",
"type": "output_text",
"logprobs": []
}
],
"role": "assistant",
"status": "completed",
"type": "message"
}
]
Output (Second run):
[
{
"content": "Hello how are you?",
"role": "user"
},
{
"id": "rs_0badf01a75adeca30069394a0841a481959dcb8286ab77a6a2",
"summary": [],
"type": "reasoning"
},
{
"arguments": "{\"number\": 58}",
"call_id": "call_BQtEJEh3dBjMRlDpgAyjloqO",
"name": "generate_number",
"type": "function_call",
"id": "fc_0badf01a75adeca30069394a0df2808195bc124f0c43d2a68a",
"status": "completed"
},
{
"call_id": "call_BQtEJEh3dBjMRlDpgAyjloqO",
"output": "Generated",
"type": "function_call_output"
},
{
"id": "msg_0badf01a75adeca30069394a0f05d8819582a5548d1cf155a1",
"content": [
{
"annotations": [],
"text": "Hi \u2014 I\u2019m doing well, thanks! How can I help you today?",
"type": "output_text",
"logprobs": []
}
],
"role": "assistant",
"status": "completed",
"type": "message"
},
{
"role": "user",
"content": "Give me the numbers you generated in the past messages."
},
{
"id": "rs_0badf01a75adeca30069394a1102908195abf12d7b822a339c",
"summary": [],
"type": "reasoning"
},
{
"id": "msg_0badf01a75adeca30069394a14276c8195958e335a89ad260f",
"content": [
{
"annotations": [],
"text": "I generated: 100.",
"type": "output_text",
"logprobs": []
}
],
"role": "assistant",
"status": "completed",
"type": "message"
}
]
Final Output: I generated: 100.
What I actually want in my real app is a UI pattern: the LLM calls a tool like show_form(...) which triggers my frontend to render a form. After the user edits/submits the form, I want the LLM to “see” the updated form state in the conversation so it reasons with the latest values. What’s the correct way to represent this update? Do I need to append a new message/tool output describing the new form JSON, or is there a supported way to modify/overwrite the earlier tool-call content so the model treats it as changed?