Skip to content

Python: [Bug]: Durable agent with AzureOpenAIResponsesClient + tools fails on 2nd turn - KeyError in _prepare_content_for_openai #3187

@jsturtevant

Description

@jsturtevant

Description

Durable agents using AzureOpenAIResponsesClient with tools fail on the second turn of a conversation. The call_id_to_id mapping is not restored from durable state.

What happened?
Second message on a thread fails with KeyError when conversation history contains tool calls.

What did you expect?
Multi-turn conversations with tools should work.

Steps to reproduce:

  1. Create durable agent with AzureOpenAIResponsesClient + a tool
  2. Send message that triggers tool use → works
  3. Send follow-up message on same thread → fails

Code Sample

# function_app.py
import os
from typing import Annotated
from azure.identity import DefaultAzureCredential
from agent_framework import ChatAgent, AIFunction
from agent_framework.azure import AzureOpenAIResponsesClient, AgentFunctionApp
from pydantic import Field

class EchoTool(AIFunction):
    def __init__(self):
        super().__init__(
            name="echo",
            description="Echoes input back",
            approval_mode="never_require",
        )

    async def run(self, message: Annotated[str, Field(description="Message")]) -> str:
        return f"Echo: {message}"

client = AzureOpenAIResponsesClient(
    endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
    deployment_name=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"),
    credential=DefaultAzureCredential(),
)

agent = ChatAgent(
    name="BugRepro",
    chat_client=client,
    instructions="Use the echo tool when asked.",
    tools=[EchoTool()], # comment out and it works
)

app = AgentFunctionApp(agents=[agent])

To Run in azure functions:

  1. Azurite running: docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite 2. DTS emulator running: docker run -p 8080:8080 -p 8082:8082 mcr.microsoft.com/dts/dts-emulator:latest
  2. func start
  3. local.settings.json configured with your Azure OpenAI endpoint
script to run to reproduce
#!/usr/bin/env bash
# Test script to reproduce the durable agent + tools bug
# 
# Prerequisites:
# 1. Azurite running: docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite
# 2. DTS emulator running: docker run -p 8080:8080 -p 8082:8082 mcr.microsoft.com/dts/dts-emulator:latest
# 3. func start running in this directory
# 4. local.settings.json configured with your Azure OpenAI endpoint

set -euo pipefail

BASE_URL="http://localhost:7071/api/agents/BugRepro"

echo "=========================================="
echo "Durable Agent + Tools Bug Reproduction"
echo "=========================================="
echo ""

# Step 1: First message - triggers tool use
echo "Step 1: Sending first message (triggers echo tool)..."
echo "Message: Please echo 'hello world'"
echo ""

response=$(curl -s -D /tmp/headers.txt -X POST "${BASE_URL}/run" \
  -H "Content-Type: text/plain" \
  -d "Please echo 'hello world'")

echo "Response: $response"
echo ""

# Extract thread ID
thread_guid=$(grep -i "x-ms-thread-id:" /tmp/headers.txt | cut -d' ' -f2 | tr -d '\r\n')
thread_id="${thread_guid}"

echo "Thread GUID: $thread_guid"
echo "Thread ID: $thread_id"
echo ""

# Step 2: Second message - should trigger the bug
echo "=========================================="
echo "Step 2: Sending second message on same thread..."
echo "Message: Now echo 'goodbye'"
echo "URL: ${BASE_URL}/run?thread_id=${thread_id}"
echo ""

echo "This should fail with KeyError: 'call_...' if the bug exists"
echo ""

read -p "Press Enter to send second message..."
echo ""

response=$(curl -s -X POST "${BASE_URL}/run?thread_id=${thread_id}" \
  -H "Content-Type: text/plain" \
  -d "Now echo 'goodbye'" 2>&1) || true

echo "Response: $response"
echo ""
echo "=========================================="
echo "Check the func start terminal for the KeyError stack trace"
echo "=========================================="

Error Messages / Stack Traces

File ".venv/lib/python3.12/site-packages/agent_framework/openai/_responses_client.py", line 602, in _prepare_content_for_openai
    "id": call_id_to_id[content.call_id],
