伍 · 委托
Agent 任务
ctx.agentTasks
调用 dsh 已注册的 subagent provider(如 claude-code、codex)执行一次性任务:默认只读权限、每个任务独立目录、类型化的 JSON Schema 输出、并发与排队上限。
接口
import { untrusted } from '@mc/dsh-agent-kit'
const r = await ctx.agentTasks.run<Verdict>({
provider: 'claude-code',
title: 'classify evt_123',
prompt: [
'请判断下面的事件是否异常。',
untrusted('event', eventJson), // 用随机分隔标记包裹外部数据,并声明其不是指令
],
outputSchema, // JSONSchemaType<Verdict>;省略时 output 为 undefined
model: 'optional-model-id', // 仅传给支持该能力的 provider
permissions: 'read-only', // 默认值,可选 workspace-write
timeoutMs: 120_000,
signal,
traceId,
onEvent: (e) => {}, // 可选:queued / started / finished
})
// r: { sessionId, taskId, text, output: Verdict, durationMs }provider 是 dsh 中已注册的 subagent provider 名称,例如 claude-code、codex。ctx.subagents 与子进程服务由 dsh 的 base bundle 提供,Profile 里只需安装对应的 provider 包。
隔离与权限
- 每个任务在
workspaceDir/<taskId>/下使用一个新建的空目录(权限 0700)作为 Agent 的工作目录,结束后删除;keepWorkdir: true时保留,便于排查。 permissions默认read-only,可选workspace-write,不提供更高档位。- 支持工具过滤的 provider:按
toolAllowlist传入工具白名单,白名单之外的工具(包括 bash 和网络)都不可见。 - 不支持工具过滤的 provider(claude-code、codex):权限由 provider 实例自身的配置决定,必须在
declaredPermissions中如实声明它的权限上限。未声明,或声明的上限高于本次请求的档位时,任务以unsupported_permissions失败。
不可信数据
- 来自 WebSocket 等外部来源的数据传给 Agent 时,用
untrusted()包裹。它会生成随机的分隔标记,外部数据无法伪造结束标记”逃逸”出来。 - Agent 返回的
text与output同样视为不可信:本包只做 Schema 校验,据此触发推送等副作用前,业务包必须按白名单校验取值。
结构化输出
给出 outputSchema 时:
- provider 支持原生结构化输出时直接使用;claude-code、codex 不支持,本包会在 prompt 末尾追加要求,让 Agent 在一个 json 代码块中输出结果。
- 从答案中取 JSON 的规则:取最后一个标注为
json的代码块;没有则取最后一个未标注语言的代码块;都没有则把整段答案作为 JSON 解析。选中的候选解析失败时直接判为invalid_output,不回退到更早的代码块;空答案同样判为invalid_output。 - 取到的结果一律再用 Ajv 按
outputSchema校验,通过后放入output,类型由outputSchema推断。
并发、超时与卸载
- 同时最多
maxConcurrency个任务运行,其余按 FIFO 排队;排队数达到maxQueueSize时新任务立即以queue_full失败,health()为degraded。 signal在排队期中止时移出队列、不占用并发槽;运行期中止时取消委托;调用时已中止则立即以aborted失败。- 单任务超过
timeoutMs时取消委托并以timeout失败。 - Service 卸载时,排队和运行中的任务都以
aborted结束。
Agent 进程的环境变量
provider 启动 Agent 时,会剔除名字匹配 KEY、PASSWORD、SECRET、TOKEN 的环境变量与 DSH_*。因此本包的密钥(例如 TYPESAFE_API_KEY)不会进入 Agent 进程;反过来,如果 Agent 依赖这类变量鉴权(例如 ANTHROPIC_AUTH_TOKEN),需要在 provider 自己的配置 env 中显式给出。
审计
claude-code、codex 不持久化 Session,这些任务不会出现在 dsh Web 的会话列表中。审计依赖本包的结构化日志(prompt 与答案只记录长度与哈希)和业务包自己的记录。
配置
在 Profile 的 cordis.patch.yml 中按 id agent-kit-agent-tasks 启用并给出配置。按 id 修改 config 时整段替换,未给出的字段使用默认值。下表由本包源码中的配置 schema 生成。
- id: agent-kit-agent-tasks
disabled: false
config:
# 只写需要改的字段,其余使用下表的默认值 | 字段 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|
workspaceDir 必填 | — | — | 任务工作目录的根,专用目录,不得是业务代码目录 |
defaultTimeoutMs | 600000 | [10000, 3600000] | run() 未指定 timeoutMs 时的单任务超时。 |
maxConcurrency | 2 | [1, 16] | 同时运行的任务数上限,其余按 FIFO 排队。 |
maxQueueSize | 100 | ≥ 0 | 排队数上限,达到后新任务立即以 queue_full 失败。 |
keepWorkdir | false | — | 任务结束后保留 workspaceDir/<taskId>/ 目录,便于排查。 |
declaredPermissions | {} | 见说明 | 不支持工具过滤的 provider 的权限上限(provider 名 → read-only | workspace-write)。 |
toolAllowlist.read-only | ["read", "read_image", "glob", "grep", "todo_write"] | 见说明 | 支持工具过滤的 provider 在 read-only 档位下可见的工具。 |
toolAllowlist.workspace-write | ["read", "read_image", "glob", "grep", "todo_write", "write", "edit", "str_replace_editor"] | 见说明 | 支持工具过滤的 provider 在 workspace-write 档位下可见的工具。 |
约束与说明
- workspaceDir 必须是绝对路径,且不能是进程工作目录或其祖先。
- 不支持工具过滤的 provider(claude-code、codex)必须在 declaredPermissions 中声明权限上限,否则任务以 unsupported_permissions 失败。
- claude-code 默认的 permissionMode: dontAsk 下不能执行命令或写文件,可声明为 read-only。
错误码
所有错误都是 KitError:用 isKitError(e) 判断,按 code 与 retryable 决定是否重试。
| code | 可重试 | 含义 |
|---|---|---|
provider_failed | 视情况 | provider 未注册、委托出错或以 error / refusal / max-tokens 结束;限流可重试,鉴权失败不可重试。 |
timeout | 是 | 任务超过 timeoutMs,委托被取消。 |
invalid_output | 否 | 答案中取不到 JSON,或不符合 outputSchema。 |
aborted | 否 | 调用方 signal 中止或 Service 卸载。 |
queue_full | 是 | 排队数达到 maxQueueSize。 |
unsupported_permissions | 否 | provider 无法保证请求的权限档位,且未声明足够严格的 declaredPermissions。 |
invalid_config | 否 | 配置或环境变量非法,Service 启动失败。 |