Track
本页说明 Track 如何按计划重复执行网页任务、查询检查记录,以及当前后端与 Node SDK 的兼容边界。
版本与部署边界
npm @qoniai/qoni@0.9.0 使用旧 /track/monitors,2026-10-08 灰度验收返回 404,不能用于当前 /track/tracks 后端。下文 HTTP 描述该后端契约;Node 示例描述未发布修复候选(Unreleased,目标版本 0.10.0),不是已发布 0.9.0 功能。使用前确认目标部署的 OpenAPI 与 SDK 发布说明。这是破坏性变更,不能作为 npm 0.9.x 的可用功能描述。下载样例仍固定官方 0.9.0,不包含候选实现。
它解决什么问题
Track 为长期任务保存调度定义,通过 DoAnything 会话重复检查网页,适用于供应商价格、政策和合作伙伴门户巡检。页面目标、抽取要求和判断变化的规则写入自然语言 instructions;结果是否符合业务要求仍需应用核验。
核心能力
当前后端支持定时创建、读取定义、暂停/恢复、立即执行、最近检查回查和软删除;调度和任务引用的边界见后文。
典型场景
- 供应商监控智能体:重复核对价格与政策,应用验证来源和变化。
- 合作伙伴门户监控智能体:设计中的登录态盯守仍需核对部署支持,不能传旧
profile_id。
什么时候用
只执行一次用 DoAnything;公开网页检索用 WebSearch。当前 Track 没有旧版结构化抽取 DSL、触发 DSL、通知渠道或对齐问询能力,不保证每次检查产生通知。
创建 Track
POST /api/v1/projects/{pid}/track/tracks
Authorization: Bearer wa_...
Content-Type: application/json| HTTP 字段 | 说明 |
|---|---|
instructions | 必填,非空任务说明,最长 4000 字符;把目标 URL 与检查要求写在这里 |
title | 可选标题,最长 120 字符 |
schedule | 必填,不会从 instructions 推断,也没有 SDK 默认值 |
调度二选一:
- 间隔:
{"every_seconds":3600},整数秒,最短 600 秒,最长 30 天(2592000 秒)。 - 每日:
{"daily_at":"09:00","tz":"Asia/Singapore"},24 小时HH:MM与时区;后端会在该时刻前 0–30 分钟开始执行,不保证恰好 09:00。
不支持任意 cron、target_urls、profile_id、extraction_schema、trigger_dsl、stop_condition_dsl、tick_instructions 或 notify_channel。旧字段不能直接移植到新资源。
Node SDK
以下示例仅适用于未发布修复候选。
高层 prompt 原样映射为 HTTP instructions;历史句柄名称 MonitorHandle 保留,代表新的 Track 资源。
// 未发布修复候选;npm 0.9.0 不支持此后端契约。
const monitor = await qoni.track.create({
token,
prompt: "检查 https://example.com/ 的标题变化,返回标题与来源 URL。",
title: "示例页面巡检",
schedule: { kind: "daily", at: "09:00", tz: "Asia/Singapore" },
});
const current = await monitor.get();
const recent = await monitor.runs({ limit: 10, offset: 0 });
console.log(recent);创建会立即启动首次检查(kind: first_look),上面的示例只读取定义和 checks,不立即 runNow()。checks 的运行状态是 running,成功终态是 done;其他终态是 failed/expired/canceled,不同于统一 RunResult.status 的 succeeded。
手动执行前,先按精确 run ID 等待首次检查终态,并核对当前没有在途检查。检查状态读回与 runNow() 之间仍有竞态:收到 HTTP 409 task_in_progress 时保留原检查、继续查询其状态,稍后由用户明确发起新的手动执行;不要自动重试或把 409 当成成功。
间隔写成 schedule: { kind: "interval", intervalSeconds: 3600 }。候选本地校验调度范围,并以 QoniUnsupportedError 拒绝 cron 和旧 DSL、targetUrls、profileId、通知等不支持字段;不会静默忽略或转换。
| 方法 | 候选行为与边界 |
|---|---|
get() | 读取 Track 定义 |
pause() / resume() | 写入 status: paused/active;暂停不取消正在执行的任务 |
refine(patch) | 只改 title/schedule,保持原始 instructions;改变监控意图请新建 Track |
runNow() | 返回 trackId/sessionId/runId 真实任务引用;创建的 first_look 或当前检查未结束时返回 409 task_in_progress;HTTP 202 只表示受理,需查询检查终态 |
runs({ limit?, offset? }) | 读取最近 50 次 checks,按最新优先;参数仅对这个窗口本地分页,不是全历史分页 |
run(runId) | 在最近 50 次 checks 内精确查找;未找到会失败,不退回任意 DoAnything 任务读取 |
delete() | 软删除 Track 并停止后续调度,不停止当前 run |
当前后端没有 Track SSE 或问询/干预接口。候选的 events()(开始迭代时)、interactionHandle()、track.api.events()、track.api.intervene() 都本地抛 QoniUnsupportedError,零 HTTP。Track 权限不能授权 DoAnything 的人工操作;需要独立取得 DoAnything 授权并处理对应任务。
首次 get() 读回时,捕获一次 current.lastTaskId(HTTP last_task_id)作为原首检 ID。checking 表示最新检查是否仍在运行(后端 pending/running/waiting 统一显示为 running);仅 checking: false 不足以判业务成功,仍按原 ID 查 checks 的终态与输出。暂停/恢复或后续读回不能替换已捕获的首检 ID。
检查记录
HTTP checks.items 只含最近 50 条,SDK runs() 对字段名作 camelCase 转换,不改 status/outcome 的值:
| HTTP 字段(SDK 字段) | 输出与边界 |
|---|---|
run_id(runId) | 该次检查的精确任务 ID;后续查询保留这个 ID |
kind | first_look、scheduled 或 manual |
status | 在途为 running;终态为 done/failed/expired/canceled |
outcome | changed、same、needs_you,尚无报告时可为 null;needs_you 不提供 Track 问询回复 API |
headline | 报告摘要;较旧记录可回退到回答首行,也可能为 null |
answer | 检查回答,可为 null;业务需核验内容及来源 |
failure | failed/expired 的失败详情,否则为 null;不能用空失败详情推断成功 |
created_at/ended_at(createdAt/endedAt) | 创建/结束时间,尚未结束时 ended_at 为 null |
step | 在途检查最近的动作标签,无记录时可为 null |
失败与自动暂停
| 响应/条件 | 处理 |
|---|---|
创建时 409 track_limit | 每项目每用户最多保留 20 个 Track,paused 也计入;删除不再需要的 Track 才释放名额 |
执行时 409 task_in_progress | 原任务仍在途,按原 ID 读回;不自动重试 |
422 invalid_track | 服务层发现无效调度或任务定义;修正输入。请求模型的字段/类型校验也可能返回 422 |
404 track_not_found | Track 不存在、已软删除或不在调用者可见范围;不要改用其他资源 ID |
连续 3 次检查没有产出 track_report | 调度器在后续调度检查时自动暂停;读回状态,查看对话与失败记录后再决定是否恢复 |
成功的报告会清零无报告计数;done 不替代报告与业务输出核验。run(runId) 在最近 50 条窗口找不到记录时,是候选 SDK 的本地 not_found(无 HTTP status),应与后端 track_not_found 区分。
原生 HTTP 生命周期
GET /api/v1/projects/{pid}/track/tracks
GET /api/v1/projects/{pid}/track/tracks/{track_id}
PATCH /api/v1/projects/{pid}/track/tracks/{track_id}
DELETE /api/v1/projects/{pid}/track/tracks/{track_id}
POST /api/v1/projects/{pid}/track/tracks/{track_id}/run_now
GET /api/v1/projects/{pid}/track/tracks/{track_id}/checksPATCH 直接传资源字段,例如 {"status":"paused"},不用旧 action/patch 包装。原生接口可更新 instructions/title/schedule/status;SDK 高层 refine() 为保留原意,只开放 title/schedule。checks 返回 items,最多最近 50 次记录;没有旧 /runs/{run_id} 全历史详情接口。
检查结果与下一步
创建后读回定义与调度;runNow() 后用返回的精确 run ID 查检查记录并等待终态,再核验输出与来源。尚未出现检查记录或只有 202 都不算任务成功。删除 Track 后仍需核对当前任务状态。
候选发布前,正式 0.9.0 调用方不能靠换一个 SDK 参数解决旧路由差额。文件产物读取见 Qoni SDK;需要登录态复用时先核对 Profiles 的支持边界。