feat: screensue 默认 5s 超时,agent 可指定时长或永不超时

- GUI main.js: screensue 默认 duration 从 0(常驻) 改为 5 秒自动关闭
- 命令带数字 token 指定时长: "screensue 30 内容"=显示30秒
- 命令带 0 表示永不超时: "screensue 0 重要公告"=常驻直到用户手动关闭
- gui-prefs.screensueDuration 用户配置默认值(未配置时 5),命令参数优先级最高
- 设置页(app.js)新增「默认时长(秒)」输入框(placeholder 提示 0=常驻)
- 回执文案区分 for Ns / persistent until closed
- 服务端 device_ctl_cmdrun 工具描述同步更新(5秒默认/指定秒数/0永不超时)
This commit is contained in:
JianFeeeee
2026-08-21 12:10:28 +08:00
parent 5b0cd45093
commit cfe5a1a7f1
3 changed files with 32 additions and 10 deletions

View File

@ -1428,7 +1428,8 @@ function executeHomeagentCmd(capability, reqId) {
}
case "screensue": {
// 在配置的目标屏幕上拉起独立窗口显示内容(支持文字 / HTML
var duration = 0; // 显示时长(秒)0=常驻
// 默认 5 秒自动关闭;命令可带 [秒] 指定时长0 = 永不超时(常驻,用户手动关闭)
var duration = 5;
var raw = String(capability || "")
.replace(/^screensue/, "")
.trim();
@ -1438,9 +1439,15 @@ function executeHomeagentCmd(capability, reqId) {
const prefs = loadGuiPrefs();
const db = prefs.deviceBridge || {};
dispIdx = parseInt(db.screensueDisplay || "0", 10) || 0;
duration = parseInt(db.screensueDuration || "0", 10) || 0;
const cfgDur = db.screensueDuration;
if (cfgDur === undefined || cfgDur === null || cfgDur === "") {
duration = 5; // 未配置时默认 5 秒
} else {
duration = parseInt(cfgDur, 10);
if (!Number.isFinite(duration) || duration < 0) duration = 5;
}
} catch (e) {}
// 参数支持 "screensue [时长秒] 内容":首个纯数字 token 作为时长
// 参数支持 "screensue [时长秒] 内容":首个纯数字 token 作为时长0=永不超时)
const tokens = raw.split(/\s+/);
if (tokens.length > 1 && /^\d+$/.test(tokens[0])) {
duration = parseInt(tokens[0], 10);
@ -1509,7 +1516,9 @@ function executeHomeagentCmd(capability, reqId) {
"ok",
"screensue shown on display " +
dispIdx +
(duration > 0 ? " for " + duration + "s" : "") +
(duration > 0
? " for " + duration + "s"
: " (persistent until closed)") +
": " +
raw.slice(0, 80),
"",
@ -2132,7 +2141,7 @@ function loadGuiPrefs() {
gateway: db.gateway || "",
token: db.token || "",
screensueDisplay: db.screensueDisplay || "0",
screensueDuration: db.screensueDuration || "0",
screensueDuration: db.screensueDuration === undefined || db.screensueDuration === null || db.screensueDuration === "" ? "5" : String(db.screensueDuration),
exec: db.exec || {},
authSchedule: db.authSchedule || {},
},
@ -2148,7 +2157,7 @@ function loadGuiPrefs() {
gateway: "",
token: "",
screensueDisplay: "0",
screensueDuration: "0",
screensueDuration: "5",
exec: {},
authSchedule: {},
},

View File

@ -4992,6 +4992,13 @@ function renderDevices() {
'</label><select id="dev-bridge-display" style="font-size:13px;padding:3px 6px;border-radius:4px;border:1px solid var(--border-color);background:var(--bg-input);color:var(--text-primary)">' +
(dispOpts || '<option value="0">默认</option>') +
"</select>" +
"<label style='font-size:13px;margin-left:8px'>" +
__("默认时长(秒)", "default duration(s)") +
'</label><input id="dev-bridge-duration" value="' +
escHtml(dbc.screensueDuration === undefined || dbc.screensueDuration === null ? "5" : String(dbc.screensueDuration)) +
'" placeholder="50=常驻" title="' +
__("screensue 默认显示秒数0=永不超时常驻。命令带数字可临时覆盖", "screensue default seconds; 0=persistent. Command number overrides") +
'" style="width:70px;font-size:13px;padding:3px 6px;border-radius:4px;border:1px solid var(--border-color);background:var(--bg-input);color:var(--text-primary)">' +
"</div>" +
'<div style="display:flex;gap:6px;align-items:center;flex-wrap:wrap">' +
"<label style='font-size:13px'>" +
@ -5138,9 +5145,14 @@ async function saveBridgeChannel() {
}
var cfg = { enabled: true, gateway: gw };
if (tok) cfg.token = tok;
// 能力配置screensue 屏幕 / cmdrun 目录 / 沙箱
// 能力配置screensue 屏幕/时长 / cmdrun 目录 / 沙箱
var disp = document.getElementById("dev-bridge-display");
if (disp) cfg.screensueDisplay = disp.value || "0";
var dur = document.getElementById("dev-bridge-duration");
if (dur) {
var dv = parseInt(dur.value, 10);
cfg.screensueDuration = Number.isFinite(dv) && dv >= 0 ? String(dv) : "5";
}
var cwd = document.getElementById("dev-bridge-cwd");
var sandbox = document.getElementById("dev-bridge-sandbox");
var boxdir = document.getElementById("dev-bridge-boxdir");

View File

@ -64,8 +64,9 @@ func (d *devicectlDevice) Tools() []agentIO.ToolDef {
"command 支持两类(前缀区分):\n" +
"- shell-cmd: 在设备上执行原生 shell 命令,如 shell-cmd ls -la /tmp\n" +
"- homeagent-cmd: 调用设备端 HomeAgent 内置能力:\n" +
" · homeagent-screensue <显示内容/HTML> — 用户侧屏幕弹窗显示自定义内容(带参显示,如 homeagent-screensue 会议提醒:三点开会\n" +
" · homeagent-screensue <秒> <内容> — 显示指定时长后自动关闭;不带参数则常驻\n" +
" · homeagent-screensue <显示内容/HTML> — 用户侧屏幕弹窗显示自定义内容(默认 5 秒后自动关闭\n" +
" · homeagent-screensue <秒> <内容> — 指定显示时长(秒),如 homeagent-screensue 30 会议提醒:三点开会\n" +
" · homeagent-screensue 0 <内容> — 永不超时,常驻显示直到用户手动关闭\n" +
" · homeagent-camerasue — 抓拍单张 jpeg结果为 base64 data URL\n" +
" · homeagent-camerasue <N秒> — 录像 N 秒 mp4二进制分块回传cmdresult 含 data_base64 字段)\n" +
" · homeagent-speakeruse <文字> — 设备端 TTS 语音朗读文字\n" +
@ -76,7 +77,7 @@ func (d *devicectlDevice) Tools() []agentIO.ToolDef {
"type": "object",
"properties": map[string]interface{}{
"device_id": map[string]interface{}{"type": "string", "description": "目标设备 ID"},
"command": map[string]interface{}{"type": "string", "description": "以 shell-cmd 或 homeagent-cmd 前缀开头。如 shell-cmd pwd、homeagent-screensue 三点开会、homeagent-camerasue 5录5秒、homeagent-speakeruse 你好"},
"command": map[string]interface{}{"type": "string", "description": "以 shell-cmd 或 homeagent-cmd 前缀开头。如 shell-cmd pwd、homeagent-screensue 三点开会、homeagent-screensue 0 重要公告、homeagent-camerasue 5录5秒、homeagent-speakeruse 你好"},
},
"required": []interface{}{"device_id", "command"},
},