Question about conversation history when exposing MAF agents over A2A #7252
Replies: 2 comments
|
No doubt that agents in production should implement persistent storage for conversation history and context, whether they are local or exposed via A2A. The reason I started this thread is about using AgentSession in local vs in A2A settings.
So, as we can see, the behavior is different. This all boils down to this: create_session(session_id=...) always give you a new AgentSession even with the same session_id. I mean, is this by design? Curiously, Why create_session() is not designed as a get_or_create? |
|
Hi Sami,
Thanks for your reply!
So, I guess for external storage backed history provider such as FileHistoryProvider, that each turn a new AgentSession is created is ok as long as the same session id is used. So does other DB backed such as Redis.
Agents with such history providers do not rely on AgentSession to store chat history. That is why create_session() is not designed as a get or create. It works just fine for production use cases.
But for the default InMemoryHistoryProvider, it get/set history against an AgentSession object. Thus a demo of an agent using it over A2A will break regardless of session_id...
On Thursday, July 23, 2026 at 06:00:45 PM GMT+8, Sami El Akkad ***@***.***> wrote:
I traced this through the current source. The behavior you are seeing follows from the present A2AExecutor implementation:
- A2AExecutor calls agent.create_session(session_id=task.context_id) for each request.
- create_session() creates a new AgentSession; the ID is an identifier, not a lookup that returns the old in-memory object.
- InMemoryHistoryProvider keeps messages in AgentSession.state, so a new session object has no previous messages. Reusing the same contextId alone therefore does not restore the conversation.
- referenceTaskId is a task identifier; it is not the model conversation store.
For a server that can restart or serve multiple workers, configure a durable HistoryProvider keyed by the A2A context ID. The current framework already includes FileHistoryProvider, and the same pattern can be implemented with a database/Redis provider:
from pathlib import Path
from agent_framework import Agent, FileHistoryProvider
agent = Agent(
client=client,
instructions="...",
context_providers=[FileHistoryProvider(Path("./sessions"))],
# Let the provider load/save the complete local history.
default_options={"store": False},
)
executor = A2AExecutor(agent)
With that setup, each fresh AgentSession receives the same session_id, and the provider loads the saved messages for that ID. For production, use a tenant-scoped database key such as (authenticated_user_or_tenant, context_id), not an unauthenticated client-supplied ID by itself.
If you prefer in-memory state, subclass/wrap the executor with a contextId -> AgentSession store plus locking, expiry, and cleanup. That is fast but loses history on restart and does not work safely across multiple workers.
So the short answer is: the A2A client should keep sending the same contextId, but the server must persist or retrieve history for that ID. create_session(session_id=...) is a factory, not a get-or-create session registry.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you authored the thread.Message ID: ***@***.***>
|
Uh oh!
There was an error while loading. Please reload this page.
Hi MAF team and everyone,
I'm experimenting with exposing a Microsoft Agent Framework (MAF) agent over A2A, and I have a question about how conversation history is expected to work across multiple turns.
Environment
• agent-framework: 1.11.0
• agent-framework-a2a: 1.0.0b260709
• a2a-sdk: 1.1.1
What I observed
1. Direct MAF agent (works)
Without A2A, I created a simple MAF agent and tested multi-turn conversation.
The second turn correctly remembers that my name is Alice and that I like hiking.
If I omit the session or create a brand new session, the agent no longer remembers the previous turn, which is exactly what I expect.
2. Recreating a session with the same session_id
I then tried the following experiment to simulate two separate HTTP requests.
The output is:
False
You haven't told me your name yet!
So
create_session(session_id=...)returns a newAgentSessionobject every time, even when the same session ID is provided.However, if I reuse the original s1 object instead of calling create_session() again, the conversation history is preserved correctly.
3. A2A client
I then exposed the same agent over A2A using
A2AExecutor.Next I created a client that performs three turns of conversation using this remote agent.
The JSON-RPC requests show that:
So the A2A client appears to preserve the conversation context correctly.
Inside
A2AExecutor.execute(), I noticed the following code:session = self._agent.create_session(session_id=task.context_id)which then passes that session into:
await self._agent.run(..., session=session)However, the remote agent still forgets the previous turns.
For example:
Turn 1:
I need a flight from Paris to Rome next Friday.
Turn 2:
Do you remember my previous request?
The agent replies that it does not remember previous conversations.
My question
From reading the source code, it appears that:
•
create_session()always creates a newAgentSession,• As a result,
A2AExecutorcreates a newAgentSessionfor every request using the same contextId.So I'm trying to understand what the intended design is.
Specifically:
1. Is
A2AExecutorexpected to preserve conversation history automatically across multiple requests, or via the same contextId that represents the same session used in the client, i.e. the agent initiating a request over A2A?2. Is
create_session(session_id=...)intentionally only a factory for a newAgentSession, rather than a "get or create" API?3. Is there a recommended way to associate an incoming A2A contextId with an existing AgentSession?
4. If I am writing an A2A client, what is the recommended approach for maintaining multi-turn conversation history with a remote MAF agent? Should this be handled automatically by the MAF framework with MAF-a2a package, or is it the responsibility of the application or the agent with a custom HistoryProvider through context provider that is exposed over A2A?
I'm mainly trying to understand the intended architecture.
Thanks in advance for any clarification!
All reactions