From a11cb56962913c46bc46b6e0a2b53d77766e7956 Mon Sep 17 00:00:00 2001 From: gongzhiyong Date: Thu, 9 Apr 2026 17:52:55 +0800 Subject: [PATCH] feat: emit real status events from on_chain_start (thinking/generating) - Add has_tool_activity flag to distinguish first agent pass (thinking) from post-tool agent pass (generating) - Replace on_chain_start debug logging with status SSE emission - Filter to only graph-level agent nodes via graph:step: tag prefix Co-Authored-By: Claude Sonnet 4.6 (1M context) --- backend/app/api/chat.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/backend/app/api/chat.py b/backend/app/api/chat.py index e6802d1..59d5f3d 100644 --- a/backend/app/api/chat.py +++ b/backend/app/api/chat.py @@ -81,6 +81,7 @@ async def _stream_response(request: ChatRequest) -> AsyncIterator[bytes]: full_content: list[str] = [] logger = logging.getLogger(__name__) tool_start_ts: dict[str, int] = {} # track per-tool start timestamps + has_tool_activity = False try: async for event in graph.astream_events( @@ -104,6 +105,7 @@ async def _stream_response(request: ChatRequest) -> AsyncIterator[bytes]: tool_input = event.get("data", {}).get("input", {}) ts = int(time.time() * 1000) tool_start_ts[call_id] = ts + has_tool_activity = True yield _sse({ "type": "tool_start", "call_id": call_id, @@ -144,14 +146,21 @@ async def _stream_response(request: ChatRequest) -> AsyncIterator[bytes]: elif kind == "on_chain_start": chain_name = event.get("name", "") - metadata = event.get("metadata", {}) tags = event.get("tags", []) - logger.warning( - "on_chain_start: name=%s, langgraph_node=%s, tags=%s", - chain_name, - metadata.get("langgraph_node", ""), - tags, - ) + is_graph_step = any(t.startswith("graph:step:") for t in tags) + if chain_name == "agent" and is_graph_step: + if has_tool_activity: + yield _sse({ + "type": "status", + "stage": "generating", + "message": "正在生成回复...", + }) + else: + yield _sse({ + "type": "status", + "stage": "thinking", + "message": "正在分析...", + }) except Exception as exc: logger.error("SSE stream error for conversation %s: %s", request.conversation_id, exc, exc_info=True)