75 lines
3.1 KiB
Python
75 lines
3.1 KiB
Python
"""UI-only "ask the user to pick a branch" tool.
|
|
|
|
收窄定位:**方案/分支确认**,不是通用提问器。模型在「需要用户在 2-4 个互斥方向
|
|
间拍板、且该选择会实质改变后续动作」时调用,前端把 question + options 渲成一组可点击
|
|
选项卡。用户点某项即作为其回复继续,也可不点直接用文字讨论。
|
|
|
|
与 task_progress 同属「虚拟工具」:结果体极小(只是占位),真正给前端用的内容全在
|
|
assistant tool_call 的 arguments 里(question/options),供 Web 渲染。loop 检测到本步
|
|
调用了本工具就提前结束本轮,等用户响应(见 core/loop.py)。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
from .base import Tool
|
|
|
|
|
|
class AskUserTool(Tool):
|
|
name = "ask_user"
|
|
description = (
|
|
"在需要用户在 2-4 个互斥方向间拍板、且该选择会实质改变你接下来动作时,展示一组可点击"
|
|
"选项让用户选。典型:确认实施方案、在多条候选路线里选一条、在明确的取舍间二选一。"
|
|
"用户点某个选项即作为其回复继续,也可不点直接用文字与你讨论。"
|
|
"不要用于:信息缺失的开放性提问(直接用文字问)、你能自己合理默认就推进的决定、"
|
|
"单纯的是/否确认、给用户播报进度。每轮最多用一次,且只在真正的分叉点用;"
|
|
"调用本工具后你的发言即结束、等待用户,不要再继续动作。"
|
|
)
|
|
parameters = {
|
|
"type": "object",
|
|
"additionalProperties": False,
|
|
"properties": {
|
|
"question": {
|
|
"type": "string",
|
|
"description": "要用户拍板的问题,一句话讲清在选什么。",
|
|
},
|
|
"options": {
|
|
"type": "array",
|
|
"description": "2-4 个互斥选项。",
|
|
"minItems": 2,
|
|
"maxItems": 4,
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": False,
|
|
"properties": {
|
|
"label": {
|
|
"type": "string",
|
|
"description": "选项短标题,用户点击后即作为其回复原文发出,写成可直接当回复的一句话。",
|
|
},
|
|
"description": {
|
|
"type": "string",
|
|
"description": "可选,一句话说明该选项的取舍 / 后果。",
|
|
},
|
|
},
|
|
"required": ["label"],
|
|
},
|
|
},
|
|
},
|
|
"required": ["question", "options"],
|
|
}
|
|
|
|
def execute(self, **kwargs: Any) -> str:
|
|
options = kwargs.get("options")
|
|
n = len(options) if isinstance(options, list) else 0
|
|
return json.dumps(
|
|
{
|
|
"ok": True,
|
|
"shown": True,
|
|
"n_options": n,
|
|
"note": "已向用户展示选项,等待其点选或继续讨论。",
|
|
},
|
|
ensure_ascii=False,
|
|
separators=(",", ":"),
|
|
)
|