From ac856d9467ab58cd8f7a9b3ef4eedb4a106225d2 Mon Sep 17 00:00:00 2001 From: hui455 <2075649045@qq.com> Date: Tue, 22 Sep 2026 01:03:50 +0800 Subject: [PATCH] fix(scheduled): allow maintenance of unarmed legacy tasks Allow metadata and pause updates without turning maintenance into an automation configuration request. Keep schedule validation for explicit arming and preserve the existing manual-to-hourly interval behavior. --- crates/host-core/src/rpc/scheduled_tools.rs | 101 ++++++++++++++++++ docs/spec/03-runtime/06-host-rpc-protocol.md | 4 + docs/spec/06-delivery/04-e2e-test-plan.md | 6 ++ .../spec/03-runtime/06-host-rpc-protocol.md | 7 ++ .../spec/06-delivery/04-e2e-test-plan.md | 9 ++ scripts/e2e-scheduled-legacy-maintenance.mjs | 22 ++++ 6 files changed, 149 insertions(+) create mode 100644 scripts/e2e-scheduled-legacy-maintenance.mjs diff --git a/crates/host-core/src/rpc/scheduled_tools.rs b/crates/host-core/src/rpc/scheduled_tools.rs index 73f398ecaa..44b97c8530 100644 --- a/crates/host-core/src/rpc/scheduled_tools.rs +++ b/crates/host-core/src/rpc/scheduled_tools.rs @@ -127,7 +127,13 @@ fn execute_inner(st: &AppState, p: &ToolsExecuteParams) -> Result Result>, session: &str, name: &str, args: Value) -> Value { super::super::handle_request( state.clone(), diff --git a/docs/spec/03-runtime/06-host-rpc-protocol.md b/docs/spec/03-runtime/06-host-rpc-protocol.md index 7be3e8e3a4..83a72e7e21 100644 --- a/docs/spec/03-runtime/06-host-rpc-protocol.md +++ b/docs/spec/03-runtime/06-host-rpc-protocol.md @@ -1211,3 +1211,7 @@ Create requires title, prompt and cadence; automatic daily/weekly tasks require a schedule. Update takes an existing ID and partial fields, preserving all unspecified configuration. Exact local times remain supported despite the UI's four period presets. No new DB schema or transport is introduced. + +### Scheduled tasks: legacy task maintenance + +Agent tools allow title, prompt and pause updates on legacy automatic tasks without a schedule, including an echoed unchanged cadence. These edits do not arm the task or capture the foreground workspace. Explicit enabling, a cadence change or a supplied schedule still follows schedule validation. Resume requires an explicit valid schedule; Manual-to-Hourly retains its existing default interval behavior. diff --git a/docs/spec/06-delivery/04-e2e-test-plan.md b/docs/spec/06-delivery/04-e2e-test-plan.md index e6fbc95131..f43aa38bdf 100644 --- a/docs/spec/06-delivery/04-e2e-test-plan.md +++ b/docs/spec/06-delivery/04-e2e-test-plan.md @@ -14402,3 +14402,9 @@ the latest destination. These assertions measure work counts, not device FPS. `fork_preserves_referenced_pasted_files_independently` and `sessions::fork_files` cover ownership, deletion, repeated/bounded forks, retained checkpoint paths, expired inputs, rollback, and symlink rejection. + +### E2E-SCHEDULED-legacy-pause + +- **Scenario:** Legacy task maintenance. +- **Expected:** Agent tools allow title, prompt and pause updates on legacy automatic tasks without a schedule, including an echoed unchanged cadence. These edits do not arm the task or capture the foreground workspace. Explicit enabling, a cadence change or a supplied schedule still follows schedule validation. Resume requires an explicit valid schedule; Manual-to-Hourly retains its existing default interval behavior. +- **Automation:** `node --experimental-strip-types scripts/e2e-scheduled-legacy-maintenance.mjs` uses an isolated real Host and SQLite profile. Inference is not sent to a live provider. diff --git a/docs/zh-CN/spec/03-runtime/06-host-rpc-protocol.md b/docs/zh-CN/spec/03-runtime/06-host-rpc-protocol.md index 9e2dc820d5..f2d8aa1a8f 100644 --- a/docs/zh-CN/spec/03-runtime/06-host-rpc-protocol.md +++ b/docs/zh-CN/spec/03-runtime/06-host-rpc-protocol.md @@ -986,3 +986,10 @@ Host 重新检查会话的持久化模式,按调用会话的项目限制访问 提示词、非法时间和星期在写入前拒绝;不能删除运行中的任务。创建需 title、prompt、cadence; 每天/每周自动任务需 schedule。修改使用已存在的 ID 并保留未指定字段。界面虽只提供四个 时段,工具仍支持具体本地时间。不新增数据库 schema 或传输协议。 + +### 定时任务:旧任务维护 + +Agent 工具允许对缺少 schedule 的旧版自动任务修改标题、提示词或暂停,也允许回传 +未变化的 cadence。这些维护操作不会启用任务,也不会捕获前台工作区。显式启用、 +改变 cadence 或提供 schedule 时仍执行 schedule 校验;恢复任务需要明确的合法 +schedule,Manual 转 Hourly 继续使用现有默认间隔行为。 diff --git a/docs/zh-CN/spec/06-delivery/04-e2e-test-plan.md b/docs/zh-CN/spec/06-delivery/04-e2e-test-plan.md index 2f38aa1b06..3fc67d3574 100644 --- a/docs/zh-CN/spec/06-delivery/04-e2e-test-plan.md +++ b/docs/zh-CN/spec/06-delivery/04-e2e-test-plan.md @@ -8563,3 +8563,12 @@ the latest destination. These assertions measure work counts, not device FPS. - **规格**:`04-ux/08-component-spec.md`、`04-ux/09-interaction-patterns.md`。 - **验收 / 里程碑**:C、Quality / M6+。 - **状态**:组件与状态层用户路径由 `queue-pending-actions.test.mjs` 覆盖。 + +### E2E-SCHEDULED-legacy-pause + +- **场景**:旧任务维护。 +- **预期**:Agent 工具可对缺少 schedule 的旧版自动任务修改标题、提示词或暂停, + 包括回传未变化的 cadence;维护不会启用任务或捕获前台工作区。显式启用、改变 + cadence 或提供 schedule 时仍执行校验,Manual 转 Hourly 的默认间隔行为不变。 +- **自动化**:`node --experimental-strip-types scripts/e2e-scheduled-legacy-maintenance.mjs` + 使用隔离的真实 Host 与 SQLite 配置,不向真实提供商发送推理请求。 diff --git a/scripts/e2e-scheduled-legacy-maintenance.mjs b/scripts/e2e-scheduled-legacy-maintenance.mjs new file mode 100644 index 0000000000..08cc1dddaa --- /dev/null +++ b/scripts/e2e-scheduled-legacy-maintenance.mjs @@ -0,0 +1,22 @@ +import assert from "node:assert/strict"; +import { mkdtemp } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { randomUUID } from "node:crypto"; +import { Host, resolveHostBinary } from "./e2e/host.mjs"; +const host=new Host(resolveHostBinary(),await mkdtemp(join(tmpdir(),"pi-scheduled-legacy-"))); +try { + await host.start();await host.call("settings.set",{defaultPermissionMode:"auto"}); + const {session}=await host.call("session.create",{mode:"agent"}); + const tool=(toolName,args)=>host.call("tools.execute",{sessionId:session.id,toolName,args,mode:"agent",toolCallId:randomUUID()}); + for(const cadence of ["hourly","daily","weekly"]) { + const id=randomUUID();await host.call("scheduled.import",{tasks:[{id,title:"Legacy",prompt:"Old",cadence}]}); + for(const fields of [{title:"Renamed"},{prompt:"Updated"},{enabled:false},{cadence,enabled:false}]) assert.equal((await tool("ScheduledTaskUpdate",{id,...fields})).ok,true); + await host.restart();const saved=(await host.call("scheduled.list")).tasks.find(task=>task.id===id); + assert.equal(saved.title,"Renamed");assert.equal(saved.prompt,"Updated");assert.equal(saved.enabled,false);assert.equal(saved.schedule,undefined);assert.equal(saved.nextRunAt,undefined); + assert.equal((await tool("ScheduledTaskUpdate",{id,enabled:true})).errorCode,"INVALID_PARAMS"); + assert.equal((await tool("ScheduledTaskUpdate",{id,cadence,enabled:true,schedule:{hour:9,minute:15,weekday:0}})).ok,true); + assert.equal((await tool("ScheduledTaskDelete",{id})).ok,true); + console.log(`PASS ${cadence}: import, AI rename/prompt/pause, restart, guarded resume, configure and delete`); + } +} finally {await host.stop();}