Session titles: strip a leading machine-name prefix

- remote_task strips the device name from the title it creates, and tells the model not to include it
- session lists (Devices tab, sidebar, remote_devices) strip it from existing titles
- tests for stripDevicePrefix
This commit is contained in:
lyuksovannyy committed 2026-10-12 10:35:43 +00:00
1 parent bf99a952fb
commit 0bef3b9fbe
2 files changed
+48 -3

No files matched your search

+14 -3
View File
@@ -56,6 +56,17 @@ const MUX_PATH = '/api/remote.mux'
const OPS = new Set(['exec', 'readFile', 'writeFile', 'listDir', 'task', 'taskStatus', 'taskCancel', 'inspectSession'])
/** Pseudo-secret name: opting into it ships the master's forge (git) logins. */
const FORGE_SECRET = 'FORGE_CREDENTIALS'
/** Session titles must not carry the machine name ("ai-pc: fix tests" → "fix tests"): the device is shown separately. */
const stripDevicePrefix = (title, names) => {
let t = String(title ?? '')
for (const n of names.filter(Boolean)) {
const esc = String(n).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
// "[name] x" / "(name) x" (brackets close the prefix) or "name: x" / "name - x" / "name | x"
const re = new RegExp(`^\\s*(?:[\\[(]${esc}[\\])]\\s*[:·|>–—-]?|${esc}\\s*[:·|>–—-])\\s*`, 'i')
t = t.replace(re, '')
}
return t.trim()
}
function sendJson(res, status, payload) {
res.statusCode = status
@@ -258,7 +269,7 @@ export function apply(ctx, config = {}) {
updatedAt: s.updatedAt,
running: s.running,
cwd: s.cwd,
title: s.projections?.values?.title ?? null,
title: stripDevicePrefix(s.projections?.values?.title, [self.id, self.name]) || (s.projections?.values?.title ?? null),
})),
workspaces,
}
@@ -1165,7 +1176,7 @@ document.getElementById('go').onclick=()=>{
prompt: S('string', 'run: the full task for the remote agent.'),
sessionId: S('string', 'Continue / poll / cancel this session on the device.'),
cwd: CWD,
title: S('string', 'run, new session: session title.'),
title: S('string', 'run, new session: session title. Describe the task only; do not include the device name (it is shown next to the session already).'),
permission: S('string', 'run: permission preset for the remote session, e.g. "danger-full-access" when the job must run tools outside the workspace sandbox (test suites that spawn processes, git credential writes). Default: the device\'s default preset.'),
wait: S('boolean', 'run: wait for completion (default true). false = start and return the sessionId.'),
timeoutMs: S('integer', 'run: how long to wait (default 1200000 = 20 min, max 2 h). On timeout the task keeps running; poll with action=status.'),
@@ -1179,7 +1190,7 @@ document.getElementById('go').onclick=()=>{
if (action === 'cancel') return { device, ...(await callDevice(device, 'taskCancel', { sessionId: args.sessionId }, 15000)) }
const t = Math.min(Math.max(Number(args.timeoutMs) || 1200000, 10000), 2 * 60 * 60 * 1000)
const r = await callDevice(device, 'task', {
prompt: args.prompt, sessionId: args.sessionId, cwd: args.cwd, title: args.title, permission: args.permission,
prompt: args.prompt, sessionId: args.sessionId, cwd: args.cwd, title: stripDevicePrefix(args.title, [device, args.device, devicesView().find((d) => d.id === device)?.name]) || undefined, permission: args.permission,
wait: args.wait !== false, timeoutMs: t,
}, t + 30000)
return { device, ...r, url: device === self.id ? `#/session/${r.sessionId}` : `/r/${device}/#/session/${r.sessionId}` }