Skip to content

Python: [Bug]: Inconsistent Thread Upgrade & chat_message_store_factory Invocation Between GPT and Anthropic Clients #3858

@aneep-agrawal

Description

@aneep-agrawal

Summary

There is an inconsistency in how the Agent Framework handles thread upgrades and message store initialization between GPT (Azure/OpenAI) and Anthropic clients.

When using Anthropic with streaming enabled, chat_message_store_factory() is invoked without any arguments during _update_thread_with_type_and_conversation_id. This differs from GPT behavior and makes it difficult to implement a provider-agnostic persistent message store.

This impacts multi-tenant applications using custom storage (e.g., Cosmos DB).


Background

Service Threads

Previously, we used:

AgentFrameworkAgent(..., use_service_thread=True)

Observed behavior:

  • GPT models:

    • Thread is created successfully

    • Conversation updates correctly

  • Anthropic models:

    • Service thread creation fails

Because of this, we moved to a custom persistent message store using:

chat_message_store_factory

Custom Message Store Approach

We implemented a Cosmos-backed ChatMessageStoreProtocol adapter and passed:

chat_message_store_factory=create_message_store

Initial behavior:

  • Both GPT and Anthropic persist initial messages correctly.

  • Multi-user isolation works.

However:

  • GPT continues to update conversation correctly.

  • Anthropic fails to update conversation correctly after streaming upgrade.


Root Cause

GPT Behavior

  • GPT responses include conversation_id.

  • During _update_thread_with_type_and_conversation_id, the framework uses this ID.

  • Thread upgrade succeeds.

  • Message store remains correctly associated.

Anthropic Behavior

  • Anthropic responses do not include conversation_id.

  • During streaming, _update_thread_with_type_and_conversation_id executes.

  • The framework calls:

thread.message_store = self.chat_message_store_factory()

This call:

  • Passes no arguments

  • Does not pass serialized_store_state

  • Does not pass thread context

As a result:

  • The factory cannot determine user_id or thread_id

  • The message store cannot correctly bind to the existing conversation

  • Conversation updates fail or become ambiguous


Code Reference

In _agents.py (around line 1244):

thread.message_store = self.chat_message_store_factory()

This occurs in the Anthropic streaming path when upgrading thread type.


Why This Is Problematic

In enterprise multi-tenant systems:

  • user_id is required for tenant isolation

  • thread_id is required for conversation scoping

  • Persistent stores cannot operate without stable identity

Because Anthropic does not return conversation_id, and the factory is invoked without context:

Code Sample

def create_message_store(user_id, thread_id):
            """Factory to create Cosmos DB message store for each thread.
            
            """
            return CosmosMessageStoreAdapter(
                thread_store=thread_store,
                user_id=user_id,
                thread_id=thread_id,
            )
 chat_message_store_factory = create_message_store


 ChatAgent(
        name="",
        instructions=""
        chat_client=chat_client,
        chat_message_store_factory=chat_message_store_factory,
        tools=mcp_tool,
    )

Error Messages / Stack Traces

.venv\Lib\site-packages\agent_framework\_agents.py", line 1244, in _update_thread_with_type_and_conversation_id
    thread.message_store = self.chat_message_store_factory()
                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
TypeError: create_agent.<locals>.create_message_store() missing 2 required positional arguments: 'user_id' and 'thread_id'

Package Versions

Name: agent-framework-core Version: 1.0.0b260130

Python Version

Python 3.14.2

Additional Context

No response

Metadata

Metadata

Labels

agent memoryRelated to agentic memorybugSomething isn't workingpythonv1.0Features being tracked for the version 1.0 GA

Type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions