13 KiB
description, kind
| description | kind |
|---|---|
| 面向模型的后台任务控制,供选择、配置或排查 job_output、job_list、job_kill 与完成通知的用户与维护者阅读。 | package-reference |
@deepseek-ai/dsh-tool-jobs
English | 中文
概述
使用 dsh-tool-jobs,可通过 job_output、job_list 与 job_kill 检查和控制后台命令、PTY 工作与 subagent。读取可在配置的超时内等待,列表结果标识各任务的 kind 与状态,而取消只有在工作停止后才结算。归属明确的工作完成时,agent(智能体)会收到会话内通知:繁忙的 agent 在下一步收到通知,空闲的 agent 则由 follow-up 轮次唤醒。配置控制等待上限、完成投递与可选的连续唤醒上限。流输出仅供单一读取方消费,待领通知无法在所有者释放后存活。
目录
使用本包
在 agent 需要启动、观察和停止后台任务的任何组合中加载本插件:它注册三个工具、附加生产方所需的控制器,并投递完成通知。它需要组合中已提供的 ctx.tools、ctx.jobs 与 ctx.systemPrompt 服务;完成通知经 ctx.agents 解析投递目标,凡有归属任务的组合都已提供它。
三个工具
job_output(job_id, wait?, timeout_ms?)——读取任务输出。流任务只返回自上次读取以来的输出;最终输出任务在结算后返回其结果。每个响应都以[status: ...]结尾。除非wait: true,否则读取是非阻塞的;wait: true最多等待到配置上限,超时时仍让运行中的任务保持存活。一次读取先渲染 stdout,再把 stderr 放进一段[stderr],标注读取前已离开内存的输出,并在结算后的第一次读取恰好携带一次任务的结果(subagent 的回答)。job_list()——列出你的后台任务及其 id、kind 与状态,每行一个:<id> [<kind>] <status> — <label>。job_kill(job_id, reason?)——立即请求取消运行中的任务;任务在其工作真正停止后以killed结算。终止任务返回其当前快照,可选的原因会被记录并转发给任务。
三个工具依次返回 { text, job }、PublicJobSnapshot[] 与 { outcome: 'cancellation-requested' | 'already-finished', job }。公共快照携带 id、kind、label、带实时进度行或终态 detail 的状态,以及开始/结束时间,并省略归属与环偏移。三个工具都通过通用 UI 卡片渲染:output 和 list 用 read,kill 用 execute。
完成通知
任务完成时,拥有它的 agent 会收到会话内消息 background job <id> (<kind>: <label>) finished [status: ...]. Read its output with job_output.。繁忙的 agent 会在下一步收到注入的通知——inbox 尚有内容时轮次无法结束,因此同时结算的多个任务只花掉一步,而不是各占一轮。空闲的 agent 则被一个 follow-up 轮次唤醒,因为无人领取的通知就是模型永远不会知道的完成。模型已经收走的完成不再通知:注册表把释放了存活 wait 的结算报告为 awaited——无论是 job_output 的等待,还是 shell 工具在等待自己的前台命令——插件则记着模型经 job_kill 请求的杀停;所有者或服务 teardown 导致的结算会被跳过,因为没有人能读它。
唤醒默认不设上限:无人值守的 agent 连续串起后台命令与一次性 subagent 时,每次完成都会唤醒它。maxConsecutiveWakes 可以封顶:每个所有者最多被唤醒这么多次,此后的通知降级为注入;领取任何用户撰写的消息都会恢复预算。上限用来约束自激链——被唤醒的一轮可能启动某个后台任务,而它的完成又会唤醒同一个所有者——但超出上限的通知会静默等到用户下一次输入,依赖唤醒完成工作的会话会停在那里。completionDelivery: quiet 让空闲所有者也在注入通道上,确定性 transcript(文本记录)需要的正是这一点。
最小配置
不带配置加载插件是常用路径;waitTimeoutMs 高于 maxWaitTimeoutMs 时会在加载时失败。
- name: '@deepseek-ai/dsh-tool-jobs'
| 字段 | 默认值 | 含义 |
|---|---|---|
waitTimeoutMs |
30,000 |
wait: true 省略 timeout_ms 时使用的等待时间 |
maxWaitTimeoutMs |
600,000 |
模型所给等待时间的上限;更大的值向下收敛到它 |
completionDelivery |
wakeup |
wakeup 为空闲所有者开启一轮;quiet 让通知继续待领 |
maxConsecutiveWakes |
未设置 | 一个所有者可由唤醒开启的轮数,超出后通知降级为注入;未设置即不封顶 |
生成的配置目录是每个受支持字段及其 JSDoc 的穷尽式真源。
可能出什么问题
组合中未加载 tool-jobs 的 agent 无法启动后台工作:本插件的控制器正是生产方 ctx.jobs.start() 得以启用所依赖的。模型给出的等待时间超过 maxWaitTimeoutMs 时会向下收敛到上限,超时的等待返回 [status: running] 并让任务保持存活,而不是失败。待领于空闲所有者的完成通知无法在该所有者释放后存活。
理解实现
实现细节——点击展开
本节解释工具背后的设计决策,并指出实现它们的代码位置;可观察行为已在使用本包中完整说明。
设计理念
- 与 kind 无关的控制。 同一套三个工具读取、列出和取消每种生产方 kind 的任务——bash、PTY——因为它们都通过通用的
ctx.jobs运行时注册。 - 投递归本插件,收件人归注册表。 插件决定未报告的完成如何到达所有者——注入繁忙的一步,或唤醒空闲所有者的一轮——而注册表把每次结算路由给其所有者 scope 链所能抵达的监听器,因此某个 preset 下的挂载永远看不到另一个 preset 的 agent,无论挂载了多少 preset,一个 agent 每次完成都只读到一条通知。
- 生产方自有的输出上限。 生产方提供
outputLimitBytes时,完整的模型侧结果——输出读取、终止 kill 快照或完成通知——会在添加状态与通知元数据之后被施加上限;省略该字段的生产方保持无界行为。
源码地图
| 文件 | 职责 |
|---|---|
src/index.ts |
插件入口:工具注册、结算订阅与模型杀停集合、提示词区段、输出上限 |
src/render.ts |
面向模型的渲染:公共投影、状态行与消耗式增量(stdout、[stderr] 段、丢失输出提示) |
输出上限
job_output 与 job_kill 会在策略运行前于前置的 pre-execute 监听器中捕获调用方可见任务,因此生产方上限适用于完整渲染结果。job_output 在策略保留默认渲染时保持其输出/状态拆分,对输出尾部与 [status: ...] 后缀设界;其他单文本结果——拒绝、短路、规范化工具或流水线失败、替换与阻止——按单个文本设界,而结构化多块策略结果保持自身形状。有界完成通知在完整 job id 与 job_output 指令都能容纳时保留两者。否则当上限至少有八字节时,它提示模型使用 job_list;更小的上限只能容纳指令前缀。PTY 支持的 64 字节下限能容纳完整的 job_list 指令。已有生产方截断标记会被复用。
通知投递通道
结算订阅({ owners: 'scope' })跳过注册表报告为 awaited 的结算、模型经 job_kill 杀停的任务、无所有者的任务与 teardown 结算,然后解析登记在拥有者会话下的 agent。wakeup 投递为空闲所有者开启一轮;设置了 maxConsecutiveWakes 时只在预算内开启,按确切 Agent 记录在 WeakMap 中,领取用户撰写的消息(agent/inbox/claimed)会重置该所有者的预算。繁忙的所有者——或超出所配预算的任何通知,以及 quiet 投递——改为注入 next-step inbox。注册表只计入结算时仍被欠着投影的等待,因此超时或中止的等待会让之后的结算照常通知;移除会把任务从模型杀停集合里删掉,该集合只保有模型杀停过的存活任务。
进一步探索
当包级约定不够用时阅读以下页面。它们从任务类型逐步进入注册表约定与生成 schema。
- 后台任务运行时子系统——任务类型、快照字段与
ctx.jobs的 Cordis 接口面。 - jobs 组映射——同级组页面及其包表格。
- 注册表约定——工具背后的抽象
ctx.jobs服务。 - 进程本地注册表——任务在本进程中的运行位置。
- 生成的工具目录——
job_output、job_list与job_kill的确切 schema。 - 生成的配置目录——每个受支持配置字段及其源声明。
- 任务注册表 seam Agent Note——按所有者隔离的注册表约定及其理由。
模型体验
系统提示词
模型看到什么
该插件注册 scope 中的每次请求都包含以下指引。按 agent scope 过滤工具时,可能会隐藏工具,却不会移除独立注册的提示词区段。
后台任务指引
Track every background job id you start. You are notified in-session when a job finishes — do not busy-poll or sleep on one; keep working on independent steps and do not duplicate a running job's work. Before giving a final answer, collect every still-relevant job with job_output (set wait: true only when you are genuinely blocked on it), and job_kill jobs that stopped mattering.
Token 影响
激活期间,每次请求都会产生少量固定的输入 token 开销。
KV Cache 影响
只要插件 scope 与指引文本不变,前缀就保持稳定。激活或释放可能使从该提示词区段起的复用失效。
工具 schema
模型看到什么
该工具集可见时,会看到生成的 job_output、job_list 和 job_kill schema。
Token 影响
工具可见时,每次请求都会产生固定的 schema token 开销。
KV Cache 影响
只要工具定义与可见性不变,前缀就保持稳定。注册生命周期或 scope 限制可能使从第一个发生变化的 schema token 起的复用失效。
结果与通知
模型看到什么
读取会返回输出或 (no new output),随后是 [status: <status>] 和可选 detail。空列表返回 (no background jobs)。kill 返回 requested cancellation of job <id> 或现有终止状态。模型尚未收走且有所有者归属的完成使用上述通知。
Token 影响
结果与通知在压缩(compaction)前保留于父级历史。流读取不会重复已消费的输出;生产方提供的 outputLimitBytes 会限制每次完整读取或通知。在 wakeup 下,抵达空闲所有者的通知还会额外买下一次用户并未要求的模型请求,其数量仅在设置了 maxConsecutiveWakes 时按所有者封顶;抵达繁忙所有者的通知则只是给它已经在支付的那一轮加一步。
KV Cache 影响
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
已知限制与延期工作
这些限制说明工具何时不合适。它们是当前包约束,不是任务积压。
- 落在 driver 退休窗口内的结算仍会让通知搁浅——在轮次循环最后一次检查 inbox 与 driver 提交 idle 相位之间,所有者读起来仍是繁忙,因此通知走注入且无人唤醒。steering(中途引导)存在同样的问题;修复它属于
agent-loop。 - 已花掉的唤醒预算不会随时间恢复——设置了
maxConsecutiveWakes时,只有用户撰写的输入才能补充,因此预算耗尽的无人值守 agent 要等到其他原因开启下一轮时才收走剩余通知,且客户端不会显示有通知在等待。 - 待领于空闲所有者的通知无法在该所有者释放后存活——释放时的取消会清空未领取的 inbox,日志保留插入/取消这一对作为记录。
- 模型读取只有单一消费方——独立观察者使用注册表非消耗的
readAt(Web 客户端的job.follow),而不是这些工具。 - 无 owner 的任务没有会话隔离——外部调用方必须提供策略或避开这些任务。
开发备注
维护者的工作上下文——点击展开
无。