Skip to content

Python: MAF Feature Request: Automatic ContextId Propagation for A2A Agent Tools #2694

@moetarhinikaseya

Description

@moetarhinikaseya

Summary

When using A2A agents as tools in an LLM orchestrator, there's no automatic propagation of ContextId from the orchestrator's thread to the A2A agent calls. This makes it difficult to share session state (e.g., Redis) across multiple A2A agents in the same orchestration.


Expected Behavior (Python Pattern)

In the Python Agent Framework, the orchestrator's thread context automatically flows to all A2A tool calls:

from agent_framework import A2AAgent, AgentThread
from agent_framework.azure import AzureOpenAIChatClient
import uuid

class TriageOrchestrationService:
    def __init__(self):
        # A2A agents as tools
        self.impact_agent = A2AAgent(
            name="ImpactAssessor",
            url="https://agents.example.com/a2a/impact-assessor"
        )
        
        self.assigner_agent = A2AAgent(
            name="SmartAssigner", 
            url="https://agents.example.com/a2a/smart-assigner"
        )
        
        # LLM Orchestrator with A2A agents as tools
        self.orchestrator = AzureOpenAIChatClient().create_agent(
            name="TriageOrchestrator",
            instructions="You orchestrate ticket triage...",
            tools=[
                self.impact_agent.as_tool(name="assess_impact"),
                self.assigner_agent.as_tool(name="get_assignment")
            ]
        )
    
    async def triage_ticket(self, ticket_id: str, description: str) -> dict:
        # Create a shared context ID
        context_id = f"triage-{ticket_id}-{uuid.uuid4().hex[:8]}"
        
        # Create thread with this context ID
        thread = AgentThread(id=context_id)
        
        # LLM decides which agents to call
        # KEY: The thread's ID automatically becomes contextId for ALL A2A calls
        result = await self.orchestrator.run(
            f"Triage ticket #{ticket_id}: {description}",
            thread=thread
        )
        
        return {"context_id": context_id, "result": result.text}

# Usage - context_id "triage-12345-abc123" is automatically used for:
# - ImpactAssessor A2A calls
# - SmartAssigner A2A calls
# - All agents share the same session context
Key mechanism: When orchestrator.run(..., thread=thread) is called, the framework automatically derives contextId from the thread and passes it to all A2A agent tool calls.
Current .NET Behavior
In .NET MAF, AsAIFunction() captures the thread statically at tool creation time, not from the orchestrator's execution context:
// Current implementation in AgentExtensions.cs
public static AIFunction AsAIFunction(this AIAgent agent, AIFunctionFactoryOptions? options = null, AgentThread? thread = null)
{
    async Task<string> InvokeAgentAsync(string query, CancellationToken cancellationToken)
    {
        // Thread is captured at creation time, NOT from orchestrator context
        var response = await agent.RunAsync(query, thread: thread, cancellationToken: cancellationToken);
        return response.Text;
    }
    
    return AIFunctionFactory.Create(InvokeAgentAsync, options);
}
Problem: Each A2A agent tool has its own isolated thread. There's no way for the orchestrator's thread context to flow to the tools.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions