From 03a30537ab19c9a0446a8a59c2fec4c7f69171a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E6=BD=AE?= Date: Fri, 15 May 2026 19:25:08 +0800 Subject: [PATCH] ask user question --- routes/chat.py | 10 +++--- skills/developing/mcp-ui/mcp_ui_tools.json | 21 +++++++++++++ skills/developing/mcp-ui/ui_render_server.py | 33 ++++++++++++++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/routes/chat.py b/routes/chat.py index e58dd20..773bcfb 100644 --- a/routes/chat.py +++ b/routes/chat.py @@ -140,12 +140,14 @@ async def enhanced_generate_stream_response( elif isinstance(msg, ToolMessage) and msg.content: message_tag = "TOOL_RESPONSE" waiting_for_answer_first_char = False - # Always output mcp-ui UIResource responses even when tool_response is disabled + # Always output UIResource and ask_user responses even when tool_response is disabled is_ui_resource = ( msg.text - and msg.text.lstrip().startswith('{"type"') - and '"ui://' in msg.text - and '"text/html' in msg.text + and msg.text.lstrip().startswith('{"') + and ( + ('"ui://' in msg.text and '"text/html' in msg.text) + or '"__ask_user__"' in msg.text + ) ) if config.tool_response or is_ui_resource: new_content = f"[{message_tag}] {msg.name}\n{msg.text}\n" diff --git a/skills/developing/mcp-ui/mcp_ui_tools.json b/skills/developing/mcp-ui/mcp_ui_tools.json index 2852817..7ea3ee1 100644 --- a/skills/developing/mcp-ui/mcp_ui_tools.json +++ b/skills/developing/mcp-ui/mcp_ui_tools.json @@ -26,5 +26,26 @@ }, "required": ["title", "html_content"] } + }, + { + "name": "ask_user", + "description": "Ask the user a question and present options for them to choose from. Use this tool when you need user input to proceed, such as clarifying requirements, choosing between alternatives, or confirming an action. The question will be displayed at the end of your response with clickable option buttons.", + "inputSchema": { + "type": "object", + "properties": { + "question": { + "type": "string", + "description": "The question to ask the user" + }, + "options": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of options for the user to choose from. If empty, a free text input will be shown instead." + } + }, + "required": ["question"] + } } ] diff --git a/skills/developing/mcp-ui/ui_render_server.py b/skills/developing/mcp-ui/ui_render_server.py index a37f540..e89e720 100644 --- a/skills/developing/mcp-ui/ui_render_server.py +++ b/skills/developing/mcp-ui/ui_render_server.py @@ -21,6 +21,27 @@ from mcp_common import ( ) +ASK_USER_MARKER = "__ask_user__" + + +def ask_user(question: str, options: list = None) -> Dict[str, Any]: + """Create an ask_user response. + + Returns a JSON structure with a marker so the backend can detect it + and emit it as a special delta.ask_user event at the end of the stream. + """ + payload = { + "__type__": ASK_USER_MARKER, + "question": question, + "options": options or [], + } + return { + "content": [ + {"type": "text", "text": json.dumps(payload, ensure_ascii=False)} + ] + } + + def render_ui( title: str, html_content: str, width: str = "100%", height: str = "400px" ) -> Dict[str, Any]: @@ -115,6 +136,18 @@ async def handle_request(request: Dict[str, Any]) -> Dict[str, Any]: result = render_ui(title, html_content, width, height) return {"jsonrpc": "2.0", "id": request_id, "result": result} + elif tool_name == "ask_user": + question = arguments.get("question", "") + options = arguments.get("options", []) + + if not question: + return create_error_response( + request_id, -32602, "Missing required parameter: question" + ) + + result = ask_user(question, options) + return {"jsonrpc": "2.0", "id": request_id, "result": result} + else: return create_error_response( request_id, -32601, f"Unknown tool: {tool_name}"