Add sidebar-only agentAccess lock for scheduled jobs.

Default remains allow; humans can deny agent pause/resume/retrigger/delete in the panel while tools never expose or set the field.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-10 21:54:31 +08:00
parent 4472a9c74b
commit ad6e90f197
7 changed files with 130 additions and 11 deletions

View file

@ -430,6 +430,10 @@ body>.dsh-ct-main{position:fixed;top:0;right:0;bottom:0;left:var(--dsh-ct-sideba
deliveryHint: '选 WhatsApp/IM 后从下拉选择已保存的投递目标(仅超管)。普通用户请在 IM 聊天里用 cron_create 建渠道任务。目标在 IM 机器人 → 投递设置里创建。',
mirrorToSession: '镜像回原会话',
mirrorToSessionHint: '开启后把每次运行摘要写入创建时的 WhatsApp/Web 会话(不新开模型轮次)。默认关闭。',
agentAccess: 'Agent 操作',
agentAccessAllow: '允许 Agent 用工具管理(默认)',
agentAccessDeny: '仅人工(禁止 Agent 暂停/恢复/重触发/删除)',
agentAccessHint: '仅侧栏可改;Agent 看不到此开关。默认保持现状(允许)。关掉后 Agent 仍可查询进度,但无法改任务。',
loginRequired: '登录后才能使用定时任务',
runNoSession: '这次运行没有可打开的会话',
runOpenFailed: '打不开这次对话,会话可能已被删除',
@ -498,6 +502,10 @@ body>.dsh-ct-main{position:fixed;top:0;right:0;bottom:0;left:var(--dsh-ct-sideba
deliveryHint: 'Pick a saved IM delivery target (super_admin only). Regular users should create channel jobs from the IM chat via cron_create. Create targets under IM bot → Delivery settings.',
mirrorToSession: 'Mirror into origin session',
mirrorToSessionHint: 'When enabled, append each run summary into the creating WhatsApp/Web session (no new model turn). Off by default.',
agentAccess: 'Agent control',
agentAccessAllow: 'Allow agents to manage via tools (default)',
agentAccessDeny: 'Human only (block agent pause/resume/retrigger/delete)',
agentAccessHint: 'Sidebar only; agents never see this toggle. Default keeps current behavior (allow). When denied, agents can still query progress but cannot mutate the job.',
loginRequired: 'Sign in to use scheduled tasks',
runNoSession: 'This run has no session to open',
runOpenFailed: 'Could not open this chat; the session may have been deleted',
@ -755,6 +763,7 @@ body>.dsh-ct-main{position:fixed;top:0;right:0;bottom:0;left:var(--dsh-ct-sideba
imBotId: '',
imTargetId: '',
mirrorToSession: false,
agentAccess: 'allow',
labelsText: '',
persistKind: 'retain',
archiveEndpoint: '',
@ -781,6 +790,7 @@ body>.dsh-ct-main{position:fixed;top:0;right:0;bottom:0;left:var(--dsh-ct-sideba
imBotId: job.delivery?.botId || '',
imTargetId: job.delivery?.targetId || '',
mirrorToSession: job.mirrorToSession === true,
agentAccess: job.agentAccess === 'deny' ? 'deny' : 'allow',
labelsText: formatLabelsText(job.labels),
persistKind: persistHistoryKind(job),
archiveEndpoint: job.persistHistory?.kind === 'archive' ? (job.persistHistory.endpoint || '') : '',
@ -1421,6 +1431,16 @@ body>.dsh-ct-main{position:fixed;top:0;right:0;bottom:0;left:var(--dsh-ct-sideba
? h(ImDeliveryFields, { t, form, setForm, imCatalog })
: null,
h('span', { className: 'dsh-ct-cwdHint' }, t('deliveryHint')),
h('label', null, t('agentAccess'),
h('select', {
value: form.agentAccess === 'deny' ? 'deny' : 'allow',
onChange: (e) => setForm({ ...form, agentAccess: e.target.value }),
},
h('option', { value: 'allow' }, t('agentAccessAllow')),
h('option', { value: 'deny' }, t('agentAccessDeny')),
),
),
h('span', { className: 'dsh-ct-cwdHint' }, t('agentAccessHint')),
h('label', { className: 'dsh-ct-check' },
h('input', {
type: 'checkbox',
@ -1689,6 +1709,7 @@ body>.dsh-ct-main{position:fixed;top:0;right:0;bottom:0;left:var(--dsh-ct-sideba
? { kind: 'im', botId: form.imBotId, targetId: form.imTargetId }
: { kind: 'dsh' },
mirrorToSession: form.mirrorToSession === true,
agentAccess: form.agentAccess === 'deny' ? 'deny' : 'allow',
labels: parseLabelsText(form.labelsText),
persistHistory: form.persistKind === 'forever'
? { kind: 'forever' }