From 0af28edca5c586f4756e5e78eabb79e7b9ac4f94 Mon Sep 17 00:00:00 2001 From: Paolo Dettori Date: Tue, 3 Mar 2026 09:03:36 -0500 Subject: [PATCH] fix: handle LLM and graph errors in weather agent executor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The execute() method had no error handling around get_graph() and graph.astream(). When the LLM call fails (bad API key, model unavailable, network error), the unhandled exception left the A2A task stuck in "submitted" state with no artifacts and no error message β€” making failures invisible to both tests and users. Now graph initialization and LLM execution errors are caught and reported as failed tasks with the actual error message, matching the existing pattern for MCP connection failures. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Paolo Dettori --- .../src/weather_service/agent.py | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/a2a/weather_service/src/weather_service/agent.py b/a2a/weather_service/src/weather_service/agent.py index 5cc445a2..54f17736 100644 --- a/a2a/weather_service/src/weather_service/agent.py +++ b/a2a/weather_service/src/weather_service/agent.py @@ -130,18 +130,30 @@ async def execute(self, context: RequestContext, event_queue: EventQueue): await event_emitter.emit_event(f"Error: Cannot connect to MCP weather service at {os.getenv('MCP_URL', 'http://localhost:8000/sse')}. Please ensure the weather MCP server is running. Error: {tool_error}", failed=True) return - graph = await get_graph(mcpclient) - async for event in graph.astream(input, stream_mode="updates"): - await event_emitter.emit_event( - "\n".join( - f"πŸšΆβ€β™‚οΈ{key}: {str(value)[:256] + '...' if len(str(value)) > 256 else str(value)}" - for key, value in event.items() + try: + graph = await get_graph(mcpclient) + except Exception as graph_error: + logger.error(f'Failed to create LLM graph: {graph_error}') + await event_emitter.emit_event(f"Error: Failed to initialize LLM graph: {graph_error}", failed=True) + return + + try: + async for event in graph.astream(input, stream_mode="updates"): + await event_emitter.emit_event( + "\n".join( + f"πŸšΆβ€β™‚οΈ{key}: {str(value)[:256] + '...' if len(str(value)) > 256 else str(value)}" + for key, value in event.items() + ) + + "\n" ) - + "\n" - ) - output = event - logger.info(f'event: {event}') - output = output.get("assistant", {}).get("final_answer") + output = event + logger.info(f'event: {event}') + except Exception as llm_error: + logger.error(f'LLM execution failed: {llm_error}') + await event_emitter.emit_event(f"Error: LLM execution failed: {llm_error}", failed=True) + return + + output = output.get("assistant", {}).get("final_answer") if output else None # Set span output BEFORE emitting final event (for streaming response capture) # This populates mlflow.spanOutputs, output.value, gen_ai.completion