KeyError: 'call_Gnn7r7uMviCtJ5SSL64sh9oo'
full stack
[2026-01-12T23:09:28.530Z] [AgentEntity.run] Agent execution failed.
[2026-01-12T23:09:28.530Z] Traceback (most recent call last):
[2026-01-12T23:09:28.530Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework_azurefunctions/_entities.py", line 162, in run
[2026-01-12T23:09:28.530Z]     agent_run_response: AgentRunResponse = await self._invoke_agent(
[2026-01-12T23:09:28.530Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework_azurefunctions/_entities.py", line 251, in _invoke_agent
[2026-01-12T23:09:28.530Z]     agent_run_response = await self._invoke_non_stream(run_kwargs)
[2026-01-12T23:09:28.530Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework_azurefunctions/_entities.py", line 284, in _invoke_non_stream
[2026-01-12T23:09:28.531Z]     result = await result
[2026-01-12T23:09:28.531Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/_middleware.py", line 1249, in middleware_enabled_run
[2026-01-12T23:09:28.531Z]     return await original_run(self, normalized_messages, thread=thread, **kwargs)  # type: ignore[return-value]
[2026-01-12T23:09:28.531Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/observability.py", line 1364, in trace_run
[2026-01-12T23:09:28.531Z]     response = await run_func(self, messages=messages, thread=thread, **kwargs)
[2026-01-12T23:09:28.531Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/_agents.py", line 886, in run
[2026-01-12T23:09:28.531Z]     response = await self.chat_client.get_response(
[2026-01-12T23:09:28.531Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/_tools.py", line 1818, in function_invocation_wrapper
[2026-01-12T23:09:28.531Z]     response = await func(self, messages=prepped_messages, **filtered_kwargs)
[2026-01-12T23:09:28.531Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/observability.py", line 1104, in trace_get_response
[2026-01-12T23:09:28.531Z]     response = await func(self, messages=messages, **kwargs)
[2026-01-12T23:09:28.531Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/_middleware.py", line 1367, in middleware_enabled_get_response
[2026-01-12T23:09:28.532Z]     return await original_get_response(self, messages, **kwargs)
[2026-01-12T23:09:28.532Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/_clients.py", line 581, in get_response
[2026-01-12T23:09:28.532Z]     return await self._inner_get_response(messages=prepped_messages, chat_options=chat_options, **filtered_kwargs)
[2026-01-12T23:09:28.532Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/openai/_responses_client.py", line 94, in _inner_get_response
[2026-01-12T23:09:28.532Z]     run_options = await self._prepare_options(messages, chat_options, **kwargs)
[2026-01-12T23:09:28.532Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/openai/_responses_client.py", line 398, in _prepare_options
[2026-01-12T23:09:28.532Z]     request_input = self._prepare_messages_for_openai(messages)
[2026-01-12T23:09:28.532Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/openai/_responses_client.py", line 492, in _prepare_messages_for_openai
[2026-01-12T23:09:28.533Z]     list_of_list = [self._prepare_message_for_openai(message, call_id_to_id) for message in chat_messages]
[2026-01-12T23:09:28.533Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/openai/_responses_client.py", line 516, in _prepare_message_for_openai
[2026-01-12T23:09:28.533Z]     function_call = self._prepare_content_for_openai(message.role, content, call_id_to_id)
[2026-01-12T23:09:28.533Z]   File "/home/jstur/projects/local-code-interpreter-tool-project/local-code-interpreter-tool/.venv/lib/python3.12/site-packages/agent_framework/openai/_responses_client.py", line 602, in _prepare_content_for_openai
[2026-01-12T23:09:28.533Z]     "id": call_id_to_id[content.call_id],
[2026-01-12T23:09:28.533Z] KeyError: 'call_4pFYHvE2vw0kMjGh363YftBM'

### Package Versions

agent-framework: 1.0.0b251218, agent-framework-azurefunctions: 1.0.0b251218

Python Version

Python 3.12.3

Additional Context

  • Works without tools (multi-turn succeeds)

Metadata

Metadata

Assignees

Labels

azure-functionsIssues and PRs related to Azure FunctionsbugSomething isn't workingpython

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions