7. Streaming and Multi-Turn Interactions (LangGraph Example)
The Hello World example demonstrates the basic mechanics of A2A. For more advanced capabilities, such as robust streaming, task state management, and multi-turn conversations powered by an LLM, turn to the LangGraph example in a2a-samples/samples/python/agents/langgraph/
.
This example features a “Currency Agent” that uses the Gemini model through LangChain and LangGraph to answer currency conversion questions.
Setting up the LangGraph example
1. Get an API key. Create a Gemini API Key if you do not already have one.
2. Set the environment variable. Create a .env file in the a2a-samples/samples/python/agents/langgraph/ directory:
echo "GOOGLE_API_KEY=YOUR_API_KEY_HERE" > .envReplace YOUR_API_KEY_HERE with your own Gemini API key. Do not commit a real key to a code repository.
3. Install dependencies. The langgraph example has its own pyproject.toml, which declares dependencies such as langchain-google-genai and langgraph. If you hit import errors at runtime, install the missing dependencies listed in that file.
Running the LangGraph server
In your terminal, go to the a2a-samples/samples/python/agents/langgraph/app directory and make sure your virtual environment is activated.
Start the LangGraph agent server:
python __main__.pyThe server usually listens on http://localhost:10000.
Interacting with the LangGraph agent
Open a new terminal window, activate your virtual environment, go to a2a-samples/samples/python/agents/langgraph/app, and run its test client:
python test_client.pyWhen you are done, press Ctrl+C in the terminal running __main__.py to shut down the server.
Key features demonstrated
The langgraph example showcases several important A2A concepts.
1. LLM integration
agent.pydefinesCurrencyAgent. It usesChatGoogleGenerativeAIand LangGraph’screate_react_agentto process user queries.- This demonstrates how a real LLM can power the agent’s logic.
2. Task state management
samples/python/agents/langgraph/app/__main__.pyinitializes aDefaultRequestHandlerwith anInMemoryTaskStore.- When the
DefaultRequestHandlercalls theexecutemethod ofCurrencyAgentExecutor, it interacts with theRequestContext, which contains the current task (if any). - For
SendMessage, theDefaultRequestHandleruses theTaskStoreto persist and retrieve task state across interactions. The response toSendMessageis a fullTaskobject if the agent’s execution flow involves multiple steps or results in a persistent task. run_single_turn_testintest_client.pyshows how to get aTaskobject back and then query it withget_task.
3. Streaming with TaskStatusUpdateEvent and TaskArtifactUpdateEvent
- The
executemethod ofCurrencyAgentExecutorhandles both non-streaming and streaming requests, orchestrated by theDefaultRequestHandler. - As the LangGraph agent processes the request (which might involve calling tools like
get_exchange_rate),CurrencyAgentExecutorenqueues different types of events onto theEventQueue:TaskStatusUpdateEvent: for intermediate updates (for example, “Looking up exchange rates…” and “Processing the exchange rates…”).TaskArtifactUpdateEvent: when the final answer is ready, it is enqueued as an artifact, with thelastChunkflag set toTrue.- A final
TaskStatusUpdateEventwithstate=TaskState.TASK_STATE_COMPLETEDsignals the end of the task and closes the stream.
run_streaming_testintest_client.pyprints these individual event chunks as they arrive from the server.
4. Multi-turn conversation (TaskState.TASK_STATE_INPUT_REQUIRED)
- The
CurrencyAgentcan ask for clarification if a query is ambiguous (for example, the user asks “how much is 100 USD?”). - When this happens,
CurrencyAgentExecutorenqueues aTaskStatusUpdateEventwhosestatus.stateisTaskState.TASK_STATE_INPUT_REQUIREDand whosestatus.messageholds the agent’s question (for example, “To which currency would you like to convert?”). The stream closes after this event. run_multi_turn_testintest_client.pydemonstrates this:- It sends an initial ambiguous query.
- The agent responds (through the
DefaultRequestHandlerprocessing the enqueued events) with aTaskwhose status isTASK_STATE_INPUT_REQUIRED. - The client then sends a second message, including the
taskIdandcontextIdfrom the first turn’sTaskresponse, to provide the missing information (“in GBP”). This continues the same task.
For what these states mean, see Life of a Task . For the details of streaming and push notifications, see Streaming and Asynchronous Operations .
Exploring the code
Take some time to read through these files:
__main__.py: server setup withDefaultRequestHandlerand a Starlette application. Note that theAgentCarddefinition includescapabilities.streaming=True.agent.py: theCurrencyAgentwith LangGraph, the LLM model, and tool definitions.agent_executor.py:CurrencyAgentExecutor, which implementsexecute(andcancel). It uses theRequestContextto understand the ongoing task and theEventQueueto send back events (TaskStatusUpdateEvent,TaskArtifactUpdateEvent, and a newTaskobject created implicitly by the first event when no task exists).test_client.py: demonstrates various interaction patterns, including retrieving task IDs and using them for multi-turn conversations.
This example gives a much richer illustration of how A2A supports complex, stateful, and asynchronous interactions between agents.
Next step
Continue with Next Steps .